Skip to content

Commit 6926d6d

Browse files
committed
BitstreamConverter: convert VVC to annexb when codec extra data is available
1 parent 45dc9ca commit 6926d6d

File tree

3 files changed

+229
-0
lines changed

3 files changed

+229
-0
lines changed

xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAmlogic.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,10 @@ bool CDVDVideoCodecAmlogic::Open(CDVDStreamInfo &hints, CDVDCodecOptions &option
335335
goto FAIL;
336336
}
337337
m_pFormatName = "am-h266";
338+
m_bitstream = new CBitstreamConverter();
339+
m_bitstream->Open(m_hints.codec, m_hints.extradata.GetData(), m_hints.extradata.GetSize(), true);
340+
if (m_hints.extradata.GetSize() == 0)
341+
m_bitstream->ResetStartDecode();
338342
break;
339343
default:
340344
CLog::Log(LOGDEBUG, "{}: Unknown hints.codec({:d})", __MODULE_NAME__, m_hints.codec);

xbmc/utils/BitstreamConverter.cpp

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,42 @@ enum
7676
HEVC_NAL_UNSPEC63 = 63 // Dolby Vision EL
7777
};
7878

79+
enum
80+
{
81+
VVC_TRAIL_NUT = 0,
82+
VVC_STSA_NUT = 1,
83+
VVC_RADL_NUT = 2,
84+
VVC_RASL_NUT = 3,
85+
VVC_RSV_VCL_4 = 4,
86+
VVC_RSV_VCL_5 = 5,
87+
VVC_RSV_VCL_6 = 6,
88+
VVC_IDR_W_RADL = 7,
89+
VVC_IDR_N_LP = 8,
90+
VVC_CRA_NUT = 9,
91+
VVC_GDR_NUT = 10,
92+
VVC_RSV_IRAP_11 = 11,
93+
VVC_OPI_NUT = 12,
94+
VVC_DCI_NUT = 13,
95+
VVC_VPS_NUT = 14,
96+
VVC_SPS_NUT = 15,
97+
VVC_PPS_NUT = 16,
98+
VVC_PREFIX_APS_NUT = 17,
99+
VVC_SUFFIX_APS_NUT = 18,
100+
VVC_PH_NUT = 19,
101+
VVC_AUD_NUT = 20,
102+
VVC_EOS_NUT = 21,
103+
VVC_EOB_NUT = 22,
104+
VVC_PREFIX_SEI_NUT = 23,
105+
VVC_SUFFIX_SEI_NUT = 24,
106+
VVC_FD_NUT = 25,
107+
VVC_RSV_NVCL_26 = 26,
108+
VVC_RSV_NVCL_27 = 27,
109+
VVC_UNSPEC_28 = 28,
110+
VVC_UNSPEC_29 = 29,
111+
VVC_UNSPEC_30 = 30,
112+
VVC_UNSPEC_31 = 31,
113+
};
114+
79115
enum {
80116
SEI_BUFFERING_PERIOD = 0,
81117
SEI_PIC_TIMING,
@@ -545,6 +581,23 @@ bool CBitstreamConverter::Open(enum AVCodecID codec, uint8_t *in_extradata, int
545581
}
546582
return false;
547583
break;
584+
case AV_CODEC_ID_VVC:
585+
if (in_extradata && in_extradata[0] == 0xff && (in_extradata[1] & 0xf0) == 0x0)
586+
{
587+
std::string extradatastr;
588+
CLog::Log(LOGINFO, "CBitstreamConverter::Open VVC, convert to annexb format");
589+
590+
m_extraData = FFmpegExtraData(in_extradata, in_extrasize);
591+
m_convert_bytestream =
592+
BitstreamConvertInitVVC(m_extraData.GetData(), m_extraData.GetSize());
593+
}
594+
else
595+
{
596+
CLog::Log(LOGINFO, "CBitstreamConverter::Open VVC, no extra data");
597+
m_convert_bytestream = true;
598+
}
599+
return true;
600+
break;
548601
default:
549602
return false;
550603
break;
@@ -759,6 +812,57 @@ bool CBitstreamConverter::Convert(uint8_t *pData, int iSize)
759812
return true;
760813
}
761814
}
815+
else if (m_codec == AV_CODEC_ID_VVC)
816+
{
817+
if (m_to_annexb)
818+
{
819+
int nal_stream_pos = 0;
820+
821+
m_inputSize = iSize;
822+
m_inputBuffer = pData;
823+
824+
if (!m_start_decode)
825+
{
826+
uint32_t packet_format = AV_RB32(m_inputBuffer);
827+
m_convert_bytestream = packet_format != 0x1 && packet_format != 0x100;
828+
}
829+
830+
while (nal_stream_pos < iSize)
831+
{
832+
if (m_convert_bytestream)
833+
{
834+
static const uint8_t nalu_header[4] = {0, 0, 0, 1};
835+
uint32_t unit_size = AV_RB32(m_inputBuffer + nal_stream_pos) + 4;
836+
uint16_t unit_type = (AV_RB16(m_inputBuffer + nal_stream_pos + 4) >> 3) & 0x1f;
837+
838+
if (unit_type == VVC_SPS_NUT || IsIDR(unit_type))
839+
m_start_decode = true;
840+
841+
memcpy(m_inputBuffer + nal_stream_pos, nalu_header, 4);
842+
nal_stream_pos += unit_size;
843+
}
844+
else if (!m_start_decode)
845+
{
846+
uint8_t *buf = m_inputBuffer + nal_stream_pos;
847+
848+
if (buf[0] == 0x0 && buf[1] == 0x0 && buf[2] == 0x1)
849+
{
850+
uint16_t unit_type = (AV_RB16(m_inputBuffer + nal_stream_pos + 3) >> 3) & 0x1f;
851+
852+
if (unit_type == VVC_SPS_NUT || IsIDR(unit_type))
853+
m_start_decode = true;
854+
855+
nal_stream_pos += 5;
856+
}
857+
else
858+
nal_stream_pos++;
859+
}
860+
else
861+
break;
862+
}
863+
}
864+
return true;
865+
}
762866
}
763867

