STATUS createMkvGenerator()

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;
}