diff --git a/trunk/src/app/srs_app_hls.cpp b/trunk/src/app/srs_app_hls.cpp index 0e72fa464..41d22b1df 100644 --- a/trunk/src/app/srs_app_hls.cpp +++ b/trunk/src/app/srs_app_hls.cpp @@ -475,6 +475,7 @@ SrsHlsSegment::SrsHlsSegment() sequence_no = 0; muxer = new SrsTSMuxer(); segment_start_dts = 0; + is_sequence_header = false; } SrsHlsSegment::~SrsHlsSegment() @@ -589,6 +590,19 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts) return ret; } +int SrsHlsMuxer::on_sequence_header() +{ + int ret = ERROR_SUCCESS; + + srs_assert(current); + + // set the current segment to sequence header, + // when close the segement, it will write a discontinuity to m3u8 file. + current->is_sequence_header = true; + + return ret; +} + bool SrsHlsMuxer::is_segment_overflow() { srs_assert(current); @@ -810,7 +824,7 @@ int SrsHlsMuxer::_refresh_m3u8(int& fd, string m3u8_file) } // TODO: maybe need to take an around value target_duration += 1; - char duration[34]; + char duration[34]; // 23+10+1 len = snprintf(duration, sizeof(duration), "#EXT-X-TARGETDURATION:%d\n", target_duration); if (::write(fd, duration, len) != len) { ret = ERROR_HLS_WRITE_FAILED; @@ -823,15 +837,27 @@ int SrsHlsMuxer::_refresh_m3u8(int& fd, string m3u8_file) for (it = segments.begin(); it != segments.end(); ++it) { SrsHlsSegment* segment = *it; + if (segment->is_sequence_header) { + // #EXT-X-DISCONTINUITY\n + char ext_discon[22]; // 21+1 + len = snprintf(ext_discon, sizeof(ext_discon), "#EXT-X-DISCONTINUITY\n"); + if (::write(fd, ext_discon, len) != len) { + ret = ERROR_HLS_WRITE_FAILED; + srs_error("write m3u8 segment discontinuity failed. ret=%d", ret); + return ret; + } + srs_verbose("write m3u8 segment discontinuity success."); + } + // "#EXTINF:4294967295.208,\n" - char ext_info[25]; + char ext_info[25]; // 14+10+1 len = snprintf(ext_info, sizeof(ext_info), "#EXTINF:%.3f\n", segment->duration); if (::write(fd, ext_info, len) != len) { ret = ERROR_HLS_WRITE_FAILED; - srs_error("write m3u8 segment failed. ret=%d", ret); + srs_error("write m3u8 segment info failed. ret=%d", ret); return ret; } - srs_verbose("write m3u8 segment success."); + srs_verbose("write m3u8 segment info success."); // file name std::string filename = segment->uri; @@ -944,6 +970,17 @@ int SrsHlsCache::on_unpublish(SrsHlsMuxer* muxer) return ret; } + +int SrsHlsCache::on_sequence_header(SrsHlsMuxer* muxer) +{ + // TODO: support discontinuity for the same stream + // currently we reap and insert discontinity when encoder republish, + // but actually, event when stream is not republish, the + // sequence header may change, for example, + // ffmpeg ingest a external rtmp stream and push to srs, + // when the sequence header changed, the stream is not republish. + return muxer->on_sequence_header(); +} int SrsHlsCache::write_audio(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t pts, SrsCodecSample* sample) { @@ -1336,7 +1373,7 @@ int SrsHls::on_audio(SrsSharedPtrMessage* audio) // ignore sequence header if (sample->aac_packet_type == SrsCodecAudioTypeSequenceHeader) { - return ret; + return hls_cache->on_sequence_header(muxer); } if ((ret = jitter->correct(audio, 0, 0)) != ERROR_SUCCESS) { @@ -1381,7 +1418,7 @@ int SrsHls::on_video(SrsSharedPtrMessage* video) // ignore sequence header if (sample->frame_type == SrsCodecVideoAVCFrameKeyFrame && sample->avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader) { - return ret; + return hls_cache->on_sequence_header(muxer); } if ((ret = jitter->correct(video, 0, 0)) != ERROR_SUCCESS) { diff --git a/trunk/src/app/srs_app_hls.hpp b/trunk/src/app/srs_app_hls.hpp index 01121c9e5..dd42fcca5 100644 --- a/trunk/src/app/srs_app_hls.hpp +++ b/trunk/src/app/srs_app_hls.hpp @@ -116,6 +116,8 @@ public: SrsTSMuxer* muxer; // current segment start dts for m3u8 int64_t segment_start_dts; + // whether current segement is sequence header. + bool is_sequence_header; SrsHlsSegment(); virtual ~SrsHlsSegment(); @@ -167,6 +169,7 @@ public: * use 0 for the first segment of HLS. */ virtual int segment_open(int64_t segment_start_dts); + virtual int on_sequence_header(); /** * whether video overflow, * that is whether the current segment duration >= the segment in config @@ -233,6 +236,13 @@ public: virtual int on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment_start_dts); virtual int on_unpublish(SrsHlsMuxer* muxer); /** + * when get sequence header, + * must write a #EXT-X-DISCONTINUITY to m3u8. + * @see: hls-m3u8-draft-pantos-http-live-streaming-12.txt + * @see: 3.4.11. EXT-X-DISCONTINUITY + */ + virtual int on_sequence_header(SrsHlsMuxer* muxer); + /** * write audio to cache, if need to flush, flush to muxer. */ virtual int write_audio(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t pts, SrsCodecSample* sample); diff --git a/trunk/src/core/srs_core.cpp b/trunk/src/core/srs_core.cpp index 9d600b6b5..e2450a109 100644 --- a/trunk/src/core/srs_core.cpp +++ b/trunk/src/core/srs_core.cpp @@ -41,6 +41,7 @@ void srs_update_system_time_ms() gettimeofday(&now, NULL); + // @see: https://github.com/winlinvip/simple-rtmp-server/issues/35 // we must convert the tv_sec/tv_usec to int64_t. _srs_system_time_us_cache = ((int64_t)now.tv_sec) * 1000 * 1000 + (int64_t)now.tv_usec;