void
videoEditOsal_free(
                void*                               pData)
{
    // Check if memory was allocated.
    if (M4OSA_NULL != pData)
    {
        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_OSAL", "videoEditOsal_free()");

        // Log the API call.
        VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR_OSAL", "free");

        // Free the memory.
        free(pData);
#ifdef OSAL_MEM_LEAK_DEBUG
        // Update the allocated block count.
        gAllocatedBlockCount--;

        // Log the number of allocated blocks.
        VIDEOEDIT_LOG_ALLOCATION(ANDROID_LOG_ERROR, "VIDEO_EDITOR_OSAL", "allocated, %d blocks",\
         gAllocatedBlockCount);
#endif
    }
}
jobject videoEditProp_getProperties(
        JNIEnv* pEnv,
        jobject thiz,
        jstring file)
{
    bool                           gotten          = true;
    M4OSA_Char*                    pFile           = M4OSA_NULL;
    M4OSA_Char*                    pExtension      = M4OSA_NULL;
    M4OSA_UInt32                   index           = 0;
    M4OSA_Int32                    cmpResult       = 0;
    VideoEditPropClass_Properties* pProperties     = M4OSA_NULL;
    M4VIDEOEDITING_ClipProperties* pClipProperties = M4OSA_NULL;
    M4OSA_ERR                      result          = M4NO_ERROR;
    M4MCS_Context                  context         = M4OSA_NULL;
    M4OSA_FilePosition             size            = 0;
    M4OSA_UInt32                   width           = 0;
    M4OSA_UInt32                   height          = 0;
    jobject                        properties      = NULL;
    M4OSA_Context                  pOMXContext     = M4OSA_NULL;
    M4DECODER_VideoInterface*      pOMXVidDecoderInterface = M4OSA_NULL;
    M4AD_Interface*                pOMXAudDecoderInterface = M4OSA_NULL;

    bool  initialized = true;
    VideoEditClasses_FileType fileType = VideoEditClasses_kFileType_Unsupported;
    M4VIDEOEDITING_FileType clipType = M4VIDEOEDITING_kFileType_Unsupported;

    VIDEOEDIT_LOG_API(
            ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
            "videoEditProp_getProperties()");

    // Add a text marker (the condition must always be true).
    ADD_TEXT_MARKER_FUN(NULL != pEnv)

    // Initialize the classes.
    videoEditPropClass_init(&initialized, (JNIEnv*)pEnv);

    // Validate the tempPath parameter.
    videoEditJava_checkAndThrowIllegalArgumentException(
            &gotten, pEnv, (NULL == file), "file is null");

    // Get the file path.
    pFile = (M4OSA_Char *)videoEditJava_getString(
            &gotten, pEnv, file, NULL, M4OSA_NULL);

    result = M4OSA_fileReadOpen(&context, (M4OSA_Void*)pFile, M4OSA_kFileRead);

    if(M4NO_ERROR != result) {
        // Free the file path.
        videoEditOsal_free(pFile);
        pFile = M4OSA_NULL;
    }

    videoEditJava_checkAndThrowIllegalArgumentException(&gotten, pEnv,
        (M4NO_ERROR != result), "file not found");

    // Close the file and free the file context
    if (context != NULL) {
        result = M4OSA_fileReadClose(context);
        context = M4OSA_NULL;
    }

    // Return if Error
    if (M4NO_ERROR != result) {
        return (properties); // NULL
    }

    // Check if the file path is valid.
    if (gotten)
    {
        // Retrieve the extension.
        pExtension = (M4OSA_Char *)strrchr((const char *)pFile, (int)'.');
        if (M4OSA_NULL != pExtension)
        {
            // Skip the dot.
            pExtension++;

            // Get the file type and Media type from extension
            getFileAndMediaTypeFromExtension(
                    pExtension ,&fileType, &clipType);
        }
    }

    // Check if the file type could be determined.
    videoEditJava_checkAndThrowIllegalArgumentException(
            &gotten, pEnv,
            (VideoEditClasses_kFileType_Unsupported == fileType),
            "file type is not supported");

    // Allocate a new properties structure.
    pProperties = (VideoEditPropClass_Properties*)videoEditOsal_alloc(
            &gotten, pEnv,
            sizeof(VideoEditPropClass_Properties), "Properties");

    // Check if the context is valid and allocation succeeded
    // (required because of dereferencing of pProperties).
    if (gotten)
    {
        // Check if this type of file needs to be analyzed using MCS.
        if ((VideoEditClasses_kFileType_MP3  == fileType) ||
            (VideoEditClasses_kFileType_MP4  == fileType) ||
            (VideoEditClasses_kFileType_3GPP == fileType) ||
            (VideoEditClasses_kFileType_AMR  == fileType) ||
            (VideoEditClasses_kFileType_PCM  == fileType) ||
            (VideoEditClasses_kFileType_M4V  == fileType))
        {
            // Allocate a new clip properties structure.
            pClipProperties =
                (M4VIDEOEDITING_ClipProperties*)videoEditOsal_alloc(
                    &gotten, pEnv,
                    sizeof(M4VIDEOEDITING_ClipProperties), "ClipProperties");

            // Check if allocation succeeded (required because of
            // dereferencing of pClipProperties).
            if (gotten)
            {
                // Add a code marker (the condition must always be true).
                ADD_CODE_MARKER_FUN(NULL != pClipProperties)

                // Log the API call.
                VIDEOEDIT_LOG_API(
                        ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
                        "getClipProperties");

                // Get Video clip properties
                result = getClipProperties(
                        pEnv, thiz, pFile, clipType, pClipProperties);

                if (M4MCS_ERR_FILE_DRM_PROTECTED == result) {
                    // Check if the creation succeeded.
                    videoEditJava_checkAndThrowIllegalArgumentException(
                            &gotten, pEnv,(M4NO_ERROR != result),
                            "Invalid File - DRM Protected ");
                } else {
                    // Check if the creation succeeded.
                    videoEditJava_checkAndThrowIllegalArgumentException(
                            &gotten, pEnv,(M4NO_ERROR != result),
                            "Invalid File or File not found ");
                }

#ifdef USE_SOFTWARE_DECODER
                /**
                 * Input clip with non-multiples of 16 is not supported.
                 */
                if ( (pClipProperties->uiVideoWidth %16)
                    || (pClipProperties->uiVideoHeight %16) )
                {
                    result = M4MCS_ERR_INPUT_VIDEO_SIZE_NON_X16;
                    videoEditJava_checkAndThrowIllegalArgumentException(
                            &gotten, pEnv, (M4NO_ERROR != result),
                            "non x16 input video frame size is not supported");
                }
#endif /* USE_SOFTWARE_DECODER */
            }

            // Check if the properties could be retrieved.
            if (gotten)
            {
                // Set the properties.
                pProperties->uiClipDuration = pClipProperties->uiClipDuration;
                if (M4VIDEOEDITING_kFileType_Unsupported == pClipProperties->FileType)
                {
                    pProperties->FileType        = VideoEditClasses_kFileType_Unsupported;
                }
                else
                {
                    pProperties->FileType        = fileType;
                }
                pProperties->VideoStreamType     = pClipProperties->VideoStreamType;
                pProperties->uiClipVideoDuration = pClipProperties->uiClipVideoDuration;
                pProperties->uiVideoBitrate      = pClipProperties->uiVideoBitrate;
                pProperties->uiVideoWidth        = pClipProperties->uiVideoWidth;
                pProperties->uiVideoHeight       = pClipProperties->uiVideoHeight;
                pProperties->fAverageFrameRate   = pClipProperties->fAverageFrameRate;
                pProperties->uiVideoProfile      = pClipProperties->uiVideoProfile;
                pProperties->uiVideoLevel        = pClipProperties->uiVideoLevel;
                // Set profile and level support to TRUE, pending check
                pProperties->bProfileSupported   = M4OSA_TRUE;
                pProperties->bLevelSupported     = M4OSA_TRUE;
                pProperties->AudioStreamType     = pClipProperties->AudioStreamType;
                pProperties->uiClipAudioDuration = pClipProperties->uiClipAudioDuration;
                pProperties->uiAudioBitrate      = pClipProperties->uiAudioBitrate;
                pProperties->uiNbChannels        = pClipProperties->uiNbChannels;
                pProperties->uiSamplingFrequency = pClipProperties->uiSamplingFrequency;
                pProperties->uiRotation          = pClipProperties->videoRotationDegrees;

            }

            // Free the clip properties.
            videoEditOsal_free(pClipProperties);
            pClipProperties = M4OSA_NULL;
        }
        else if ((VideoEditClasses_kFileType_JPG == fileType) ||
            (VideoEditClasses_kFileType_GIF == fileType) ||
            (VideoEditClasses_kFileType_PNG == fileType))
        {
            pProperties->uiClipDuration      = 0;
            pProperties->FileType            = fileType;
            pProperties->VideoStreamType     = M4VIDEOEDITING_kNoneVideo;
            pProperties->uiClipVideoDuration = 0;
            pProperties->uiVideoBitrate      = 0;
            pProperties->uiVideoWidth        = width;
            pProperties->uiVideoHeight       = height;
            pProperties->fAverageFrameRate   = 0.0f;
            pProperties->uiVideoProfile = M4VIDEOEDITING_VIDEO_UNKNOWN_PROFILE;
            pProperties->uiVideoLevel = M4VIDEOEDITING_VIDEO_UNKNOWN_LEVEL;
            pProperties->AudioStreamType     = M4VIDEOEDITING_kNoneAudio;
            pProperties->uiClipAudioDuration = 0;
            pProperties->uiAudioBitrate      = 0;
            pProperties->uiNbChannels        = 0;
            pProperties->uiSamplingFrequency = 0;

            // Added for Handling invalid paths and non existent image files
            // Open the file for reading.
            result = M4OSA_fileReadOpen(&context, (M4OSA_Void*)pFile, M4OSA_kFileRead);
            if (M4NO_ERROR != result)
            {
                pProperties->FileType = VideoEditClasses_kFileType_Unsupported;
            }
            result = M4OSA_fileReadClose(context);
            context = M4OSA_NULL;
        }
    }

    if (M4NO_ERROR == result) {
        // Create a properties object.
        videoEditPropClass_createProperties(&gotten, pEnv, pProperties, &properties);

        // Log the properties.
        VIDEOEDIT_PROP_LOG_PROPERTIES(pProperties);
    }

    // Free the properties.
    videoEditOsal_free(pProperties);
    pProperties = M4OSA_NULL;

    // Free the file path.
    videoEditOsal_free(pFile);
    pFile = M4OSA_NULL;

    // Add a text marker (the condition must always be true).
    ADD_TEXT_MARKER_FUN(NULL != pEnv)

    // Return the Properties object.
    return(properties);
}
static M4OSA_ERR getClipProperties(
        JNIEnv* pEnv,
        jobject thiz,
        M4OSA_Char* pFile,
        M4VIDEOEDITING_FileType clipType,
        M4VIDEOEDITING_ClipProperties* pClipProperties)
{
    bool                      gotten          = true;
    M4OSA_ERR                 result          = M4NO_ERROR;
    M4OSA_ERR                 resultAbort     = M4NO_ERROR;
    M4MCS_Context             context         = M4OSA_NULL;

    M4OSA_FileReadPointer fileReadPtr =
            { M4OSA_NULL, M4OSA_NULL, M4OSA_NULL,
              M4OSA_NULL, M4OSA_NULL, M4OSA_NULL };

    M4OSA_FileWriterPointer fileWritePtr =
            { M4OSA_NULL, M4OSA_NULL, M4OSA_NULL,
              M4OSA_NULL, M4OSA_NULL, M4OSA_NULL, M4OSA_NULL };

    // Initialize the OSAL file system function pointers.
    videoEditOsal_getFilePointers(&fileReadPtr , &fileWritePtr);

    // Log the API call.
    VIDEOEDIT_LOG_API(
            ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",\
            "getClipProperties - M4MCS_init()");

    // Initialize the MCS context.
    result = M4MCS_init(&context, &fileReadPtr, &fileWritePtr);

    // Log the result.
    VIDEOEDIT_PROP_LOG_RESULT(
            ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES", "%s",
            videoEditOsal_getResultString(result));

    // Check if the creation succeeded.
    videoEditJava_checkAndThrowRuntimeException(
            &gotten, pEnv, (M4NO_ERROR != result), result);

    // Check if opening the MCS context succeeded.
    if (gotten)
    {
        // Log the API call.
        VIDEOEDIT_LOG_API(
                ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
                "getClipProperties - M4MCS_open_normalMode()");

        // Open the MCS in the normal opening mode to
        // retrieve the exact duration
        result = M4MCS_open_normalMode(
                context, pFile, clipType, M4OSA_NULL, M4OSA_NULL);

        // Log the result.
        VIDEOEDIT_PROP_LOG_RESULT(
                ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES", "%s",
                videoEditOsal_getResultString(result));

        // Check if the creation succeeded.
        videoEditJava_checkAndThrowRuntimeException(
                &gotten, pEnv, (M4NO_ERROR != result), result);

        // Check if the MCS could be opened.
        if (gotten)
        {
            // Log the API call.
            VIDEOEDIT_LOG_API(
                    ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
                    "getClipProperties - M4MCS_getInputFileProperties()");

            // Get the properties.
            result = M4MCS_getInputFileProperties(context, pClipProperties);

            // Log the result.
            VIDEOEDIT_PROP_LOG_RESULT(
                    ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES", "%s",
                    videoEditOsal_getResultString(result));

            // Check if the creation succeeded.
            videoEditJava_checkAndThrowRuntimeException(
                    &gotten, pEnv, (M4NO_ERROR != result), result);
        }

        // Log the API call.
        VIDEOEDIT_LOG_API(
                ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
                "getClipProperties - M4MCS_abort()");

        // Close the MCS session.
        resultAbort = M4MCS_abort(context);

       if (result == M4NO_ERROR) {
            // Log the result.
            VIDEOEDIT_PROP_LOG_RESULT(
                    ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES", "%s",
                    videoEditOsal_getResultString(resultAbort));

            // Check if the abort succeeded.
            videoEditJava_checkAndThrowRuntimeException(
                    &gotten, pEnv, (M4NO_ERROR != resultAbort), resultAbort);
            result = resultAbort;
        }
    }

    return result;
}