in src/mkvgen/src/NalAdapter.c [270:416]
STATUS adaptH265CpdNalsFromAnnexBToHvcc(PBYTE pCpd, UINT32 cpdSize, PBYTE pAdaptedCpd, PUINT32 pAdaptedCpdSize)
{
STATUS retStatus = STATUS_SUCCESS;
UINT32 naluSize, adaptedRawSize, adaptedCpdSize = 0, naluCount = 0, i;
PBYTE pAdaptedBits = NULL, pCurPnt = pAdaptedCpd, pSrcPnt;
H265SpsInfo spsInfo;
UINT32 naluSizes[3];
PBYTE naluPtrs[3];
// Nalu types in order - VPS, SPS, PPS
BYTE naluTypes[3] = {HEVC_VPS_NALU_TYPE, HEVC_SPS_NALU_TYPE, HEVC_PPS_NALU_TYPE};
CHK(pCpd != NULL && pAdaptedCpdSize != NULL, STATUS_NULL_ARG);
// We should have at least 3 NALs with at least single byte data so even the short start code should account for 12
CHK(cpdSize >= MIN_H_265_ANNEXB_CPD_SIZE, STATUS_MKV_MIN_ANNEX_B_CPD_SIZE);
// Convert the raw bits
CHK_STATUS(adaptFrameNalsFromAnnexBToAvcc(pCpd, cpdSize, FALSE, NULL, &adaptedRawSize));
// Allocate enough storage to store the data temporarily
pAdaptedBits = (PBYTE) MEMALLOC(adaptedRawSize);
CHK(pAdaptedBits != NULL, STATUS_NOT_ENOUGH_MEMORY);
// Get the converted bits
CHK_STATUS(adaptFrameNalsFromAnnexBToAvcc(pCpd, cpdSize, FALSE, pAdaptedBits, &adaptedRawSize));
// Set the source pointer to walk the adapted data
pSrcPnt = pAdaptedBits;
// Get the NALu count and store the pointer to SPS
// It should be VPS/SPS/PPS
// In some cases the PPS might be missing
while (naluCount < ARRAY_SIZE(naluTypes) && (UINT32)(pSrcPnt - pAdaptedBits) < adaptedRawSize) {
CHK(pSrcPnt - pAdaptedBits + SIZEOF(UINT32) <= adaptedRawSize, STATUS_MKV_INVALID_ANNEXB_CPD_NALUS);
naluSize = (UINT32) GET_UNALIGNED_BIG_ENDIAN((PUINT32) pSrcPnt);
// Store the NALU pointer
naluPtrs[naluCount] = pSrcPnt + SIZEOF(UINT32);
naluSizes[naluCount] = naluSize;
pSrcPnt += SIZEOF(UINT32) + naluSize;
CHK((UINT32)(pSrcPnt - pAdaptedBits) <= adaptedRawSize, STATUS_MKV_INVALID_ANNEXB_CPD_NALUS);
naluCount++;
}
CHK(naluCount >= 2, STATUS_MKV_ANNEXB_CPD_MISSING_NALUS);
// Limit NALus to 3
naluCount = MIN(3, naluCount);
// Calculate the required size
adaptedCpdSize = HEVC_CPD_HEADER_OVERHEAD + naluCount * HEVC_CPD_ENTRY_OVERHEAD;
// Add the raw size
for (i = 0; i < naluCount; i++) {
adaptedCpdSize += naluSizes[i];
}
// Quick check for size only
CHK(pAdaptedCpd != NULL, retStatus);
// If we get a larger buffer size then it's an error
CHK(adaptedCpdSize <= *pAdaptedCpdSize, STATUS_BUFFER_TOO_SMALL);
// Parse the SPS
CHK_STATUS(parseH265Sps(naluPtrs[1], naluSizes[1], &spsInfo));
// Start converting and copying it to the output
// configurationVersion
*pCurPnt++ = HEVC_CONFIG_VERSION_CODE;
// general_profile_space, general_tier_flag, general_profile_idc
*pCurPnt++ = (UINT8)(spsInfo.general_profile_space << 6 | (spsInfo.general_tier_flag & 0x01) << 5 | (spsInfo.general_profile_idc & 0x1f));
// general_profile_compatibility_flags
*pCurPnt++ = spsInfo.general_profile_compatibility_flags[0];
*pCurPnt++ = spsInfo.general_profile_compatibility_flags[1];
*pCurPnt++ = spsInfo.general_profile_compatibility_flags[2];
*pCurPnt++ = spsInfo.general_profile_compatibility_flags[3];
// general_constraint_indicator_flags
*pCurPnt++ = spsInfo.general_constraint_indicator_flags[0];
*pCurPnt++ = spsInfo.general_constraint_indicator_flags[1];
*pCurPnt++ = spsInfo.general_constraint_indicator_flags[2];
*pCurPnt++ = spsInfo.general_constraint_indicator_flags[3];
*pCurPnt++ = spsInfo.general_constraint_indicator_flags[4];
*pCurPnt++ = spsInfo.general_constraint_indicator_flags[5];
// general_level_idc
*pCurPnt++ = spsInfo.general_level_idc;
// min_spatial_segmentation_idc
*pCurPnt++ = 0xf0;
*pCurPnt++ = 0x00;
// parallelismType
*pCurPnt++ = 0xfc;
// chroma_format_idc
*pCurPnt++ = (UINT8)(0xfc | (spsInfo.chroma_format_idc & 0x03));
// bit_depth_luma_minus8
*pCurPnt++ = (UINT8)(0xf8 | (spsInfo.bit_depth_luma_minus8 & 0x07));
// bit_depth_luma_minus8
*pCurPnt++ = (UINT8)(0xf8 | (spsInfo.bit_depth_chroma_minus8 & 0x07));
// avgFrameRate
*pCurPnt++ = 0x00;
*pCurPnt++ = 0x00;
// constantFrameRate, numTemporalLayers, temporalIdNested, lengthSizeMinusOne
*pCurPnt++ = 0x0f;
// numOfArrays
*pCurPnt++ = (UINT8) naluCount;
for (i = 0; i < naluCount; i++) {
// array_completeness, reserved, NAL_unit_type
*pCurPnt++ = naluTypes[i];
// numNalus
*pCurPnt++ = 0x00;
*pCurPnt++ = 0x01;
// nalUnitLength
PUT_UNALIGNED_BIG_ENDIAN((PINT16) pCurPnt, (UINT16) naluSizes[i]);
pCurPnt += SIZEOF(UINT16);
// Write the NALu data
MEMCPY(pCurPnt, naluPtrs[i], naluSizes[i]);
pCurPnt += naluSizes[i];
}
CleanUp:
if (pAdaptedCpdSize != NULL) {
*pAdaptedCpdSize = adaptedCpdSize;
}
if (pAdaptedBits != NULL) {
MEMFREE(pAdaptedBits);
}
return retStatus;
}