VideoEditorPropertiesMain.cpp revision 2fb605a088d25037c66eae04f5d35ea1fe115390
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
17#include <dlfcn.h>
18#include <stdio.h>
19#include <unistd.h>
20#include <utils/Log.h>
21#include <utils/threads.h>
22#include <VideoEditorClasses.h>
23#include <VideoEditorJava.h>
24#include <VideoEditorOsal.h>
25#include <VideoEditorLogging.h>
26#include <VideoEditorOsal.h>
27#include <marker.h>
28
29extern "C" {
30#include <M4OSA_Clock.h>
31#include <M4OSA_CharStar.h>
32#include <M4OSA_Error.h>
33#include <M4OSA_FileCommon.h>
34#include <M4OSA_FileReader.h>
35#include <M4OSA_FileWriter.h>
36#include <M4OSA_Memory.h>
37#include <M4OSA_Thread.h>
38#include <M4VSS3GPP_API.h>
39#include <M4VSS3GPP_ErrorCodes.h>
40#include <M4MCS_API.h>
41#include <M4MCS_ErrorCodes.h>
42#include <M4READER_Common.h>
43#include <M4WRITER_common.h>
44#include <M4DECODER_Common.h>
45#include <M4AD_Common.h>
46};
47
48extern "C" M4OSA_ERR M4MCS_open_normalMode(
49                M4MCS_Context                       pContext,
50                M4OSA_Void*                         pFileIn,
51                M4VIDEOEDITING_FileType             InputFileType,
52                M4OSA_Void*                         pFileOut,
53                M4OSA_Void*                         pTempFile);
54
55jobject videoEditProp_getProperties(
56                JNIEnv*                             pEnv,
57                jobject                             thiz,
58                jstring                             file);
59
60static void
61getFileAndMediaTypeFromExtension (
62                M4OSA_Char* pExtension,
63                VideoEditClasses_FileType   *pFileType,
64                M4VIDEOEDITING_FileType       *pClipType);
65
66static M4OSA_ERR
67getClipProperties(  JNIEnv*                         pEnv,
68                    jobject                         thiz,
69                    M4OSA_Char*                     pFile,
70                    M4VIDEOEDITING_FileType         clipType,
71                    M4VIDEOEDITING_ClipProperties*  pClipProperties);
72
73M4OSA_UInt32
74VideoEdit_chrCompare(M4OSA_Char* pStrIn1,
75                     M4OSA_Char* pStrIn2,
76                     M4OSA_Int32* pCmpResult);
77
78jobject videoEditProp_getProperties(
79        JNIEnv* pEnv,
80        jobject thiz,
81        jstring file)
82{
83    bool                           gotten          = true;
84    M4OSA_Char*                    pFile           = M4OSA_NULL;
85    M4OSA_Char*                    pExtension      = M4OSA_NULL;
86    M4OSA_UInt32                   index           = 0;
87    M4OSA_Int32                    cmpResult       = 0;
88    VideoEditPropClass_Properties* pProperties     = M4OSA_NULL;
89    M4VIDEOEDITING_ClipProperties* pClipProperties = M4OSA_NULL;
90    M4OSA_ERR                      result          = M4NO_ERROR;
91    M4MCS_Context                  context         = M4OSA_NULL;
92    M4OSA_FilePosition             size            = 0;
93    M4OSA_UInt32                   width           = 0;
94    M4OSA_UInt32                   height          = 0;
95    jobject                        properties      = NULL;
96    M4OSA_Context                  pOMXContext     = M4OSA_NULL;
97    M4DECODER_VideoInterface*      pOMXVidDecoderInterface = M4OSA_NULL;
98    M4AD_Interface*                pOMXAudDecoderInterface = M4OSA_NULL;
99
100    bool  initialized = true;
101    VideoEditClasses_FileType fileType = VideoEditClasses_kFileType_Unsupported;
102    M4VIDEOEDITING_FileType clipType = M4VIDEOEDITING_kFileType_Unsupported;
103
104    VIDEOEDIT_LOG_API(
105            ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
106            "videoEditProp_getProperties()");
107
108    // Add a text marker (the condition must always be true).
109    ADD_TEXT_MARKER_FUN(NULL != pEnv)
110
111    // Initialize the classes.
112    videoEditPropClass_init(&initialized, (JNIEnv*)pEnv);
113
114    // Validate the tempPath parameter.
115    videoEditJava_checkAndThrowIllegalArgumentException(
116            &gotten, pEnv, (NULL == file), "file is null");
117
118    // Get the file path.
119    pFile = (M4OSA_Char *)videoEditJava_getString(
120            &gotten, pEnv, file, NULL, M4OSA_NULL);
121
122    result = M4OSA_fileReadOpen(&context, (M4OSA_Void*)pFile, M4OSA_kFileRead);
123
124    if(M4NO_ERROR != result) {
125        // Free the file path.
126        videoEditOsal_free(pFile);
127        pFile = M4OSA_NULL;
128    }
129
130    videoEditJava_checkAndThrowIllegalArgumentException(&gotten, pEnv,
131        (M4NO_ERROR != result), "file not found");
132
133    // Close the file and free the file context
134    if (context != NULL) {
135        result = M4OSA_fileReadClose(context);
136        context = M4OSA_NULL;
137    }
138
139    // Return if Error
140    if (M4NO_ERROR != result) {
141        return (properties); // NULL
142    }
143
144    // Check if the file path is valid.
145    if (gotten)
146    {
147        // Retrieve the extension.
148        pExtension = (M4OSA_Char *)strrchr((const char *)pFile, (int)'.');
149        if (M4OSA_NULL != pExtension)
150        {
151            // Skip the dot.
152            pExtension++;
153
154            // Get the file type and Media type from extension
155            getFileAndMediaTypeFromExtension(
156                    pExtension ,&fileType, &clipType);
157        }
158    }
159
160    // Check if the file type could be determined.
161    videoEditJava_checkAndThrowIllegalArgumentException(
162            &gotten, pEnv,
163            (VideoEditClasses_kFileType_Unsupported == fileType),
164            "file type is not supported");
165
166    // Allocate a new properties structure.
167    pProperties = (VideoEditPropClass_Properties*)videoEditOsal_alloc(
168            &gotten, pEnv,
169            sizeof(VideoEditPropClass_Properties), "Properties");
170
171    // Check if the context is valid and allocation succeeded
172    // (required because of dereferencing of pProperties).
173    if (gotten)
174    {
175        // Check if this type of file needs to be analyzed using MCS.
176        if ((VideoEditClasses_kFileType_MP3  == fileType) ||
177            (VideoEditClasses_kFileType_MP4  == fileType) ||
178            (VideoEditClasses_kFileType_3GPP == fileType) ||
179            (VideoEditClasses_kFileType_AMR  == fileType) ||
180            (VideoEditClasses_kFileType_PCM  == fileType) ||
181            (VideoEditClasses_kFileType_M4V  == fileType))
182        {
183            // Allocate a new clip properties structure.
184            pClipProperties =
185                (M4VIDEOEDITING_ClipProperties*)videoEditOsal_alloc(
186                    &gotten, pEnv,
187                    sizeof(M4VIDEOEDITING_ClipProperties), "ClipProperties");
188
189            // Check if allocation succeeded (required because of
190            // dereferencing of pClipProperties).
191            if (gotten)
192            {
193                // Add a code marker (the condition must always be true).
194                ADD_CODE_MARKER_FUN(NULL != pClipProperties)
195
196                // Log the API call.
197                VIDEOEDIT_LOG_API(
198                        ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
199                        "getClipProperties");
200
201                // Get Video clip properties
202                result = getClipProperties(
203                        pEnv, thiz, pFile, clipType, pClipProperties);
204
205                if (M4MCS_ERR_FILE_DRM_PROTECTED == result) {
206                    // Check if the creation succeeded.
207                    videoEditJava_checkAndThrowIllegalArgumentException(
208                            &gotten, pEnv,(M4NO_ERROR != result),
209                            "Invalid File - DRM Protected ");
210                } else {
211                    // Check if the creation succeeded.
212                    videoEditJava_checkAndThrowIllegalArgumentException(
213                            &gotten, pEnv,(M4NO_ERROR != result),
214                            "Invalid File or File not found ");
215                }
216
217                /**
218                 * Max resolution supported is 1280 x 720.
219                 */
220                if ( (pClipProperties->uiVideoWidth > 1280)
221                    || (pClipProperties->uiVideoHeight > 720) )
222                {
223                    result = M4MCS_ERR_INVALID_INPUT_VIDEO_FRAME_SIZE;
224                    videoEditJava_checkAndThrowIllegalArgumentException(
225                            &gotten, pEnv, (M4NO_ERROR != result),
226                            "Unsupported input video frame size");
227                }
228
229#ifdef USE_SOFTWARE_DECODER
230                /**
231                 * Input clip with non-multiples of 16 is not supported.
232                 */
233                if ( (pClipProperties->uiVideoWidth %16)
234                    || (pClipProperties->uiVideoHeight %16) )
235                {
236                    result = M4MCS_ERR_INPUT_VIDEO_SIZE_NON_X16;
237                    videoEditJava_checkAndThrowIllegalArgumentException(
238                            &gotten, pEnv, (M4NO_ERROR != result),
239                            "non x16 input video frame size is not supported");
240                }
241#endif /* USE_SOFTWARE_DECODER */
242            }
243
244            // Check if the properties could be retrieved.
245            if (gotten)
246            {
247                // Set the properties.
248                pProperties->uiClipDuration = pClipProperties->uiClipDuration;
249                if (M4VIDEOEDITING_kFileType_Unsupported == pClipProperties->FileType)
250                {
251                    pProperties->FileType        = VideoEditClasses_kFileType_Unsupported;
252                }
253                else
254                {
255                    pProperties->FileType        = fileType;
256                }
257                pProperties->VideoStreamType     = pClipProperties->VideoStreamType;
258                pProperties->uiClipVideoDuration = pClipProperties->uiClipVideoDuration;
259                pProperties->uiVideoBitrate      = pClipProperties->uiVideoBitrate;
260                pProperties->uiVideoWidth        = pClipProperties->uiVideoWidth;
261                pProperties->uiVideoHeight       = pClipProperties->uiVideoHeight;
262                pProperties->fAverageFrameRate   = pClipProperties->fAverageFrameRate;
263                pProperties->ProfileAndLevel     = pClipProperties->ProfileAndLevel;
264                pProperties->AudioStreamType     = pClipProperties->AudioStreamType;
265                pProperties->uiClipAudioDuration = pClipProperties->uiClipAudioDuration;
266                pProperties->uiAudioBitrate      = pClipProperties->uiAudioBitrate;
267                pProperties->uiNbChannels        = pClipProperties->uiNbChannels;
268                pProperties->uiSamplingFrequency = pClipProperties->uiSamplingFrequency;
269            }
270
271            // Free the clip properties.
272            videoEditOsal_free(pClipProperties);
273            pClipProperties = M4OSA_NULL;
274        }
275        else if ((VideoEditClasses_kFileType_JPG == fileType) ||
276            (VideoEditClasses_kFileType_GIF == fileType) ||
277            (VideoEditClasses_kFileType_PNG == fileType))
278        {
279            pProperties->uiClipDuration      = 0;
280            pProperties->FileType            = fileType;
281            pProperties->VideoStreamType     = M4VIDEOEDITING_kNoneVideo;
282            pProperties->uiClipVideoDuration = 0;
283            pProperties->uiVideoBitrate      = 0;
284            pProperties->uiVideoWidth        = width;
285            pProperties->uiVideoHeight       = height;
286            pProperties->fAverageFrameRate   = 0.0f;
287            pProperties->ProfileAndLevel     = M4VIDEOEDITING_kProfile_and_Level_Out_Of_Range;
288            pProperties->AudioStreamType     = M4VIDEOEDITING_kNoneAudio;
289            pProperties->uiClipAudioDuration = 0;
290            pProperties->uiAudioBitrate      = 0;
291            pProperties->uiNbChannels        = 0;
292            pProperties->uiSamplingFrequency = 0;
293
294            // Added for Handling invalid paths and non existent image files
295            // Open the file for reading.
296            result = M4OSA_fileReadOpen(&context, (M4OSA_Void*)pFile, M4OSA_kFileRead);
297            if (M4NO_ERROR != result)
298            {
299                pProperties->FileType = VideoEditClasses_kFileType_Unsupported;
300            }
301            result = M4OSA_fileReadClose(context);
302            context = M4OSA_NULL;
303        }
304    }
305
306    // Create a properties object.
307    videoEditPropClass_createProperties(&gotten, pEnv, pProperties, &properties);
308
309    // Log the properties.
310    VIDEOEDIT_PROP_LOG_PROPERTIES(pProperties);
311
312    // Free the properties.
313    videoEditOsal_free(pProperties);
314    pProperties = M4OSA_NULL;
315
316    // Free the file path.
317    videoEditOsal_free(pFile);
318    pFile = M4OSA_NULL;
319
320    // Add a text marker (the condition must always be true).
321    ADD_TEXT_MARKER_FUN(NULL != pEnv)
322
323    // Return the Properties object.
324    return(properties);
325}
326
327static void getFileAndMediaTypeFromExtension (
328        M4OSA_Char *pExtension,
329        VideoEditClasses_FileType *pFileType,
330        M4VIDEOEDITING_FileType *pClipType)
331{
332    M4OSA_Char extension[5] = {0, 0, 0, 0, 0};
333    VideoEditClasses_FileType fileType =
334            VideoEditClasses_kFileType_Unsupported;
335
336    M4VIDEOEDITING_FileType clipType =
337            M4VIDEOEDITING_kFileType_Unsupported;
338
339    M4OSA_UInt32 index = 0;
340    M4OSA_ERR result = M4NO_ERROR;
341    M4OSA_Int32 cmpResult = 0;
342    M4OSA_UInt32  extLength = strlen((const char *)pExtension);
343
344    // Assign default
345    *pFileType = VideoEditClasses_kFileType_Unsupported;
346    *pClipType = M4VIDEOEDITING_kFileType_Unsupported;
347
348    // Check if the length of the extension is valid.
349    if ((3 == extLength) || (4 == extLength))
350    {
351        // Convert the extension to lowercase.
352        for (index = 0; index < extLength ; index++)
353        {
354            extension[index] = tolower((int)pExtension[index]);
355        }
356
357        // Check if the extension is ".mp3".
358        if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"mp3", &cmpResult)))
359        {
360            *pFileType = VideoEditClasses_kFileType_MP3;
361            *pClipType = M4VIDEOEDITING_kFileType_MP3;
362        }
363        // Check if the extension is ".mp4".
364        else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"mp4", &cmpResult)))
365        {
366            *pFileType = VideoEditClasses_kFileType_MP4;
367            *pClipType = M4VIDEOEDITING_kFileType_MP4;
368        }
369        // Check if the extension is ".3gp".
370        else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"3gp", &cmpResult)))
371        {
372            *pFileType = VideoEditClasses_kFileType_3GPP;
373            *pClipType = M4VIDEOEDITING_kFileType_3GPP;
374        }
375        // Check if the extension is ".m4a".
376        else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"m4a", &cmpResult)))
377        {
378            *pFileType = VideoEditClasses_kFileType_3GPP;
379            *pClipType = M4VIDEOEDITING_kFileType_3GPP;
380        }
381        // Check if the extension is ".3gpp".
382        else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"3gpp", &cmpResult)))
383        {
384            *pFileType = VideoEditClasses_kFileType_3GPP;
385            *pClipType = M4VIDEOEDITING_kFileType_3GPP;
386        }
387        // Check if the extension is ".amr".
388        else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"amr", &cmpResult)))
389        {
390            *pFileType = VideoEditClasses_kFileType_AMR;
391            *pClipType = M4VIDEOEDITING_kFileType_AMR;
392        }
393        // Check if the extension is ".pcm".
394        else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"pcm", &cmpResult)))
395        {
396            *pFileType = VideoEditClasses_kFileType_PCM;
397            *pClipType = M4VIDEOEDITING_kFileType_PCM;
398        }
399        // Check if the extension is ".jpg".
400        else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"jpg", &cmpResult)))
401        {
402            *pFileType = VideoEditClasses_kFileType_JPG;
403        }
404        // Check if the extension is ".jpeg".
405        else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"jpeg", &cmpResult)))
406        {
407            *pFileType = VideoEditClasses_kFileType_JPG;
408        }
409        // Check if the extension is ".gif".
410        else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"gif", &cmpResult)))
411        {
412            *pFileType = VideoEditClasses_kFileType_GIF;
413        }
414        // Check if the extension is ".png".
415        else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"png", &cmpResult)))
416        {
417            *pFileType = VideoEditClasses_kFileType_PNG;
418        }
419        // Check if the extension is ".m4v".
420        else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"m4v", &cmpResult)))
421        {
422            *pFileType = VideoEditClasses_kFileType_M4V;
423            *pClipType = M4VIDEOEDITING_kFileType_M4V;
424        }
425    }
426}
427
428static M4OSA_ERR getClipProperties(
429        JNIEnv* pEnv,
430        jobject thiz,
431        M4OSA_Char* pFile,
432        M4VIDEOEDITING_FileType clipType,
433        M4VIDEOEDITING_ClipProperties* pClipProperties)
434{
435    bool                      gotten          = true;
436    M4OSA_ERR                 result          = M4NO_ERROR;
437    M4OSA_ERR                 resultAbort     = M4NO_ERROR;
438    M4MCS_Context             context         = M4OSA_NULL;
439
440    M4OSA_FileReadPointer fileReadPtr =
441            { M4OSA_NULL, M4OSA_NULL, M4OSA_NULL,
442              M4OSA_NULL, M4OSA_NULL, M4OSA_NULL };
443
444    M4OSA_FileWriterPointer fileWritePtr =
445            { M4OSA_NULL, M4OSA_NULL, M4OSA_NULL,
446              M4OSA_NULL, M4OSA_NULL, M4OSA_NULL, M4OSA_NULL };
447
448    // Initialize the OSAL file system function pointers.
449    videoEditOsal_getFilePointers(&fileReadPtr , &fileWritePtr);
450
451    // Log the API call.
452    VIDEOEDIT_LOG_API(
453            ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",\
454            "getClipProperties - M4MCS_init()");
455
456    // Initialize the MCS context.
457    result = M4MCS_init(&context, &fileReadPtr, &fileWritePtr);
458
459    // Log the result.
460    VIDEOEDIT_PROP_LOG_RESULT(
461            ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES", "%s",
462            videoEditOsal_getResultString(result));
463
464    // Check if the creation succeeded.
465    videoEditJava_checkAndThrowRuntimeException(
466            &gotten, pEnv, (M4NO_ERROR != result), result);
467
468    // Check if opening the MCS context succeeded.
469    if (gotten)
470    {
471        // Log the API call.
472        VIDEOEDIT_LOG_API(
473                ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
474                "getClipProperties - M4MCS_open_normalMode()");
475
476        // Open the MCS in the normal opening mode to
477        // retrieve the exact duration
478        result = M4MCS_open_normalMode(
479                context, pFile, clipType, M4OSA_NULL, M4OSA_NULL);
480
481        // Log the result.
482        VIDEOEDIT_PROP_LOG_RESULT(
483                ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES", "%s",
484                videoEditOsal_getResultString(result));
485
486        // Check if the creation succeeded.
487        videoEditJava_checkAndThrowRuntimeException(
488                &gotten, pEnv, (M4NO_ERROR != result), result);
489
490        // Check if the MCS could be opened.
491        if (gotten)
492        {
493            // Log the API call.
494            VIDEOEDIT_LOG_API(
495                    ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
496                    "getClipProperties - M4MCS_getInputFileProperties()");
497
498            // Get the properties.
499            result = M4MCS_getInputFileProperties(context, pClipProperties);
500
501            // Log the result.
502            VIDEOEDIT_PROP_LOG_RESULT(
503                    ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES", "%s",
504                    videoEditOsal_getResultString(result));
505
506            // Check if the creation succeeded.
507            videoEditJava_checkAndThrowRuntimeException(
508                    &gotten, pEnv, (M4NO_ERROR != result), result);
509        }
510
511        // Log the API call.
512        VIDEOEDIT_LOG_API(
513                ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
514                "getClipProperties - M4MCS_abort()");
515
516        // Close the MCS session.
517        resultAbort = M4MCS_abort(context);
518
519       if (result == M4NO_ERROR) {
520            // Log the result.
521            VIDEOEDIT_PROP_LOG_RESULT(
522                    ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES", "%s",
523                    videoEditOsal_getResultString(resultAbort));
524
525            // Check if the abort succeeded.
526            videoEditJava_checkAndThrowRuntimeException(
527                    &gotten, pEnv, (M4NO_ERROR != resultAbort), resultAbort);
528            result = resultAbort;
529        }
530    }
531
532    return result;
533}
534
535M4OSA_UInt32
536VideoEdit_chrCompare(M4OSA_Char* pStrIn1,
537                     M4OSA_Char* pStrIn2,
538                      M4OSA_Int32* pCmpResult)
539{
540    *pCmpResult = strcmp((const char *)pStrIn1, (const char *)pStrIn2);
541    return *pCmpResult;
542}
543
544
545