/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_NDEBUG 1 #define LOG_TAG "VideoEditorMain" #include <dlfcn.h> #include <stdio.h> #include <unistd.h> #include <utils/Log.h> #include <utils/threads.h> #include <VideoEditorClasses.h> #include <VideoEditorJava.h> #include <VideoEditorOsal.h> #include <VideoEditorLogging.h> #include <marker.h> #include <VideoEditorClasses.h> #include <VideoEditorThumbnailMain.h> #include <M4OSA_Debug.h> #include <M4xVSS_Internal.h> #include <gui/Surface.h> #include "VideoEditorPreviewController.h" #include "VideoEditorMain.h" extern "C" { #include <M4OSA_Clock.h> #include <M4OSA_CharStar.h> #include <M4OSA_Error.h> #include <M4OSA_FileCommon.h> #include <M4OSA_FileReader.h> #include <M4OSA_FileWriter.h> #include <M4OSA_Memory.h> #include <M4OSA_Thread.h> #include <M4xVSS_API.h> #include <M4VSS3GPP_ErrorCodes.h> #include <M4MCS_API.h> #include <M4MCS_ErrorCodes.h> #include <M4READER_Common.h> #include <M4WRITER_common.h> }; using namespace android; #define THREAD_STACK_SIZE (65536) #define VIDEOEDITOR_VERSION_MAJOR 0 #define VIDEOEDITOR_VERSION_MINOR 0 #define VIDEOEDITOR_VERSION_REVISION 1 typedef enum { ManualEditState_NOT_INITIALIZED, ManualEditState_INITIALIZED, ManualEditState_ANALYZING, ManualEditState_ANALYZING_ERROR, ManualEditState_OPENED, ManualEditState_SAVING, ManualEditState_SAVING_ERROR, ManualEditState_SAVED, ManualEditState_STOPPING } ManualEditState; typedef struct { JavaVM* pVM; jobject engine; jmethodID onCompletionMethodId; jmethodID onErrorMethodId; jmethodID onWarningMethodId; jmethodID onProgressUpdateMethodId; jmethodID onPreviewProgressUpdateMethodId; jmethodID previewFrameEditInfoId; M4xVSS_InitParams initParams; void* pTextRendererHandle; M4xVSS_getTextRgbBufferFct pTextRendererFunction; M4OSA_Context engineContext; ManualEditState state; M4VSS3GPP_EditSettings* pEditSettings; M4OSA_Context threadContext; M4OSA_ERR threadResult; M4OSA_UInt8 threadProgress; VideoEditorPreviewController *mPreviewController; M4xVSS_AudioMixingSettings *mAudioSettings; /* Audio Graph changes */ M4OSA_Context pAudioGraphMCSCtx; M4OSA_Bool bSkipState; jmethodID onAudioGraphProgressUpdateMethodId; Mutex mLock; bool mIsUpdateOverlay; char *mOverlayFileName; int mOverlayRenderingMode; M4DECODER_VideoDecoders* decoders; } ManualEditContext; extern "C" M4OSA_ERR M4MCS_open_normalMode( M4MCS_Context pContext, M4OSA_Void* pFileIn, M4VIDEOEDITING_FileType InputFileType, M4OSA_Void* pFileOut, M4OSA_Void* pTempFile); static M4OSA_ERR videoEditor_toUTF8Fct( M4OSA_Void* pBufferIn, M4OSA_UInt8* pBufferOut, M4OSA_UInt32* bufferOutSize); static M4OSA_ERR videoEditor_fromUTF8Fct( M4OSA_UInt8* pBufferIn, M4OSA_Void* pBufferOut, M4OSA_UInt32* bufferOutSize); static M4OSA_ERR videoEditor_getTextRgbBufferFct( M4OSA_Void* pRenderingData, M4OSA_Void* pTextBuffer, M4OSA_UInt32 textBufferSize, M4VIFI_ImagePlane** pOutputPlane); static void videoEditor_callOnProgressUpdate( ManualEditContext* pContext, int task, int progress); static void videoEditor_freeContext( JNIEnv* pEnv, ManualEditContext** ppContext); static M4OSA_ERR videoEditor_threadProc( M4OSA_Void* param); static jobject videoEditor_getVersion( JNIEnv* pEnv, jobject thiz); static void videoEditor_init( JNIEnv* pEnv, jobject thiz, jstring tempPath, jstring textRendererPath); static void videoEditor_loadSettings( JNIEnv* pEnv, jobject thiz, jobject settings); static void videoEditor_unloadSettings( JNIEnv* pEnv, jobject thiz); static void videoEditor_stopEncoding( JNIEnv* pEnv, jobject thiz); static void videoEditor_release( JNIEnv* pEnv, jobject thiz); static int videoEditor_getPixels( JNIEnv* env, jobject thiz, jstring path, jintArray pixelArray, M4OSA_UInt32 width, M4OSA_UInt32 height, M4OSA_UInt32 timeMS); static int videoEditor_getPixelsList( JNIEnv* env, jobject thiz, jstring path, jintArray pixelArray, M4OSA_UInt32 width, M4OSA_UInt32 height, M4OSA_UInt32 noOfThumbnails, jlong startTime, jlong endTime, jintArray indexArray, jobject callback); static void videoEditor_startPreview( JNIEnv* pEnv, jobject thiz, jobject mSurface, jlong fromMs, jlong toMs, jint callbackInterval, jboolean loop); static void videoEditor_populateSettings( JNIEnv* pEnv, jobject thiz, jobject settings, jobject object, jobject audioSettingObject); static int videoEditor_stopPreview(JNIEnv* pEnv, jobject thiz); static jobject videoEditor_getProperties( JNIEnv* pEnv, jobject thiz, jstring file); static int videoEditor_renderPreviewFrame(JNIEnv* pEnv, jobject thiz, jobject mSurface, jlong fromMs, jint surfaceWidth, jint surfaceHeight); static int videoEditor_registerManualEditMethods( JNIEnv* pEnv); static void jniPreviewProgressCallback(void* cookie, M4OSA_UInt32 msgType, void *argc); static int videoEditor_renderMediaItemPreviewFrame(JNIEnv* pEnv, jobject thiz, jobject mSurface, jstring filePath, jint frameWidth, jint frameHeight, jint surfaceWidth, jint surfaceHeight, jlong fromMs); static int videoEditor_generateAudioWaveFormSync ( JNIEnv* pEnv, jobject thiz, jstring pcmfilePath, jstring outGraphfilePath, jint frameDuration, jint channels, jint samplesCount); static int videoEditor_generateAudioRawFile(JNIEnv* pEnv, jobject thiz, jstring infilePath, jstring pcmfilePath ); M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext, M4OSA_Char* infilePath, M4OSA_Char* pcmfilePath ); static int videoEditor_generateClip( JNIEnv* pEnv, jobject thiz, jobject settings); static void videoEditor_clearSurface(JNIEnv* pEnv, jobject thiz, jobject surface); static JNINativeMethod gManualEditMethods[] = { {"getVersion", "()L"VERSION_CLASS_NAME";", (void *)videoEditor_getVersion }, {"_init", "(Ljava/lang/String;Ljava/lang/String;)V", (void *)videoEditor_init }, {"nativeStartPreview", "(Landroid/view/Surface;JJIZ)V", (void *)videoEditor_startPreview }, {"nativePopulateSettings", "(L"EDIT_SETTINGS_CLASS_NAME";L"PREVIEW_PROPERTIES_CLASS_NAME";L" AUDIO_SETTINGS_CLASS_NAME";)V", (void *)videoEditor_populateSettings }, {"nativeRenderPreviewFrame", "(Landroid/view/Surface;JII)I", (int *)videoEditor_renderPreviewFrame }, {"nativeRenderMediaItemPreviewFrame", "(Landroid/view/Surface;Ljava/lang/String;IIIIJ)I", (int *)videoEditor_renderMediaItemPreviewFrame }, {"nativeStopPreview", "()I", (int *)videoEditor_stopPreview }, {"stopEncoding", "()V", (void *)videoEditor_stopEncoding }, {"release", "()V", (void *)videoEditor_release }, {"nativeGetPixels", "(Ljava/lang/String;[IIIJ)I", (void*)videoEditor_getPixels }, {"nativeGetPixelsList", "(Ljava/lang/String;[IIIIJJ[ILandroid/media/videoeditor/MediaArtistNativeHelper$NativeGetPixelsListCallback;)I", (void*)videoEditor_getPixelsList }, {"getMediaProperties", "(Ljava/lang/String;)Landroid/media/videoeditor/MediaArtistNativeHelper$Properties;", (void *)videoEditor_getProperties }, {"nativeGenerateAudioGraph","(Ljava/lang/String;Ljava/lang/String;III)I", (int *)videoEditor_generateAudioWaveFormSync }, {"nativeGenerateRawAudio", "(Ljava/lang/String;Ljava/lang/String;)I", (int *)videoEditor_generateAudioRawFile }, {"nativeGenerateClip", "(L"EDIT_SETTINGS_CLASS_NAME";)I", (void *)videoEditor_generateClip }, {"nativeClearSurface", "(Landroid/view/Surface;)V", (void *)videoEditor_clearSurface }, }; // temp file name of VSS out file #define TEMP_MCS_OUT_FILE_PATH "tmpOut.3gp" void getClipSetting( JNIEnv* pEnv, jobject object, M4VSS3GPP_ClipSettings* pSettings) { jfieldID fid; int field = 0; bool needToBeLoaded = true; jclass clazz = pEnv->FindClass(PROPERTIES_CLASS_NAME); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == clazz), "not initialized"); fid = pEnv->GetFieldID(clazz,"duration","I"); pSettings->ClipProperties.uiClipDuration = pEnv->GetIntField(object,fid); M4OSA_TRACE1_1("duration = %d",pSettings->ClipProperties.uiClipDuration); fid = pEnv->GetFieldID(clazz,"videoFormat","I"); pSettings->ClipProperties.VideoStreamType = (M4VIDEOEDITING_VideoFormat)pEnv->GetIntField(object,fid); M4OSA_TRACE1_1("videoFormat = %d",pSettings->ClipProperties.VideoStreamType); fid = pEnv->GetFieldID(clazz,"videoDuration","I"); pSettings->ClipProperties.uiClipVideoDuration = pEnv->GetIntField(object,fid); M4OSA_TRACE1_1("videoDuration = %d", pSettings->ClipProperties.uiClipVideoDuration); fid = pEnv->GetFieldID(clazz,"width","I"); pSettings->ClipProperties.uiVideoWidth = pEnv->GetIntField(object,fid); M4OSA_TRACE1_1("width = %d",pSettings->ClipProperties.uiVideoWidth); fid = pEnv->GetFieldID(clazz,"height","I"); pSettings->ClipProperties.uiVideoHeight = pEnv->GetIntField(object,fid); M4OSA_TRACE1_1("height = %d",pSettings->ClipProperties.uiVideoHeight); fid = pEnv->GetFieldID(clazz,"audioFormat","I"); pSettings->ClipProperties.AudioStreamType = (M4VIDEOEDITING_AudioFormat)pEnv->GetIntField(object,fid); M4OSA_TRACE1_1("audioFormat = %d",pSettings->ClipProperties.AudioStreamType); fid = pEnv->GetFieldID(clazz,"audioDuration","I"); pSettings->ClipProperties.uiClipAudioDuration = pEnv->GetIntField(object,fid); M4OSA_TRACE1_1("audioDuration = %d", pSettings->ClipProperties.uiClipAudioDuration); fid = pEnv->GetFieldID(clazz,"audioBitrate","I"); pSettings->ClipProperties.uiAudioBitrate = pEnv->GetIntField(object,fid); M4OSA_TRACE1_1("audioBitrate = %d",pSettings->ClipProperties.uiAudioBitrate); fid = pEnv->GetFieldID(clazz,"audioChannels","I"); pSettings->ClipProperties.uiNbChannels = pEnv->GetIntField(object,fid); M4OSA_TRACE1_1("audioChannels = %d",pSettings->ClipProperties.uiNbChannels); fid = pEnv->GetFieldID(clazz,"audioSamplingFrequency","I"); pSettings->ClipProperties.uiSamplingFrequency = pEnv->GetIntField(object,fid); M4OSA_TRACE1_1("audioSamplingFrequency = %d", pSettings->ClipProperties.uiSamplingFrequency); fid = pEnv->GetFieldID(clazz,"audioVolumeValue","I"); pSettings->ClipProperties.uiClipAudioVolumePercentage = pEnv->GetIntField(object,fid); M4OSA_TRACE1_1("audioVolumeValue = %d", pSettings->ClipProperties.uiClipAudioVolumePercentage); fid = pEnv->GetFieldID(clazz,"videoRotation","I"); pSettings->ClipProperties.videoRotationDegrees = pEnv->GetIntField(object,fid); M4OSA_TRACE1_1("videoRotation = %d", pSettings->ClipProperties.videoRotationDegrees); // Free the local references to avoid memory leaks pEnv->DeleteLocalRef(clazz); } static void jniPreviewProgressCallback (void* cookie, M4OSA_UInt32 msgType, void *argc) { ManualEditContext *pContext = (ManualEditContext *)cookie; JNIEnv* pEnv = NULL; bool isFinished = false; int currentMs = 0; int error = M4NO_ERROR; bool isUpdateOverlay = false; int overlayEffectIndex; char *extPos; bool isSendProgress = true; jstring tmpFileName; VideoEditorCurretEditInfo *pCurrEditInfo; // Attach the current thread. pContext->pVM->AttachCurrentThread(&pEnv, NULL); switch(msgType) { case MSG_TYPE_PROGRESS_INDICATION: currentMs = *(int*)argc; break; case MSG_TYPE_PLAYER_ERROR: currentMs = -1; error = *(int*)argc; break; case MSG_TYPE_PREVIEW_END: isFinished = true; break; case MSG_TYPE_OVERLAY_UPDATE: { int overlayFileNameLen = 0; isSendProgress = false; pContext->mIsUpdateOverlay = true; pCurrEditInfo = (VideoEditorCurretEditInfo*)argc; overlayEffectIndex = pCurrEditInfo->overlaySettingsIndex; ALOGV("MSG_TYPE_OVERLAY_UPDATE"); if (pContext->mOverlayFileName != NULL) { free(pContext->mOverlayFileName); pContext->mOverlayFileName = NULL; } overlayFileNameLen = strlen((const char*)pContext->pEditSettings->Effects[overlayEffectIndex].xVSS.pFramingFilePath); pContext->mOverlayFileName = (char*)M4OSA_32bitAlignedMalloc(overlayFileNameLen+1, M4VS, (M4OSA_Char*)"videoEdito JNI overlayFile"); if (pContext->mOverlayFileName != NULL) { strncpy (pContext->mOverlayFileName, (const char*)pContext->pEditSettings->\ Effects[overlayEffectIndex].xVSS.pFramingFilePath, overlayFileNameLen); //Change the name to png file extPos = strstr(pContext->mOverlayFileName, ".rgb"); if (extPos != NULL) { *extPos = '\0'; } else { ALOGE("ERROR the overlay file is incorrect"); } strcat(pContext->mOverlayFileName, ".png"); ALOGV("Conv string is %s", pContext->mOverlayFileName); ALOGV("Current Clip index = %d", pCurrEditInfo->clipIndex); pContext->mOverlayRenderingMode = pContext->pEditSettings->\ pClipList[pCurrEditInfo->clipIndex]->xVSS.MediaRendering; ALOGV("rendering mode %d ", pContext->mOverlayRenderingMode); } break; } case MSG_TYPE_OVERLAY_CLEAR: isSendProgress = false; if (pContext->mOverlayFileName != NULL) { free(pContext->mOverlayFileName); pContext->mOverlayFileName = NULL; } ALOGV("MSG_TYPE_OVERLAY_CLEAR"); //argc is not used pContext->mIsUpdateOverlay = true; break; default: break; } if (isSendProgress) { tmpFileName = pEnv->NewStringUTF(pContext->mOverlayFileName); pEnv->CallVoidMethod(pContext->engine, pContext->onPreviewProgressUpdateMethodId, currentMs,isFinished, pContext->mIsUpdateOverlay, tmpFileName, pContext->mOverlayRenderingMode, error); if (pContext->mIsUpdateOverlay) { pContext->mIsUpdateOverlay = false; } if (tmpFileName) { pEnv->DeleteLocalRef(tmpFileName); } } // Detach the current thread. pContext->pVM->DetachCurrentThread(); } static M4OSA_ERR checkClipVideoProfileAndLevel(M4DECODER_VideoDecoders *pDecoders, M4OSA_Int32 format, M4OSA_UInt32 profile, M4OSA_UInt32 level){ M4OSA_Int32 codec = 0; M4OSA_Bool foundCodec = M4OSA_FALSE; M4OSA_ERR result = M4VSS3GPP_ERR_EDITING_UNSUPPORTED_VIDEO_PROFILE; M4OSA_Bool foundProfile = M4OSA_FALSE; ALOGV("checkClipVideoProfileAndLevel format %d profile;%d level:0x%x", format, profile, level); switch (format) { case M4VIDEOEDITING_kH263: codec = M4DA_StreamTypeVideoH263; break; case M4VIDEOEDITING_kH264: codec = M4DA_StreamTypeVideoMpeg4Avc; break; case M4VIDEOEDITING_kMPEG4: codec = M4DA_StreamTypeVideoMpeg4; break; case M4VIDEOEDITING_kNoneVideo: case M4VIDEOEDITING_kNullVideo: case M4VIDEOEDITING_kUnsupportedVideo: // For these case we do not check the profile and level return M4NO_ERROR; default : ALOGE("checkClipVideoProfileAndLevel unsupport Video format %ld", format); break; } if (pDecoders != M4OSA_NULL && pDecoders->decoderNumber > 0) { VideoDecoder *pVideoDecoder = pDecoders->decoder; for(size_t k =0; k < pDecoders->decoderNumber; k++) { if (pVideoDecoder != M4OSA_NULL) { if (pVideoDecoder->codec == codec) { foundCodec = M4OSA_TRUE; break; } } pVideoDecoder++; } if (foundCodec) { VideoComponentCapabilities* pComponent = pVideoDecoder->component; for (size_t i = 0; i < pVideoDecoder->componentNumber; i++) { if (pComponent != M4OSA_NULL) { VideoProfileLevel *pProfileLevel = pComponent->profileLevel; for (size_t j =0; j < pComponent->profileNumber; j++) { // Check the profile and level if (pProfileLevel != M4OSA_NULL) { if (profile == pProfileLevel->mProfile) { foundProfile = M4OSA_TRUE; if (level <= pProfileLevel->mLevel) { return M4NO_ERROR; } } else { foundProfile = M4OSA_FALSE; } } pProfileLevel++; } } pComponent++; } } } if (foundProfile) { result = M4VSS3GPP_ERR_EDITING_UNSUPPORTED_VIDEO_LEVEL; } else { result = M4VSS3GPP_ERR_EDITING_UNSUPPORTED_VIDEO_PROFILE; } return result; } static int videoEditor_stopPreview(JNIEnv* pEnv, jobject thiz) { ManualEditContext* pContext = M4OSA_NULL; bool needToBeLoaded = true; M4OSA_UInt32 lastProgressTimeMs = 0; // Get the context. pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz); // Make sure that the context was set. videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == pContext), "not initialized"); lastProgressTimeMs = pContext->mPreviewController->stopPreview(); if (pContext->mOverlayFileName != NULL) { free(pContext->mOverlayFileName); pContext->mOverlayFileName = NULL; } return lastProgressTimeMs; } static void videoEditor_clearSurface(JNIEnv* pEnv, jobject thiz, jobject surface) { bool needToBeLoaded = true; M4OSA_ERR result = M4NO_ERROR; VideoEditor_renderPreviewFrameStr frameStr; const char* pMessage = NULL; // Let the size be QVGA int width = 320; int height = 240; ManualEditContext* pContext = M4OSA_NULL; // Get the context. pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz); VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR","pContext = 0x%x",pContext); // Make sure that the context was set. videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == pContext), "not initialized"); // Make sure that the context was set. videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == pContext->mPreviewController), "not initialized"); // Validate the surface parameter. videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv, (NULL == surface), "surface is null"); jclass surfaceClass = pEnv->FindClass("android/view/Surface"); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == surfaceClass), "not initialized"); jfieldID surface_native = pEnv->GetFieldID(surfaceClass, ANDROID_VIEW_SURFACE_JNI_ID, "I"); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == surface_native), "not initialized"); Surface* const p = (Surface*)pEnv->GetIntField(surface, surface_native); sp<Surface> previewSurface = sp<Surface>(p); // Validate the mSurface's mNativeSurface field videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (NULL == previewSurface.get()), "mNativeSurface is null"); frameStr.pBuffer = M4OSA_NULL; frameStr.timeMs = 0; frameStr.uiSurfaceWidth = width; frameStr.uiSurfaceHeight = height; frameStr.uiFrameWidth = width; frameStr.uiFrameHeight = height; frameStr.bApplyEffect = M4OSA_FALSE; frameStr.clipBeginCutTime = 0; frameStr.clipEndCutTime = 0; result = pContext->mPreviewController->clearSurface(previewSurface, &frameStr); videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, (M4NO_ERROR != result), result); } static int videoEditor_renderPreviewFrame(JNIEnv* pEnv, jobject thiz, jobject mSurface, jlong fromMs, jint surfaceWidth, jint surfaceHeight ) { bool needToBeLoaded = true; M4OSA_ERR result = M4NO_ERROR; M4OSA_UInt32 timeMs = (M4OSA_UInt32)fromMs; M4OSA_UInt32 i=0,tnTimeMs = 0, framesizeYuv =0; M4VIFI_UInt8 *pixelArray = M4OSA_NULL; M4OSA_UInt32 iCurrentClipIndex = 0, uiNumberOfClipsInStoryBoard =0, uiClipDuration = 0, uiTotalClipDuration = 0, iIncrementedDuration = 0; VideoEditor_renderPreviewFrameStr frameStr; M4OSA_Context tnContext = M4OSA_NULL; const char* pMessage = NULL; M4VIFI_ImagePlane *yuvPlane = NULL; VideoEditorCurretEditInfo currEditInfo; VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "surfaceWidth = %d",surfaceWidth); VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "surfaceHeight = %d",surfaceHeight); ManualEditContext* pContext = M4OSA_NULL; // Get the context. pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz); VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR","pContext = 0x%x",pContext); // Make sure that the context was set. videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == pContext), "not initialized"); // Make sure that the context was set. videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == pContext->mPreviewController), "not initialized"); // Validate the mSurface parameter. videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv, (NULL == mSurface), "mSurface is null"); jclass surfaceClass = pEnv->FindClass("android/view/Surface"); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == surfaceClass), "not initialized"); jfieldID surface_native = pEnv->GetFieldID(surfaceClass, ANDROID_VIEW_SURFACE_JNI_ID, "I"); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == surface_native), "not initialized"); Surface* const p = (Surface*)pEnv->GetIntField(mSurface, surface_native); sp<Surface> previewSurface = sp<Surface>(p); // Validate the mSurface's mNativeSurface field videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (NULL == previewSurface.get()), "mNativeSurface is null"); /* Determine the total number of clips, total duration*/ uiNumberOfClipsInStoryBoard = pContext->pEditSettings->uiClipNumber; for (i = 0; i < uiNumberOfClipsInStoryBoard; i++) { uiClipDuration = pContext->pEditSettings->pClipList[i]->uiEndCutTime - pContext->pEditSettings->pClipList[i]->uiBeginCutTime; uiTotalClipDuration += uiClipDuration; } /* determine the clip whose thumbnail needs to be rendered*/ if (timeMs == 0) { iCurrentClipIndex = 0; i=0; } else { VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_renderPreviewFrame() timeMs=%d", timeMs); if (timeMs > uiTotalClipDuration) { VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_renderPreviewFrame() timeMs > uiTotalClipDuration"); pMessage = videoEditJava_getErrorName(M4ERR_PARAMETER); jniThrowException(pEnv, "java/lang/IllegalArgumentException", pMessage); return -1; } for (i = 0; i < uiNumberOfClipsInStoryBoard; i++) { if (timeMs <= (iIncrementedDuration + (pContext->pEditSettings->pClipList[i]->uiEndCutTime - pContext->pEditSettings->pClipList[i]->uiBeginCutTime))) { iCurrentClipIndex = i; VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_renderPreviewFrame() iCurrentClipIndex=%d for timeMs=%d", iCurrentClipIndex, timeMs); break; } else { iIncrementedDuration = iIncrementedDuration + (pContext->pEditSettings->pClipList[i]->uiEndCutTime - pContext->pEditSettings->pClipList[i]->uiBeginCutTime); } } } /* If timestamp is beyond story board duration, return*/ if (i >= uiNumberOfClipsInStoryBoard) { if (timeMs == iIncrementedDuration) { iCurrentClipIndex = i-1; } else { return -1; } } /*+ Handle the image files here */ if (pContext->pEditSettings->pClipList[iCurrentClipIndex]->FileType == /*M4VIDEOEDITING_kFileType_JPG*/ M4VIDEOEDITING_kFileType_ARGB8888 ) { VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", " iCurrentClipIndex %d ", iCurrentClipIndex); VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", " Height = %d", pContext->pEditSettings->pClipList[iCurrentClipIndex]->ClipProperties.uiVideoHeight); VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", " Width = %d", pContext->pEditSettings->pClipList[iCurrentClipIndex]->ClipProperties.uiVideoWidth); LvGetImageThumbNail((const char *)pContext->pEditSettings->\ pClipList[iCurrentClipIndex]->pFile, pContext->pEditSettings->pClipList[iCurrentClipIndex]->ClipProperties.uiVideoHeight, pContext->pEditSettings->pClipList[iCurrentClipIndex]->ClipProperties.uiVideoWidth, (M4OSA_Void **)&frameStr.pBuffer); tnTimeMs = (M4OSA_UInt32)timeMs; frameStr.videoRotationDegree = 0; } else { /* Handle 3gp/mp4 Clips here */ /* get thumbnail*/ result = ThumbnailOpen(&tnContext, (const M4OSA_Char*)pContext->pEditSettings->\ pClipList[iCurrentClipIndex]->pFile, M4OSA_TRUE); if (result != M4NO_ERROR || tnContext == M4OSA_NULL) { return -1; } /* timeMs is relative to storyboard; in this api it shud be relative to this clip */ if ((i >= uiNumberOfClipsInStoryBoard) && (timeMs == iIncrementedDuration)) { tnTimeMs = pContext->pEditSettings->\ pClipList[iCurrentClipIndex]->uiEndCutTime; } else { tnTimeMs = pContext->pEditSettings->\ pClipList[iCurrentClipIndex]->uiBeginCutTime + (timeMs - iIncrementedDuration); } VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "video width = %d",pContext->pEditSettings->pClipList[iCurrentClipIndex]->\ ClipProperties.uiVideoWidth); VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "video height = %d",pContext->pEditSettings->pClipList[iCurrentClipIndex]->\ ClipProperties.uiVideoHeight); VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "current clip index = %d",iCurrentClipIndex); M4OSA_UInt32 width = pContext->pEditSettings->pClipList[iCurrentClipIndex]->\ ClipProperties.uiVideoWidth; M4OSA_UInt32 height = pContext->pEditSettings->pClipList[iCurrentClipIndex]->\ ClipProperties.uiVideoHeight; framesizeYuv = width * height * 1.5; pixelArray = (M4VIFI_UInt8 *)M4OSA_32bitAlignedMalloc(framesizeYuv, M4VS, (M4OSA_Char*)"videoEditor pixelArray"); if (pixelArray == M4OSA_NULL) { VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_renderPreviewFrame() malloc error"); ThumbnailClose(tnContext); pMessage = videoEditJava_getErrorName(M4ERR_ALLOC); jniThrowException(pEnv, "java/lang/RuntimeException", pMessage); return -1; } result = ThumbnailGetPixels16(tnContext, (M4OSA_Int16 *)pixelArray, pContext->pEditSettings->pClipList[iCurrentClipIndex]->\ ClipProperties.uiVideoWidth, pContext->pEditSettings->pClipList[iCurrentClipIndex]->\ ClipProperties.uiVideoHeight, &tnTimeMs, 0); if (result != M4NO_ERROR) { free(pixelArray); ThumbnailClose(tnContext); return -1; } ThumbnailClose(tnContext); tnContext = M4OSA_NULL; #ifdef DUMPTOFILE { M4OSA_Context fileContext; M4OSA_Char* fileName = (M4OSA_Char*)"/mnt/sdcard/FirstRGB565.raw"; remove((const char *)fileName); M4OSA_fileWriteOpen(&fileContext, (M4OSA_Void*) fileName,\ M4OSA_kFileWrite|M4OSA_kFileCreate); M4OSA_fileWriteData(fileContext, (M4OSA_MemAddr8) pixelArray, framesizeYuv); M4OSA_fileWriteClose(fileContext); } #endif /** * Allocate output YUV planes */ yuvPlane = (M4VIFI_ImagePlane*)M4OSA_32bitAlignedMalloc(3*sizeof(M4VIFI_ImagePlane), M4VS, (M4OSA_Char*)"videoEditor_renderPreviewFrame Output plane YUV"); if (yuvPlane == M4OSA_NULL) { VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_renderPreviewFrame() malloc error for yuv plane"); free(pixelArray); pMessage = videoEditJava_getErrorName(M4ERR_ALLOC); jniThrowException(pEnv, "java/lang/RuntimeException", pMessage); return -1; } yuvPlane[0].u_width = width; yuvPlane[0].u_height = height; yuvPlane[0].u_topleft = 0; yuvPlane[0].u_stride = width; yuvPlane[0].pac_data = (M4VIFI_UInt8*)pixelArray; yuvPlane[1].u_width = width>>1; yuvPlane[1].u_height = height>>1; yuvPlane[1].u_topleft = 0; yuvPlane[1].u_stride = width>>1; yuvPlane[1].pac_data = yuvPlane[0].pac_data + yuvPlane[0].u_width * yuvPlane[0].u_height; yuvPlane[2].u_width = (width)>>1; yuvPlane[2].u_height = (height)>>1; yuvPlane[2].u_topleft = 0; yuvPlane[2].u_stride = (width)>>1; yuvPlane[2].pac_data = yuvPlane[1].pac_data + yuvPlane[1].u_width * yuvPlane[1].u_height; #ifdef DUMPTOFILE { M4OSA_Context fileContext; M4OSA_Char* fileName = (M4OSA_Char*)"/mnt/sdcard/ConvertedYuv.yuv"; remove((const char *)fileName); M4OSA_fileWriteOpen(&fileContext, (M4OSA_Void*) fileName,\ M4OSA_kFileWrite|M4OSA_kFileCreate); M4OSA_fileWriteData(fileContext, (M4OSA_MemAddr8) yuvPlane[0].pac_data, framesizeYuv); M4OSA_fileWriteClose(fileContext); } #endif /* Fill up the render structure*/ frameStr.pBuffer = (M4OSA_Void*)yuvPlane[0].pac_data; frameStr.videoRotationDegree = pContext->pEditSettings->\ pClipList[iCurrentClipIndex]->ClipProperties.videoRotationDegrees; } frameStr.timeMs = timeMs; /* timestamp on storyboard*/ frameStr.uiSurfaceWidth = pContext->pEditSettings->pClipList[iCurrentClipIndex]->\ ClipProperties.uiVideoWidth; frameStr.uiSurfaceHeight = pContext->pEditSettings->pClipList[iCurrentClipIndex]->\ ClipProperties.uiVideoHeight; frameStr.uiFrameWidth = pContext->pEditSettings->pClipList[iCurrentClipIndex]->\ ClipProperties.uiVideoWidth; frameStr.uiFrameHeight = pContext->pEditSettings->pClipList[iCurrentClipIndex]->\ ClipProperties.uiVideoHeight; if (pContext->pEditSettings->nbEffects > 0) { frameStr.bApplyEffect = M4OSA_TRUE; } else { frameStr.bApplyEffect = M4OSA_FALSE; } frameStr.clipBeginCutTime = iIncrementedDuration; frameStr.clipEndCutTime = iIncrementedDuration + (pContext->pEditSettings->pClipList[iCurrentClipIndex]->uiEndCutTime -\ pContext->pEditSettings->pClipList[iCurrentClipIndex]->uiBeginCutTime); pContext->mPreviewController->setPreviewFrameRenderingMode( pContext->pEditSettings->\ pClipList[iCurrentClipIndex]->xVSS.MediaRendering, pContext->pEditSettings->xVSS.outputVideoSize); result = pContext->mPreviewController->renderPreviewFrame(previewSurface, &frameStr, &currEditInfo); if (currEditInfo.overlaySettingsIndex != -1) { char tmpOverlayFilename[100]; char *extPos = NULL; jstring tmpOverlayString; int tmpRenderingMode = 0; strncpy (tmpOverlayFilename, (const char*)pContext->pEditSettings->Effects[currEditInfo.overlaySettingsIndex].xVSS.pFramingFilePath, 99); //Change the name to png file extPos = strstr(tmpOverlayFilename, ".rgb"); if (extPos != NULL) { *extPos = '\0'; } else { ALOGE("ERROR the overlay file is incorrect"); } strcat(tmpOverlayFilename, ".png"); tmpRenderingMode = pContext->pEditSettings->pClipList[iCurrentClipIndex]->xVSS.MediaRendering; tmpOverlayString = pEnv->NewStringUTF(tmpOverlayFilename); pEnv->CallVoidMethod(pContext->engine, pContext->previewFrameEditInfoId, tmpOverlayString, tmpRenderingMode); } videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, (M4NO_ERROR != result), result); free(frameStr.pBuffer); if (pContext->pEditSettings->pClipList[iCurrentClipIndex]->FileType != M4VIDEOEDITING_kFileType_ARGB8888) { free(yuvPlane); } return tnTimeMs; } static int videoEditor_renderMediaItemPreviewFrame(JNIEnv* pEnv, jobject thiz, jobject mSurface, jstring filePath, jint frameWidth, jint frameHeight, jint surfaceWidth, jint surfaceHeight, jlong fromMs) { bool needToBeLoaded = true; M4OSA_ERR result = M4NO_ERROR; M4OSA_UInt32 timeMs = (M4OSA_UInt32)fromMs; M4OSA_UInt32 framesizeYuv =0; M4VIFI_UInt8 *pixelArray = M4OSA_NULL; VideoEditor_renderPreviewFrameStr frameStr; M4OSA_Context tnContext = M4OSA_NULL; const char* pMessage = NULL; M4VIFI_ImagePlane yuvPlane[3], rgbPlane; ManualEditContext* pContext = M4OSA_NULL; // Get the context. pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz); // Make sure that the context was set. videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == pContext), "not initialized"); // Make sure that the context was set. videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == pContext->mPreviewController), "not initialized"); // Validate the mSurface parameter. videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv, (NULL == mSurface), "mSurface is null"); jclass surfaceClass = pEnv->FindClass("android/view/Surface"); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == surfaceClass), "not initialized"); jfieldID surface_native = pEnv->GetFieldID(surfaceClass, ANDROID_VIEW_SURFACE_JNI_ID, "I"); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == surface_native), "not initialized"); Surface* const p = (Surface*)pEnv->GetIntField(mSurface, surface_native); sp<Surface> previewSurface = sp<Surface>(p); const char *pString = pEnv->GetStringUTFChars(filePath, NULL); if (pString == M4OSA_NULL) { if (pEnv != NULL) { jniThrowException(pEnv, "java/lang/RuntimeException", "Input string null"); } } VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_renderMediaItemPreviewFrame() timeMs=%d", timeMs); /* get thumbnail*/ result = ThumbnailOpen(&tnContext,(const M4OSA_Char*)pString, M4OSA_TRUE); if (result != M4NO_ERROR || tnContext == M4OSA_NULL) { return timeMs; } framesizeYuv = ((frameWidth)*(frameHeight)*1.5); pixelArray = (M4VIFI_UInt8 *)M4OSA_32bitAlignedMalloc(framesizeYuv, M4VS,\ (M4OSA_Char*)"videoEditor pixelArray"); if (pixelArray == M4OSA_NULL) { VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_renderPreviewFrame() malloc error"); ThumbnailClose(tnContext); pMessage = videoEditJava_getErrorName(M4ERR_ALLOC); jniThrowException(pEnv, "java/lang/RuntimeException", pMessage); return timeMs; } result = ThumbnailGetPixels16(tnContext, (M4OSA_Int16 *)pixelArray, frameWidth, frameHeight, &timeMs, 0); if (result != M4NO_ERROR) { free(pixelArray); ThumbnailClose(tnContext); return fromMs; } #ifdef DUMPTOFILESYSTEM { M4OSA_Context fileContext; M4OSA_Char* fileName = (M4OSA_Char*)"/mnt/sdcard/FirstRGB565.rgb"; M4OSA_fileWriteOpen(&fileContext, (M4OSA_Void*) fileName,\ M4OSA_kFileWrite|M4OSA_kFileCreate); M4OSA_fileWriteData(fileContext, (M4OSA_MemAddr8) pixelArray, framesizeRgb); M4OSA_fileWriteClose(fileContext); } #endif yuvPlane[0].pac_data = (M4VIFI_UInt8*)pixelArray; yuvPlane[0].u_height = frameHeight; yuvPlane[0].u_width = frameWidth; yuvPlane[0].u_stride = yuvPlane[0].u_width; yuvPlane[0].u_topleft = 0; yuvPlane[1].u_height = frameHeight/2; yuvPlane[1].u_width = frameWidth/2; yuvPlane[1].u_stride = yuvPlane[1].u_width; yuvPlane[1].u_topleft = 0; yuvPlane[1].pac_data = yuvPlane[0].pac_data + yuvPlane[0].u_width*yuvPlane[0].u_height; yuvPlane[2].u_height = frameHeight/2; yuvPlane[2].u_width = frameWidth/2; yuvPlane[2].u_stride = yuvPlane[2].u_width; yuvPlane[2].u_topleft = 0; yuvPlane[2].pac_data = yuvPlane[0].pac_data + yuvPlane[0].u_width*yuvPlane[0].u_height + \ (yuvPlane[0].u_width/2)*(yuvPlane[0].u_height/2); #ifdef DUMPTOFILESYSTEM { M4OSA_Context fileContext; M4OSA_Char* fileName = (M4OSA_Char*)"/mnt/sdcard/ConvertedYuv.yuv"; M4OSA_fileWriteOpen(&fileContext, (M4OSA_Void*) fileName,\ M4OSA_kFileWrite|M4OSA_kFileCreate); M4OSA_fileWriteData(fileContext, (M4OSA_MemAddr8) yuvPlane[0].pac_data, framesizeYuv); M4OSA_fileWriteClose(fileContext); } #endif /* Fill up the render structure*/ frameStr.pBuffer = (M4OSA_Void*)yuvPlane[0].pac_data; frameStr.timeMs = timeMs; /* timestamp on storyboard*/ frameStr.uiSurfaceWidth = frameWidth; frameStr.uiSurfaceHeight = frameHeight; frameStr.uiFrameWidth = frameWidth; frameStr.uiFrameHeight = frameHeight; frameStr.bApplyEffect = M4OSA_FALSE; // clip begin cuttime and end cuttime set to 0 // as its only required when effect needs to be applied while rendering frameStr.clipBeginCutTime = 0; frameStr.clipEndCutTime = 0; /* pContext->mPreviewController->setPreviewFrameRenderingMode(M4xVSS_kBlackBorders, (M4VIDEOEDITING_VideoFrameSize)(M4VIDEOEDITING_kHD960+1));*/ result = pContext->mPreviewController->renderPreviewFrame(previewSurface,&frameStr, NULL); videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, (M4NO_ERROR != result), result); /* free the pixelArray and yuvPlane[0].pac_data */ free(yuvPlane[0].pac_data); ThumbnailClose(tnContext); if (pString != NULL) { pEnv->ReleaseStringUTFChars(filePath, pString); } return timeMs; } int videoEditor_generateAudioRawFile( JNIEnv* pEnv, jobject thiz, jstring infilePath, jstring pcmfilePath) { M4OSA_ERR result = M4NO_ERROR; bool loaded = true; ManualEditContext* pContext = M4OSA_NULL; const char *pInputFile = pEnv->GetStringUTFChars(infilePath, NULL); if (pInputFile == M4OSA_NULL) { if (pEnv != NULL) { jniThrowException(pEnv, "java/lang/RuntimeException", "Input string null"); } } const char *pStringOutPCMFilePath = pEnv->GetStringUTFChars(pcmfilePath, NULL); if (pStringOutPCMFilePath == M4OSA_NULL) { if (pEnv != NULL) { jniThrowException(pEnv, "java/lang/RuntimeException", "Input string null"); } } VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_generateAudioRawFile infilePath %s", pInputFile); VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_generateAudioRawFile pcmfilePath %s", pStringOutPCMFilePath); // Get the context. pContext = (ManualEditContext*)videoEditClasses_getContext(&loaded, pEnv, thiz); result = videoEditor_generateAudio( pEnv, pContext, (M4OSA_Char*)pInputFile, (M4OSA_Char*)pStringOutPCMFilePath); if (pInputFile != NULL) { pEnv->ReleaseStringUTFChars(infilePath, pInputFile); } if (pStringOutPCMFilePath != NULL) { pEnv->ReleaseStringUTFChars(pcmfilePath, pStringOutPCMFilePath); } return result; } M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext, M4OSA_Char* infilePath, M4OSA_Char* pcmfilePath ) { bool needToBeLoaded = true; M4OSA_ERR result = M4NO_ERROR; M4MCS_Context mcsContext = M4OSA_NULL; M4OSA_Char* pInputFile = M4OSA_NULL; M4OSA_Char* pOutputFile = M4OSA_NULL; M4OSA_Char* pTempPath = M4OSA_NULL; M4MCS_OutputParams* pOutputParams = M4OSA_NULL; M4MCS_EncodingParams* pEncodingParams = M4OSA_NULL; M4OSA_Int32 pInputFileType = 0; M4OSA_UInt8 threadProgress = 0; M4OSA_Char* pTemp3gpFilePath = M4OSA_NULL; VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_generateAudio()"); videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv, (NULL == pContext), "ManualEditContext is null"); VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_init()"); pOutputParams = (M4MCS_OutputParams *)M4OSA_32bitAlignedMalloc( sizeof(M4MCS_OutputParams),0x00, (M4OSA_Char *)"M4MCS_OutputParams"); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == pOutputParams), "not initialized"); if (needToBeLoaded == false) { return M4ERR_ALLOC; } pEncodingParams = (M4MCS_EncodingParams *)M4OSA_32bitAlignedMalloc( sizeof(M4MCS_EncodingParams),0x00, (M4OSA_Char *)"M4MCS_EncodingParams"); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == pEncodingParams), "not initialized"); if (needToBeLoaded == false) { free(pEncodingParams); pEncodingParams = M4OSA_NULL; return M4ERR_ALLOC; } // Initialize the MCS library. result = M4MCS_init(&mcsContext, pContext->initParams.pFileReadPtr, pContext->initParams.pFileWritePtr); videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,\ (M4NO_ERROR != result), result); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == mcsContext), "not initialized"); if(needToBeLoaded == false) { free(pOutputParams); pOutputParams = M4OSA_NULL; free(pEncodingParams); pEncodingParams = M4OSA_NULL; return result; } // generate the path for temp 3gp output file pTemp3gpFilePath = (M4OSA_Char*) M4OSA_32bitAlignedMalloc ( (strlen((const char*)pContext->initParams.pTempPath) + strlen((const char*)TEMP_MCS_OUT_FILE_PATH)) + 1 /* for null termination */ , 0x0, (M4OSA_Char*)"Malloc for temp 3gp file"); if (pTemp3gpFilePath != M4OSA_NULL) { memset((void *)pTemp3gpFilePath ,0, strlen((const char*)pContext->initParams.pTempPath) + strlen((const char*)TEMP_MCS_OUT_FILE_PATH) + 1); strncat((char *)pTemp3gpFilePath, (const char *)pContext->initParams.pTempPath , (size_t) ((M4OSA_Char*)pContext->initParams.pTempPath)); strncat((char *)pTemp3gpFilePath , (const char *)TEMP_MCS_OUT_FILE_PATH, (size_t)strlen ((const char*)TEMP_MCS_OUT_FILE_PATH)); } else { M4MCS_abort(mcsContext); free(pOutputParams); pOutputParams = M4OSA_NULL; free(pEncodingParams); pEncodingParams = M4OSA_NULL; return M4ERR_ALLOC; } pInputFile = (M4OSA_Char *) infilePath; //pContext->mAudioSettings->pFile; //Delete this file later pOutputFile = (M4OSA_Char *) pTemp3gpFilePath; // Temp folder path for VSS use = ProjectPath pTempPath = (M4OSA_Char *) pContext->initParams.pTempPath; pInputFileType = (M4VIDEOEDITING_FileType)pContext->mAudioSettings->fileType; VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "TEMP_MCS_OUT_FILE_PATH len %d", strlen ((const char*)TEMP_MCS_OUT_FILE_PATH)); VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "pTemp3gpFilePath %s", pOutputFile); VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_open()"); result = M4MCS_open(mcsContext, pInputFile, (M4VIDEOEDITING_FileType)pInputFileType, pOutputFile, pTempPath); videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, (M4NO_ERROR != result), result); if(needToBeLoaded == false) { free(pTemp3gpFilePath); pTemp3gpFilePath = M4OSA_NULL; M4MCS_abort(mcsContext); free(pOutputParams); pOutputParams = M4OSA_NULL; free(pEncodingParams); pEncodingParams = M4OSA_NULL; return result; } pOutputParams->OutputFileType = (M4VIDEOEDITING_FileType)M4VIDEOEDITING_kFileType_3GPP; // Set the video format. pOutputParams->OutputVideoFormat = (M4VIDEOEDITING_VideoFormat)M4VIDEOEDITING_kNoneVideo;//M4VIDEOEDITING_kNoneVideo; pOutputParams->outputVideoProfile = 1; pOutputParams->outputVideoLevel = 1; // Set the frame size. pOutputParams->OutputVideoFrameSize = (M4VIDEOEDITING_VideoFrameSize)M4VIDEOEDITING_kQCIF; // Set the frame rate. pOutputParams->OutputVideoFrameRate = (M4VIDEOEDITING_VideoFramerate)M4VIDEOEDITING_k5_FPS; // Set the audio format. pOutputParams->OutputAudioFormat = (M4VIDEOEDITING_AudioFormat)M4VIDEOEDITING_kAAC; // Set the audio sampling frequency. pOutputParams->OutputAudioSamplingFrequency = (M4VIDEOEDITING_AudioSamplingFrequency)M4VIDEOEDITING_k32000_ASF; // Set the audio mono. pOutputParams->bAudioMono = false; // Set the pcm file; null for now. pOutputParams->pOutputPCMfile = (M4OSA_Char *)pcmfilePath; //(M4OSA_Char *)"/sdcard/Output/AudioPcm.pcm"; // Set the audio sampling frequency. pOutputParams->MediaRendering = (M4MCS_MediaRendering)M4MCS_kCropping; // new params after integrating MCS 2.0 // Set the number of audio effects; 0 for now. pOutputParams->nbEffects = 0; // Set the audio effect; null for now. pOutputParams->pEffects = NULL; // Set the audio effect; null for now. pOutputParams->bDiscardExif = M4OSA_FALSE; // Set the audio effect; null for now. pOutputParams->bAdjustOrientation = M4OSA_FALSE; VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_setOutputParams()"); result = M4MCS_setOutputParams(mcsContext, pOutputParams); videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, (M4NO_ERROR != result), result); if (needToBeLoaded == false) { free(pTemp3gpFilePath); pTemp3gpFilePath = M4OSA_NULL; M4MCS_abort(mcsContext); free(pOutputParams); pOutputParams = M4OSA_NULL; free(pEncodingParams); pEncodingParams = M4OSA_NULL; return result; } // Set the video bitrate. pEncodingParams->OutputVideoBitrate = (M4VIDEOEDITING_Bitrate)M4VIDEOEDITING_kUndefinedBitrate; // Set the audio bitrate. pEncodingParams->OutputAudioBitrate = (M4VIDEOEDITING_Bitrate)M4VIDEOEDITING_k128_KBPS; // Set the end cut time in milliseconds. pEncodingParams->BeginCutTime = 0; // Set the end cut time in milliseconds. pEncodingParams->EndCutTime = 0; // Set the output file size in bytes. pEncodingParams->OutputFileSize = 0; // Set video time scale. pEncodingParams->OutputVideoTimescale = 0; VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_setEncodingParams()"); result = M4MCS_setEncodingParams(mcsContext, pEncodingParams); videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, (M4NO_ERROR != result), result); if (needToBeLoaded == false) { free(pTemp3gpFilePath); pTemp3gpFilePath = M4OSA_NULL; M4MCS_abort(mcsContext); free(pOutputParams); pOutputParams = M4OSA_NULL; free(pEncodingParams); pEncodingParams = M4OSA_NULL; return result; } VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_checkParamsAndStart()"); result = M4MCS_checkParamsAndStart(mcsContext); videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, (M4NO_ERROR != result), result); if (needToBeLoaded == false) { free(pTemp3gpFilePath); pTemp3gpFilePath = M4OSA_NULL; M4MCS_abort(mcsContext); free(pOutputParams); pOutputParams = M4OSA_NULL; free(pEncodingParams); pEncodingParams = M4OSA_NULL; return result; } VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_step()"); /*+ PROGRESS CB */ M4OSA_UInt8 curProgress = 0; int lastProgress = 0; ALOGV("LVME_generateAudio Current progress is =%d", curProgress); pEnv->CallVoidMethod(pContext->engine, pContext->onProgressUpdateMethodId, 1/*task status*/, curProgress/*progress*/); do { result = M4MCS_step(mcsContext, &curProgress); if (result != M4NO_ERROR) { ALOGV("LVME_generateAudio M4MCS_step returned 0x%x",result); if (result == M4MCS_WAR_TRANSCODING_DONE) { ALOGV("LVME_generateAudio MCS process ended"); // Send a progress notification. curProgress = 100; pEnv->CallVoidMethod(pContext->engine, pContext->onProgressUpdateMethodId, 1/*task status*/, curProgress); ALOGV("LVME_generateAudio Current progress is =%d", curProgress); } } else { // Send a progress notification if needed if (curProgress != lastProgress) { lastProgress = curProgress; pEnv->CallVoidMethod(pContext->engine, pContext->onProgressUpdateMethodId, 0/*task status*/, curProgress/*progress*/); ALOGV("LVME_generateAudio Current progress is =%d",curProgress); } } } while (result == M4NO_ERROR); /*- PROGRESS CB */ videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, (M4MCS_WAR_TRANSCODING_DONE != result), result); if (needToBeLoaded == false) { free(pTemp3gpFilePath); pTemp3gpFilePath = M4OSA_NULL; M4MCS_abort(mcsContext); free(pOutputParams); pOutputParams = M4OSA_NULL; free(pEncodingParams); pEncodingParams = M4OSA_NULL; return result; } VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_abort()"); result = M4MCS_abort(mcsContext); videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, (M4NO_ERROR != result), result); //pContext->mAudioSettings->pFile = pOutputParams->pOutputPCMfile; remove((const char *) pTemp3gpFilePath); VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_generateAudio() EXIT "); if (pTemp3gpFilePath != M4OSA_NULL) { free(pTemp3gpFilePath); } if (pOutputParams != M4OSA_NULL) { free(pOutputParams); } if(pEncodingParams != M4OSA_NULL) { free(pEncodingParams); } return result; } static int removeAlphafromRGB8888 ( M4OSA_Char* pFramingFilePath, M4xVSS_FramingStruct *pFramingCtx) { M4OSA_UInt32 frameSize_argb = (pFramingCtx->width * pFramingCtx->height * 4); // aRGB data M4OSA_Context lImageFileFp = M4OSA_NULL; M4OSA_ERR err = M4NO_ERROR; ALOGV("removeAlphafromRGB8888: width %d", pFramingCtx->width); M4OSA_UInt8 *pTmpData = (M4OSA_UInt8*) M4OSA_32bitAlignedMalloc(frameSize_argb, M4VS, (M4OSA_Char*)"Image argb data"); if (pTmpData == M4OSA_NULL) { ALOGE("Failed to allocate memory for Image clip"); return M4ERR_ALLOC; } /** Read the argb data from the passed file. */ M4OSA_ERR lerr = M4OSA_fileReadOpen(&lImageFileFp, (M4OSA_Void *) pFramingFilePath, M4OSA_kFileRead); if ((lerr != M4NO_ERROR) || (lImageFileFp == M4OSA_NULL)) { ALOGE("removeAlphafromRGB8888: Can not open the file "); free(pTmpData); return M4ERR_FILE_NOT_FOUND; } lerr = M4OSA_fileReadData(lImageFileFp, (M4OSA_MemAddr8)pTmpData, &frameSize_argb); if (lerr != M4NO_ERROR) { ALOGE("removeAlphafromRGB8888: can not read the data "); M4OSA_fileReadClose(lImageFileFp); free(pTmpData); return lerr; } M4OSA_fileReadClose(lImageFileFp); M4OSA_UInt32 frameSize = (pFramingCtx->width * pFramingCtx->height * 3); //Size of RGB 888 data. pFramingCtx->FramingRgb = (M4VIFI_ImagePlane*)M4OSA_32bitAlignedMalloc( sizeof(M4VIFI_ImagePlane), M4VS, (M4OSA_Char*)"Image clip RGB888 data"); pFramingCtx->FramingRgb->pac_data = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc( frameSize, M4VS, (M4OSA_Char*)"Image clip RGB888 data"); if (pFramingCtx->FramingRgb == M4OSA_NULL) { ALOGE("Failed to allocate memory for Image clip"); free(pTmpData); return M4ERR_ALLOC; } /** Remove the alpha channel */ for (size_t i = 0, j = 0; i < frameSize_argb; i++) { if ((i % 4) == 0) continue; pFramingCtx->FramingRgb->pac_data[j] = pTmpData[i]; j++; } free(pTmpData); return M4NO_ERROR; } static void videoEditor_populateSettings( JNIEnv* pEnv, jobject thiz, jobject settings, jobject object, jobject audioSettingObject) { VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_populateSettings()"); bool needToBeLoaded = true; ManualEditContext* pContext = M4OSA_NULL; M4OSA_ERR result = M4NO_ERROR; jstring strPath = M4OSA_NULL; jstring strPCMPath = M4OSA_NULL; jobjectArray propertiesClipsArray = M4OSA_NULL; jobject properties = M4OSA_NULL; jint* bitmapArray = M4OSA_NULL; jobjectArray effectSettingsArray = M4OSA_NULL; jobject effectSettings = M4OSA_NULL; jintArray pixelArray = M4OSA_NULL; int width = 0; int height = 0; int nbOverlays = 0; int i,j = 0; int *pOverlayIndex = M4OSA_NULL; M4OSA_Char* pTempChar = M4OSA_NULL; // Add a code marker (the condition must always be true). ADD_CODE_MARKER_FUN(NULL != pEnv) // Validate the settings parameter. videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv, (NULL == settings), "settings is null"); // Get the context. pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz); // Make sure that the context was set. videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == pContext), "not initialized"); // Make sure that the context was set. videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == pContext->mPreviewController), "not initialized"); jclass mPreviewClipPropClazz = pEnv->FindClass(PREVIEW_PROPERTIES_CLASS_NAME); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == mPreviewClipPropClazz), "not initialized"); jfieldID fid = pEnv->GetFieldID(mPreviewClipPropClazz,"clipProperties", "[L"PROPERTIES_CLASS_NAME";" ); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == fid), "not initialized"); propertiesClipsArray = (jobjectArray)pEnv->GetObjectField(object, fid); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == propertiesClipsArray), "not initialized"); jclass engineClass = pEnv->FindClass(MANUAL_EDIT_ENGINE_CLASS_NAME); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == engineClass), "not initialized"); pContext->onPreviewProgressUpdateMethodId = pEnv->GetMethodID(engineClass, "onPreviewProgressUpdate", "(IZZLjava/lang/String;II)V"); // Check if the context is valid (required because the context is dereferenced). if (needToBeLoaded) { // Make sure that we are in a correct state. videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (pContext->state != ManualEditState_INITIALIZED), "settings already loaded"); if (needToBeLoaded) { // Retrieve the edit settings. if (pContext->pEditSettings != M4OSA_NULL) { videoEditClasses_freeEditSettings(&pContext->pEditSettings); pContext->pEditSettings = M4OSA_NULL; } videoEditClasses_getEditSettings(&needToBeLoaded, pEnv, settings, &pContext->pEditSettings,false); } } if (needToBeLoaded == false) { j = 0; while (j < pContext->pEditSettings->nbEffects) { if (pContext->pEditSettings->Effects[j].xVSS.pFramingFilePath != M4OSA_NULL) { if (pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer != M4OSA_NULL) { free(pContext->pEditSettings->\ Effects[j].xVSS.pFramingBuffer); pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer = M4OSA_NULL; } } j++; } return; } M4OSA_TRACE1_0("videoEditorC_getEditSettings done"); pContext->previewFrameEditInfoId = pEnv->GetMethodID(engineClass, "previewFrameEditInfo", "(Ljava/lang/String;I)V"); if ( pContext->pEditSettings != NULL ) { // Check if the edit settings could be retrieved. jclass mEditClazz = pEnv->FindClass(EDIT_SETTINGS_CLASS_NAME); if(mEditClazz == M4OSA_NULL) { M4OSA_TRACE1_0("cannot find object field for mEditClazz"); goto videoEditor_populateSettings_cleanup; } jclass mEffectsClazz = pEnv->FindClass(EFFECT_SETTINGS_CLASS_NAME); if(mEffectsClazz == M4OSA_NULL) { M4OSA_TRACE1_0("cannot find object field for mEffectsClazz"); goto videoEditor_populateSettings_cleanup; } fid = pEnv->GetFieldID(mEditClazz,"effectSettingsArray", "[L"EFFECT_SETTINGS_CLASS_NAME";" ); if(fid == M4OSA_NULL) { M4OSA_TRACE1_0("cannot find field for effectSettingsArray Array"); goto videoEditor_populateSettings_cleanup; } effectSettingsArray = (jobjectArray)pEnv->GetObjectField(settings, fid); if(effectSettingsArray == M4OSA_NULL) { M4OSA_TRACE1_0("cannot find object field for effectSettingsArray"); goto videoEditor_populateSettings_cleanup; } //int overlayIndex[pContext->pEditSettings->nbEffects]; if (pContext->pEditSettings->nbEffects > 0) { pOverlayIndex = (int*) M4OSA_32bitAlignedMalloc(pContext->pEditSettings->nbEffects * sizeof(int), 0, (M4OSA_Char*)"pOverlayIndex"); if (pOverlayIndex == M4OSA_NULL) { videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, M4OSA_TRUE, M4ERR_ALLOC); goto videoEditor_populateSettings_cleanup; } } i = 0; j = 0; M4OSA_TRACE1_1("no of effects = %d",pContext->pEditSettings->nbEffects); while (j < pContext->pEditSettings->nbEffects) { if (pContext->pEditSettings->Effects[j].xVSS.pFramingFilePath != M4OSA_NULL) { pOverlayIndex[nbOverlays] = j; M4xVSS_FramingStruct *aFramingCtx = M4OSA_NULL; aFramingCtx = (M4xVSS_FramingStruct*)M4OSA_32bitAlignedMalloc(sizeof(M4xVSS_FramingStruct), M4VS, (M4OSA_Char*)"M4xVSS_internalDecodeGIF: Context of the framing effect"); if (aFramingCtx == M4OSA_NULL) { M4OSA_TRACE1_0("Allocation error in videoEditor_populateSettings"); videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, M4OSA_TRUE, M4ERR_ALLOC); goto videoEditor_populateSettings_cleanup; } aFramingCtx->pCurrent = M4OSA_NULL; /* Only used by the first element of the chain */ aFramingCtx->previousClipTime = -1; aFramingCtx->FramingYuv = M4OSA_NULL; aFramingCtx->FramingRgb = M4OSA_NULL; aFramingCtx->topleft_x = pContext->pEditSettings->Effects[j].xVSS.topleft_x; aFramingCtx->topleft_y = pContext->pEditSettings->Effects[j].xVSS.topleft_y; VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "OF u_width %d", pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_width); VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "OF u_height() %d", pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_height); VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "OF rgbType() %d", pContext->pEditSettings->Effects[j].xVSS.rgbType); aFramingCtx->width = pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_width; aFramingCtx->height = pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_height; result = M4xVSS_internalConvertARGB888toYUV420_FrammingEffect(pContext->engineContext, &(pContext->pEditSettings->Effects[j]),aFramingCtx, pContext->pEditSettings->Effects[j].xVSS.framingScaledSize); videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, (M4NO_ERROR != result), result); if (needToBeLoaded == false) { M4OSA_TRACE1_1("M4xVSS_internalConvertARGB888toYUV420_FrammingEffect returned 0x%x", result); if (aFramingCtx != M4OSA_NULL) { free(aFramingCtx); aFramingCtx = M4OSA_NULL; } goto videoEditor_populateSettings_cleanup; } //framing buffers are resized to fit the output video resolution. pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_width = aFramingCtx->FramingRgb->u_width; pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_height = aFramingCtx->FramingRgb->u_height; VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "A framing Context aFramingCtx->width = %d", aFramingCtx->FramingRgb->u_width); VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "A framing Context aFramingCtx->height = %d", aFramingCtx->FramingRgb->u_height); width = pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_width; height = pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_height; //RGB 565 pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_stride = width * 2; //for RGB565 pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_topleft = 0; pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->pac_data = (M4VIFI_UInt8 *)M4OSA_32bitAlignedMalloc(width*height*2, 0x00,(M4OSA_Char *)"pac_data buffer"); if (pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->pac_data == M4OSA_NULL) { M4OSA_TRACE1_0("Failed to allocate memory for framing buffer"); videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, M4OSA_TRUE, M4ERR_ALLOC); goto videoEditor_populateSettings_cleanup; } memcpy((void *)&pContext->pEditSettings->\ Effects[j].xVSS.pFramingBuffer->\ pac_data[0],(void *)&aFramingCtx->FramingRgb->pac_data[0],(width*height*2)); //As of now rgb type is 565 pContext->pEditSettings->Effects[j].xVSS.rgbType = (M4VSS3GPP_RGBType) M4VSS3GPP_kRGB565; if (aFramingCtx->FramingYuv != M4OSA_NULL ) { if (aFramingCtx->FramingYuv[0].pac_data != M4OSA_NULL) { free(aFramingCtx->FramingYuv[0].pac_data); aFramingCtx->FramingYuv[0].pac_data = M4OSA_NULL; } if (aFramingCtx->FramingYuv[1].pac_data != M4OSA_NULL) { free(aFramingCtx->FramingYuv[1].pac_data); aFramingCtx->FramingYuv[1].pac_data = M4OSA_NULL; } if (aFramingCtx->FramingYuv[2].pac_data != M4OSA_NULL) { free(aFramingCtx->FramingYuv[2].pac_data); aFramingCtx->FramingYuv[2].pac_data = M4OSA_NULL; } free(aFramingCtx->FramingYuv); aFramingCtx->FramingYuv = M4OSA_NULL; } if (aFramingCtx->FramingRgb->pac_data != M4OSA_NULL) { free(aFramingCtx->FramingRgb->pac_data); aFramingCtx->FramingRgb->pac_data = M4OSA_NULL; } if (aFramingCtx->FramingRgb != M4OSA_NULL) { free(aFramingCtx->FramingRgb); aFramingCtx->FramingRgb = M4OSA_NULL; } if (aFramingCtx != M4OSA_NULL) { free(aFramingCtx); aFramingCtx = M4OSA_NULL; } nbOverlays++; } j++; } // Check if the edit settings could be retrieved. M4OSA_TRACE1_1("total clips are = %d",pContext->pEditSettings->uiClipNumber); for (i = 0; i < pContext->pEditSettings->uiClipNumber; i++) { M4OSA_TRACE1_1("clip no = %d",i); properties = pEnv->GetObjectArrayElement(propertiesClipsArray, i); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == properties), "not initialized"); if (needToBeLoaded) { getClipSetting(pEnv,properties, pContext->pEditSettings->pClipList[i]); pEnv->DeleteLocalRef(properties); } else { pEnv->DeleteLocalRef(properties); goto videoEditor_populateSettings_cleanup; } } if (needToBeLoaded) { // Log the edit settings. VIDEOEDIT_LOG_EDIT_SETTINGS(pContext->pEditSettings); } } /* free previous allocations , if any */ if (pContext->mAudioSettings != M4OSA_NULL) { if (pContext->mAudioSettings->pFile != NULL) { free(pContext->mAudioSettings->pFile); pContext->mAudioSettings->pFile = M4OSA_NULL; } if (pContext->mAudioSettings->pPCMFilePath != NULL) { free(pContext->mAudioSettings->pPCMFilePath); pContext->mAudioSettings->pPCMFilePath = M4OSA_NULL; } } if (audioSettingObject != M4OSA_NULL) { jclass audioSettingClazz = pEnv->FindClass(AUDIO_SETTINGS_CLASS_NAME); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == audioSettingClazz), "not initialized"); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == pContext->mAudioSettings), "not initialized"); if (needToBeLoaded == false) { goto videoEditor_populateSettings_cleanup; } fid = pEnv->GetFieldID(audioSettingClazz,"bRemoveOriginal","Z"); pContext->mAudioSettings->bRemoveOriginal = pEnv->GetBooleanField(audioSettingObject,fid); M4OSA_TRACE1_1("bRemoveOriginal = %d",pContext->mAudioSettings->bRemoveOriginal); fid = pEnv->GetFieldID(audioSettingClazz,"channels","I"); pContext->mAudioSettings->uiNbChannels = pEnv->GetIntField(audioSettingObject,fid); M4OSA_TRACE1_1("uiNbChannels = %d",pContext->mAudioSettings->uiNbChannels); fid = pEnv->GetFieldID(audioSettingClazz,"Fs","I"); pContext->mAudioSettings->uiSamplingFrequency = pEnv->GetIntField(audioSettingObject,fid); M4OSA_TRACE1_1("uiSamplingFrequency = %d",pContext->mAudioSettings->uiSamplingFrequency); fid = pEnv->GetFieldID(audioSettingClazz,"ExtendedFs","I"); pContext->mAudioSettings->uiExtendedSamplingFrequency = pEnv->GetIntField(audioSettingObject,fid); M4OSA_TRACE1_1("uiExtendedSamplingFrequency = %d", pContext->mAudioSettings->uiExtendedSamplingFrequency); fid = pEnv->GetFieldID(audioSettingClazz,"startMs","J"); pContext->mAudioSettings->uiAddCts = pEnv->GetLongField(audioSettingObject,fid); M4OSA_TRACE1_1("uiAddCts = %d",pContext->mAudioSettings->uiAddCts); fid = pEnv->GetFieldID(audioSettingClazz,"volume","I"); pContext->mAudioSettings->uiAddVolume = pEnv->GetIntField(audioSettingObject,fid); M4OSA_TRACE1_1("uiAddVolume = %d",pContext->mAudioSettings->uiAddVolume); fid = pEnv->GetFieldID(audioSettingClazz,"loop","Z"); pContext->mAudioSettings->bLoop = pEnv->GetBooleanField(audioSettingObject,fid); M4OSA_TRACE1_1("bLoop = %d",pContext->mAudioSettings->bLoop); fid = pEnv->GetFieldID(audioSettingClazz,"beginCutTime","J"); pContext->mAudioSettings->beginCutMs = pEnv->GetLongField(audioSettingObject,fid); M4OSA_TRACE1_1("begin cut time = %d",pContext->mAudioSettings->beginCutMs); fid = pEnv->GetFieldID(audioSettingClazz,"endCutTime","J"); pContext->mAudioSettings->endCutMs = pEnv->GetLongField(audioSettingObject,fid); M4OSA_TRACE1_1("end cut time = %d",pContext->mAudioSettings->endCutMs); fid = pEnv->GetFieldID(audioSettingClazz,"fileType","I"); pContext->mAudioSettings->fileType = pEnv->GetIntField(audioSettingObject,fid); M4OSA_TRACE1_1("fileType = %d",pContext->mAudioSettings->fileType); fid = pEnv->GetFieldID(audioSettingClazz,"pFile","Ljava/lang/String;"); strPath = (jstring)pEnv->GetObjectField(audioSettingObject,fid); pTempChar = (M4OSA_Char*)pEnv->GetStringUTFChars(strPath, M4OSA_NULL); if (pTempChar != NULL) { pContext->mAudioSettings->pFile = (M4OSA_Char*) M4OSA_32bitAlignedMalloc( (M4OSA_UInt32)(strlen((const char*)pTempChar))+1 /* +1 for NULL termination */, 0, (M4OSA_Char*)"strPath allocation " ); if (pContext->mAudioSettings->pFile != M4OSA_NULL) { memcpy((void *)pContext->mAudioSettings->pFile , (void *)pTempChar , strlen((const char*)pTempChar)); ((M4OSA_Int8 *)(pContext->mAudioSettings->pFile))[strlen((const char*)pTempChar)] = '\0'; pEnv->ReleaseStringUTFChars(strPath,(const char *)pTempChar); } else { pEnv->ReleaseStringUTFChars(strPath,(const char *)pTempChar); VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "regenerateAudio() Malloc failed for pContext->mAudioSettings->pFile "); videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, M4OSA_TRUE, M4ERR_ALLOC); goto videoEditor_populateSettings_cleanup; } } M4OSA_TRACE1_1("file name = %s",pContext->mAudioSettings->pFile); VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEOEDITOR", "regenerateAudio() file name = %s",\ pContext->mAudioSettings->pFile); fid = pEnv->GetFieldID(audioSettingClazz,"pcmFilePath","Ljava/lang/String;"); strPCMPath = (jstring)pEnv->GetObjectField(audioSettingObject,fid); pTempChar = (M4OSA_Char*)pEnv->GetStringUTFChars(strPCMPath, M4OSA_NULL); if (pTempChar != NULL) { pContext->mAudioSettings->pPCMFilePath = (M4OSA_Char*) M4OSA_32bitAlignedMalloc( (M4OSA_UInt32)(strlen((const char*)pTempChar))+1 /* +1 for NULL termination */, 0, (M4OSA_Char*)"strPCMPath allocation " ); if (pContext->mAudioSettings->pPCMFilePath != M4OSA_NULL) { memcpy((void *)pContext->mAudioSettings->pPCMFilePath , (void *)pTempChar , strlen((const char*)pTempChar)); ((M4OSA_Int8 *)(pContext->mAudioSettings->pPCMFilePath))[strlen((const char*)pTempChar)] = '\0'; pEnv->ReleaseStringUTFChars(strPCMPath,(const char *)pTempChar); } else { pEnv->ReleaseStringUTFChars(strPCMPath,(const char *)pTempChar); VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "regenerateAudio() Malloc failed for pContext->mAudioSettings->pPCMFilePath "); videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, M4OSA_TRUE, M4ERR_ALLOC); goto videoEditor_populateSettings_cleanup; } } VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEOEDITOR", "pPCMFilePath -- %s ",\ pContext->mAudioSettings->pPCMFilePath); fid = pEnv->GetFieldID(engineClass,"mRegenerateAudio","Z"); bool regenerateAudio = pEnv->GetBooleanField(thiz,fid); VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEOEDITOR", "regenerateAudio -- %d ",\ regenerateAudio); if (regenerateAudio) { M4OSA_TRACE1_0("Calling Generate Audio now"); result = videoEditor_generateAudio(pEnv, pContext, (M4OSA_Char*)pContext->mAudioSettings->pFile, (M4OSA_Char*)pContext->mAudioSettings->pPCMFilePath); videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, (M4NO_ERROR != result), result); if (needToBeLoaded == false) { goto videoEditor_populateSettings_cleanup; } regenerateAudio = false; pEnv->SetBooleanField(thiz,fid,regenerateAudio); } /* Audio mix and duck */ fid = pEnv->GetFieldID(audioSettingClazz,"ducking_threshold","I"); pContext->mAudioSettings->uiInDucking_threshold = pEnv->GetIntField(audioSettingObject,fid); M4OSA_TRACE1_1("ducking threshold = %d", pContext->mAudioSettings->uiInDucking_threshold); fid = pEnv->GetFieldID(audioSettingClazz,"ducking_lowVolume","I"); pContext->mAudioSettings->uiInDucking_lowVolume = pEnv->GetIntField(audioSettingObject,fid); M4OSA_TRACE1_1("ducking lowVolume = %d", pContext->mAudioSettings->uiInDucking_lowVolume); fid = pEnv->GetFieldID(audioSettingClazz,"bInDucking_enable","Z"); pContext->mAudioSettings->bInDucking_enable = pEnv->GetBooleanField(audioSettingObject,fid); M4OSA_TRACE1_1("ducking lowVolume = %d", pContext->mAudioSettings->bInDucking_enable); } else { if (pContext->mAudioSettings != M4OSA_NULL) { pContext->mAudioSettings->pFile = M4OSA_NULL; pContext->mAudioSettings->pPCMFilePath = M4OSA_NULL; pContext->mAudioSettings->bRemoveOriginal = 0; pContext->mAudioSettings->uiNbChannels = 0; pContext->mAudioSettings->uiSamplingFrequency = 0; pContext->mAudioSettings->uiExtendedSamplingFrequency = 0; pContext->mAudioSettings->uiAddCts = 0; pContext->mAudioSettings->uiAddVolume = 0; pContext->mAudioSettings->beginCutMs = 0; pContext->mAudioSettings->endCutMs = 0; pContext->mAudioSettings->fileType = 0; pContext->mAudioSettings->bLoop = 0; pContext->mAudioSettings->uiInDucking_lowVolume = 0; pContext->mAudioSettings->bInDucking_enable = 0; pContext->mAudioSettings->uiBTChannelCount = 0; pContext->mAudioSettings->uiInDucking_threshold = 0; fid = pEnv->GetFieldID(engineClass,"mRegenerateAudio","Z"); bool regenerateAudio = pEnv->GetBooleanField(thiz,fid); if (!regenerateAudio) { regenerateAudio = true; pEnv->SetBooleanField(thiz,fid,regenerateAudio); } } } if (pContext->pEditSettings != NULL) { result = pContext->mPreviewController->loadEditSettings(pContext->pEditSettings, pContext->mAudioSettings); videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, (M4NO_ERROR != result), result); if (needToBeLoaded) { pContext->mPreviewController->setJniCallback((void*)pContext, (jni_progress_callback_fct)jniPreviewProgressCallback); } } videoEditor_populateSettings_cleanup: j = 0; while (j < nbOverlays) { if (pContext->pEditSettings->Effects[pOverlayIndex[j]].xVSS.pFramingBuffer->pac_data != \ M4OSA_NULL) { free(pContext->pEditSettings->\ Effects[pOverlayIndex[j]].xVSS.pFramingBuffer->pac_data); pContext->pEditSettings->\ Effects[pOverlayIndex[j]].xVSS.pFramingBuffer->pac_data = M4OSA_NULL; } j++; } j = 0; while (j < pContext->pEditSettings->nbEffects) { if (pContext->pEditSettings->Effects[j].xVSS.pFramingFilePath != M4OSA_NULL) { if (pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer != M4OSA_NULL) { free(pContext->pEditSettings->\ Effects[j].xVSS.pFramingBuffer); pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer = M4OSA_NULL; } } j++; } if (pOverlayIndex != M4OSA_NULL) { free(pOverlayIndex); pOverlayIndex = M4OSA_NULL; } return; } static void videoEditor_startPreview( JNIEnv* pEnv, jobject thiz, jobject mSurface, jlong fromMs, jlong toMs, jint callbackInterval, jboolean loop) { bool needToBeLoaded = true; M4OSA_ERR result = M4NO_ERROR; VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_startPreview()"); ManualEditContext* pContext = M4OSA_NULL; // Get the context. pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz); // Make sure that the context was set. videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == pContext), "not initialized"); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == pContext->mAudioSettings), "not initialized"); // Make sure that the context was set. videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == pContext->mPreviewController), "not initialized"); // Validate the mSurface parameter. videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv, (NULL == mSurface), "mSurface is null"); jclass surfaceClass = pEnv->FindClass("android/view/Surface"); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == surfaceClass), "not initialized"); //jfieldID surface_native = pEnv->GetFieldID(surfaceClass, "mSurface", "I"); jfieldID surface_native = pEnv->GetFieldID(surfaceClass, ANDROID_VIEW_SURFACE_JNI_ID, "I"); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == surface_native), "not initialized"); Surface* const p = (Surface*)pEnv->GetIntField(mSurface, surface_native); sp<Surface> previewSurface = sp<Surface>(p); // Validate the mSurface's mNativeSurface field videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (NULL == previewSurface.get()), "mNativeSurface is null"); result = pContext->mPreviewController->setSurface(previewSurface); videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, (M4NO_ERROR != result), result); VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "fromMs=%ld, toMs=%ld", (M4OSA_UInt32)fromMs, (M4OSA_Int32)toMs); result = pContext->mPreviewController->startPreview((M4OSA_UInt32)fromMs, (M4OSA_Int32)toMs, (M4OSA_UInt16)callbackInterval, (M4OSA_Bool)loop); videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, (M4NO_ERROR != result), result); } static jobject videoEditor_getProperties( JNIEnv* pEnv, jobject thiz, jstring file) { jobject object = M4OSA_NULL; jclass clazz = pEnv->FindClass(PROPERTIES_CLASS_NAME); jfieldID fid; bool needToBeLoaded = true; ManualEditContext* pContext = M4OSA_NULL; M4OSA_ERR result = M4NO_ERROR; int profile = 0; int level = 0; int videoFormat = 0; // Get the context. pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz); videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == clazz), "not initialized"); object = videoEditProp_getProperties(pEnv,thiz,file); if (object != M4OSA_NULL) { fid = pEnv->GetFieldID(clazz,"profile","I"); profile = pEnv->GetIntField(object,fid); fid = pEnv->GetFieldID(clazz,"level","I"); level = pEnv->GetIntField(object,fid); fid = pEnv->GetFieldID(clazz,"videoFormat","I"); videoFormat = pEnv->GetIntField(object,fid); result = checkClipVideoProfileAndLevel(pContext->decoders, videoFormat, profile, level); fid = pEnv->GetFieldID(clazz,"profileSupported","Z"); if (M4VSS3GPP_ERR_EDITING_UNSUPPORTED_VIDEO_PROFILE == result) { pEnv->SetBooleanField(object,fid,false); } fid = pEnv->GetFieldID(clazz,"levelSupported","Z"); if (M4VSS3GPP_ERR_EDITING_UNSUPPORTED_VIDEO_LEVEL == result) { pEnv->SetBooleanField(object,fid,false); } } return object; } static int videoEditor_getPixels( JNIEnv* env, jobject thiz, jstring path, jintArray pixelArray, M4OSA_UInt32 width, M4OSA_UInt32 height, M4OSA_UInt32 timeMS) { M4OSA_ERR err = M4NO_ERROR; M4OSA_Context mContext = M4OSA_NULL; jint* m_dst32 = M4OSA_NULL; // Add a text marker (the condition must always be true). ADD_TEXT_MARKER_FUN(NULL != env) const char *pString = env->GetStringUTFChars(path, NULL); if (pString == M4OSA_NULL) { if (env != NULL) { jniThrowException(env, "java/lang/RuntimeException", "Input string null"); } return M4ERR_ALLOC; } err = ThumbnailOpen(&mContext,(const M4OSA_Char*)pString, M4OSA_FALSE); if (err != M4NO_ERROR || mContext == M4OSA_NULL) { if (pString != NULL) { env->ReleaseStringUTFChars(path, pString); } if (env != NULL) { jniThrowException(env, "java/lang/RuntimeException", "ThumbnailOpen failed"); } } m_dst32 = env->GetIntArrayElements(pixelArray, NULL); err = ThumbnailGetPixels32(mContext, (M4OSA_Int32 *)m_dst32, width,height,&timeMS,0); if (err != M4NO_ERROR ) { if (env != NULL) { jniThrowException(env, "java/lang/RuntimeException",\ "ThumbnailGetPixels32 failed"); } } env->ReleaseIntArrayElements(pixelArray, m_dst32, 0); ThumbnailClose(mContext); if (pString != NULL) { env->ReleaseStringUTFChars(path, pString); } return timeMS; } static int videoEditor_getPixelsList( JNIEnv* env, jobject thiz, jstring path, jintArray pixelArray, M4OSA_UInt32 width, M4OSA_UInt32 height, M4OSA_UInt32 noOfThumbnails, jlong startTime, jlong endTime, jintArray indexArray, jobject callback) { M4OSA_ERR err = M4NO_ERROR; M4OSA_Context mContext = M4OSA_NULL; const char *pString = env->GetStringUTFChars(path, NULL); if (pString == M4OSA_NULL) { jniThrowException(env, "java/lang/RuntimeException", "Input string null"); return M4ERR_ALLOC; } err = ThumbnailOpen(&mContext,(const M4OSA_Char*)pString, M4OSA_FALSE); if (err != M4NO_ERROR || mContext == M4OSA_NULL) { jniThrowException(env, "java/lang/RuntimeException", "ThumbnailOpen failed"); if (pString != NULL) { env->ReleaseStringUTFChars(path, pString); } return err; } jlong duration = (endTime - startTime); M4OSA_UInt32 tolerance = duration / (2 * noOfThumbnails); jint* m_dst32 = env->GetIntArrayElements(pixelArray, NULL); jint* indices = env->GetIntArrayElements(indexArray, NULL); jsize len = env->GetArrayLength(indexArray); jclass cls = env->GetObjectClass(callback); jmethodID mid = env->GetMethodID(cls, "onThumbnail", "(I)V"); for (int i = 0; i < len; i++) { int k = indices[i]; M4OSA_UInt32 timeMS = startTime; timeMS += (2 * k + 1) * duration / (2 * noOfThumbnails); err = ThumbnailGetPixels32(mContext, ((M4OSA_Int32 *)m_dst32), width, height, &timeMS, tolerance); if (err != M4NO_ERROR) { break; } env->CallVoidMethod(callback, mid, (jint)k); if (env->ExceptionCheck()) { err = M4ERR_ALLOC; break; } } env->ReleaseIntArrayElements(pixelArray, m_dst32, 0); env->ReleaseIntArrayElements(indexArray, indices, 0); ThumbnailClose(mContext); if (pString != NULL) { env->ReleaseStringUTFChars(path, pString); } if (err != M4NO_ERROR && !env->ExceptionCheck()) { jniThrowException(env, "java/lang/RuntimeException",\ "ThumbnailGetPixels32 failed"); } return err; } static M4OSA_ERR videoEditor_toUTF8Fct( M4OSA_Void* pBufferIn, M4OSA_UInt8* pBufferOut, M4OSA_UInt32* bufferOutSize) { M4OSA_ERR result = M4NO_ERROR; M4OSA_UInt32 length = 0; VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_toUTF8Fct()"); // Determine the length of the input buffer. if (M4OSA_NULL != pBufferIn) { length = strlen((const char *)pBufferIn); } // Check if the output buffer is large enough to hold the input buffer. if ((*bufferOutSize) > length) { // Check if the input buffer is not M4OSA_NULL. if (M4OSA_NULL != pBufferIn) { // Copy the temp path, ignore the result. M4OSA_chrNCopy((M4OSA_Char *)pBufferOut, (M4OSA_Char *)pBufferIn, length); } else { // Set the output buffer to an empty string. (*(M4OSA_Char *)pBufferOut) = 0; } } else { // The buffer is too small. result = M4xVSSWAR_BUFFER_OUT_TOO_SMALL; } // Return the buffer output size. (*bufferOutSize) = length + 1; // Return the result. return(result); } static M4OSA_ERR videoEditor_fromUTF8Fct( M4OSA_UInt8* pBufferIn, M4OSA_Void* pBufferOut, M4OSA_UInt32* bufferOutSize) { M4OSA_ERR result = M4NO_ERROR; M4OSA_UInt32 length = 0; VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_fromUTF8Fct()"); // Determine the length of the input buffer. if (M4OSA_NULL != pBufferIn) { length = strlen((const char *)pBufferIn); } // Check if the output buffer is large enough to hold the input buffer. if ((*bufferOutSize) > length) { // Check if the input buffer is not M4OSA_NULL. if (M4OSA_NULL != pBufferIn) { // Copy the temp path, ignore the result. M4OSA_chrNCopy((M4OSA_Char *)pBufferOut, (M4OSA_Char *)pBufferIn, length); } else { // Set the output buffer to an empty string. (*(M4OSA_Char *)pBufferOut) = 0; } } else { // The buffer is too small. result = M4xVSSWAR_BUFFER_OUT_TOO_SMALL; } // Return the buffer output size. (*bufferOutSize) = length + 1; // Return the result. return(result); } static M4OSA_ERR videoEditor_getTextRgbBufferFct( M4OSA_Void* pRenderingData, M4OSA_Void* pTextBuffer, M4OSA_UInt32 textBufferSize, M4VIFI_ImagePlane** pOutputPlane) { M4OSA_ERR result = M4NO_ERROR; VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_getTextRgbBufferFct()"); // Return the result. return(result); } static void videoEditor_callOnProgressUpdate( ManualEditContext* pContext, int task, int progress) { JNIEnv* pEnv = NULL; // Attach the current thread. pContext->pVM->AttachCurrentThread(&pEnv, NULL); // Call the on completion callback. pEnv->CallVoidMethod(pContext->engine, pContext->onProgressUpdateMethodId, videoEditJava_getEngineCToJava(task), progress); // Detach the current thread. pContext->pVM->DetachCurrentThread(); } static void videoEditor_freeContext( JNIEnv* pEnv, ManualEditContext** ppContext) { ManualEditContext* pContext = M4OSA_NULL; VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_freeContext"); // Set the context pointer. pContext = (*ppContext); // Check if the context was set. if (M4OSA_NULL != pContext) { // Check if a global reference to the engine object was set. if (NULL != pContext->engine) { // Free the global reference. pEnv->DeleteGlobalRef(pContext->engine); pContext->engine = NULL; } // Check if the temp path was set. if (M4OSA_NULL != pContext->initParams.pTempPath) { // Free the memory allocated for the temp path. videoEditOsal_free(pContext->initParams.pTempPath); pContext->initParams.pTempPath = M4OSA_NULL; } // Check if the file writer was set. if (M4OSA_NULL != pContext->initParams.pFileWritePtr) { // Free the memory allocated for the file writer. videoEditOsal_free(pContext->initParams.pFileWritePtr); pContext->initParams.pFileWritePtr = M4OSA_NULL; } // Check if the file reader was set. if (M4OSA_NULL != pContext->initParams.pFileReadPtr) { // Free the memory allocated for the file reader. videoEditOsal_free(pContext->initParams.pFileReadPtr); pContext->initParams.pFileReadPtr = M4OSA_NULL; } // Free the memory allocated for the context. videoEditOsal_free(pContext); pContext = M4OSA_NULL; // Reset the context pointer. (*ppContext) = M4OSA_NULL; } } static jobject videoEditor_getVersion( JNIEnv* pEnv, jobject thiz) { bool isSuccessful = true; jobject version = NULL; M4_VersionInfo versionInfo = {0, 0, 0, 0}; M4OSA_ERR result = M4NO_ERROR; VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_getVersion()"); versionInfo.m_structSize = sizeof(versionInfo); versionInfo.m_major = VIDEOEDITOR_VERSION_MAJOR; versionInfo.m_minor = VIDEOEDITOR_VERSION_MINOR; versionInfo.m_revision = VIDEOEDITOR_VERSION_REVISION; VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_getVersion() major %d,\ minor %d, revision %d", versionInfo.m_major, versionInfo.m_minor, versionInfo.m_revision); // Create a version object. videoEditClasses_createVersion(&isSuccessful, pEnv, &versionInfo, &version); // Return the version object. return(version); } static void videoEditor_init( JNIEnv* pEnv, jobject thiz, jstring tempPath, jstring libraryPath) { bool initialized = true; ManualEditContext* pContext = M4OSA_NULL; VideoEditJava_EngineMethodIds methodIds = {NULL}; M4OSA_Char* pLibraryPath = M4OSA_NULL; M4OSA_Char* pTextRendererPath = M4OSA_NULL; M4OSA_UInt32 textRendererPathLength = 0; M4OSA_ERR result = M4NO_ERROR; VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_init()"); // Add a text marker (the condition must always be true). ADD_TEXT_MARKER_FUN(NULL != pEnv) // Get the context. pContext = (ManualEditContext*)videoEditClasses_getContext(&initialized, pEnv, thiz); // Get the engine method ids. videoEditJava_getEngineMethodIds(&initialized, pEnv, &methodIds); // Validate the tempPath parameter. videoEditJava_checkAndThrowIllegalArgumentException(&initialized, pEnv, (NULL == tempPath), "tempPath is null"); // Make sure that the context was not set already. videoEditJava_checkAndThrowIllegalStateException(&initialized, pEnv, (M4OSA_NULL != pContext), "already initialized"); // Check if the initialization succeeded (required because of dereferencing of psContext, // and freeing when initialization fails). if (initialized) { // Allocate a new context. pContext = new ManualEditContext; // Check if the initialization succeeded (required because of dereferencing of psContext). //if (initialized) if (pContext != NULL) { // Set the state to not initialized. pContext->state = ManualEditState_NOT_INITIALIZED; // Allocate a file read pointer structure. pContext->initParams.pFileReadPtr = (M4OSA_FileReadPointer*)videoEditOsal_alloc(&initialized, pEnv, sizeof(M4OSA_FileReadPointer), "FileReadPointer"); // Allocate a file write pointer structure. pContext->initParams.pFileWritePtr = (M4OSA_FileWriterPointer*)videoEditOsal_alloc(&initialized, pEnv, sizeof(M4OSA_FileWriterPointer), "FileWriterPointer"); // Get the temp path. M4OSA_Char* tmpString = (M4OSA_Char *)videoEditJava_getString(&initialized, pEnv, tempPath, NULL, M4OSA_NULL); M4OSA_UInt32 length = strlen((const char *)tmpString); // Malloc additional 2 bytes for beginning and tail separator. M4OSA_UInt32 pathLength = length + 2; pContext->initParams.pTempPath = (M4OSA_Char *) M4OSA_32bitAlignedMalloc(pathLength, 0x0, (M4OSA_Char *)"tempPath"); //initialize the first char. so that strcat works. M4OSA_Char *ptmpChar = (M4OSA_Char*)pContext->initParams.pTempPath; ptmpChar[0] = 0x00; strncat((char *)pContext->initParams.pTempPath, (const char *)tmpString, length); strncat((char *)pContext->initParams.pTempPath, (const char *)"/", (size_t)1); free(tmpString); tmpString = NULL; pContext->mIsUpdateOverlay = false; pContext->mOverlayFileName = NULL; pContext->decoders = NULL; } // Check if the initialization succeeded // (required because of dereferencing of pContext, pFileReadPtr and pFileWritePtr). if (initialized) { // Initialize the OSAL file system function pointers. videoEditOsal_getFilePointers(pContext->initParams.pFileReadPtr , pContext->initParams.pFileWritePtr); // Set the UTF8 conversion functions. pContext->initParams.pConvToUTF8Fct = videoEditor_toUTF8Fct; pContext->initParams.pConvFromUTF8Fct = videoEditor_fromUTF8Fct; // Set the callback method ids. pContext->onProgressUpdateMethodId = methodIds.onProgressUpdate; // Set the virtual machine. pEnv->GetJavaVM(&(pContext->pVM)); // Create a global reference to the engine object. pContext->engine = pEnv->NewGlobalRef(thiz); // Check if the global reference could be created. videoEditJava_checkAndThrowRuntimeException(&initialized, pEnv, (NULL == pContext->engine), M4NO_ERROR); } // Check if the initialization succeeded (required because of dereferencing of pContext). if (initialized) { // Log the API call. VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4xVSS_Init()"); // Initialize the visual studio library. result = M4xVSS_Init(&pContext->engineContext, &pContext->initParams); // Log the result. VIDEOEDIT_LOG_RESULT(ANDROID_LOG_INFO, "VIDEO_EDITOR", videoEditOsal_getResultString(result)); // Check if the library could be initialized. videoEditJava_checkAndThrowRuntimeException(&initialized, pEnv, (M4NO_ERROR != result), result); // Get platform video decoder capablities. result = M4xVSS_getVideoDecoderCapabilities(&pContext->decoders); videoEditJava_checkAndThrowRuntimeException(&initialized, pEnv, (M4NO_ERROR != result), result); } if(initialized) { pContext->mPreviewController = new VideoEditorPreviewController(); videoEditJava_checkAndThrowIllegalStateException(&initialized, pEnv, (M4OSA_NULL == pContext->mPreviewController), "not initialized"); pContext->mAudioSettings = (M4xVSS_AudioMixingSettings *) M4OSA_32bitAlignedMalloc(sizeof(M4xVSS_AudioMixingSettings),0x0, (M4OSA_Char *)"mAudioSettings"); videoEditJava_checkAndThrowIllegalStateException(&initialized, pEnv, (M4OSA_NULL == pContext->mAudioSettings), "not initialized"); pContext->mAudioSettings->pFile = M4OSA_NULL; pContext->mAudioSettings->pPCMFilePath = M4OSA_NULL; pContext->mAudioSettings->bRemoveOriginal = 0; pContext->mAudioSettings->uiNbChannels = 0; pContext->mAudioSettings->uiSamplingFrequency = 0; pContext->mAudioSettings->uiExtendedSamplingFrequency = 0; pContext->mAudioSettings->uiAddCts = 0; pContext->mAudioSettings->uiAddVolume = 0; pContext->mAudioSettings->beginCutMs = 0; pContext->mAudioSettings->endCutMs = 0; pContext->mAudioSettings->fileType = 0; pContext->mAudioSettings->bLoop = 0; pContext->mAudioSettings->uiInDucking_lowVolume = 0; pContext->mAudioSettings->bInDucking_enable = 0; pContext->mAudioSettings->uiBTChannelCount = 0; pContext->mAudioSettings->uiInDucking_threshold = 0; } // Check if the library could be initialized. if (initialized) { // Set the state to initialized. pContext->state = ManualEditState_INITIALIZED; } // Set the context. videoEditClasses_setContext(&initialized, pEnv, thiz, (void* )pContext); pLibraryPath = M4OSA_NULL; pContext->pEditSettings = M4OSA_NULL; // Cleanup if anything went wrong during initialization. if (!initialized) { // Free the context. videoEditor_freeContext(pEnv, &pContext); } } } /*+ PROGRESS CB */ static M4OSA_ERR videoEditor_processClip( JNIEnv* pEnv, jobject thiz, int unuseditemID) { bool loaded = true; ManualEditContext* pContext = NULL; M4OSA_UInt8 progress = 0; M4OSA_UInt8 progressBase = 0; M4OSA_UInt8 lastProgress = 0; M4OSA_ERR result = M4NO_ERROR; // Get the context. pContext = (ManualEditContext*)videoEditClasses_getContext(&loaded, pEnv, thiz); // Make sure that the context was set. videoEditJava_checkAndThrowIllegalStateException(&loaded, pEnv, (M4OSA_NULL == pContext), "not initialized"); // We start in Analyzing state pContext->state = ManualEditState_INITIALIZED; M4OSA_ERR completionResult = M4VSS3GPP_WAR_ANALYZING_DONE; ManualEditState completionState = ManualEditState_OPENED; ManualEditState errorState = ManualEditState_ANALYZING_ERROR; // While analyzing progress goes from 0 to 10 (except Kenburn clip // generation, which goes from 0 to 50) progressBase = 0; // Set the text rendering function. if (M4OSA_NULL != pContext->pTextRendererFunction) { // Use the text renderer function in the library. pContext->pEditSettings->xVSS.pTextRenderingFct = pContext->pTextRendererFunction; } else { // Use the internal text renderer function. pContext->pEditSettings->xVSS.pTextRenderingFct = videoEditor_getTextRgbBufferFct; } // Send the command. ALOGV("videoEditor_processClip ITEM %d Calling M4xVSS_SendCommand()", unuseditemID); result = M4xVSS_SendCommand(pContext->engineContext, pContext->pEditSettings); ALOGV("videoEditor_processClip ITEM %d M4xVSS_SendCommand() returned 0x%x", unuseditemID, (unsigned int) result); // Remove warnings indications (we only care about errors here) if ((result == M4VSS3GPP_WAR_TRANSCODING_NECESSARY) || (result == M4VSS3GPP_WAR_OUTPUTFILESIZE_EXCEED)) { result = M4NO_ERROR; } // Send the first progress indication (=0) ALOGV("VERY FIRST PROGRESS videoEditor_processClip ITEM %d Progress indication %d", unuseditemID, progress); pEnv->CallVoidMethod(pContext->engine, pContext->onProgressUpdateMethodId, unuseditemID, progress); // Check if a task is being performed. // ??? ADD STOPPING MECHANISM ALOGV("videoEditor_processClip Entering processing loop"); M4OSA_UInt8 prevReportedProgress = 0; while((result == M4NO_ERROR) &&(pContext->state!=ManualEditState_SAVED) &&(pContext->state!=ManualEditState_STOPPING)) { // Perform the next processing step. //ALOGV("LVME_processClip Entering M4xVSS_Step()"); result = M4xVSS_Step(pContext->engineContext, &progress); if (progress != prevReportedProgress) { prevReportedProgress = progress; // Log the 1 % .. 100 % progress after processing. if (M4OSA_TRUE == pContext->pEditSettings->pClipList[0]->xVSS.isPanZoom) { // For KenBurn clip generation, return 0 to 50 // for Analysis phase and 50 to 100 for Saving phase progress = progressBase + progress/2; } else { // For export/transition clips, 0 to 10 for Analysis phase // and 10 to 100 for Saving phase if (ManualEditState_INITIALIZED == pContext->state) { progress = 0.1*progress; } else { progress = progressBase + 0.9*progress; } } if (progress > lastProgress) { // Send a progress notification. ALOGV("videoEditor_processClip ITEM %d Progress indication %d", unuseditemID, progress); pEnv->CallVoidMethod(pContext->engine, pContext->onProgressUpdateMethodId, unuseditemID, progress); lastProgress = progress; } } // Check if processing has been completed. if (result == completionResult) { // Set the state to the completions state. pContext->state = completionState; ALOGV("videoEditor_processClip ITEM %d STATE changed to %d", unuseditemID, pContext->state); // Reset progress indication, as we switch to next state lastProgress = 0; // Reset error code, as we start a new round of processing result = M4NO_ERROR; // Check if we are analyzing input if (pContext->state == ManualEditState_OPENED) { // File is opened, we must start saving it ALOGV("videoEditor_processClip Calling M4xVSS_SaveStart()"); result = M4xVSS_SaveStart(pContext->engineContext, (M4OSA_Char*)pContext->pEditSettings->pOutputFile, (M4OSA_UInt32)pContext->pEditSettings->uiOutputPathSize); ALOGV("videoEditor_processClip ITEM %d SaveStart() returned 0x%x", unuseditemID, (unsigned int) result); // Set the state to saving. pContext->state = ManualEditState_SAVING; completionState = ManualEditState_SAVED; completionResult = M4VSS3GPP_WAR_SAVING_DONE; errorState = ManualEditState_SAVING_ERROR; // While saving, progress goes from 10 to 100 // except for Kenburn clip which goes from 50 to 100 if (M4OSA_TRUE == pContext->pEditSettings->pClipList[0]->xVSS.isPanZoom) { progressBase = 50; } else { progressBase = 10; } } // Check if we encoding is ongoing else if (pContext->state == ManualEditState_SAVED) { // Send a progress notification. progress = 100; ALOGV("videoEditor_processClip ITEM %d Last progress indication %d", unuseditemID, progress); pEnv->CallVoidMethod(pContext->engine, pContext->onProgressUpdateMethodId, unuseditemID, progress); // Stop the encoding. ALOGV("videoEditor_processClip Calling M4xVSS_SaveStop()"); result = M4xVSS_SaveStop(pContext->engineContext); ALOGV("videoEditor_processClip M4xVSS_SaveStop() returned 0x%x", result); } // Other states are unexpected else { result = M4ERR_STATE; ALOGE("videoEditor_processClip ITEM %d State ERROR 0x%x", unuseditemID, (unsigned int) result); } } // Check if an error occurred. if (result != M4NO_ERROR) { // Set the state to the error state. pContext->state = errorState; // Log the result. ALOGE("videoEditor_processClip ITEM %d Processing ERROR 0x%x", unuseditemID, (unsigned int) result); } } // Return the error result ALOGE("videoEditor_processClip ITEM %d END 0x%x", unuseditemID, (unsigned int) result); return result; } /*+ PROGRESS CB */ static int videoEditor_generateClip( JNIEnv* pEnv, jobject thiz, jobject settings) { bool loaded = true; ManualEditContext* pContext = M4OSA_NULL; M4OSA_ERR result = M4NO_ERROR; ALOGV("videoEditor_generateClip START"); // Get the context. pContext = (ManualEditContext*)videoEditClasses_getContext(&loaded, pEnv, thiz); Mutex::Autolock autoLock(pContext->mLock); // Validate the settings parameter. videoEditJava_checkAndThrowIllegalArgumentException(&loaded, pEnv, (NULL == settings), "settings is null"); // Make sure that the context was set. videoEditJava_checkAndThrowIllegalStateException(&loaded, pEnv, (M4OSA_NULL == pContext), "not initialized"); // Load the clip settings ALOGV("videoEditor_generateClip Calling videoEditor_loadSettings"); videoEditor_loadSettings(pEnv, thiz, settings); ALOGV("videoEditor_generateClip videoEditor_loadSettings returned"); // Generate the clip ALOGV("videoEditor_generateClip Calling LVME_processClip"); result = videoEditor_processClip(pEnv, thiz, 0 /*item id is unused*/); ALOGV("videoEditor_generateClip videoEditor_processClip returned 0x%x", result); if (pContext->state != ManualEditState_INITIALIZED) { // Free up memory (whatever the result) videoEditor_unloadSettings(pEnv, thiz); } ALOGV("videoEditor_generateClip END 0x%x", (unsigned int) result); return result; } static void videoEditor_loadSettings( JNIEnv* pEnv, jobject thiz, jobject settings) { bool needToBeLoaded = true; ManualEditContext* pContext = M4OSA_NULL; VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_loadSettings()"); // Add a code marker (the condition must always be true). ADD_CODE_MARKER_FUN(NULL != pEnv) // Get the context. pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz); // Validate the settings parameter. videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv, (NULL == settings), "settings is null"); // Make sure that the context was set. videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (M4OSA_NULL == pContext), "not initialized"); // Check if the context is valid (required because the context is dereferenced). if (needToBeLoaded) { // Make sure that we are in a correct state. videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv, (pContext->state != ManualEditState_INITIALIZED), "settings already loaded"); // Retrieve the edit settings. if(pContext->pEditSettings != M4OSA_NULL) { videoEditClasses_freeEditSettings(&pContext->pEditSettings); pContext->pEditSettings = M4OSA_NULL; } videoEditClasses_getEditSettings(&needToBeLoaded, pEnv, settings, &pContext->pEditSettings,true); } // Check if the edit settings could be retrieved. if (needToBeLoaded) { // Log the edit settings. VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "inside load settings"); VIDEOEDIT_LOG_EDIT_SETTINGS(pContext->pEditSettings); } ALOGV("videoEditor_loadSettings END"); } static void videoEditor_unloadSettings( JNIEnv* pEnv, jobject thiz) { bool needToBeUnLoaded = true; ManualEditContext* pContext = M4OSA_NULL; M4OSA_ERR result = M4NO_ERROR; VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_unloadSettings()"); // Get the context. pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeUnLoaded, pEnv, thiz); // Make sure that the context was set. videoEditJava_checkAndThrowIllegalStateException(&needToBeUnLoaded, pEnv, (M4OSA_NULL == pContext), "not initialized"); // Check if the context is valid (required because the context is dereferenced). if (needToBeUnLoaded) { ALOGV("videoEditor_unloadSettings state %d", pContext->state); // Make sure that we are in a correct state. videoEditJava_checkAndThrowIllegalStateException(&needToBeUnLoaded, pEnv, ((pContext->state != ManualEditState_ANALYZING ) && (pContext->state != ManualEditState_ANALYZING_ERROR) && (pContext->state != ManualEditState_OPENED ) && (pContext->state != ManualEditState_SAVING_ERROR ) && (pContext->state != ManualEditState_SAVED ) && (pContext->state != ManualEditState_STOPPING ) ), "videoEditor_unloadSettings no load settings in progress"); } // Check if we are in a correct state. if (needToBeUnLoaded) { // Check if the thread could be stopped. if (needToBeUnLoaded) { // Close the command. ALOGV("videoEditor_unloadSettings Calling M4xVSS_CloseCommand()"); result = M4xVSS_CloseCommand(pContext->engineContext); ALOGV("videoEditor_unloadSettings M4xVSS_CloseCommand() returned 0x%x", (unsigned int)result); // Check if the command could be closed. videoEditJava_checkAndThrowRuntimeException(&needToBeUnLoaded, pEnv, (M4NO_ERROR != result), result); } // Check if the command could be closed. if (needToBeUnLoaded) { // Free the edit settings. //videoEditClasses_freeEditSettings(&pContext->pEditSettings); // Reset the thread result. pContext->threadResult = M4NO_ERROR; // Reset the thread progress. pContext->threadProgress = 0; // Set the state to initialized. pContext->state = ManualEditState_INITIALIZED; } } } static void videoEditor_stopEncoding( JNIEnv* pEnv, jobject thiz) { bool stopped = true; ManualEditContext* pContext = M4OSA_NULL; M4OSA_ERR result = M4NO_ERROR; ALOGV("videoEditor_stopEncoding START"); // Get the context. pContext = (ManualEditContext*)videoEditClasses_getContext(&stopped, pEnv, thiz); // Change state and get Lock // This will ensure the generateClip function exits pContext->state = ManualEditState_STOPPING; Mutex::Autolock autoLock(pContext->mLock); // Make sure that the context was set. videoEditJava_checkAndThrowIllegalStateException(&stopped, pEnv, (M4OSA_NULL == pContext), "not initialized"); if (stopped) { // Check if the command should be closed. if (pContext->state != ManualEditState_INITIALIZED) { // Close the command. ALOGV("videoEditor_stopEncoding Calling M4xVSS_CloseCommand()"); result = M4xVSS_CloseCommand(pContext->engineContext); ALOGV("videoEditor_stopEncoding M4xVSS_CloseCommand() returned 0x%x", (unsigned int)result); } // Check if the command could be closed. videoEditJava_checkAndThrowRuntimeException(&stopped, pEnv, (M4NO_ERROR != result), result); // Free the edit settings. videoEditClasses_freeEditSettings(&pContext->pEditSettings); // Set the state to initialized. pContext->state = ManualEditState_INITIALIZED; } } static void videoEditor_release( JNIEnv* pEnv, jobject thiz) { bool released = true; ManualEditContext* pContext = M4OSA_NULL; M4OSA_ERR result = M4NO_ERROR; VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_release()"); // Add a text marker (the condition must always be true). ADD_TEXT_MARKER_FUN(NULL != pEnv) // Get the context. pContext = (ManualEditContext*)videoEditClasses_getContext(&released, pEnv, thiz); // If context is not set, return (we consider release already happened) if (pContext == NULL) { ALOGV("videoEditor_release Nothing to do, context is aleady NULL"); return; } // Check if the context is valid (required because the context is dereferenced). if (released) { if (pContext->state != ManualEditState_INITIALIZED) { // Change state and get Lock // This will ensure the generateClip function exits if it is running pContext->state = ManualEditState_STOPPING; Mutex::Autolock autoLock(pContext->mLock); } // Reset the context. videoEditClasses_setContext(&released, pEnv, thiz, (void *)M4OSA_NULL); // Check if the command should be closed. if (pContext->state != ManualEditState_INITIALIZED) { // Close the command. ALOGV("videoEditor_release Calling M4xVSS_CloseCommand() state =%d", pContext->state); result = M4xVSS_CloseCommand(pContext->engineContext); ALOGV("videoEditor_release M4xVSS_CloseCommand() returned 0x%x", (unsigned int)result); // Check if the command could be closed. videoEditJava_checkAndThrowRuntimeException(&released, pEnv, (M4NO_ERROR != result), result); } // Cleanup the engine. ALOGV("videoEditor_release Calling M4xVSS_CleanUp()"); result = M4xVSS_CleanUp(pContext->engineContext); ALOGV("videoEditor_release M4xVSS_CleanUp() returned 0x%x", (unsigned int)result); // Check if the cleanup succeeded. videoEditJava_checkAndThrowRuntimeException(&released, pEnv, (M4NO_ERROR != result), result); // Free the edit settings. videoEditClasses_freeEditSettings(&pContext->pEditSettings); pContext->pEditSettings = M4OSA_NULL; if(pContext->mPreviewController != M4OSA_NULL) { delete pContext->mPreviewController; pContext->mPreviewController = M4OSA_NULL; } // Free the mAudioSettings context. if(pContext->mAudioSettings != M4OSA_NULL) { if (pContext->mAudioSettings->pFile != NULL) { free(pContext->mAudioSettings->pFile); pContext->mAudioSettings->pFile = M4OSA_NULL; } if (pContext->mAudioSettings->pPCMFilePath != NULL) { free(pContext->mAudioSettings->pPCMFilePath); pContext->mAudioSettings->pPCMFilePath = M4OSA_NULL; } free(pContext->mAudioSettings); pContext->mAudioSettings = M4OSA_NULL; } // Free video Decoders capabilities if (pContext->decoders != M4OSA_NULL) { VideoDecoder *pDecoder = NULL; VideoComponentCapabilities *pComponents = NULL; int32_t decoderNumber = pContext->decoders->decoderNumber; if (pContext->decoders->decoder != NULL && decoderNumber > 0) { pDecoder = pContext->decoders->decoder; for (int32_t k = 0; k < decoderNumber; k++) { // free each component ALOGV("decoder index :%d",k); if (pDecoder != NULL && pDecoder->component != NULL && pDecoder->componentNumber > 0) { ALOGV("component number %d",pDecoder->componentNumber); int32_t componentNumber = pDecoder->componentNumber; pComponents = pDecoder->component; for (int32_t i = 0; i< componentNumber; i++) { ALOGV("component index :%d",i); if (pComponents != NULL && pComponents->profileLevel != NULL) { free(pComponents->profileLevel); pComponents->profileLevel = NULL; } pComponents++; } free(pDecoder->component); pDecoder->component = NULL; } pDecoder++; } free(pContext->decoders->decoder); pContext->decoders->decoder = NULL; } free(pContext->decoders); pContext->decoders = NULL; } videoEditor_freeContext(pEnv, &pContext); } } static int videoEditor_registerManualEditMethods( JNIEnv* pEnv) { int result = -1; VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_registerManualEditMethods()"); // Look up the engine class jclass engineClazz = pEnv->FindClass(MANUAL_EDIT_ENGINE_CLASS_NAME); // Clear any resulting exceptions. pEnv->ExceptionClear(); // Check if the engine class was found. if (NULL != engineClazz) { // Register all the methods. if (pEnv->RegisterNatives(engineClazz, gManualEditMethods, sizeof(gManualEditMethods) / sizeof(gManualEditMethods[0])) == JNI_OK) { // Success. result = 0; } } // Return the result. return(result); } /*******Audio Graph*******/ static M4OSA_UInt32 getDecibelSound(M4OSA_UInt32 value) { int dbSound = 1; if (value == 0) return 0; if (value > 0x4000 && value <= 0x8000) // 32768 dbSound = 90; else if (value > 0x2000 && value <= 0x4000) // 16384 dbSound = 84; else if (value > 0x1000 && value <= 0x2000) // 8192 dbSound = 78; else if (value > 0x0800 && value <= 0x1000) // 4028 dbSound = 72; else if (value > 0x0400 && value <= 0x0800) // 2048 dbSound = 66; else if (value > 0x0200 && value <= 0x0400) // 1024 dbSound = 60; else if (value > 0x0100 && value <= 0x0200) // 512 dbSound = 54; else if (value > 0x0080 && value <= 0x0100) // 256 dbSound = 48; else if (value > 0x0040 && value <= 0x0080) // 128 dbSound = 42; else if (value > 0x0020 && value <= 0x0040) // 64 dbSound = 36; else if (value > 0x0010 && value <= 0x0020) // 32 dbSound = 30; else if (value > 0x0008 && value <= 0x0010) //16 dbSound = 24; else if (value > 0x0007 && value <= 0x0008) //8 dbSound = 24; else if (value > 0x0003 && value <= 0x0007) // 4 dbSound = 18; else if (value > 0x0001 && value <= 0x0003) //2 dbSound = 12; else if (value > 0x000 && value == 0x0001) // 1 dbSound = 6; else dbSound = 0; return dbSound; } typedef struct { M4OSA_UInt8 *m_dataAddress; M4OSA_UInt32 m_bufferSize; } M4AM_Buffer; M4OSA_UInt8 logLookUp[256] = { 0,120,137,146,154,159,163,167,171,173,176,178,181,182,184,186,188,189,190,192,193, 194,195,196,198,199,199,200,201,202,203,204,205,205,206,207,207,208,209,209,210, 211,211,212,212,213,213,214,215,215,216,216,216,217,217,218,218,219,219,220,220, 220,221,221,222,222,222,223,223,223,224,224,224,225,225,225,226,226,226,227,227, 227,228,228,228,229,229,229,229,230,230,230,230,231,231,231,232,232,232,232,233, 233,233,233,233,234,234,234,234,235,235,235,235,236,236,236,236,236,237,237,237, 237,237,238,238,238,238,238,239,239,239,239,239,240,240,240,240,240,240,241,241, 241,241,241,241,242,242,242,242,242,242,243,243,243,243,243,243,244,244,244,244, 244,244,245,245,245,245,245,245,245,246,246,246,246,246,246,246,247,247,247,247, 247,247,247,247,248,248,248,248,248,248,248,249,249,249,249,249,249,249,249,250, 250,250,250,250,250,250,250,250,251,251,251,251,251,251,251,251,252,252,252,252, 252,252,252,252,252,253,253,253,253,253,253,253,253,253,253,254,254,254,254,254, 254,254,254,254,255,255,255,255,255,255,255,255,255,255,255}; M4OSA_ERR M4MA_generateAudioGraphFile(JNIEnv* pEnv, M4OSA_Char* pInputFileURL, M4OSA_Char* pOutFileURL, M4OSA_UInt32 samplesPerValue, M4OSA_UInt32 channels, M4OSA_UInt32 frameDuration, ManualEditContext* pContext) { M4OSA_ERR err; M4OSA_Context outFileHandle = M4OSA_NULL; M4OSA_Context inputFileHandle = M4OSA_NULL; M4AM_Buffer bufferIn = {0, 0}; M4OSA_UInt32 peakVolumeDbValue = 0; M4OSA_UInt32 samplesCountInBytes= 0 , numBytesToRead = 0, index = 0; M4OSA_UInt32 writeCount = 0, samplesCountBigEndian = 0, volumeValuesCount = 0; M4OSA_Int32 seekPos = 0; M4OSA_UInt32 fileSize = 0; M4OSA_UInt32 totalBytesRead = 0; M4OSA_UInt32 prevProgress = 0; bool threadStarted = true; int dbValue = 0; M4OSA_Int16 *ptr16 ; jclass engineClass = pEnv->FindClass(MANUAL_EDIT_ENGINE_CLASS_NAME); videoEditJava_checkAndThrowIllegalStateException(&threadStarted, pEnv, (M4OSA_NULL == engineClass), "not initialized"); /* register the call back function pointer */ pContext->onAudioGraphProgressUpdateMethodId = pEnv->GetMethodID(engineClass, "onAudioGraphExtractProgressUpdate", "(IZ)V"); /* ENTER */ VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "ENTER - M4MA_generateAudioGraphFile"); VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "Audio Graph samplesPerValue %d channels %d", samplesPerValue, channels); /****************************************************************************** OPEN INPUT AND OUTPUT FILES *******************************************************************************/ err = M4OSA_fileReadOpen (&inputFileHandle, pInputFileURL, M4OSA_kFileRead); if (inputFileHandle == M4OSA_NULL) { VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MA_generateAudioGraphFile: Cannot open input file 0x%lx", err); return err; } /* get the file size for progress */ err = M4OSA_fileReadGetOption(inputFileHandle, M4OSA_kFileReadGetFileSize, (M4OSA_Void**)&fileSize); if ( err != M4NO_ERROR) { //LVMEL_LOG_ERROR("M4MA_generateAudioGraphFile : File write failed \n"); jniThrowException(pEnv, "java/lang/IOException", "file size get option failed"); //return -1; } err = M4OSA_fileWriteOpen (&outFileHandle,(M4OSA_Char*) pOutFileURL, M4OSA_kFileCreate | M4OSA_kFileWrite); if (outFileHandle == M4OSA_NULL) { if (inputFileHandle != NULL) { M4OSA_fileReadClose(inputFileHandle); } return err; } /****************************************************************************** PROCESS THE SAMPLES *******************************************************************************/ samplesCountInBytes = (samplesPerValue * sizeof(M4OSA_UInt16) * channels); bufferIn.m_dataAddress = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc(samplesCountInBytes*sizeof(M4OSA_UInt16), 0, (M4OSA_Char*)"AudioGraph" ); if ( bufferIn.m_dataAddress != M4OSA_NULL) { bufferIn.m_bufferSize = samplesCountInBytes*sizeof(M4OSA_UInt16); } else { VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MA_generateAudioGraphFile: Malloc failed for bufferIn.m_dataAddress 0x%lx", M4ERR_ALLOC); return M4ERR_ALLOC; } /* sample to be converted to BIG endian ; store the frame duration */ samplesCountBigEndian = ((frameDuration>>24)&0xff) | // move byte 3 to byte 0 ((frameDuration<<8)&0xff0000) | // move byte 1 to byte 2 ((frameDuration>>8)&0xff00) | // move byte 2 to byte 1 ((frameDuration<<24)&0xff000000); // byte 0 to byte 3 /* write the samples per value supplied to out file */ err = M4OSA_fileWriteData (outFileHandle, (M4OSA_MemAddr8)&samplesCountBigEndian, sizeof(M4OSA_UInt32) ); if (err != M4NO_ERROR) { jniThrowException(pEnv, "java/lang/IOException", "file write failed"); } /* write UIn32 value 0 for no of values as place holder */ samplesCountBigEndian = 0; /* reusing local var */ err = M4OSA_fileWriteData (outFileHandle, (M4OSA_MemAddr8)&samplesCountBigEndian, sizeof(M4OSA_UInt32) ); if (err != M4NO_ERROR) { jniThrowException(pEnv, "java/lang/IOException", "file write failed"); } /* loop until EOF */ do { memset((void *)bufferIn.m_dataAddress,0,bufferIn.m_bufferSize); numBytesToRead = samplesCountInBytes; err = M4OSA_fileReadData( inputFileHandle, (M4OSA_MemAddr8)bufferIn.m_dataAddress, &numBytesToRead ); if (err != M4NO_ERROR) { // if out value of bytes-read is 0, break if ( numBytesToRead == 0) { VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "numBytesToRead 0x%lx", numBytesToRead); break; /* stop if file is empty or EOF */ } } ptr16 = (M4OSA_Int16*)bufferIn.m_dataAddress; peakVolumeDbValue = 0; index = 0; // loop through half the lenght frame bytes read 'cause its 16 bits samples while (index < (numBytesToRead / 2)) { /* absolute values of 16 bit sample */ if (ptr16[index] < 0) { ptr16[index] = -(ptr16[index]); } peakVolumeDbValue = (peakVolumeDbValue > (M4OSA_UInt32)ptr16[index] ?\ peakVolumeDbValue : (M4OSA_UInt32)ptr16[index]); index++; } // move 7 bits , ignore sign bit dbValue = (peakVolumeDbValue >> 7); dbValue = logLookUp[(M4OSA_UInt8)dbValue]; err = M4OSA_fileWriteData (outFileHandle, (M4OSA_MemAddr8)&dbValue, sizeof(M4OSA_UInt8) ); if (err != M4NO_ERROR) { VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MA_generateAudioGraphFile : File write failed"); break; } volumeValuesCount ++; totalBytesRead += numBytesToRead; if ((((totalBytesRead*100)/fileSize)) != prevProgress) { if ( (pContext->threadProgress != prevProgress) && (prevProgress != 0 )) { //pContext->threadProgress = prevProgress; //onWveformProgressUpdateMethodId(prevProgress, 0); //LVME_callAudioGraphOnProgressUpdate(pContext, 0, prevProgress); pEnv->CallVoidMethod(pContext->engine, pContext->onAudioGraphProgressUpdateMethodId, prevProgress, 0); VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "pContext->threadProgress %d", prevProgress); } } prevProgress = (((totalBytesRead*100)/fileSize)); } while (numBytesToRead != 0); VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "loop 0x%lx", volumeValuesCount); /* if some error occured in fwrite */ if (numBytesToRead != 0) { //err = -1; jniThrowException(pEnv, "java/lang/IOException", "numBytesToRead != 0 ; file write failed"); } /* write the count in place holder after seek */ seekPos = sizeof(M4OSA_UInt32); err = M4OSA_fileWriteSeek(outFileHandle, M4OSA_kFileSeekBeginning, &seekPos /* after samples per value */); if ( err != M4NO_ERROR) { jniThrowException(pEnv, "java/lang/IOException", "file seek failed"); } else { volumeValuesCount = ((volumeValuesCount>>24)&0xff) | // move byte 3 to byte 0 ((volumeValuesCount<<8)&0xff0000) | // move byte 1 to byte 2 ((volumeValuesCount>>8)&0xff00) | // move byte 2 to byte 1 ((volumeValuesCount<<24)&0xff000000); // byte 0 to byte 3 err = M4OSA_fileWriteData (outFileHandle, (M4OSA_MemAddr8)&volumeValuesCount, sizeof(M4OSA_UInt32) ); if ( err != M4NO_ERROR) { jniThrowException(pEnv, "java/lang/IOException", "file write failed"); } } /****************************************************************************** CLOSE AND FREE ALLOCATIONS *******************************************************************************/ free(bufferIn.m_dataAddress); M4OSA_fileReadClose(inputFileHandle); M4OSA_fileWriteClose(outFileHandle); /* final finish callback */ pEnv->CallVoidMethod(pContext->engine, pContext->onAudioGraphProgressUpdateMethodId, 100, 0); /* EXIT */ VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "EXIT - M4MA_generateAudioGraphFile"); return err; } static int videoEditor_generateAudioWaveFormSync (JNIEnv* pEnv, jobject thiz, jstring pcmfilePath, jstring outGraphfilePath, jint frameDuration, jint channels, jint samplesCount) { M4OSA_ERR result = M4NO_ERROR; ManualEditContext* pContext = M4OSA_NULL; bool needToBeLoaded = true; const char *pPCMFilePath, *pStringOutAudioGraphFile; VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_generateAudioWaveFormSync() "); /* Get the context. */ pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz); if (pContext == M4OSA_NULL) { VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_generateAudioWaveFormSync() - pContext is NULL "); } VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_generateAudioWaveFormSync Retrieving pStringOutAudioGraphFile"); pPCMFilePath = pEnv->GetStringUTFChars(pcmfilePath, NULL); if (pPCMFilePath == M4OSA_NULL) { jniThrowException(pEnv, "java/lang/RuntimeException", "Input string PCMFilePath is null"); result = M4ERR_PARAMETER; goto out; } pStringOutAudioGraphFile = pEnv->GetStringUTFChars(outGraphfilePath, NULL); if (pStringOutAudioGraphFile == M4OSA_NULL) { jniThrowException(pEnv, "java/lang/RuntimeException", "Input string outGraphfilePath is null"); result = M4ERR_PARAMETER; goto out2; } VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_generateAudioWaveFormSync Generate the waveform data %s %d %d %d", pStringOutAudioGraphFile, frameDuration, channels, samplesCount); /* Generate the waveform */ result = M4MA_generateAudioGraphFile(pEnv, (M4OSA_Char*) pPCMFilePath, (M4OSA_Char*) pStringOutAudioGraphFile, (M4OSA_UInt32) samplesCount, (M4OSA_UInt32) channels, (M4OSA_UInt32)frameDuration, pContext); pEnv->ReleaseStringUTFChars(outGraphfilePath, pStringOutAudioGraphFile); out2: if (pPCMFilePath != NULL) { pEnv->ReleaseStringUTFChars(pcmfilePath, pPCMFilePath); } out: VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_generateAudioWaveFormSync pContext->bSkipState "); return result; } /******** End Audio Graph *******/ jint JNI_OnLoad( JavaVM* pVm, void* pReserved) { void* pEnv = NULL; bool needToBeInitialized = true; jint result = -1; VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "JNI_OnLoad()"); // Add a text marker (the condition must always be true). ADD_TEXT_MARKER_FUN(NULL != pVm) // Check the JNI version. if (pVm->GetEnv(&pEnv, JNI_VERSION_1_4) == JNI_OK) { // Add a code marker (the condition must always be true). ADD_CODE_MARKER_FUN(NULL != pEnv) // Register the manual edit JNI methods. if (videoEditor_registerManualEditMethods((JNIEnv*)pEnv) == 0) { // Initialize the classes. videoEditClasses_init(&needToBeInitialized, (JNIEnv*)pEnv); if (needToBeInitialized) { // Success, return valid version number. result = JNI_VERSION_1_4; } } } // Return the result. return(result); }