764868
return false;
@@ -1116,6 +1220,122 @@ bool CBitstreamConverter::BitstreamConvertInitHEVC(void *in_extradata, int in_ex
11161220
return true;
11171221
}
11181222

1223+
bool CBitstreamConverter::BitstreamConvertInitVVC(void *in_extradata, int in_extrasize)
1224+
{
1225+
m_sps_pps_size = 0;
1226+
m_sps_pps_context.sps_pps_data = NULL;
1227+
1228+
// nothing to filter
1229+
if (!in_extradata)
1230+
return false;
1231+
1232+
uint16_t unit_size;
1233+
uint32_t total_size = 0;
1234+
uint8_t *out = NULL, array_nb, nal_type, sps_seen = 0, pps_seen = 0;
1235+
uint8_t num_sublayers, num_bytes_constraint_info, ptl_sublayer_level_present_flags;
1236+
const uint8_t *extradata = (uint8_t*)in_extradata;
1237+
static const uint8_t nalu_header[4] = {0, 0, 0, 1};
1238+
1239+
// length coded size
1240+
m_sps_pps_context.length_size = sizeof(nalu_header);
1241+
1242+
// skip several fields of VVCDecoderConfigurationRecord
1243+
// extradata point to 00 after FF, 8b
1244+
extradata++;
1245+
// ols_idx, num_sublayers , constant_frame_rate, chroma_format_idc, 16b
1246+
num_sublayers = ((extradata[0] << 8 | extradata[1]) >> 4) & 0x7;
1247+
extradata += 2;
1248+
// bit_depth_minus8, 8b
1249+
extradata++;
1250+
// num_bytes_constraint_info, 8b
1251+
num_bytes_constraint_info = extradata[0] & 0x3f;
1252+
extradata++;
1253+
// general_profile_idc, general_tier_flag, 8b
1254+
// general_level_idc, 8b
1255+
extradata += 2;
1256+
// constraint_info, 8b * num_bytes_constraint_info
1257+
extradata += num_bytes_constraint_info;
1258+
// ptl_sublayer_level_present_flag, 8b
1259+
ptl_sublayer_level_present_flags = *extradata++ & 0x3f;
1260+
for (int i = num_sublayers - 2; i >= 0; i--)
1261+
if ((ptl_sublayer_level_present_flags >> 1) & 0x1)
1262+
extradata++;
1263+
// ptl_num_sub_profiles, 8b
1264+
extradata++;
1265+
// max_picture_width, 16b
1266+
extradata += 2;
1267+
// max_picture_height, 16b
1268+
extradata += 2;
1269+
// avg_frame_rate, 16b
1270+
extradata += 2;
1271+
// num_of_arrays, 8b
1272+
array_nb = *extradata++;
1273+
1274+
while (array_nb--)
1275+
{
1276+
void *tmp;
1277+
1278+
extradata++; // array_completeness, 8b
1279+
if (extradata[0] == 0x0 && extradata[1] == 0x01)
1280+
{
1281+
extradata += 2; // nal header, 16b
1282+
unit_size = extradata[0] << 8 | extradata[1];
1283+
extradata += 2; // nal unit size, 16b
1284+
nal_type = (extradata[1] >> 3) & 0x1f;
1285+
1286+
if (nal_type == VVC_SPS_NUT)
1287+
{
1288+
sps_seen = 1;
1289+
m_start_decode = true;
1290+
}
1291+
else if (nal_type == VVC_PPS_NUT)
1292+
{
1293+
pps_seen = 1;
1294+
}
1295+
else
1296+
{
1297+
extradata += unit_size;
1298+
continue;
1299+
}
1300+
total_size += unit_size + 4;
1301+
1302+
if (total_size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE ||
1303+
(extradata + unit_size) > ((uint8_t*)in_extradata + in_extrasize))
1304+
{
1305+
av_free(out);
1306+
return false;
1307+
}
1308+
tmp = av_realloc(out, total_size + AV_INPUT_BUFFER_PADDING_SIZE);
1309+
if (!tmp)
1310+
{
1311+
av_free(out);
1312+
return false;
1313+
}
1314+
out = (uint8_t*)tmp;
1315+
memcpy(out + total_size - unit_size - 4, nalu_header, 4);
1316+
memcpy(out + total_size - unit_size, extradata, unit_size);
1317+
extradata += unit_size;
1318+
}
1319+
else
1320+
return false;
1321+
}
1322+
1323+
if (out)
1324+
memset(out + total_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
1325+
1326+
if (!sps_seen)
1327+
CLog::Log(LOGDEBUG, "SPS NALU missing or invalid. The resulting stream may not play");
1328+
if (!pps_seen)
1329+
CLog::Log(LOGDEBUG, "PPS NALU missing or invalid. The resulting stream may not play");
1330+
1331+
m_sps_pps_context.sps_pps_data = out;
1332+
m_sps_pps_context.size = total_size;
1333+
m_sps_pps_context.first_idr = 1;
1334+
m_sps_pps_context.idr_sps_pps_seen = 0;
1335+
1336+
return true;
1337+
}
1338+
11191339
bool CBitstreamConverter::IsIDR(uint8_t unit_type)
11201340
{
11211341
switch (m_codec)
@@ -1126,6 +1346,10 @@ bool CBitstreamConverter::IsIDR(uint8_t unit_type)
11261346
return unit_type == HEVC_NAL_IDR_W_RADL ||
11271347
unit_type == HEVC_NAL_IDR_N_LP ||
11281348
unit_type == HEVC_NAL_CRA_NUT;
1349+
case AV_CODEC_ID_VVC:
1350+
return unit_type == VVC_IDR_W_RADL ||
1351+
unit_type == VVC_IDR_N_LP ||
1352+
unit_type == VVC_CRA_NUT;
11291353
default:
11301354
return false;
11311355
}

xbmc/utils/BitstreamConverter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ class CBitstreamConverter
143143
bool IsSlice(uint8_t unit_type);
144144
bool BitstreamConvertInitAVC(void *in_extradata, int in_extrasize);
145145
bool BitstreamConvertInitHEVC(void *in_extradata, int in_extrasize);
146+
bool BitstreamConvertInitVVC(void *in_extradata, int in_extrasize);
146147
bool BitstreamConvert(uint8_t* pData, int iSize, uint8_t **poutbuf, int *poutbuf_size);
147148
static void BitstreamAllocAndCopy(uint8_t** poutbuf,
148149
int* poutbuf_size,

0 commit comments

Comments
 (0)