diff --git a/trunk/src/app/srs_app_hls.cpp b/trunk/src/app/srs_app_hls.cpp index a286dd624..186666ceb 100644 --- a/trunk/src/app/srs_app_hls.cpp +++ b/trunk/src/app/srs_app_hls.cpp @@ -44,7 +44,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include // max PES packets size to flush the video. -#define SRS_HLS_AUDIO_CACHE_SIZE 512 * 1024 +#define SRS_HLS_AUDIO_CACHE_SIZE 1024 * 1024 // @see: NGX_RTMP_HLS_DELAY, // 63000: 700ms, ts_tbn=90000 @@ -481,12 +481,20 @@ SrsHlsSegment::~SrsHlsSegment() srs_freep(muxer); } -double SrsHlsSegment::update_duration(int64_t current_frame_dts) +void SrsHlsSegment::update_duration(int64_t current_frame_dts) { + // we use video/audio to update segment duration, + // so when reap segment, some previous audio frame will + // update the segment duration, which is nagetive, + // just ignore it. + if (current_frame_dts < segment_start_dts) { + return; + } + duration = (current_frame_dts - segment_start_dts) / 90000.0; srs_assert(duration >= 0); - return duration; + return; } SrsHlsAacJitter::SrsHlsAacJitter() @@ -503,7 +511,6 @@ SrsHlsMuxer::SrsHlsMuxer() hls_fragment = hls_window = 0; file_index = 0; current = NULL; - video_count = 0; } SrsHlsMuxer::~SrsHlsMuxer() @@ -542,9 +549,6 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts) return ret; } - // reset video count for new publish session. - video_count = 0; - // TODO: create all parents dirs. // create dir for app. if ((ret = create_dir()) != ERROR_SUCCESS) { @@ -605,6 +609,9 @@ int SrsHlsMuxer::flush_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab) return ret; } + // update the duration of segment. + current->update_duration(af->pts); + if ((ret = current->muxer->write_audio(af, ab)) != ERROR_SUCCESS) { return ret; } @@ -635,6 +642,9 @@ int SrsHlsMuxer::flush_video( return ret; } + // write success, clear and free the buffer + vb->free(); + return ret; } @@ -860,6 +870,8 @@ SrsHlsCache::SrsHlsCache() af = new SrsMpegtsFrame(); vf = new SrsMpegtsFrame(); + + video_count = 0; } SrsHlsCache::~SrsHlsCache() @@ -890,6 +902,9 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment // get the hls path config std::string hls_path = _srs_config->get_hls_path(vhost); + // reset video count for new publish session. + video_count = 0; + // open muxer if ((ret = muxer->update_config(app, stream, hls_path, hls_fragment, hls_window)) != ERROR_SUCCESS) { srs_error("m3u8 muxer update config failed. ret=%d", ret); @@ -956,13 +971,25 @@ int SrsHlsCache::write_audio(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t pts, S } } + // for pure audio + // start new segment when duration overflow. + if (video_count == 0 && muxer->is_segment_overflow()) { + srs_trace("pure audio segment reap"); + if ((ret = reap_segment(muxer, af->pts)) != ERROR_SUCCESS) { + return ret; + } + } + return ret; } -int SrsHlsCache::write_video(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t dts, SrsCodecSample* sample) +int SrsHlsCache::write_video( + SrsCodec* codec, SrsHlsMuxer* muxer, int64_t dts, SrsCodecSample* sample) { int ret = ERROR_SUCCESS; + video_count++; + // write video to cache. if ((ret = cache_video(codec, sample)) != ERROR_SUCCESS) { return ret; @@ -974,26 +1001,11 @@ int SrsHlsCache::write_video(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t dts, S vf->sid = TS_VIDEO_AVC; vf->key = sample->frame_type == SrsCodecVideoAVCFrameKeyFrame; - // reopen the muxer for a gop - // close current segment, open a new segment, - // then write the key frame to the new segment. + // new segment when: + // 1. base on gop. + // 2. some gops duration overflow. if (vf->key && muxer->is_segment_overflow()) { - if ((ret = muxer->segment_close()) != ERROR_SUCCESS) { - srs_error("m3u8 muxer close segment failed. ret=%d", ret); - return ret; - } - - if ((ret = muxer->segment_open(vf->dts)) != ERROR_SUCCESS) { - srs_error("m3u8 muxer open segment failed. ret=%d", ret); - return ret; - } - - // TODO: flush audio before or after segment? - // segment open, flush the audio. - // @see: ngx_rtmp_hls_open_fragment - /* start fragment with audio to make iPhone happy */ - if ((ret = muxer->flush_audio(af, ab)) != ERROR_SUCCESS) { - srs_error("m3u8 muxer flush audio failed. ret=%d", ret); + if ((ret = reap_segment(muxer, vf->dts)) != ERROR_SUCCESS) { return ret; } } @@ -1004,8 +1016,31 @@ int SrsHlsCache::write_video(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t dts, S return ret; } - // write success, clear and free the buffer - vb->free(); + return ret; +} + +int SrsHlsCache::reap_segment(SrsHlsMuxer* muxer, int64_t segment_start_dts) +{ + int ret = ERROR_SUCCESS; + + if ((ret = muxer->segment_close()) != ERROR_SUCCESS) { + srs_error("m3u8 muxer close segment failed. ret=%d", ret); + return ret; + } + + if ((ret = muxer->segment_open(segment_start_dts)) != ERROR_SUCCESS) { + srs_error("m3u8 muxer open segment failed. ret=%d", ret); + return ret; + } + + // TODO: flush audio before or after segment? + // segment open, flush the audio. + // @see: ngx_rtmp_hls_open_fragment + /* start fragment with audio to make iPhone happy */ + if ((ret = muxer->flush_audio(af, ab)) != ERROR_SUCCESS) { + srs_error("m3u8 muxer flush audio failed. ret=%d", ret); + return ret; + } return ret; } diff --git a/trunk/src/app/srs_app_hls.hpp b/trunk/src/app/srs_app_hls.hpp index 89a465317..071a848e2 100644 --- a/trunk/src/app/srs_app_hls.hpp +++ b/trunk/src/app/srs_app_hls.hpp @@ -124,7 +124,7 @@ public: * update the segment duration. * @current_frame_dts the dts of frame, in tbn of ts. */ - virtual double update_duration(int64_t current_frame_dts); + virtual void update_duration(int64_t current_frame_dts); }; /** @@ -147,14 +147,6 @@ private: private: int file_index; std::string m3u8; -private: - /** - * for pure audio HLS application, - * the video count used to count the video, - * if zero and audio buffer overflow, reap the ts, - * just like we got a keyframe. - */ - u_int32_t video_count; private: /** * m3u8 segments. @@ -219,6 +211,14 @@ private: int64_t audio_buffer_start_pts; // time jitter for aac SrsHlsAacJitter* aac_jitter; +private: + /** + * for pure audio HLS application, + * the video count used to count the video, + * if zero and audio buffer overflow, reap the ts, + * just like we got a keyframe. + */ + u_int32_t video_count; public: SrsHlsCache(); virtual ~SrsHlsCache(); @@ -237,6 +237,13 @@ public: */ virtual int write_video(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t dts, SrsCodecSample* sample); private: + /** + * reopen the muxer for a new hls segment, + * close current segment, open a new segment, + * then write the key frame to the new segment. + * so, user must reap_segment then flush_video to hls muxer. + */ + virtual int reap_segment(SrsHlsMuxer* muxer, int64_t segment_start_dts); virtual int cache_audio(SrsCodec* codec, SrsCodecSample* sample); virtual int cache_video(SrsCodec* codec, SrsCodecSample* sample); }; diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index a4507b74a..5962c114a 100644 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // current release version #define VERSION_MAJOR "0" #define VERSION_MINOR "9" -#define VERSION_REVISION "23" +#define VERSION_REVISION "24" #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION // server info. #define RTMP_SIG_SRS_KEY "srs"