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 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 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 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 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