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
29 extern "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
48 extern "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
55 jobject videoEditProp_getProperties(
56 JNIEnv* pEnv,
57 jobject thiz,
58 jstring file);
59
60 static void
61 getFileAndMediaTypeFromExtension (
62 M4OSA_Char* pExtension,
63 VideoEditClasses_FileType *pFileType,
64 M4VIDEOEDITING_FileType *pClipType);
65
66 static M4OSA_ERR
67 getClipProperties( JNIEnv* pEnv,
68 jobject thiz,
69 M4OSA_Char* pFile,
70 M4VIDEOEDITING_FileType clipType,
71 M4VIDEOEDITING_ClipProperties* pClipProperties);
72
73 M4OSA_UInt32
74 VideoEdit_chrCompare(M4OSA_Char* pStrIn1,
75 M4OSA_Char* pStrIn2,
76 M4OSA_Int32* pCmpResult);
77
videoEditProp_getProperties(JNIEnv * pEnv,jobject thiz,jstring file)78 jobject 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 #ifdef USE_SOFTWARE_DECODER
218 /**
219 * Input clip with non-multiples of 16 is not supported.
220 */
221 if ( (pClipProperties->uiVideoWidth %16)
222 || (pClipProperties->uiVideoHeight %16) )
223 {
224 result = M4MCS_ERR_INPUT_VIDEO_SIZE_NON_X16;
225 videoEditJava_checkAndThrowIllegalArgumentException(
226 &gotten, pEnv, (M4NO_ERROR != result),
227 "non x16 input video frame size is not supported");
228 }
229 #endif /* USE_SOFTWARE_DECODER */
230 }
231
232 // Check if the properties could be retrieved.
233 if (gotten)
234 {
235 // Set the properties.
236 pProperties->uiClipDuration = pClipProperties->uiClipDuration;
237 if (M4VIDEOEDITING_kFileType_Unsupported == pClipProperties->FileType)
238 {
239 pProperties->FileType = VideoEditClasses_kFileType_Unsupported;
240 }
241 else
242 {
243 pProperties->FileType = fileType;
244 }
245 pProperties->VideoStreamType = pClipProperties->VideoStreamType;
246 pProperties->uiClipVideoDuration = pClipProperties->uiClipVideoDuration;
247 pProperties->uiVideoBitrate = pClipProperties->uiVideoBitrate;
248 pProperties->uiVideoWidth = pClipProperties->uiVideoWidth;
249 pProperties->uiVideoHeight = pClipProperties->uiVideoHeight;
250 pProperties->fAverageFrameRate = pClipProperties->fAverageFrameRate;
251 pProperties->uiVideoProfile = pClipProperties->uiVideoProfile;
252 pProperties->uiVideoLevel = pClipProperties->uiVideoLevel;
253 // Set profile and level support to TRUE, pending check
254 pProperties->bProfileSupported = M4OSA_TRUE;
255 pProperties->bLevelSupported = M4OSA_TRUE;
256 pProperties->AudioStreamType = pClipProperties->AudioStreamType;
257 pProperties->uiClipAudioDuration = pClipProperties->uiClipAudioDuration;
258 pProperties->uiAudioBitrate = pClipProperties->uiAudioBitrate;
259 pProperties->uiNbChannels = pClipProperties->uiNbChannels;
260 pProperties->uiSamplingFrequency = pClipProperties->uiSamplingFrequency;
261 pProperties->uiRotation = pClipProperties->videoRotationDegrees;
262
263 }
264
265 // Free the clip properties.
266 videoEditOsal_free(pClipProperties);
267 pClipProperties = M4OSA_NULL;
268 }
269 else if ((VideoEditClasses_kFileType_JPG == fileType) ||
270 (VideoEditClasses_kFileType_GIF == fileType) ||
271 (VideoEditClasses_kFileType_PNG == fileType))
272 {
273 pProperties->uiClipDuration = 0;
274 pProperties->FileType = fileType;
275 pProperties->VideoStreamType = M4VIDEOEDITING_kNoneVideo;
276 pProperties->uiClipVideoDuration = 0;
277 pProperties->uiVideoBitrate = 0;
278 pProperties->uiVideoWidth = width;
279 pProperties->uiVideoHeight = height;
280 pProperties->fAverageFrameRate = 0.0f;
281 pProperties->uiVideoProfile = M4VIDEOEDITING_VIDEO_UNKNOWN_PROFILE;
282 pProperties->uiVideoLevel = M4VIDEOEDITING_VIDEO_UNKNOWN_LEVEL;
283 pProperties->AudioStreamType = M4VIDEOEDITING_kNoneAudio;
284 pProperties->uiClipAudioDuration = 0;
285 pProperties->uiAudioBitrate = 0;
286 pProperties->uiNbChannels = 0;
287 pProperties->uiSamplingFrequency = 0;
288
289 // Added for Handling invalid paths and non existent image files
290 // Open the file for reading.
291 result = M4OSA_fileReadOpen(&context, (M4OSA_Void*)pFile, M4OSA_kFileRead);
292 if (M4NO_ERROR != result)
293 {
294 pProperties->FileType = VideoEditClasses_kFileType_Unsupported;
295 }
296 result = M4OSA_fileReadClose(context);
297 context = M4OSA_NULL;
298 }
299 }
300
301 if (M4NO_ERROR == result) {
302 // Create a properties object.
303 videoEditPropClass_createProperties(&gotten, pEnv, pProperties, &properties);
304
305 // Log the properties.
306 VIDEOEDIT_PROP_LOG_PROPERTIES(pProperties);
307 }
308
309 // Free the properties.
310 videoEditOsal_free(pProperties);
311 pProperties = M4OSA_NULL;
312
313 // Free the file path.
314 videoEditOsal_free(pFile);
315 pFile = M4OSA_NULL;
316
317 // Add a text marker (the condition must always be true).
318 ADD_TEXT_MARKER_FUN(NULL != pEnv)
319
320 // Return the Properties object.
321 return(properties);
322 }
323
getFileAndMediaTypeFromExtension(M4OSA_Char * pExtension,VideoEditClasses_FileType * pFileType,M4VIDEOEDITING_FileType * pClipType)324 static void getFileAndMediaTypeFromExtension (
325 M4OSA_Char *pExtension,
326 VideoEditClasses_FileType *pFileType,
327 M4VIDEOEDITING_FileType *pClipType)
328 {
329 M4OSA_Char extension[5] = {0, 0, 0, 0, 0};
330 VideoEditClasses_FileType fileType =
331 VideoEditClasses_kFileType_Unsupported;
332
333 M4VIDEOEDITING_FileType clipType =
334 M4VIDEOEDITING_kFileType_Unsupported;
335
336 M4OSA_UInt32 index = 0;
337 M4OSA_ERR result = M4NO_ERROR;
338 M4OSA_Int32 cmpResult = 0;
339 M4OSA_UInt32 extLength = strlen((const char *)pExtension);
340
341 // Assign default
342 *pFileType = VideoEditClasses_kFileType_Unsupported;
343 *pClipType = M4VIDEOEDITING_kFileType_Unsupported;
344
345 // Check if the length of the extension is valid.
346 if ((3 == extLength) || (4 == extLength))
347 {
348 // Convert the extension to lowercase.
349 for (index = 0; index < extLength ; index++)
350 {
351 extension[index] = tolower((int)pExtension[index]);
352 }
353
354 // Check if the extension is ".mp3".
355 if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"mp3", &cmpResult)))
356 {
357 *pFileType = VideoEditClasses_kFileType_MP3;
358 *pClipType = M4VIDEOEDITING_kFileType_MP3;
359 }
360 // Check if the extension is ".mp4".
361 else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"mp4", &cmpResult)))
362 {
363 *pFileType = VideoEditClasses_kFileType_MP4;
364 *pClipType = M4VIDEOEDITING_kFileType_MP4;
365 }
366 // Check if the extension is ".3gp".
367 else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"3gp", &cmpResult)))
368 {
369 *pFileType = VideoEditClasses_kFileType_3GPP;
370 *pClipType = M4VIDEOEDITING_kFileType_3GPP;
371 }
372 // Check if the extension is ".m4a".
373 else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"m4a", &cmpResult)))
374 {
375 *pFileType = VideoEditClasses_kFileType_3GPP;
376 *pClipType = M4VIDEOEDITING_kFileType_3GPP;
377 }
378 // Check if the extension is ".3gpp".
379 else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"3gpp", &cmpResult)))
380 {
381 *pFileType = VideoEditClasses_kFileType_3GPP;
382 *pClipType = M4VIDEOEDITING_kFileType_3GPP;
383 }
384 // Check if the extension is ".amr".
385 else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"amr", &cmpResult)))
386 {
387 *pFileType = VideoEditClasses_kFileType_AMR;
388 *pClipType = M4VIDEOEDITING_kFileType_AMR;
389 }
390 // Check if the extension is ".pcm".
391 else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"pcm", &cmpResult)))
392 {
393 *pFileType = VideoEditClasses_kFileType_PCM;
394 *pClipType = M4VIDEOEDITING_kFileType_PCM;
395 }
396 // Check if the extension is ".jpg".
397 else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"jpg", &cmpResult)))
398 {
399 *pFileType = VideoEditClasses_kFileType_JPG;
400 }
401 // Check if the extension is ".jpeg".
402 else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"jpeg", &cmpResult)))
403 {
404 *pFileType = VideoEditClasses_kFileType_JPG;
405 }
406 // Check if the extension is ".gif".
407 else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"gif", &cmpResult)))
408 {
409 *pFileType = VideoEditClasses_kFileType_GIF;
410 }
411 // Check if the extension is ".png".
412 else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"png", &cmpResult)))
413 {
414 *pFileType = VideoEditClasses_kFileType_PNG;
415 }
416 // Check if the extension is ".m4v".
417 else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"m4v", &cmpResult)))
418 {
419 *pFileType = VideoEditClasses_kFileType_M4V;
420 *pClipType = M4VIDEOEDITING_kFileType_M4V;
421 }
422 }
423 }
424
getClipProperties(JNIEnv * pEnv,jobject thiz,M4OSA_Char * pFile,M4VIDEOEDITING_FileType clipType,M4VIDEOEDITING_ClipProperties * pClipProperties)425 static M4OSA_ERR getClipProperties(
426 JNIEnv* pEnv,
427 jobject thiz,
428 M4OSA_Char* pFile,
429 M4VIDEOEDITING_FileType clipType,
430 M4VIDEOEDITING_ClipProperties* pClipProperties)
431 {
432 bool gotten = true;
433 M4OSA_ERR result = M4NO_ERROR;
434 M4OSA_ERR resultAbort = M4NO_ERROR;
435 M4MCS_Context context = M4OSA_NULL;
436
437 M4OSA_FileReadPointer fileReadPtr =
438 { M4OSA_NULL, M4OSA_NULL, M4OSA_NULL,
439 M4OSA_NULL, M4OSA_NULL, M4OSA_NULL };
440
441 M4OSA_FileWriterPointer fileWritePtr =
442 { M4OSA_NULL, M4OSA_NULL, M4OSA_NULL,
443 M4OSA_NULL, M4OSA_NULL, M4OSA_NULL, M4OSA_NULL };
444
445 // Initialize the OSAL file system function pointers.
446 videoEditOsal_getFilePointers(&fileReadPtr , &fileWritePtr);
447
448 // Log the API call.
449 VIDEOEDIT_LOG_API(
450 ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",\
451 "getClipProperties - M4MCS_init()");
452
453 // Initialize the MCS context.
454 result = M4MCS_init(&context, &fileReadPtr, &fileWritePtr);
455
456 // Log the result.
457 VIDEOEDIT_PROP_LOG_RESULT(
458 ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES", "%s",
459 videoEditOsal_getResultString(result));
460
461 // Check if the creation succeeded.
462 videoEditJava_checkAndThrowRuntimeException(
463 &gotten, pEnv, (M4NO_ERROR != result), result);
464
465 // Check if opening the MCS context succeeded.
466 if (gotten)
467 {
468 // Log the API call.
469 VIDEOEDIT_LOG_API(
470 ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
471 "getClipProperties - M4MCS_open_normalMode()");
472
473 // Open the MCS in the normal opening mode to
474 // retrieve the exact duration
475 result = M4MCS_open_normalMode(
476 context, pFile, clipType, M4OSA_NULL, M4OSA_NULL);
477
478 // Log the result.
479 VIDEOEDIT_PROP_LOG_RESULT(
480 ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES", "%s",
481 videoEditOsal_getResultString(result));
482
483 // Check if the creation succeeded.
484 videoEditJava_checkAndThrowRuntimeException(
485 &gotten, pEnv, (M4NO_ERROR != result), result);
486
487 // Check if the MCS could be opened.
488 if (gotten)
489 {
490 // Log the API call.
491 VIDEOEDIT_LOG_API(
492 ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
493 "getClipProperties - M4MCS_getInputFileProperties()");
494
495 // Get the properties.
496 result = M4MCS_getInputFileProperties(context, pClipProperties);
497
498 // Log the result.
499 VIDEOEDIT_PROP_LOG_RESULT(
500 ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES", "%s",
501 videoEditOsal_getResultString(result));
502
503 // Check if the creation succeeded.
504 videoEditJava_checkAndThrowRuntimeException(
505 &gotten, pEnv, (M4NO_ERROR != result), result);
506 }
507
508 // Log the API call.
509 VIDEOEDIT_LOG_API(
510 ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
511 "getClipProperties - M4MCS_abort()");
512
513 // Close the MCS session.
514 resultAbort = M4MCS_abort(context);
515
516 if (result == M4NO_ERROR) {
517 // Log the result.
518 VIDEOEDIT_PROP_LOG_RESULT(
519 ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES", "%s",
520 videoEditOsal_getResultString(resultAbort));
521
522 // Check if the abort succeeded.
523 videoEditJava_checkAndThrowRuntimeException(
524 &gotten, pEnv, (M4NO_ERROR != resultAbort), resultAbort);
525 result = resultAbort;
526 }
527 }
528
529 return result;
530 }
531
532 M4OSA_UInt32
VideoEdit_chrCompare(M4OSA_Char * pStrIn1,M4OSA_Char * pStrIn2,M4OSA_Int32 * pCmpResult)533 VideoEdit_chrCompare(M4OSA_Char* pStrIn1,
534 M4OSA_Char* pStrIn2,
535 M4OSA_Int32* pCmpResult)
536 {
537 *pCmpResult = strcmp((const char *)pStrIn1, (const char *)pStrIn2);
538 return *pCmpResult;
539 }
540
541
542