正在显示
3 个修改的文件
包含
54 行增加
和
6 行删除
| @@ -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 |
-
请 注册 或 登录 后发表评论