Skip to content

Commit 1656391

Browse files
suzp1984winlinvip
andauthored
RTC: Support dropping h.264 SEI from NALUs. v5.0.213 v6.0.125 (ossrs#4057)
try to fix ossrs#4052. --------- Co-authored-by: winlin <[email protected]>
1 parent 282d94d commit 1656391

12 files changed

+141
-66
lines changed

trunk/conf/full.conf

+7
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,13 @@ vhost rtc.vhost.srs.com {
562562
# Overwrite by env SRS_VHOST_RTC_KEEP_BFRAME for all vhosts.
563563
# default: off
564564
keep_bframe off;
565+
# Whether to keep the h.264 SEI type NALU packet.
566+
# DJI drone M30T will send many SEI type NALU packet, while iOS hardware decoder (Video Toolbox)
567+
# dislike to feed it so many SEI NALU between NonIDR and IDR NALU packets.
568+
# @see https://github.com/ossrs/srs/issues/4052
569+
# Overwrite by env SRS_VHOST_RTC_KEEP_AVC_NALU_SEI for all vhosts.
570+
# Default: on
571+
keep_avc_nalu_sei on;
565572
# The transcode audio bitrate, for RTMP to RTC.
566573
# Overwrite by env SRS_VHOST_RTC_OPUS_BITRATE for all vhosts.
567574
# [8000, 320000]

trunk/doc/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ The changelog for SRS.
77
<a name="v6-changes"></a>
88

99
## SRS 6.0 Changelog
10+
* v6.0, 2024-06-03, Merge [#4057](https://github.com/ossrs/srs/pull/4057): RTC: Support dropping h.264 SEI from NALUs. v6.0.125 (#4057)
1011
* v6.0, 2024-04-26, Merge [#4044](https://github.com/ossrs/srs/pull/4044): fix: correct SRS_ERRNO_MAP_HTTP duplicate error code. v6.0.124 (#4044)
1112
* v6.0, 2024-04-23, Merge [#4038](https://github.com/ossrs/srs/pull/4038): RTMP: Do not response publish start message if hooks fail. v6.0.123 (#4038)
1213
* v6.0, 2024-04-22, Merge [#4033](https://github.com/ossrs/srs/pull/4033): issue #3967: support x509 certification chiain in single pem file. v6.0.122 (#4033)
@@ -135,6 +136,7 @@ The changelog for SRS.
135136
<a name="v5-changes"></a>
136137

137138
## SRS 5.0 Changelog
139+
* v5.0, 2024-06-03, Merge [#4057](https://github.com/ossrs/srs/pull/4057): RTC: Support dropping h.264 SEI from NALUs. v5.0.213 (#4057)
138140
* v5.0, 2024-04-23, Merge [#4038](https://github.com/ossrs/srs/pull/4038): RTMP: Do not response publish start message if hooks fail. v5.0.212 (#4038)
139141
* v5.0, 2024-04-22, Merge [#4033](https://github.com/ossrs/srs/pull/4033): issue #3967: support x509 certification chiain in single pem file. v5.0.211 (#4033)
140142
* v5.0, 2024-03-26, Filter JSONP callback function name. v5.0.210

trunk/src/app/srs_app_config.cpp

+21-1
Original file line numberDiff line numberDiff line change
@@ -2726,7 +2726,7 @@ srs_error_t SrsConfig::check_normal_config()
27262726
&& m != "bframe" && m != "aac" && m != "stun_timeout" && m != "stun_strict_check"
27272727
&& m != "dtls_role" && m != "dtls_version" && m != "drop_for_pt" && m != "rtc_to_rtmp"
27282728
&& m != "pli_for_rtmp" && m != "rtmp_to_rtc" && m != "keep_bframe" && m != "opus_bitrate"
2729-
&& m != "aac_bitrate") {
2729+
&& m != "aac_bitrate" && m != "keep_avc_nalu_sei") {
27302730
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.rtc.%s of %s", m.c_str(), vhost->arg0().c_str());
27312731
}
27322732
}
@@ -4474,6 +4474,26 @@ bool SrsConfig::get_rtc_keep_bframe(string vhost)
44744474
return SRS_CONF_PERFER_FALSE(conf->arg0());
44754475
}
44764476

4477+
bool SrsConfig::get_rtc_keep_avc_nalu_sei(std::string vhost)
4478+
{
4479+
SRS_OVERWRITE_BY_ENV_BOOL2("srs.vhost.rtc.keep_avc_nalu_sei"); // SRS_VHOST_RTC_KEEP_AVC_NALU_SEI
4480+
4481+
static bool DEFAULT = true;
4482+
4483+
SrsConfDirective* conf = get_rtc(vhost);
4484+
4485+
if (!conf) {
4486+
return DEFAULT;
4487+
}
4488+
4489+
conf = conf->get("keep_avc_nalu_sei");
4490+
if (!conf || conf->arg0().empty()) {
4491+
return DEFAULT;
4492+
}
4493+
4494+
return SRS_CONF_PERFER_TRUE(conf->arg0());
4495+
}
4496+
44774497
bool SrsConfig::get_rtc_from_rtmp(string vhost)
44784498
{
44794499
SRS_OVERWRITE_BY_ENV_BOOL("srs.vhost.rtc.rtmp_to_rtc"); // SRS_VHOST_RTC_RTMP_TO_RTC

trunk/src/app/srs_app_config.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,7 @@ class SrsConfig
533533
SrsConfDirective* get_rtc(std::string vhost);
534534
bool get_rtc_enabled(std::string vhost);
535535
bool get_rtc_keep_bframe(std::string vhost);
536+
bool get_rtc_keep_avc_nalu_sei(std::string vhost);
536537
bool get_rtc_from_rtmp(std::string vhost);
537538
srs_utime_t get_rtc_stun_timeout(std::string vhost);
538539
bool get_rtc_stun_strict_check(std::string vhost);

trunk/src/app/srs_app_rtc_source.cpp

+20-16
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,7 @@ SrsRtcRtpBuilder::SrsRtcRtpBuilder(SrsFrameToRtcBridge* bridge, uint32_t assrc,
739739
codec_ = new SrsAudioTranscoder();
740740
latest_codec_ = SrsAudioCodecIdForbidden;
741741
keep_bframe = false;
742+
keep_avc_nalu_sei = true;
742743
merge_nalus = false;
743744
meta = new SrsMetaCache();
744745
audio_sequence = 0;
@@ -771,8 +772,10 @@ srs_error_t SrsRtcRtpBuilder::initialize(SrsRequest* r)
771772
format->try_annexb_first = _srs_config->try_annexb_first(r->vhost);
772773

773774
keep_bframe = _srs_config->get_rtc_keep_bframe(req->vhost);
775+
keep_avc_nalu_sei = _srs_config->get_rtc_keep_avc_nalu_sei(req->vhost);
774776
merge_nalus = _srs_config->get_rtc_server_merge_nalus();
775-
srs_trace("RTC bridge from RTMP, keep_bframe=%d, merge_nalus=%d", keep_bframe, merge_nalus);
777+
srs_trace("RTC bridge from RTMP, keep_bframe=%d, keep_avc_nalu_sei=%d, merge_nalus=%d",
778+
keep_bframe, keep_avc_nalu_sei, merge_nalus);
776779

777780
return err;
778781
}
@@ -1013,12 +1016,6 @@ srs_error_t SrsRtcRtpBuilder::on_video(SrsSharedPtrMessage* msg)
10131016
for (int i = 0; i < nn_samples; i++) {
10141017
SrsSample* sample = samples[i];
10151018

1016-
// We always ignore bframe here, if config to discard bframe,
1017-
// the bframe flag will not be set.
1018-
if (sample->bframe) {
1019-
continue;
1020-
}
1021-
10221019
if (sample->size <= kRtpMaxPayloadSize) {
10231020
if ((err = package_single_nalu(msg, sample, pkts)) != srs_success) {
10241021
return srs_error_wrap(err, "package single nalu");
@@ -1050,14 +1047,27 @@ srs_error_t SrsRtcRtpBuilder::filter(SrsSharedPtrMessage* msg, SrsFormat* format
10501047
// Update samples to shared frame.
10511048
for (int i = 0; i < format->video->nb_samples; ++i) {
10521049
SrsSample* sample = &format->video->samples[i];
1050+
1051+
if (!keep_avc_nalu_sei && format->vcodec->id == SrsVideoCodecIdAVC) {
1052+
SrsAvcNaluType avc_nalu_type;
1053+
// TODO: FIXME use static method to parse avc nalu type.
1054+
if ((err = SrsVideoFrame::parse_avc_nalu_type(sample, avc_nalu_type)) != srs_success) {
1055+
return srs_error_wrap(err, "parse avc nalu_type");
1056+
}
1057+
if (avc_nalu_type == SrsAvcNaluTypeSEI) {
1058+
// srs_warn("skip avc nalu type SEI, size=%d", sample->size);
1059+
continue;
1060+
}
1061+
}
10531062

10541063
// Because RTC does not support B-frame, so we will drop them.
10551064
// TODO: Drop B-frame in better way, which not cause picture corruption.
1056-
if (!keep_bframe) {
1057-
if ((err = sample->parse_bframe()) != srs_success) {
1065+
if (!keep_bframe && format->vcodec->id == SrsVideoCodecIdAVC) {
1066+
bool is_b_frame;
1067+
if ((err = SrsVideoFrame::parse_avc_b_frame(sample, is_b_frame)) != srs_success) {
10581068
return srs_error_wrap(err, "parse bframe");
10591069
}
1060-
if (sample->bframe) {
1070+
if (is_b_frame) {
10611071
continue;
10621072
}
10631073
}
@@ -1137,12 +1147,6 @@ srs_error_t SrsRtcRtpBuilder::package_nalus(SrsSharedPtrMessage* msg, const vect
11371147
for (int i = 0; i < (int)samples.size(); i++) {
11381148
SrsSample* sample = samples[i];
11391149

1140-
// We always ignore bframe here, if config to discard bframe,
1141-
// the bframe flag will not be set.
1142-
if (sample->bframe) {
1143-
continue;
1144-
}
1145-
11461150
if (!sample->size) {
11471151
continue;
11481152
}

trunk/src/app/srs_app_rtc_source.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ class SrsRtcRtpBuilder
262262
SrsAudioCodecId latest_codec_;
263263
SrsAudioTranscoder* codec_;
264264
bool keep_bframe;
265+
bool keep_avc_nalu_sei;
265266
bool merge_nalus;
266267
uint16_t audio_sequence;
267268
uint16_t video_sequence;

trunk/src/core/srs_core_version5.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@
99

1010
#define VERSION_MAJOR 5
1111
#define VERSION_MINOR 0
12-
#define VERSION_REVISION 212
12+
#define VERSION_REVISION 213
1313

1414
#endif

trunk/src/core/srs_core_version6.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@
99

1010
#define VERSION_MAJOR 6
1111
#define VERSION_MINOR 0
12-
#define VERSION_REVISION 124
12+
#define VERSION_REVISION 125
1313

1414
#endif

trunk/src/kernel/srs_kernel_codec.cpp

+58-41
Original file line numberDiff line numberDiff line change
@@ -504,63 +504,23 @@ SrsSample::SrsSample()
504504
{
505505
size = 0;
506506
bytes = NULL;
507-
bframe = false;
508507
}
509508

510509
SrsSample::SrsSample(char* b, int s)
511510
{
512511
size = s;
513512
bytes = b;
514-
bframe = false;
515513
}
516514

517515
SrsSample::~SrsSample()
518516
{
519517
}
520518

521-
srs_error_t SrsSample::parse_bframe()
522-
{
523-
srs_error_t err = srs_success;
524-
525-
uint8_t header = bytes[0];
526-
SrsAvcNaluType nal_type = (SrsAvcNaluType)(header & kNalTypeMask);
527-
528-
if (nal_type != SrsAvcNaluTypeNonIDR && nal_type != SrsAvcNaluTypeDataPartitionA && nal_type != SrsAvcNaluTypeIDR) {
529-
return err;
530-
}
531-
532-
SrsBuffer* stream = new SrsBuffer(bytes, size);
533-
SrsAutoFree(SrsBuffer, stream);
534-
535-
// Skip nalu header.
536-
stream->skip(1);
537-
538-
SrsBitBuffer bitstream(stream);
539-
int32_t first_mb_in_slice = 0;
540-
if ((err = srs_avc_nalu_read_uev(&bitstream, first_mb_in_slice)) != srs_success) {
541-
return srs_error_wrap(err, "nalu read uev");
542-
}
543-
544-
int32_t slice_type_v = 0;
545-
if ((err = srs_avc_nalu_read_uev(&bitstream, slice_type_v)) != srs_success) {
546-
return srs_error_wrap(err, "nalu read uev");
547-
}
548-
SrsAvcSliceType slice_type = (SrsAvcSliceType)slice_type_v;
549-
550-
if (slice_type == SrsAvcSliceTypeB || slice_type == SrsAvcSliceTypeB1) {
551-
bframe = true;
552-
srs_verbose("nal_type=%d, slice type=%d", nal_type, slice_type);
553-
}
554-
555-
return err;
556-
}
557-
558519
SrsSample* SrsSample::copy()
559520
{
560521
SrsSample* p = new SrsSample();
561522
p->bytes = bytes;
562523
p->size = size;
563-
p->bframe = bframe;
564524
return p;
565525
}
566526

@@ -655,7 +615,6 @@ srs_error_t SrsFrame::add_sample(char* bytes, int size)
655615
SrsSample* sample = &samples[nb_samples++];
656616
sample->bytes = bytes;
657617
sample->size = size;
658-
sample->bframe = false;
659618

660619
return err;
661620
}
@@ -739,6 +698,64 @@ SrsVideoCodecConfig* SrsVideoFrame::vcodec()
739698
return (SrsVideoCodecConfig*)codec;
740699
}
741700

701+
srs_error_t SrsVideoFrame::parse_avc_nalu_type(const SrsSample* sample, SrsAvcNaluType& avc_nalu_type)
702+
{
703+
srs_error_t err = srs_success;
704+
705+
if (sample == NULL || sample->size < 1) {
706+
return srs_error_new(ERROR_AVC_NALU_EMPTY, "empty nalu");
707+
}
708+
709+
uint8_t header = sample->bytes[0];
710+
avc_nalu_type = (SrsAvcNaluType)(header & kNalTypeMask);
711+
712+
return err;
713+
}
714+
715+
srs_error_t SrsVideoFrame::parse_avc_b_frame(const SrsSample* sample, bool& is_b_frame)
716+
{
717+
srs_error_t err = srs_success;
718+
719+
if (sample == NULL || sample->size < 1) {
720+
return srs_error_new(ERROR_AVC_NALU_EMPTY, "empty nalu");
721+
}
722+
723+
SrsAvcNaluType nalu_type;
724+
if ((err = parse_avc_nalu_type(sample, nalu_type)) != srs_success) {
725+
return srs_error_wrap(err, "parse avc nalu type error");
726+
}
727+
728+
if (nalu_type != SrsAvcNaluTypeNonIDR && nalu_type != SrsAvcNaluTypeDataPartitionA && nalu_type != SrsAvcNaluTypeIDR) {
729+
is_b_frame = false;
730+
return err;
731+
}
732+
733+
SrsBuffer* stream = new SrsBuffer(sample->bytes, sample->size);
734+
SrsAutoFree(SrsBuffer, stream);
735+
736+
// Skip nalu header.
737+
stream->skip(1);
738+
739+
SrsBitBuffer bitstream(stream);
740+
int32_t first_mb_in_slice = 0;
741+
if ((err = srs_avc_nalu_read_uev(&bitstream, first_mb_in_slice)) != srs_success) {
742+
return srs_error_wrap(err, "nalu read uev");
743+
}
744+
745+
int32_t slice_type_v = 0;
746+
if ((err = srs_avc_nalu_read_uev(&bitstream, slice_type_v)) != srs_success) {
747+
return srs_error_wrap(err, "nalu read uev");
748+
}
749+
SrsAvcSliceType slice_type = (SrsAvcSliceType)slice_type_v;
750+
751+
is_b_frame = slice_type == SrsAvcSliceTypeB || slice_type == SrsAvcSliceTypeB1;
752+
if (is_b_frame) {
753+
srs_verbose("nalu_type=%d, slice type=%d", nalu_type, slice_type);
754+
}
755+
756+
return err;
757+
}
758+
742759
SrsFormat::SrsFormat()
743760
{
744761
acodec = NULL;

trunk/src/kernel/srs_kernel_codec.hpp

+4-5
Original file line numberDiff line numberDiff line change
@@ -1120,7 +1120,7 @@ std::string srs_hevc_level2str(SrsHevcLevel level);
11201120

11211121
/**
11221122
* A sample is the unit of frame.
1123-
* It's a NALU for H.264.
1123+
* It's a NALU for H.264, H.265.
11241124
* It's the whole AAC raw data for AAC.
11251125
* @remark Neither SPS/PPS or ASC is sample unit, it's codec sequence header.
11261126
*/
@@ -1131,15 +1131,11 @@ class SrsSample
11311131
int size;
11321132
// The ptr of unit, user must free it.
11331133
char* bytes;
1134-
// Whether is B frame.
1135-
bool bframe;
11361134
public:
11371135
SrsSample();
11381136
SrsSample(char* b, int s);
11391137
~SrsSample();
11401138
public:
1141-
// If we need to know whether sample is bframe, we have to parse the NALU payload.
1142-
srs_error_t parse_bframe();
11431139
// Copy sample, share the bytes pointer.
11441140
SrsSample* copy();
11451141
};
@@ -1322,6 +1318,9 @@ class SrsVideoFrame : public SrsFrame
13221318
virtual srs_error_t add_sample(char* bytes, int size);
13231319
public:
13241320
virtual SrsVideoCodecConfig* vcodec();
1321+
public:
1322+
static srs_error_t parse_avc_nalu_type(const SrsSample* sample, SrsAvcNaluType& avc_nalu_type);
1323+
static srs_error_t parse_avc_b_frame(const SrsSample* sample, bool& is_b_frame);
13251324
};
13261325

13271326
/**

trunk/src/kernel/srs_kernel_error.hpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,8 @@
276276
XX(ERROR_HEVC_DISABLED , 3098, "HevcDisabled", "HEVC is disabled") \
277277
XX(ERROR_HEVC_DECODE_ERROR , 3099, "HevcDecode", "HEVC decode av stream failed") \
278278
XX(ERROR_MP4_HVCC_CHANGE , 3100, "Mp4HvcCChange", "MP4 does not support video HvcC change") \
279-
XX(ERROR_HEVC_API_NO_PREFIXED , 3101, "HevcAnnexbPrefix", "No annexb prefix for HEVC decoder")
279+
XX(ERROR_HEVC_API_NO_PREFIXED , 3101, "HevcAnnexbPrefix", "No annexb prefix for HEVC decoder") \
280+
XX(ERROR_AVC_NALU_EMPTY , 3102, "AvcNaluEmpty", "AVC NALU is empty")
280281

281282
/**************************************************/
282283
/* HTTP/StreamConverter protocol error. */

trunk/src/utest/srs_utest_config.cpp

+23
Original file line numberDiff line numberDiff line change
@@ -4405,6 +4405,29 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesVhostRtc)
44054405

44064406
SrsSetEnvConfig(rtc_keep_bframe, "SRS_VHOST_RTC_KEEP_BFRAME", "on");
44074407
EXPECT_TRUE(conf.get_rtc_keep_bframe("__defaultVhost__"));
4408+
4409+
{
4410+
// make sure the default value is false, if defined incorrect env value.
4411+
SrsSetEnvConfig(rtc_keep_bframe, "SRS_VHOST_RTC_KEEP_BFRAME", "onn");
4412+
EXPECT_FALSE(conf.get_rtc_keep_bframe("__defaultVhost__"));
4413+
4414+
}
4415+
4416+
{
4417+
SrsSetEnvConfig(rtc_keep_avc_nalu_sei, "SRS_VHOST_RTC_KEEP_AVC_NALU_SEI", "off");
4418+
EXPECT_FALSE(conf.get_rtc_keep_avc_nalu_sei("__defaultVhost__"));
4419+
}
4420+
4421+
{
4422+
SrsSetEnvConfig(rtc_keep_avc_nalu_sei, "SRS_VHOST_RTC_KEEP_AVC_NALU_SEI", "on");
4423+
EXPECT_TRUE(conf.get_rtc_keep_avc_nalu_sei("__defaultVhost__"));
4424+
}
4425+
4426+
{
4427+
// make sure the default value is true, if defined incorrect env value.
4428+
SrsSetEnvConfig(rtc_keep_avc_nalu_sei, "SRS_VHOST_RTC_KEEP_AVC_NALU_SEI", "xx");
4429+
EXPECT_TRUE(conf.get_rtc_keep_avc_nalu_sei("__defaultVhost__"));
4430+
}
44084431
}
44094432

44104433
if (true) {

0 commit comments

Comments
 (0)