android_media_MediaMetadataRetriever.cpp revision 5bb357f4ccdb573efbe1476a7f20e82f454b3a93
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; 380e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong jfieldID nativeBitmap; 3953ebc72fd83f83bb5536d5917390aae03b7f5cadJames Dong jmethodID createBitmapMethod; 409f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong jmethodID createScaledBitmapMethod; 410e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong jclass configClazz; 420e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong jmethodID createConfigMethod; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic fields_t fields; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic Mutex sLock; 474935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissenstatic const char* const kClassPathName = "android/media/MediaMetadataRetriever"; 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void process_media_retriever_call(JNIEnv *env, status_t opStatus, const char* exception, const char *message) 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (opStatus == (status_t) INVALID_OPERATION) { 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/IllegalStateException", NULL); 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (opStatus != (status_t) OK) { 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (strlen(message) > 230) { 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If the message is too long, don't bother displaying the status code. 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException( env, exception, message); 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char msg[256]; 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Append the status code to the message. 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sprintf(msg, "%s: status = 0x%X", message, opStatus); 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException( env, exception, msg); 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic MediaMetadataRetriever* getRetriever(JNIEnv* env, jobject thiz) 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // No lock is needed, since it is called internally by other methods that are protected 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaMetadataRetriever* retriever = (MediaMetadataRetriever*) env->GetIntField(thiz, fields.context); 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return retriever; 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void setRetriever(JNIEnv* env, jobject thiz, int retriever) 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // No lock is needed, since it is called internally by other methods that are protected 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaMetadataRetriever *old = (MediaMetadataRetriever*) env->GetIntField(thiz, fields.context); 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project env->SetIntField(thiz, fields.context, retriever); 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 805b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huberstatic void 815b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huberandroid_media_MediaMetadataRetriever_setDataSourceAndHeaders( 825b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber JNIEnv *env, jobject thiz, jstring path, jobject headers) { 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGV("setDataSource"); 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaMetadataRetriever* retriever = getRetriever(env, thiz); 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (retriever == 0) { 865b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber jniThrowException( 875b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber env, 885b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber "java/lang/IllegalStateException", "No retriever available"); 895b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 925b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!path) { 945b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber jniThrowException( 955b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber env, "java/lang/IllegalArgumentException", "Null pointer"); 965b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1005b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber const char *tmp = env->GetStringUTFChars(path, NULL); 1015bb357f4ccdb573efbe1476a7f20e82f454b3a93Andreas Huber if (!tmp) { // OutOfMemoryError exception already thrown 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1055bb357f4ccdb573efbe1476a7f20e82f454b3a93Andreas Huber String8 pathStr(tmp); 1065b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber 1075b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber env->ReleaseStringUTFChars(path, tmp); 1085b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber tmp = NULL; 1095b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Don't let somebody trick us in to reading some random block of memory 1115b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber if (strncmp("mem://", pathStr.string(), 6) == 0) { 1125b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber jniThrowException( 1135b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber env, "java/lang/IllegalArgumentException", "Invalid pathname"); 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1175b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber // headers is a Map<String, String>. 1185b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber // We build a similar KeyedVector out of it. 1195b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber KeyedVector<String8, String8> headersVector; 1205b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber if (headers) { 1215b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber // Get the Map's entry Set. 1225b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber jclass mapClass = env->FindClass("java/util/Map"); 1235b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber 1245b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber jmethodID entrySet = 1255b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber env->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;"); 1265b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber 1275b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber jobject set = env->CallObjectMethod(headers, entrySet); 1285b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber // Obtain an iterator over the Set 1295b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber jclass setClass = env->FindClass("java/util/Set"); 1305b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber 1315b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber jmethodID iterator = 1325b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;"); 1335b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber 1345b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber jobject iter = env->CallObjectMethod(set, iterator); 1355b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber // Get the Iterator method IDs 1365b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber jclass iteratorClass = env->FindClass("java/util/Iterator"); 1375b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z"); 1385b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber 1395b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber jmethodID next = 1405b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;"); 1415b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber 1425b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber // Get the Entry class method IDs 1435b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber jclass entryClass = env->FindClass("java/util/Map$Entry"); 1445b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber 1455b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber jmethodID getKey = 1465b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;"); 1475b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber 1485b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber jmethodID getValue = 1495b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;"); 1505b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber 1515b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber // Iterate over the entry Set 1525b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber while (env->CallBooleanMethod(iter, hasNext)) { 1535b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber jobject entry = env->CallObjectMethod(iter, next); 1545b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber jstring key = (jstring) env->CallObjectMethod(entry, getKey); 1555b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber jstring value = (jstring) env->CallObjectMethod(entry, getValue); 1565b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber 1575b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber const char* keyStr = env->GetStringUTFChars(key, NULL); 1585b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber if (!keyStr) { // Out of memory 1595b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber return; 1605b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber } 1615b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber 1625b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber const char* valueStr = env->GetStringUTFChars(value, NULL); 1635b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber if (!valueStr) { // Out of memory 1645b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber return; 1655b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber } 1665b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber 1675b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber headersVector.add(String8(keyStr), String8(valueStr)); 1685b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber 1695b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber env->DeleteLocalRef(entry); 1705b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber env->ReleaseStringUTFChars(key, keyStr); 1715b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber env->DeleteLocalRef(key); 1725b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber env->ReleaseStringUTFChars(value, valueStr); 1735b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber env->DeleteLocalRef(value); 1745b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber } 1755b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber 1765b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber env->DeleteLocalRef(entryClass); 1775b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber env->DeleteLocalRef(iteratorClass); 1785b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber env->DeleteLocalRef(iter); 1795b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber env->DeleteLocalRef(setClass); 1805b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber env->DeleteLocalRef(set); 1815b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber env->DeleteLocalRef(mapClass); 1825b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber } 1835b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber 1845b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber process_media_retriever_call( 1855b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber env, 1865b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber retriever->setDataSource( 1875b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber pathStr.string(), headers ? &headersVector : NULL), 1885b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber 1895b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber "java/lang/RuntimeException", 1905b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber "setDataSource failed"); 1915b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber} 1925b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber 1935b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huberstatic void android_media_MediaMetadataRetriever_setDataSource( 1945b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber JNIEnv *env, jobject thiz, jstring path) { 1955b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber android_media_MediaMetadataRetriever_setDataSourceAndHeaders( 1965b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber env, thiz, path, NULL); 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void android_media_MediaMetadataRetriever_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length) 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGV("setDataSource"); 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaMetadataRetriever* retriever = getRetriever(env, thiz); 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (retriever == 0) { 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!fileDescriptor) { 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int fd = getParcelFileDescriptorFD(env, fileDescriptor); 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (offset < 0 || length < 0 || fd < 0) { 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (offset < 0) { 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGE("negative offset (%lld)", offset); 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (length < 0) { 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGE("negative length (%lld)", length); 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fd < 0) { 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGE("invalid file descriptor"); 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project process_media_retriever_call(env, retriever->setDataSource(fd, offset, length), "java/lang/RuntimeException", "setDataSource failed"); 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 228ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapirotemplate<typename T> 229ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapirostatic void rotate0(T* dst, const T* src, size_t width, size_t height) 230ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro{ 231ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro memcpy(dst, src, width * height * sizeof(T)); 232ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro} 233ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro 234ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapirotemplate<typename T> 235ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapirostatic void rotate90(T* dst, const T* src, size_t width, size_t height) 236ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro{ 237ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro for (size_t i = 0; i < height; ++i) { 238ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro for (size_t j = 0; j < width; ++j) { 239ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro dst[j * height + height - 1 - i] = src[i * width + j]; 240ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro } 241ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro } 242ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro} 243ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro 244ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapirotemplate<typename T> 245ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapirostatic void rotate180(T* dst, const T* src, size_t width, size_t height) 246ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro{ 247ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro for (size_t i = 0; i < height; ++i) { 248ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro for (size_t j = 0; j < width; ++j) { 249ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro dst[(height - 1 - i) * width + width - 1 - j] = src[i * width + j]; 250ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro } 251ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro } 252ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro} 253ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro 254ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapirotemplate<typename T> 255ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapirostatic void rotate270(T* dst, const T* src, size_t width, size_t height) 256ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro{ 257ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro for (size_t i = 0; i < height; ++i) { 258ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro for (size_t j = 0; j < width; ++j) { 259ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro dst[(width - 1 - j) * height + i] = src[i * width + j]; 260ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro } 261ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro } 262ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro} 263ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro 264ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapirotemplate<typename T> 265ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapirostatic void rotate(T *dst, const T *src, size_t width, size_t height, int angle) 266ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro{ 267ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro switch (angle) { 268ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro case 0: 269ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro rotate0(dst, src, width, height); 270ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro break; 271ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro case 90: 272ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro rotate90(dst, src, width, height); 273ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro break; 274ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro case 180: 275ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro rotate180(dst, src, width, height); 276ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro break; 277ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro case 270: 278ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro rotate270(dst, src, width, height); 279ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro break; 280ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro } 281ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro} 282ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro 283faf09ba9405ff019b5ca7e2317debe4ff269d4f8James Dongstatic jobject android_media_MediaMetadataRetriever_getFrameAtTime(JNIEnv *env, jobject thiz, jlong timeUs, jint option) 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 285faf09ba9405ff019b5ca7e2317debe4ff269d4f8James Dong LOGV("getFrameAtTime: %lld us option: %d", timeUs, option); 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaMetadataRetriever* retriever = getRetriever(env, thiz); 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (retriever == 0) { 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Call native method to retrieve a video frame 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project VideoFrame *videoFrame = NULL; 294faf09ba9405ff019b5ca7e2317debe4ff269d4f8James Dong sp<IMemory> frameMemory = retriever->getFrameAtTime(timeUs, option); 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (frameMemory != 0) { // cast the shared structure to a VideoFrame object 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project videoFrame = static_cast<VideoFrame *>(frameMemory->pointer()); 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (videoFrame == NULL) { 299faf09ba9405ff019b5ca7e2317debe4ff269d4f8James Dong LOGE("getFrameAtTime: videoFrame is a NULL pointer"); 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3030e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong LOGV("Dimension = %dx%d and bytes = %d", 3040e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong videoFrame->mDisplayWidth, 3050e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong videoFrame->mDisplayHeight, 3060e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong videoFrame->mSize); 3070e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong 3080e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong jobject config = env->CallStaticObjectMethod( 3090e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong fields.configClazz, 3100e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong fields.createConfigMethod, 3110e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong SkBitmap::kRGB_565_Config); 3120e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong 313ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro size_t width, height; 3149f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong bool swapWidthAndHeight = false; 315ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro if (videoFrame->mRotationAngle == 90 || videoFrame->mRotationAngle == 270) { 3169f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong width = videoFrame->mHeight; 3179f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong height = videoFrame->mWidth; 3189f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong swapWidthAndHeight = true; 319ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro } else { 3209f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong width = videoFrame->mWidth; 3219f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong height = videoFrame->mHeight; 322ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro } 323ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro 3240e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong jobject jBitmap = env->CallStaticObjectMethod( 3250e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong fields.bitmapClazz, 3260e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong fields.createBitmapMethod, 327ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro width, 328ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro height, 3290e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong config); 330ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro 3310e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong SkBitmap *bitmap = 3320e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong (SkBitmap *) env->GetIntField(jBitmap, fields.nativeBitmap); 3330e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong 3340e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong bitmap->lockPixels(); 335ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro rotate((uint16_t*)bitmap->getPixels(), 336ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro (uint16_t*)((char*)videoFrame + sizeof(VideoFrame)), 3379f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong videoFrame->mWidth, 3389f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong videoFrame->mHeight, 339ae12a50a35c0d8425430d0e934c022ecb9cd4936Carl Shapiro videoFrame->mRotationAngle); 3400e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong bitmap->unlockPixels(); 3410e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong 3429f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong if (videoFrame->mDisplayWidth != videoFrame->mWidth || 3439f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong videoFrame->mDisplayHeight != videoFrame->mHeight) { 3449f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong size_t displayWidth = videoFrame->mDisplayWidth; 3459f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong size_t displayHeight = videoFrame->mDisplayHeight; 3469f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong if (swapWidthAndHeight) { 3479f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong displayWidth = videoFrame->mDisplayHeight; 3489f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong displayHeight = videoFrame->mDisplayWidth; 3499f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong } 3509f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong LOGV("Bitmap dimension is scaled from %dx%d to %dx%d", 3519f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong width, height, displayWidth, displayHeight); 3529f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong jobject scaledBitmap = env->CallStaticObjectMethod(fields.bitmapClazz, 3539f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong fields.createScaledBitmapMethod, 3549f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong jBitmap, 3559f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong displayWidth, 3569f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong displayHeight, 3579f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong true); 3589f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong return scaledBitmap; 3599f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong } 3609f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong 3610e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong return jBitmap; 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 364df9b349b960fff95dff4fcf8b2661899e33059daJames Dongstatic jbyteArray android_media_MediaMetadataRetriever_getEmbeddedPicture( 365df9b349b960fff95dff4fcf8b2661899e33059daJames Dong JNIEnv *env, jobject thiz, jint pictureType) 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 367df9b349b960fff95dff4fcf8b2661899e33059daJames Dong LOGV("getEmbeddedPicture: %d", pictureType); 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaMetadataRetriever* retriever = getRetriever(env, thiz); 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (retriever == 0) { 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaAlbumArt* mediaAlbumArt = NULL; 374df9b349b960fff95dff4fcf8b2661899e33059daJames Dong 375df9b349b960fff95dff4fcf8b2661899e33059daJames Dong // FIXME: 376df9b349b960fff95dff4fcf8b2661899e33059daJames Dong // Use pictureType to retrieve the intended embedded picture and also change 377df9b349b960fff95dff4fcf8b2661899e33059daJames Dong // the method name to getEmbeddedPicture(). 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sp<IMemory> albumArtMemory = retriever->extractAlbumArt(); 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (albumArtMemory != 0) { // cast the shared structure to a MediaAlbumArt object 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mediaAlbumArt = static_cast<MediaAlbumArt *>(albumArtMemory->pointer()); 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mediaAlbumArt == NULL) { 383df9b349b960fff95dff4fcf8b2661899e33059daJames Dong LOGE("getEmbeddedPicture: Call to getEmbeddedPicture failed."); 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project unsigned int len = mediaAlbumArt->mSize; 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char* data = (char*) mediaAlbumArt + sizeof(MediaAlbumArt); 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jbyteArray array = env->NewByteArray(len); 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!array) { // OutOfMemoryError exception has already been thrown. 391df9b349b960fff95dff4fcf8b2661899e33059daJames Dong LOGE("getEmbeddedPicture: OutOfMemoryError is thrown."); 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jbyte* bytes = env->GetByteArrayElements(array, NULL); 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (bytes != NULL) { 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project memcpy(bytes, data, len); 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project env->ReleaseByteArrayElements(array, bytes, 0); 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // No need to delete mediaAlbumArt here 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return array; 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jobject android_media_MediaMetadataRetriever_extractMetadata(JNIEnv *env, jobject thiz, jint keyCode) 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGV("extractMetadata"); 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaMetadataRetriever* retriever = getRetriever(env, thiz); 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (retriever == 0) { 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const char* value = retriever->extractMetadata(keyCode); 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!value) { 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGV("extractMetadata: Metadata is not found"); 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGV("extractMetadata: value (%s) for keyCode(%d)", value, keyCode); 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return env->NewStringUTF(value); 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void android_media_MediaMetadataRetriever_release(JNIEnv *env, jobject thiz) 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGV("release"); 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Mutex::Autolock lock(sLock); 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaMetadataRetriever* retriever = getRetriever(env, thiz); 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project delete retriever; 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setRetriever(env, thiz, 0); 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void android_media_MediaMetadataRetriever_native_finalize(JNIEnv *env, jobject thiz) 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGV("native_finalize"); 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // No lock is needed, since android_media_MediaMetadataRetriever_release() is protected 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project android_media_MediaMetadataRetriever_release(env, thiz); 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4374935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen// This function gets a field ID, which in turn causes class initialization. 4384935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen// It is called from a static block in MediaMetadataRetriever, which won't run until the 4394935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen// first time an instance of this class is used. 4404935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissenstatic void android_media_MediaMetadataRetriever_native_init(JNIEnv *env) 4414935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen{ 4424935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen jclass clazz = env->FindClass(kClassPathName); 4434935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen if (clazz == NULL) { 4444935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen jniThrowException(env, "java/lang/RuntimeException", "Can't find android/media/MediaMetadataRetriever"); 4454935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen return; 4464935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen } 4474935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen 4484935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen fields.context = env->GetFieldID(clazz, "mNativeContext", "I"); 4494935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen if (fields.context == NULL) { 4504935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaMetadataRetriever.mNativeContext"); 4514935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen return; 4524935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen } 4534935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen 4544935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen fields.bitmapClazz = env->FindClass("android/graphics/Bitmap"); 4554935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen if (fields.bitmapClazz == NULL) { 4564935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen jniThrowException(env, "java/lang/RuntimeException", "Can't find android/graphics/Bitmap"); 4574935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen return; 4584935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen } 4590e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong fields.createBitmapMethod = 4600e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong env->GetStaticMethodID(fields.bitmapClazz, "createBitmap", 4610e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong "(IILandroid/graphics/Bitmap$Config;)" 4620e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong "Landroid/graphics/Bitmap;"); 4630e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong if (fields.createBitmapMethod == NULL) { 4640e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong jniThrowException(env, "java/lang/RuntimeException", 4650e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong "Can't find Bitmap.createBitmap(int, int, Config) method"); 4660e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong return; 4670e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong } 4689f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong fields.createScaledBitmapMethod = 4699f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong env->GetStaticMethodID(fields.bitmapClazz, "createScaledBitmap", 4709f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong "(Landroid/graphics/Bitmap;IIZ)" 4719f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong "Landroid/graphics/Bitmap;"); 4729f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong if (fields.createScaledBitmapMethod == NULL) { 4739f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong jniThrowException(env, "java/lang/RuntimeException", 4749f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong "Can't find Bitmap.createScaledBitmap(Bitmap, int, int, boolean) method"); 4759f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong return; 4769f2cde3cdb3e2de97f450d0f4e2b52aae86ce5a3James Dong } 4770e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong fields.nativeBitmap = env->GetFieldID(fields.bitmapClazz, "mNativeBitmap", "I"); 4780e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong if (fields.nativeBitmap == NULL) { 4790e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong jniThrowException(env, "java/lang/RuntimeException", 4800e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong "Can't find Bitmap.mNativeBitmap field"); 4810e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong } 4820e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong 4830e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong fields.configClazz = env->FindClass("android/graphics/Bitmap$Config"); 4840e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong if (fields.configClazz == NULL) { 4850e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong jniThrowException(env, "java/lang/RuntimeException", 4860e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong "Can't find Bitmap$Config class"); 4870e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong return; 4880e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong } 4890e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong fields.createConfigMethod = 4900e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong env->GetStaticMethodID(fields.configClazz, "nativeToConfig", 4910e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong "(I)Landroid/graphics/Bitmap$Config;"); 4920e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong if (fields.createConfigMethod == NULL) { 4930e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong jniThrowException(env, "java/lang/RuntimeException", 4940e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong "Can't find Bitmap$Config.nativeToConfig(int) method"); 4950e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong return; 4960e4b535b439f2c8bd4f7ba820f81bf74336bae76James Dong } 4974935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen} 4984935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void android_media_MediaMetadataRetriever_native_setup(JNIEnv *env, jobject thiz) 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LOGV("native_setup"); 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaMetadataRetriever* retriever = new MediaMetadataRetriever(); 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (retriever == 0) { 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setRetriever(env, thiz, (int)retriever); 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// JNI mapping between Java methods and native methods 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic JNINativeMethod nativeMethods[] = { 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaMetadataRetriever_setDataSource}, 5135b7ced6a4ebcec34a36d0779773bc9e671732dbfAndreas Huber {"setDataSource", "(Ljava/lang/String;Ljava/util/Map;)V", (void *)android_media_MediaMetadataRetriever_setDataSourceAndHeaders}, 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaMetadataRetriever_setDataSourceFD}, 515faf09ba9405ff019b5ca7e2317debe4ff269d4f8James Dong {"_getFrameAtTime", "(JI)Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getFrameAtTime}, 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {"extractMetadata", "(I)Ljava/lang/String;", (void *)android_media_MediaMetadataRetriever_extractMetadata}, 517df9b349b960fff95dff4fcf8b2661899e33059daJames Dong {"getEmbeddedPicture", "(I)[B", (void *)android_media_MediaMetadataRetriever_getEmbeddedPicture}, 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {"release", "()V", (void *)android_media_MediaMetadataRetriever_release}, 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {"native_finalize", "()V", (void *)android_media_MediaMetadataRetriever_native_finalize}, 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {"native_setup", "()V", (void *)android_media_MediaMetadataRetriever_native_setup}, 5214935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen {"native_init", "()V", (void *)android_media_MediaMetadataRetriever_native_init}, 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}; 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5244935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen// This function only registers the native methods, and is called from 5254935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen// JNI_OnLoad in android_media_MediaPlayer.cpp 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint register_android_media_MediaMetadataRetriever(JNIEnv *env) 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return AndroidRuntime::registerNativeMethods 5294935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen (env, kClassPathName, nativeMethods, NELEM(nativeMethods)); 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 531