正在显示
3 个修改的文件
包含
81 行增加
和
39 行删除
| @@ -44,7 +44,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -44,7 +44,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 44 | #include <srs_app_pithy_print.hpp> | 44 | #include <srs_app_pithy_print.hpp> |
| 45 | 45 | ||
| 46 | // max PES packets size to flush the video. | 46 | // max PES packets size to flush the video. |
| 47 | -#define SRS_HLS_AUDIO_CACHE_SIZE 512 * 1024 | 47 | +#define SRS_HLS_AUDIO_CACHE_SIZE 1024 * 1024 |
| 48 | 48 | ||
| 49 | // @see: NGX_RTMP_HLS_DELAY, | 49 | // @see: NGX_RTMP_HLS_DELAY, |
| 50 | // 63000: 700ms, ts_tbn=90000 | 50 | // 63000: 700ms, ts_tbn=90000 |
| @@ -481,12 +481,20 @@ SrsHlsSegment::~SrsHlsSegment() | @@ -481,12 +481,20 @@ SrsHlsSegment::~SrsHlsSegment() | ||
| 481 | srs_freep(muxer); | 481 | srs_freep(muxer); |
| 482 | } | 482 | } |
| 483 | 483 | ||
| 484 | -double SrsHlsSegment::update_duration(int64_t current_frame_dts) | 484 | +void SrsHlsSegment::update_duration(int64_t current_frame_dts) |
| 485 | { | 485 | { |
| 486 | + // we use video/audio to update segment duration, | ||
| 487 | + // so when reap segment, some previous audio frame will | ||
| 488 | + // update the segment duration, which is nagetive, | ||
| 489 | + // just ignore it. | ||
| 490 | + if (current_frame_dts < segment_start_dts) { | ||
| 491 | + return; | ||
| 492 | + } | ||
| 493 | + | ||
| 486 | duration = (current_frame_dts - segment_start_dts) / 90000.0; | 494 | duration = (current_frame_dts - segment_start_dts) / 90000.0; |
| 487 | srs_assert(duration >= 0); | 495 | srs_assert(duration >= 0); |
| 488 | 496 | ||
| 489 | - return duration; | 497 | + return; |
| 490 | } | 498 | } |
| 491 | 499 | ||
| 492 | SrsHlsAacJitter::SrsHlsAacJitter() | 500 | SrsHlsAacJitter::SrsHlsAacJitter() |
| @@ -503,7 +511,6 @@ SrsHlsMuxer::SrsHlsMuxer() | @@ -503,7 +511,6 @@ SrsHlsMuxer::SrsHlsMuxer() | ||
| 503 | hls_fragment = hls_window = 0; | 511 | hls_fragment = hls_window = 0; |
| 504 | file_index = 0; | 512 | file_index = 0; |
| 505 | current = NULL; | 513 | current = NULL; |
| 506 | - video_count = 0; | ||
| 507 | } | 514 | } |
| 508 | 515 | ||
| 509 | SrsHlsMuxer::~SrsHlsMuxer() | 516 | SrsHlsMuxer::~SrsHlsMuxer() |
| @@ -542,9 +549,6 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts) | @@ -542,9 +549,6 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts) | ||
| 542 | return ret; | 549 | return ret; |
| 543 | } | 550 | } |
| 544 | 551 | ||
| 545 | - // reset video count for new publish session. | ||
| 546 | - video_count = 0; | ||
| 547 | - | ||
| 548 | // TODO: create all parents dirs. | 552 | // TODO: create all parents dirs. |
| 549 | // create dir for app. | 553 | // create dir for app. |
| 550 | if ((ret = create_dir()) != ERROR_SUCCESS) { | 554 | if ((ret = create_dir()) != ERROR_SUCCESS) { |
| @@ -605,6 +609,9 @@ int SrsHlsMuxer::flush_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab) | @@ -605,6 +609,9 @@ int SrsHlsMuxer::flush_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab) | ||
| 605 | return ret; | 609 | return ret; |
| 606 | } | 610 | } |
| 607 | 611 | ||
| 612 | + // update the duration of segment. | ||
| 613 | + current->update_duration(af->pts); | ||
| 614 | + | ||
| 608 | if ((ret = current->muxer->write_audio(af, ab)) != ERROR_SUCCESS) { | 615 | if ((ret = current->muxer->write_audio(af, ab)) != ERROR_SUCCESS) { |
| 609 | return ret; | 616 | return ret; |
| 610 | } | 617 | } |
| @@ -635,6 +642,9 @@ int SrsHlsMuxer::flush_video( | @@ -635,6 +642,9 @@ int SrsHlsMuxer::flush_video( | ||
| 635 | return ret; | 642 | return ret; |
| 636 | } | 643 | } |
| 637 | 644 | ||
| 645 | + // write success, clear and free the buffer | ||
| 646 | + vb->free(); | ||
| 647 | + | ||
| 638 | return ret; | 648 | return ret; |
| 639 | } | 649 | } |
| 640 | 650 | ||
| @@ -860,6 +870,8 @@ SrsHlsCache::SrsHlsCache() | @@ -860,6 +870,8 @@ SrsHlsCache::SrsHlsCache() | ||
| 860 | 870 | ||
| 861 | af = new SrsMpegtsFrame(); | 871 | af = new SrsMpegtsFrame(); |
| 862 | vf = new SrsMpegtsFrame(); | 872 | vf = new SrsMpegtsFrame(); |
| 873 | + | ||
| 874 | + video_count = 0; | ||
| 863 | } | 875 | } |
| 864 | 876 | ||
| 865 | SrsHlsCache::~SrsHlsCache() | 877 | SrsHlsCache::~SrsHlsCache() |
| @@ -890,6 +902,9 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment | @@ -890,6 +902,9 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment | ||
| 890 | // get the hls path config | 902 | // get the hls path config |
| 891 | std::string hls_path = _srs_config->get_hls_path(vhost); | 903 | std::string hls_path = _srs_config->get_hls_path(vhost); |
| 892 | 904 | ||
| 905 | + // reset video count for new publish session. | ||
| 906 | + video_count = 0; | ||
| 907 | + | ||
| 893 | // open muxer | 908 | // open muxer |
| 894 | if ((ret = muxer->update_config(app, stream, hls_path, hls_fragment, hls_window)) != ERROR_SUCCESS) { | 909 | if ((ret = muxer->update_config(app, stream, hls_path, hls_fragment, hls_window)) != ERROR_SUCCESS) { |
| 895 | srs_error("m3u8 muxer update config failed. ret=%d", ret); | 910 | 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 | @@ -956,13 +971,25 @@ int SrsHlsCache::write_audio(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t pts, S | ||
| 956 | } | 971 | } |
| 957 | } | 972 | } |
| 958 | 973 | ||
| 974 | + // for pure audio | ||
| 975 | + // start new segment when duration overflow. | ||
| 976 | + if (video_count == 0 && muxer->is_segment_overflow()) { | ||
| 977 | + srs_trace("pure audio segment reap"); | ||
| 978 | + if ((ret = reap_segment(muxer, af->pts)) != ERROR_SUCCESS) { | ||
| 979 | + return ret; | ||
| 980 | + } | ||
| 981 | + } | ||
| 982 | + | ||
| 959 | return ret; | 983 | return ret; |
| 960 | } | 984 | } |
| 961 | 985 | ||
| 962 | -int SrsHlsCache::write_video(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t dts, SrsCodecSample* sample) | 986 | +int SrsHlsCache::write_video( |
| 987 | + SrsCodec* codec, SrsHlsMuxer* muxer, int64_t dts, SrsCodecSample* sample) | ||
| 963 | { | 988 | { |
| 964 | int ret = ERROR_SUCCESS; | 989 | int ret = ERROR_SUCCESS; |
| 965 | 990 | ||
| 991 | + video_count++; | ||
| 992 | + | ||
| 966 | // write video to cache. | 993 | // write video to cache. |
| 967 | if ((ret = cache_video(codec, sample)) != ERROR_SUCCESS) { | 994 | if ((ret = cache_video(codec, sample)) != ERROR_SUCCESS) { |
| 968 | return ret; | 995 | return ret; |
| @@ -974,26 +1001,11 @@ int SrsHlsCache::write_video(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t dts, S | @@ -974,26 +1001,11 @@ int SrsHlsCache::write_video(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t dts, S | ||
| 974 | vf->sid = TS_VIDEO_AVC; | 1001 | vf->sid = TS_VIDEO_AVC; |
| 975 | vf->key = sample->frame_type == SrsCodecVideoAVCFrameKeyFrame; | 1002 | vf->key = sample->frame_type == SrsCodecVideoAVCFrameKeyFrame; |
| 976 | 1003 | ||
| 977 | - // reopen the muxer for a gop | ||
| 978 | - // close current segment, open a new segment, | ||
| 979 | - // then write the key frame to the new segment. | 1004 | + // new segment when: |
| 1005 | + // 1. base on gop. | ||
| 1006 | + // 2. some gops duration overflow. | ||
| 980 | if (vf->key && muxer->is_segment_overflow()) { | 1007 | if (vf->key && muxer->is_segment_overflow()) { |
| 981 | - if ((ret = muxer->segment_close()) != ERROR_SUCCESS) { | ||
| 982 | - srs_error("m3u8 muxer close segment failed. ret=%d", ret); | ||
| 983 | - return ret; | ||
| 984 | - } | ||
| 985 | - | ||
| 986 | - if ((ret = muxer->segment_open(vf->dts)) != ERROR_SUCCESS) { | ||
| 987 | - srs_error("m3u8 muxer open segment failed. ret=%d", ret); | ||
| 988 | - return ret; | ||
| 989 | - } | ||
| 990 | - | ||
| 991 | - // TODO: flush audio before or after segment? | ||
| 992 | - // segment open, flush the audio. | ||
| 993 | - // @see: ngx_rtmp_hls_open_fragment | ||
| 994 | - /* start fragment with audio to make iPhone happy */ | ||
| 995 | - if ((ret = muxer->flush_audio(af, ab)) != ERROR_SUCCESS) { | ||
| 996 | - srs_error("m3u8 muxer flush audio failed. ret=%d", ret); | 1008 | + if ((ret = reap_segment(muxer, vf->dts)) != ERROR_SUCCESS) { |
| 997 | return ret; | 1009 | return ret; |
| 998 | } | 1010 | } |
| 999 | } | 1011 | } |
| @@ -1004,8 +1016,31 @@ int SrsHlsCache::write_video(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t dts, S | @@ -1004,8 +1016,31 @@ int SrsHlsCache::write_video(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t dts, S | ||
| 1004 | return ret; | 1016 | return ret; |
| 1005 | } | 1017 | } |
| 1006 | 1018 | ||
| 1007 | - // write success, clear and free the buffer | ||
| 1008 | - vb->free(); | 1019 | + return ret; |
| 1020 | +} | ||
| 1021 | + | ||
| 1022 | +int SrsHlsCache::reap_segment(SrsHlsMuxer* muxer, int64_t segment_start_dts) | ||
| 1023 | +{ | ||
| 1024 | + int ret = ERROR_SUCCESS; | ||
| 1025 | + | ||
| 1026 | + if ((ret = muxer->segment_close()) != ERROR_SUCCESS) { | ||
| 1027 | + srs_error("m3u8 muxer close segment failed. ret=%d", ret); | ||
| 1028 | + return ret; | ||
| 1029 | + } | ||
| 1030 | + | ||
| 1031 | + if ((ret = muxer->segment_open(segment_start_dts)) != ERROR_SUCCESS) { | ||
| 1032 | + srs_error("m3u8 muxer open segment failed. ret=%d", ret); | ||
| 1033 | + return ret; | ||
| 1034 | + } | ||
| 1035 | + | ||
| 1036 | + // TODO: flush audio before or after segment? | ||
| 1037 | + // segment open, flush the audio. | ||
| 1038 | + // @see: ngx_rtmp_hls_open_fragment | ||
| 1039 | + /* start fragment with audio to make iPhone happy */ | ||
| 1040 | + if ((ret = muxer->flush_audio(af, ab)) != ERROR_SUCCESS) { | ||
| 1041 | + srs_error("m3u8 muxer flush audio failed. ret=%d", ret); | ||
| 1042 | + return ret; | ||
| 1043 | + } | ||
| 1009 | 1044 | ||
| 1010 | return ret; | 1045 | return ret; |
| 1011 | } | 1046 | } |
| @@ -124,7 +124,7 @@ public: | @@ -124,7 +124,7 @@ public: | ||
| 124 | * update the segment duration. | 124 | * update the segment duration. |
| 125 | * @current_frame_dts the dts of frame, in tbn of ts. | 125 | * @current_frame_dts the dts of frame, in tbn of ts. |
| 126 | */ | 126 | */ |
| 127 | - virtual double update_duration(int64_t current_frame_dts); | 127 | + virtual void update_duration(int64_t current_frame_dts); |
| 128 | }; | 128 | }; |
| 129 | 129 | ||
| 130 | /** | 130 | /** |
| @@ -149,14 +149,6 @@ private: | @@ -149,14 +149,6 @@ private: | ||
| 149 | std::string m3u8; | 149 | std::string m3u8; |
| 150 | private: | 150 | private: |
| 151 | /** | 151 | /** |
| 152 | - * for pure audio HLS application, | ||
| 153 | - * the video count used to count the video, | ||
| 154 | - * if zero and audio buffer overflow, reap the ts, | ||
| 155 | - * just like we got a keyframe. | ||
| 156 | - */ | ||
| 157 | - u_int32_t video_count; | ||
| 158 | -private: | ||
| 159 | - /** | ||
| 160 | * m3u8 segments. | 152 | * m3u8 segments. |
| 161 | */ | 153 | */ |
| 162 | std::vector<SrsHlsSegment*> segments; | 154 | std::vector<SrsHlsSegment*> segments; |
| @@ -219,6 +211,14 @@ private: | @@ -219,6 +211,14 @@ private: | ||
| 219 | int64_t audio_buffer_start_pts; | 211 | int64_t audio_buffer_start_pts; |
| 220 | // time jitter for aac | 212 | // time jitter for aac |
| 221 | SrsHlsAacJitter* aac_jitter; | 213 | SrsHlsAacJitter* aac_jitter; |
| 214 | +private: | ||
| 215 | + /** | ||
| 216 | + * for pure audio HLS application, | ||
| 217 | + * the video count used to count the video, | ||
| 218 | + * if zero and audio buffer overflow, reap the ts, | ||
| 219 | + * just like we got a keyframe. | ||
| 220 | + */ | ||
| 221 | + u_int32_t video_count; | ||
| 222 | public: | 222 | public: |
| 223 | SrsHlsCache(); | 223 | SrsHlsCache(); |
| 224 | virtual ~SrsHlsCache(); | 224 | virtual ~SrsHlsCache(); |
| @@ -237,6 +237,13 @@ public: | @@ -237,6 +237,13 @@ public: | ||
| 237 | */ | 237 | */ |
| 238 | virtual int write_video(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t dts, SrsCodecSample* sample); | 238 | virtual int write_video(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t dts, SrsCodecSample* sample); |
| 239 | private: | 239 | private: |
| 240 | + /** | ||
| 241 | + * reopen the muxer for a new hls segment, | ||
| 242 | + * close current segment, open a new segment, | ||
| 243 | + * then write the key frame to the new segment. | ||
| 244 | + * so, user must reap_segment then flush_video to hls muxer. | ||
| 245 | + */ | ||
| 246 | + virtual int reap_segment(SrsHlsMuxer* muxer, int64_t segment_start_dts); | ||
| 240 | virtual int cache_audio(SrsCodec* codec, SrsCodecSample* sample); | 247 | virtual int cache_audio(SrsCodec* codec, SrsCodecSample* sample); |
| 241 | virtual int cache_video(SrsCodec* codec, SrsCodecSample* sample); | 248 | virtual int cache_video(SrsCodec* codec, SrsCodecSample* sample); |
| 242 | }; | 249 | }; |
| @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 31 | // current release version | 31 | // current release version |
| 32 | #define VERSION_MAJOR "0" | 32 | #define VERSION_MAJOR "0" |
| 33 | #define VERSION_MINOR "9" | 33 | #define VERSION_MINOR "9" |
| 34 | -#define VERSION_REVISION "23" | 34 | +#define VERSION_REVISION "24" |
| 35 | #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION | 35 | #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION |
| 36 | // server info. | 36 | // server info. |
| 37 | #define RTMP_SIG_SRS_KEY "srs" | 37 | #define RTMP_SIG_SRS_KEY "srs" |
-
请 注册 或 登录 后发表评论