Skip to content

Commit eb0d0c0

Browse files
committed
WHIP: Parse profile and level from extradata.
1 parent b76afd2 commit eb0d0c0

File tree

2 files changed

+80
-10
lines changed

2 files changed

+80
-10
lines changed

libavformat/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ OBJS-$(CONFIG_RSD_DEMUXER) += rsd.o
493493
OBJS-$(CONFIG_RPL_DEMUXER) += rpl.o
494494
OBJS-$(CONFIG_RSO_DEMUXER) += rsodec.o rso.o pcm.o
495495
OBJS-$(CONFIG_RSO_MUXER) += rsoenc.o rso.o rawenc.o
496-
OBJS-$(CONFIG_RTC_MUXER) += rtcenc.o http.o srtp.o
496+
OBJS-$(CONFIG_RTC_MUXER) += rtcenc.o avc.o http.o srtp.o
497497
OBJS-$(CONFIG_RTP_MPEGTS_MUXER) += rtpenc_mpegts.o
498498
OBJS-$(CONFIG_RTP_MUXER) += rtp.o \
499499
rtpenc_aac.o \

libavformat/rtcenc.c

Lines changed: 79 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include <openssl/err.h>
2424

2525
#include "libavcodec/avcodec.h"
26+
#include "libavcodec/h264.h"
27+
#include "libavcodec/startcode.h"
2628
#include "libavutil/base64.h"
2729
#include "libavutil/bprint.h"
2830
#include "libavutil/crc.h"
@@ -31,6 +33,7 @@
3133
#include "libavutil/opt.h"
3234
#include "libavutil/random_seed.h"
3335
#include "libavutil/time.h"
36+
#include "avc.h"
3437
#include "avio_internal.h"
3538
#include "http.h"
3639
#include "internal.h"
@@ -1086,6 +1089,56 @@ static av_cold int whip_init(AVFormatContext *s)
10861089
return 0;
10871090
}
10881091

1092+
/**
1093+
* When utilizing an encoder, such as libx264, to encode a stream, the extradata in
1094+
* par->extradata contains the SPS, which includes profile and level information.
1095+
* However, the profile and level of par remain unspecified. Therefore, it is necessary
1096+
* to extract the profile and level data from the extradata and assign it to the par's
1097+
* profile and level.
1098+
*
1099+
* When copying a stream, the extradata, as well as the profile and level of the par,
1100+
* are already set by demuxer.
1101+
*/
1102+
static int parse_profile_level(AVFormatContext *s, AVCodecParameters *par)
1103+
{
1104+
int ret = 0;
1105+
const uint8_t *r = par->extradata, *r1, *end = par->extradata + par->extradata_size;
1106+
H264SPS seq, *const sps = &seq;
1107+
uint32_t state;
1108+
RTCContext *rtc = s->priv_data;
1109+
1110+
if (par->codec_id != AV_CODEC_ID_H264)
1111+
return ret;
1112+
1113+
if (par->profile != FF_PROFILE_UNKNOWN && par->level != FF_LEVEL_UNKNOWN)
1114+
return ret;
1115+
1116+
while (1) {
1117+
r = avpriv_find_start_code(r, end, &state);
1118+
if (r >= end)
1119+
break;
1120+
1121+
r1 = ff_avc_find_startcode(r, end);
1122+
if ((state & 0x1f) == H264_NAL_SPS) {
1123+
ret = ff_avc_decode_sps(sps, r, r1 - r);
1124+
if (ret < 0) {
1125+
av_log(rtc, AV_LOG_ERROR, "WHIP: Failed to decode SPS, state=%x, size=%d\n",
1126+
state, (int)(r1 - r));
1127+
return ret;
1128+
}
1129+
1130+
av_log(rtc, AV_LOG_INFO, "WHIP: Parse profile=%d, level=%d from SPS\n",
1131+
sps->profile_idc, sps->level_idc);
1132+
par->profile = sps->profile_idc;
1133+
par->level = sps->level_idc;
1134+
}
1135+
1136+
r = r1;
1137+
}
1138+
1139+
return ret;
1140+
}
1141+
10891142
/**
10901143
* Parses video SPS/PPS from the extradata of codecpar and checks the codec.
10911144
* Currently only supports video(h264) and audio(opus). Note that only baseline
@@ -1109,7 +1162,7 @@ static av_cold int whip_init(AVFormatContext *s)
11091162
*/
11101163
static int parse_codec(AVFormatContext *s)
11111164
{
1112-
int i;
1165+
int i, ret = 0;
11131166
RTCContext *rtc = s->priv_data;
11141167

11151168
for (i = 0; i < s->nb_streams; i++) {
@@ -1133,6 +1186,20 @@ static int parse_codec(AVFormatContext *s)
11331186
av_log(rtc, AV_LOG_ERROR, "WHIP: Unsupported B frames by RTC\n");
11341187
return AVERROR_PATCHWELCOME;
11351188
}
1189+
1190+
if ((ret = parse_profile_level(s, par)) < 0) {
1191+
av_log(rtc, AV_LOG_ERROR, "WHIP: Failed to parse SPS/PPS from extradata\n");
1192+
return AVERROR(EINVAL);
1193+
}
1194+
1195+
if (par->profile == FF_PROFILE_UNKNOWN) {
1196+
av_log(rtc, AV_LOG_WARNING, "WHIP: No profile found in extradata, consider baseline\n");
1197+
return AVERROR(EINVAL);
1198+
}
1199+
if (par->level == FF_LEVEL_UNKNOWN) {
1200+
av_log(rtc, AV_LOG_WARNING, "WHIP: No level found in extradata, consider 3.1\n");
1201+
return AVERROR(EINVAL);
1202+
}
11361203
break;
11371204
case AVMEDIA_TYPE_AUDIO:
11381205
if (rtc->audio_par) {
@@ -1165,7 +1232,7 @@ static int parse_codec(AVFormatContext *s)
11651232
}
11661233
}
11671234

