23
23
#include <openssl/err.h>
24
24
25
25
#include "libavcodec/avcodec.h"
26
+ #include "libavcodec/h264.h"
27
+ #include "libavcodec/startcode.h"
26
28
#include "libavutil/base64.h"
27
29
#include "libavutil/bprint.h"
28
30
#include "libavutil/crc.h"
31
33
#include "libavutil/opt.h"
32
34
#include "libavutil/random_seed.h"
33
35
#include "libavutil/time.h"
36
+ #include "avc.h"
34
37
#include "avio_internal.h"
35
38
#include "http.h"
36
39
#include "internal.h"
@@ -1086,6 +1089,56 @@ static av_cold int whip_init(AVFormatContext *s)
1086
1089
return 0 ;
1087
1090
}
1088
1091
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
+
1089
1142
/**
1090
1143
* Parses video SPS/PPS from the extradata of codecpar and checks the codec.
1091
1144
* Currently only supports video(h264) and audio(opus). Note that only baseline
@@ -1109,7 +1162,7 @@ static av_cold int whip_init(AVFormatContext *s)
1109
1162
*/
1110
1163
static int parse_codec (AVFormatContext * s )
1111
1164
{
1112
- int i ;
1165
+ int i , ret = 0 ;
1113
1166
RTCContext * rtc = s -> priv_data ;
1114
1167
1115
1168
for (i = 0 ; i < s -> nb_streams ; i ++ ) {
@@ -1133,6 +1186,20 @@ static int parse_codec(AVFormatContext *s)
1133
1186
av_log (rtc , AV_LOG_ERROR , "WHIP: Unsupported B frames by RTC\n" );
1134
1187
return AVERROR_PATCHWELCOME ;
1135
1188
}
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
+ }
1136
1203
break ;
1137
1204
case AVMEDIA_TYPE_AUDIO :
1138
1205
if (rtc -> audio_par ) {
@@ -1165,7 +1232,7 @@ static int parse_codec(AVFormatContext *s)
1165
1232
}
1166
1233
}
1167
1234
1168
- return 0 ;
1235
+ return ret ;
1169
1236
}
1170
1237
1171
1238
/**
@@ -1246,8 +1313,8 @@ static int generate_sdp_offer(AVFormatContext *s)
1246
1313
}
1247
1314
1248
1315
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 ;
1251
1318
if (rtc -> video_par -> codec_id == AV_CODEC_ID_H264 ) {
1252
1319
vcodec_name = "H264" ;
1253
1320
profile_iop &= FF_PROFILE_H264_CONSTRAINED ;
@@ -2320,14 +2387,17 @@ static av_cold void rtc_deinit(AVFormatContext *s)
2320
2387
2321
2388
static int rtc_check_bitstream (AVFormatContext * s , AVStream * st , const AVPacket * pkt )
2322
2389
{
2323
- int ret = 1 ;
2390
+ int ret = 1 , extradata_isom = 0 ;
2391
+ uint8_t * b = pkt -> data ;
2392
+ RTCContext * rtc = s -> priv_data ;
2324
2393
2325
2394
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 )) {
2330
2397
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
+ }
2331
2401
}
2332
2402
2333
2403
return ret ;
0 commit comments