fix the aac jump bug on iphone, correct the audio pts, use audio buffer and flush audio
正在显示
8 个修改的文件
包含
281 行增加
和
72 行删除
@@ -34,7 +34,7 @@ For example, use ffmpeg to publish: | @@ -34,7 +34,7 @@ For example, use ffmpeg to publish: | ||
34 | step 5: play live stream <br/> | 34 | step 5: play live stream <br/> |
35 | <pre> | 35 | <pre> |
36 | rtmp url: rtmp://127.0.0.1:1935/live/livestream | 36 | rtmp url: rtmp://127.0.0.1:1935/live/livestream |
37 | -m3u8 url: http://127.0.0.1:1935/live/livestream.m3u8 | 37 | +m3u8 url: http://127.0.0.1:80/live/livestream.m3u8 |
38 | </pre> | 38 | </pre> |
39 | 39 | ||
40 | ### Summary | 40 | ### Summary |
@@ -13,8 +13,8 @@ vhost __defaultVhost__ { | @@ -13,8 +13,8 @@ vhost __defaultVhost__ { | ||
13 | gop_cache on; | 13 | gop_cache on; |
14 | hls on; | 14 | hls on; |
15 | hls_path ./objs/nginx/html; | 15 | hls_path ./objs/nginx/html; |
16 | - hls_fragment 10; | ||
17 | - hls_window 60; | 16 | + hls_fragment 5; |
17 | + hls_window 30; | ||
18 | } | 18 | } |
19 | # the vhost disabled. | 19 | # the vhost disabled. |
20 | vhost removed.vhost.com { | 20 | vhost removed.vhost.com { |
@@ -159,7 +159,7 @@ int SrsCodec::audio_aac_demux(int8_t* data, int size, SrsCodecSample* sample) | @@ -159,7 +159,7 @@ int SrsCodec::audio_aac_demux(int8_t* data, int size, SrsCodecSample* sample) | ||
159 | 159 | ||
160 | int8_t sound_type = sound_format & 0x01; | 160 | int8_t sound_type = sound_format & 0x01; |
161 | int8_t sound_size = (sound_format >> 1) & 0x01; | 161 | int8_t sound_size = (sound_format >> 1) & 0x01; |
162 | - int8_t sound_rate = (sound_format >> 2) & 0x01; | 162 | + int8_t sound_rate = (sound_format >> 2) & 0x03; |
163 | sound_format = (sound_format >> 4) & 0x0f; | 163 | sound_format = (sound_format >> 4) & 0x0f; |
164 | 164 | ||
165 | audio_codec_id = sound_format; | 165 | audio_codec_id = sound_format; |
@@ -167,6 +167,25 @@ int SrsCodec::audio_aac_demux(int8_t* data, int size, SrsCodecSample* sample) | @@ -167,6 +167,25 @@ int SrsCodec::audio_aac_demux(int8_t* data, int size, SrsCodecSample* sample) | ||
167 | sample->sound_rate = (SrsCodecAudioSampleRate)sound_rate; | 167 | sample->sound_rate = (SrsCodecAudioSampleRate)sound_rate; |
168 | sample->sound_size = (SrsCodecAudioSampleSize)sound_size; | 168 | sample->sound_size = (SrsCodecAudioSampleSize)sound_size; |
169 | 169 | ||
170 | + // reset the sample rate by sequence header | ||
171 | + static int aac_sample_rates[] = { | ||
172 | + 96000, 88200, 64000, 48000, | ||
173 | + 44100, 32000, 24000, 22050, | ||
174 | + 16000, 12000, 11025, 8000, | ||
175 | + 7350, 0, 0, 0 | ||
176 | + }; | ||
177 | + switch (aac_sample_rates[aac_sample_rate]) { | ||
178 | + case 11025: | ||
179 | + sample->sound_rate = SrsCodecAudioSampleRate11025; | ||
180 | + break; | ||
181 | + case 22050: | ||
182 | + sample->sound_rate = SrsCodecAudioSampleRate22050; | ||
183 | + break; | ||
184 | + case 44100: | ||
185 | + sample->sound_rate = SrsCodecAudioSampleRate44100; | ||
186 | + break; | ||
187 | + }; | ||
188 | + | ||
170 | // only support aac | 189 | // only support aac |
171 | if (audio_codec_id != SrsCodecAudioAAC) { | 190 | if (audio_codec_id != SrsCodecAudioAAC) { |
172 | ret = ERROR_HLS_DECODE_ERROR; | 191 | ret = ERROR_HLS_DECODE_ERROR; |
@@ -40,6 +40,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -40,6 +40,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
40 | #define SRS_CONF_DEFAULT_HLS_PATH "./objs/nginx/html" | 40 | #define SRS_CONF_DEFAULT_HLS_PATH "./objs/nginx/html" |
41 | #define SRS_CONF_DEFAULT_HLS_FRAGMENT 10 | 41 | #define SRS_CONF_DEFAULT_HLS_FRAGMENT 10 |
42 | #define SRS_CONF_DEFAULT_HLS_WINDOW 60 | 42 | #define SRS_CONF_DEFAULT_HLS_WINDOW 60 |
43 | +// in ms, for HLS aac sync time. | ||
44 | +#define SRS_CONF_DEFAULT_AAC_SYNC 100 | ||
45 | +// in ms, for HLS aac flush the audio | ||
46 | +#define SRS_CONF_DEFAULT_AAC_DELAY 300 | ||
43 | 47 | ||
44 | class SrsFileBuffer | 48 | class SrsFileBuffer |
45 | { | 49 | { |
@@ -269,9 +269,6 @@ public: | @@ -269,9 +269,6 @@ public: | ||
269 | } | 269 | } |
270 | } | 270 | } |
271 | 271 | ||
272 | - // write success, clear and free the buffer | ||
273 | - buffer->free(); | ||
274 | - | ||
275 | return ret; | 272 | return ret; |
276 | } | 273 | } |
277 | private: | 274 | private: |
@@ -360,16 +357,79 @@ SrsM3u8Segment::~SrsM3u8Segment() | @@ -360,16 +357,79 @@ SrsM3u8Segment::~SrsM3u8Segment() | ||
360 | srs_freep(muxer); | 357 | srs_freep(muxer); |
361 | } | 358 | } |
362 | 359 | ||
363 | -SrsHLS::SrsHLS() | 360 | +SrsHlsAacJitter::SrsHlsAacJitter() |
361 | +{ | ||
362 | + base_pts = 0; | ||
363 | + nb_samples = 0; | ||
364 | + | ||
365 | + // TODO: config it, 0 means no adjust | ||
366 | + sync_ms = SRS_CONF_DEFAULT_AAC_SYNC; | ||
367 | +} | ||
368 | + | ||
369 | +SrsHlsAacJitter::~SrsHlsAacJitter() | ||
370 | +{ | ||
371 | +} | ||
372 | + | ||
373 | +int64_t SrsHlsAacJitter::on_buffer_start(int64_t flv_pts, int sample_rate) | ||
374 | +{ | ||
375 | + // 0 = 5.5 kHz = 5512 Hz | ||
376 | + // 1 = 11 kHz = 11025 Hz | ||
377 | + // 2 = 22 kHz = 22050 Hz | ||
378 | + // 3 = 44 kHz = 44100 Hz | ||
379 | + static int flv_sample_rates[] = {5512, 11025, 22050, 44100}; | ||
380 | + int flv_sample_rate = flv_sample_rates[sample_rate & 0x03]; | ||
381 | + | ||
382 | + // sync time set to 0, donot adjust the aac timestamp. | ||
383 | + if (!sync_ms) { | ||
384 | + return flv_pts; | ||
385 | + } | ||
386 | + | ||
387 | + // @see: ngx_rtmp_hls_audio | ||
388 | + /* TODO: We assume here AAC frame size is 1024 | ||
389 | + * Need to handle AAC frames with frame size of 960 */ | ||
390 | + int64_t est_pts = base_pts + nb_samples * 90000LL * 1024LL / flv_sample_rate; | ||
391 | + int64_t dpts = (int64_t) (est_pts - flv_pts); | ||
392 | + | ||
393 | + if (dpts <= (int64_t) sync_ms * 90 && dpts >= (int64_t) sync_ms * -90) { | ||
394 | + srs_info("HLS correct aac pts " | ||
395 | + "from %"PRId64" to %"PRId64", base=%"PRId64", nb_samples=%d, sample_rate=%d", | ||
396 | + flv_pts, est_pts, nb_samples, flv_sample_rate, base_pts); | ||
397 | + | ||
398 | + nb_samples++; | ||
399 | + | ||
400 | + return est_pts; | ||
401 | + } | ||
402 | + | ||
403 | + // resync | ||
404 | + srs_trace("HLS aac resync, dpts=%"PRId64", pts=%"PRId64 | ||
405 | + ", base=%"PRId64", nb_samples=%"PRId64", sample_rate=%d", | ||
406 | + dpts, flv_pts, base_pts, nb_samples, flv_sample_rate); | ||
407 | + | ||
408 | + base_pts = flv_pts; | ||
409 | + nb_samples = 1; | ||
410 | + | ||
411 | + return flv_pts; | ||
412 | +} | ||
413 | + | ||
414 | +void SrsHlsAacJitter::on_buffer_continue() | ||
415 | +{ | ||
416 | + nb_samples++; | ||
417 | +} | ||
418 | + | ||
419 | +SrsHls::SrsHls() | ||
364 | { | 420 | { |
365 | hls_enabled = false; | 421 | hls_enabled = false; |
366 | codec = new SrsCodec(); | 422 | codec = new SrsCodec(); |
367 | sample = new SrsCodecSample(); | 423 | sample = new SrsCodecSample(); |
368 | current = NULL; | 424 | current = NULL; |
369 | jitter = new SrsRtmpJitter(); | 425 | jitter = new SrsRtmpJitter(); |
426 | + aac_jitter = new SrsHlsAacJitter(); | ||
370 | file_index = 0; | 427 | file_index = 0; |
371 | - m3u8_dts = stream_dts = 0; | 428 | + audio_buffer_start_pts = m3u8_dts = stream_dts = 0; |
372 | hls_fragment = hls_window = 0; | 429 | hls_fragment = hls_window = 0; |
430 | + | ||
431 | + // TODO: config it. | ||
432 | + audio_delay = SRS_CONF_DEFAULT_AAC_DELAY; | ||
373 | 433 | ||
374 | audio_buffer = new SrsCodecBuffer(); | 434 | audio_buffer = new SrsCodecBuffer(); |
375 | video_buffer = new SrsCodecBuffer(); | 435 | video_buffer = new SrsCodecBuffer(); |
@@ -378,11 +438,12 @@ SrsHLS::SrsHLS() | @@ -378,11 +438,12 @@ SrsHLS::SrsHLS() | ||
378 | video_frame = new SrsMpegtsFrame(); | 438 | video_frame = new SrsMpegtsFrame(); |
379 | } | 439 | } |
380 | 440 | ||
381 | -SrsHLS::~SrsHLS() | 441 | +SrsHls::~SrsHls() |
382 | { | 442 | { |
383 | srs_freep(codec); | 443 | srs_freep(codec); |
384 | srs_freep(sample); | 444 | srs_freep(sample); |
385 | srs_freep(jitter); | 445 | srs_freep(jitter); |
446 | + srs_freep(aac_jitter); | ||
386 | 447 | ||
387 | std::vector<SrsM3u8Segment*>::iterator it; | 448 | std::vector<SrsM3u8Segment*>::iterator it; |
388 | for (it = segments.begin(); it != segments.end(); ++it) { | 449 | for (it = segments.begin(); it != segments.end(); ++it) { |
@@ -403,7 +464,7 @@ SrsHLS::~SrsHLS() | @@ -403,7 +464,7 @@ SrsHLS::~SrsHLS() | ||
403 | srs_freep(video_frame); | 464 | srs_freep(video_frame); |
404 | } | 465 | } |
405 | 466 | ||
406 | -int SrsHLS::on_publish(std::string _vhost, std::string _app, std::string _stream) | 467 | +int SrsHls::on_publish(std::string _vhost, std::string _app, std::string _stream) |
407 | { | 468 | { |
408 | int ret = ERROR_SUCCESS; | 469 | int ret = ERROR_SUCCESS; |
409 | 470 | ||
@@ -435,12 +496,12 @@ int SrsHLS::on_publish(std::string _vhost, std::string _app, std::string _stream | @@ -435,12 +496,12 @@ int SrsHLS::on_publish(std::string _vhost, std::string _app, std::string _stream | ||
435 | return ret; | 496 | return ret; |
436 | } | 497 | } |
437 | 498 | ||
438 | -void SrsHLS::on_unpublish() | 499 | +void SrsHls::on_unpublish() |
439 | { | 500 | { |
440 | hls_enabled = false; | 501 | hls_enabled = false; |
441 | } | 502 | } |
442 | 503 | ||
443 | -int SrsHLS::on_meta_data(SrsOnMetaDataPacket* metadata) | 504 | +int SrsHls::on_meta_data(SrsOnMetaDataPacket* metadata) |
444 | { | 505 | { |
445 | int ret = ERROR_SUCCESS; | 506 | int ret = ERROR_SUCCESS; |
446 | 507 | ||
@@ -492,7 +553,7 @@ int SrsHLS::on_meta_data(SrsOnMetaDataPacket* metadata) | @@ -492,7 +553,7 @@ int SrsHLS::on_meta_data(SrsOnMetaDataPacket* metadata) | ||
492 | return ret; | 553 | return ret; |
493 | } | 554 | } |
494 | 555 | ||
495 | -int SrsHLS::on_audio(SrsSharedPtrMessage* audio) | 556 | +int SrsHls::on_audio(SrsSharedPtrMessage* audio) |
496 | { | 557 | { |
497 | int ret = ERROR_SUCCESS; | 558 | int ret = ERROR_SUCCESS; |
498 | 559 | ||
@@ -523,18 +584,43 @@ int SrsHLS::on_audio(SrsSharedPtrMessage* audio) | @@ -523,18 +584,43 @@ int SrsHLS::on_audio(SrsSharedPtrMessage* audio) | ||
523 | 584 | ||
524 | srs_assert(current); | 585 | srs_assert(current); |
525 | 586 | ||
526 | - stream_dts = audio_frame->dts = audio_frame->pts = audio->header.timestamp * 90; | ||
527 | - audio_frame->pid = TS_AUDIO_PID; | ||
528 | - audio_frame->sid = TS_AUDIO_AAC; | 587 | + // the pts calc from rtmp/flv header. |
588 | + int64_t pts = audio->header.timestamp * 90; | ||
589 | + | ||
590 | + // flush if audio delay exceed | ||
591 | + if (pts - audio_buffer_start_pts > audio_delay * 90) { | ||
592 | + if ((ret = flush_audio()) != ERROR_SUCCESS) { | ||
593 | + return ret; | ||
594 | + } | ||
595 | + } | ||
529 | 596 | ||
530 | - if ((ret = current->muxer->write_audio(audio_frame, audio_buffer, codec, sample)) != ERROR_SUCCESS) { | 597 | + // start buffer, set the audio_frame |
598 | + if (audio_buffer->size == 0) { | ||
599 | + pts = aac_jitter->on_buffer_start(pts, sample->sound_rate); | ||
600 | + | ||
601 | + audio_frame->dts = audio_frame->pts = audio_buffer_start_pts = pts; | ||
602 | + audio_frame->pid = TS_AUDIO_PID; | ||
603 | + audio_frame->sid = TS_AUDIO_AAC; | ||
604 | + } else { | ||
605 | + aac_jitter->on_buffer_continue(); | ||
606 | + } | ||
607 | + | ||
608 | + // write audio to cache. | ||
609 | + if ((ret = write_audio()) != ERROR_SUCCESS) { | ||
531 | return ret; | 610 | return ret; |
532 | } | 611 | } |
533 | 612 | ||
613 | + // write cache to file. | ||
614 | + if (audio_buffer->size > 1024 * 1024) { | ||
615 | + if ((ret = flush_audio()) != ERROR_SUCCESS) { | ||
616 | + return ret; | ||
617 | + } | ||
618 | + } | ||
619 | + | ||
534 | return ret; | 620 | return ret; |
535 | } | 621 | } |
536 | 622 | ||
537 | -int SrsHLS::on_video(SrsSharedPtrMessage* video) | 623 | +int SrsHls::on_video(SrsSharedPtrMessage* video) |
538 | { | 624 | { |
539 | int ret = ERROR_SUCCESS; | 625 | int ret = ERROR_SUCCESS; |
540 | 626 | ||
@@ -563,6 +649,11 @@ int SrsHLS::on_video(SrsSharedPtrMessage* video) | @@ -563,6 +649,11 @@ int SrsHLS::on_video(SrsSharedPtrMessage* video) | ||
563 | return ret; | 649 | return ret; |
564 | } | 650 | } |
565 | 651 | ||
652 | + // write video to cache. | ||
653 | + if ((ret = write_video()) != ERROR_SUCCESS) { | ||
654 | + return ret; | ||
655 | + } | ||
656 | + | ||
566 | stream_dts = video_frame->dts = video->header.timestamp * 90; | 657 | stream_dts = video_frame->dts = video->header.timestamp * 90; |
567 | video_frame->pts = video_frame->dts + sample->cts * 90; | 658 | video_frame->pts = video_frame->dts + sample->cts * 90; |
568 | video_frame->pid = TS_VIDEO_PID; | 659 | video_frame->pid = TS_VIDEO_PID; |
@@ -580,14 +671,17 @@ int SrsHLS::on_video(SrsSharedPtrMessage* video) | @@ -580,14 +671,17 @@ int SrsHLS::on_video(SrsSharedPtrMessage* video) | ||
580 | } | 671 | } |
581 | 672 | ||
582 | srs_assert(current); | 673 | srs_assert(current); |
583 | - if ((ret = current->muxer->write_video(video_frame, video_buffer, codec, sample)) != ERROR_SUCCESS) { | 674 | + if ((ret = current->muxer->write_video(video_frame, video_buffer)) != ERROR_SUCCESS) { |
584 | return ret; | 675 | return ret; |
585 | } | 676 | } |
677 | + | ||
678 | + // write success, clear and free the buffer | ||
679 | + video_buffer->free(); | ||
586 | 680 | ||
587 | return ret; | 681 | return ret; |
588 | } | 682 | } |
589 | 683 | ||
590 | -int SrsHLS::reopen() | 684 | +int SrsHls::reopen() |
591 | { | 685 | { |
592 | int ret = ERROR_SUCCESS; | 686 | int ret = ERROR_SUCCESS; |
593 | 687 | ||
@@ -675,10 +769,19 @@ int SrsHLS::reopen() | @@ -675,10 +769,19 @@ int SrsHLS::reopen() | ||
675 | } | 769 | } |
676 | srs_info("open HLS muxer success. vhost=%s, path=%s", vhost.c_str(), current->full_path.c_str()); | 770 | srs_info("open HLS muxer success. vhost=%s, path=%s", vhost.c_str(), current->full_path.c_str()); |
677 | 771 | ||
772 | + // segment open, flush the audio. | ||
773 | + // @see: ngx_rtmp_hls_open_fragment | ||
774 | + /* start fragment with audio to make iPhone happy */ | ||
775 | + if (current->muxer->fresh()) { | ||
776 | + if ((ret = flush_audio()) != ERROR_SUCCESS) { | ||
777 | + return ret; | ||
778 | + } | ||
779 | + } | ||
780 | + | ||
678 | return ret; | 781 | return ret; |
679 | } | 782 | } |
680 | 783 | ||
681 | -int SrsHLS::refresh_m3u8() | 784 | +int SrsHls::refresh_m3u8() |
682 | { | 785 | { |
683 | int ret = ERROR_SUCCESS; | 786 | int ret = ERROR_SUCCESS; |
684 | 787 | ||
@@ -708,7 +811,7 @@ int SrsHLS::refresh_m3u8() | @@ -708,7 +811,7 @@ int SrsHLS::refresh_m3u8() | ||
708 | return ret; | 811 | return ret; |
709 | } | 812 | } |
710 | 813 | ||
711 | -int SrsHLS::_refresh_m3u8(int& fd, std::string m3u8_file) | 814 | +int SrsHls::_refresh_m3u8(int& fd, std::string m3u8_file) |
712 | { | 815 | { |
713 | int ret = ERROR_SUCCESS; | 816 | int ret = ERROR_SUCCESS; |
714 | 817 | ||
@@ -799,7 +902,7 @@ int SrsHLS::_refresh_m3u8(int& fd, std::string m3u8_file) | @@ -799,7 +902,7 @@ int SrsHLS::_refresh_m3u8(int& fd, std::string m3u8_file) | ||
799 | return ret; | 902 | return ret; |
800 | } | 903 | } |
801 | 904 | ||
802 | -int SrsHLS::create_dir() | 905 | +int SrsHls::create_dir() |
803 | { | 906 | { |
804 | int ret = ERROR_SUCCESS; | 907 | int ret = ERROR_SUCCESS; |
805 | 908 | ||
@@ -822,41 +925,7 @@ int SrsHLS::create_dir() | @@ -822,41 +925,7 @@ int SrsHLS::create_dir() | ||
822 | return ret; | 925 | return ret; |
823 | } | 926 | } |
824 | 927 | ||
825 | -SrsTSMuxer::SrsTSMuxer() | ||
826 | -{ | ||
827 | - fd = -1; | ||
828 | -} | ||
829 | - | ||
830 | -SrsTSMuxer::~SrsTSMuxer() | ||
831 | -{ | ||
832 | - close(); | ||
833 | -} | ||
834 | - | ||
835 | -int SrsTSMuxer::open(std::string _path) | ||
836 | -{ | ||
837 | - int ret = ERROR_SUCCESS; | ||
838 | - | ||
839 | - path = _path; | ||
840 | - | ||
841 | - close(); | ||
842 | - | ||
843 | - int flags = O_CREAT|O_WRONLY|O_TRUNC; | ||
844 | - mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH; | ||
845 | - if ((fd = ::open(path.c_str(), flags, mode)) < 0) { | ||
846 | - ret = ERROR_HLS_OPEN_FAILED; | ||
847 | - srs_error("open ts file %s failed. ret=%d", path.c_str(), ret); | ||
848 | - return ret; | ||
849 | - } | ||
850 | - | ||
851 | - // write mpegts header | ||
852 | - if ((ret = SrsMpegtsWriter::write_header(fd)) != ERROR_SUCCESS) { | ||
853 | - return ret; | ||
854 | - } | ||
855 | - | ||
856 | - return ret; | ||
857 | -} | ||
858 | - | ||
859 | -int SrsTSMuxer::write_audio(SrsMpegtsFrame* audio_frame, SrsCodecBuffer* audio_buffer, SrsCodec* codec, SrsCodecSample* sample) | 928 | +int SrsHls::write_audio() |
860 | { | 929 | { |
861 | int ret = ERROR_SUCCESS; | 930 | int ret = ERROR_SUCCESS; |
862 | 931 | ||
@@ -920,14 +989,10 @@ int SrsTSMuxer::write_audio(SrsMpegtsFrame* audio_frame, SrsCodecBuffer* audio_b | @@ -920,14 +989,10 @@ int SrsTSMuxer::write_audio(SrsMpegtsFrame* audio_frame, SrsCodecBuffer* audio_b | ||
920 | audio_buffer->append(buf->bytes, buf->size); | 989 | audio_buffer->append(buf->bytes, buf->size); |
921 | } | 990 | } |
922 | 991 | ||
923 | - if ((ret = SrsMpegtsWriter::write_frame(fd, audio_frame, audio_buffer)) != ERROR_SUCCESS) { | ||
924 | - return ret; | ||
925 | - } | ||
926 | - | ||
927 | return ret; | 992 | return ret; |
928 | } | 993 | } |
929 | 994 | ||
930 | -int SrsTSMuxer::write_video(SrsMpegtsFrame* video_frame, SrsCodecBuffer* video_buffer, SrsCodec* codec, SrsCodecSample* sample) | 995 | +int SrsHls::write_video() |
931 | { | 996 | { |
932 | int ret = ERROR_SUCCESS; | 997 | int ret = ERROR_SUCCESS; |
933 | 998 | ||
@@ -991,6 +1056,81 @@ int SrsTSMuxer::write_video(SrsMpegtsFrame* video_frame, SrsCodecBuffer* video_b | @@ -991,6 +1056,81 @@ int SrsTSMuxer::write_video(SrsMpegtsFrame* video_frame, SrsCodecBuffer* video_b | ||
991 | video_buffer->append(buf->bytes, buf->size); | 1056 | video_buffer->append(buf->bytes, buf->size); |
992 | } | 1057 | } |
993 | 1058 | ||
1059 | + return ret; | ||
1060 | +} | ||
1061 | + | ||
1062 | +int SrsHls::flush_audio() | ||
1063 | +{ | ||
1064 | + int ret = ERROR_SUCCESS; | ||
1065 | + | ||
1066 | + if (audio_buffer->size <= 0) { | ||
1067 | + return ret; | ||
1068 | + } | ||
1069 | + | ||
1070 | + if ((ret = current->muxer->write_audio(audio_frame, audio_buffer)) != ERROR_SUCCESS) { | ||
1071 | + return ret; | ||
1072 | + } | ||
1073 | + | ||
1074 | + // write success, clear and free the buffer | ||
1075 | + audio_buffer->free(); | ||
1076 | + | ||
1077 | + return ret; | ||
1078 | +} | ||
1079 | + | ||
1080 | +SrsTSMuxer::SrsTSMuxer() | ||
1081 | +{ | ||
1082 | + fd = -1; | ||
1083 | + _fresh = false; | ||
1084 | +} | ||
1085 | + | ||
1086 | +SrsTSMuxer::~SrsTSMuxer() | ||
1087 | +{ | ||
1088 | + close(); | ||
1089 | +} | ||
1090 | + | ||
1091 | +int SrsTSMuxer::open(std::string _path) | ||
1092 | +{ | ||
1093 | + int ret = ERROR_SUCCESS; | ||
1094 | + | ||
1095 | + path = _path; | ||
1096 | + | ||
1097 | + close(); | ||
1098 | + | ||
1099 | + int flags = O_CREAT|O_WRONLY|O_TRUNC; | ||
1100 | + mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH; | ||
1101 | + if ((fd = ::open(path.c_str(), flags, mode)) < 0) { | ||
1102 | + ret = ERROR_HLS_OPEN_FAILED; | ||
1103 | + srs_error("open ts file %s failed. ret=%d", path.c_str(), ret); | ||
1104 | + return ret; | ||
1105 | + } | ||
1106 | + | ||
1107 | + // write mpegts header | ||
1108 | + if ((ret = SrsMpegtsWriter::write_header(fd)) != ERROR_SUCCESS) { | ||
1109 | + return ret; | ||
1110 | + } | ||
1111 | + | ||
1112 | + _fresh = true; | ||
1113 | + | ||
1114 | + return ret; | ||
1115 | +} | ||
1116 | + | ||
1117 | +int SrsTSMuxer::write_audio(SrsMpegtsFrame* audio_frame, SrsCodecBuffer* audio_buffer) | ||
1118 | +{ | ||
1119 | + int ret = ERROR_SUCCESS; | ||
1120 | + | ||
1121 | + if ((ret = SrsMpegtsWriter::write_frame(fd, audio_frame, audio_buffer)) != ERROR_SUCCESS) { | ||
1122 | + return ret; | ||
1123 | + } | ||
1124 | + | ||
1125 | + _fresh = false; | ||
1126 | + | ||
1127 | + return ret; | ||
1128 | +} | ||
1129 | + | ||
1130 | +int SrsTSMuxer::write_video(SrsMpegtsFrame* video_frame, SrsCodecBuffer* video_buffer) | ||
1131 | +{ | ||
1132 | + int ret = ERROR_SUCCESS; | ||
1133 | + | ||
994 | if ((ret = SrsMpegtsWriter::write_frame(fd, video_frame, video_buffer)) != ERROR_SUCCESS) { | 1134 | if ((ret = SrsMpegtsWriter::write_frame(fd, video_frame, video_buffer)) != ERROR_SUCCESS) { |
995 | return ret; | 1135 | return ret; |
996 | } | 1136 | } |
@@ -1003,6 +1143,12 @@ void SrsTSMuxer::close() | @@ -1003,6 +1143,12 @@ void SrsTSMuxer::close() | ||
1003 | if (fd > 0) { | 1143 | if (fd > 0) { |
1004 | ::close(fd); | 1144 | ::close(fd); |
1005 | fd = -1; | 1145 | fd = -1; |
1146 | + _fresh = false; | ||
1006 | } | 1147 | } |
1007 | } | 1148 | } |
1008 | 1149 | ||
1150 | +bool SrsTSMuxer::fresh() | ||
1151 | +{ | ||
1152 | + return _fresh; | ||
1153 | +} | ||
1154 | + |
@@ -65,9 +65,39 @@ struct SrsM3u8Segment | @@ -65,9 +65,39 @@ struct SrsM3u8Segment | ||
65 | }; | 65 | }; |
66 | 66 | ||
67 | /** | 67 | /** |
68 | +* jitter correct for audio, | ||
69 | +* the sample rate 44100/32000 will lost precise, | ||
70 | +* when mp4/ts(tbn=90000) covert to flv/rtmp(1000), | ||
71 | +* so the Hls on ipad or iphone will corrupt, | ||
72 | +* @see nginx-rtmp: est_pts | ||
73 | +*/ | ||
74 | +class SrsHlsAacJitter | ||
75 | +{ | ||
76 | +private: | ||
77 | + int64_t base_pts; | ||
78 | + int64_t nb_samples; | ||
79 | + int sync_ms; | ||
80 | +public: | ||
81 | + SrsHlsAacJitter(); | ||
82 | + virtual ~SrsHlsAacJitter(); | ||
83 | + /** | ||
84 | + * when buffer start, calc the "correct" pts for ts, | ||
85 | + * @param flv_pts, the flv pts calc from flv header timestamp, | ||
86 | + * @return the calc correct pts. | ||
87 | + */ | ||
88 | + virtual int64_t on_buffer_start(int64_t flv_pts, int sample_rate); | ||
89 | + /** | ||
90 | + * when buffer continue, muxer donot write to file, | ||
91 | + * the audio buffer continue grow and donot need a pts, | ||
92 | + * for the ts audio PES packet only has one pts at the first time. | ||
93 | + */ | ||
94 | + virtual void on_buffer_continue(); | ||
95 | +}; | ||
96 | + | ||
97 | +/** | ||
68 | * write m3u8 hls. | 98 | * write m3u8 hls. |
69 | */ | 99 | */ |
70 | -class SrsHLS | 100 | +class SrsHls |
71 | { | 101 | { |
72 | private: | 102 | private: |
73 | std::string vhost; | 103 | std::string vhost; |
@@ -95,16 +125,20 @@ private: | @@ -95,16 +125,20 @@ private: | ||
95 | SrsCodecBuffer* video_buffer; | 125 | SrsCodecBuffer* video_buffer; |
96 | // last known dts | 126 | // last known dts |
97 | int64_t stream_dts; | 127 | int64_t stream_dts; |
128 | + int64_t audio_buffer_start_pts; | ||
98 | // last segment dts in m3u8 | 129 | // last segment dts in m3u8 |
99 | int64_t m3u8_dts; | 130 | int64_t m3u8_dts; |
131 | + // in ms, audio delay to flush the audios. | ||
132 | + int64_t audio_delay; | ||
100 | private: | 133 | private: |
101 | bool hls_enabled; | 134 | bool hls_enabled; |
102 | SrsCodec* codec; | 135 | SrsCodec* codec; |
103 | SrsCodecSample* sample; | 136 | SrsCodecSample* sample; |
104 | SrsRtmpJitter* jitter; | 137 | SrsRtmpJitter* jitter; |
138 | + SrsHlsAacJitter* aac_jitter; | ||
105 | public: | 139 | public: |
106 | - SrsHLS(); | ||
107 | - virtual ~SrsHLS(); | 140 | + SrsHls(); |
141 | + virtual ~SrsHls(); | ||
108 | public: | 142 | public: |
109 | virtual int on_publish(std::string _vhost, std::string _app, std::string _stream); | 143 | virtual int on_publish(std::string _vhost, std::string _app, std::string _stream); |
110 | virtual void on_unpublish(); | 144 | virtual void on_unpublish(); |
@@ -116,6 +150,10 @@ private: | @@ -116,6 +150,10 @@ private: | ||
116 | virtual int refresh_m3u8(); | 150 | virtual int refresh_m3u8(); |
117 | virtual int _refresh_m3u8(int& fd, std::string m3u8_file); | 151 | virtual int _refresh_m3u8(int& fd, std::string m3u8_file); |
118 | virtual int create_dir(); | 152 | virtual int create_dir(); |
153 | +private: | ||
154 | + virtual int write_audio(); | ||
155 | + virtual int write_video(); | ||
156 | + virtual int flush_audio(); | ||
119 | }; | 157 | }; |
120 | 158 | ||
121 | class SrsTSMuxer | 159 | class SrsTSMuxer |
@@ -123,14 +161,16 @@ class SrsTSMuxer | @@ -123,14 +161,16 @@ class SrsTSMuxer | ||
123 | private: | 161 | private: |
124 | int fd; | 162 | int fd; |
125 | std::string path; | 163 | std::string path; |
164 | + bool _fresh; | ||
126 | public: | 165 | public: |
127 | SrsTSMuxer(); | 166 | SrsTSMuxer(); |
128 | virtual ~SrsTSMuxer(); | 167 | virtual ~SrsTSMuxer(); |
129 | public: | 168 | public: |
130 | virtual int open(std::string _path); | 169 | virtual int open(std::string _path); |
131 | - virtual int write_audio(SrsMpegtsFrame* audio_frame, SrsCodecBuffer* audio_buffer, SrsCodec* codec, SrsCodecSample* sample); | ||
132 | - virtual int write_video(SrsMpegtsFrame* video_frame, SrsCodecBuffer* video_buffer, SrsCodec* codec, SrsCodecSample* sample); | 170 | + virtual int write_audio(SrsMpegtsFrame* audio_frame, SrsCodecBuffer* audio_buffer); |
171 | + virtual int write_video(SrsMpegtsFrame* video_frame, SrsCodecBuffer* video_buffer); | ||
133 | virtual void close(); | 172 | virtual void close(); |
173 | + virtual bool fresh(); | ||
134 | }; | 174 | }; |
135 | 175 | ||
136 | #endif | 176 | #endif |
@@ -257,7 +257,7 @@ SrsSource* SrsSource::find(std::string stream_url) | @@ -257,7 +257,7 @@ SrsSource* SrsSource::find(std::string stream_url) | ||
257 | SrsSource::SrsSource(std::string _stream_url) | 257 | SrsSource::SrsSource(std::string _stream_url) |
258 | { | 258 | { |
259 | stream_url = _stream_url; | 259 | stream_url = _stream_url; |
260 | - hls = new SrsHLS(); | 260 | + hls = new SrsHls(); |
261 | 261 | ||
262 | cache_metadata = cache_sh_video = cache_sh_audio = NULL; | 262 | cache_metadata = cache_sh_video = cache_sh_audio = NULL; |
263 | 263 |
@@ -38,7 +38,7 @@ class SrsSource; | @@ -38,7 +38,7 @@ class SrsSource; | ||
38 | class SrsCommonMessage; | 38 | class SrsCommonMessage; |
39 | class SrsOnMetaDataPacket; | 39 | class SrsOnMetaDataPacket; |
40 | class SrsSharedPtrMessage; | 40 | class SrsSharedPtrMessage; |
41 | -class SrsHLS; | 41 | +class SrsHls; |
42 | 42 | ||
43 | /** | 43 | /** |
44 | * time jitter detect and correct, | 44 | * time jitter detect and correct, |
@@ -125,7 +125,7 @@ public: | @@ -125,7 +125,7 @@ public: | ||
125 | */ | 125 | */ |
126 | static SrsSource* find(std::string stream_url); | 126 | static SrsSource* find(std::string stream_url); |
127 | private: | 127 | private: |
128 | - SrsHLS* hls; | 128 | + SrsHls* hls; |
129 | std::string stream_url; | 129 | std::string stream_url; |
130 | std::vector<SrsConsumer*> consumers; | 130 | std::vector<SrsConsumer*> consumers; |
131 | // gop cache for client fast startup. | 131 | // gop cache for client fast startup. |
-
请 注册 或 登录 后发表评论