PageRenderTime 717ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/media/jni/android_media_MediaScanner.cpp

https://github.com/doixanh/android_frameworks_base
C++ | 347 lines | 251 code | 62 blank | 34 comment | 46 complexity | 8621954827a7c4e52d10b42320733bd3 MD5 | raw file
  1. /* //device/libs/media_jni/MediaScanner.cpp
  2. **
  3. ** Copyright 2007, The Android Open Source Project
  4. **
  5. ** Licensed under the Apache License, Version 2.0 (the "License");
  6. ** you may not use this file except in compliance with the License.
  7. ** You may obtain a copy of the License at
  8. **
  9. ** http://www.apache.org/licenses/LICENSE-2.0
  10. **
  11. ** Unless required by applicable law or agreed to in writing, software
  12. ** distributed under the License is distributed on an "AS IS" BASIS,
  13. ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. ** See the License for the specific language governing permissions and
  15. ** limitations under the License.
  16. */
  17. #define LOG_TAG "MediaScanner"
  18. #include "utils/Log.h"
  19. #include <media/mediascanner.h>
  20. #include <stdio.h>
  21. #include <assert.h>
  22. #include <limits.h>
  23. #include <unistd.h>
  24. #include <fcntl.h>
  25. #include <cutils/properties.h>
  26. #include <utils/threads.h>
  27. #include "jni.h"
  28. #include "JNIHelp.h"
  29. #include "android_runtime/AndroidRuntime.h"
  30. #include <media/stagefright/StagefrightMediaScanner.h>
  31. #ifdef USE_BOARD_MEDIASCANNER
  32. #include <media/stagefright/StagefrightMediaScanner.h>
  33. #include <hardware_legacy/MediaPlayerHardwareInterface.h>
  34. #endif
  35. // ----------------------------------------------------------------------------
  36. using namespace android;
  37. // ----------------------------------------------------------------------------
  38. struct fields_t {
  39. jfieldID context;
  40. };
  41. static fields_t fields;
  42. // ----------------------------------------------------------------------------
  43. class MyMediaScannerClient : public MediaScannerClient
  44. {
  45. public:
  46. MyMediaScannerClient(JNIEnv *env, jobject client)
  47. : mEnv(env),
  48. mClient(env->NewGlobalRef(client)),
  49. mScanFileMethodID(0),
  50. mHandleStringTagMethodID(0),
  51. mSetMimeTypeMethodID(0)
  52. {
  53. jclass mediaScannerClientInterface = env->FindClass("android/media/MediaScannerClient");
  54. if (mediaScannerClientInterface == NULL) {
  55. fprintf(stderr, "android/media/MediaScannerClient not found\n");
  56. }
  57. else {
  58. mScanFileMethodID = env->GetMethodID(mediaScannerClientInterface, "scanFile",
  59. "(Ljava/lang/String;JJ)V");
  60. mHandleStringTagMethodID = env->GetMethodID(mediaScannerClientInterface, "handleStringTag",
  61. "(Ljava/lang/String;Ljava/lang/String;)V");
  62. mSetMimeTypeMethodID = env->GetMethodID(mediaScannerClientInterface, "setMimeType",
  63. "(Ljava/lang/String;)V");
  64. mAddNoMediaFolderMethodID = env->GetMethodID(mediaScannerClientInterface, "addNoMediaFolder",
  65. "(Ljava/lang/String;)V");
  66. }
  67. }
  68. virtual ~MyMediaScannerClient()
  69. {
  70. mEnv->DeleteGlobalRef(mClient);
  71. }
  72. // returns true if it succeeded, false if an exception occured in the Java code
  73. virtual bool scanFile(const char* path, long long lastModified, long long fileSize)
  74. {
  75. jstring pathStr;
  76. if ((pathStr = mEnv->NewStringUTF(path)) == NULL) return false;
  77. mEnv->CallVoidMethod(mClient, mScanFileMethodID, pathStr, lastModified, fileSize);
  78. mEnv->DeleteLocalRef(pathStr);
  79. return (!mEnv->ExceptionCheck());
  80. }
  81. // returns true if it succeeded, false if an exception occured in the Java code
  82. virtual bool handleStringTag(const char* name, const char* value)
  83. {
  84. jstring nameStr, valueStr;
  85. if ((nameStr = mEnv->NewStringUTF(name)) == NULL) return false;
  86. if ((valueStr = mEnv->NewStringUTF(value)) == NULL) return false;
  87. mEnv->CallVoidMethod(mClient, mHandleStringTagMethodID, nameStr, valueStr);
  88. mEnv->DeleteLocalRef(nameStr);
  89. mEnv->DeleteLocalRef(valueStr);
  90. return (!mEnv->ExceptionCheck());
  91. }
  92. // returns true if it succeeded, false if an exception occured in the Java code
  93. virtual bool setMimeType(const char* mimeType)
  94. {
  95. jstring mimeTypeStr;
  96. if ((mimeTypeStr = mEnv->NewStringUTF(mimeType)) == NULL) return false;
  97. mEnv->CallVoidMethod(mClient, mSetMimeTypeMethodID, mimeTypeStr);
  98. mEnv->DeleteLocalRef(mimeTypeStr);
  99. return (!mEnv->ExceptionCheck());
  100. }
  101. // returns true if it succeeded, false if an exception occured in the Java code
  102. virtual bool addNoMediaFolder(const char* path)
  103. {
  104. jstring pathStr;
  105. if ((pathStr = mEnv->NewStringUTF(path)) == NULL) return false;
  106. mEnv->CallVoidMethod(mClient, mAddNoMediaFolderMethodID, pathStr);
  107. mEnv->DeleteLocalRef(pathStr);
  108. return (!mEnv->ExceptionCheck());
  109. }
  110. private:
  111. JNIEnv *mEnv;
  112. jobject mClient;
  113. jmethodID mScanFileMethodID;
  114. jmethodID mHandleStringTagMethodID;
  115. jmethodID mSetMimeTypeMethodID;
  116. jmethodID mAddNoMediaFolderMethodID;
  117. };
  118. // ----------------------------------------------------------------------------
  119. static bool ExceptionCheck(void* env)
  120. {
  121. return ((JNIEnv *)env)->ExceptionCheck();
  122. }
  123. static void
  124. android_media_MediaScanner_processDirectory(JNIEnv *env, jobject thiz, jstring path, jstring extensions, jobject client)
  125. {
  126. MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context);
  127. if (path == NULL) {
  128. jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
  129. return;
  130. }
  131. if (extensions == NULL) {
  132. jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
  133. return;
  134. }
  135. const char *pathStr = env->GetStringUTFChars(path, NULL);
  136. if (pathStr == NULL) { // Out of memory
  137. jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
  138. return;
  139. }
  140. const char *extensionsStr = env->GetStringUTFChars(extensions, NULL);
  141. if (extensionsStr == NULL) { // Out of memory
  142. env->ReleaseStringUTFChars(path, pathStr);
  143. jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
  144. return;
  145. }
  146. MyMediaScannerClient myClient(env, client);
  147. mp->processDirectory(pathStr, extensionsStr, myClient, ExceptionCheck, env);
  148. env->ReleaseStringUTFChars(path, pathStr);
  149. env->ReleaseStringUTFChars(extensions, extensionsStr);
  150. }
  151. static void
  152. android_media_MediaScanner_processFile(JNIEnv *env, jobject thiz, jstring path, jstring mimeType, jobject client)
  153. {
  154. MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context);
  155. if (path == NULL) {
  156. jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
  157. return;
  158. }
  159. const char *pathStr = env->GetStringUTFChars(path, NULL);
  160. if (pathStr == NULL) { // Out of memory
  161. jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
  162. return;
  163. }
  164. const char *mimeTypeStr = (mimeType ? env->GetStringUTFChars(mimeType, NULL) : NULL);
  165. if (mimeType && mimeTypeStr == NULL) { // Out of memory
  166. env->ReleaseStringUTFChars(path, pathStr);
  167. jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
  168. return;
  169. }
  170. MyMediaScannerClient myClient(env, client);
  171. mp->processFile(pathStr, mimeTypeStr, myClient);
  172. env->ReleaseStringUTFChars(path, pathStr);
  173. if (mimeType) {
  174. env->ReleaseStringUTFChars(mimeType, mimeTypeStr);
  175. }
  176. }
  177. static void
  178. android_media_MediaScanner_setLocale(JNIEnv *env, jobject thiz, jstring locale)
  179. {
  180. MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context);
  181. if (locale == NULL) {
  182. jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
  183. return;
  184. }
  185. const char *localeStr = env->GetStringUTFChars(locale, NULL);
  186. if (localeStr == NULL) { // Out of memory
  187. jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
  188. return;
  189. }
  190. mp->setLocale(localeStr);
  191. env->ReleaseStringUTFChars(locale, localeStr);
  192. }
  193. static jbyteArray
  194. android_media_MediaScanner_extractAlbumArt(JNIEnv *env, jobject thiz, jobject fileDescriptor)
  195. {
  196. MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context);
  197. if (fileDescriptor == NULL) {
  198. jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
  199. return NULL;
  200. }
  201. int fd = getParcelFileDescriptorFD(env, fileDescriptor);
  202. char* data = mp->extractAlbumArt(fd);
  203. if (!data) {
  204. return NULL;
  205. }
  206. long len = *((long*)data);
  207. jbyteArray array = env->NewByteArray(len);
  208. if (array != NULL) {
  209. jbyte* bytes = env->GetByteArrayElements(array, NULL);
  210. memcpy(bytes, data + 4, len);
  211. env->ReleaseByteArrayElements(array, bytes, 0);
  212. }
  213. done:
  214. free(data);
  215. // if NewByteArray() returned NULL, an out-of-memory
  216. // exception will have been raised. I just want to
  217. // return null in that case.
  218. env->ExceptionClear();
  219. return array;
  220. }
  221. // This function gets a field ID, which in turn causes class initialization.
  222. // It is called from a static block in MediaScanner, which won't run until the
  223. // first time an instance of this class is used.
  224. static void
  225. android_media_MediaScanner_native_init(JNIEnv *env)
  226. {
  227. jclass clazz;
  228. clazz = env->FindClass("android/media/MediaScanner");
  229. if (clazz == NULL) {
  230. jniThrowException(env, "java/lang/RuntimeException", "Can't find android/media/MediaScanner");
  231. return;
  232. }
  233. fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
  234. if (fields.context == NULL) {
  235. jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaScanner.mNativeContext");
  236. return;
  237. }
  238. }
  239. static MediaScanner *createMediaScanner() {
  240. LOGV("MediaScanner *createMediaScanner\n");
  241. #ifdef USE_BOARD_MEDIASCANNER
  242. LOGV("MediaScanner *createMediaScannerHardware\n");
  243. return createMediaScannerHardware();
  244. #endif
  245. return new StagefrightMediaScanner;
  246. }
  247. static void
  248. android_media_MediaScanner_native_setup(JNIEnv *env, jobject thiz)
  249. {
  250. MediaScanner *mp = createMediaScanner();
  251. if (mp == NULL) {
  252. jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
  253. return;
  254. }
  255. env->SetIntField(thiz, fields.context, (int)mp);
  256. }
  257. static void
  258. android_media_MediaScanner_native_finalize(JNIEnv *env, jobject thiz)
  259. {
  260. MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context);
  261. //printf("##### android_media_MediaScanner_native_finalize: ctx=0x%p\n", ctx);
  262. if (mp == 0)
  263. return;
  264. delete mp;
  265. }
  266. // ----------------------------------------------------------------------------
  267. static JNINativeMethod gMethods[] = {
  268. {"processDirectory", "(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
  269. (void *)android_media_MediaScanner_processDirectory},
  270. {"processFile", "(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
  271. (void *)android_media_MediaScanner_processFile},
  272. {"setLocale", "(Ljava/lang/String;)V", (void *)android_media_MediaScanner_setLocale},
  273. {"extractAlbumArt", "(Ljava/io/FileDescriptor;)[B", (void *)android_media_MediaScanner_extractAlbumArt},
  274. {"native_init", "()V", (void *)android_media_MediaScanner_native_init},
  275. {"native_setup", "()V", (void *)android_media_MediaScanner_native_setup},
  276. {"native_finalize", "()V", (void *)android_media_MediaScanner_native_finalize},
  277. };
  278. static const char* const kClassPathName = "android/media/MediaScanner";
  279. // This function only registers the native methods, and is called from
  280. // JNI_OnLoad in android_media_MediaPlayer.cpp
  281. int register_android_media_MediaScanner(JNIEnv *env)
  282. {
  283. return AndroidRuntime::registerNativeMethods(env,
  284. "android/media/MediaScanner", gMethods, NELEM(gMethods));
  285. }