正在显示
15 个修改的文件
包含
207 行增加
和
90 行删除
| @@ -1045,6 +1045,7 @@ Winlin | @@ -1045,6 +1045,7 @@ Winlin | ||
| 1045 | [bug #367]: https://github.com/simple-rtmp-server/srs/issues/367 | 1045 | [bug #367]: https://github.com/simple-rtmp-server/srs/issues/367 |
| 1046 | [bug #471]: https://github.com/simple-rtmp-server/srs/issues/471 | 1046 | [bug #471]: https://github.com/simple-rtmp-server/srs/issues/471 |
| 1047 | [bug #380]: https://github.com/simple-rtmp-server/srs/issues/380 | 1047 | [bug #380]: https://github.com/simple-rtmp-server/srs/issues/380 |
| 1048 | +[bug #474]: https://github.com/simple-rtmp-server/srs/issues/474 | ||
| 1048 | [bug #475]: https://github.com/simple-rtmp-server/srs/issues/475 | 1049 | [bug #475]: https://github.com/simple-rtmp-server/srs/issues/475 |
| 1049 | [bug #458]: https://github.com/simple-rtmp-server/srs/issues/458 | 1050 | [bug #458]: https://github.com/simple-rtmp-server/srs/issues/458 |
| 1050 | [bug #454]: https://github.com/simple-rtmp-server/srs/issues/454 | 1051 | [bug #454]: https://github.com/simple-rtmp-server/srs/issues/454 |
| @@ -498,6 +498,14 @@ vhost min.delay.com { | @@ -498,6 +498,14 @@ vhost min.delay.com { | ||
| 498 | } | 498 | } |
| 499 | } | 499 | } |
| 500 | 500 | ||
| 501 | +# whether disable the sps parse, for the resolution of video. | ||
| 502 | +vhost no.parse.sps.com { | ||
| 503 | + # @see publish.srs.com | ||
| 504 | + publish { | ||
| 505 | + parse_sps on; | ||
| 506 | + } | ||
| 507 | +} | ||
| 508 | + | ||
| 501 | # the vhost to control the stream delivery feature | 509 | # the vhost to control the stream delivery feature |
| 502 | vhost stream.control.com { | 510 | vhost stream.control.com { |
| 503 | # @see scope.vhost.srs.com | 511 | # @see scope.vhost.srs.com |
| @@ -546,6 +554,11 @@ vhost publish.srs.com { | @@ -546,6 +554,11 @@ vhost publish.srs.com { | ||
| 546 | # the normal packet timeout in ms for encoder. | 554 | # the normal packet timeout in ms for encoder. |
| 547 | # default: 5000 | 555 | # default: 5000 |
| 548 | normal_timeout 7000; | 556 | normal_timeout 7000; |
| 557 | + # whether parse the sps when publish stream. | ||
| 558 | + # we can got the resolution of video for stat api. | ||
| 559 | + # but we may failed to cause publish failed. | ||
| 560 | + # default: on | ||
| 561 | + parse_sps on; | ||
| 549 | } | 562 | } |
| 550 | } | 563 | } |
| 551 | 564 |
| @@ -739,6 +739,9 @@ int SrsConfig::reload_vhost(SrsConfDirective* old_root) | @@ -739,6 +739,9 @@ int SrsConfig::reload_vhost(SrsConfDirective* old_root) | ||
| 739 | return ret; | 739 | return ret; |
| 740 | } | 740 | } |
| 741 | 741 | ||
| 742 | + // the auto reload configs: | ||
| 743 | + // publish.parse_sps | ||
| 744 | + | ||
| 742 | // ENABLED => ENABLED (modified) | 745 | // ENABLED => ENABLED (modified) |
| 743 | if (get_vhost_enabled(new_vhost) && get_vhost_enabled(old_vhost)) { | 746 | if (get_vhost_enabled(new_vhost) && get_vhost_enabled(old_vhost)) { |
| 744 | srs_trace("vhost %s maybe modified, reload its detail.", vhost.c_str()); | 747 | srs_trace("vhost %s maybe modified, reload its detail.", vhost.c_str()); |
| @@ -3096,7 +3099,7 @@ int SrsConfig::check_config() | @@ -3096,7 +3099,7 @@ int SrsConfig::check_config() | ||
| 3096 | } else if (n == "publish") { | 3099 | } else if (n == "publish") { |
| 3097 | for (int j = 0; j < (int)conf->directives.size(); j++) { | 3100 | for (int j = 0; j < (int)conf->directives.size(); j++) { |
| 3098 | string m = conf->at(j)->name.c_str(); | 3101 | string m = conf->at(j)->name.c_str(); |
| 3099 | - if (m != "mr" && m != "mr_latency" && m != "firstpkt_timeout" && m != "normal_timeout") { | 3102 | + if (m != "mr" && m != "mr_latency" && m != "firstpkt_timeout" && m != "normal_timeout" && m != "parse_sps") { |
| 3100 | ret = ERROR_SYSTEM_CONFIG_INVALID; | 3103 | ret = ERROR_SYSTEM_CONFIG_INVALID; |
| 3101 | srs_error("unsupported vhost publish directive %s, ret=%d", m.c_str(), ret); | 3104 | srs_error("unsupported vhost publish directive %s, ret=%d", m.c_str(), ret); |
| 3102 | return ret; | 3105 | return ret; |
| @@ -3841,6 +3844,29 @@ int SrsConfig::get_chunk_size(string vhost) | @@ -3841,6 +3844,29 @@ int SrsConfig::get_chunk_size(string vhost) | ||
| 3841 | return ::atoi(conf->arg0().c_str()); | 3844 | return ::atoi(conf->arg0().c_str()); |
| 3842 | } | 3845 | } |
| 3843 | 3846 | ||
| 3847 | +bool SrsConfig::get_parse_sps(string vhost) | ||
| 3848 | +{ | ||
| 3849 | + static bool DEFAULT = true; | ||
| 3850 | + | ||
| 3851 | + SrsConfDirective* conf = get_vhost(vhost); | ||
| 3852 | + | ||
| 3853 | + if (!conf) { | ||
| 3854 | + return DEFAULT; | ||
| 3855 | + } | ||
| 3856 | + | ||
| 3857 | + conf = conf->get("publish"); | ||
| 3858 | + if (!conf) { | ||
| 3859 | + return DEFAULT; | ||
| 3860 | + } | ||
| 3861 | + | ||
| 3862 | + conf = conf->get("parse_sps"); | ||
| 3863 | + if (!conf || conf->arg0().empty()) { | ||
| 3864 | + return DEFAULT; | ||
| 3865 | + } | ||
| 3866 | + | ||
| 3867 | + return SRS_CONF_PERFER_TRUE(conf->arg0()); | ||
| 3868 | +} | ||
| 3869 | + | ||
| 3844 | bool SrsConfig::get_mr_enabled(string vhost) | 3870 | bool SrsConfig::get_mr_enabled(string vhost) |
| 3845 | { | 3871 | { |
| 3846 | SrsConfDirective* conf = get_vhost(vhost); | 3872 | SrsConfDirective* conf = get_vhost(vhost); |
| @@ -604,6 +604,10 @@ public: | @@ -604,6 +604,10 @@ public: | ||
| 604 | */ | 604 | */ |
| 605 | virtual int get_chunk_size(std::string vhost); | 605 | virtual int get_chunk_size(std::string vhost); |
| 606 | /** | 606 | /** |
| 607 | + * whether parse the sps when publish stream to SRS. | ||
| 608 | + */ | ||
| 609 | + virtual bool get_parse_sps(std::string vhost); | ||
| 610 | + /** | ||
| 607 | * whether mr is enabled for vhost. | 611 | * whether mr is enabled for vhost. |
| 608 | * @param vhost, the vhost to get the mr. | 612 | * @param vhost, the vhost to get the mr. |
| 609 | */ | 613 | */ |
| @@ -476,6 +476,8 @@ void SrsEdgeForwarder::stop() | @@ -476,6 +476,8 @@ void SrsEdgeForwarder::stop() | ||
| 476 | 476 | ||
| 477 | close_underlayer_socket(); | 477 | close_underlayer_socket(); |
| 478 | 478 | ||
| 479 | + queue->clear(); | ||
| 480 | + | ||
| 479 | srs_freep(client); | 481 | srs_freep(client); |
| 480 | srs_freep(io); | 482 | srs_freep(io); |
| 481 | kbps->set_io(NULL, NULL); | 483 | kbps->set_io(NULL, NULL); |
| @@ -1252,7 +1252,7 @@ int SrsHls::initialize(SrsSource* s, ISrsHlsHandler* h) | @@ -1252,7 +1252,7 @@ int SrsHls::initialize(SrsSource* s, ISrsHlsHandler* h) | ||
| 1252 | return ret; | 1252 | return ret; |
| 1253 | } | 1253 | } |
| 1254 | 1254 | ||
| 1255 | -int SrsHls::on_publish(SrsRequest* req) | 1255 | +int SrsHls::on_publish(SrsRequest* req, bool fetch_sequence_header) |
| 1256 | { | 1256 | { |
| 1257 | int ret = ERROR_SUCCESS; | 1257 | int ret = ERROR_SUCCESS; |
| 1258 | 1258 | ||
| @@ -1282,6 +1282,9 @@ int SrsHls::on_publish(SrsRequest* req) | @@ -1282,6 +1282,9 @@ int SrsHls::on_publish(SrsRequest* req) | ||
| 1282 | // ok, the hls can be dispose, or need to be dispose. | 1282 | // ok, the hls can be dispose, or need to be dispose. |
| 1283 | hls_can_dispose = true; | 1283 | hls_can_dispose = true; |
| 1284 | 1284 | ||
| 1285 | + // when publish, don't need to fetch sequence header, which is old and maybe corrupt. | ||
| 1286 | + // when reload, we must fetch the sequence header from source cache. | ||
| 1287 | + if (fetch_sequence_header) { | ||
| 1285 | // notice the source to get the cached sequence header. | 1288 | // notice the source to get the cached sequence header. |
| 1286 | // when reload to start hls, hls will never get the sequence header in stream, | 1289 | // when reload to start hls, hls will never get the sequence header in stream, |
| 1287 | // use the SrsSource.on_hls_start to push the sequence header to HLS. | 1290 | // use the SrsSource.on_hls_start to push the sequence header to HLS. |
| @@ -1289,6 +1292,7 @@ int SrsHls::on_publish(SrsRequest* req) | @@ -1289,6 +1292,7 @@ int SrsHls::on_publish(SrsRequest* req) | ||
| 1289 | srs_error("callback source hls start failed. ret=%d", ret); | 1292 | srs_error("callback source hls start failed. ret=%d", ret); |
| 1290 | return ret; | 1293 | return ret; |
| 1291 | } | 1294 | } |
| 1295 | + } | ||
| 1292 | 1296 | ||
| 1293 | return ret; | 1297 | return ret; |
| 1294 | } | 1298 | } |
| @@ -1391,7 +1395,7 @@ int SrsHls::on_audio(SrsSharedPtrMessage* shared_audio) | @@ -1391,7 +1395,7 @@ int SrsHls::on_audio(SrsSharedPtrMessage* shared_audio) | ||
| 1391 | return ret; | 1395 | return ret; |
| 1392 | } | 1396 | } |
| 1393 | 1397 | ||
| 1394 | -int SrsHls::on_video(SrsSharedPtrMessage* shared_video) | 1398 | +int SrsHls::on_video(SrsSharedPtrMessage* shared_video, bool is_sps_pps) |
| 1395 | { | 1399 | { |
| 1396 | int ret = ERROR_SUCCESS; | 1400 | int ret = ERROR_SUCCESS; |
| 1397 | 1401 | ||
| @@ -1405,6 +1409,12 @@ int SrsHls::on_video(SrsSharedPtrMessage* shared_video) | @@ -1405,6 +1409,12 @@ int SrsHls::on_video(SrsSharedPtrMessage* shared_video) | ||
| 1405 | SrsSharedPtrMessage* video = shared_video->copy(); | 1409 | SrsSharedPtrMessage* video = shared_video->copy(); |
| 1406 | SrsAutoFree(SrsSharedPtrMessage, video); | 1410 | SrsAutoFree(SrsSharedPtrMessage, video); |
| 1407 | 1411 | ||
| 1412 | + // user can disable the sps parse to workaround when parse sps failed. | ||
| 1413 | + // @see https://github.com/simple-rtmp-server/srs/issues/474 | ||
| 1414 | + if (is_sps_pps) { | ||
| 1415 | + codec->avc_parse_sps = _srs_config->get_parse_sps(_req->vhost); | ||
| 1416 | + } | ||
| 1417 | + | ||
| 1408 | sample->clear(); | 1418 | sample->clear(); |
| 1409 | if ((ret = codec->video_avc_demux(video->payload, video->size, sample)) != ERROR_SUCCESS) { | 1419 | if ((ret = codec->video_avc_demux(video->payload, video->size, sample)) != ERROR_SUCCESS) { |
| 1410 | srs_error("hls codec demux video failed. ret=%d", ret); | 1420 | srs_error("hls codec demux video failed. ret=%d", ret); |
| @@ -426,8 +426,9 @@ public: | @@ -426,8 +426,9 @@ public: | ||
| 426 | /** | 426 | /** |
| 427 | * publish stream event, continue to write the m3u8, | 427 | * publish stream event, continue to write the m3u8, |
| 428 | * for the muxer object not destroyed. | 428 | * for the muxer object not destroyed. |
| 429 | + * @param fetch_sequence_header whether fetch sequence from source. | ||
| 429 | */ | 430 | */ |
| 430 | - virtual int on_publish(SrsRequest* req); | 431 | + virtual int on_publish(SrsRequest* req, bool fetch_sequence_header); |
| 431 | /** | 432 | /** |
| 432 | * the unpublish event, only close the muxer, donot destroy the | 433 | * the unpublish event, only close the muxer, donot destroy the |
| 433 | * muxer, for when we continue to publish, the m3u8 will continue. | 434 | * muxer, for when we continue to publish, the m3u8 will continue. |
| @@ -445,8 +446,9 @@ public: | @@ -445,8 +446,9 @@ public: | ||
| 445 | /** | 446 | /** |
| 446 | * mux the video packets to ts. | 447 | * mux the video packets to ts. |
| 447 | * @param shared_video, directly ptr, copy it if need to save it. | 448 | * @param shared_video, directly ptr, copy it if need to save it. |
| 449 | + * @param is_sps_pps whether the video is h.264 sps/pps. | ||
| 448 | */ | 450 | */ |
| 449 | - virtual int on_video(SrsSharedPtrMessage* shared_video); | 451 | + virtual int on_video(SrsSharedPtrMessage* shared_video, bool is_sps_pps); |
| 450 | private: | 452 | private: |
| 451 | virtual void hls_show_mux_log(); | 453 | virtual void hls_show_mux_log(); |
| 452 | }; | 454 | }; |
| @@ -816,7 +816,14 @@ int SrsRtmpConn::publishing(SrsSource* source) | @@ -816,7 +816,14 @@ int SrsRtmpConn::publishing(SrsSource* source) | ||
| 816 | 816 | ||
| 817 | // stop isolate recv thread | 817 | // stop isolate recv thread |
| 818 | trd.stop(); | 818 | trd.stop(); |
| 819 | + } | ||
| 819 | 820 | ||
| 821 | + // whatever the acquire publish, always release publish. | ||
| 822 | + // when the acquire error in the midlle-way, the publish state changed, | ||
| 823 | + // but failed, so we must cleanup it. | ||
| 824 | + // @see https://github.com/simple-rtmp-server/srs/issues/474 | ||
| 825 | + // @remark when stream is busy, should never release it. | ||
| 826 | + if (ret != ERROR_SYSTEM_STREAM_BUSY) { | ||
| 820 | release_publish(source, vhost_is_edge); | 827 | release_publish(source, vhost_is_edge); |
| 821 | } | 828 | } |
| 822 | 829 | ||
| @@ -926,10 +933,12 @@ int SrsRtmpConn::acquire_publish(SrsSource* source, bool is_edge) | @@ -926,10 +933,12 @@ int SrsRtmpConn::acquire_publish(SrsSource* source, bool is_edge) | ||
| 926 | if (is_edge) { | 933 | if (is_edge) { |
| 927 | if ((ret = source->on_edge_start_publish()) != ERROR_SUCCESS) { | 934 | if ((ret = source->on_edge_start_publish()) != ERROR_SUCCESS) { |
| 928 | srs_error("notice edge start publish stream failed. ret=%d", ret); | 935 | srs_error("notice edge start publish stream failed. ret=%d", ret); |
| 936 | + return ret; | ||
| 929 | } | 937 | } |
| 930 | } else { | 938 | } else { |
| 931 | if ((ret = source->on_publish()) != ERROR_SUCCESS) { | 939 | if ((ret = source->on_publish()) != ERROR_SUCCESS) { |
| 932 | srs_error("notify publish failed. ret=%d", ret); | 940 | srs_error("notify publish failed. ret=%d", ret); |
| 941 | + return ret; | ||
| 933 | } | 942 | } |
| 934 | } | 943 | } |
| 935 | 944 |
| @@ -1161,7 +1161,7 @@ int SrsSource::on_reload_vhost_hls(string vhost) | @@ -1161,7 +1161,7 @@ int SrsSource::on_reload_vhost_hls(string vhost) | ||
| 1161 | 1161 | ||
| 1162 | #ifdef SRS_AUTO_HLS | 1162 | #ifdef SRS_AUTO_HLS |
| 1163 | hls->on_unpublish(); | 1163 | hls->on_unpublish(); |
| 1164 | - if ((ret = hls->on_publish(_req)) != ERROR_SUCCESS) { | 1164 | + if ((ret = hls->on_publish(_req, true)) != ERROR_SUCCESS) { |
| 1165 | srs_error("hls publish failed. ret=%d", ret); | 1165 | srs_error("hls publish failed. ret=%d", ret); |
| 1166 | return ret; | 1166 | return ret; |
| 1167 | } | 1167 | } |
| @@ -1297,7 +1297,7 @@ int SrsSource::on_hls_start() | @@ -1297,7 +1297,7 @@ int SrsSource::on_hls_start() | ||
| 1297 | // when reload to start hls, hls will never get the sequence header in stream, | 1297 | // when reload to start hls, hls will never get the sequence header in stream, |
| 1298 | // use the SrsSource.on_hls_start to push the sequence header to HLS. | 1298 | // use the SrsSource.on_hls_start to push the sequence header to HLS. |
| 1299 | // TODO: maybe need to decode the metadata? | 1299 | // TODO: maybe need to decode the metadata? |
| 1300 | - if (cache_sh_video && (ret = hls->on_video(cache_sh_video)) != ERROR_SUCCESS) { | 1300 | + if (cache_sh_video && (ret = hls->on_video(cache_sh_video, true)) != ERROR_SUCCESS) { |
| 1301 | srs_error("hls process video sequence header message failed. ret=%d", ret); | 1301 | srs_error("hls process video sequence header message failed. ret=%d", ret); |
| 1302 | return ret; | 1302 | return ret; |
| 1303 | } | 1303 | } |
| @@ -1558,6 +1558,44 @@ int SrsSource::on_audio_imp(SrsSharedPtrMessage* msg) | @@ -1558,6 +1558,44 @@ int SrsSource::on_audio_imp(SrsSharedPtrMessage* msg) | ||
| 1558 | bool is_aac_sequence_header = SrsFlvCodec::audio_is_sequence_header(msg->payload, msg->size); | 1558 | bool is_aac_sequence_header = SrsFlvCodec::audio_is_sequence_header(msg->payload, msg->size); |
| 1559 | bool is_sequence_header = is_aac_sequence_header; | 1559 | bool is_sequence_header = is_aac_sequence_header; |
| 1560 | 1560 | ||
| 1561 | + // whether consumer should drop for the duplicated sequence header. | ||
| 1562 | + bool drop_for_reduce = false; | ||
| 1563 | + if (is_sequence_header && cache_sh_audio && _srs_config->get_reduce_sequence_header(_req->vhost)) { | ||
| 1564 | + if (cache_sh_audio->size == msg->size) { | ||
| 1565 | + drop_for_reduce = srs_bytes_equals(cache_sh_audio->payload, msg->payload, msg->size); | ||
| 1566 | + srs_warn("drop for reduce sh audio, size=%d", msg->size); | ||
| 1567 | + } | ||
| 1568 | + } | ||
| 1569 | + | ||
| 1570 | + // cache the sequence header if aac | ||
| 1571 | + // donot cache the sequence header to gop_cache, return here. | ||
| 1572 | + if (is_aac_sequence_header) { | ||
| 1573 | + // parse detail audio codec | ||
| 1574 | + SrsAvcAacCodec codec; | ||
| 1575 | + SrsCodecSample sample; | ||
| 1576 | + if ((ret = codec.audio_aac_demux(msg->payload, msg->size, &sample)) != ERROR_SUCCESS) { | ||
| 1577 | + srs_error("source codec demux audio failed. ret=%d", ret); | ||
| 1578 | + return ret; | ||
| 1579 | + } | ||
| 1580 | + | ||
| 1581 | + static int flv_sample_sizes[] = {8, 16, 0}; | ||
| 1582 | + static int flv_sound_types[] = {1, 2, 0}; | ||
| 1583 | + | ||
| 1584 | + // when got audio stream info. | ||
| 1585 | + SrsStatistic* stat = SrsStatistic::instance(); | ||
| 1586 | + if ((ret = stat->on_audio_info(_req, SrsCodecAudioAAC, sample.sound_rate, sample.sound_type, codec.aac_object)) != ERROR_SUCCESS) { | ||
| 1587 | + return ret; | ||
| 1588 | + } | ||
| 1589 | + | ||
| 1590 | + srs_trace("%dB audio sh, codec(%d, profile=%s, %dchannels, %dkbps, %dHZ), " | ||
| 1591 | + "flv(%dbits, %dchannels, %dHZ)", | ||
| 1592 | + msg->size, codec.audio_codec_id, | ||
| 1593 | + srs_codec_aac_object2str(codec.aac_object).c_str(), codec.aac_channels, | ||
| 1594 | + codec.audio_data_rate / 1000, aac_sample_rates[codec.aac_sample_rate], | ||
| 1595 | + flv_sample_sizes[sample.sound_size], flv_sound_types[sample.sound_type], | ||
| 1596 | + flv_sample_rates[sample.sound_rate]); | ||
| 1597 | + } | ||
| 1598 | + | ||
| 1561 | #ifdef SRS_AUTO_HLS | 1599 | #ifdef SRS_AUTO_HLS |
| 1562 | if ((ret = hls->on_audio(msg)) != ERROR_SUCCESS) { | 1600 | if ((ret = hls->on_audio(msg)) != ERROR_SUCCESS) { |
| 1563 | // apply the error strategy for hls. | 1601 | // apply the error strategy for hls. |
| @@ -1611,13 +1649,6 @@ int SrsSource::on_audio_imp(SrsSharedPtrMessage* msg) | @@ -1611,13 +1649,6 @@ int SrsSource::on_audio_imp(SrsSharedPtrMessage* msg) | ||
| 1611 | #endif | 1649 | #endif |
| 1612 | 1650 | ||
| 1613 | // copy to all consumer | 1651 | // copy to all consumer |
| 1614 | - bool drop_for_reduce = false; | ||
| 1615 | - if (is_sequence_header && cache_sh_audio && _srs_config->get_reduce_sequence_header(_req->vhost)) { | ||
| 1616 | - if (cache_sh_audio->size == msg->size) { | ||
| 1617 | - drop_for_reduce = srs_bytes_equals(cache_sh_audio->payload, msg->payload, msg->size); | ||
| 1618 | - srs_warn("drop for reduce sh audio, size=%d", msg->size); | ||
| 1619 | - } | ||
| 1620 | - } | ||
| 1621 | if (!drop_for_reduce) { | 1652 | if (!drop_for_reduce) { |
| 1622 | for (int i = 0; i < (int)consumers.size(); i++) { | 1653 | for (int i = 0; i < (int)consumers.size(); i++) { |
| 1623 | SrsConsumer* consumer = consumers.at(i); | 1654 | SrsConsumer* consumer = consumers.at(i); |
| @@ -1649,34 +1680,8 @@ int SrsSource::on_audio_imp(SrsSharedPtrMessage* msg) | @@ -1649,34 +1680,8 @@ int SrsSource::on_audio_imp(SrsSharedPtrMessage* msg) | ||
| 1649 | cache_sh_audio = msg->copy(); | 1680 | cache_sh_audio = msg->copy(); |
| 1650 | } | 1681 | } |
| 1651 | 1682 | ||
| 1652 | - // cache the sequence header if aac | ||
| 1653 | - // donot cache the sequence header to gop_cache, return here. | ||
| 1654 | - if (is_aac_sequence_header) { | ||
| 1655 | - // parse detail audio codec | ||
| 1656 | - SrsAvcAacCodec codec; | ||
| 1657 | - SrsCodecSample sample; | ||
| 1658 | - if ((ret = codec.audio_aac_demux(msg->payload, msg->size, &sample)) != ERROR_SUCCESS) { | ||
| 1659 | - srs_error("source codec demux audio failed. ret=%d", ret); | ||
| 1660 | - return ret; | ||
| 1661 | - } | ||
| 1662 | - | ||
| 1663 | - static int flv_sample_sizes[] = {8, 16, 0}; | ||
| 1664 | - static int flv_sound_types[] = {1, 2, 0}; | ||
| 1665 | - | ||
| 1666 | - // when got audio stream info. | ||
| 1667 | - SrsStatistic* stat = SrsStatistic::instance(); | ||
| 1668 | - if ((ret = stat->on_audio_info(_req, SrsCodecAudioAAC, sample.sound_rate, sample.sound_type, codec.aac_object)) != ERROR_SUCCESS) { | ||
| 1669 | - return ret; | ||
| 1670 | - } | ||
| 1671 | - | ||
| 1672 | - srs_trace("%dB audio sh, " | ||
| 1673 | - "codec(%d, profile=%s, %dchannels, %dkbps, %dHZ), " | ||
| 1674 | - "flv(%dbits, %dchannels, %dHZ)", | ||
| 1675 | - msg->size, codec.audio_codec_id, | ||
| 1676 | - srs_codec_aac_object2str(codec.aac_object).c_str(), codec.aac_channels, | ||
| 1677 | - codec.audio_data_rate / 1000, aac_sample_rates[codec.aac_sample_rate], | ||
| 1678 | - flv_sample_sizes[sample.sound_size], flv_sound_types[sample.sound_type], | ||
| 1679 | - flv_sample_rates[sample.sound_rate]); | 1683 | + // when sequence header, donot push to gop cache and adjust the timestamp. |
| 1684 | + if (is_sequence_header) { | ||
| 1680 | return ret; | 1685 | return ret; |
| 1681 | } | 1686 | } |
| 1682 | 1687 | ||
| @@ -1768,8 +1773,49 @@ int SrsSource::on_video_imp(SrsSharedPtrMessage* msg) | @@ -1768,8 +1773,49 @@ int SrsSource::on_video_imp(SrsSharedPtrMessage* msg) | ||
| 1768 | 1773 | ||
| 1769 | bool is_sequence_header = SrsFlvCodec::video_is_sequence_header(msg->payload, msg->size); | 1774 | bool is_sequence_header = SrsFlvCodec::video_is_sequence_header(msg->payload, msg->size); |
| 1770 | 1775 | ||
| 1776 | + // whether consumer should drop for the duplicated sequence header. | ||
| 1777 | + bool drop_for_reduce = false; | ||
| 1778 | + if (is_sequence_header && cache_sh_video && _srs_config->get_reduce_sequence_header(_req->vhost)) { | ||
| 1779 | + if (cache_sh_video->size == msg->size) { | ||
| 1780 | + drop_for_reduce = srs_bytes_equals(cache_sh_video->payload, msg->payload, msg->size); | ||
| 1781 | + srs_warn("drop for reduce sh video, size=%d", msg->size); | ||
| 1782 | + } | ||
| 1783 | + } | ||
| 1784 | + | ||
| 1785 | + // cache the sequence header if h264 | ||
| 1786 | + // donot cache the sequence header to gop_cache, return here. | ||
| 1787 | + if (is_sequence_header) { | ||
| 1788 | + srs_freep(cache_sh_video); | ||
| 1789 | + cache_sh_video = msg->copy(); | ||
| 1790 | + | ||
| 1791 | + // parse detail audio codec | ||
| 1792 | + SrsAvcAacCodec codec; | ||
| 1793 | + | ||
| 1794 | + // user can disable the sps parse to workaround when parse sps failed. | ||
| 1795 | + // @see https://github.com/simple-rtmp-server/srs/issues/474 | ||
| 1796 | + codec.avc_parse_sps = _srs_config->get_parse_sps(_req->vhost); | ||
| 1797 | + | ||
| 1798 | + SrsCodecSample sample; | ||
| 1799 | + if ((ret = codec.video_avc_demux(msg->payload, msg->size, &sample)) != ERROR_SUCCESS) { | ||
| 1800 | + srs_error("source codec demux video failed. ret=%d", ret); | ||
| 1801 | + return ret; | ||
| 1802 | + } | ||
| 1803 | + | ||
| 1804 | + // when got video stream info. | ||
| 1805 | + SrsStatistic* stat = SrsStatistic::instance(); | ||
| 1806 | + if ((ret = stat->on_video_info(_req, SrsCodecVideoAVC, codec.avc_profile, codec.avc_level, codec.width, codec.height)) != ERROR_SUCCESS) { | ||
| 1807 | + return ret; | ||
| 1808 | + } | ||
| 1809 | + | ||
| 1810 | + srs_trace("%dB video sh, codec(%d, profile=%s, level=%s, %dx%d, %dkbps, %dfps, %ds)", | ||
| 1811 | + msg->size, codec.video_codec_id, | ||
| 1812 | + srs_codec_avc_profile2str(codec.avc_profile).c_str(), | ||
| 1813 | + srs_codec_avc_level2str(codec.avc_level).c_str(), codec.width, codec.height, | ||
| 1814 | + codec.video_data_rate / 1000, codec.frame_rate, codec.duration); | ||
| 1815 | + } | ||
| 1816 | + | ||
| 1771 | #ifdef SRS_AUTO_HLS | 1817 | #ifdef SRS_AUTO_HLS |
| 1772 | - if ((ret = hls->on_video(msg)) != ERROR_SUCCESS) { | 1818 | + if ((ret = hls->on_video(msg, is_sequence_header)) != ERROR_SUCCESS) { |
| 1773 | // apply the error strategy for hls. | 1819 | // apply the error strategy for hls. |
| 1774 | // @see https://github.com/simple-rtmp-server/srs/issues/264 | 1820 | // @see https://github.com/simple-rtmp-server/srs/issues/264 |
| 1775 | std::string hls_error_strategy = _srs_config->get_hls_on_error(_req->vhost); | 1821 | std::string hls_error_strategy = _srs_config->get_hls_on_error(_req->vhost); |
| @@ -1821,13 +1867,6 @@ int SrsSource::on_video_imp(SrsSharedPtrMessage* msg) | @@ -1821,13 +1867,6 @@ int SrsSource::on_video_imp(SrsSharedPtrMessage* msg) | ||
| 1821 | #endif | 1867 | #endif |
| 1822 | 1868 | ||
| 1823 | // copy to all consumer | 1869 | // copy to all consumer |
| 1824 | - bool drop_for_reduce = false; | ||
| 1825 | - if (is_sequence_header && cache_sh_video && _srs_config->get_reduce_sequence_header(_req->vhost)) { | ||
| 1826 | - if (cache_sh_video->size == msg->size) { | ||
| 1827 | - drop_for_reduce = srs_bytes_equals(cache_sh_video->payload, msg->payload, msg->size); | ||
| 1828 | - srs_warn("drop for reduce sh video, size=%d", msg->size); | ||
| 1829 | - } | ||
| 1830 | - } | ||
| 1831 | if (!drop_for_reduce) { | 1870 | if (!drop_for_reduce) { |
| 1832 | for (int i = 0; i < (int)consumers.size(); i++) { | 1871 | for (int i = 0; i < (int)consumers.size(); i++) { |
| 1833 | SrsConsumer* consumer = consumers.at(i); | 1872 | SrsConsumer* consumer = consumers.at(i); |
| @@ -1851,32 +1890,8 @@ int SrsSource::on_video_imp(SrsSharedPtrMessage* msg) | @@ -1851,32 +1890,8 @@ int SrsSource::on_video_imp(SrsSharedPtrMessage* msg) | ||
| 1851 | } | 1890 | } |
| 1852 | } | 1891 | } |
| 1853 | 1892 | ||
| 1854 | - // cache the sequence header if h264 | ||
| 1855 | - // donot cache the sequence header to gop_cache, return here. | 1893 | + // when sequence header, donot push to gop cache and adjust the timestamp. |
| 1856 | if (is_sequence_header) { | 1894 | if (is_sequence_header) { |
| 1857 | - srs_freep(cache_sh_video); | ||
| 1858 | - cache_sh_video = msg->copy(); | ||
| 1859 | - | ||
| 1860 | - // parse detail audio codec | ||
| 1861 | - SrsAvcAacCodec codec; | ||
| 1862 | - SrsCodecSample sample; | ||
| 1863 | - if ((ret = codec.video_avc_demux(msg->payload, msg->size, &sample)) != ERROR_SUCCESS) { | ||
| 1864 | - srs_error("source codec demux video failed. ret=%d", ret); | ||
| 1865 | - return ret; | ||
| 1866 | - } | ||
| 1867 | - | ||
| 1868 | - // when got video stream info. | ||
| 1869 | - SrsStatistic* stat = SrsStatistic::instance(); | ||
| 1870 | - if ((ret = stat->on_video_info(_req, SrsCodecVideoAVC, codec.avc_profile, codec.avc_level, codec.width, codec.height)) != ERROR_SUCCESS) { | ||
| 1871 | - return ret; | ||
| 1872 | - } | ||
| 1873 | - | ||
| 1874 | - srs_trace("%dB video sh, " | ||
| 1875 | - "codec(%d, profile=%s, level=%s, %dx%d, %dkbps, %dfps, %ds)", | ||
| 1876 | - msg->size, codec.video_codec_id, | ||
| 1877 | - srs_codec_avc_profile2str(codec.avc_profile).c_str(), | ||
| 1878 | - srs_codec_avc_level2str(codec.avc_level).c_str(), codec.width, codec.height, | ||
| 1879 | - codec.video_data_rate / 1000, codec.frame_rate, codec.duration); | ||
| 1880 | return ret; | 1895 | return ret; |
| 1881 | } | 1896 | } |
| 1882 | 1897 | ||
| @@ -2044,7 +2059,7 @@ int SrsSource::on_publish() | @@ -2044,7 +2059,7 @@ int SrsSource::on_publish() | ||
| 2044 | 2059 | ||
| 2045 | // TODO: FIXME: use initialize to set req. | 2060 | // TODO: FIXME: use initialize to set req. |
| 2046 | #ifdef SRS_AUTO_HLS | 2061 | #ifdef SRS_AUTO_HLS |
| 2047 | - if ((ret = hls->on_publish(_req)) != ERROR_SUCCESS) { | 2062 | + if ((ret = hls->on_publish(_req, false)) != ERROR_SUCCESS) { |
| 2048 | srs_error("start hls failed. ret=%d", ret); | 2063 | srs_error("start hls failed. ret=%d", ret); |
| 2049 | return ret; | 2064 | return ret; |
| 2050 | } | 2065 | } |
| @@ -2079,6 +2094,7 @@ int SrsSource::on_publish() | @@ -2079,6 +2094,7 @@ int SrsSource::on_publish() | ||
| 2079 | } | 2094 | } |
| 2080 | SrsStatistic* stat = SrsStatistic::instance(); | 2095 | SrsStatistic* stat = SrsStatistic::instance(); |
| 2081 | stat->on_stream_publish(_req, _source_id); | 2096 | stat->on_stream_publish(_req, _source_id); |
| 2097 | + | ||
| 2082 | return ret; | 2098 | return ret; |
| 2083 | } | 2099 | } |
| 2084 | 2100 |
| @@ -191,6 +191,10 @@ private: | @@ -191,6 +191,10 @@ private: | ||
| 191 | * if no iframe found, clear it. | 191 | * if no iframe found, clear it. |
| 192 | */ | 192 | */ |
| 193 | virtual void shrink(); | 193 | virtual void shrink(); |
| 194 | +public: | ||
| 195 | + /** | ||
| 196 | + * clear all messages in queue. | ||
| 197 | + */ | ||
| 194 | virtual void clear(); | 198 | virtual void clear(); |
| 195 | }; | 199 | }; |
| 196 | 200 |
| @@ -66,6 +66,7 @@ namespace internal { | @@ -66,6 +66,7 @@ namespace internal { | ||
| 66 | really_terminated = true; | 66 | really_terminated = true; |
| 67 | _cid = -1; | 67 | _cid = -1; |
| 68 | _joinable = joinable; | 68 | _joinable = joinable; |
| 69 | + disposed = false; | ||
| 69 | 70 | ||
| 70 | // in start(), the thread cycle method maybe stop and remove the thread itself, | 71 | // in start(), the thread cycle method maybe stop and remove the thread itself, |
| 71 | // and the thread start() is waiting for the _cid, and segment fault then. | 72 | // and the thread start() is waiting for the _cid, and segment fault then. |
| @@ -115,8 +116,32 @@ namespace internal { | @@ -115,8 +116,32 @@ namespace internal { | ||
| 115 | 116 | ||
| 116 | void SrsThread::stop() | 117 | void SrsThread::stop() |
| 117 | { | 118 | { |
| 118 | - if (tid) { | 119 | + if (!tid) { |
| 120 | + return; | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + loop = false; | ||
| 124 | + | ||
| 125 | + dispose(); | ||
| 126 | + | ||
| 127 | + tid = NULL; | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + bool SrsThread::can_loop() | ||
| 131 | + { | ||
| 132 | + return loop; | ||
| 133 | + } | ||
| 134 | + | ||
| 135 | + void SrsThread::stop_loop() | ||
| 136 | + { | ||
| 119 | loop = false; | 137 | loop = false; |
| 138 | + } | ||
| 139 | + | ||
| 140 | + void SrsThread::dispose() | ||
| 141 | + { | ||
| 142 | + if (disposed) { | ||
| 143 | + return; | ||
| 144 | + } | ||
| 120 | 145 | ||
| 121 | // the interrupt will cause the socket to read/write error, | 146 | // the interrupt will cause the socket to read/write error, |
| 122 | // which will terminate the cycle thread. | 147 | // which will terminate the cycle thread. |
| @@ -145,18 +170,7 @@ namespace internal { | @@ -145,18 +170,7 @@ namespace internal { | ||
| 145 | srs_warn("core: wait thread to actually terminated"); | 170 | srs_warn("core: wait thread to actually terminated"); |
| 146 | } | 171 | } |
| 147 | 172 | ||
| 148 | - tid = NULL; | ||
| 149 | - } | ||
| 150 | - } | ||
| 151 | - | ||
| 152 | - bool SrsThread::can_loop() | ||
| 153 | - { | ||
| 154 | - return loop; | ||
| 155 | - } | ||
| 156 | - | ||
| 157 | - void SrsThread::stop_loop() | ||
| 158 | - { | ||
| 159 | - loop = false; | 173 | + disposed = true; |
| 160 | } | 174 | } |
| 161 | 175 | ||
| 162 | void SrsThread::thread_cycle() | 176 | void SrsThread::thread_cycle() |
| @@ -217,6 +231,9 @@ namespace internal { | @@ -217,6 +231,9 @@ namespace internal { | ||
| 217 | 231 | ||
| 218 | handler->on_thread_stop(); | 232 | handler->on_thread_stop(); |
| 219 | srs_info("thread %s cycle finished", _name); | 233 | srs_info("thread %s cycle finished", _name); |
| 234 | + | ||
| 235 | + // when thread terminated normally, also disposed. | ||
| 236 | + disposed = true; | ||
| 220 | } | 237 | } |
| 221 | 238 | ||
| 222 | void* SrsThread::thread_fun(void* arg) | 239 | void* SrsThread::thread_fun(void* arg) |
| @@ -100,6 +100,7 @@ namespace internal { | @@ -100,6 +100,7 @@ namespace internal { | ||
| 100 | bool really_terminated; | 100 | bool really_terminated; |
| 101 | bool _joinable; | 101 | bool _joinable; |
| 102 | const char* _name; | 102 | const char* _name; |
| 103 | + bool disposed; | ||
| 103 | private: | 104 | private: |
| 104 | ISrsThreadHandler* handler; | 105 | ISrsThreadHandler* handler; |
| 105 | int64_t cycle_interval_us; | 106 | int64_t cycle_interval_us; |
| @@ -154,6 +155,7 @@ namespace internal { | @@ -154,6 +155,7 @@ namespace internal { | ||
| 154 | */ | 155 | */ |
| 155 | virtual void stop_loop(); | 156 | virtual void stop_loop(); |
| 156 | private: | 157 | private: |
| 158 | + virtual void dispose(); | ||
| 157 | virtual void thread_cycle(); | 159 | virtual void thread_cycle(); |
| 158 | static void* thread_fun(void* arg); | 160 | static void* thread_fun(void* arg); |
| 159 | }; | 161 | }; |
| @@ -382,6 +382,8 @@ int SrsCodecSample::add_sample_unit(char* bytes, int size) | @@ -382,6 +382,8 @@ int SrsCodecSample::add_sample_unit(char* bytes, int size) | ||
| 382 | 382 | ||
| 383 | SrsAvcAacCodec::SrsAvcAacCodec() | 383 | SrsAvcAacCodec::SrsAvcAacCodec() |
| 384 | { | 384 | { |
| 385 | + avc_parse_sps = true; | ||
| 386 | + | ||
| 385 | width = 0; | 387 | width = 0; |
| 386 | height = 0; | 388 | height = 0; |
| 387 | duration = 0; | 389 | duration = 0; |
| @@ -939,6 +941,12 @@ int SrsAvcAacCodec::avc_demux_sps_rbsp(char* rbsp, int nb_rbsp) | @@ -939,6 +941,12 @@ int SrsAvcAacCodec::avc_demux_sps_rbsp(char* rbsp, int nb_rbsp) | ||
| 939 | { | 941 | { |
| 940 | int ret = ERROR_SUCCESS; | 942 | int ret = ERROR_SUCCESS; |
| 941 | 943 | ||
| 944 | + // we donot parse the detail of sps. | ||
| 945 | + // @see https://github.com/simple-rtmp-server/srs/issues/474 | ||
| 946 | + if (!avc_parse_sps) { | ||
| 947 | + return ret; | ||
| 948 | + } | ||
| 949 | + | ||
| 942 | // reparse the rbsp. | 950 | // reparse the rbsp. |
| 943 | SrsStream stream; | 951 | SrsStream stream; |
| 944 | if ((ret = stream.initialize(rbsp, nb_rbsp)) != ERROR_SUCCESS) { | 952 | if ((ret = stream.initialize(rbsp, nb_rbsp)) != ERROR_SUCCESS) { |
| @@ -606,6 +606,9 @@ public: | @@ -606,6 +606,9 @@ public: | ||
| 606 | int aac_extra_size; | 606 | int aac_extra_size; |
| 607 | char* aac_extra_data; | 607 | char* aac_extra_data; |
| 608 | public: | 608 | public: |
| 609 | + // for sequence header, whether parse the h.264 sps. | ||
| 610 | + bool avc_parse_sps; | ||
| 611 | +public: | ||
| 609 | SrsAvcAacCodec(); | 612 | SrsAvcAacCodec(); |
| 610 | virtual ~SrsAvcAacCodec(); | 613 | virtual ~SrsAvcAacCodec(); |
| 611 | public: | 614 | public: |
| @@ -905,7 +905,7 @@ namespace _srs_internal | @@ -905,7 +905,7 @@ namespace _srs_internal | ||
| 905 | } | 905 | } |
| 906 | 906 | ||
| 907 | // client c1 time and version | 907 | // client c1 time and version |
| 908 | - time = ::time(NULL); | 908 | + time = (int32_t)::time(NULL); |
| 909 | version = 0x80000702; // client c1 version | 909 | version = 0x80000702; // client c1 version |
| 910 | 910 | ||
| 911 | // generate signature by schema | 911 | // generate signature by schema |
-
请 注册 或 登录 后发表评论