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