android_media_MediaMetadataRetriever.cpp revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** Copyright 2008, The Android Open Source Project 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License"); 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** you may not use this file except in compliance with the License. 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** You may obtain a copy of the License at 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** http://www.apache.org/licenses/LICENSE-2.0 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** Unless required by applicable law or agreed to in writing, software 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** distributed under the License is distributed on an "AS IS" BASIS, 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** See the License for the specific language governing permissions and 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** limitations under the License. 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project*/ 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//#define LOG_NDEBUG 0 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "MediaMetadataRetrieverJNI" 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <assert.h> 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Log.h> 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/threads.h> 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <core/SkBitmap.h> 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <media/mediametadataretriever.h> 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <private/media/VideoFrame.h> 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "jni.h" 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "JNIHelp.h" 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "android_runtime/AndroidRuntime.h" 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectusing namespace android; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstruct fields_t { 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jfieldID context; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jclass bitmapClazz; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jmethodID bitmapConstructor; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic fields_t fields; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic Mutex sLock; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void process_media_retriever_call(JNIEnv *env, status_t opStatus, const char* exception, const char *message) 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (opStatus == (status_t) INVALID_OPERATION) { 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/IllegalStateException", NULL); 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (opStatus != (status_t) OK) { 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (strlen(message) > 230) { 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If the message is too long, don't bother displaying the status code. 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException( env, exception, message); 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char msg[256]; 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Append the status code to the message. 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sprintf(msg, "%s: status = 0x%X", message, opStatus); 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException( env, exception, msg); 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic MediaMetadataRetriever* getRetriever(JNIEnv* env, jobject thiz) 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // No lock is needed, since it is called internally by other methods that are protected 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaMetadataRetriever* retriever = (MediaMetadataRetriever*) env->GetIntField(thiz, fields.context); 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return retriever; 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void setRetriever(JNIEnv* env, jobject thiz, int retriever) 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // No lock is needed, since it is called internally by other methods that are protected 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaMetadataRetriever *old = (MediaMetadataRetriever*) env->GetIntField(thiz, fields.context); 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project env->SetIntField(thiz, fields.context, retriever); 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void android_media_MediaMetadataRetriever_setDataSource(JNIEnv *env, jobject thiz, jstring path) 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGV("setDataSource"); 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Mutex::Autolock lock(sLock); 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaMetadataRetriever* retriever = getRetriever(env, thiz); 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (retriever == 0) { 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!path) { 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/IllegalArgumentException", "Null pointer"); 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const char *pathStr = env->GetStringUTFChars(path, NULL); 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!pathStr) { // OutOfMemoryError exception already thrown 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Don't let somebody trick us in to reading some random block of memory 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (strncmp("mem://", pathStr, 6) == 0) { 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid pathname"); 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project process_media_retriever_call(env, retriever->setDataSource(pathStr), "java/lang/RuntimeException", "setDataSource failed"); 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project env->ReleaseStringUTFChars(path, pathStr); 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void android_media_MediaMetadataRetriever_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length) 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGV("setDataSource"); 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Mutex::Autolock lock(sLock); 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaMetadataRetriever* retriever = getRetriever(env, thiz); 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (retriever == 0) { 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!fileDescriptor) { 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int fd = getParcelFileDescriptorFD(env, fileDescriptor); 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (offset < 0 || length < 0 || fd < 0) { 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (offset < 0) { 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGE("negative offset (%lld)", offset); 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (length < 0) { 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGE("negative length (%lld)", length); 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fd < 0) { 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGE("invalid file descriptor"); 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project process_media_retriever_call(env, retriever->setDataSource(fd, offset, length), "java/lang/RuntimeException", "setDataSource failed"); 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void android_media_MediaMetadataRetriever_setMode(JNIEnv *env, jobject thiz, jint mode) 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGV("setMode"); 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Mutex::Autolock lock(sLock); 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaMetadataRetriever* retriever = getRetriever(env, thiz); 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (retriever == 0) { 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project process_media_retriever_call(env, retriever->setMode(mode), "java/lang/RuntimeException", "setMode failed"); 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic int android_media_MediaMetadataRetriever_getMode(JNIEnv *env, jobject thiz) 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGV("getMode"); 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Mutex::Autolock lock(sLock); 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaMetadataRetriever* retriever = getRetriever(env, thiz); 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (retriever == 0) { 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; // Error 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int mode = -1; 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project retriever->getMode(&mode); 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mode; 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jobject android_media_MediaMetadataRetriever_captureFrame(JNIEnv *env, jobject thiz) 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGV("captureFrame"); 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Mutex::Autolock lock(sLock); 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaMetadataRetriever* retriever = getRetriever(env, thiz); 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (retriever == 0) { 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Call native method to retrieve a video frame 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project VideoFrame *videoFrame = NULL; 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sp<IMemory> frameMemory = retriever->captureFrame(); 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (frameMemory != 0) { // cast the shared structure to a VideoFrame object 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project videoFrame = static_cast<VideoFrame *>(frameMemory->pointer()); 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (videoFrame == NULL) { 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGE("captureFrame: videoFrame is a NULL pointer"); 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Create a SkBitmap to hold the pixels 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkBitmap *bitmap = new SkBitmap(); 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (bitmap == NULL) { 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGE("captureFrame: cannot instantiate a SkBitmap object."); 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bitmap->setConfig(SkBitmap::kRGB_565_Config, videoFrame->mDisplayWidth, videoFrame->mDisplayHeight); 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!bitmap->allocPixels()) { 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project delete bitmap; 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGE("failed to allocate pixel buffer"); 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project memcpy((uint8_t*)bitmap->getPixels(), (uint8_t*)videoFrame + sizeof(VideoFrame), videoFrame->mSize); 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Since internally SkBitmap uses reference count to manage the reference to 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // its pixels, it is important that the pixels (along with SkBitmap) be 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // available after creating the Bitmap is returned to Java app. 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return env->NewObject(fields.bitmapClazz, fields.bitmapConstructor, (int) bitmap, true, NULL); 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jbyteArray android_media_MediaMetadataRetriever_extractAlbumArt(JNIEnv *env, jobject thiz) 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGV("extractAlbumArt"); 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Mutex::Autolock lock(sLock); 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaMetadataRetriever* retriever = getRetriever(env, thiz); 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (retriever == 0) { 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaAlbumArt* mediaAlbumArt = NULL; 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sp<IMemory> albumArtMemory = retriever->extractAlbumArt(); 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (albumArtMemory != 0) { // cast the shared structure to a MediaAlbumArt object 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mediaAlbumArt = static_cast<MediaAlbumArt *>(albumArtMemory->pointer()); 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mediaAlbumArt == NULL) { 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGE("extractAlbumArt: Call to extractAlbumArt failed."); 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unsigned int len = mediaAlbumArt->mSize; 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char* data = (char*) mediaAlbumArt + sizeof(MediaAlbumArt); 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jbyteArray array = env->NewByteArray(len); 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!array) { // OutOfMemoryError exception has already been thrown. 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGE("extractAlbumArt: OutOfMemoryError is thrown."); 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jbyte* bytes = env->GetByteArrayElements(array, NULL); 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (bytes != NULL) { 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project memcpy(bytes, data, len); 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project env->ReleaseByteArrayElements(array, bytes, 0); 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // No need to delete mediaAlbumArt here 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return array; 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jobject android_media_MediaMetadataRetriever_extractMetadata(JNIEnv *env, jobject thiz, jint keyCode) 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGV("extractMetadata"); 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Mutex::Autolock lock(sLock); 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaMetadataRetriever* retriever = getRetriever(env, thiz); 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (retriever == 0) { 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const char* value = retriever->extractMetadata(keyCode); 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!value) { 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGV("extractMetadata: Metadata is not found"); 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGV("extractMetadata: value (%s) for keyCode(%d)", value, keyCode); 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return env->NewStringUTF(value); 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void android_media_MediaMetadataRetriever_release(JNIEnv *env, jobject thiz) 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGV("release"); 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Mutex::Autolock lock(sLock); 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaMetadataRetriever* retriever = getRetriever(env, thiz); 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project delete retriever; 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setRetriever(env, thiz, 0); 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void android_media_MediaMetadataRetriever_native_finalize(JNIEnv *env, jobject thiz) 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGV("native_finalize"); 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // No lock is needed, since android_media_MediaMetadataRetriever_release() is protected 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project android_media_MediaMetadataRetriever_release(env, thiz); 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void android_media_MediaMetadataRetriever_native_setup(JNIEnv *env, jobject thiz) 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGV("native_setup"); 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaMetadataRetriever* retriever = new MediaMetadataRetriever(); 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (retriever == 0) { 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setRetriever(env, thiz, (int)retriever); 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// JNI mapping between Java methods and native methods 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic JNINativeMethod nativeMethods[] = { 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaMetadataRetriever_setDataSource}, 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaMetadataRetriever_setDataSourceFD}, 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {"setMode", "(I)V", (void *)android_media_MediaMetadataRetriever_setMode}, 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {"getMode", "()I", (void *)android_media_MediaMetadataRetriever_getMode}, 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {"captureFrame", "()Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_captureFrame}, 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {"extractMetadata", "(I)Ljava/lang/String;", (void *)android_media_MediaMetadataRetriever_extractMetadata}, 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {"extractAlbumArt", "()[B", (void *)android_media_MediaMetadataRetriever_extractAlbumArt}, 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {"release", "()V", (void *)android_media_MediaMetadataRetriever_release}, 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {"native_finalize", "()V", (void *)android_media_MediaMetadataRetriever_native_finalize}, 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {"native_setup", "()V", (void *)android_media_MediaMetadataRetriever_native_setup}, 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}; 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// Register native mehtods with Android runtime environment 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint register_android_media_MediaMetadataRetriever(JNIEnv *env) 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static const char* const kClassPathName = "android/media/MediaMetadataRetriever"; 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jclass clazz = env->FindClass(kClassPathName); 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (clazz == NULL) { 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGE("Can't find class: %s", kClassPathName); 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fields.context = env->GetFieldID(clazz, "mNativeContext", "I"); 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fields.context == NULL) { 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGE("Can't find MediaMetadataRetriever.mNativeContext"); 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fields.bitmapClazz = env->FindClass("android/graphics/Bitmap"); 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fields.bitmapClazz == NULL) { 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGE("Bitmap class is not found"); 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fields.bitmapConstructor = env->GetMethodID(fields.bitmapClazz, "<init>", "(IZ[B)V"); 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fields.bitmapConstructor == NULL) { 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGE("Bitmap constructor is not found"); 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return AndroidRuntime::registerNativeMethods 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (env, kClassPathName, nativeMethods, NELEM(nativeMethods)); 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 328