diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 470a0555ed..4cf4ed9a61 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -1049,6 +1049,9 @@ vhost publish.srs.com { # @remark If disabled, HLS might never update the sps/pps, it depends on this. # default: on parse_sps on; + # When parsing SPS/PPS, whether try ANNEXB first. If not, try IBMF first, then ANNEXB. + # default: on + try_annexb_first on; } } diff --git a/trunk/doc/CHANGELOG.md b/trunk/doc/CHANGELOG.md index 3738213359..3cd12117fb 100644 --- a/trunk/doc/CHANGELOG.md +++ b/trunk/doc/CHANGELOG.md @@ -7,6 +7,7 @@ The changelog for SRS. ## SRS 5.0 Changelog +* v5.0, 2022-09-01, Fix [#1405](https://github.com/ossrs/srs/issues/1405): Support guessing IBMF first. v5.0.58 * v5.0, 2022-09-01, ST: Define and use a new jmpbuf. v5.0.57 * v5.0, 2022-08-31, Fix URL parsing bug for `__defaultVhost__`. v5.0.56 * v5.0, 2022-08-30, Fix [#2837](https://github.com/ossrs/srs/issues/2837): Callback: Support stream_url and stream_id. v5.0.55 diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 7c44fb377c..932e9edf39 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -2499,7 +2499,8 @@ srs_error_t SrsConfig::check_normal_config() } else if (n == "publish") { for (int j = 0; j < (int)conf->directives.size(); j++) { string m = conf->at(j)->name; - if (m != "mr" && m != "mr_latency" && m != "firstpkt_timeout" && m != "normal_timeout" && m != "parse_sps") { + if (m != "mr" && m != "mr_latency" && m != "firstpkt_timeout" && m != "normal_timeout" + && m != "parse_sps" && m != "try_annexb_first") { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.publish.%s of %s", m.c_str(), vhost->arg0().c_str()); } } @@ -4379,23 +4380,46 @@ int SrsConfig::get_chunk_size(string vhost) bool SrsConfig::get_parse_sps(string vhost) { static bool DEFAULT = true; - + SrsConfDirective* conf = get_vhost(vhost); - + if (!conf) { return DEFAULT; } - + conf = conf->get("publish"); if (!conf) { return DEFAULT; } - + conf = conf->get("parse_sps"); if (!conf || conf->arg0().empty()) { return DEFAULT; } - + + return SRS_CONF_PERFER_TRUE(conf->arg0()); +} + +bool SrsConfig::try_annexb_first(string vhost) +{ + static bool DEFAULT = true; + + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return DEFAULT; + } + + conf = conf->get("publish"); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("try_annexb_first"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + return SRS_CONF_PERFER_TRUE(conf->arg0()); } diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 6b1baf368c..18300b225a 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -593,6 +593,8 @@ class SrsConfig virtual int get_chunk_size(std::string vhost); // Whether parse the sps when publish stream to SRS. virtual bool get_parse_sps(std::string vhost); + // Whether try ANNEXB first when parsing SPS/PPS. + virtual bool try_annexb_first(std::string vhost); // Whether mr is enabled for vhost. // @param vhost, the vhost to get the mr. virtual bool get_mr_enabled(std::string vhost); diff --git a/trunk/src/app/srs_app_rtc_source.cpp b/trunk/src/app/srs_app_rtc_source.cpp index 734e3561fe..f3d9c53465 100644 --- a/trunk/src/app/srs_app_rtc_source.cpp +++ b/trunk/src/app/srs_app_rtc_source.cpp @@ -752,6 +752,9 @@ srs_error_t SrsRtcFromRtmpBridge::initialize(SrsRequest* r) return srs_error_wrap(err, "format initialize"); } + // Setup the SPS/PPS parsing strategy. + format->try_annexb_first = _srs_config->try_annexb_first(r->vhost); + int bitrate = 48000; // The output bitrate in bps. if ((err = codec_->initialize(SrsAudioCodecIdAAC, SrsAudioCodecIdOpus, kAudioChannel, kAudioSamplerate, bitrate)) != srs_success) { @@ -1309,6 +1312,9 @@ srs_error_t SrsRtmpFromRtcBridge::initialize(SrsRequest* r) return srs_error_wrap(err, "format initialize"); } + // Setup the SPS/PPS parsing strategy. + format->try_annexb_first = _srs_config->try_annexb_first(r->vhost); + return err; } diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index f7120d9d64..a5d2e2a892 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -858,6 +858,9 @@ srs_error_t SrsOriginHub::initialize(SrsLiveSource* s, SrsRequest* r) if ((err = format->initialize()) != srs_success) { return srs_error_wrap(err, "format initialize"); } + + // Setup the SPS/PPS parsing strategy. + format->try_annexb_first = _srs_config->try_annexb_first(r->vhost); if ((err = hls->initialize(this, req_)) != srs_success) { return srs_error_wrap(err, "hls initialize"); diff --git a/trunk/src/core/srs_core_version5.hpp b/trunk/src/core/srs_core_version5.hpp index 4853ef1a08..aa7ee67cc4 100644 --- a/trunk/src/core/srs_core_version5.hpp +++ b/trunk/src/core/srs_core_version5.hpp @@ -9,6 +9,6 @@ #define VERSION_MAJOR 5 #define VERSION_MINOR 0 -#define VERSION_REVISION 57 +#define VERSION_REVISION 58 #endif diff --git a/trunk/src/kernel/srs_kernel_codec.cpp b/trunk/src/kernel/srs_kernel_codec.cpp index f914637de9..bf2fa6779b 100644 --- a/trunk/src/kernel/srs_kernel_codec.cpp +++ b/trunk/src/kernel/srs_kernel_codec.cpp @@ -572,6 +572,7 @@ SrsFormat::SrsFormat() audio = NULL; video = NULL; avc_parse_sps = true; + try_annexb_first = true; raw = NULL; nb_raw = 0; } @@ -1138,23 +1139,34 @@ srs_error_t SrsFormat::video_nalu_demux(SrsBuffer* stream) // guess for the first time. if (vcodec->payload_format == SrsAvcPayloadFormatGuess) { - // One or more NALUs (Full frames are required) - // try "AnnexB" from ISO_IEC_14496-10-AVC-2003.pdf, page 211. - if ((err = avc_demux_annexb_format(stream)) != srs_success) { - // stop try when system error. - if (srs_error_code(err) != ERROR_HLS_AVC_TRY_OTHERS) { - return srs_error_wrap(err, "avc demux for annexb"); - } - srs_freep(err); - - // try "ISO Base Media File Format" from ISO_IEC_14496-15-AVC-format-2012.pdf, page 20 - if ((err = avc_demux_ibmf_format(stream)) != srs_success) { - return srs_error_wrap(err, "avc demux ibmf"); + if (try_annexb_first) { + // One or more NALUs (Full frames are required) + // try "AnnexB" from ISO_IEC_14496-10-AVC-2003.pdf, page 211. + if ((err = avc_demux_annexb_format(stream)) != srs_success) { + srs_freep(err); + + // try "ISO Base Media File Format" from ISO_IEC_14496-15-AVC-format-2012.pdf, page 20 + if ((err = avc_demux_ibmf_format(stream)) != srs_success) { + return srs_error_wrap(err, "avc demux ibmf"); + } else { + vcodec->payload_format = SrsAvcPayloadFormatIbmf; + } } else { - vcodec->payload_format = SrsAvcPayloadFormatIbmf; + vcodec->payload_format = SrsAvcPayloadFormatAnnexb; } } else { - vcodec->payload_format = SrsAvcPayloadFormatAnnexb; + // One or more NALUs (Full frames are required) + // try "AnnexB" from ISO_IEC_14496-10-AVC-2003.pdf, page 211. + if ((err = avc_demux_ibmf_format(stream)) == srs_success) { + vcodec->payload_format = SrsAvcPayloadFormatIbmf; + } else { + srs_freep(err); + if ((err = avc_demux_annexb_format(stream)) == srs_success) { + vcodec->payload_format = SrsAvcPayloadFormatAnnexb; + } else { + return srs_error_wrap(err, "avc demux annexb"); + } + } } } else if (vcodec->payload_format == SrsAvcPayloadFormatIbmf) { // try "ISO Base Media File Format" from ISO_IEC_14496-15-AVC-format-2012.pdf, page 20 @@ -1165,10 +1177,6 @@ srs_error_t SrsFormat::video_nalu_demux(SrsBuffer* stream) // One or more NALUs (Full frames are required) // try "AnnexB" from ISO_IEC_14496-10-AVC-2003.pdf, page 211. if ((err = avc_demux_annexb_format(stream)) != srs_success) { - // ok, we guess out the payload is annexb, but maybe changed to ibmf. - if (srs_error_code(err) != ERROR_HLS_AVC_TRY_OTHERS) { - return srs_error_wrap(err, "avc demux annexb"); - } srs_freep(err); // try "ISO Base Media File Format" from ISO_IEC_14496-15-AVC-format-2012.pdf, page 20 diff --git a/trunk/src/kernel/srs_kernel_codec.hpp b/trunk/src/kernel/srs_kernel_codec.hpp index 6f3b66aedb..da97f390ef 100644 --- a/trunk/src/kernel/srs_kernel_codec.hpp +++ b/trunk/src/kernel/srs_kernel_codec.hpp @@ -724,6 +724,8 @@ class SrsFormat // for sequence header, whether parse the h.264 sps. // TODO: FIXME: Refine it. bool avc_parse_sps; + // Whether try to parse in ANNEXB, then by IBMF. + bool try_annexb_first; public: SrsFormat(); virtual ~SrsFormat(); diff --git a/trunk/src/utest/srs_utest_config.cpp b/trunk/src/utest/srs_utest_config.cpp index 01f883cfe9..9ea1c61a8d 100644 --- a/trunk/src/utest/srs_utest_config.cpp +++ b/trunk/src/utest/srs_utest_config.cpp @@ -2928,6 +2928,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig2) EXPECT_EQ(2500000, conf.get_out_ack_size("ossrs.net")); EXPECT_EQ(60000, conf.get_chunk_size("ossrs.net")); EXPECT_TRUE(conf.get_parse_sps("ossrs.net")); + EXPECT_TRUE(conf.try_annexb_first("ossrs.net")); EXPECT_FALSE(conf.get_mr_enabled("ossrs.net")); EXPECT_EQ(350 * SRS_UTIME_MILLISECONDS, conf.get_mr_sleep("ossrs.net")); EXPECT_EQ(350 * SRS_UTIME_MILLISECONDS, conf.get_mw_sleep("ossrs.net")); @@ -3020,6 +3021,12 @@ VOID TEST(ConfigMainTest, CheckVhostConfig2) EXPECT_FALSE(conf.get_parse_sps("ossrs.net")); } + if (true) { + MockSrsConfig conf; + HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{publish{try_annexb_first off;}}")); + EXPECT_FALSE(conf.try_annexb_first("ossrs.net")); + } + if (true) { MockSrsConfig conf; HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{chunk_size 10;}"));