1168-
return 0;
1235+
return ret;
11691236
}
11701237

11711238
/**
@@ -1246,8 +1313,8 @@ static int generate_sdp_offer(AVFormatContext *s)
12461313
}
12471314

12481315
if (rtc->video_par) {
1249-
profile_iop = profile = rtc->video_par->profile < 0 ? 0x42 : rtc->video_par->profile;
1250-
level = rtc->video_par->level < 0 ? 0x1e : rtc->video_par->level;
1316+
profile_iop = profile = rtc->video_par->profile;
1317+
level = rtc->video_par->level;
12511318
if (rtc->video_par->codec_id == AV_CODEC_ID_H264) {
12521319
vcodec_name = "H264";
12531320
profile_iop &= FF_PROFILE_H264_CONSTRAINED;
@@ -2320,14 +2387,17 @@ static av_cold void rtc_deinit(AVFormatContext *s)
23202387

23212388
static int rtc_check_bitstream(AVFormatContext *s, AVStream *st, const AVPacket *pkt)
23222389
{
2323-
int ret = 1;
2390+
int ret = 1, extradata_isom = 0;
2391+
uint8_t *b = pkt->data;
2392+
RTCContext *rtc = s->priv_data;
23242393

23252394
if (st->codecpar->codec_id == AV_CODEC_ID_H264) {
2326-
if (pkt->size >= 5 && AV_RB32(pkt->data) != 0x0000001 &&
2327-
(AV_RB24(pkt->data) != 0x000001 ||
2328-
(st->codecpar->extradata_size > 0 &&
2329-
st->codecpar->extradata[0] == 1)))
2395+
extradata_isom = st->codecpar->extradata_size > 0 && st->codecpar->extradata[0] == 1;
2396+
if (pkt->size >= 5 && AV_RB32(b) != 0x0000001 && (AV_RB24(b) != 0x000001 || extradata_isom)) {
23302397
ret = ff_stream_add_bitstream_filter(st, "h264_mp4toannexb", NULL);
2398+
av_log(rtc, AV_LOG_INFO, "WHIP: Enable BSF h264_mp4toannexb, packet=[%x %x %x %x %x ...], extradata_isom=%d\n",
2399+
b[0], b[1], b[2], b[3], b[4], extradata_isom);
2400+
}
23312401
}
23322402

23332403
return ret;

0 commit comments

Comments
 (0)