MP4+h.265 configuration tag mux
函数ff_isom_write_hvcc()
int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data,
int size, int ps_array_completeness)
{
int ret = 0;
uint8_t *buf, *end, *start = NULL;
HEVCDecoderConfigurationRecord hvcc;
hvcc_init(&hvcc);
if (size < 6) {
/* We can't write a valid hvcC from the provided data */
ret = AVERROR_INVALIDDATA;
goto end;
} else if (*data == 1) {
/* Data is already hvcC-formatted */
avio_write(pb, data, size);
goto end;
} else if (!(AV_RB24(data) == 1 || AV_RB32(data) == 1)) {
/* Not a valid Annex B start code prefix */
ret = AVERROR_INVALIDDATA;
goto end;
}
ret = ff_avc_parse_nal_units_buf(data, &start, &size);
if (ret < 0)
goto end;
buf = start;
end = start + size;
while (end - buf > 4) {
uint32_t len = FFMIN(AV_RB32(buf), end - buf - 4);
uint8_t type = (buf[4] >> 1) & 0x3f;
buf += 4;
switch (type) {
case NAL_VPS:
case NAL_SPS:
case NAL_PPS:
case NAL_SEI_PREFIX:
case NAL_SEI_SUFFIX:
ret = hvcc_add_nal_unit(buf, len, ps_array_completeness, &hvcc);
if (ret < 0)
goto end;
break;
default:
break;
}
buf += len;
}
ret = hvcc_write(pb, &hvcc);
end:
hvcc_close(&hvcc);
av_free(start);
return ret;
}
hvcc_write()
static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc)
{
uint8_t i;
uint16_t j, vps_count = 0, sps_count = 0, pps_count = 0;
/*
* We only support writing HEVCDecoderConfigurationRecord version 1.
*/
hvcc->configurationVersion = 1;
/*
* If min_spatial_segmentation_idc is invalid, reset to 0 (unspecified).
*/
if (hvcc->min_spatial_segmentation_idc > MAX_SPATIAL_SEGMENTATION)
hvcc->min_spatial_segmentation_idc = 0;
/*
* parallelismType indicates the type of parallelism that is used to meet
* the restrictions imposed by min_spatial_segmentation_idc when the value
* of min_spatial_segmentation_idc is greater than 0.
*/
if (!hvcc->min_spatial_segmentation_idc)
hvcc->parallelismType = 0;
/*
* It's unclear how to properly compute these fields, so
* let's always set them to values meaning 'unspecified'.
*/
hvcc->avgFrameRate = 0;
hvcc->constantFrameRate = 0;
av_log(NULL, AV_LOG_TRACE, "configurationVersion: %"PRIu8"\n",
hvcc->configurationVersion);
av_log(NULL, AV_LOG_TRACE, "general_profile_space: %"PRIu8"\n",
hvcc->general_profile_space);
av_log(NULL, AV_LOG_TRACE, "general_tier_flag: %"PRIu8"\n",
hvcc->general_tier_flag);
av_log(NULL, AV_LOG_TRACE, "general_profile_idc: %"PRIu8"\n",
hvcc->general_profile_idc);
av_log(NULL, AV_LOG_TRACE, "general_profile_compatibility_flags: 0x%08"PRIx32"\n",
hvcc->general_profile_compatibility_flags);
av_log(NULL, AV_LOG_TRACE, "general_constraint_indicator_flags: 0x%012"PRIx64"\n",
hvcc->general_constraint_indicator_flags);
av_log(NULL, AV_LOG_TRACE, "general_level_idc: %"PRIu8"\n",
hvcc->general_level_idc);
av_log(NULL, AV_LOG_TRACE, "min_spatial_segmentation_idc: %"PRIu16"\n",
hvcc->min_spatial_segmentation_idc);
av_log(NULL, AV_LOG_TRACE, "parallelismType: %"PRIu8"\n",
hvcc->parallelismType);
av_log(NULL, AV_LOG_TRACE, "chromaFormat: %"PRIu8"\n",
hvcc->chromaFormat);
av_log(NULL, AV_LOG_TRACE, "bitDepthLumaMinus8: %"PRIu8"\n",
hvcc->bitDepthLumaMinus8);
av_log(NULL, AV_LOG_TRACE, "bitDepthChromaMinus8: %"PRIu8"\n",
hvcc->bitDepthChromaMinus8);
av_log(NULL, AV_LOG_TRACE, "avgFrameRate: %"PRIu16"\n",
hvcc->avgFrameRate);
av_log(NULL, AV_LOG_TRACE, "constantFrameRate: %"PRIu8"\n",
hvcc->constantFrameRate);
av_log(NULL, AV_LOG_TRACE, "numTemporalLayers: %"PRIu8"\n",
hvcc->numTemporalLayers);
av_log(NULL, AV_LOG_TRACE, "temporalIdNested: %"PRIu8"\n",
hvcc->temporalIdNested);
av_log(NULL, AV_LOG_TRACE, "lengthSizeMinusOne: %"PRIu8"\n",
hvcc->lengthSizeMinusOne);
av_log(NULL, AV_LOG_TRACE, "numOfArrays: %"PRIu8"\n",
hvcc->numOfArrays);
for (i = 0; i < hvcc->numOfArrays; i++) {
av_log(NULL, AV_LOG_TRACE, "array_completeness[%"PRIu8"]: %"PRIu8"\n",
i, hvcc->array[i].array_completeness);
av_log(NULL, AV_LOG_TRACE, "NAL_unit_type[%"PRIu8"]: %"PRIu8"\n",
i, hvcc->array[i].NAL_unit_type);
av_log(NULL, AV_LOG_TRACE, "numNalus[%"PRIu8"]: %"PRIu16"\n",
i, hvcc->array[i].numNalus);
for (j = 0; j < hvcc->array[i].numNalus; j++)
av_log(NULL, AV_LOG_TRACE,
"nalUnitLength[%"PRIu8"][%"PRIu16"]: %"PRIu16"\n",
i, j, hvcc->array[i].nalUnitLength[j]);
}
/*
* We need at least one of each: VPS, SPS and PPS.
*/
for (i = 0; i < hvcc->numOfArrays; i++)
switch (hvcc->array[i].NAL_unit_type) {
case NAL_VPS:
vps_count += hvcc->array[i].numNalus;
break;
case NAL_SPS:
sps_count += hvcc->array[i].numNalus;
break;
case NAL_PPS:
pps_count += hvcc->array[i].numNalus;
break;
default:
break;
}
if (!vps_count || vps_count > MAX_VPS_COUNT ||
!sps_count || sps_count > MAX_SPS_COUNT ||
!pps_count || pps_count > MAX_PPS_COUNT)
return AVERROR_INVALIDDATA;
/* unsigned int(8) configurationVersion = 1; */
avio_w8(pb, hvcc->configurationVersion);
/*
* unsigned int(2) general_profile_space;
* unsigned int(1) general_tier_flag;
* unsigned int(5) general_profile_idc;
*/
avio_w8(pb, hvcc->general_profile_space << 6 |
hvcc->general_tier_flag << 5 |
hvcc->general_profile_idc);
/* unsigned int(32) general_profile_compatibility_flags; */
avio_wb32(pb, hvcc->general_profile_compatibility_flags);
/* unsigned int(48) general_constraint_indicator_flags; */
avio_wb32(pb, hvcc->general_constraint_indicator_flags >> 16);
avio_wb16(pb, hvcc->general_constraint_indicator_flags);
/* unsigned int(8) general_level_idc; */
avio_w8(pb, hvcc->general_level_idc);
/*
* bit(4) reserved = 鈥?111鈥檅;
* unsigned int(12) min_spatial_segmentation_idc;
*/
avio_wb16(pb, hvcc->min_spatial_segmentation_idc | 0xf000);
/*
* bit(6) reserved = 鈥?11111鈥檅;
* unsigned int(2) parallelismType;
*/
avio_w8(pb, hvcc->parallelismType | 0xfc);
/*
* bit(6) reserved = 鈥?11111鈥檅;
* unsigned int(2) chromaFormat;
*/
avio_w8(pb, hvcc->chromaFormat | 0xfc);
/*
* bit(5) reserved = 鈥?1111鈥檅;
* unsigned int(3) bitDepthLumaMinus8;
*/
avio_w8(pb, hvcc->bitDepthLumaMinus8 | 0xf8);
/*
* bit(5) reserved = 鈥?1111鈥檅;
* unsigned int(3) bitDepthChromaMinus8;
*/
avio_w8(pb, hvcc->bitDepthChromaMinus8 | 0xf8);
/* bit(16) avgFrameRate; */
avio_wb16(pb, hvcc->avgFrameRate);
/*
* bit(2) constantFrameRate;
* bit(3) numTemporalLayers;
* bit(1) temporalIdNested;
* unsigned int(2) lengthSizeMinusOne;
*/
avio_w8(pb, hvcc->constantFrameRate << 6 |
hvcc->numTemporalLayers << 3 |
hvcc->temporalIdNested << 2 |
hvcc->lengthSizeMinusOne);
/* unsigned int(8) numOfArrays; */
avio_w8(pb, hvcc->numOfArrays);
for (i = 0; i < hvcc->numOfArrays; i++) {
/*
* bit(1) array_completeness;
* unsigned int(1) reserved = 0;
* unsigned int(6) NAL_unit_type;
*/
avio_w8(pb, hvcc->array[i].array_completeness << 7 |
hvcc->array[i].NAL_unit_type & 0x3f);
/* unsigned int(16) numNalus; */
avio_wb16(pb, hvcc->array[i].numNalus);
for (j = 0; j < hvcc->array[i].numNalus; j++) {
/* unsigned int(16) nalUnitLength; */
avio_wb16(pb, hvcc->array[i].nalUnitLength[j]);
/* bit(8*nalUnitLength) nalUnit; */
avio_write(pb, hvcc->array[i].nalUnit[j],
hvcc->array[i].nalUnitLength[j]);
}
}
return 0;
}
MP4+h.265 configuration tag demux
函数hevc_decode_extradata()
static int hevc_decode_extradata(HEVCContext *s)
{
AVCodecContext *avctx = s->avctx;
GetByteContext gb;
int ret, i;
bytestream2_init(&gb, avctx->extradata, avctx->extradata_size);
if (avctx->extradata_size > 3 &&
(avctx->extradata[0] || avctx->extradata[1] ||
avctx->extradata[2] > 1)) {
/* It seems the extradata is encoded as hvcC format.
* Temporarily, we support configurationVersion==0 until 14496-15 3rd
* is finalized. When finalized, configurationVersion will be 1 and we
* can recognize hvcC by checking if avctx->extradata[0]==1 or not. */
int i, j, num_arrays, nal_len_size;
s->is_nalff = 1;
bytestream2_skip(&gb, 21);
nal_len_size = (bytestream2_get_byte(&gb) & 3) + 1;
num_arrays = bytestream2_get_byte(&gb);
/* nal units in the hvcC always have length coded with 2 bytes,
* so put a fake nal_length_size = 2 while parsing them */
s->nal_length_size = 2;
/* Decode nal units from hvcC. */
for (i = 0; i < num_arrays; i++) {
int type = bytestream2_get_byte(&gb) & 0x3f;
int cnt = bytestream2_get_be16(&gb);
for (j = 0; j < cnt; j++) {
// +2 for the nal size field
int nalsize = bytestream2_peek_be16(&gb) + 2;
if (bytestream2_get_bytes_left(&gb) < nalsize) {
av_log(s->avctx, AV_LOG_ERROR,
"Invalid NAL unit size in extradata.\n");
return AVERROR_INVALIDDATA;
}
ret = decode_nal_units(s, gb.buffer, nalsize);
if (ret < 0) {
av_log(avctx, AV_LOG_ERROR,
"Decoding nal unit %d %d from hvcC failed\n",
type, i);
return ret;
}
bytestream2_skip(&gb, nalsize);
}
}
/* Now store right nal length size, that will be used to parse
* all other nals */
s->nal_length_size = nal_len_size;
} else {
s->is_nalff = 0;
ret = decode_nal_units(s, avctx->extradata, avctx->extradata_size);
if (ret < 0)
return ret;
}
/* export stream parameters from the first SPS */
for (i = 0; i < FF_ARRAY_ELEMS(s->ps.sps_list); i++) {
if (s->ps.sps_list[i]) {
const HEVCSPS *sps = (const HEVCSPS*)s->ps.sps_list[i]->data;
export_stream_params(s->avctx, &s->ps, sps);
break;
}
}
return 0;
}