1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#define LOG_NDEBUG 1
17#define LOG_TAG "VideoEditorMain"
18#include <dlfcn.h>
19#include <stdio.h>
20#include <unistd.h>
21#include <utils/Log.h>
22#include <utils/threads.h>
23#include <VideoEditorClasses.h>
24#include <VideoEditorJava.h>
25#include <VideoEditorOsal.h>
26#include <VideoEditorLogging.h>
27#include <marker.h>
28#include <VideoEditorClasses.h>
29#include <VideoEditorThumbnailMain.h>
30#include <M4OSA_Debug.h>
31#include <M4xVSS_Internal.h>
32#include <gui/Surface.h>
33#include "VideoEditorPreviewController.h"
34
35#include "VideoEditorMain.h"
36
37#include <android_runtime/android_view_Surface.h>
38
39extern "C" {
40#include <M4OSA_Clock.h>
41#include <M4OSA_CharStar.h>
42#include <M4OSA_Error.h>
43#include <M4OSA_FileCommon.h>
44#include <M4OSA_FileReader.h>
45#include <M4OSA_FileWriter.h>
46#include <M4OSA_Memory.h>
47#include <M4OSA_Thread.h>
48#include <M4xVSS_API.h>
49#include <M4VSS3GPP_ErrorCodes.h>
50#include <M4MCS_API.h>
51#include <M4MCS_ErrorCodes.h>
52#include <M4READER_Common.h>
53#include <M4WRITER_common.h>
54};
55
56
57using namespace android;
58
59#define THREAD_STACK_SIZE       (65536)
60
61#define VIDEOEDITOR_VERSION_MAJOR     0
62#define VIDEOEDITOR_VERSION_MINOR     0
63#define VIDEOEDITOR_VERSION_REVISION  1
64
65
66typedef enum
67{
68    ManualEditState_NOT_INITIALIZED,
69    ManualEditState_INITIALIZED,
70    ManualEditState_ANALYZING,
71    ManualEditState_ANALYZING_ERROR,
72    ManualEditState_OPENED,
73    ManualEditState_SAVING,
74    ManualEditState_SAVING_ERROR,
75    ManualEditState_SAVED,
76    ManualEditState_STOPPING
77} ManualEditState;
78
79typedef struct
80{
81    JavaVM*                        pVM;
82    jobject                        engine;
83    jmethodID                      onCompletionMethodId;
84    jmethodID                      onErrorMethodId;
85    jmethodID                      onWarningMethodId;
86    jmethodID                      onProgressUpdateMethodId;
87    jmethodID                      onPreviewProgressUpdateMethodId;
88    jmethodID                      previewFrameEditInfoId;
89    M4xVSS_InitParams              initParams;
90    void*                          pTextRendererHandle;
91    M4xVSS_getTextRgbBufferFct     pTextRendererFunction;
92    M4OSA_Context                  engineContext;
93    ManualEditState                state;
94    M4VSS3GPP_EditSettings*        pEditSettings;
95    M4OSA_Context                  threadContext;
96    M4OSA_ERR                      threadResult;
97    M4OSA_UInt8                    threadProgress;
98    VideoEditorPreviewController   *mPreviewController;
99    M4xVSS_AudioMixingSettings     *mAudioSettings;
100    /* Audio Graph changes */
101    M4OSA_Context                   pAudioGraphMCSCtx;
102    M4OSA_Bool                      bSkipState;
103    jmethodID                       onAudioGraphProgressUpdateMethodId;
104    Mutex                           mLock;
105    bool                            mIsUpdateOverlay;
106    char                            *mOverlayFileName;
107    int                             mOverlayRenderingMode;
108    M4DECODER_VideoDecoders* decoders;
109} ManualEditContext;
110
111extern "C" M4OSA_ERR M4MCS_open_normalMode(
112                M4MCS_Context                       pContext,
113                M4OSA_Void*                         pFileIn,
114                M4VIDEOEDITING_FileType             InputFileType,
115                M4OSA_Void*                         pFileOut,
116                M4OSA_Void*                         pTempFile);
117
118static M4OSA_ERR videoEditor_toUTF8Fct(
119                M4OSA_Void*                         pBufferIn,
120                M4OSA_UInt8*                        pBufferOut,
121                M4OSA_UInt32*                       bufferOutSize);
122
123static M4OSA_ERR videoEditor_fromUTF8Fct(
124                M4OSA_UInt8*                        pBufferIn,
125                M4OSA_Void*                         pBufferOut,
126                M4OSA_UInt32*                       bufferOutSize);
127
128static M4OSA_ERR videoEditor_getTextRgbBufferFct(
129                M4OSA_Void*                         pRenderingData,
130                M4OSA_Void*                         pTextBuffer,
131                M4OSA_UInt32                        textBufferSize,
132                M4VIFI_ImagePlane**                 pOutputPlane);
133
134static void videoEditor_callOnProgressUpdate(
135                ManualEditContext*                  pContext,
136                int                                 task,
137                int                                 progress);
138
139static void videoEditor_freeContext(
140                JNIEnv*                             pEnv,
141                ManualEditContext**                 ppContext);
142
143static M4OSA_ERR videoEditor_threadProc(
144                M4OSA_Void*                         param);
145
146static jobject videoEditor_getVersion(
147                JNIEnv*                             pEnv,
148                jobject                             thiz);
149
150static void videoEditor_init(
151                JNIEnv*                             pEnv,
152                jobject                             thiz,
153                jstring                             tempPath,
154                jstring                             textRendererPath);
155
156static void videoEditor_loadSettings(
157                JNIEnv*                             pEnv,
158                jobject                             thiz,
159                jobject                             settings);
160
161static void videoEditor_unloadSettings(
162                JNIEnv*                             pEnv,
163                jobject                             thiz);
164
165
166static void videoEditor_stopEncoding(
167                JNIEnv*                             pEnv,
168                jobject                             thiz);
169
170static void videoEditor_release(
171                JNIEnv*                             pEnv,
172                jobject                             thiz);
173static int videoEditor_getPixels(
174                                 JNIEnv*                  env,
175                                 jobject                  thiz,
176                                 jstring                  path,
177                                 jintArray                pixelArray,
178                                 M4OSA_UInt32             width,
179                                 M4OSA_UInt32             height,
180                                 M4OSA_UInt32             timeMS);
181static int videoEditor_getPixelsList(
182                                     JNIEnv*                  env,
183                                     jobject                  thiz,
184                                     jstring                  path,
185                                     jintArray                pixelArray,
186                                     M4OSA_UInt32             width,
187                                     M4OSA_UInt32             height,
188                                     M4OSA_UInt32             noOfThumbnails,
189                                     jlong                    startTime,
190                                     jlong                    endTime,
191                                     jintArray                indexArray,
192                                     jobject                  callback);
193
194static void
195videoEditor_startPreview(
196                JNIEnv*                 pEnv,
197                jobject                 thiz,
198                jobject                 mSurface,
199                jlong                   fromMs,
200                jlong                   toMs,
201                jint                    callbackInterval,
202                jboolean                loop);
203
204static void
205videoEditor_populateSettings(
206                JNIEnv*                 pEnv,
207                jobject                 thiz,
208                jobject                 settings,
209                jobject                 object,
210                jobject                 audioSettingObject);
211
212static int videoEditor_stopPreview(JNIEnv*  pEnv,
213                              jobject  thiz);
214
215static jobject
216videoEditor_getProperties(
217                JNIEnv*                             pEnv,
218                jobject                             thiz,
219                jstring                             file);
220
221static int videoEditor_renderPreviewFrame(JNIEnv* pEnv,
222                                    jobject thiz,
223                                    jobject    mSurface,
224                                    jlong fromMs,
225                                    jint  surfaceWidth,
226                                    jint  surfaceHeight);
227
228static int videoEditor_registerManualEditMethods(
229                JNIEnv*                             pEnv);
230
231static void jniPreviewProgressCallback(void* cookie, M4OSA_UInt32 msgType,
232                                        void *argc);
233
234static int videoEditor_renderMediaItemPreviewFrame(JNIEnv* pEnv,
235                                                    jobject thiz,
236                                                    jobject mSurface,
237                                                    jstring filePath,
238                                                    jint frameWidth,
239                                                    jint frameHeight,
240                                                    jint surfaceWidth,
241                                                    jint surfaceHeight,
242                                                    jlong fromMs);
243
244static int videoEditor_generateAudioWaveFormSync ( JNIEnv*     pEnv,
245                                                  jobject     thiz,
246                                                  jstring     pcmfilePath,
247                                                  jstring     outGraphfilePath,
248                                                  jint        frameDuration,
249                                                  jint        channels,
250                                                  jint        samplesCount);
251
252static int videoEditor_generateAudioRawFile(JNIEnv* pEnv,
253                                    jobject thiz,
254                                    jstring infilePath,
255                                    jstring pcmfilePath );
256
257M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext,
258                                    M4OSA_Char* infilePath,
259                                    M4OSA_Char* pcmfilePath );
260
261static int
262videoEditor_generateClip(
263                JNIEnv*                             pEnv,
264                jobject                             thiz,
265                jobject                             settings);
266
267static void videoEditor_clearSurface(JNIEnv* pEnv,
268                                    jobject thiz,
269                                    jobject surface);
270
271static JNINativeMethod gManualEditMethods[] = {
272    {"getVersion",               "()L"VERSION_CLASS_NAME";",
273                                (void *)videoEditor_getVersion      },
274    {"_init",                    "(Ljava/lang/String;Ljava/lang/String;)V",
275                                (void *)videoEditor_init    },
276    {"nativeStartPreview",       "(Landroid/view/Surface;JJIZ)V",
277                                (void *)videoEditor_startPreview    },
278    {"nativePopulateSettings",
279            "(L"EDIT_SETTINGS_CLASS_NAME";L"PREVIEW_PROPERTIES_CLASS_NAME";L"
280            AUDIO_SETTINGS_CLASS_NAME";)V",
281                                (void *)videoEditor_populateSettings    },
282    {"nativeRenderPreviewFrame", "(Landroid/view/Surface;JII)I",
283                                (int *)videoEditor_renderPreviewFrame     },
284    {"nativeRenderMediaItemPreviewFrame",
285    "(Landroid/view/Surface;Ljava/lang/String;IIIIJ)I",
286                        (int *)videoEditor_renderMediaItemPreviewFrame     },
287    {"nativeStopPreview",       "()I",
288                                (int *)videoEditor_stopPreview    },
289    {"stopEncoding",            "()V",
290                                (void *)videoEditor_stopEncoding         },
291    {"release",                 "()V",
292                                (void *)videoEditor_release            },
293    {"nativeGetPixels",         "(Ljava/lang/String;[IIIJ)I",
294                                (void*)videoEditor_getPixels               },
295    {"nativeGetPixelsList",     "(Ljava/lang/String;[IIIIJJ[ILandroid/media/videoeditor/MediaArtistNativeHelper$NativeGetPixelsListCallback;)I",
296                                (void*)videoEditor_getPixelsList           },
297    {"getMediaProperties",
298    "(Ljava/lang/String;)Landroid/media/videoeditor/MediaArtistNativeHelper$Properties;",
299                                (void *)videoEditor_getProperties          },
300    {"nativeGenerateAudioGraph","(Ljava/lang/String;Ljava/lang/String;III)I",
301                                (int *)videoEditor_generateAudioWaveFormSync },
302    {"nativeGenerateRawAudio",  "(Ljava/lang/String;Ljava/lang/String;)I",
303                                (int *)videoEditor_generateAudioRawFile      },
304    {"nativeGenerateClip",      "(L"EDIT_SETTINGS_CLASS_NAME";)I",
305                                (void *)videoEditor_generateClip  },
306    {"nativeClearSurface",       "(Landroid/view/Surface;)V",
307                                (void *)videoEditor_clearSurface  },
308};
309
310// temp file name of VSS out file
311#define TEMP_MCS_OUT_FILE_PATH "tmpOut.3gp"
312
313void
314getClipSetting(
315                JNIEnv*                                       pEnv,
316                jobject                                       object,
317                M4VSS3GPP_ClipSettings*                       pSettings)
318{
319
320    jfieldID fid;
321    int field = 0;
322    bool needToBeLoaded = true;
323    jclass clazz = pEnv->FindClass(PROPERTIES_CLASS_NAME);
324
325    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
326                                             (M4OSA_NULL == clazz),
327                                             "not initialized");
328
329    fid = pEnv->GetFieldID(clazz,"duration","I");
330    pSettings->ClipProperties.uiClipDuration = pEnv->GetIntField(object,fid);
331    M4OSA_TRACE1_1("duration = %d",pSettings->ClipProperties.uiClipDuration);
332
333    fid = pEnv->GetFieldID(clazz,"videoFormat","I");
334    pSettings->ClipProperties.VideoStreamType =
335        (M4VIDEOEDITING_VideoFormat)pEnv->GetIntField(object,fid);
336    M4OSA_TRACE1_1("videoFormat = %d",pSettings->ClipProperties.VideoStreamType);
337
338    fid = pEnv->GetFieldID(clazz,"videoDuration","I");
339    pSettings->ClipProperties.uiClipVideoDuration = pEnv->GetIntField(object,fid);
340    M4OSA_TRACE1_1("videoDuration = %d",
341                    pSettings->ClipProperties.uiClipVideoDuration);
342
343    fid = pEnv->GetFieldID(clazz,"width","I");
344    pSettings->ClipProperties.uiVideoWidth = pEnv->GetIntField(object,fid);
345    M4OSA_TRACE1_1("width = %d",pSettings->ClipProperties.uiVideoWidth);
346
347    fid = pEnv->GetFieldID(clazz,"height","I");
348    pSettings->ClipProperties.uiVideoHeight = pEnv->GetIntField(object,fid);
349    M4OSA_TRACE1_1("height = %d",pSettings->ClipProperties.uiVideoHeight);
350
351    fid = pEnv->GetFieldID(clazz,"audioFormat","I");
352    pSettings->ClipProperties.AudioStreamType =
353        (M4VIDEOEDITING_AudioFormat)pEnv->GetIntField(object,fid);
354    M4OSA_TRACE1_1("audioFormat = %d",pSettings->ClipProperties.AudioStreamType);
355
356    fid = pEnv->GetFieldID(clazz,"audioDuration","I");
357    pSettings->ClipProperties.uiClipAudioDuration = pEnv->GetIntField(object,fid);
358    M4OSA_TRACE1_1("audioDuration = %d",
359                    pSettings->ClipProperties.uiClipAudioDuration);
360
361    fid = pEnv->GetFieldID(clazz,"audioBitrate","I");
362    pSettings->ClipProperties.uiAudioBitrate = pEnv->GetIntField(object,fid);
363    M4OSA_TRACE1_1("audioBitrate = %d",pSettings->ClipProperties.uiAudioBitrate);
364
365    fid = pEnv->GetFieldID(clazz,"audioChannels","I");
366    pSettings->ClipProperties.uiNbChannels = pEnv->GetIntField(object,fid);
367    M4OSA_TRACE1_1("audioChannels = %d",pSettings->ClipProperties.uiNbChannels);
368
369    fid = pEnv->GetFieldID(clazz,"audioSamplingFrequency","I");
370    pSettings->ClipProperties.uiSamplingFrequency = pEnv->GetIntField(object,fid);
371    M4OSA_TRACE1_1("audioSamplingFrequency = %d",
372                    pSettings->ClipProperties.uiSamplingFrequency);
373
374   fid = pEnv->GetFieldID(clazz,"audioVolumeValue","I");
375   pSettings->ClipProperties.uiClipAudioVolumePercentage =
376                    pEnv->GetIntField(object,fid);
377   M4OSA_TRACE1_1("audioVolumeValue = %d",
378                    pSettings->ClipProperties.uiClipAudioVolumePercentage);
379
380   fid = pEnv->GetFieldID(clazz,"videoRotation","I");
381   pSettings->ClipProperties.videoRotationDegrees =
382                    pEnv->GetIntField(object,fid);
383   M4OSA_TRACE1_1("videoRotation = %d",
384                    pSettings->ClipProperties.videoRotationDegrees);
385
386   // Free the local references to avoid memory leaks
387   pEnv->DeleteLocalRef(clazz);
388}
389
390static void jniPreviewProgressCallback (void* cookie, M4OSA_UInt32 msgType,
391                                        void *argc)
392{
393    ManualEditContext *pContext = (ManualEditContext *)cookie;
394    JNIEnv*     pEnv = NULL;
395    bool        isFinished = false;
396    int         currentMs = 0;
397    int         error = M4NO_ERROR;
398    bool        isUpdateOverlay = false;
399    int         overlayEffectIndex;
400    char        *extPos;
401    bool        isSendProgress = true;
402    jstring     tmpFileName;
403    VideoEditorCurretEditInfo *pCurrEditInfo;
404
405    // Attach the current thread.
406    pContext->pVM->AttachCurrentThread(&pEnv, NULL);
407    switch(msgType)
408    {
409        case MSG_TYPE_PROGRESS_INDICATION:
410            currentMs = *(int*)argc;
411            break;
412        case MSG_TYPE_PLAYER_ERROR:
413            currentMs = -1;
414            error = *(int*)argc;
415            break;
416        case MSG_TYPE_PREVIEW_END:
417            isFinished = true;
418            break;
419        case MSG_TYPE_OVERLAY_UPDATE:
420        {
421            int overlayFileNameLen = 0;
422            isSendProgress = false;
423            pContext->mIsUpdateOverlay = true;
424            pCurrEditInfo = (VideoEditorCurretEditInfo*)argc;
425            overlayEffectIndex = pCurrEditInfo->overlaySettingsIndex;
426            ALOGV("MSG_TYPE_OVERLAY_UPDATE");
427
428            if (pContext->mOverlayFileName != NULL) {
429                free(pContext->mOverlayFileName);
430                pContext->mOverlayFileName = NULL;
431            }
432
433            overlayFileNameLen =
434                strlen((const char*)pContext->pEditSettings->Effects[overlayEffectIndex].xVSS.pFramingFilePath);
435
436            pContext->mOverlayFileName =
437                (char*)M4OSA_32bitAlignedMalloc(overlayFileNameLen+1,
438                                    M4VS, (M4OSA_Char*)"videoEdito JNI overlayFile");
439            if (pContext->mOverlayFileName != NULL) {
440                strncpy (pContext->mOverlayFileName,
441                    (const char*)pContext->pEditSettings->\
442                    Effects[overlayEffectIndex].xVSS.pFramingFilePath, overlayFileNameLen);
443                //Change the name to png file
444                extPos = strstr(pContext->mOverlayFileName, ".rgb");
445                if (extPos != NULL) {
446                    *extPos = '\0';
447                } else {
448                    ALOGE("ERROR the overlay file is incorrect");
449                }
450
451                strcat(pContext->mOverlayFileName, ".png");
452                ALOGV("Conv string is %s", pContext->mOverlayFileName);
453                ALOGV("Current Clip index = %d", pCurrEditInfo->clipIndex);
454
455                pContext->mOverlayRenderingMode = pContext->pEditSettings->\
456                         pClipList[pCurrEditInfo->clipIndex]->xVSS.MediaRendering;
457                ALOGV("rendering mode %d ", pContext->mOverlayRenderingMode);
458
459            }
460
461            break;
462        }
463
464        case MSG_TYPE_OVERLAY_CLEAR:
465            isSendProgress = false;
466            if (pContext->mOverlayFileName != NULL) {
467                free(pContext->mOverlayFileName);
468                pContext->mOverlayFileName = NULL;
469            }
470
471            ALOGV("MSG_TYPE_OVERLAY_CLEAR");
472            //argc is not used
473            pContext->mIsUpdateOverlay = true;
474            break;
475        default:
476            break;
477    }
478
479    if (isSendProgress) {
480        tmpFileName  = pEnv->NewStringUTF(pContext->mOverlayFileName);
481        pEnv->CallVoidMethod(pContext->engine,
482                pContext->onPreviewProgressUpdateMethodId,
483                currentMs,isFinished, pContext->mIsUpdateOverlay,
484                tmpFileName, pContext->mOverlayRenderingMode, error);
485
486        if (pContext->mIsUpdateOverlay) {
487            pContext->mIsUpdateOverlay = false;
488        }
489
490        if (tmpFileName) {
491            pEnv->DeleteLocalRef(tmpFileName);
492        }
493    }
494
495    // Detach the current thread.
496    pContext->pVM->DetachCurrentThread();
497
498}
499static M4OSA_ERR checkClipVideoProfileAndLevel(M4DECODER_VideoDecoders *pDecoders,
500    M4OSA_Int32 format, M4OSA_UInt32 profile, M4OSA_UInt32 level){
501
502    M4OSA_Int32 codec = 0;
503    M4OSA_Bool foundCodec = M4OSA_FALSE;
504    M4OSA_ERR  result = M4VSS3GPP_ERR_EDITING_UNSUPPORTED_VIDEO_PROFILE;
505    M4OSA_Bool foundProfile = M4OSA_FALSE;
506    ALOGV("checkClipVideoProfileAndLevel format %d profile;%d level:0x%x",
507       format, profile, level);
508
509    switch (format) {
510        case M4VIDEOEDITING_kH263:
511            codec = M4DA_StreamTypeVideoH263;
512            break;
513        case M4VIDEOEDITING_kH264:
514             codec = M4DA_StreamTypeVideoMpeg4Avc;
515            break;
516        case M4VIDEOEDITING_kMPEG4:
517             codec = M4DA_StreamTypeVideoMpeg4;
518            break;
519        case M4VIDEOEDITING_kNoneVideo:
520        case M4VIDEOEDITING_kNullVideo:
521        case M4VIDEOEDITING_kUnsupportedVideo:
522             // For these case we do not check the profile and level
523             return M4NO_ERROR;
524        default :
525            ALOGE("checkClipVideoProfileAndLevel unsupport Video format %ld", format);
526            break;
527    }
528
529    if (pDecoders != M4OSA_NULL && pDecoders->decoderNumber > 0) {
530        VideoDecoder *pVideoDecoder = pDecoders->decoder;
531        for(size_t k =0; k < pDecoders->decoderNumber; k++) {
532            if (pVideoDecoder != M4OSA_NULL) {
533                if (pVideoDecoder->codec == codec) {
534                    foundCodec = M4OSA_TRUE;
535                    break;
536                }
537            }
538            pVideoDecoder++;
539        }
540
541        if (foundCodec) {
542            VideoComponentCapabilities* pComponent = pVideoDecoder->component;
543            for (size_t i = 0; i < pVideoDecoder->componentNumber; i++) {
544                if (pComponent != M4OSA_NULL) {
545                    VideoProfileLevel *pProfileLevel = pComponent->profileLevel;
546                    for (size_t j =0; j < pComponent->profileNumber; j++) {
547                        // Check the profile and level
548                        if (pProfileLevel != M4OSA_NULL) {
549                            if (profile == pProfileLevel->mProfile) {
550                                foundProfile = M4OSA_TRUE;
551
552                                if (level <= pProfileLevel->mLevel) {
553                                    return M4NO_ERROR;
554                                }
555                            } else {
556                                foundProfile = M4OSA_FALSE;
557                            }
558                        }
559                        pProfileLevel++;
560                    }
561                }
562                pComponent++;
563            }
564        }
565    }
566
567    if (foundProfile) {
568        result = M4VSS3GPP_ERR_EDITING_UNSUPPORTED_VIDEO_LEVEL;
569    } else {
570        result = M4VSS3GPP_ERR_EDITING_UNSUPPORTED_VIDEO_PROFILE;
571    }
572
573    return result;
574}
575static int videoEditor_stopPreview(JNIEnv*  pEnv,
576                              jobject  thiz)
577{
578    ManualEditContext* pContext = M4OSA_NULL;
579    bool needToBeLoaded = true;
580    M4OSA_UInt32 lastProgressTimeMs = 0;
581
582    // Get the context.
583    pContext =
584            (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz);
585
586    // Make sure that the context was set.
587    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
588                                             (M4OSA_NULL == pContext),
589                                             "not initialized");
590    lastProgressTimeMs = pContext->mPreviewController->stopPreview();
591
592    if (pContext->mOverlayFileName != NULL) {
593        free(pContext->mOverlayFileName);
594        pContext->mOverlayFileName = NULL;
595    }
596
597    return lastProgressTimeMs;
598}
599
600static void videoEditor_clearSurface(JNIEnv* pEnv,
601                                    jobject thiz,
602                                    jobject surface)
603{
604    bool needToBeLoaded = true;
605    M4OSA_ERR result = M4NO_ERROR;
606    VideoEditor_renderPreviewFrameStr frameStr;
607    const char* pMessage = NULL;
608    // Let the size be QVGA
609    int width = 320;
610    int height = 240;
611    ManualEditContext* pContext = M4OSA_NULL;
612
613    // Get the context.
614    pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz);
615    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO,
616                                "VIDEO_EDITOR","pContext = 0x%x",pContext);
617
618    // Make sure that the context was set.
619    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
620                                             (M4OSA_NULL == pContext),
621                                             "not initialized");
622
623    // Make sure that the context was set.
624    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
625                                 (M4OSA_NULL == pContext->mPreviewController),
626                                 "not initialized");
627
628    // Validate the surface parameter.
629    videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv,
630                                                (NULL == surface),
631                                                "surface is null");
632
633    sp<Surface> previewSurface = android_view_Surface_getSurface(pEnv, surface);
634
635    // Validate the mSurface's mNativeSurface field
636    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
637                                                (NULL == previewSurface.get()),
638                                                "mNativeSurface is null");
639
640    frameStr.pBuffer = M4OSA_NULL;
641    frameStr.timeMs = 0;
642    frameStr.uiSurfaceWidth = width;
643    frameStr.uiSurfaceHeight = height;
644    frameStr.uiFrameWidth = width;
645    frameStr.uiFrameHeight = height;
646    frameStr.bApplyEffect = M4OSA_FALSE;
647    frameStr.clipBeginCutTime = 0;
648    frameStr.clipEndCutTime = 0;
649
650    result = pContext->mPreviewController->clearSurface(previewSurface,
651                                                              &frameStr);
652    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
653            (M4NO_ERROR != result), result);
654
655  }
656
657static int videoEditor_renderPreviewFrame(JNIEnv* pEnv,
658                                    jobject thiz,
659                                    jobject    mSurface,
660                                    jlong fromMs,
661                                    jint surfaceWidth,
662                                    jint surfaceHeight )
663{
664    bool needToBeLoaded = true;
665    M4OSA_ERR result = M4NO_ERROR;
666    M4OSA_UInt32 timeMs = (M4OSA_UInt32)fromMs;
667    M4OSA_UInt32 i=0,tnTimeMs = 0, framesizeYuv =0;
668    M4VIFI_UInt8 *pixelArray = M4OSA_NULL;
669    M4OSA_UInt32    iCurrentClipIndex = 0, uiNumberOfClipsInStoryBoard =0,
670                    uiClipDuration = 0, uiTotalClipDuration = 0,
671                    iIncrementedDuration = 0;
672    VideoEditor_renderPreviewFrameStr frameStr;
673    M4OSA_Context tnContext = M4OSA_NULL;
674    const char* pMessage = NULL;
675    M4VIFI_ImagePlane *yuvPlane = NULL;
676    VideoEditorCurretEditInfo  currEditInfo;
677
678    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO,
679        "VIDEO_EDITOR", "surfaceWidth = %d",surfaceWidth);
680    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO,
681        "VIDEO_EDITOR", "surfaceHeight = %d",surfaceHeight);
682    ManualEditContext* pContext = M4OSA_NULL;
683    // Get the context.
684    pContext =
685            (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz);
686    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO,
687                                "VIDEO_EDITOR","pContext = 0x%x",pContext);
688
689    // Make sure that the context was set.
690    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
691                                             (M4OSA_NULL == pContext),
692                                             "not initialized");
693
694    // Make sure that the context was set.
695    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
696                                 (M4OSA_NULL == pContext->mPreviewController),
697                                 "not initialized");
698
699    // Validate the mSurface parameter.
700    videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv,
701                                                (NULL == mSurface),
702                                                "mSurface is null");
703
704    sp<Surface> previewSurface = android_view_Surface_getSurface(pEnv, mSurface);
705
706    // Validate the mSurface's mNativeSurface field
707    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
708                                                (NULL == previewSurface.get()),
709                                                "mNativeSurface is null");
710
711    /* Determine the total number of clips, total duration*/
712    uiNumberOfClipsInStoryBoard = pContext->pEditSettings->uiClipNumber;
713
714    for (i = 0; i < uiNumberOfClipsInStoryBoard; i++) {
715        uiClipDuration = pContext->pEditSettings->pClipList[i]->uiEndCutTime -
716            pContext->pEditSettings->pClipList[i]->uiBeginCutTime;
717        uiTotalClipDuration += uiClipDuration;
718    }
719
720    /* determine the clip whose thumbnail needs to be rendered*/
721    if (timeMs == 0) {
722        iCurrentClipIndex = 0;
723        i=0;
724    } else {
725        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
726            "videoEditor_renderPreviewFrame() timeMs=%d", timeMs);
727
728        if (timeMs > uiTotalClipDuration) {
729            VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
730                "videoEditor_renderPreviewFrame() timeMs > uiTotalClipDuration");
731            pMessage = videoEditJava_getErrorName(M4ERR_PARAMETER);
732            jniThrowException(pEnv, "java/lang/IllegalArgumentException", pMessage);
733            return -1;
734        }
735
736        for (i = 0; i < uiNumberOfClipsInStoryBoard; i++) {
737            if (timeMs <= (iIncrementedDuration +
738                          (pContext->pEditSettings->pClipList[i]->uiEndCutTime -
739                           pContext->pEditSettings->pClipList[i]->uiBeginCutTime)))
740            {
741                iCurrentClipIndex = i;
742                VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
743                    "videoEditor_renderPreviewFrame() iCurrentClipIndex=%d for timeMs=%d",
744                    iCurrentClipIndex, timeMs);
745                break;
746            }
747            else {
748                iIncrementedDuration = iIncrementedDuration +
749                    (pContext->pEditSettings->pClipList[i]->uiEndCutTime -
750                    pContext->pEditSettings->pClipList[i]->uiBeginCutTime);
751            }
752        }
753    }
754    /* If timestamp is beyond story board duration, return*/
755    if (i >= uiNumberOfClipsInStoryBoard) {
756        if (timeMs == iIncrementedDuration) {
757            iCurrentClipIndex = i-1;
758        } else {
759           return -1;
760        }
761    }
762
763    /*+ Handle the image files here */
764      if (pContext->pEditSettings->pClipList[iCurrentClipIndex]->FileType ==
765          /*M4VIDEOEDITING_kFileType_JPG*/ M4VIDEOEDITING_kFileType_ARGB8888 ) {
766          VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", " iCurrentClipIndex %d ", iCurrentClipIndex);
767          VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
768                "  Height = %d",
769                pContext->pEditSettings->pClipList[iCurrentClipIndex]->ClipProperties.uiVideoHeight);
770
771          VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
772                "  Width = %d",
773                pContext->pEditSettings->pClipList[iCurrentClipIndex]->ClipProperties.uiVideoWidth);
774
775          LvGetImageThumbNail((const char *)pContext->pEditSettings->\
776          pClipList[iCurrentClipIndex]->pFile,
777            pContext->pEditSettings->pClipList[iCurrentClipIndex]->ClipProperties.uiVideoHeight,
778            pContext->pEditSettings->pClipList[iCurrentClipIndex]->ClipProperties.uiVideoWidth,
779            (M4OSA_Void **)&frameStr.pBuffer);
780            tnTimeMs = (M4OSA_UInt32)timeMs;
781
782          frameStr.videoRotationDegree = 0;
783    } else {
784        /* Handle 3gp/mp4 Clips here */
785        /* get thumbnail*/
786        result = ThumbnailOpen(&tnContext,
787            (const M4OSA_Char*)pContext->pEditSettings->\
788            pClipList[iCurrentClipIndex]->pFile, M4OSA_TRUE);
789        if (result != M4NO_ERROR || tnContext  == M4OSA_NULL) {
790            return -1;
791        }
792
793        /* timeMs is relative to storyboard; in this api it shud be relative to this clip */
794        if ((i >= uiNumberOfClipsInStoryBoard) &&
795            (timeMs == iIncrementedDuration)) {
796            tnTimeMs = pContext->pEditSettings->\
797            pClipList[iCurrentClipIndex]->uiEndCutTime;
798        } else {
799            tnTimeMs = pContext->pEditSettings->\
800            pClipList[iCurrentClipIndex]->uiBeginCutTime
801            + (timeMs - iIncrementedDuration);
802        }
803
804        VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
805            "video width = %d",pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
806            ClipProperties.uiVideoWidth);
807        VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
808            "video height = %d",pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
809            ClipProperties.uiVideoHeight);
810        VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
811            "current clip index = %d",iCurrentClipIndex);
812
813        M4OSA_UInt32 width = pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
814            ClipProperties.uiVideoWidth;
815        M4OSA_UInt32 height = pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
816            ClipProperties.uiVideoHeight;
817
818        framesizeYuv = width * height * 1.5;
819
820        pixelArray = (M4VIFI_UInt8 *)M4OSA_32bitAlignedMalloc(framesizeYuv, M4VS,
821            (M4OSA_Char*)"videoEditor pixelArray");
822        if (pixelArray == M4OSA_NULL) {
823            VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
824                "videoEditor_renderPreviewFrame() malloc error");
825            ThumbnailClose(tnContext);
826            pMessage = videoEditJava_getErrorName(M4ERR_ALLOC);
827            jniThrowException(pEnv, "java/lang/RuntimeException", pMessage);
828            return -1;
829        }
830
831        result = ThumbnailGetPixels16(tnContext, (M4OSA_Int16 *)pixelArray,
832            pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
833            ClipProperties.uiVideoWidth,
834            pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
835            ClipProperties.uiVideoHeight,
836            &tnTimeMs, 0);
837        if (result != M4NO_ERROR) {
838            free(pixelArray);
839            ThumbnailClose(tnContext);
840            return -1;
841        }
842
843        ThumbnailClose(tnContext);
844        tnContext = M4OSA_NULL;
845
846#ifdef DUMPTOFILE
847        {
848            M4OSA_Context fileContext;
849            M4OSA_Char* fileName = (M4OSA_Char*)"/mnt/sdcard/FirstRGB565.raw";
850            remove((const char *)fileName);
851            M4OSA_fileWriteOpen(&fileContext, (M4OSA_Void*) fileName,\
852                M4OSA_kFileWrite|M4OSA_kFileCreate);
853            M4OSA_fileWriteData(fileContext, (M4OSA_MemAddr8) pixelArray,
854                framesizeYuv);
855            M4OSA_fileWriteClose(fileContext);
856        }
857#endif
858
859        /**
860        * Allocate output YUV planes
861        */
862        yuvPlane = (M4VIFI_ImagePlane*)M4OSA_32bitAlignedMalloc(3*sizeof(M4VIFI_ImagePlane), M4VS,
863            (M4OSA_Char*)"videoEditor_renderPreviewFrame Output plane YUV");
864        if (yuvPlane == M4OSA_NULL) {
865            VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
866                "videoEditor_renderPreviewFrame() malloc error for yuv plane");
867            free(pixelArray);
868            pMessage = videoEditJava_getErrorName(M4ERR_ALLOC);
869            jniThrowException(pEnv, "java/lang/RuntimeException", pMessage);
870            return -1;
871        }
872
873        yuvPlane[0].u_width = width;
874        yuvPlane[0].u_height = height;
875        yuvPlane[0].u_topleft = 0;
876        yuvPlane[0].u_stride = width;
877        yuvPlane[0].pac_data = (M4VIFI_UInt8*)pixelArray;
878
879        yuvPlane[1].u_width = width>>1;
880        yuvPlane[1].u_height = height>>1;
881        yuvPlane[1].u_topleft = 0;
882        yuvPlane[1].u_stride = width>>1;
883        yuvPlane[1].pac_data = yuvPlane[0].pac_data
884                    + yuvPlane[0].u_width * yuvPlane[0].u_height;
885        yuvPlane[2].u_width = (width)>>1;
886        yuvPlane[2].u_height = (height)>>1;
887        yuvPlane[2].u_topleft = 0;
888        yuvPlane[2].u_stride = (width)>>1;
889        yuvPlane[2].pac_data = yuvPlane[1].pac_data
890                    + yuvPlane[1].u_width * yuvPlane[1].u_height;
891
892#ifdef DUMPTOFILE
893        {
894            M4OSA_Context fileContext;
895            M4OSA_Char* fileName = (M4OSA_Char*)"/mnt/sdcard/ConvertedYuv.yuv";
896            remove((const char *)fileName);
897            M4OSA_fileWriteOpen(&fileContext, (M4OSA_Void*) fileName,\
898                M4OSA_kFileWrite|M4OSA_kFileCreate);
899            M4OSA_fileWriteData(fileContext,
900                (M4OSA_MemAddr8) yuvPlane[0].pac_data, framesizeYuv);
901            M4OSA_fileWriteClose(fileContext);
902        }
903#endif
904
905        /* Fill up the render structure*/
906        frameStr.pBuffer = (M4OSA_Void*)yuvPlane[0].pac_data;
907
908        frameStr.videoRotationDegree = pContext->pEditSettings->\
909            pClipList[iCurrentClipIndex]->ClipProperties.videoRotationDegrees;
910    }
911
912    frameStr.timeMs = timeMs;    /* timestamp on storyboard*/
913    frameStr.uiSurfaceWidth =
914        pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
915        ClipProperties.uiVideoWidth;
916    frameStr.uiSurfaceHeight =
917        pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
918        ClipProperties.uiVideoHeight;
919    frameStr.uiFrameWidth =
920        pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
921        ClipProperties.uiVideoWidth;
922    frameStr.uiFrameHeight =
923        pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
924        ClipProperties.uiVideoHeight;
925    if (pContext->pEditSettings->nbEffects > 0) {
926        frameStr.bApplyEffect = M4OSA_TRUE;
927    } else {
928        frameStr.bApplyEffect = M4OSA_FALSE;
929    }
930    frameStr.clipBeginCutTime = iIncrementedDuration;
931    frameStr.clipEndCutTime =
932        iIncrementedDuration +
933        (pContext->pEditSettings->pClipList[iCurrentClipIndex]->uiEndCutTime -\
934        pContext->pEditSettings->pClipList[iCurrentClipIndex]->uiBeginCutTime);
935
936    pContext->mPreviewController->setPreviewFrameRenderingMode(
937        pContext->pEditSettings->\
938        pClipList[iCurrentClipIndex]->xVSS.MediaRendering,
939        pContext->pEditSettings->xVSS.outputVideoSize);
940    result = pContext->mPreviewController->renderPreviewFrame(previewSurface,
941                                                              &frameStr, &currEditInfo);
942
943    if (currEditInfo.overlaySettingsIndex != -1) {
944        char tmpOverlayFilename[100];
945        char *extPos = NULL;
946        jstring tmpOverlayString;
947        int tmpRenderingMode = 0;
948
949        strncpy (tmpOverlayFilename,
950                (const char*)pContext->pEditSettings->Effects[currEditInfo.overlaySettingsIndex].xVSS.pFramingFilePath, 99);
951
952        //Change the name to png file
953        extPos = strstr(tmpOverlayFilename, ".rgb");
954        if (extPos != NULL) {
955            *extPos = '\0';
956        } else {
957            ALOGE("ERROR the overlay file is incorrect");
958        }
959
960        strcat(tmpOverlayFilename, ".png");
961
962        tmpRenderingMode = pContext->pEditSettings->pClipList[iCurrentClipIndex]->xVSS.MediaRendering;
963        tmpOverlayString = pEnv->NewStringUTF(tmpOverlayFilename);
964        pEnv->CallVoidMethod(pContext->engine,
965            pContext->previewFrameEditInfoId,
966            tmpOverlayString, tmpRenderingMode);
967
968    }
969
970    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
971            (M4NO_ERROR != result), result);
972
973    free(frameStr.pBuffer);
974    if (pContext->pEditSettings->pClipList[iCurrentClipIndex]->FileType !=
975            M4VIDEOEDITING_kFileType_ARGB8888) {
976        free(yuvPlane);
977    }
978
979    return tnTimeMs;
980}
981
982static int videoEditor_renderMediaItemPreviewFrame(JNIEnv* pEnv,
983                                                    jobject thiz,
984                                                    jobject mSurface,
985                                                    jstring filePath,
986                                                    jint    frameWidth,
987                                                    jint    frameHeight,
988                                                    jint    surfaceWidth,
989                                                    jint    surfaceHeight,
990                                                    jlong   fromMs)
991{
992    bool needToBeLoaded = true;
993    M4OSA_ERR result = M4NO_ERROR;
994    M4OSA_UInt32 timeMs = (M4OSA_UInt32)fromMs;
995    M4OSA_UInt32 framesizeYuv =0;
996    M4VIFI_UInt8 *pixelArray = M4OSA_NULL;
997    VideoEditor_renderPreviewFrameStr frameStr;
998    M4OSA_Context tnContext = M4OSA_NULL;
999    const char* pMessage = NULL;
1000    M4VIFI_ImagePlane yuvPlane[3], rgbPlane;
1001
1002    ManualEditContext* pContext = M4OSA_NULL;
1003    // Get the context.
1004    pContext =
1005            (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded,
1006                                                      pEnv, thiz);
1007
1008    // Make sure that the context was set.
1009    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
1010                                             (M4OSA_NULL == pContext),
1011                                             "not initialized");
1012
1013    // Make sure that the context was set.
1014    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
1015                                 (M4OSA_NULL == pContext->mPreviewController),
1016                                 "not initialized");
1017
1018    // Validate the mSurface parameter.
1019    videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv,
1020                                                (NULL == mSurface),
1021                                                "mSurface is null");
1022
1023    sp<Surface> previewSurface = android_view_Surface_getSurface(pEnv, mSurface);
1024
1025    const char *pString = pEnv->GetStringUTFChars(filePath, NULL);
1026    if (pString == M4OSA_NULL) {
1027        if (pEnv != NULL) {
1028            jniThrowException(pEnv, "java/lang/RuntimeException", "Input string null");
1029        }
1030    }
1031    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
1032        "videoEditor_renderMediaItemPreviewFrame() timeMs=%d", timeMs);
1033    /* get thumbnail*/
1034    result = ThumbnailOpen(&tnContext,(const M4OSA_Char*)pString, M4OSA_TRUE);
1035    if (result != M4NO_ERROR || tnContext  == M4OSA_NULL) {
1036        return timeMs;
1037    }
1038
1039    framesizeYuv = ((frameWidth)*(frameHeight)*1.5);
1040
1041    pixelArray = (M4VIFI_UInt8 *)M4OSA_32bitAlignedMalloc(framesizeYuv, M4VS,\
1042        (M4OSA_Char*)"videoEditor pixelArray");
1043    if (pixelArray == M4OSA_NULL) {
1044        VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
1045            "videoEditor_renderPreviewFrame() malloc error");
1046        ThumbnailClose(tnContext);
1047        pMessage = videoEditJava_getErrorName(M4ERR_ALLOC);
1048        jniThrowException(pEnv, "java/lang/RuntimeException", pMessage);
1049        return timeMs;
1050    }
1051
1052    result = ThumbnailGetPixels16(tnContext, (M4OSA_Int16 *)pixelArray,
1053                                                frameWidth,
1054                                                frameHeight, &timeMs, 0);
1055    if (result != M4NO_ERROR) {
1056        free(pixelArray);
1057        ThumbnailClose(tnContext);
1058        return fromMs;
1059    }
1060
1061#ifdef DUMPTOFILESYSTEM
1062    {
1063        M4OSA_Context fileContext;
1064        M4OSA_Char* fileName = (M4OSA_Char*)"/mnt/sdcard/FirstRGB565.rgb";
1065        M4OSA_fileWriteOpen(&fileContext, (M4OSA_Void*) fileName,\
1066            M4OSA_kFileWrite|M4OSA_kFileCreate);
1067        M4OSA_fileWriteData(fileContext, (M4OSA_MemAddr8) pixelArray,
1068                            framesizeRgb);
1069        M4OSA_fileWriteClose(fileContext);
1070    }
1071#endif
1072
1073    yuvPlane[0].pac_data = (M4VIFI_UInt8*)pixelArray;
1074    yuvPlane[0].u_height = frameHeight;
1075    yuvPlane[0].u_width = frameWidth;
1076    yuvPlane[0].u_stride = yuvPlane[0].u_width;
1077    yuvPlane[0].u_topleft = 0;
1078
1079    yuvPlane[1].u_height = frameHeight/2;
1080    yuvPlane[1].u_width = frameWidth/2;
1081    yuvPlane[1].u_stride = yuvPlane[1].u_width;
1082    yuvPlane[1].u_topleft = 0;
1083    yuvPlane[1].pac_data = yuvPlane[0].pac_data
1084                + yuvPlane[0].u_width*yuvPlane[0].u_height;
1085
1086    yuvPlane[2].u_height = frameHeight/2;
1087    yuvPlane[2].u_width = frameWidth/2;
1088    yuvPlane[2].u_stride = yuvPlane[2].u_width;
1089    yuvPlane[2].u_topleft = 0;
1090    yuvPlane[2].pac_data = yuvPlane[0].pac_data
1091        + yuvPlane[0].u_width*yuvPlane[0].u_height + \
1092        (yuvPlane[0].u_width/2)*(yuvPlane[0].u_height/2);
1093#ifdef DUMPTOFILESYSTEM
1094    {
1095        M4OSA_Context fileContext;
1096        M4OSA_Char* fileName = (M4OSA_Char*)"/mnt/sdcard/ConvertedYuv.yuv";
1097        M4OSA_fileWriteOpen(&fileContext, (M4OSA_Void*) fileName,\
1098            M4OSA_kFileWrite|M4OSA_kFileCreate);
1099        M4OSA_fileWriteData(fileContext, (M4OSA_MemAddr8) yuvPlane[0].pac_data,
1100                            framesizeYuv);
1101        M4OSA_fileWriteClose(fileContext);
1102    }
1103#endif
1104
1105    /* Fill up the render structure*/
1106    frameStr.pBuffer = (M4OSA_Void*)yuvPlane[0].pac_data;
1107    frameStr.timeMs = timeMs;    /* timestamp on storyboard*/
1108    frameStr.uiSurfaceWidth = frameWidth;
1109    frameStr.uiSurfaceHeight = frameHeight;
1110    frameStr.uiFrameWidth = frameWidth;
1111    frameStr.uiFrameHeight = frameHeight;
1112    frameStr.bApplyEffect = M4OSA_FALSE;
1113    // clip begin cuttime and end cuttime set to 0
1114    // as its only required when effect needs to be applied while rendering
1115    frameStr.clipBeginCutTime = 0;
1116    frameStr.clipEndCutTime = 0;
1117
1118    /*  pContext->mPreviewController->setPreviewFrameRenderingMode(M4xVSS_kBlackBorders,
1119    (M4VIDEOEDITING_VideoFrameSize)(M4VIDEOEDITING_kHD960+1));*/
1120    result
1121    = pContext->mPreviewController->renderPreviewFrame(previewSurface,&frameStr, NULL);
1122    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
1123                                                (M4NO_ERROR != result), result);
1124
1125    /* free the pixelArray and yuvPlane[0].pac_data */
1126    free(yuvPlane[0].pac_data);
1127
1128    ThumbnailClose(tnContext);
1129
1130    if (pString != NULL) {
1131        pEnv->ReleaseStringUTFChars(filePath, pString);
1132    }
1133
1134    return timeMs;
1135}
1136
1137int videoEditor_generateAudioRawFile(   JNIEnv*     pEnv,
1138                                        jobject     thiz,
1139                                        jstring     infilePath,
1140                                        jstring     pcmfilePath)
1141{
1142    M4OSA_ERR result = M4NO_ERROR;
1143    bool               loaded   = true;
1144    ManualEditContext* pContext = M4OSA_NULL;
1145
1146
1147
1148    const char *pInputFile = pEnv->GetStringUTFChars(infilePath, NULL);
1149    if (pInputFile == M4OSA_NULL) {
1150        if (pEnv != NULL) {
1151            jniThrowException(pEnv, "java/lang/RuntimeException", "Input string null");
1152        }
1153    }
1154
1155    const char *pStringOutPCMFilePath = pEnv->GetStringUTFChars(pcmfilePath, NULL);
1156    if (pStringOutPCMFilePath == M4OSA_NULL) {
1157        if (pEnv != NULL) {
1158            jniThrowException(pEnv, "java/lang/RuntimeException", "Input string null");
1159        }
1160    }
1161
1162    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO,
1163        "VIDEO_EDITOR", "videoEditor_generateAudioRawFile infilePath %s",
1164        pInputFile);
1165    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO,
1166        "VIDEO_EDITOR", "videoEditor_generateAudioRawFile pcmfilePath %s",
1167        pStringOutPCMFilePath);
1168    // Get the context.
1169    pContext = (ManualEditContext*)videoEditClasses_getContext(&loaded, pEnv, thiz);
1170
1171    result = videoEditor_generateAudio( pEnv, pContext, (M4OSA_Char*)pInputFile,
1172        (M4OSA_Char*)pStringOutPCMFilePath);
1173
1174    if (pInputFile != NULL) {
1175        pEnv->ReleaseStringUTFChars(infilePath, pInputFile);
1176    }
1177    if (pStringOutPCMFilePath != NULL) {
1178        pEnv->ReleaseStringUTFChars(pcmfilePath, pStringOutPCMFilePath);
1179    }
1180
1181    return result;
1182}
1183
1184M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext,
1185                                    M4OSA_Char* infilePath,
1186                                    M4OSA_Char* pcmfilePath )
1187{
1188    bool                            needToBeLoaded = true;
1189    M4OSA_ERR                       result = M4NO_ERROR;
1190    M4MCS_Context                   mcsContext = M4OSA_NULL;
1191    M4OSA_Char*                     pInputFile = M4OSA_NULL;
1192    M4OSA_Char*                     pOutputFile = M4OSA_NULL;
1193    M4OSA_Char*                     pTempPath = M4OSA_NULL;
1194    M4MCS_OutputParams*             pOutputParams = M4OSA_NULL;
1195    M4MCS_EncodingParams*           pEncodingParams = M4OSA_NULL;
1196    M4OSA_Int32                     pInputFileType = 0;
1197    M4OSA_UInt8                     threadProgress = 0;
1198    M4OSA_Char*                     pTemp3gpFilePath = M4OSA_NULL;
1199
1200    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_generateAudio()");
1201
1202    videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv,
1203        (NULL == pContext),
1204        "ManualEditContext is null");
1205
1206    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_init()");
1207
1208    pOutputParams = (M4MCS_OutputParams *)M4OSA_32bitAlignedMalloc(
1209        sizeof(M4MCS_OutputParams),0x00,
1210        (M4OSA_Char *)"M4MCS_OutputParams");
1211    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
1212        (M4OSA_NULL == pOutputParams),
1213        "not initialized");
1214    if (needToBeLoaded == false) {
1215        return M4ERR_ALLOC;
1216    }
1217
1218    pEncodingParams = (M4MCS_EncodingParams *)M4OSA_32bitAlignedMalloc(
1219        sizeof(M4MCS_EncodingParams),0x00,
1220        (M4OSA_Char *)"M4MCS_EncodingParams");
1221    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
1222        (M4OSA_NULL == pEncodingParams),
1223        "not initialized");
1224    if (needToBeLoaded == false) {
1225        free(pEncodingParams);
1226        pEncodingParams = M4OSA_NULL;
1227        return M4ERR_ALLOC;
1228    }
1229
1230    // Initialize the MCS library.
1231    result = M4MCS_init(&mcsContext, pContext->initParams.pFileReadPtr,
1232        pContext->initParams.pFileWritePtr);
1233    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,\
1234        (M4NO_ERROR != result), result);
1235    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
1236        (M4OSA_NULL == mcsContext),
1237        "not initialized");
1238     if(needToBeLoaded == false) {
1239         free(pOutputParams);
1240         pOutputParams = M4OSA_NULL;
1241         free(pEncodingParams);
1242         pEncodingParams = M4OSA_NULL;
1243         return result;
1244     }
1245
1246    // generate the path for temp 3gp output file
1247    pTemp3gpFilePath = (M4OSA_Char*) M4OSA_32bitAlignedMalloc (
1248        (strlen((const char*)pContext->initParams.pTempPath)
1249        + strlen((const char*)TEMP_MCS_OUT_FILE_PATH)) + 1 /* for null termination */ , 0x0,
1250        (M4OSA_Char*)"Malloc for temp 3gp file");
1251    if (pTemp3gpFilePath != M4OSA_NULL)
1252    {
1253        memset((void *)pTemp3gpFilePath  ,0,
1254            strlen((const char*)pContext->initParams.pTempPath)
1255            + strlen((const char*)TEMP_MCS_OUT_FILE_PATH) + 1);
1256        strncat((char *)pTemp3gpFilePath,
1257            (const char *)pContext->initParams.pTempPath  ,
1258            (size_t) ((M4OSA_Char*)pContext->initParams.pTempPath));
1259        strncat((char *)pTemp3gpFilePath , (const char *)TEMP_MCS_OUT_FILE_PATH,
1260            (size_t)strlen ((const char*)TEMP_MCS_OUT_FILE_PATH));
1261    }
1262    else {
1263         M4MCS_abort(mcsContext);
1264         free(pOutputParams);
1265         pOutputParams = M4OSA_NULL;
1266         free(pEncodingParams);
1267         pEncodingParams = M4OSA_NULL;
1268         return M4ERR_ALLOC;
1269    }
1270
1271    pInputFile = (M4OSA_Char *) infilePath; //pContext->mAudioSettings->pFile;
1272    //Delete this file later
1273    pOutputFile = (M4OSA_Char *) pTemp3gpFilePath;
1274    // Temp folder path for VSS use = ProjectPath
1275    pTempPath = (M4OSA_Char *) pContext->initParams.pTempPath;
1276    pInputFileType = (M4VIDEOEDITING_FileType)pContext->mAudioSettings->fileType;
1277
1278    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "TEMP_MCS_OUT_FILE_PATH len %d",
1279        strlen ((const char*)TEMP_MCS_OUT_FILE_PATH));
1280    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "pTemp3gpFilePath %s",
1281        pOutputFile);
1282
1283    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_open()");
1284
1285    result = M4MCS_open(mcsContext, pInputFile,
1286        (M4VIDEOEDITING_FileType)pInputFileType,
1287        pOutputFile, pTempPath);
1288    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
1289        (M4NO_ERROR != result), result);
1290    if(needToBeLoaded == false) {
1291         free(pTemp3gpFilePath);
1292         pTemp3gpFilePath = M4OSA_NULL;
1293         M4MCS_abort(mcsContext);
1294         free(pOutputParams);
1295         pOutputParams = M4OSA_NULL;
1296         free(pEncodingParams);
1297         pEncodingParams = M4OSA_NULL;
1298         return result;
1299    }
1300
1301    pOutputParams->OutputFileType
1302        = (M4VIDEOEDITING_FileType)M4VIDEOEDITING_kFileType_3GPP;
1303    // Set the video format.
1304    pOutputParams->OutputVideoFormat =
1305        (M4VIDEOEDITING_VideoFormat)M4VIDEOEDITING_kNoneVideo;//M4VIDEOEDITING_kNoneVideo;
1306    pOutputParams->outputVideoProfile = 1;
1307    pOutputParams->outputVideoLevel = 1;
1308    // Set the frame size.
1309    pOutputParams->OutputVideoFrameSize
1310        = (M4VIDEOEDITING_VideoFrameSize)M4VIDEOEDITING_kQCIF;
1311    // Set the frame rate.
1312    pOutputParams->OutputVideoFrameRate
1313        = (M4VIDEOEDITING_VideoFramerate)M4VIDEOEDITING_k5_FPS;
1314
1315    // Set the audio format.
1316    pOutputParams->OutputAudioFormat
1317        = (M4VIDEOEDITING_AudioFormat)M4VIDEOEDITING_kAAC;
1318    // Set the audio sampling frequency.
1319    pOutputParams->OutputAudioSamplingFrequency =
1320        (M4VIDEOEDITING_AudioSamplingFrequency)M4VIDEOEDITING_k32000_ASF;
1321    // Set the audio mono.
1322    pOutputParams->bAudioMono = false;
1323    // Set the pcm file; null for now.
1324    pOutputParams->pOutputPCMfile = (M4OSA_Char *)pcmfilePath;
1325    //(M4OSA_Char *)"/sdcard/Output/AudioPcm.pcm";
1326    // Set the audio sampling frequency.
1327    pOutputParams->MediaRendering = (M4MCS_MediaRendering)M4MCS_kCropping;
1328    // new params after integrating MCS 2.0
1329    // Set the number of audio effects; 0 for now.
1330    pOutputParams->nbEffects = 0;
1331    // Set the audio effect; null for now.
1332    pOutputParams->pEffects = NULL;
1333    // Set the audio effect; null for now.
1334    pOutputParams->bDiscardExif = M4OSA_FALSE;
1335    // Set the audio effect; null for now.
1336    pOutputParams->bAdjustOrientation = M4OSA_FALSE;
1337
1338    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_setOutputParams()");
1339    result = M4MCS_setOutputParams(mcsContext, pOutputParams);
1340    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
1341                                        (M4NO_ERROR != result), result);
1342    if (needToBeLoaded == false) {
1343         free(pTemp3gpFilePath);
1344         pTemp3gpFilePath = M4OSA_NULL;
1345         M4MCS_abort(mcsContext);
1346         free(pOutputParams);
1347         pOutputParams = M4OSA_NULL;
1348         free(pEncodingParams);
1349         pEncodingParams = M4OSA_NULL;
1350        return result;
1351    }
1352    // Set the video bitrate.
1353    pEncodingParams->OutputVideoBitrate =
1354    (M4VIDEOEDITING_Bitrate)M4VIDEOEDITING_kUndefinedBitrate;
1355    // Set the audio bitrate.
1356    pEncodingParams->OutputAudioBitrate
1357        = (M4VIDEOEDITING_Bitrate)M4VIDEOEDITING_k128_KBPS;
1358    // Set the end cut time in milliseconds.
1359    pEncodingParams->BeginCutTime = 0;
1360    // Set the end cut time in milliseconds.
1361    pEncodingParams->EndCutTime = 0;
1362    // Set the output file size in bytes.
1363    pEncodingParams->OutputFileSize = 0;
1364    // Set video time scale.
1365    pEncodingParams->OutputVideoTimescale = 0;
1366
1367    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
1368                            "M4MCS_setEncodingParams()");
1369    result = M4MCS_setEncodingParams(mcsContext, pEncodingParams);
1370    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
1371        (M4NO_ERROR != result), result);
1372    if (needToBeLoaded == false) {
1373         free(pTemp3gpFilePath);
1374         pTemp3gpFilePath = M4OSA_NULL;
1375         M4MCS_abort(mcsContext);
1376         free(pOutputParams);
1377         pOutputParams = M4OSA_NULL;
1378         free(pEncodingParams);
1379         pEncodingParams = M4OSA_NULL;
1380         return result;
1381    }
1382
1383    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
1384                            "M4MCS_checkParamsAndStart()");
1385    result = M4MCS_checkParamsAndStart(mcsContext);
1386    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
1387        (M4NO_ERROR != result), result);
1388    if (needToBeLoaded == false) {
1389         free(pTemp3gpFilePath);
1390         pTemp3gpFilePath = M4OSA_NULL;
1391         M4MCS_abort(mcsContext);
1392         free(pOutputParams);
1393         pOutputParams = M4OSA_NULL;
1394         free(pEncodingParams);
1395         pEncodingParams = M4OSA_NULL;
1396        return result;
1397    }
1398
1399    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_step()");
1400
1401    /*+ PROGRESS CB */
1402    M4OSA_UInt8 curProgress = 0;
1403    int         lastProgress = 0;
1404
1405    ALOGV("LVME_generateAudio Current progress is =%d", curProgress);
1406    pEnv->CallVoidMethod(pContext->engine,
1407            pContext->onProgressUpdateMethodId, 1/*task status*/,
1408            curProgress/*progress*/);
1409    do {
1410        result = M4MCS_step(mcsContext, &curProgress);
1411
1412        if (result != M4NO_ERROR) {
1413            ALOGV("LVME_generateAudio M4MCS_step returned 0x%x",result);
1414
1415            if (result == M4MCS_WAR_TRANSCODING_DONE) {
1416                ALOGV("LVME_generateAudio MCS process ended");
1417
1418                // Send a progress notification.
1419                curProgress = 100;
1420                pEnv->CallVoidMethod(pContext->engine,
1421                    pContext->onProgressUpdateMethodId, 1/*task status*/,
1422                    curProgress);
1423                ALOGV("LVME_generateAudio Current progress is =%d", curProgress);
1424            }
1425        } else {
1426            // Send a progress notification if needed
1427            if (curProgress != lastProgress) {
1428                lastProgress = curProgress;
1429                pEnv->CallVoidMethod(pContext->engine,
1430                    pContext->onProgressUpdateMethodId, 0/*task status*/,
1431                    curProgress/*progress*/);
1432                ALOGV("LVME_generateAudio Current progress is =%d",curProgress);
1433            }
1434        }
1435    } while (result == M4NO_ERROR);
1436    /*- PROGRESS CB */
1437
1438    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
1439        (M4MCS_WAR_TRANSCODING_DONE != result), result);
1440    if (needToBeLoaded == false) {
1441         free(pTemp3gpFilePath);
1442         pTemp3gpFilePath = M4OSA_NULL;
1443         M4MCS_abort(mcsContext);
1444         free(pOutputParams);
1445         pOutputParams = M4OSA_NULL;
1446         free(pEncodingParams);
1447         pEncodingParams = M4OSA_NULL;
1448        return result;
1449    }
1450
1451    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_abort()");
1452    result = M4MCS_abort(mcsContext);
1453    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
1454        (M4NO_ERROR != result), result);
1455
1456    //pContext->mAudioSettings->pFile = pOutputParams->pOutputPCMfile;
1457    remove((const char *) pTemp3gpFilePath);
1458    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_generateAudio() EXIT ");
1459
1460    if (pTemp3gpFilePath != M4OSA_NULL) {
1461        free(pTemp3gpFilePath);
1462    }
1463    if (pOutputParams != M4OSA_NULL) {
1464       free(pOutputParams);
1465    }
1466    if(pEncodingParams != M4OSA_NULL) {
1467       free(pEncodingParams);
1468    }
1469    return result;
1470}
1471
1472static int removeAlphafromRGB8888 (
1473                        M4OSA_Char* pFramingFilePath,
1474                        M4xVSS_FramingStruct *pFramingCtx)
1475{
1476    M4OSA_UInt32 frameSize_argb = (pFramingCtx->width * pFramingCtx->height * 4); // aRGB data
1477    M4OSA_Context lImageFileFp  = M4OSA_NULL;
1478    M4OSA_ERR err = M4NO_ERROR;
1479
1480    ALOGV("removeAlphafromRGB8888: width %d", pFramingCtx->width);
1481
1482    M4OSA_UInt8 *pTmpData = (M4OSA_UInt8*) M4OSA_32bitAlignedMalloc(frameSize_argb, M4VS, (M4OSA_Char*)"Image argb data");
1483    if (pTmpData == M4OSA_NULL) {
1484        ALOGE("Failed to allocate memory for Image clip");
1485        return M4ERR_ALLOC;
1486    }
1487
1488       /** Read the argb data from the passed file. */
1489    M4OSA_ERR lerr = M4OSA_fileReadOpen(&lImageFileFp, (M4OSA_Void *) pFramingFilePath, M4OSA_kFileRead);
1490
1491
1492    if ((lerr != M4NO_ERROR) || (lImageFileFp == M4OSA_NULL))
1493    {
1494        ALOGE("removeAlphafromRGB8888: Can not open the file ");
1495        free(pTmpData);
1496        return M4ERR_FILE_NOT_FOUND;
1497    }
1498
1499
1500    lerr = M4OSA_fileReadData(lImageFileFp, (M4OSA_MemAddr8)pTmpData, &frameSize_argb);
1501    if (lerr != M4NO_ERROR)
1502    {
1503        ALOGE("removeAlphafromRGB8888: can not read the data ");
1504        M4OSA_fileReadClose(lImageFileFp);
1505        free(pTmpData);
1506        return lerr;
1507    }
1508    M4OSA_fileReadClose(lImageFileFp);
1509
1510    M4OSA_UInt32 frameSize = (pFramingCtx->width * pFramingCtx->height * 3); //Size of RGB 888 data.
1511
1512    pFramingCtx->FramingRgb = (M4VIFI_ImagePlane*)M4OSA_32bitAlignedMalloc(
1513             sizeof(M4VIFI_ImagePlane), M4VS, (M4OSA_Char*)"Image clip RGB888 data");
1514    pFramingCtx->FramingRgb->pac_data = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc(
1515             frameSize, M4VS, (M4OSA_Char*)"Image clip RGB888 data");
1516
1517    if (pFramingCtx->FramingRgb == M4OSA_NULL)
1518    {
1519        ALOGE("Failed to allocate memory for Image clip");
1520        free(pTmpData);
1521        return M4ERR_ALLOC;
1522    }
1523
1524    /** Remove the alpha channel */
1525    for (size_t i = 0, j = 0; i < frameSize_argb; i++) {
1526        if ((i % 4) == 0) continue;
1527        pFramingCtx->FramingRgb->pac_data[j] = pTmpData[i];
1528        j++;
1529    }
1530    free(pTmpData);
1531    return M4NO_ERROR;
1532}
1533
1534static void
1535videoEditor_populateSettings(
1536                JNIEnv*                 pEnv,
1537                jobject                 thiz,
1538                jobject                 settings,
1539                jobject                 object,
1540                jobject                 audioSettingObject)
1541{
1542    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
1543            "videoEditor_populateSettings()");
1544
1545    bool                needToBeLoaded  = true;
1546    ManualEditContext*  pContext        = M4OSA_NULL;
1547    M4OSA_ERR           result          = M4NO_ERROR;
1548    jstring             strPath         = M4OSA_NULL;
1549    jstring             strPCMPath      = M4OSA_NULL;
1550    jobjectArray        propertiesClipsArray           = M4OSA_NULL;
1551    jobject             properties      = M4OSA_NULL;
1552    jint*               bitmapArray     =  M4OSA_NULL;
1553    jobjectArray        effectSettingsArray = M4OSA_NULL;
1554    jobject             effectSettings  = M4OSA_NULL;
1555    jintArray           pixelArray      = M4OSA_NULL;
1556    int width = 0;
1557    int height = 0;
1558    int nbOverlays = 0;
1559    int i,j = 0;
1560    int *pOverlayIndex = M4OSA_NULL;
1561    M4OSA_Char* pTempChar = M4OSA_NULL;
1562
1563    // Add a code marker (the condition must always be true).
1564    ADD_CODE_MARKER_FUN(NULL != pEnv)
1565
1566    // Validate the settings parameter.
1567    videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv,
1568                                                (NULL == settings),
1569                                                "settings is null");
1570    // Get the context.
1571    pContext =
1572            (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz);
1573
1574    // Make sure that the context was set.
1575    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
1576                                             (M4OSA_NULL == pContext),
1577                                             "not initialized");
1578    // Make sure that the context was set.
1579    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
1580                                 (M4OSA_NULL == pContext->mPreviewController),
1581                                 "not initialized");
1582    jclass mPreviewClipPropClazz = pEnv->FindClass(PREVIEW_PROPERTIES_CLASS_NAME);
1583    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
1584                                     (M4OSA_NULL == mPreviewClipPropClazz),
1585                                     "not initialized");
1586
1587    jfieldID fid = pEnv->GetFieldID(mPreviewClipPropClazz,"clipProperties",
1588            "[L"PROPERTIES_CLASS_NAME";"  );
1589    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
1590                                     (M4OSA_NULL == fid),
1591                                     "not initialized");
1592
1593    propertiesClipsArray = (jobjectArray)pEnv->GetObjectField(object, fid);
1594    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
1595                                     (M4OSA_NULL == propertiesClipsArray),
1596                                     "not initialized");
1597
1598    jclass engineClass = pEnv->FindClass(MANUAL_EDIT_ENGINE_CLASS_NAME);
1599    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
1600                                     (M4OSA_NULL == engineClass),
1601                                     "not initialized");
1602
1603    pContext->onPreviewProgressUpdateMethodId = pEnv->GetMethodID(engineClass,
1604            "onPreviewProgressUpdate",     "(IZZLjava/lang/String;II)V");
1605    // Check if the context is valid (required because the context is dereferenced).
1606    if (needToBeLoaded) {
1607        // Make sure that we are in a correct state.
1608        videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
1609                             (pContext->state != ManualEditState_INITIALIZED),
1610                             "settings already loaded");
1611        if (needToBeLoaded) {
1612            // Retrieve the edit settings.
1613            if (pContext->pEditSettings != M4OSA_NULL) {
1614                videoEditClasses_freeEditSettings(&pContext->pEditSettings);
1615                pContext->pEditSettings = M4OSA_NULL;
1616            }
1617            videoEditClasses_getEditSettings(&needToBeLoaded, pEnv,
1618                settings, &pContext->pEditSettings,false);
1619        }
1620    }
1621
1622    if (needToBeLoaded == false) {
1623        j = 0;
1624        while (j < pContext->pEditSettings->nbEffects)
1625        {
1626            if (pContext->pEditSettings->Effects[j].xVSS.pFramingFilePath != M4OSA_NULL) {
1627                if (pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer != M4OSA_NULL) {
1628                    free(pContext->pEditSettings->\
1629                    Effects[j].xVSS.pFramingBuffer);
1630                    pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer = M4OSA_NULL;
1631                }
1632            }
1633          j++;
1634        }
1635        return;
1636    }
1637
1638    M4OSA_TRACE1_0("videoEditorC_getEditSettings done");
1639
1640    pContext->previewFrameEditInfoId = pEnv->GetMethodID(engineClass,
1641        "previewFrameEditInfo", "(Ljava/lang/String;I)V");
1642
1643    if ( pContext->pEditSettings != NULL )
1644    {
1645        // Check if the edit settings could be retrieved.
1646        jclass mEditClazz = pEnv->FindClass(EDIT_SETTINGS_CLASS_NAME);
1647        if(mEditClazz == M4OSA_NULL)
1648        {
1649            M4OSA_TRACE1_0("cannot find object field for mEditClazz");
1650            goto videoEditor_populateSettings_cleanup;
1651        }
1652        jclass mEffectsClazz = pEnv->FindClass(EFFECT_SETTINGS_CLASS_NAME);
1653        if(mEffectsClazz == M4OSA_NULL)
1654        {
1655            M4OSA_TRACE1_0("cannot find object field for mEffectsClazz");
1656            goto videoEditor_populateSettings_cleanup;
1657        }
1658        fid = pEnv->GetFieldID(mEditClazz,"effectSettingsArray", "[L"EFFECT_SETTINGS_CLASS_NAME";"  );
1659        if(fid == M4OSA_NULL)
1660        {
1661            M4OSA_TRACE1_0("cannot find field for effectSettingsArray Array");
1662            goto videoEditor_populateSettings_cleanup;
1663        }
1664        effectSettingsArray = (jobjectArray)pEnv->GetObjectField(settings, fid);
1665        if(effectSettingsArray == M4OSA_NULL)
1666        {
1667            M4OSA_TRACE1_0("cannot find object field for effectSettingsArray");
1668            goto videoEditor_populateSettings_cleanup;
1669        }
1670
1671        //int overlayIndex[pContext->pEditSettings->nbEffects];
1672        if (pContext->pEditSettings->nbEffects > 0)
1673        {
1674            pOverlayIndex
1675            = (int*) M4OSA_32bitAlignedMalloc(pContext->pEditSettings->nbEffects * sizeof(int), 0,
1676                (M4OSA_Char*)"pOverlayIndex");
1677            if (pOverlayIndex == M4OSA_NULL) {
1678                videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
1679                    M4OSA_TRUE, M4ERR_ALLOC);
1680                goto videoEditor_populateSettings_cleanup;
1681            }
1682        }
1683
1684        i = 0;
1685        j = 0;
1686        M4OSA_TRACE1_1("no of effects = %d",pContext->pEditSettings->nbEffects);
1687        while (j < pContext->pEditSettings->nbEffects)
1688        {
1689            if (pContext->pEditSettings->Effects[j].xVSS.pFramingFilePath != M4OSA_NULL)
1690            {
1691                pOverlayIndex[nbOverlays] = j;
1692
1693                M4xVSS_FramingStruct *aFramingCtx = M4OSA_NULL;
1694                aFramingCtx
1695                = (M4xVSS_FramingStruct*)M4OSA_32bitAlignedMalloc(sizeof(M4xVSS_FramingStruct), M4VS,
1696                  (M4OSA_Char*)"M4xVSS_internalDecodeGIF: Context of the framing effect");
1697                if (aFramingCtx == M4OSA_NULL)
1698                {
1699                    M4OSA_TRACE1_0("Allocation error in videoEditor_populateSettings");
1700                    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
1701                        M4OSA_TRUE, M4ERR_ALLOC);
1702                    goto videoEditor_populateSettings_cleanup;
1703                }
1704
1705                aFramingCtx->pCurrent = M4OSA_NULL; /* Only used by the first element of the chain */
1706                aFramingCtx->previousClipTime = -1;
1707                aFramingCtx->FramingYuv = M4OSA_NULL;
1708                aFramingCtx->FramingRgb = M4OSA_NULL;
1709                aFramingCtx->topleft_x
1710                    = pContext->pEditSettings->Effects[j].xVSS.topleft_x;
1711                aFramingCtx->topleft_y
1712                    = pContext->pEditSettings->Effects[j].xVSS.topleft_y;
1713
1714
1715                 VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "OF u_width %d",
1716                                        pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_width);
1717                 VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "OF u_height() %d",
1718                                        pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_height);
1719                 VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "OF rgbType() %d",
1720                                        pContext->pEditSettings->Effects[j].xVSS.rgbType);
1721
1722                 aFramingCtx->width = pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_width;
1723                 aFramingCtx->height = pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_height;
1724
1725                result = M4xVSS_internalConvertARGB888toYUV420_FrammingEffect(pContext->engineContext,
1726                    &(pContext->pEditSettings->Effects[j]),aFramingCtx,
1727                pContext->pEditSettings->Effects[j].xVSS.framingScaledSize);
1728                videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
1729                                            (M4NO_ERROR != result), result);
1730                if (needToBeLoaded == false) {
1731                    M4OSA_TRACE1_1("M4xVSS_internalConvertARGB888toYUV420_FrammingEffect returned 0x%x", result);
1732                    if (aFramingCtx != M4OSA_NULL) {
1733                        free(aFramingCtx);
1734                        aFramingCtx = M4OSA_NULL;
1735                    }
1736                    goto videoEditor_populateSettings_cleanup;
1737                }
1738
1739                //framing buffers are resized to fit the output video resolution.
1740                pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_width =
1741                    aFramingCtx->FramingRgb->u_width;
1742                pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_height =
1743                    aFramingCtx->FramingRgb->u_height;
1744
1745                VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "A framing Context aFramingCtx->width = %d",
1746                    aFramingCtx->FramingRgb->u_width);
1747
1748                VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "A framing Context aFramingCtx->height = %d",
1749                    aFramingCtx->FramingRgb->u_height);
1750
1751
1752                width = pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_width;
1753                height = pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_height;
1754
1755                //RGB 565
1756                pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_stride = width * 2;
1757
1758                //for RGB565
1759                pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_topleft = 0;
1760                pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->pac_data =
1761                            (M4VIFI_UInt8 *)M4OSA_32bitAlignedMalloc(width*height*2,
1762                            0x00,(M4OSA_Char *)"pac_data buffer");
1763
1764                if (pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->pac_data == M4OSA_NULL) {
1765                    M4OSA_TRACE1_0("Failed to allocate memory for framing buffer");
1766                    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
1767                                            M4OSA_TRUE, M4ERR_ALLOC);
1768                    goto videoEditor_populateSettings_cleanup;
1769                }
1770
1771                memcpy((void *)&pContext->pEditSettings->\
1772                    Effects[j].xVSS.pFramingBuffer->\
1773                    pac_data[0],(void *)&aFramingCtx->FramingRgb->pac_data[0],(width*height*2));
1774
1775                //As of now rgb type is 565
1776                pContext->pEditSettings->Effects[j].xVSS.rgbType =
1777                    (M4VSS3GPP_RGBType) M4VSS3GPP_kRGB565;
1778
1779                if (aFramingCtx->FramingYuv != M4OSA_NULL )
1780                {
1781                    if (aFramingCtx->FramingYuv[0].pac_data != M4OSA_NULL) {
1782                        free(aFramingCtx->FramingYuv[0].pac_data);
1783                        aFramingCtx->FramingYuv[0].pac_data = M4OSA_NULL;
1784                    }
1785                    if (aFramingCtx->FramingYuv[1].pac_data != M4OSA_NULL) {
1786                        free(aFramingCtx->FramingYuv[1].pac_data);
1787                        aFramingCtx->FramingYuv[1].pac_data = M4OSA_NULL;
1788                    }
1789                    if (aFramingCtx->FramingYuv[2].pac_data != M4OSA_NULL) {
1790                        free(aFramingCtx->FramingYuv[2].pac_data);
1791                        aFramingCtx->FramingYuv[2].pac_data = M4OSA_NULL;
1792                    }
1793
1794                    free(aFramingCtx->FramingYuv);
1795                    aFramingCtx->FramingYuv = M4OSA_NULL;
1796                }
1797                if (aFramingCtx->FramingRgb->pac_data != M4OSA_NULL) {
1798                    free(aFramingCtx->FramingRgb->pac_data);
1799                    aFramingCtx->FramingRgb->pac_data = M4OSA_NULL;
1800                }
1801                if (aFramingCtx->FramingRgb != M4OSA_NULL) {
1802                    free(aFramingCtx->FramingRgb);
1803                    aFramingCtx->FramingRgb = M4OSA_NULL;
1804                }
1805                if (aFramingCtx != M4OSA_NULL) {
1806                    free(aFramingCtx);
1807                    aFramingCtx = M4OSA_NULL;
1808                }
1809                nbOverlays++;
1810            }
1811            j++;
1812        }
1813
1814        // Check if the edit settings could be retrieved.
1815        M4OSA_TRACE1_1("total clips are = %d",pContext->pEditSettings->uiClipNumber);
1816        for (i = 0; i < pContext->pEditSettings->uiClipNumber; i++) {
1817            M4OSA_TRACE1_1("clip no = %d",i);
1818            properties = pEnv->GetObjectArrayElement(propertiesClipsArray, i);
1819            videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
1820                (M4OSA_NULL == properties),
1821                "not initialized");
1822            if (needToBeLoaded) {
1823                getClipSetting(pEnv,properties, pContext->pEditSettings->pClipList[i]);
1824                pEnv->DeleteLocalRef(properties);
1825            } else {
1826                pEnv->DeleteLocalRef(properties);
1827                goto videoEditor_populateSettings_cleanup;
1828            }
1829        }
1830
1831        if (needToBeLoaded) {
1832            // Log the edit settings.
1833            VIDEOEDIT_LOG_EDIT_SETTINGS(pContext->pEditSettings);
1834        }
1835    }
1836    /* free previous allocations , if any */
1837    if (pContext->mAudioSettings != M4OSA_NULL) {
1838        if (pContext->mAudioSettings->pFile != NULL) {
1839            free(pContext->mAudioSettings->pFile);
1840            pContext->mAudioSettings->pFile = M4OSA_NULL;
1841        }
1842        if (pContext->mAudioSettings->pPCMFilePath != NULL) {
1843            free(pContext->mAudioSettings->pPCMFilePath);
1844            pContext->mAudioSettings->pPCMFilePath = M4OSA_NULL;
1845        }
1846    }
1847
1848    if (audioSettingObject != M4OSA_NULL) {
1849        jclass audioSettingClazz = pEnv->FindClass(AUDIO_SETTINGS_CLASS_NAME);
1850        videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
1851                                         (M4OSA_NULL == audioSettingClazz),
1852                                         "not initialized");
1853
1854        videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
1855                                     (M4OSA_NULL == pContext->mAudioSettings),
1856                                     "not initialized");
1857
1858        if (needToBeLoaded == false) {
1859            goto videoEditor_populateSettings_cleanup;
1860        }
1861
1862        fid = pEnv->GetFieldID(audioSettingClazz,"bRemoveOriginal","Z");
1863        pContext->mAudioSettings->bRemoveOriginal =
1864            pEnv->GetBooleanField(audioSettingObject,fid);
1865        M4OSA_TRACE1_1("bRemoveOriginal = %d",pContext->mAudioSettings->bRemoveOriginal);
1866
1867        fid = pEnv->GetFieldID(audioSettingClazz,"channels","I");
1868        pContext->mAudioSettings->uiNbChannels = pEnv->GetIntField(audioSettingObject,fid);
1869        M4OSA_TRACE1_1("uiNbChannels = %d",pContext->mAudioSettings->uiNbChannels);
1870
1871        fid = pEnv->GetFieldID(audioSettingClazz,"Fs","I");
1872        pContext->mAudioSettings->uiSamplingFrequency = pEnv->GetIntField(audioSettingObject,fid);
1873        M4OSA_TRACE1_1("uiSamplingFrequency = %d",pContext->mAudioSettings->uiSamplingFrequency);
1874
1875        fid = pEnv->GetFieldID(audioSettingClazz,"ExtendedFs","I");
1876        pContext->mAudioSettings->uiExtendedSamplingFrequency =
1877         pEnv->GetIntField(audioSettingObject,fid);
1878        M4OSA_TRACE1_1("uiExtendedSamplingFrequency = %d",
1879        pContext->mAudioSettings->uiExtendedSamplingFrequency);
1880
1881        fid = pEnv->GetFieldID(audioSettingClazz,"startMs","J");
1882        pContext->mAudioSettings->uiAddCts
1883            = pEnv->GetLongField(audioSettingObject,fid);
1884        M4OSA_TRACE1_1("uiAddCts = %d",pContext->mAudioSettings->uiAddCts);
1885
1886        fid = pEnv->GetFieldID(audioSettingClazz,"volume","I");
1887        pContext->mAudioSettings->uiAddVolume
1888            = pEnv->GetIntField(audioSettingObject,fid);
1889        M4OSA_TRACE1_1("uiAddVolume = %d",pContext->mAudioSettings->uiAddVolume);
1890
1891        fid = pEnv->GetFieldID(audioSettingClazz,"loop","Z");
1892        pContext->mAudioSettings->bLoop
1893            = pEnv->GetBooleanField(audioSettingObject,fid);
1894        M4OSA_TRACE1_1("bLoop = %d",pContext->mAudioSettings->bLoop);
1895
1896        fid = pEnv->GetFieldID(audioSettingClazz,"beginCutTime","J");
1897        pContext->mAudioSettings->beginCutMs
1898            = pEnv->GetLongField(audioSettingObject,fid);
1899        M4OSA_TRACE1_1("begin cut time = %d",pContext->mAudioSettings->beginCutMs);
1900
1901        fid = pEnv->GetFieldID(audioSettingClazz,"endCutTime","J");
1902        pContext->mAudioSettings->endCutMs
1903            = pEnv->GetLongField(audioSettingObject,fid);
1904        M4OSA_TRACE1_1("end cut time = %d",pContext->mAudioSettings->endCutMs);
1905
1906        fid = pEnv->GetFieldID(audioSettingClazz,"fileType","I");
1907        pContext->mAudioSettings->fileType
1908            = pEnv->GetIntField(audioSettingObject,fid);
1909        M4OSA_TRACE1_1("fileType = %d",pContext->mAudioSettings->fileType);
1910
1911        fid = pEnv->GetFieldID(audioSettingClazz,"pFile","Ljava/lang/String;");
1912        strPath = (jstring)pEnv->GetObjectField(audioSettingObject,fid);
1913        pTempChar = (M4OSA_Char*)pEnv->GetStringUTFChars(strPath, M4OSA_NULL);
1914        if (pTempChar != NULL) {
1915            pContext->mAudioSettings->pFile = (M4OSA_Char*) M4OSA_32bitAlignedMalloc(
1916                (M4OSA_UInt32)(strlen((const char*)pTempChar))+1 /* +1 for NULL termination */, 0,
1917                (M4OSA_Char*)"strPath allocation " );
1918            if (pContext->mAudioSettings->pFile != M4OSA_NULL) {
1919                memcpy((void *)pContext->mAudioSettings->pFile ,
1920                    (void *)pTempChar , strlen((const char*)pTempChar));
1921                ((M4OSA_Int8 *)(pContext->mAudioSettings->pFile))[strlen((const char*)pTempChar)] = '\0';
1922                pEnv->ReleaseStringUTFChars(strPath,(const char *)pTempChar);
1923            } else {
1924                pEnv->ReleaseStringUTFChars(strPath,(const char *)pTempChar);
1925                VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR",
1926                    "regenerateAudio() Malloc failed for pContext->mAudioSettings->pFile ");
1927                videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
1928                    M4OSA_TRUE, M4ERR_ALLOC);
1929                goto videoEditor_populateSettings_cleanup;
1930            }
1931        }
1932        M4OSA_TRACE1_1("file name = %s",pContext->mAudioSettings->pFile);
1933        VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEOEDITOR", "regenerateAudio() file name = %s",\
1934        pContext->mAudioSettings->pFile);
1935
1936        fid = pEnv->GetFieldID(audioSettingClazz,"pcmFilePath","Ljava/lang/String;");
1937        strPCMPath = (jstring)pEnv->GetObjectField(audioSettingObject,fid);
1938        pTempChar = (M4OSA_Char*)pEnv->GetStringUTFChars(strPCMPath, M4OSA_NULL);
1939        if (pTempChar != NULL) {
1940            pContext->mAudioSettings->pPCMFilePath = (M4OSA_Char*) M4OSA_32bitAlignedMalloc(
1941                (M4OSA_UInt32)(strlen((const char*)pTempChar))+1 /* +1 for NULL termination */, 0,
1942                (M4OSA_Char*)"strPCMPath allocation " );
1943            if (pContext->mAudioSettings->pPCMFilePath != M4OSA_NULL) {
1944                memcpy((void *)pContext->mAudioSettings->pPCMFilePath ,
1945                    (void *)pTempChar , strlen((const char*)pTempChar));
1946                ((M4OSA_Int8 *)(pContext->mAudioSettings->pPCMFilePath))[strlen((const char*)pTempChar)] = '\0';
1947                pEnv->ReleaseStringUTFChars(strPCMPath,(const char *)pTempChar);
1948            } else {
1949                pEnv->ReleaseStringUTFChars(strPCMPath,(const char *)pTempChar);
1950                VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR",
1951                    "regenerateAudio() Malloc failed for pContext->mAudioSettings->pPCMFilePath ");
1952                videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
1953                    M4OSA_TRUE, M4ERR_ALLOC);
1954                goto videoEditor_populateSettings_cleanup;
1955            }
1956        }
1957        VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEOEDITOR", "pPCMFilePath -- %s ",\
1958        pContext->mAudioSettings->pPCMFilePath);
1959
1960        fid = pEnv->GetFieldID(engineClass,"mRegenerateAudio","Z");
1961        bool regenerateAudio = pEnv->GetBooleanField(thiz,fid);
1962
1963        VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEOEDITOR", "regenerateAudio -- %d ",\
1964        regenerateAudio);
1965
1966        if (regenerateAudio) {
1967            M4OSA_TRACE1_0("Calling Generate Audio now");
1968            result = videoEditor_generateAudio(pEnv,
1969                        pContext,
1970                        (M4OSA_Char*)pContext->mAudioSettings->pFile,
1971                        (M4OSA_Char*)pContext->mAudioSettings->pPCMFilePath);
1972
1973            videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
1974                (M4NO_ERROR != result), result);
1975            if (needToBeLoaded == false) {
1976                goto videoEditor_populateSettings_cleanup;
1977            }
1978
1979            regenerateAudio = false;
1980            pEnv->SetBooleanField(thiz,fid,regenerateAudio);
1981        }
1982
1983        /* Audio mix and duck */
1984        fid = pEnv->GetFieldID(audioSettingClazz,"ducking_threshold","I");
1985        pContext->mAudioSettings->uiInDucking_threshold
1986            = pEnv->GetIntField(audioSettingObject,fid);
1987
1988        M4OSA_TRACE1_1("ducking threshold = %d",
1989            pContext->mAudioSettings->uiInDucking_threshold);
1990
1991        fid = pEnv->GetFieldID(audioSettingClazz,"ducking_lowVolume","I");
1992        pContext->mAudioSettings->uiInDucking_lowVolume
1993            = pEnv->GetIntField(audioSettingObject,fid);
1994
1995        M4OSA_TRACE1_1("ducking lowVolume = %d",
1996            pContext->mAudioSettings->uiInDucking_lowVolume);
1997
1998        fid = pEnv->GetFieldID(audioSettingClazz,"bInDucking_enable","Z");
1999        pContext->mAudioSettings->bInDucking_enable
2000            = pEnv->GetBooleanField(audioSettingObject,fid);
2001        M4OSA_TRACE1_1("ducking lowVolume = %d",
2002            pContext->mAudioSettings->bInDucking_enable);
2003
2004    } else {
2005        if (pContext->mAudioSettings != M4OSA_NULL) {
2006            pContext->mAudioSettings->pFile = M4OSA_NULL;
2007            pContext->mAudioSettings->pPCMFilePath = M4OSA_NULL;
2008            pContext->mAudioSettings->bRemoveOriginal = 0;
2009            pContext->mAudioSettings->uiNbChannels = 0;
2010            pContext->mAudioSettings->uiSamplingFrequency = 0;
2011            pContext->mAudioSettings->uiExtendedSamplingFrequency = 0;
2012            pContext->mAudioSettings->uiAddCts = 0;
2013            pContext->mAudioSettings->uiAddVolume = 0;
2014            pContext->mAudioSettings->beginCutMs = 0;
2015            pContext->mAudioSettings->endCutMs = 0;
2016            pContext->mAudioSettings->fileType = 0;
2017            pContext->mAudioSettings->bLoop = 0;
2018            pContext->mAudioSettings->uiInDucking_lowVolume  = 0;
2019            pContext->mAudioSettings->bInDucking_enable  = 0;
2020            pContext->mAudioSettings->uiBTChannelCount  = 0;
2021            pContext->mAudioSettings->uiInDucking_threshold = 0;
2022
2023            fid = pEnv->GetFieldID(engineClass,"mRegenerateAudio","Z");
2024            bool regenerateAudio = pEnv->GetBooleanField(thiz,fid);
2025            if (!regenerateAudio) {
2026                regenerateAudio = true;
2027                pEnv->SetBooleanField(thiz,fid,regenerateAudio);
2028            }
2029        }
2030    }
2031
2032    if (pContext->pEditSettings != NULL)
2033    {
2034        result = pContext->mPreviewController->loadEditSettings(pContext->pEditSettings,
2035            pContext->mAudioSettings);
2036        videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
2037                                            (M4NO_ERROR != result), result);
2038
2039        if (needToBeLoaded) {
2040            pContext->mPreviewController->setJniCallback((void*)pContext,
2041            (jni_progress_callback_fct)jniPreviewProgressCallback);
2042        }
2043    }
2044
2045videoEditor_populateSettings_cleanup:
2046        j = 0;
2047        while (j < nbOverlays)
2048        {
2049            if (pContext->pEditSettings->Effects[pOverlayIndex[j]].xVSS.pFramingBuffer->pac_data != \
2050                M4OSA_NULL) {
2051                free(pContext->pEditSettings->\
2052                Effects[pOverlayIndex[j]].xVSS.pFramingBuffer->pac_data);
2053                pContext->pEditSettings->\
2054                Effects[pOverlayIndex[j]].xVSS.pFramingBuffer->pac_data = M4OSA_NULL;
2055            }
2056            j++;
2057        }
2058
2059        j = 0;
2060        while (j < pContext->pEditSettings->nbEffects)
2061        {
2062            if (pContext->pEditSettings->Effects[j].xVSS.pFramingFilePath != M4OSA_NULL) {
2063                if (pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer != M4OSA_NULL) {
2064                    free(pContext->pEditSettings->\
2065                    Effects[j].xVSS.pFramingBuffer);
2066                    pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer = M4OSA_NULL;
2067                }
2068            }
2069          j++;
2070        }
2071
2072    if (pOverlayIndex != M4OSA_NULL)
2073    {
2074        free(pOverlayIndex);
2075        pOverlayIndex = M4OSA_NULL;
2076    }
2077    return;
2078}
2079
2080static void
2081videoEditor_startPreview(
2082                JNIEnv*                 pEnv,
2083                jobject                 thiz,
2084                jobject                 mSurface,
2085                jlong                   fromMs,
2086                jlong                   toMs,
2087                jint                    callbackInterval,
2088                jboolean                loop)
2089{
2090    bool needToBeLoaded = true;
2091    M4OSA_ERR result = M4NO_ERROR;
2092    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_startPreview()");
2093
2094    ManualEditContext* pContext = M4OSA_NULL;
2095    // Get the context.
2096    pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz);
2097
2098    // Make sure that the context was set.
2099    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
2100                                             (M4OSA_NULL == pContext),
2101                                             "not initialized");
2102
2103    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
2104                                     (M4OSA_NULL == pContext->mAudioSettings),
2105                                     "not initialized");
2106    // Make sure that the context was set.
2107    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
2108                                 (M4OSA_NULL == pContext->mPreviewController),
2109                                 "not initialized");
2110
2111    // Validate the mSurface parameter.
2112    videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv,
2113                                                (NULL == mSurface),
2114                                                "mSurface is null");
2115
2116    sp<Surface> previewSurface = android_view_Surface_getSurface(pEnv, mSurface);
2117
2118    // Validate the mSurface's mNativeSurface field
2119    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
2120                                                (NULL == previewSurface.get()),
2121                                                "mNativeSurface is null");
2122
2123    result =  pContext->mPreviewController->setSurface(previewSurface);
2124    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
2125        (M4NO_ERROR != result), result);
2126    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "fromMs=%ld, toMs=%ld",
2127        (M4OSA_UInt32)fromMs, (M4OSA_Int32)toMs);
2128
2129    result = pContext->mPreviewController->startPreview((M4OSA_UInt32)fromMs,
2130                                                (M4OSA_Int32)toMs,
2131                                                (M4OSA_UInt16)callbackInterval,
2132                                                (M4OSA_Bool)loop);
2133    videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, (M4NO_ERROR != result), result);
2134}
2135
2136
2137static jobject
2138videoEditor_getProperties(
2139                JNIEnv*                             pEnv,
2140                jobject                             thiz,
2141                jstring                             file)
2142{
2143    jobject object = M4OSA_NULL;
2144    jclass clazz = pEnv->FindClass(PROPERTIES_CLASS_NAME);
2145    jfieldID fid;
2146    bool needToBeLoaded = true;
2147    ManualEditContext* pContext = M4OSA_NULL;
2148    M4OSA_ERR          result   = M4NO_ERROR;
2149    int profile = 0;
2150    int level = 0;
2151    int videoFormat = 0;
2152
2153    // Get the context.
2154    pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz);
2155
2156    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
2157                                             (M4OSA_NULL == clazz),
2158                                             "not initialized");
2159
2160    object = videoEditProp_getProperties(pEnv,thiz,file);
2161
2162    if (object != M4OSA_NULL) {
2163        fid = pEnv->GetFieldID(clazz,"profile","I");
2164        profile = pEnv->GetIntField(object,fid);
2165        fid = pEnv->GetFieldID(clazz,"level","I");
2166        level = pEnv->GetIntField(object,fid);
2167        fid = pEnv->GetFieldID(clazz,"videoFormat","I");
2168        videoFormat = pEnv->GetIntField(object,fid);
2169
2170        result = checkClipVideoProfileAndLevel(pContext->decoders, videoFormat, profile, level);
2171
2172        fid = pEnv->GetFieldID(clazz,"profileSupported","Z");
2173        if (M4VSS3GPP_ERR_EDITING_UNSUPPORTED_VIDEO_PROFILE == result) {
2174            pEnv->SetBooleanField(object,fid,false);
2175        }
2176
2177        fid = pEnv->GetFieldID(clazz,"levelSupported","Z");
2178        if (M4VSS3GPP_ERR_EDITING_UNSUPPORTED_VIDEO_LEVEL == result) {
2179            pEnv->SetBooleanField(object,fid,false);
2180        }
2181    }
2182    return object;
2183
2184}
2185static int videoEditor_getPixels(
2186                    JNIEnv*                     env,
2187                    jobject                     thiz,
2188                    jstring                     path,
2189                    jintArray                   pixelArray,
2190                    M4OSA_UInt32                width,
2191                    M4OSA_UInt32                height,
2192                    M4OSA_UInt32                timeMS)
2193{
2194
2195    M4OSA_ERR       err = M4NO_ERROR;
2196    M4OSA_Context   mContext = M4OSA_NULL;
2197    jint*           m_dst32 = M4OSA_NULL;
2198
2199
2200    // Add a text marker (the condition must always be true).
2201    ADD_TEXT_MARKER_FUN(NULL != env)
2202
2203    const char *pString = env->GetStringUTFChars(path, NULL);
2204    if (pString == M4OSA_NULL) {
2205        if (env != NULL) {
2206            jniThrowException(env, "java/lang/RuntimeException", "Input string null");
2207        }
2208        return M4ERR_ALLOC;
2209    }
2210
2211    err = ThumbnailOpen(&mContext,(const M4OSA_Char*)pString, M4OSA_FALSE);
2212    if (err != M4NO_ERROR || mContext == M4OSA_NULL) {
2213        if (pString != NULL) {
2214            env->ReleaseStringUTFChars(path, pString);
2215        }
2216        if (env != NULL) {
2217            jniThrowException(env, "java/lang/RuntimeException", "ThumbnailOpen failed");
2218        }
2219    }
2220
2221    m_dst32 = env->GetIntArrayElements(pixelArray, NULL);
2222
2223    err = ThumbnailGetPixels32(mContext, (M4OSA_Int32 *)m_dst32, width,height,&timeMS,0);
2224    if (err != M4NO_ERROR ) {
2225        if (env != NULL) {
2226            jniThrowException(env, "java/lang/RuntimeException",\
2227                "ThumbnailGetPixels32 failed");
2228        }
2229    }
2230    env->ReleaseIntArrayElements(pixelArray, m_dst32, 0);
2231
2232    ThumbnailClose(mContext);
2233    if (pString != NULL) {
2234        env->ReleaseStringUTFChars(path, pString);
2235    }
2236
2237    return timeMS;
2238}
2239
2240static int videoEditor_getPixelsList(
2241                JNIEnv*                 env,
2242                jobject                 thiz,
2243                jstring                 path,
2244                jintArray               pixelArray,
2245                M4OSA_UInt32            width,
2246                M4OSA_UInt32            height,
2247                M4OSA_UInt32            noOfThumbnails,
2248                jlong                   startTime,
2249                jlong                   endTime,
2250                jintArray               indexArray,
2251                jobject                 callback)
2252{
2253
2254    M4OSA_ERR           err = M4NO_ERROR;
2255    M4OSA_Context       mContext = M4OSA_NULL;
2256
2257    const char *pString = env->GetStringUTFChars(path, NULL);
2258    if (pString == M4OSA_NULL) {
2259        jniThrowException(env, "java/lang/RuntimeException", "Input string null");
2260        return M4ERR_ALLOC;
2261    }
2262
2263    err = ThumbnailOpen(&mContext,(const M4OSA_Char*)pString, M4OSA_FALSE);
2264    if (err != M4NO_ERROR || mContext == M4OSA_NULL) {
2265        jniThrowException(env, "java/lang/RuntimeException", "ThumbnailOpen failed");
2266        if (pString != NULL) {
2267            env->ReleaseStringUTFChars(path, pString);
2268        }
2269        return err;
2270    }
2271
2272    jlong duration = (endTime - startTime);
2273    M4OSA_UInt32 tolerance = duration / (2 * noOfThumbnails);
2274    jint* m_dst32 = env->GetIntArrayElements(pixelArray, NULL);
2275    jint* indices = env->GetIntArrayElements(indexArray, NULL);
2276    jsize len = env->GetArrayLength(indexArray);
2277
2278    jclass cls = env->GetObjectClass(callback);
2279    jmethodID mid = env->GetMethodID(cls, "onThumbnail", "(I)V");
2280
2281    for (int i = 0; i < len; i++) {
2282        int k = indices[i];
2283        M4OSA_UInt32 timeMS = startTime;
2284        timeMS += (2 * k + 1) * duration / (2 * noOfThumbnails);
2285        err = ThumbnailGetPixels32(mContext, ((M4OSA_Int32 *)m_dst32),
2286            width, height, &timeMS, tolerance);
2287        if (err != M4NO_ERROR) {
2288            break;
2289        }
2290        env->CallVoidMethod(callback, mid, (jint)k);
2291        if (env->ExceptionCheck()) {
2292            err = M4ERR_ALLOC;
2293            break;
2294        }
2295    }
2296
2297    env->ReleaseIntArrayElements(pixelArray, m_dst32, 0);
2298    env->ReleaseIntArrayElements(indexArray, indices, 0);
2299
2300    ThumbnailClose(mContext);
2301    if (pString != NULL) {
2302        env->ReleaseStringUTFChars(path, pString);
2303    }
2304
2305    if (err != M4NO_ERROR && !env->ExceptionCheck()) {
2306        jniThrowException(env, "java/lang/RuntimeException",\
2307                "ThumbnailGetPixels32 failed");
2308    }
2309
2310    return err;
2311}
2312
2313static M4OSA_ERR
2314videoEditor_toUTF8Fct(
2315                M4OSA_Void*                         pBufferIn,
2316                M4OSA_UInt8*                        pBufferOut,
2317                M4OSA_UInt32*                       bufferOutSize)
2318{
2319    M4OSA_ERR    result = M4NO_ERROR;
2320    M4OSA_UInt32 length = 0;
2321
2322    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_toUTF8Fct()");
2323
2324    // Determine the length of the input buffer.
2325    if (M4OSA_NULL != pBufferIn)
2326    {
2327        length = strlen((const char *)pBufferIn);
2328    }
2329
2330    // Check if the output buffer is large enough to hold the input buffer.
2331    if ((*bufferOutSize) > length)
2332    {
2333        // Check if the input buffer is not M4OSA_NULL.
2334        if (M4OSA_NULL != pBufferIn)
2335        {
2336            // Copy the temp path, ignore the result.
2337            M4OSA_chrNCopy((M4OSA_Char *)pBufferOut, (M4OSA_Char *)pBufferIn, length);
2338        }
2339        else
2340        {
2341            // Set the output buffer to an empty string.
2342            (*(M4OSA_Char *)pBufferOut) = 0;
2343        }
2344    }
2345    else
2346    {
2347        // The buffer is too small.
2348        result = M4xVSSWAR_BUFFER_OUT_TOO_SMALL;
2349    }
2350
2351    // Return the buffer output size.
2352    (*bufferOutSize) = length + 1;
2353
2354    // Return the result.
2355    return(result);
2356}
2357
2358static M4OSA_ERR
2359videoEditor_fromUTF8Fct(
2360                M4OSA_UInt8*                        pBufferIn,
2361                M4OSA_Void*                         pBufferOut,
2362                M4OSA_UInt32*                       bufferOutSize)
2363{
2364    M4OSA_ERR    result = M4NO_ERROR;
2365    M4OSA_UInt32 length = 0;
2366
2367    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_fromUTF8Fct()");
2368
2369    // Determine the length of the input buffer.
2370    if (M4OSA_NULL != pBufferIn)
2371    {
2372        length = strlen((const char *)pBufferIn);
2373    }
2374
2375    // Check if the output buffer is large enough to hold the input buffer.
2376    if ((*bufferOutSize) > length)
2377    {
2378        // Check if the input buffer is not M4OSA_NULL.
2379        if (M4OSA_NULL != pBufferIn)
2380        {
2381            // Copy the temp path, ignore the result.
2382            M4OSA_chrNCopy((M4OSA_Char *)pBufferOut, (M4OSA_Char *)pBufferIn, length);
2383        }
2384        else
2385        {
2386            // Set the output buffer to an empty string.
2387            (*(M4OSA_Char *)pBufferOut) = 0;
2388        }
2389    }
2390    else
2391    {
2392        // The buffer is too small.
2393        result = M4xVSSWAR_BUFFER_OUT_TOO_SMALL;
2394    }
2395
2396    // Return the buffer output size.
2397    (*bufferOutSize) = length + 1;
2398
2399    // Return the result.
2400    return(result);
2401}
2402
2403static M4OSA_ERR
2404videoEditor_getTextRgbBufferFct(
2405                M4OSA_Void*                         pRenderingData,
2406                M4OSA_Void*                         pTextBuffer,
2407                M4OSA_UInt32                        textBufferSize,
2408                M4VIFI_ImagePlane**                 pOutputPlane)
2409{
2410    M4OSA_ERR result = M4NO_ERROR;
2411
2412    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_getTextRgbBufferFct()");
2413
2414    // Return the result.
2415    return(result);
2416}
2417
2418static void
2419videoEditor_callOnProgressUpdate(
2420                ManualEditContext*                  pContext,
2421                int                                 task,
2422                int                                 progress)
2423{
2424    JNIEnv* pEnv = NULL;
2425
2426
2427    // Attach the current thread.
2428    pContext->pVM->AttachCurrentThread(&pEnv, NULL);
2429
2430
2431    // Call the on completion callback.
2432    pEnv->CallVoidMethod(pContext->engine, pContext->onProgressUpdateMethodId,
2433     videoEditJava_getEngineCToJava(task), progress);
2434
2435
2436    // Detach the current thread.
2437    pContext->pVM->DetachCurrentThread();
2438}
2439
2440static void
2441videoEditor_freeContext(
2442                JNIEnv*                             pEnv,
2443                ManualEditContext**                 ppContext)
2444{
2445    ManualEditContext* pContext = M4OSA_NULL;
2446
2447    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_freeContext");
2448
2449    // Set the context pointer.
2450    pContext = (*ppContext);
2451
2452    // Check if the context was set.
2453    if (M4OSA_NULL != pContext)
2454    {
2455        // Check if a global reference to the engine object was set.
2456        if (NULL != pContext->engine)
2457        {
2458            // Free the global reference.
2459            pEnv->DeleteGlobalRef(pContext->engine);
2460            pContext->engine = NULL;
2461        }
2462
2463        // Check if the temp path was set.
2464        if (M4OSA_NULL != pContext->initParams.pTempPath)
2465        {
2466            // Free the memory allocated for the temp path.
2467            videoEditOsal_free(pContext->initParams.pTempPath);
2468            pContext->initParams.pTempPath = M4OSA_NULL;
2469        }
2470
2471        // Check if the file writer was set.
2472        if (M4OSA_NULL != pContext->initParams.pFileWritePtr)
2473        {
2474            // Free the memory allocated for the file writer.
2475            videoEditOsal_free(pContext->initParams.pFileWritePtr);
2476            pContext->initParams.pFileWritePtr = M4OSA_NULL;
2477        }
2478
2479        // Check if the file reader was set.
2480        if (M4OSA_NULL != pContext->initParams.pFileReadPtr)
2481        {
2482            // Free the memory allocated for the file reader.
2483            videoEditOsal_free(pContext->initParams.pFileReadPtr);
2484            pContext->initParams.pFileReadPtr = M4OSA_NULL;
2485        }
2486
2487        // Free the memory allocated for the context.
2488        videoEditOsal_free(pContext);
2489        pContext = M4OSA_NULL;
2490
2491        // Reset the context pointer.
2492        (*ppContext) = M4OSA_NULL;
2493    }
2494}
2495
2496static jobject
2497videoEditor_getVersion(
2498                JNIEnv*                             pEnv,
2499                jobject                             thiz)
2500{
2501    bool           isSuccessful          = true;
2502    jobject        version         = NULL;
2503    M4_VersionInfo versionInfo     = {0, 0, 0, 0};
2504    M4OSA_ERR      result          = M4NO_ERROR;
2505
2506    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_getVersion()");
2507
2508    versionInfo.m_structSize = sizeof(versionInfo);
2509    versionInfo.m_major = VIDEOEDITOR_VERSION_MAJOR;
2510    versionInfo.m_minor = VIDEOEDITOR_VERSION_MINOR;
2511    versionInfo.m_revision = VIDEOEDITOR_VERSION_REVISION;
2512
2513    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_getVersion() major %d,\
2514     minor %d, revision %d", versionInfo.m_major, versionInfo.m_minor, versionInfo.m_revision);
2515
2516    // Create a version object.
2517    videoEditClasses_createVersion(&isSuccessful, pEnv, &versionInfo, &version);
2518
2519    // Return the version object.
2520    return(version);
2521}
2522
2523static void
2524videoEditor_init(
2525                JNIEnv*                             pEnv,
2526                jobject                             thiz,
2527                jstring                             tempPath,
2528                jstring                             libraryPath)
2529{
2530    bool                  initialized            = true;
2531    ManualEditContext*    pContext               = M4OSA_NULL;
2532    VideoEditJava_EngineMethodIds methodIds              = {NULL};
2533    M4OSA_Char*           pLibraryPath           = M4OSA_NULL;
2534    M4OSA_Char*           pTextRendererPath      = M4OSA_NULL;
2535    M4OSA_UInt32          textRendererPathLength = 0;
2536    M4OSA_ERR             result                 = M4NO_ERROR;
2537
2538    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_init()");
2539
2540    // Add a text marker (the condition must always be true).
2541    ADD_TEXT_MARKER_FUN(NULL != pEnv)
2542
2543    // Get the context.
2544    pContext = (ManualEditContext*)videoEditClasses_getContext(&initialized, pEnv, thiz);
2545
2546    // Get the engine method ids.
2547    videoEditJava_getEngineMethodIds(&initialized, pEnv, &methodIds);
2548
2549    // Validate the tempPath parameter.
2550    videoEditJava_checkAndThrowIllegalArgumentException(&initialized, pEnv,
2551                                                (NULL == tempPath),
2552                                                "tempPath is null");
2553
2554    // Make sure that the context was not set already.
2555    videoEditJava_checkAndThrowIllegalStateException(&initialized, pEnv,
2556                                             (M4OSA_NULL != pContext),
2557                                             "already initialized");
2558
2559    // Check if the initialization succeeded (required because of dereferencing of psContext,
2560    // and freeing when initialization fails).
2561    if (initialized)
2562    {
2563        // Allocate a new context.
2564        pContext = new ManualEditContext;
2565
2566        // Check if the initialization succeeded (required because of dereferencing of psContext).
2567        //if (initialized)
2568        if (pContext != NULL)
2569        {
2570            // Set the state to not initialized.
2571            pContext->state = ManualEditState_NOT_INITIALIZED;
2572
2573            // Allocate a file read pointer structure.
2574            pContext->initParams.pFileReadPtr =
2575             (M4OSA_FileReadPointer*)videoEditOsal_alloc(&initialized, pEnv,
2576              sizeof(M4OSA_FileReadPointer), "FileReadPointer");
2577
2578            // Allocate a file write pointer structure.
2579            pContext->initParams.pFileWritePtr =
2580             (M4OSA_FileWriterPointer*)videoEditOsal_alloc(&initialized, pEnv,
2581              sizeof(M4OSA_FileWriterPointer), "FileWriterPointer");
2582
2583            // Get the temp path.
2584            M4OSA_Char* tmpString =
2585                (M4OSA_Char *)videoEditJava_getString(&initialized, pEnv, tempPath,
2586                NULL, M4OSA_NULL);
2587            M4OSA_UInt32 length = strlen((const char *)tmpString);
2588            // Malloc additional 2 bytes for beginning and tail separator.
2589            M4OSA_UInt32 pathLength = length + 2;
2590
2591            pContext->initParams.pTempPath = (M4OSA_Char *)
2592                 M4OSA_32bitAlignedMalloc(pathLength, 0x0, (M4OSA_Char *)"tempPath");
2593
2594            //initialize the first char. so that strcat works.
2595            M4OSA_Char *ptmpChar = (M4OSA_Char*)pContext->initParams.pTempPath;
2596            ptmpChar[0] = 0x00;
2597            strncat((char *)pContext->initParams.pTempPath, (const char *)tmpString,
2598                length);
2599            strncat((char *)pContext->initParams.pTempPath, (const char *)"/", (size_t)1);
2600            free(tmpString);
2601            tmpString = NULL;
2602            pContext->mIsUpdateOverlay = false;
2603            pContext->mOverlayFileName = NULL;
2604            pContext->decoders = NULL;
2605        }
2606
2607        // Check if the initialization succeeded
2608        // (required because of dereferencing of pContext, pFileReadPtr and pFileWritePtr).
2609        if (initialized)
2610        {
2611
2612            // Initialize the OSAL file system function pointers.
2613            videoEditOsal_getFilePointers(pContext->initParams.pFileReadPtr ,
2614                                          pContext->initParams.pFileWritePtr);
2615
2616            // Set the UTF8 conversion functions.
2617            pContext->initParams.pConvToUTF8Fct   = videoEditor_toUTF8Fct;
2618            pContext->initParams.pConvFromUTF8Fct = videoEditor_fromUTF8Fct;
2619
2620            // Set the callback method ids.
2621            pContext->onProgressUpdateMethodId = methodIds.onProgressUpdate;
2622
2623            // Set the virtual machine.
2624            pEnv->GetJavaVM(&(pContext->pVM));
2625
2626            // Create a global reference to the engine object.
2627            pContext->engine = pEnv->NewGlobalRef(thiz);
2628
2629            // Check if the global reference could be created.
2630            videoEditJava_checkAndThrowRuntimeException(&initialized, pEnv,
2631             (NULL == pContext->engine), M4NO_ERROR);
2632        }
2633
2634        // Check if the initialization succeeded (required because of dereferencing of pContext).
2635        if (initialized)
2636        {
2637            // Log the API call.
2638            VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4xVSS_Init()");
2639
2640            // Initialize the visual studio library.
2641            result = M4xVSS_Init(&pContext->engineContext, &pContext->initParams);
2642
2643            // Log the result.
2644            VIDEOEDIT_LOG_RESULT(ANDROID_LOG_INFO, "VIDEO_EDITOR",
2645             videoEditOsal_getResultString(result));
2646
2647            // Check if the library could be initialized.
2648            videoEditJava_checkAndThrowRuntimeException(&initialized, pEnv,
2649             (M4NO_ERROR != result), result);
2650
2651            // Get platform video decoder capablities.
2652            result = M4xVSS_getVideoDecoderCapabilities(&pContext->decoders);
2653
2654            videoEditJava_checkAndThrowRuntimeException(&initialized, pEnv,
2655             (M4NO_ERROR != result), result);
2656        }
2657
2658        if(initialized)
2659        {
2660            pContext->mPreviewController = new VideoEditorPreviewController();
2661            videoEditJava_checkAndThrowIllegalStateException(&initialized, pEnv,
2662                                 (M4OSA_NULL == pContext->mPreviewController),
2663                                 "not initialized");
2664            pContext->mAudioSettings =
2665             (M4xVSS_AudioMixingSettings *)
2666             M4OSA_32bitAlignedMalloc(sizeof(M4xVSS_AudioMixingSettings),0x0,
2667             (M4OSA_Char *)"mAudioSettings");
2668            videoEditJava_checkAndThrowIllegalStateException(&initialized, pEnv,
2669                                     (M4OSA_NULL == pContext->mAudioSettings),
2670                                     "not initialized");
2671            pContext->mAudioSettings->pFile = M4OSA_NULL;
2672            pContext->mAudioSettings->pPCMFilePath = M4OSA_NULL;
2673            pContext->mAudioSettings->bRemoveOriginal = 0;
2674            pContext->mAudioSettings->uiNbChannels = 0;
2675            pContext->mAudioSettings->uiSamplingFrequency = 0;
2676            pContext->mAudioSettings->uiExtendedSamplingFrequency = 0;
2677            pContext->mAudioSettings->uiAddCts = 0;
2678            pContext->mAudioSettings->uiAddVolume = 0;
2679            pContext->mAudioSettings->beginCutMs = 0;
2680            pContext->mAudioSettings->endCutMs = 0;
2681            pContext->mAudioSettings->fileType = 0;
2682            pContext->mAudioSettings->bLoop = 0;
2683            pContext->mAudioSettings->uiInDucking_lowVolume  = 0;
2684            pContext->mAudioSettings->bInDucking_enable  = 0;
2685            pContext->mAudioSettings->uiBTChannelCount  = 0;
2686            pContext->mAudioSettings->uiInDucking_threshold = 0;
2687        }
2688        // Check if the library could be initialized.
2689        if (initialized)
2690        {
2691            // Set the state to initialized.
2692            pContext->state = ManualEditState_INITIALIZED;
2693        }
2694
2695        // Set the context.
2696        videoEditClasses_setContext(&initialized, pEnv, thiz, (void* )pContext);
2697        pLibraryPath = M4OSA_NULL;
2698
2699        pContext->pEditSettings = M4OSA_NULL;
2700        // Cleanup if anything went wrong during initialization.
2701        if (!initialized)
2702        {
2703            // Free the context.
2704            videoEditor_freeContext(pEnv, &pContext);
2705        }
2706    }
2707}
2708
2709/*+ PROGRESS CB */
2710static
2711M4OSA_ERR videoEditor_processClip(
2712                            JNIEnv*  pEnv,
2713                            jobject  thiz,
2714                            int      unuseditemID) {
2715
2716    bool               loaded           = true;
2717    ManualEditContext* pContext         = NULL;
2718    M4OSA_UInt8        progress         = 0;
2719    M4OSA_UInt8        progressBase     = 0;
2720    M4OSA_UInt8        lastProgress     = 0;
2721    M4OSA_ERR          result           = M4NO_ERROR;
2722
2723    // Get the context.
2724    pContext = (ManualEditContext*)videoEditClasses_getContext(&loaded, pEnv, thiz);
2725
2726    // Make sure that the context was set.
2727    videoEditJava_checkAndThrowIllegalStateException(&loaded, pEnv,
2728                                             (M4OSA_NULL == pContext),
2729                                             "not initialized");
2730
2731    // We start in Analyzing state
2732    pContext->state = ManualEditState_INITIALIZED;
2733    M4OSA_ERR          completionResult = M4VSS3GPP_WAR_ANALYZING_DONE;
2734    ManualEditState    completionState  = ManualEditState_OPENED;
2735    ManualEditState    errorState       = ManualEditState_ANALYZING_ERROR;
2736
2737    // While analyzing progress goes from 0 to 10 (except Kenburn clip
2738    // generation, which goes from 0 to 50)
2739    progressBase     = 0;
2740
2741    // Set the text rendering function.
2742    if (M4OSA_NULL != pContext->pTextRendererFunction)
2743    {
2744        // Use the text renderer function in the library.
2745        pContext->pEditSettings->xVSS.pTextRenderingFct = pContext->pTextRendererFunction;
2746    }
2747    else
2748    {
2749        // Use the internal text renderer function.
2750        pContext->pEditSettings->xVSS.pTextRenderingFct = videoEditor_getTextRgbBufferFct;
2751    }
2752
2753    // Send the command.
2754    ALOGV("videoEditor_processClip ITEM %d Calling M4xVSS_SendCommand()", unuseditemID);
2755    result = M4xVSS_SendCommand(pContext->engineContext, pContext->pEditSettings);
2756    ALOGV("videoEditor_processClip ITEM %d M4xVSS_SendCommand() returned 0x%x",
2757        unuseditemID, (unsigned int) result);
2758
2759    // Remove warnings indications (we only care about errors here)
2760    if ((result == M4VSS3GPP_WAR_TRANSCODING_NECESSARY)
2761        || (result == M4VSS3GPP_WAR_OUTPUTFILESIZE_EXCEED)) {
2762        result = M4NO_ERROR;
2763    }
2764
2765    // Send the first progress indication (=0)
2766    ALOGV("VERY FIRST PROGRESS videoEditor_processClip ITEM %d Progress indication %d",
2767        unuseditemID, progress);
2768    pEnv->CallVoidMethod(pContext->engine, pContext->onProgressUpdateMethodId,
2769        unuseditemID, progress);
2770
2771    // Check if a task is being performed.
2772    // ??? ADD STOPPING MECHANISM
2773    ALOGV("videoEditor_processClip Entering processing loop");
2774    M4OSA_UInt8 prevReportedProgress = 0;
2775    while((result == M4NO_ERROR)
2776        &&(pContext->state!=ManualEditState_SAVED)
2777        &&(pContext->state!=ManualEditState_STOPPING)) {
2778
2779            // Perform the next processing step.
2780            //ALOGV("LVME_processClip Entering M4xVSS_Step()");
2781            result = M4xVSS_Step(pContext->engineContext, &progress);
2782
2783            if (progress != prevReportedProgress) {
2784                prevReportedProgress = progress;
2785                // Log the 1 % .. 100 % progress after processing.
2786                if (M4OSA_TRUE ==
2787                    pContext->pEditSettings->pClipList[0]->xVSS.isPanZoom) {
2788                    // For KenBurn clip generation, return 0 to 50
2789                    // for Analysis phase and 50 to 100 for Saving phase
2790                    progress = progressBase + progress/2;
2791                } else {
2792                    // For export/transition clips, 0 to 10 for Analysis phase
2793                    // and 10 to 100 for Saving phase
2794                    if (ManualEditState_INITIALIZED == pContext->state) {
2795                        progress = 0.1*progress;
2796                    } else {
2797                        progress = progressBase + 0.9*progress;
2798                    }
2799                }
2800
2801                if (progress > lastProgress)
2802                {
2803                    // Send a progress notification.
2804                    ALOGV("videoEditor_processClip ITEM %d Progress indication %d",
2805                        unuseditemID, progress);
2806                    pEnv->CallVoidMethod(pContext->engine,
2807                        pContext->onProgressUpdateMethodId,
2808                        unuseditemID, progress);
2809                    lastProgress = progress;
2810                }
2811            }
2812
2813            // Check if processing has been completed.
2814            if (result == completionResult)
2815            {
2816                // Set the state to the completions state.
2817                pContext->state = completionState;
2818                ALOGV("videoEditor_processClip ITEM %d STATE changed to %d",
2819                    unuseditemID, pContext->state);
2820
2821                // Reset progress indication, as we switch to next state
2822                lastProgress = 0;
2823
2824                // Reset error code, as we start a new round of processing
2825                result = M4NO_ERROR;
2826
2827                // Check if we are analyzing input
2828                if (pContext->state == ManualEditState_OPENED) {
2829                    // File is opened, we must start saving it
2830                    ALOGV("videoEditor_processClip Calling M4xVSS_SaveStart()");
2831                    result = M4xVSS_SaveStart(pContext->engineContext,
2832                        (M4OSA_Char*)pContext->pEditSettings->pOutputFile,
2833                        (M4OSA_UInt32)pContext->pEditSettings->uiOutputPathSize);
2834                    ALOGV("videoEditor_processClip ITEM %d SaveStart() returned 0x%x",
2835                        unuseditemID, (unsigned int) result);
2836
2837                    // Set the state to saving.
2838                    pContext->state  = ManualEditState_SAVING;
2839                    completionState  = ManualEditState_SAVED;
2840                    completionResult = M4VSS3GPP_WAR_SAVING_DONE;
2841                    errorState       = ManualEditState_SAVING_ERROR;
2842
2843                    // While saving, progress goes from 10 to 100
2844                    // except for Kenburn clip which goes from 50 to 100
2845                    if (M4OSA_TRUE ==
2846                            pContext->pEditSettings->pClipList[0]->xVSS.isPanZoom) {
2847                        progressBase = 50;
2848                    } else {
2849                        progressBase     = 10;
2850                    }
2851                }
2852                // Check if we encoding is ongoing
2853                else if (pContext->state == ManualEditState_SAVED) {
2854
2855                    // Send a progress notification.
2856                    progress = 100;
2857                    ALOGV("videoEditor_processClip ITEM %d Last progress indication %d",
2858                        unuseditemID, progress);
2859                    pEnv->CallVoidMethod(pContext->engine,
2860                        pContext->onProgressUpdateMethodId,
2861                        unuseditemID, progress);
2862
2863
2864                    // Stop the encoding.
2865                    ALOGV("videoEditor_processClip Calling M4xVSS_SaveStop()");
2866                    result = M4xVSS_SaveStop(pContext->engineContext);
2867                    ALOGV("videoEditor_processClip M4xVSS_SaveStop() returned 0x%x", result);
2868                }
2869                // Other states are unexpected
2870                else {
2871                    result = M4ERR_STATE;
2872                    ALOGE("videoEditor_processClip ITEM %d State ERROR 0x%x",
2873                        unuseditemID, (unsigned int) result);
2874                }
2875            }
2876
2877            // Check if an error occurred.
2878            if (result != M4NO_ERROR)
2879            {
2880                // Set the state to the error state.
2881                pContext->state = errorState;
2882
2883                // Log the result.
2884                ALOGE("videoEditor_processClip ITEM %d Processing ERROR 0x%x",
2885                    unuseditemID, (unsigned int) result);
2886            }
2887    }
2888
2889    // Return the error result
2890    ALOGE("videoEditor_processClip ITEM %d END 0x%x", unuseditemID, (unsigned int) result);
2891    return result;
2892}
2893/*+ PROGRESS CB */
2894
2895static int
2896videoEditor_generateClip(
2897                JNIEnv*                             pEnv,
2898                jobject                             thiz,
2899                jobject                             settings) {
2900    bool               loaded   = true;
2901    ManualEditContext* pContext = M4OSA_NULL;
2902    M4OSA_ERR          result   = M4NO_ERROR;
2903
2904    ALOGV("videoEditor_generateClip START");
2905
2906    // Get the context.
2907    pContext = (ManualEditContext*)videoEditClasses_getContext(&loaded, pEnv, thiz);
2908
2909    Mutex::Autolock autoLock(pContext->mLock);
2910
2911    // Validate the settings parameter.
2912    videoEditJava_checkAndThrowIllegalArgumentException(&loaded, pEnv,
2913                                                (NULL == settings),
2914                                                "settings is null");
2915
2916    // Make sure that the context was set.
2917    videoEditJava_checkAndThrowIllegalStateException(&loaded, pEnv,
2918                                             (M4OSA_NULL == pContext),
2919                                             "not initialized");
2920
2921    // Load the clip settings
2922    ALOGV("videoEditor_generateClip Calling videoEditor_loadSettings");
2923    videoEditor_loadSettings(pEnv, thiz, settings);
2924    ALOGV("videoEditor_generateClip videoEditor_loadSettings returned");
2925
2926    // Generate the clip
2927    ALOGV("videoEditor_generateClip Calling LVME_processClip");
2928    result = videoEditor_processClip(pEnv, thiz, 0 /*item id is unused*/);
2929    ALOGV("videoEditor_generateClip videoEditor_processClip returned 0x%x", result);
2930
2931    if (pContext->state != ManualEditState_INITIALIZED) {
2932        // Free up memory (whatever the result)
2933        videoEditor_unloadSettings(pEnv, thiz);
2934    }
2935
2936    ALOGV("videoEditor_generateClip END 0x%x", (unsigned int) result);
2937    return result;
2938}
2939
2940static void
2941videoEditor_loadSettings(
2942                JNIEnv*                             pEnv,
2943                jobject                             thiz,
2944                jobject                             settings)
2945{
2946    bool               needToBeLoaded   = true;
2947    ManualEditContext* pContext = M4OSA_NULL;
2948
2949    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_loadSettings()");
2950
2951    // Add a code marker (the condition must always be true).
2952    ADD_CODE_MARKER_FUN(NULL != pEnv)
2953
2954    // Get the context.
2955    pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded,
2956                                                                pEnv, thiz);
2957
2958    // Validate the settings parameter.
2959    videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv,
2960                                                (NULL == settings),
2961                                                "settings is null");
2962
2963    // Make sure that the context was set.
2964    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
2965                                             (M4OSA_NULL == pContext),
2966                                             "not initialized");
2967
2968    // Check if the context is valid (required because the context is dereferenced).
2969    if (needToBeLoaded)
2970    {
2971        // Make sure that we are in a correct state.
2972        videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
2973                             (pContext->state != ManualEditState_INITIALIZED),
2974                             "settings already loaded");
2975
2976        // Retrieve the edit settings.
2977        if(pContext->pEditSettings != M4OSA_NULL) {
2978            videoEditClasses_freeEditSettings(&pContext->pEditSettings);
2979            pContext->pEditSettings = M4OSA_NULL;
2980        }
2981        videoEditClasses_getEditSettings(&needToBeLoaded, pEnv, settings,
2982            &pContext->pEditSettings,true);
2983    }
2984
2985    // Check if the edit settings could be retrieved.
2986    if (needToBeLoaded)
2987    {
2988        // Log the edit settings.
2989        VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "inside load settings");
2990        VIDEOEDIT_LOG_EDIT_SETTINGS(pContext->pEditSettings);
2991    }
2992    ALOGV("videoEditor_loadSettings END");
2993}
2994
2995
2996
2997static void
2998videoEditor_unloadSettings(
2999                JNIEnv*                             pEnv,
3000                jobject                             thiz)
3001{
3002    bool               needToBeUnLoaded = true;
3003    ManualEditContext* pContext = M4OSA_NULL;
3004    M4OSA_ERR          result   = M4NO_ERROR;
3005
3006    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_unloadSettings()");
3007
3008    // Get the context.
3009    pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeUnLoaded, pEnv, thiz);
3010
3011    // Make sure that the context was set.
3012    videoEditJava_checkAndThrowIllegalStateException(&needToBeUnLoaded, pEnv,
3013                                             (M4OSA_NULL == pContext),
3014                                             "not initialized");
3015
3016    // Check if the context is valid (required because the context is dereferenced).
3017    if (needToBeUnLoaded)
3018    {
3019        ALOGV("videoEditor_unloadSettings state %d", pContext->state);
3020        // Make sure that we are in a correct state.
3021        videoEditJava_checkAndThrowIllegalStateException(&needToBeUnLoaded, pEnv,
3022                     ((pContext->state != ManualEditState_ANALYZING      ) &&
3023                      (pContext->state != ManualEditState_ANALYZING_ERROR) &&
3024                      (pContext->state != ManualEditState_OPENED         ) &&
3025                      (pContext->state != ManualEditState_SAVING_ERROR   ) &&
3026                      (pContext->state != ManualEditState_SAVED          ) &&
3027                      (pContext->state != ManualEditState_STOPPING       ) ),
3028                     "videoEditor_unloadSettings no load settings in progress");
3029    }
3030
3031    // Check if we are in a correct state.
3032    if (needToBeUnLoaded)
3033    {
3034        // Check if the thread could be stopped.
3035        if (needToBeUnLoaded)
3036        {
3037            // Close the command.
3038            ALOGV("videoEditor_unloadSettings Calling M4xVSS_CloseCommand()");
3039            result = M4xVSS_CloseCommand(pContext->engineContext);
3040            ALOGV("videoEditor_unloadSettings M4xVSS_CloseCommand() returned 0x%x",
3041                (unsigned int)result);
3042
3043            // Check if the command could be closed.
3044            videoEditJava_checkAndThrowRuntimeException(&needToBeUnLoaded, pEnv,
3045             (M4NO_ERROR != result), result);
3046        }
3047
3048        // Check if the command could be closed.
3049        if (needToBeUnLoaded)
3050        {
3051            // Free the edit settings.
3052            //videoEditClasses_freeEditSettings(&pContext->pEditSettings);
3053
3054            // Reset the thread result.
3055            pContext->threadResult = M4NO_ERROR;
3056
3057            // Reset the thread progress.
3058            pContext->threadProgress = 0;
3059
3060            // Set the state to initialized.
3061            pContext->state = ManualEditState_INITIALIZED;
3062        }
3063    }
3064}
3065
3066static void
3067videoEditor_stopEncoding(
3068                JNIEnv*                             pEnv,
3069                jobject                             thiz)
3070{
3071    bool               stopped  = true;
3072    ManualEditContext* pContext = M4OSA_NULL;
3073    M4OSA_ERR          result   = M4NO_ERROR;
3074
3075    ALOGV("videoEditor_stopEncoding START");
3076
3077    // Get the context.
3078    pContext = (ManualEditContext*)videoEditClasses_getContext(&stopped, pEnv, thiz);
3079
3080    // Change state and get Lock
3081    // This will ensure the generateClip function exits
3082    pContext->state = ManualEditState_STOPPING;
3083    Mutex::Autolock autoLock(pContext->mLock);
3084
3085    // Make sure that the context was set.
3086    videoEditJava_checkAndThrowIllegalStateException(&stopped, pEnv,
3087                                             (M4OSA_NULL == pContext),
3088                                             "not initialized");
3089
3090    if (stopped) {
3091
3092        // Check if the command should be closed.
3093        if (pContext->state != ManualEditState_INITIALIZED)
3094        {
3095            // Close the command.
3096            ALOGV("videoEditor_stopEncoding Calling M4xVSS_CloseCommand()");
3097            result = M4xVSS_CloseCommand(pContext->engineContext);
3098            ALOGV("videoEditor_stopEncoding M4xVSS_CloseCommand() returned 0x%x",
3099                (unsigned int)result);
3100        }
3101
3102        // Check if the command could be closed.
3103        videoEditJava_checkAndThrowRuntimeException(&stopped, pEnv,
3104            (M4NO_ERROR != result), result);
3105
3106        // Free the edit settings.
3107        videoEditClasses_freeEditSettings(&pContext->pEditSettings);
3108
3109        // Set the state to initialized.
3110        pContext->state = ManualEditState_INITIALIZED;
3111    }
3112
3113}
3114
3115static void
3116videoEditor_release(
3117                JNIEnv*                             pEnv,
3118                jobject                             thiz)
3119{
3120    bool               released = true;
3121    ManualEditContext* pContext = M4OSA_NULL;
3122    M4OSA_ERR          result   = M4NO_ERROR;
3123
3124    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_release()");
3125
3126    // Add a text marker (the condition must always be true).
3127    ADD_TEXT_MARKER_FUN(NULL != pEnv)
3128
3129    // Get the context.
3130    pContext = (ManualEditContext*)videoEditClasses_getContext(&released, pEnv, thiz);
3131
3132    // If context is not set, return (we consider release already happened)
3133    if (pContext == NULL) {
3134        ALOGV("videoEditor_release Nothing to do, context is aleady NULL");
3135        return;
3136    }
3137
3138
3139    // Check if the context is valid (required because the context is dereferenced).
3140    if (released)
3141    {
3142        if (pContext->state != ManualEditState_INITIALIZED)
3143        {
3144            // Change state and get Lock
3145            // This will ensure the generateClip function exits if it is running
3146            pContext->state = ManualEditState_STOPPING;
3147            Mutex::Autolock autoLock(pContext->mLock);
3148        }
3149
3150        // Reset the context.
3151        videoEditClasses_setContext(&released, pEnv, thiz, (void *)M4OSA_NULL);
3152
3153        // Check if the command should be closed.
3154        if (pContext->state != ManualEditState_INITIALIZED)
3155        {
3156            // Close the command.
3157            ALOGV("videoEditor_release Calling M4xVSS_CloseCommand() state =%d",
3158                pContext->state);
3159            result = M4xVSS_CloseCommand(pContext->engineContext);
3160            ALOGV("videoEditor_release M4xVSS_CloseCommand() returned 0x%x",
3161                (unsigned int)result);
3162
3163            // Check if the command could be closed.
3164            videoEditJava_checkAndThrowRuntimeException(&released, pEnv,
3165                (M4NO_ERROR != result), result);
3166        }
3167
3168        // Cleanup the engine.
3169        ALOGV("videoEditor_release Calling M4xVSS_CleanUp()");
3170        result = M4xVSS_CleanUp(pContext->engineContext);
3171        ALOGV("videoEditor_release M4xVSS_CleanUp() returned 0x%x", (unsigned int)result);
3172
3173        // Check if the cleanup succeeded.
3174        videoEditJava_checkAndThrowRuntimeException(&released, pEnv,
3175            (M4NO_ERROR != result), result);
3176
3177        // Free the edit settings.
3178        videoEditClasses_freeEditSettings(&pContext->pEditSettings);
3179        pContext->pEditSettings = M4OSA_NULL;
3180
3181
3182        if(pContext->mPreviewController != M4OSA_NULL)
3183        {
3184            delete pContext->mPreviewController;
3185            pContext->mPreviewController = M4OSA_NULL;
3186        }
3187
3188        // Free the mAudioSettings context.
3189        if(pContext->mAudioSettings != M4OSA_NULL)
3190        {
3191            if (pContext->mAudioSettings->pFile != NULL) {
3192                free(pContext->mAudioSettings->pFile);
3193                pContext->mAudioSettings->pFile = M4OSA_NULL;
3194            }
3195            if (pContext->mAudioSettings->pPCMFilePath != NULL) {
3196                free(pContext->mAudioSettings->pPCMFilePath);
3197                pContext->mAudioSettings->pPCMFilePath = M4OSA_NULL;
3198            }
3199
3200            free(pContext->mAudioSettings);
3201            pContext->mAudioSettings = M4OSA_NULL;
3202        }
3203        // Free video Decoders capabilities
3204        if (pContext->decoders != M4OSA_NULL) {
3205            VideoDecoder *pDecoder = NULL;
3206            VideoComponentCapabilities *pComponents = NULL;
3207            int32_t decoderNumber = pContext->decoders->decoderNumber;
3208            if (pContext->decoders->decoder != NULL &&
3209                decoderNumber > 0) {
3210                pDecoder = pContext->decoders->decoder;
3211                for (int32_t k = 0; k < decoderNumber; k++) {
3212                    // free each component
3213                    ALOGV("decoder index :%d",k);
3214                    if (pDecoder != NULL &&
3215                        pDecoder->component != NULL &&
3216                        pDecoder->componentNumber > 0) {
3217                        ALOGV("component number %d",pDecoder->componentNumber);
3218                        int32_t componentNumber =
3219                           pDecoder->componentNumber;
3220
3221                        pComponents = pDecoder->component;
3222                        for (int32_t i = 0; i< componentNumber; i++) {
3223                            ALOGV("component index :%d",i);
3224                            if (pComponents != NULL &&
3225                                pComponents->profileLevel != NULL) {
3226                                free(pComponents->profileLevel);
3227                                pComponents->profileLevel = NULL;
3228                            }
3229                            pComponents++;
3230                        }
3231                        free(pDecoder->component);
3232                        pDecoder->component = NULL;
3233                    }
3234
3235                    pDecoder++;
3236                }
3237                free(pContext->decoders->decoder);
3238                pContext->decoders->decoder = NULL;
3239            }
3240            free(pContext->decoders);
3241            pContext->decoders = NULL;
3242        }
3243
3244        videoEditor_freeContext(pEnv, &pContext);
3245    }
3246}
3247
3248static int
3249videoEditor_registerManualEditMethods(
3250                JNIEnv*                             pEnv)
3251{
3252    int result = -1;
3253
3254    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
3255     "videoEditor_registerManualEditMethods()");
3256
3257    // Look up the engine class
3258    jclass engineClazz = pEnv->FindClass(MANUAL_EDIT_ENGINE_CLASS_NAME);
3259
3260    // Clear any resulting exceptions.
3261    pEnv->ExceptionClear();
3262
3263    // Check if the engine class was found.
3264    if (NULL != engineClazz)
3265    {
3266        // Register all the methods.
3267        if (pEnv->RegisterNatives(engineClazz, gManualEditMethods,
3268                sizeof(gManualEditMethods) / sizeof(gManualEditMethods[0])) == JNI_OK)
3269        {
3270            // Success.
3271            result = 0;
3272        }
3273    }
3274
3275    // Return the result.
3276    return(result);
3277}
3278
3279/*******Audio Graph*******/
3280
3281static M4OSA_UInt32 getDecibelSound(M4OSA_UInt32 value)
3282{
3283    int dbSound = 1;
3284
3285    if (value == 0) return 0;
3286
3287    if (value > 0x4000 && value <= 0x8000) // 32768
3288        dbSound = 90;
3289    else if (value > 0x2000 && value <= 0x4000) // 16384
3290        dbSound = 84;
3291    else if (value > 0x1000 && value <= 0x2000) // 8192
3292        dbSound = 78;
3293    else if (value > 0x0800 && value <= 0x1000) // 4028
3294        dbSound = 72;
3295    else if (value > 0x0400 && value <= 0x0800) // 2048
3296        dbSound = 66;
3297    else if (value > 0x0200 && value <= 0x0400) // 1024
3298        dbSound = 60;
3299    else if (value > 0x0100 && value <= 0x0200) // 512
3300        dbSound = 54;
3301    else if (value > 0x0080 && value <= 0x0100) // 256
3302        dbSound = 48;
3303    else if (value > 0x0040 && value <= 0x0080) // 128
3304        dbSound = 42;
3305    else if (value > 0x0020 && value <= 0x0040) // 64
3306        dbSound = 36;
3307    else if (value > 0x0010 && value <= 0x0020) // 32
3308        dbSound = 30;
3309    else if (value > 0x0008 && value <= 0x0010) //16
3310        dbSound = 24;
3311    else if (value > 0x0007 && value <= 0x0008) //8
3312        dbSound = 24;
3313    else if (value > 0x0003 && value <= 0x0007) // 4
3314        dbSound = 18;
3315    else if (value > 0x0001 && value <= 0x0003) //2
3316        dbSound = 12;
3317    else if (value > 0x000 && value == 0x0001) // 1
3318        dbSound = 6;
3319    else
3320        dbSound = 0;
3321
3322    return dbSound;
3323}
3324
3325typedef struct
3326{
3327    M4OSA_UInt8      *m_dataAddress;
3328    M4OSA_UInt32    m_bufferSize;
3329} M4AM_Buffer;
3330
3331
3332M4OSA_UInt8 logLookUp[256] = {
33330,120,137,146,154,159,163,167,171,173,176,178,181,182,184,186,188,189,190,192,193,
3334194,195,196,198,199,199,200,201,202,203,204,205,205,206,207,207,208,209,209,210,
3335211,211,212,212,213,213,214,215,215,216,216,216,217,217,218,218,219,219,220,220,
3336220,221,221,222,222,222,223,223,223,224,224,224,225,225,225,226,226,226,227,227,
3337227,228,228,228,229,229,229,229,230,230,230,230,231,231,231,232,232,232,232,233,
3338233,233,233,233,234,234,234,234,235,235,235,235,236,236,236,236,236,237,237,237,
3339237,237,238,238,238,238,238,239,239,239,239,239,240,240,240,240,240,240,241,241,
3340241,241,241,241,242,242,242,242,242,242,243,243,243,243,243,243,244,244,244,244,
3341244,244,245,245,245,245,245,245,245,246,246,246,246,246,246,246,247,247,247,247,
3342247,247,247,247,248,248,248,248,248,248,248,249,249,249,249,249,249,249,249,250,
3343250,250,250,250,250,250,250,250,251,251,251,251,251,251,251,251,252,252,252,252,
3344252,252,252,252,252,253,253,253,253,253,253,253,253,253,253,254,254,254,254,254,
3345254,254,254,254,255,255,255,255,255,255,255,255,255,255,255};
3346
3347M4OSA_ERR M4MA_generateAudioGraphFile(JNIEnv* pEnv, M4OSA_Char* pInputFileURL,
3348                     M4OSA_Char* pOutFileURL,
3349                     M4OSA_UInt32 samplesPerValue,
3350                     M4OSA_UInt32 channels,
3351                     M4OSA_UInt32 frameDuration,
3352                     ManualEditContext* pContext)
3353{
3354    M4OSA_ERR           err;
3355    M4OSA_Context       outFileHandle = M4OSA_NULL;
3356    M4OSA_Context       inputFileHandle = M4OSA_NULL;
3357    M4AM_Buffer         bufferIn = {0, 0};
3358    M4OSA_UInt32        peakVolumeDbValue = 0;
3359    M4OSA_UInt32        samplesCountInBytes= 0 , numBytesToRead = 0, index = 0;
3360    M4OSA_UInt32        writeCount = 0, samplesCountBigEndian = 0, volumeValuesCount = 0;
3361    M4OSA_Int32         seekPos = 0;
3362    M4OSA_UInt32        fileSize = 0;
3363    M4OSA_UInt32        totalBytesRead = 0;
3364    M4OSA_UInt32        prevProgress = 0;
3365    bool                threadStarted = true;
3366
3367    int dbValue = 0;
3368    M4OSA_Int16 *ptr16 ;
3369
3370    jclass engineClass = pEnv->FindClass(MANUAL_EDIT_ENGINE_CLASS_NAME);
3371    videoEditJava_checkAndThrowIllegalStateException(&threadStarted, pEnv,
3372                                             (M4OSA_NULL == engineClass),
3373                                             "not initialized");
3374
3375    /* register the call back function pointer */
3376    pContext->onAudioGraphProgressUpdateMethodId =
3377            pEnv->GetMethodID(engineClass, "onAudioGraphExtractProgressUpdate", "(IZ)V");
3378
3379
3380    /* ENTER */
3381    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "ENTER - M4MA_generateAudioGraphFile");
3382    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
3383            "Audio Graph samplesPerValue %d channels %d", samplesPerValue, channels);
3384
3385    /******************************************************************************
3386        OPEN INPUT AND OUTPUT FILES
3387    *******************************************************************************/
3388    err = M4OSA_fileReadOpen (&inputFileHandle, pInputFileURL, M4OSA_kFileRead);
3389    if (inputFileHandle == M4OSA_NULL) {
3390        VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR",
3391            "M4MA_generateAudioGraphFile: Cannot open input file 0x%lx", err);
3392        return err;
3393    }
3394
3395    /* get the file size for progress */
3396    err = M4OSA_fileReadGetOption(inputFileHandle, M4OSA_kFileReadGetFileSize,
3397                                (M4OSA_Void**)&fileSize);
3398    if ( err != M4NO_ERROR) {
3399        //LVMEL_LOG_ERROR("M4MA_generateAudioGraphFile : File write failed \n");
3400        jniThrowException(pEnv, "java/lang/IOException", "file size get option failed");
3401        //return -1;
3402    }
3403
3404    err = M4OSA_fileWriteOpen (&outFileHandle,(M4OSA_Char*) pOutFileURL,
3405        M4OSA_kFileCreate | M4OSA_kFileWrite);
3406    if (outFileHandle == M4OSA_NULL) {
3407        if (inputFileHandle != NULL)
3408        {
3409            M4OSA_fileReadClose(inputFileHandle);
3410        }
3411        return err;
3412    }
3413
3414    /******************************************************************************
3415        PROCESS THE SAMPLES
3416    *******************************************************************************/
3417    samplesCountInBytes = (samplesPerValue * sizeof(M4OSA_UInt16) * channels);
3418
3419    bufferIn.m_dataAddress = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc(samplesCountInBytes*sizeof(M4OSA_UInt16), 0,
3420    (M4OSA_Char*)"AudioGraph" );
3421    if ( bufferIn.m_dataAddress != M4OSA_NULL) {
3422        bufferIn.m_bufferSize = samplesCountInBytes*sizeof(M4OSA_UInt16);
3423    } else {
3424        VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR",
3425            "M4MA_generateAudioGraphFile: Malloc failed for bufferIn.m_dataAddress 0x%lx",
3426            M4ERR_ALLOC);
3427        return M4ERR_ALLOC;
3428    }
3429    /* sample to be converted to BIG endian ; store the frame duration */
3430    samplesCountBigEndian = ((frameDuration>>24)&0xff) | // move byte 3 to byte 0
3431                    ((frameDuration<<8)&0xff0000) | // move byte 1 to byte 2
3432                    ((frameDuration>>8)&0xff00) | // move byte 2 to byte 1
3433                    ((frameDuration<<24)&0xff000000); // byte 0 to byte 3
3434
3435    /* write the samples per value supplied to out file */
3436    err = M4OSA_fileWriteData (outFileHandle, (M4OSA_MemAddr8)&samplesCountBigEndian,
3437        sizeof(M4OSA_UInt32) );
3438    if (err != M4NO_ERROR) {
3439        jniThrowException(pEnv, "java/lang/IOException", "file write failed");
3440    }
3441
3442
3443    /* write UIn32 value 0 for no of values as place holder */
3444    samplesCountBigEndian = 0; /* reusing local var */
3445    err = M4OSA_fileWriteData (outFileHandle, (M4OSA_MemAddr8)&samplesCountBigEndian,
3446        sizeof(M4OSA_UInt32) );
3447    if (err != M4NO_ERROR) {
3448        jniThrowException(pEnv, "java/lang/IOException", "file write failed");
3449    }
3450
3451    /* loop until EOF */
3452    do
3453    {
3454        memset((void *)bufferIn.m_dataAddress,0,bufferIn.m_bufferSize);
3455
3456        numBytesToRead = samplesCountInBytes;
3457
3458        err =  M4OSA_fileReadData(  inputFileHandle,
3459                                    (M4OSA_MemAddr8)bufferIn.m_dataAddress,
3460                                    &numBytesToRead );
3461
3462        if (err != M4NO_ERROR) {
3463            // if out value of bytes-read is 0, break
3464            if ( numBytesToRead == 0) {
3465                VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "numBytesToRead 0x%lx",
3466                numBytesToRead);
3467                break; /* stop if file is empty or EOF */
3468            }
3469        }
3470
3471        ptr16 = (M4OSA_Int16*)bufferIn.m_dataAddress;
3472
3473        peakVolumeDbValue = 0;
3474        index = 0;
3475
3476        // loop through half the lenght frame bytes read 'cause its 16 bits samples
3477        while (index < (numBytesToRead / 2)) {
3478            /* absolute values of 16 bit sample */
3479            if (ptr16[index] < 0) {
3480                ptr16[index] = -(ptr16[index]);
3481            }
3482            peakVolumeDbValue = (peakVolumeDbValue > (M4OSA_UInt32)ptr16[index] ?\
3483             peakVolumeDbValue : (M4OSA_UInt32)ptr16[index]);
3484            index++;
3485        }
3486
3487        // move 7 bits , ignore sign bit
3488        dbValue = (peakVolumeDbValue >> 7);
3489        dbValue = logLookUp[(M4OSA_UInt8)dbValue];
3490
3491        err = M4OSA_fileWriteData (outFileHandle, (M4OSA_MemAddr8)&dbValue, sizeof(M4OSA_UInt8) );
3492        if (err != M4NO_ERROR) {
3493            VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR",
3494             "M4MA_generateAudioGraphFile : File write failed");
3495            break;
3496        }
3497
3498        volumeValuesCount ++;
3499        totalBytesRead += numBytesToRead;
3500
3501        if ((((totalBytesRead*100)/fileSize)) != prevProgress) {
3502            if ( (pContext->threadProgress != prevProgress) && (prevProgress != 0 )) {
3503                //pContext->threadProgress = prevProgress;
3504                //onWveformProgressUpdateMethodId(prevProgress, 0);
3505                //LVME_callAudioGraphOnProgressUpdate(pContext, 0, prevProgress);
3506            pEnv->CallVoidMethod(pContext->engine,
3507                                 pContext->onAudioGraphProgressUpdateMethodId,
3508                                 prevProgress, 0);
3509            VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "pContext->threadProgress %d",
3510                             prevProgress);
3511            }
3512        }
3513        prevProgress = (((totalBytesRead*100)/fileSize));
3514
3515    } while (numBytesToRead != 0);
3516
3517    VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "loop 0x%lx", volumeValuesCount);
3518
3519    /* if some error occured in fwrite */
3520    if (numBytesToRead != 0) {
3521        //err = -1;
3522        jniThrowException(pEnv, "java/lang/IOException", "numBytesToRead != 0 ; file write failed");
3523    }
3524
3525    /* write the count in place holder after seek */
3526    seekPos = sizeof(M4OSA_UInt32);
3527    err = M4OSA_fileWriteSeek(outFileHandle, M4OSA_kFileSeekBeginning,
3528            &seekPos /* after samples per value */);
3529    if ( err != M4NO_ERROR) {
3530        jniThrowException(pEnv, "java/lang/IOException", "file seek failed");
3531    } else {
3532        volumeValuesCount = ((volumeValuesCount>>24)&0xff) | // move byte 3 to byte 0
3533                    ((volumeValuesCount<<8)&0xff0000) | // move byte 1 to byte 2
3534                    ((volumeValuesCount>>8)&0xff00) |  // move byte 2 to byte 1
3535                    ((volumeValuesCount<<24)&0xff000000); // byte 0 to byte 3
3536
3537        err = M4OSA_fileWriteData (outFileHandle, (M4OSA_MemAddr8)&volumeValuesCount,
3538                                    sizeof(M4OSA_UInt32) );
3539        if ( err != M4NO_ERROR) {
3540            jniThrowException(pEnv, "java/lang/IOException", "file write failed");
3541        }
3542    }
3543
3544    /******************************************************************************
3545    CLOSE AND FREE ALLOCATIONS
3546    *******************************************************************************/
3547    free(bufferIn.m_dataAddress);
3548    M4OSA_fileReadClose(inputFileHandle);
3549    M4OSA_fileWriteClose(outFileHandle);
3550    /* final finish callback */
3551    pEnv->CallVoidMethod(pContext->engine, pContext->onAudioGraphProgressUpdateMethodId, 100, 0);
3552
3553    /* EXIT */
3554    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "EXIT - M4MA_generateAudioGraphFile");
3555
3556    return err;
3557}
3558
3559static int videoEditor_generateAudioWaveFormSync (JNIEnv*  pEnv, jobject thiz,
3560                                                  jstring pcmfilePath,
3561                                                  jstring outGraphfilePath,
3562                                                  jint frameDuration, jint channels,
3563                                                  jint samplesCount)
3564{
3565    M4OSA_ERR result = M4NO_ERROR;
3566    ManualEditContext* pContext = M4OSA_NULL;
3567    bool needToBeLoaded = true;
3568    const char *pPCMFilePath, *pStringOutAudioGraphFile;
3569
3570    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
3571        "videoEditor_generateAudioWaveFormSync() ");
3572
3573    /* Get the context. */
3574    pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz);
3575    if (pContext == M4OSA_NULL) {
3576        VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
3577            "videoEditor_generateAudioWaveFormSync() - pContext is NULL ");
3578    }
3579
3580    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
3581        "videoEditor_generateAudioWaveFormSync Retrieving pStringOutAudioGraphFile");
3582
3583    pPCMFilePath = pEnv->GetStringUTFChars(pcmfilePath, NULL);
3584    if (pPCMFilePath == M4OSA_NULL) {
3585        jniThrowException(pEnv, "java/lang/RuntimeException",
3586            "Input string PCMFilePath is null");
3587        result = M4ERR_PARAMETER;
3588        goto out;
3589    }
3590
3591    pStringOutAudioGraphFile = pEnv->GetStringUTFChars(outGraphfilePath, NULL);
3592    if (pStringOutAudioGraphFile == M4OSA_NULL) {
3593        jniThrowException(pEnv, "java/lang/RuntimeException",
3594            "Input string outGraphfilePath is null");
3595        result = M4ERR_PARAMETER;
3596        goto out2;
3597    }
3598
3599    VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
3600        "videoEditor_generateAudioWaveFormSync Generate the waveform data %s %d %d %d",
3601        pStringOutAudioGraphFile, frameDuration, channels, samplesCount);
3602
3603    /* Generate the waveform */
3604    result = M4MA_generateAudioGraphFile(pEnv, (M4OSA_Char*) pPCMFilePath,
3605        (M4OSA_Char*) pStringOutAudioGraphFile,
3606        (M4OSA_UInt32) samplesCount,
3607        (M4OSA_UInt32) channels,
3608        (M4OSA_UInt32)frameDuration,
3609        pContext);
3610
3611    pEnv->ReleaseStringUTFChars(outGraphfilePath, pStringOutAudioGraphFile);
3612
3613out2:
3614    if (pPCMFilePath != NULL) {
3615        pEnv->ReleaseStringUTFChars(pcmfilePath, pPCMFilePath);
3616    }
3617
3618out:
3619    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
3620        "videoEditor_generateAudioWaveFormSync pContext->bSkipState ");
3621
3622    return result;
3623}
3624
3625/******** End Audio Graph *******/
3626jint JNI_OnLoad(
3627                JavaVM*                             pVm,
3628                void*                               pReserved)
3629{
3630    void* pEnv         = NULL;
3631    bool  needToBeInitialized = true;
3632    jint  result      = -1;
3633
3634    VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "JNI_OnLoad()");
3635
3636    // Add a text marker (the condition must always be true).
3637    ADD_TEXT_MARKER_FUN(NULL != pVm)
3638
3639    // Check the JNI version.
3640    if (pVm->GetEnv(&pEnv, JNI_VERSION_1_4) == JNI_OK)
3641    {
3642        // Add a code marker (the condition must always be true).
3643        ADD_CODE_MARKER_FUN(NULL != pEnv)
3644
3645        // Register the manual edit JNI methods.
3646        if (videoEditor_registerManualEditMethods((JNIEnv*)pEnv) == 0)
3647        {
3648            // Initialize the classes.
3649            videoEditClasses_init(&needToBeInitialized, (JNIEnv*)pEnv);
3650            if (needToBeInitialized)
3651            {
3652                // Success, return valid version number.
3653                result = JNI_VERSION_1_4;
3654            }
3655        }
3656    }
3657
3658    // Return the result.
3659    return(result);
3660}
3661
3662