HLS: Remove deprecated hls_acodec/hls_vcodec configs. v7.0.53 (#4225)
## Summary Removes the deprecated `hls_acodec` and `hls_vcodec` configuration options and implements automatic codec detection for HLS streams, fixing issues with video-only streams incorrectly showing audio information. ## Problem - When streaming video-only content via RTMP, HLS output incorrectly contained audio track information due to hardcoded default codec settings - The static `hls_acodec` and `hls_vcodec` configurations were inflexible and caused compatibility issues with some players - Users had to manually configure `hls_acodec an` to fix video-only streams ## Solution - **Remove deprecated configs**: Eliminates `hls_acodec` and `hls_vcodec` configuration options entirely - **Dynamic codec detection**: HLS muxer now automatically detects and uses actual stream codecs in real-time - **Improved defaults**: Changes from hardcoded AAC/H.264 defaults to disabled state, letting actual stream content determine codec information - **Real-time codec switching**: Supports codec changes during streaming with proper logging ## Changes - Remove `get_hls_acodec()` and `get_hls_vcodec()` from SrsConfig - Update HLS muxer to use `latest_acodec_`/`latest_vcodec_` for codec detection - Add codec detection logic in `write_audio()` and `write_video()` methods - Remove deprecated config options from all configuration files - Add comprehensive unit tests for codec detection functionality Fixes #4223 --------- Co-authored-by: Haibo Chen <495810242@qq.com> Co-authored-by: OSSRS-AI <winlinam@gmail.com>
This commit is contained in:
parent
7e8728755e
commit
7aba442a38
|
|
@ -1941,22 +1941,6 @@ vhost hls.srs.com {
|
|||
# Overwrite by env SRS_VHOST_HLS_HLS_ENTRY_PREFIX for all vhosts.
|
||||
# optional, default to empty string.
|
||||
hls_entry_prefix http://your-server;
|
||||
# the default audio codec of hls.
|
||||
# when codec changed, write the PAT/PMT table, but maybe ok util next ts.
|
||||
# so user can set the default codec for mp3.
|
||||
# the available audio codec:
|
||||
# aac, mp3, an
|
||||
# Overwrite by env SRS_VHOST_HLS_HLS_ACODEC for all vhosts.
|
||||
# default: aac
|
||||
hls_acodec aac;
|
||||
# the default video codec of hls.
|
||||
# when codec changed, write the PAT/PMT table, but maybe ok util next ts.
|
||||
# so user can set the default codec for pure audio(without video) to vn.
|
||||
# the available video codec:
|
||||
# h264, vn
|
||||
# Overwrite by env SRS_VHOST_HLS_HLS_VCODEC for all vhosts.
|
||||
# default: h264
|
||||
hls_vcodec h264;
|
||||
# whether cleanup the old expired ts files.
|
||||
# Overwrite by env SRS_VHOST_HLS_HLS_CLEANUP for all vhosts.
|
||||
# default: on
|
||||
|
|
|
|||
|
|
@ -14,6 +14,5 @@ vhost __defaultVhost__ {
|
|||
}
|
||||
hls {
|
||||
enabled on;
|
||||
hls_acodec mp3;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ vhost __defaultVhost__ {
|
|||
}
|
||||
hls {
|
||||
enabled on;
|
||||
hls_acodec mp3;
|
||||
}
|
||||
rtc {
|
||||
enabled on;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ The changelog for SRS.
|
|||
<a name="v7-changes"></a>
|
||||
|
||||
## SRS 7.0 Changelog
|
||||
* v7.0, 2025-08-13, Merge [#4225](https://github.com/ossrs/srs/pull/4225): issue #4223: remove hls_acodec and hls_vcodec config. v7.0.53 (#4225)
|
||||
* v7.0, 2025-08-12, Merge [#4230](https://github.com/ossrs/srs/pull/4230): MP4 DVR: Fix audio/video synchronization issues in WebRTC recordings. v7.0.52 (#4230)
|
||||
* v7.0, 2025-08-12, Merge [#4301](https://github.com/ossrs/srs/pull/4301): Valgrind: Return error for unsupported check=new on Valgrind < 3.21. v7.0.52 (#4301)
|
||||
* v7.0, 2025-08-12, Merge [#4431](https://github.com/ossrs/srs/pull/4431): fix srt cmake 4.x compiling error. v7.0.52 (#4431)
|
||||
|
|
|
|||
|
|
@ -7284,44 +7284,6 @@ string SrsConfig::get_hls_on_error(string vhost)
|
|||
return conf->arg0();
|
||||
}
|
||||
|
||||
string SrsConfig::get_hls_acodec(string vhost)
|
||||
{
|
||||
SRS_OVERWRITE_BY_ENV_STRING("srs.vhost.hls.hls_acodec"); // SRS_VHOST_HLS_HLS_ACODEC
|
||||
|
||||
static string DEFAULT = "aac";
|
||||
|
||||
SrsConfDirective *conf = get_hls(vhost);
|
||||
if (!conf) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
conf = conf->get("hls_acodec");
|
||||
if (!conf || conf->arg0().empty()) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
return conf->arg0();
|
||||
}
|
||||
|
||||
string SrsConfig::get_hls_vcodec(string vhost)
|
||||
{
|
||||
SRS_OVERWRITE_BY_ENV_STRING("srs.vhost.hls.hls_vcodec"); // SRS_VHOST_HLS_HLS_VCODEC
|
||||
|
||||
static string DEFAULT = "h264";
|
||||
|
||||
SrsConfDirective *conf = get_hls(vhost);
|
||||
if (!conf) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
conf = conf->get("hls_vcodec");
|
||||
if (!conf || conf->arg0().empty()) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
return conf->arg0();
|
||||
}
|
||||
|
||||
int SrsConfig::get_vhost_hls_nb_notify(string vhost)
|
||||
{
|
||||
SRS_OVERWRITE_BY_ENV_INT("srs.vhost.hls.hls_nb_notify"); // SRS_VHOST_HLS_HLS_NB_NOTIFY
|
||||
|
|
|
|||
|
|
@ -1006,10 +1006,6 @@ public:
|
|||
// The ignore will ignore error and disable hls.
|
||||
// The disconnect will disconnect publish connection.
|
||||
virtual std::string get_hls_on_error(std::string vhost);
|
||||
// Get the HLS default audio codec.
|
||||
virtual std::string get_hls_acodec(std::string vhost);
|
||||
// Get the HLS default video codec.
|
||||
virtual std::string get_hls_vcodec(std::string vhost);
|
||||
// Whether cleanup the old ts files.
|
||||
virtual bool get_hls_cleanup(std::string vhost);
|
||||
// The timeout in srs_utime_t to dispose the hls.
|
||||
|
|
|
|||
|
|
@ -1267,37 +1267,15 @@ srs_error_t SrsHlsMuxer::segment_open()
|
|||
srs_assert(!current);
|
||||
|
||||
// load the default acodec from config.
|
||||
SrsAudioCodecId default_acodec = SrsAudioCodecIdAAC;
|
||||
if (true) {
|
||||
std::string default_acodec_str = _srs_config->get_hls_acodec(req->vhost);
|
||||
if (default_acodec_str == "mp3") {
|
||||
default_acodec = SrsAudioCodecIdMP3;
|
||||
} else if (default_acodec_str == "aac") {
|
||||
default_acodec = SrsAudioCodecIdAAC;
|
||||
} else if (default_acodec_str == "an") {
|
||||
default_acodec = SrsAudioCodecIdDisabled;
|
||||
} else {
|
||||
srs_warn("hls: use aac for other codec=%s", default_acodec_str.c_str());
|
||||
}
|
||||
}
|
||||
SrsAudioCodecId default_acodec = SrsAudioCodecIdDisabled;
|
||||
|
||||
// Now that we know the latest audio codec in stream, use it.
|
||||
if (latest_acodec_ != SrsAudioCodecIdForbidden)
|
||||
default_acodec = latest_acodec_;
|
||||
|
||||
// load the default vcodec from config.
|
||||
SrsVideoCodecId default_vcodec = SrsVideoCodecIdAVC;
|
||||
if (true) {
|
||||
std::string default_vcodec_str = _srs_config->get_hls_vcodec(req->vhost);
|
||||
if (default_vcodec_str == "h264") {
|
||||
default_vcodec = SrsVideoCodecIdAVC;
|
||||
} else if (default_vcodec_str == "h265") {
|
||||
default_vcodec = SrsVideoCodecIdHEVC;
|
||||
} else if (default_vcodec_str == "vn") {
|
||||
default_vcodec = SrsVideoCodecIdDisabled;
|
||||
} else {
|
||||
srs_warn("hls: use h264 for other codec=%s", default_vcodec_str.c_str());
|
||||
}
|
||||
}
|
||||
SrsVideoCodecId default_vcodec = SrsVideoCodecIdDisabled;
|
||||
|
||||
// Now that we know the latest video codec in stream, use it.
|
||||
if (latest_vcodec_ != SrsVideoCodecIdForbidden)
|
||||
default_vcodec = latest_vcodec_;
|
||||
|
|
@ -2156,12 +2134,20 @@ srs_error_t SrsHlsMp4Controller::on_unpublish()
|
|||
srs_error_t SrsHlsMp4Controller::write_audio(SrsSharedPtrMessage *shared_audio, SrsFormat *format)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
SrsAudioFrame *frame = format->audio;
|
||||
|
||||
// Ignore audio sequence header
|
||||
if (format->is_aac_sequence_header() || format->is_mp3_sequence_header()) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// Refresh the codec ASAP.
|
||||
if (muxer_->latest_acodec() != frame->acodec()->id) {
|
||||
srs_trace("HLS: Switch audio codec %d(%s) to %d(%s)", muxer_->latest_acodec(), srs_audio_codec_id2str(muxer_->latest_acodec()).c_str(),
|
||||
frame->acodec()->id, srs_audio_codec_id2str(frame->acodec()->id).c_str());
|
||||
muxer_->set_latest_acodec(frame->acodec()->id);
|
||||
}
|
||||
|
||||
audio_dts_ = shared_audio->timestamp;
|
||||
|
||||
if ((err = muxer_->write_audio(shared_audio, format)) != srs_success) {
|
||||
|
|
@ -2178,7 +2164,7 @@ srs_error_t SrsHlsMp4Controller::write_video(SrsSharedPtrMessage *shared_video,
|
|||
|
||||
// Refresh the codec ASAP.
|
||||
if (muxer_->latest_vcodec() != frame->vcodec()->id) {
|
||||
srs_trace("HLS: Switch video codec %d(%s) to %d(%s)", muxer_->latest_acodec(), srs_video_codec_id2str(muxer_->latest_vcodec()).c_str(),
|
||||
srs_trace("HLS: Switch video codec %d(%s) to %d(%s)", muxer_->latest_vcodec(), srs_video_codec_id2str(muxer_->latest_vcodec()).c_str(),
|
||||
frame->vcodec()->id, srs_video_codec_id2str(frame->vcodec()->id).c_str());
|
||||
muxer_->set_latest_vcodec(frame->vcodec()->id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@
|
|||
|
||||
#define VERSION_MAJOR 7
|
||||
#define VERSION_MINOR 0
|
||||
#define VERSION_REVISION 52
|
||||
#define VERSION_REVISION 53
|
||||
|
||||
#endif
|
||||
|
|
@ -3742,13 +3742,11 @@ VOID TEST(ConfigMainTest, CheckVhostConfig5)
|
|||
|
||||
if (true) {
|
||||
MockSrsConfig conf;
|
||||
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{hls{hls_td_ratio 2.1;hls_aof_ratio 3.1;hls_window 10;hls_on_error xxx;hls_acodec xxx2;hls_vcodec xxx3;hls_nb_notify 5;hls_dts_directly off;hls_cleanup off;hls_dispose 10;hls_wait_keyframe off;}}"));
|
||||
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{hls{hls_td_ratio 2.1;hls_aof_ratio 3.1;hls_window 10;hls_on_error xxx;hls_nb_notify 5;hls_dts_directly off;hls_cleanup off;hls_dispose 10;hls_wait_keyframe off;}}"));
|
||||
EXPECT_EQ(2.1, conf.get_hls_td_ratio("ossrs.net"));
|
||||
EXPECT_EQ(3.1, conf.get_hls_aof_ratio("ossrs.net"));
|
||||
EXPECT_EQ(10 * SRS_UTIME_SECONDS, conf.get_hls_window("ossrs.net"));
|
||||
EXPECT_STREQ("xxx", conf.get_hls_on_error("ossrs.net").c_str());
|
||||
EXPECT_STREQ("xxx2", conf.get_hls_acodec("ossrs.net").c_str());
|
||||
EXPECT_STREQ("xxx3", conf.get_hls_vcodec("ossrs.net").c_str());
|
||||
EXPECT_EQ(5, conf.get_vhost_hls_nb_notify("ossrs.net"));
|
||||
EXPECT_FALSE(conf.get_vhost_hls_dts_directly("ossrs.net"));
|
||||
EXPECT_FALSE(conf.get_hls_cleanup("ossrs.net"));
|
||||
|
|
@ -5118,12 +5116,6 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesHls)
|
|||
SrsSetEnvConfig(conf, hls_entry_prefix, "SRS_VHOST_HLS_HLS_ENTRY_PREFIX", "yyy");
|
||||
EXPECT_STREQ("yyy", conf.get_hls_entry_prefix("__defaultVhost__").c_str());
|
||||
|
||||
SrsSetEnvConfig(conf, hls_acodec, "SRS_VHOST_HLS_HLS_ACODEC", "yyy2");
|
||||
EXPECT_STREQ("yyy2", conf.get_hls_acodec("__defaultVhost__").c_str());
|
||||
|
||||
SrsSetEnvConfig(conf, hls_vcodec, "SRS_VHOST_HLS_HLS_VCODEC", "yyy3");
|
||||
EXPECT_STREQ("yyy3", conf.get_hls_vcodec("__defaultVhost__").c_str());
|
||||
|
||||
SrsSetEnvConfig(conf, hls_cleanup, "SRS_VHOST_HLS_HLS_CLEANUP", "off");
|
||||
EXPECT_FALSE(conf.get_hls_cleanup("__defaultVhost__"));
|
||||
|
||||
|
|
|
|||
|
|
@ -751,6 +751,84 @@ VOID TEST(Fmp4Test, Configuration_SequenceHeaderValidation)
|
|||
controller.dispose();
|
||||
}
|
||||
|
||||
VOID TEST(Fmp4Test, CodecDetection_AudioCodecUpdate)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
SrsHlsMp4Controller controller;
|
||||
HELPER_ASSERT_SUCCESS(controller.initialize());
|
||||
|
||||
MockSrsRequest req;
|
||||
HELPER_ASSERT_SUCCESS(controller.on_publish(&req));
|
||||
|
||||
// Create mock format with AAC audio codec
|
||||
MockSrsFormat fmt;
|
||||
fmt.acodec = new SrsAudioCodecConfig();
|
||||
fmt.acodec->id = SrsAudioCodecIdAAC;
|
||||
fmt.audio = new SrsAudioFrame();
|
||||
fmt.audio->codec = fmt.acodec;
|
||||
|
||||
// Initial codec should be forbidden (not set)
|
||||
EXPECT_EQ(SrsAudioCodecIdForbidden, controller.muxer_->latest_acodec());
|
||||
|
||||
// Write audio frame - should detect and update codec
|
||||
MockSrsSharedPtrMessage audio_msg(false, 1000);
|
||||
HELPER_ASSERT_SUCCESS(controller.write_audio(&audio_msg, &fmt));
|
||||
|
||||
// Codec should now be detected as AAC
|
||||
EXPECT_EQ(SrsAudioCodecIdAAC, controller.muxer_->latest_acodec());
|
||||
|
||||
// Test codec change from AAC to MP3
|
||||
fmt.acodec->id = SrsAudioCodecIdMP3;
|
||||
HELPER_ASSERT_SUCCESS(controller.write_audio(&audio_msg, &fmt));
|
||||
|
||||
// Codec should now be updated to MP3
|
||||
EXPECT_EQ(SrsAudioCodecIdMP3, controller.muxer_->latest_acodec());
|
||||
|
||||
controller.dispose();
|
||||
srs_freep(fmt.acodec);
|
||||
srs_freep(fmt.audio);
|
||||
}
|
||||
|
||||
VOID TEST(Fmp4Test, CodecDetection_VideoCodecUpdate)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
SrsHlsMp4Controller controller;
|
||||
HELPER_ASSERT_SUCCESS(controller.initialize());
|
||||
|
||||
MockSrsRequest req;
|
||||
HELPER_ASSERT_SUCCESS(controller.on_publish(&req));
|
||||
|
||||
// Create mock format with H.264 video codec
|
||||
MockSrsFormat fmt;
|
||||
fmt.vcodec = new SrsVideoCodecConfig();
|
||||
fmt.vcodec->id = SrsVideoCodecIdAVC;
|
||||
fmt.video = new SrsVideoFrame();
|
||||
fmt.video->codec = fmt.vcodec;
|
||||
|
||||
// Initial codec should be forbidden (not set)
|
||||
EXPECT_EQ(SrsVideoCodecIdForbidden, controller.muxer_->latest_vcodec());
|
||||
|
||||
// Write video frame - should detect and update codec
|
||||
MockSrsSharedPtrMessage video_msg(true, 1000);
|
||||
HELPER_ASSERT_SUCCESS(controller.write_video(&video_msg, &fmt));
|
||||
|
||||
// Codec should now be detected as H.264
|
||||
EXPECT_EQ(SrsVideoCodecIdAVC, controller.muxer_->latest_vcodec());
|
||||
|
||||
// Test codec change from H.264 to HEVC
|
||||
fmt.vcodec->id = SrsVideoCodecIdHEVC;
|
||||
HELPER_ASSERT_SUCCESS(controller.write_video(&video_msg, &fmt));
|
||||
|
||||
// Codec should now be updated to HEVC
|
||||
EXPECT_EQ(SrsVideoCodecIdHEVC, controller.muxer_->latest_vcodec());
|
||||
|
||||
controller.dispose();
|
||||
srs_freep(fmt.vcodec);
|
||||
srs_freep(fmt.video);
|
||||
}
|
||||
|
||||
VOID TEST(Fmp4Test, Performance_MultipleSegments)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user