in src/mkvgen/src/MkvGenerator.c [15:151]
STATUS createMkvGenerator(PCHAR contentType, UINT32 behaviorFlags, UINT64 timecodeScale, UINT64 clusterDuration, PBYTE segmentUuid,
PTrackInfo trackInfoList, UINT32 trackInfoCount, PCHAR clientId, GetCurrentTimeFunc getTimeFn, UINT64 customData,
PMkvGenerator* ppMkvGenerator)
{
ENTERS();
STATUS retStatus = STATUS_SUCCESS;
PStreamMkvGenerator pMkvGenerator = NULL;
UINT32 allocationSize, i;
BOOL adaptAnnexB = FALSE, adaptAvcc = FALSE, adaptCpdAnnexB = FALSE;
PTrackInfo pSrcTrackInfo, pDstTrackInfo;
// Check the input params
CHK(ppMkvGenerator != NULL, STATUS_NULL_ARG);
// Clustering boundary checks if we are not doing key-frame clustering
if ((behaviorFlags & MKV_GEN_KEY_FRAME_PROCESSING) == MKV_GEN_FLAG_NONE) {
CHK(clusterDuration <= MAX_CLUSTER_DURATION && clusterDuration >= MIN_CLUSTER_DURATION, STATUS_MKV_INVALID_CLUSTER_DURATION);
}
if ((behaviorFlags & MKV_GEN_ADAPT_ANNEXB_NALS) == MKV_GEN_ADAPT_ANNEXB_NALS) {
adaptAnnexB = TRUE;
}
if ((behaviorFlags & MKV_GEN_ADAPT_AVCC_NALS) == MKV_GEN_ADAPT_AVCC_NALS) {
adaptAvcc = TRUE;
}
if ((behaviorFlags & MKV_GEN_ADAPT_ANNEXB_CPD_NALS) == MKV_GEN_ADAPT_ANNEXB_CPD_NALS) {
adaptCpdAnnexB = TRUE;
}
CHK(!(adaptAnnexB && adaptAvcc), STATUS_MKV_BOTH_ANNEXB_AND_AVCC_SPECIFIED);
CHK(timecodeScale <= MAX_TIMECODE_SCALE && timecodeScale >= MIN_TIMECODE_SCALE, STATUS_MKV_INVALID_TIMECODE_SCALE);
CHK(STRNLEN(contentType, MAX_CONTENT_TYPE_LEN + 1) <= MAX_CONTENT_TYPE_LEN, STATUS_MKV_INVALID_CONTENT_TYPE_LENGTH);
// Validate the client id string if specified
CHK(clientId == NULL || STRNLEN(clientId, MAX_MKV_CLIENT_ID_STRING_LEN + 1) <= MAX_MKV_CLIENT_ID_STRING_LEN, STATUS_MKV_INVALID_CLIENT_ID_LENGTH);
for (i = 0; i < trackInfoCount; ++i) {
PTrackInfo pTrackInfo = &trackInfoList[i];
CHK(STRNLEN(pTrackInfo->codecId, MKV_MAX_CODEC_ID_LEN + 1) <= MKV_MAX_CODEC_ID_LEN, STATUS_MKV_INVALID_CODEC_ID_LENGTH);
CHK(STRNLEN(pTrackInfo->trackName, MKV_MAX_TRACK_NAME_LEN + 1) <= MKV_MAX_TRACK_NAME_LEN, STATUS_MKV_INVALID_TRACK_NAME_LENGTH);
CHK(pTrackInfo->codecPrivateDataSize <= MKV_MAX_CODEC_PRIVATE_LEN, STATUS_MKV_INVALID_CODEC_PRIVATE_LENGTH);
CHK(pTrackInfo->codecPrivateDataSize == 0 || pTrackInfo->codecPrivateData != NULL, STATUS_MKV_CODEC_PRIVATE_NULL);
CHK(pTrackInfo->trackId != 0, STATUS_MKV_INVALID_TRACK_UID);
}
// Initialize the endianness for the library
initializeEndianness();
for (i = 0; i < trackInfoCount; ++i) {
if (trackInfoList[i].codecPrivateDataSize != 0) {
DLOGS("TrackName: %s, CodecId: %s", trackInfoList[i].trackName, trackInfoList[i].codecId);
dumpMemoryHex(trackInfoList[i].codecPrivateData, trackInfoList[i].codecPrivateDataSize);
}
}
// Allocate the main struct
// NOTE: The calloc will Zero the fields
allocationSize = SIZEOF(StreamMkvGenerator) + SIZEOF(TrackInfo) * trackInfoCount;
pMkvGenerator = (PStreamMkvGenerator) MEMCALLOC(1, allocationSize);
CHK(pMkvGenerator != NULL, STATUS_NOT_ENOUGH_MEMORY);
// Set the values
pMkvGenerator->mkvGenerator.version = 0;
pMkvGenerator->timecodeScale = timecodeScale * DEFAULT_TIME_UNIT_IN_NANOS; // store in nanoseconds
pMkvGenerator->clusterDuration =
clusterDuration * DEFAULT_TIME_UNIT_IN_NANOS / pMkvGenerator->timecodeScale; // No chance of an overflow as we check against max earlier
pMkvGenerator->contentType = mkvgenGetContentTypeFromContentTypeString(contentType);
pMkvGenerator->generatorState = MKV_GENERATOR_STATE_START;
pMkvGenerator->keyFrameClustering = (behaviorFlags & MKV_GEN_KEY_FRAME_PROCESSING) != MKV_GEN_FLAG_NONE;
pMkvGenerator->streamTimestamps = (behaviorFlags & MKV_GEN_IN_STREAM_TIME) != MKV_GEN_FLAG_NONE;
pMkvGenerator->absoluteTimeClusters = (behaviorFlags & MKV_GEN_ABSOLUTE_CLUSTER_TIME) != MKV_GEN_FLAG_NONE;
pMkvGenerator->adaptCpdNals = adaptCpdAnnexB;
pMkvGenerator->lastClusterPts = 0;
pMkvGenerator->lastClusterDts = 0;
pMkvGenerator->streamStartTimestamp = 0;
pMkvGenerator->streamStartTimestampStored = FALSE;
pMkvGenerator->trackInfoCount = trackInfoCount;
// Package the version
if (clientId != NULL && clientId[0] != '\0') {
pMkvGenerator->versionSize =
SNPRINTF(pMkvGenerator->version, SIZEOF(pMkvGenerator->version), (PCHAR) "%c%s%c%s", MKV_VERSION_STRING_DELIMITER,
MKV_GENERATOR_CURRENT_VERSION_STRING, MKV_VERSION_STRING_DELIMITER, clientId);
} else {
pMkvGenerator->versionSize = SNPRINTF(pMkvGenerator->version, SIZEOF(pMkvGenerator->version), (PCHAR) "%c%s", MKV_VERSION_STRING_DELIMITER,
MKV_GENERATOR_CURRENT_VERSION_STRING);
}
// Copy TrackInfoList to the end of MkvGenerator struct
pMkvGenerator->trackInfoList = (PTrackInfo)(pMkvGenerator + 1);
MEMCPY(pMkvGenerator->trackInfoList, trackInfoList, SIZEOF(TrackInfo) * trackInfoCount);
if (adaptAnnexB) {
pMkvGenerator->nalsAdaptation = MKV_NALS_ADAPT_ANNEXB;
} else if (adaptAvcc) {
pMkvGenerator->nalsAdaptation = MKV_NALS_ADAPT_AVCC;
} else {
pMkvGenerator->nalsAdaptation = MKV_NALS_ADAPT_NONE;
}
// the getTime function is optional
pMkvGenerator->getTimeFn = (getTimeFn != NULL) ? getTimeFn : getTimeAdapter;
// Segment UUID has been zeroed already by calloc
if (segmentUuid != NULL) {
CHK(!checkBufferValues(segmentUuid, 0x00, MKV_SEGMENT_UUID_LEN), STATUS_MKV_INVALID_SEGMENT_UUID);
MEMCPY(pMkvGenerator->segmentUuid, segmentUuid, MKV_SEGMENT_UUID_LEN);
} else {
MEMSET(pMkvGenerator->segmentUuid, MKV_SEGMENT_UUID_DEFAULT_VALUE, MKV_SEGMENT_UUID_LEN);
}
// Store the custom data as well
pMkvGenerator->customData = customData;
// Set the codec private data
pDstTrackInfo = pMkvGenerator->trackInfoList;
pSrcTrackInfo = trackInfoList;
for (i = 0; i < trackInfoCount; i++, pDstTrackInfo++, pSrcTrackInfo++) {
CHK_STATUS(mkvgenAdaptCodecPrivateData(pMkvGenerator, pSrcTrackInfo->trackType, pSrcTrackInfo->codecId, pSrcTrackInfo->codecPrivateDataSize,
pSrcTrackInfo->codecPrivateData, &pDstTrackInfo->codecPrivateDataSize,
&pDstTrackInfo->codecPrivateData, &pDstTrackInfo->trackCustomData));
}
// Assign the created object
*ppMkvGenerator = (PMkvGenerator) pMkvGenerator;
CleanUp:
if (STATUS_FAILED(retStatus)) {
freeMkvGenerator((PMkvGenerator) pMkvGenerator);
}
LEAVES();
return retStatus;
}