2013-11-23 11:15:11 +00:00
|
|
|
/*
|
|
|
|
The MIT License (MIT)
|
|
|
|
|
2014-01-01 02:37:12 +00:00
|
|
|
Copyright (c) 2013-2014 winlin
|
2013-11-23 11:15:11 +00:00
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
|
|
this software and associated documentation files (the "Software"), to deal in
|
|
|
|
the Software without restriction, including without limitation the rights to
|
|
|
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
|
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
|
|
subject to the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
|
|
copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
|
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
|
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
|
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2014-03-02 13:49:09 +00:00
|
|
|
#ifndef SRS_APP_HLS_HPP
|
|
|
|
#define SRS_APP_HLS_HPP
|
2013-11-23 11:15:11 +00:00
|
|
|
|
|
|
|
/*
|
2014-03-02 13:49:09 +00:00
|
|
|
#include <srs_app_hls.hpp>
|
2013-11-23 11:15:11 +00:00
|
|
|
*/
|
|
|
|
#include <srs_core.hpp>
|
|
|
|
|
2013-11-27 14:41:58 +00:00
|
|
|
#ifdef SRS_HLS
|
|
|
|
|
2013-11-24 09:15:37 +00:00
|
|
|
#include <string>
|
2013-11-26 08:06:58 +00:00
|
|
|
#include <vector>
|
2013-11-24 09:15:37 +00:00
|
|
|
|
2013-11-26 03:48:18 +00:00
|
|
|
class SrsSharedPtrMessage;
|
2013-11-24 08:00:45 +00:00
|
|
|
class SrsCodecSample;
|
2013-11-24 15:13:14 +00:00
|
|
|
class SrsCodecBuffer;
|
2013-11-26 02:47:05 +00:00
|
|
|
class SrsMpegtsFrame;
|
2013-12-15 12:29:18 +00:00
|
|
|
class SrsAmf0Object;
|
2013-11-26 08:06:58 +00:00
|
|
|
class SrsRtmpJitter;
|
2013-11-24 09:15:37 +00:00
|
|
|
class SrsTSMuxer;
|
2013-11-24 04:39:47 +00:00
|
|
|
class SrsCodec;
|
2013-12-01 09:32:06 +00:00
|
|
|
class SrsRequest;
|
2013-12-05 15:34:26 +00:00
|
|
|
class SrsPithyPrint;
|
2013-12-15 12:29:18 +00:00
|
|
|
class SrsSource;
|
2013-11-24 04:39:47 +00:00
|
|
|
|
2013-11-27 09:30:16 +00:00
|
|
|
/**
|
|
|
|
* jitter correct for audio,
|
|
|
|
* the sample rate 44100/32000 will lost precise,
|
|
|
|
* when mp4/ts(tbn=90000) covert to flv/rtmp(1000),
|
|
|
|
* so the Hls on ipad or iphone will corrupt,
|
|
|
|
* @see nginx-rtmp: est_pts
|
|
|
|
*/
|
|
|
|
class SrsHlsAacJitter
|
|
|
|
{
|
|
|
|
private:
|
2014-03-18 03:32:58 +00:00
|
|
|
int64_t base_pts;
|
|
|
|
int64_t nb_samples;
|
|
|
|
int sync_ms;
|
2013-11-27 09:30:16 +00:00
|
|
|
public:
|
2014-03-18 03:32:58 +00:00
|
|
|
SrsHlsAacJitter();
|
|
|
|
virtual ~SrsHlsAacJitter();
|
|
|
|
/**
|
|
|
|
* when buffer start, calc the "correct" pts for ts,
|
|
|
|
* @param flv_pts, the flv pts calc from flv header timestamp,
|
|
|
|
* @return the calc correct pts.
|
|
|
|
*/
|
|
|
|
virtual int64_t on_buffer_start(int64_t flv_pts, int sample_rate);
|
|
|
|
/**
|
|
|
|
* when buffer continue, muxer donot write to file,
|
|
|
|
* the audio buffer continue grow and donot need a pts,
|
|
|
|
* for the ts audio PES packet only has one pts at the first time.
|
|
|
|
*/
|
|
|
|
virtual void on_buffer_continue();
|
2013-11-27 09:30:16 +00:00
|
|
|
};
|
|
|
|
|
2013-12-02 07:55:10 +00:00
|
|
|
//TODO: refine the ts muxer, do more jobs.
|
|
|
|
class SrsTSMuxer
|
|
|
|
{
|
|
|
|
private:
|
2014-03-18 03:32:58 +00:00
|
|
|
int fd;
|
|
|
|
std::string path;
|
2013-12-02 07:55:10 +00:00
|
|
|
public:
|
2014-03-18 03:32:58 +00:00
|
|
|
SrsTSMuxer();
|
|
|
|
virtual ~SrsTSMuxer();
|
2013-12-02 07:55:10 +00:00
|
|
|
public:
|
2014-03-18 03:32:58 +00:00
|
|
|
virtual int open(std::string _path);
|
|
|
|
virtual int write_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab);
|
|
|
|
virtual int write_video(SrsMpegtsFrame* vf, SrsCodecBuffer* vb);
|
|
|
|
virtual void close();
|
2013-12-02 07:55:10 +00:00
|
|
|
};
|
|
|
|
|
2013-12-02 06:24:09 +00:00
|
|
|
/**
|
|
|
|
* 3.3.2. EXTINF
|
|
|
|
* The EXTINF tag specifies the duration of a media segment.
|
|
|
|
*/
|
|
|
|
struct SrsM3u8Segment
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
// duration in seconds in m3u8.
|
|
|
|
double duration;
|
|
|
|
// sequence number in m3u8.
|
|
|
|
int sequence_no;
|
|
|
|
// ts uri in m3u8.
|
|
|
|
std::string uri;
|
|
|
|
// ts full file to write.
|
|
|
|
std::string full_path;
|
|
|
|
// the muxer to write ts.
|
|
|
|
SrsTSMuxer* muxer;
|
|
|
|
// current segment start dts for m3u8
|
|
|
|
int64_t segment_start_dts;
|
|
|
|
|
|
|
|
SrsM3u8Segment();
|
|
|
|
virtual ~SrsM3u8Segment();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* update the segment duration.
|
|
|
|
*/
|
|
|
|
virtual double update_duration(int64_t video_stream_dts);
|
2013-12-02 06:24:09 +00:00
|
|
|
};
|
|
|
|
|
2013-11-26 08:06:58 +00:00
|
|
|
/**
|
2013-12-02 07:55:10 +00:00
|
|
|
* muxer the m3u8 and ts files.
|
2013-11-26 08:06:58 +00:00
|
|
|
*/
|
2013-12-02 07:55:10 +00:00
|
|
|
class SrsM3u8Muxer
|
2013-11-23 12:16:47 +00:00
|
|
|
{
|
2013-11-24 04:39:47 +00:00
|
|
|
private:
|
2014-03-18 03:32:58 +00:00
|
|
|
std::string app;
|
|
|
|
std::string stream;
|
2013-12-02 07:55:10 +00:00
|
|
|
private:
|
2014-03-18 03:32:58 +00:00
|
|
|
std::string hls_path;
|
|
|
|
int hls_fragment;
|
|
|
|
int hls_window;
|
2013-11-26 08:06:58 +00:00
|
|
|
private:
|
2014-03-18 03:32:58 +00:00
|
|
|
int file_index;
|
|
|
|
std::string m3u8;
|
2013-11-26 08:06:58 +00:00
|
|
|
private:
|
2014-03-18 03:32:58 +00:00
|
|
|
/**
|
|
|
|
* m3u8 segments.
|
|
|
|
*/
|
|
|
|
std::vector<SrsM3u8Segment*> segments;
|
|
|
|
/**
|
|
|
|
* current writing segment.
|
|
|
|
*/
|
|
|
|
SrsM3u8Segment* current;
|
|
|
|
// last known dts
|
|
|
|
int64_t video_stream_dts;
|
2013-12-02 07:55:10 +00:00
|
|
|
public:
|
2014-03-18 03:32:58 +00:00
|
|
|
SrsM3u8Muxer();
|
|
|
|
virtual ~SrsM3u8Muxer();
|
2013-12-02 07:55:10 +00:00
|
|
|
public:
|
2014-03-18 03:32:58 +00:00
|
|
|
virtual int update_config(std::string _app, std::string _stream, std::string path, int fragment, int window);
|
|
|
|
virtual int segment_open();
|
|
|
|
virtual int flush_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab);
|
|
|
|
virtual int flush_video(SrsMpegtsFrame* af, SrsCodecBuffer* ab, SrsMpegtsFrame* vf, SrsCodecBuffer* vb);
|
|
|
|
virtual int segment_close();
|
2013-12-02 07:55:10 +00:00
|
|
|
private:
|
2014-03-18 03:32:58 +00:00
|
|
|
virtual int refresh_m3u8();
|
|
|
|
virtual int _refresh_m3u8(int& fd, std::string m3u8_file);
|
|
|
|
virtual int create_dir();
|
2013-12-02 07:55:10 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2013-12-02 14:09:10 +00:00
|
|
|
* ts need to cache some audio then flush
|
2013-12-02 07:55:10 +00:00
|
|
|
*/
|
2013-12-02 14:09:10 +00:00
|
|
|
class SrsTSCache
|
2013-12-02 07:55:10 +00:00
|
|
|
{
|
|
|
|
private:
|
2014-03-18 03:32:58 +00:00
|
|
|
// current frame and buffer
|
|
|
|
SrsMpegtsFrame* af;
|
|
|
|
SrsCodecBuffer* ab;
|
|
|
|
SrsMpegtsFrame* vf;
|
|
|
|
SrsCodecBuffer* vb;
|
2013-12-02 14:09:10 +00:00
|
|
|
private:
|
2014-03-18 03:32:58 +00:00
|
|
|
// the audio cache buffer start pts, to flush audio if full.
|
|
|
|
int64_t audio_buffer_start_pts;
|
|
|
|
// time jitter for aac
|
|
|
|
SrsHlsAacJitter* aac_jitter;
|
2013-12-02 14:09:10 +00:00
|
|
|
public:
|
2014-03-18 03:32:58 +00:00
|
|
|
SrsTSCache();
|
|
|
|
virtual ~SrsTSCache();
|
2013-12-02 14:09:10 +00:00
|
|
|
public:
|
2014-03-18 03:32:58 +00:00
|
|
|
/**
|
|
|
|
* write audio to cache, if need to flush, flush to muxer.
|
|
|
|
*/
|
|
|
|
virtual int write_audio(SrsCodec* codec, SrsM3u8Muxer* muxer, int64_t pts, SrsCodecSample* sample);
|
|
|
|
/**
|
|
|
|
* write video to muxer.
|
|
|
|
*/
|
|
|
|
virtual int write_video(SrsCodec* codec, SrsM3u8Muxer* muxer, int64_t dts, SrsCodecSample* sample);
|
|
|
|
/**
|
|
|
|
* flush audio in cache to muxer.
|
|
|
|
*/
|
|
|
|
virtual int flush_audio(SrsM3u8Muxer* muxer);
|
2013-12-02 14:09:10 +00:00
|
|
|
private:
|
2014-03-18 03:32:58 +00:00
|
|
|
virtual int cache_audio(SrsCodec* codec, SrsCodecSample* sample);
|
|
|
|
virtual int cache_video(SrsCodec* codec, SrsCodecSample* sample);
|
2013-12-02 14:09:10 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* write m3u8 hls.
|
|
|
|
*/
|
|
|
|
class SrsHls
|
|
|
|
{
|
|
|
|
private:
|
2014-03-18 03:32:58 +00:00
|
|
|
SrsM3u8Muxer* muxer;
|
|
|
|
SrsTSCache* ts_cache;
|
2013-11-26 08:06:58 +00:00
|
|
|
private:
|
2014-03-18 03:32:58 +00:00
|
|
|
bool hls_enabled;
|
|
|
|
SrsSource* source;
|
|
|
|
SrsCodec* codec;
|
|
|
|
SrsCodecSample* sample;
|
|
|
|
SrsRtmpJitter* jitter;
|
|
|
|
SrsPithyPrint* pithy_print;
|
2013-11-23 12:16:47 +00:00
|
|
|
public:
|
2014-03-18 03:32:58 +00:00
|
|
|
SrsHls(SrsSource* _source);
|
|
|
|
virtual ~SrsHls();
|
2013-11-24 04:39:47 +00:00
|
|
|
public:
|
2014-03-18 03:32:58 +00:00
|
|
|
/**
|
|
|
|
* publish stream event, continue to write the m3u8,
|
|
|
|
* for the muxer object not destroyed.
|
|
|
|
*/
|
|
|
|
virtual int on_publish(SrsRequest* req);
|
|
|
|
/**
|
|
|
|
* the unpublish event, only close the muxer, donot destroy the
|
|
|
|
* muxer, for when we continue to publish, the m3u8 will continue.
|
|
|
|
*/
|
|
|
|
virtual void on_unpublish();
|
|
|
|
/**
|
|
|
|
* get some information from metadata, it's optinal.
|
|
|
|
*/
|
|
|
|
virtual int on_meta_data(SrsAmf0Object* metadata);
|
|
|
|
/**
|
|
|
|
* mux the audio packets to ts.
|
|
|
|
*/
|
|
|
|
virtual int on_audio(SrsSharedPtrMessage* audio);
|
|
|
|
/**
|
|
|
|
* mux the video packets to ts.
|
|
|
|
*/
|
|
|
|
virtual int on_video(SrsSharedPtrMessage* video);
|
2013-12-05 15:34:26 +00:00
|
|
|
private:
|
2014-03-18 03:32:58 +00:00
|
|
|
virtual void hls_mux();
|
2013-11-23 12:16:47 +00:00
|
|
|
};
|
|
|
|
|
2013-11-27 14:41:58 +00:00
|
|
|
#endif
|
|
|
|
|
2013-11-23 11:15:11 +00:00
|
|
|
#endif
|