in src/mkvgen/src/MkvGenerator.c [1102:1264]
STATUS mkvgenEbmlEncodeTrackInfo(PBYTE pBuffer, UINT32 bufferSize, PStreamMkvGenerator pMkvGenerator, PUINT32 pEncodedLen)
{
STATUS retStatus = STATUS_SUCCESS;
UINT32 j, encodedCpdLen = 0, cpdSize = 0, encodedLen = 0, cpdOffset = 0;
UINT32 mkvTrackDataSize = 0, mkvTracksDataSize = 0, codecIdDataSize = 0, trackNameDataSize = 0;
PBYTE pTrackStart = NULL;
UINT32 trackSpecificDataOffset = 0, mkvAudioBitsSize = 0;
PTrackInfo pTrackInfo = NULL;
CHK(pEncodedLen != NULL && pMkvGenerator != NULL, STATUS_NULL_ARG);
// Set the size first
*pEncodedLen = mkvgenGetMkvTrackHeaderSize(pMkvGenerator->trackInfoList, pMkvGenerator->trackInfoCount);
// Quick return if we just need to calculate the size
CHK(pBuffer != NULL, retStatus);
CHK(bufferSize >= *pEncodedLen, STATUS_NOT_ENOUGH_MEMORY);
// Copy over Tracks Header bytes (element + size)
MEMCPY(pBuffer, MKV_TRACKS_ELEM_BITS, MKV_TRACKS_ELEM_BITS_SIZE);
// Save the beginning of TrackEntry element
pTrackStart = pBuffer + MKV_TRACK_ENTRY_OFFSET;
for (j = 0; j < pMkvGenerator->trackInfoCount; ++j) {
pTrackInfo = &pMkvGenerator->trackInfoList[j];
MEMCPY(pTrackStart, MKV_TRACK_INFO_BITS, MKV_TRACK_INFO_BITS_SIZE);
mkvTrackDataSize += MKV_TRACK_INFO_BITS_SIZE - MKV_TRACK_ENTRY_HEADER_BITS_SIZE;
// Offset into available spots to store elements not in default TrackEntry template.
// Such elements include audio, video, cpd.
trackSpecificDataOffset = MKV_TRACK_INFO_BITS_SIZE;
// Fix-up the track type
*(pTrackStart + MKV_TRACK_TYPE_OFFSET) = (BYTE) pTrackInfo->trackType;
// Package track name
trackNameDataSize = (UINT32) STRNLEN(pTrackInfo->trackName, MKV_MAX_TRACK_NAME_LEN);
if (trackNameDataSize > 0) {
MEMCPY(pTrackStart + trackSpecificDataOffset, MKV_TRACK_NAME_BITS, MKV_TRACK_NAME_BITS_SIZE);
trackSpecificDataOffset += MKV_TRACK_NAME_BITS_SIZE;
// Encode the track name
CHK_STATUS(
mkvgenEbmlEncodeNumber(trackNameDataSize, pTrackStart + trackSpecificDataOffset, bufferSize - trackSpecificDataOffset, &encodedLen));
trackSpecificDataOffset += encodedLen;
MEMCPY(pTrackStart + trackSpecificDataOffset, pTrackInfo->trackName, trackNameDataSize);
trackSpecificDataOffset += trackNameDataSize;
mkvTrackDataSize += MKV_TRACK_NAME_BITS_SIZE + encodedLen + trackNameDataSize;
}
// done packaging track name
// Package codec id
codecIdDataSize = (UINT32) STRNLEN(pTrackInfo->codecId, MKV_MAX_CODEC_ID_LEN);
if (codecIdDataSize > 0) {
MEMCPY(pTrackStart + trackSpecificDataOffset, MKV_CODEC_ID_BITS, MKV_CODEC_ID_BITS_SIZE);
trackSpecificDataOffset += MKV_CODEC_ID_BITS_SIZE;
// Encode the codec id size
CHK_STATUS(
mkvgenEbmlEncodeNumber(codecIdDataSize, pTrackStart + trackSpecificDataOffset, bufferSize - trackSpecificDataOffset, &encodedLen));
trackSpecificDataOffset += encodedLen;
mkvTrackDataSize += MKV_CODEC_ID_BITS_SIZE + encodedLen + codecIdDataSize;
MEMCPY(pTrackStart + trackSpecificDataOffset, pTrackInfo->codecId, codecIdDataSize);
trackSpecificDataOffset += codecIdDataSize;
}
// done packaging codec id
// Fix up track number. Use trackInfo's index as mkv track number. Mkv track number starts from 1
*(pTrackStart + MKV_TRACK_NUMBER_OFFSET) = (BYTE)(j + 1);
// Fix up the track UID
PUT_UNALIGNED_BIG_ENDIAN((PINT64)(pTrackStart + MKV_TRACK_ID_OFFSET), pTrackInfo->trackId);
// Append the video config if any
if (GENERATE_VIDEO_CONFIG(&pMkvGenerator->trackInfoList[j])) {
// Record the amount of storage used in order to skip to next track later
mkvTrackDataSize += MKV_TRACK_VIDEO_BITS_SIZE;
// Copy the element first
MEMCPY(pTrackStart + trackSpecificDataOffset, MKV_TRACK_VIDEO_BITS, MKV_TRACK_VIDEO_BITS_SIZE);
// Fix-up the width and height
PUT_UNALIGNED_BIG_ENDIAN((PINT16)(pTrackStart + trackSpecificDataOffset + MKV_TRACK_VIDEO_WIDTH_OFFSET),
pTrackInfo->trackCustomData.trackVideoConfig.videoWidth);
PUT_UNALIGNED_BIG_ENDIAN((PINT16)(pTrackStart + trackSpecificDataOffset + MKV_TRACK_VIDEO_HEIGHT_OFFSET),
pTrackInfo->trackCustomData.trackVideoConfig.videoHeight);
trackSpecificDataOffset += MKV_TRACK_VIDEO_BITS_SIZE;
} else if (GENERATE_AUDIO_CONFIG(&pMkvGenerator->trackInfoList[j])) {
mkvAudioBitsSize = mkvgenGetMkvAudioBitsSize(&pMkvGenerator->trackInfoList[j]);
// Record the amount of storage used in order to skip to next track later
mkvTrackDataSize += mkvAudioBitsSize;
// Copy the element first
MEMCPY(pTrackStart + trackSpecificDataOffset, MKV_TRACK_AUDIO_BITS, MKV_TRACK_AUDIO_BITS_SIZE);
PUT_UNALIGNED_BIG_ENDIAN((PINT64)(pTrackStart + trackSpecificDataOffset + MKV_TRACK_AUDIO_SAMPLING_RATE_OFFSET),
*((PINT64)(&pTrackInfo->trackCustomData.trackAudioConfig.samplingFrequency)));
*(pTrackStart + trackSpecificDataOffset + MKV_TRACK_AUDIO_CHANNELS_OFFSET) =
(UINT8) pTrackInfo->trackCustomData.trackAudioConfig.channelConfig;
if (pMkvGenerator->trackInfoList[j].trackCustomData.trackAudioConfig.bitDepth != 0) {
MEMCPY(pTrackStart + trackSpecificDataOffset + MKV_TRACK_AUDIO_BITS_SIZE, MKV_TRACK_AUDIO_BIT_DEPTH_BITS,
MKV_TRACK_AUDIO_BIT_DEPTH_BITS_SIZE);
*(pTrackStart + trackSpecificDataOffset + MKV_TRACK_AUDIO_BIT_DEPTH_OFFSET) =
(UINT8) pTrackInfo->trackCustomData.trackAudioConfig.bitDepth;
// fix up audio element data size
encodedLen = (0x10000000 | (UINT32)(mkvAudioBitsSize)) - MKV_TRACK_AUDIO_EBML_HEADER_SIZE;
// +1 to skip the audio element
PUT_UNALIGNED_BIG_ENDIAN((PINT32)(pTrackStart + trackSpecificDataOffset + 1), encodedLen);
}
trackSpecificDataOffset += mkvAudioBitsSize;
}
// Append the codec private data if any
if (pTrackInfo->codecPrivateDataSize != 0 && pTrackInfo->codecPrivateData != NULL) {
// Offset of the CPD right after the main structure and the video config if any
cpdOffset = trackSpecificDataOffset;
// Copy the element first
MEMCPY(pTrackStart + cpdOffset, MKV_CODEC_PRIVATE_DATA_ELEM, MKV_CODEC_PRIVATE_DATA_ELEM_SIZE);
cpdSize = MKV_CODEC_PRIVATE_DATA_ELEM_SIZE;
// Encode the CPD size
CHK_STATUS(mkvgenEbmlEncodeNumber(pTrackInfo->codecPrivateDataSize, pTrackStart + cpdOffset + cpdSize, bufferSize - cpdOffset - cpdSize,
&encodedCpdLen));
cpdSize += encodedCpdLen;
CHK(cpdOffset + cpdSize + pTrackInfo->codecPrivateDataSize <= bufferSize, STATUS_NOT_ENOUGH_MEMORY);
// Copy the actual CPD bits
MEMCPY(pTrackStart + cpdOffset + cpdSize, pTrackInfo->codecPrivateData, pTrackInfo->codecPrivateDataSize);
cpdSize += pTrackInfo->codecPrivateDataSize;
mkvTrackDataSize += cpdSize;
}
// Important! Need to fix-up the overall track header element size and the track entry element size
// Encode and fix-up the size - encode 4 bytes
encodedLen = 0x10000000 | (UINT32)(mkvTrackDataSize);
PUT_UNALIGNED_BIG_ENDIAN((PINT32)(pTrackStart + MKV_TRACK_ENTRY_SIZE_OFFSET), encodedLen);
// Need to add back TrackEntry header bits to skip to the end of current TrackEntry
pTrackStart += mkvTrackDataSize + MKV_TRACK_ENTRY_HEADER_BITS_SIZE;
// TrackEntry header bits size also need to be accounted when calculating overall Tracks size
mkvTracksDataSize += mkvTrackDataSize + MKV_TRACK_ENTRY_HEADER_BITS_SIZE;
// Reset mkvTrackDataSize as we are starting for a new track
mkvTrackDataSize = 0;
}
// Important! Need to fix-up the overall track header element size and the track entry element size
// Encode and fix-up the size - encode 4 bytes
encodedLen = 0x10000000 | (UINT32)(mkvTracksDataSize);
PUT_UNALIGNED_BIG_ENDIAN((PINT32)(pBuffer + MKV_TRACK_HEADER_SIZE_OFFSET), encodedLen);
CleanUp:
return retStatus;
}