继续操作前请注册或者登录。
winlin

support hls republish

@@ -475,6 +475,7 @@ SrsHlsSegment::SrsHlsSegment() @@ -475,6 +475,7 @@ SrsHlsSegment::SrsHlsSegment()
475 sequence_no = 0; 475 sequence_no = 0;
476 muxer = new SrsTSMuxer(); 476 muxer = new SrsTSMuxer();
477 segment_start_dts = 0; 477 segment_start_dts = 0;
  478 + is_sequence_header = false;
478 } 479 }
479 480
480 SrsHlsSegment::~SrsHlsSegment() 481 SrsHlsSegment::~SrsHlsSegment()
@@ -589,6 +590,19 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts) @@ -589,6 +590,19 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts)
589 return ret; 590 return ret;
590 } 591 }
591 592
  593 +int SrsHlsMuxer::on_sequence_header()
  594 +{
  595 + int ret = ERROR_SUCCESS;
  596 +
  597 + srs_assert(current);
  598 +
  599 + // set the current segment to sequence header,
  600 + // when close the segement, it will write a discontinuity to m3u8 file.
  601 + current->is_sequence_header = true;
  602 +
  603 + return ret;
  604 +}
  605 +
592 bool SrsHlsMuxer::is_segment_overflow() 606 bool SrsHlsMuxer::is_segment_overflow()
593 { 607 {
594 srs_assert(current); 608 srs_assert(current);
@@ -810,7 +824,7 @@ int SrsHlsMuxer::_refresh_m3u8(int& fd, string m3u8_file) @@ -810,7 +824,7 @@ int SrsHlsMuxer::_refresh_m3u8(int& fd, string m3u8_file)
810 } 824 }
811 // TODO: maybe need to take an around value 825 // TODO: maybe need to take an around value
812 target_duration += 1; 826 target_duration += 1;
813 - char duration[34]; 827 + char duration[34]; // 23+10+1
814 len = snprintf(duration, sizeof(duration), "#EXT-X-TARGETDURATION:%d\n", target_duration); 828 len = snprintf(duration, sizeof(duration), "#EXT-X-TARGETDURATION:%d\n", target_duration);
815 if (::write(fd, duration, len) != len) { 829 if (::write(fd, duration, len) != len) {
816 ret = ERROR_HLS_WRITE_FAILED; 830 ret = ERROR_HLS_WRITE_FAILED;
@@ -823,15 +837,27 @@ int SrsHlsMuxer::_refresh_m3u8(int& fd, string m3u8_file) @@ -823,15 +837,27 @@ int SrsHlsMuxer::_refresh_m3u8(int& fd, string m3u8_file)
823 for (it = segments.begin(); it != segments.end(); ++it) { 837 for (it = segments.begin(); it != segments.end(); ++it) {
824 SrsHlsSegment* segment = *it; 838 SrsHlsSegment* segment = *it;
825 839
  840 + if (segment->is_sequence_header) {
  841 + // #EXT-X-DISCONTINUITY\n
  842 + char ext_discon[22]; // 21+1
  843 + len = snprintf(ext_discon, sizeof(ext_discon), "#EXT-X-DISCONTINUITY\n");
  844 + if (::write(fd, ext_discon, len) != len) {
  845 + ret = ERROR_HLS_WRITE_FAILED;
  846 + srs_error("write m3u8 segment discontinuity failed. ret=%d", ret);
  847 + return ret;
  848 + }
  849 + srs_verbose("write m3u8 segment discontinuity success.");
  850 + }
  851 +
826 // "#EXTINF:4294967295.208,\n" 852 // "#EXTINF:4294967295.208,\n"
827 - char ext_info[25]; 853 + char ext_info[25]; // 14+10+1
828 len = snprintf(ext_info, sizeof(ext_info), "#EXTINF:%.3f\n", segment->duration); 854 len = snprintf(ext_info, sizeof(ext_info), "#EXTINF:%.3f\n", segment->duration);
829 if (::write(fd, ext_info, len) != len) { 855 if (::write(fd, ext_info, len) != len) {
830 ret = ERROR_HLS_WRITE_FAILED; 856 ret = ERROR_HLS_WRITE_FAILED;
831 - srs_error("write m3u8 segment failed. ret=%d", ret); 857 + srs_error("write m3u8 segment info failed. ret=%d", ret);
832 return ret; 858 return ret;
833 } 859 }
834 - srs_verbose("write m3u8 segment success."); 860 + srs_verbose("write m3u8 segment info success.");
835 861
836 // file name 862 // file name
837 std::string filename = segment->uri; 863 std::string filename = segment->uri;
@@ -945,6 +971,17 @@ int SrsHlsCache::on_unpublish(SrsHlsMuxer* muxer) @@ -945,6 +971,17 @@ int SrsHlsCache::on_unpublish(SrsHlsMuxer* muxer)
945 return ret; 971 return ret;
946 } 972 }
947 973
  974 +int SrsHlsCache::on_sequence_header(SrsHlsMuxer* muxer)
  975 +{
  976 + // TODO: support discontinuity for the same stream
  977 + // currently we reap and insert discontinity when encoder republish,
  978 + // but actually, event when stream is not republish, the
  979 + // sequence header may change, for example,
  980 + // ffmpeg ingest a external rtmp stream and push to srs,
  981 + // when the sequence header changed, the stream is not republish.
  982 + return muxer->on_sequence_header();
  983 +}
  984 +
948 int SrsHlsCache::write_audio(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t pts, SrsCodecSample* sample) 985 int SrsHlsCache::write_audio(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t pts, SrsCodecSample* sample)
949 { 986 {
950 int ret = ERROR_SUCCESS; 987 int ret = ERROR_SUCCESS;
@@ -1336,7 +1373,7 @@ int SrsHls::on_audio(SrsSharedPtrMessage* audio) @@ -1336,7 +1373,7 @@ int SrsHls::on_audio(SrsSharedPtrMessage* audio)
1336 1373
1337 // ignore sequence header 1374 // ignore sequence header
1338 if (sample->aac_packet_type == SrsCodecAudioTypeSequenceHeader) { 1375 if (sample->aac_packet_type == SrsCodecAudioTypeSequenceHeader) {
1339 - return ret; 1376 + return hls_cache->on_sequence_header(muxer);
1340 } 1377 }
1341 1378
1342 if ((ret = jitter->correct(audio, 0, 0)) != ERROR_SUCCESS) { 1379 if ((ret = jitter->correct(audio, 0, 0)) != ERROR_SUCCESS) {
@@ -1381,7 +1418,7 @@ int SrsHls::on_video(SrsSharedPtrMessage* video) @@ -1381,7 +1418,7 @@ int SrsHls::on_video(SrsSharedPtrMessage* video)
1381 // ignore sequence header 1418 // ignore sequence header
1382 if (sample->frame_type == SrsCodecVideoAVCFrameKeyFrame 1419 if (sample->frame_type == SrsCodecVideoAVCFrameKeyFrame
1383 && sample->avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader) { 1420 && sample->avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader) {
1384 - return ret; 1421 + return hls_cache->on_sequence_header(muxer);
1385 } 1422 }
1386 1423
1387 if ((ret = jitter->correct(video, 0, 0)) != ERROR_SUCCESS) { 1424 if ((ret = jitter->correct(video, 0, 0)) != ERROR_SUCCESS) {
@@ -116,6 +116,8 @@ public: @@ -116,6 +116,8 @@ public:
116 SrsTSMuxer* muxer; 116 SrsTSMuxer* muxer;
117 // current segment start dts for m3u8 117 // current segment start dts for m3u8
118 int64_t segment_start_dts; 118 int64_t segment_start_dts;
  119 + // whether current segement is sequence header.
  120 + bool is_sequence_header;
119 121
120 SrsHlsSegment(); 122 SrsHlsSegment();
121 virtual ~SrsHlsSegment(); 123 virtual ~SrsHlsSegment();
@@ -167,6 +169,7 @@ public: @@ -167,6 +169,7 @@ public:
167 * use 0 for the first segment of HLS. 169 * use 0 for the first segment of HLS.
168 */ 170 */
169 virtual int segment_open(int64_t segment_start_dts); 171 virtual int segment_open(int64_t segment_start_dts);
  172 + virtual int on_sequence_header();
170 /** 173 /**
171 * whether video overflow, 174 * whether video overflow,
172 * that is whether the current segment duration >= the segment in config 175 * that is whether the current segment duration >= the segment in config
@@ -233,6 +236,13 @@ public: @@ -233,6 +236,13 @@ public:
233 virtual int on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment_start_dts); 236 virtual int on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment_start_dts);
234 virtual int on_unpublish(SrsHlsMuxer* muxer); 237 virtual int on_unpublish(SrsHlsMuxer* muxer);
235 /** 238 /**
  239 + * when get sequence header,
  240 + * must write a #EXT-X-DISCONTINUITY to m3u8.
  241 + * @see: hls-m3u8-draft-pantos-http-live-streaming-12.txt
  242 + * @see: 3.4.11. EXT-X-DISCONTINUITY
  243 + */
  244 + virtual int on_sequence_header(SrsHlsMuxer* muxer);
  245 + /**
236 * write audio to cache, if need to flush, flush to muxer. 246 * write audio to cache, if need to flush, flush to muxer.
237 */ 247 */
238 virtual int write_audio(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t pts, SrsCodecSample* sample); 248 virtual int write_audio(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t pts, SrsCodecSample* sample);
@@ -41,6 +41,7 @@ void srs_update_system_time_ms() @@ -41,6 +41,7 @@ void srs_update_system_time_ms()
41 41
42 gettimeofday(&now, NULL); 42 gettimeofday(&now, NULL);
43 43
  44 + // @see: https://github.com/winlinvip/simple-rtmp-server/issues/35
44 // we must convert the tv_sec/tv_usec to int64_t. 45 // we must convert the tv_sec/tv_usec to int64_t.
45 _srs_system_time_us_cache = ((int64_t)now.tv_sec) * 1000 * 1000 + (int64_t)now.tv_usec; 46 _srs_system_time_us_cache = ((int64_t)now.tv_sec) * 1000 * 1000 + (int64_t)now.tv_usec;
46 47