winlin

support pure audio hls. change to 0.9.24

@@ -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"