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. |
-
请 注册 或 登录 后发表评论