static jbyteArray wseemann_media_FFmpegMediaMetadataRetriever_getEmbeddedPicture(JNIEnv *env, jobject thiz) { //__android_log_write(ANDROID_LOG_INFO, LOG_TAG, "getEmbeddedPicture"); MediaMetadataRetriever* retriever = getRetriever(env, thiz); if (retriever == 0) { jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); return NULL; } AVPacket packet; av_init_packet(&packet); jbyteArray array = NULL; if (retriever->extractAlbumArt(&packet) == 0) { int size = packet.size; uint8_t* data = packet.data; array = env->NewByteArray(size); if (!array) { // OutOfMemoryError exception has already been thrown. //__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "getEmbeddedPicture: OutOfMemoryError is thrown."); } else { //__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "getEmbeddedPicture: Found album art."); jbyte* bytes = env->GetByteArrayElements(array, NULL); if (bytes != NULL) { memcpy(bytes, data, size); env->ReleaseByteArrayElements(array, bytes, 0); } } } av_free_packet(&packet); return array; }
static void android_media_MediaMetadataRetriever_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length) { ALOGV("setDataSource Fd"); MediaMetadataRetriever* retriever = getRetriever(env, thiz); if (retriever == 0) { jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); return; } if (!fileDescriptor) { jniThrowException(env, "java/lang/IllegalArgumentException", NULL); return; } int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); if (offset < 0 || length < 0 || fd < 0) { if (offset < 0) { ALOGE("negative offset (%lld)", offset); } if (length < 0) { ALOGE("negative length (%lld)", length); } if (fd < 0) { ALOGE("invalid file descriptor"); } jniThrowException(env, "java/lang/IllegalArgumentException", NULL); return; } process_media_retriever_call(env, retriever->setDataSource(fd, offset, length), "java/lang/RuntimeException", "setDataSource failed"); }
static jobject wseemann_media_FFmpegMediaMetadataRetriever_extractMetadataFromChapter(JNIEnv *env, jobject thiz, jstring jkey, jint chapter) { //__android_log_write(ANDROID_LOG_INFO, LOG_TAG, "extractMetadataFromChapter"); MediaMetadataRetriever* retriever = getRetriever(env, thiz); if (retriever == 0) { jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); return NULL; } if (!jkey) { jniThrowException(env, "java/lang/IllegalArgumentException", "Null pointer"); return NULL; } const char *key = env->GetStringUTFChars(jkey, NULL); if (!key) { // OutOfMemoryError exception already thrown return NULL; } if (chapter <= 0) { return NULL; } const char* value = retriever->extractMetadataFromChapter(key, chapter); if (!value) { //__android_log_write(ANDROID_LOG_INFO, LOG_TAG, "extractMetadata: Metadata is not found"); return NULL; } //__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "extractMetadata: value (%s) for keyCode(%s)", value, key); env->ReleaseStringUTFChars(jkey, key); return env->NewStringUTF(value); }
static jbyteArray wseemann_media_FFmpegMediaMetadataRetriever_getScaledFrameAtTime(JNIEnv *env, jobject thiz, jlong timeUs, jint option, jint width, jint height) { //__android_log_write(ANDROID_LOG_INFO, LOG_TAG, "getScaledFrameAtTime"); MediaMetadataRetriever* retriever = getRetriever(env, thiz); if (retriever == 0) { jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); return NULL; } AVPacket packet; av_init_packet(&packet); jbyteArray array = NULL; if (retriever->getScaledFrameAtTime(timeUs, option, &packet, width, height) == 0) { int size = packet.size; uint8_t* data = packet.data; array = env->NewByteArray(size); if (!array) { // OutOfMemoryError exception has already been thrown. __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "getFrameAtTime: OutOfMemoryError is thrown."); } else { //__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "getFrameAtTime: Got frame."); jbyte* bytes = env->GetByteArrayElements(array, NULL); if (bytes != NULL) { memcpy(bytes, data, size); env->ReleaseByteArrayElements(array, bytes, 0); } } } av_free_packet(&packet); return array; }
static void wseemann_media_FFmpegMediaMetadataRetriever_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length) { __android_log_write(ANDROID_LOG_VERBOSE, LOG_TAG, "setDataSource"); MediaMetadataRetriever* retriever = getRetriever(env, thiz); if (retriever == 0) { jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); return; } if (!fileDescriptor) { jniThrowException(env, "java/lang/IllegalArgumentException", NULL); return; } int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); if (offset < 0 || length < 0 || fd < 0) { if (offset < 0) { __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "negative offset (%lld)", offset); } if (length < 0) { __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "negative length (%lld)", length); } if (fd < 0) { __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, "invalid file descriptor"); } jniThrowException(env, "java/lang/IllegalArgumentException", NULL); return; } process_media_retriever_call(env, retriever->setDataSource(fd, offset, length), "java/lang/RuntimeException", "setDataSource failed"); }
//MTK Begin static void android_media_MediaMetadataRetriever_setThumbnail(JNIEnv *env, jobject thiz, jboolean isThumbnail) { ALOGV("setThumbnail"); MediaMetadataRetriever* retriever = getRetriever(env, thiz); if (retriever == 0) { jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); return; } process_media_retriever_call(env, retriever->setThumbnail(isThumbnail), "java/lang/RuntimeException", "setThumbnail failed"); }
static void android_media_MediaMetadataRetriever_setDataSourceAndHeaders( JNIEnv *env, jobject thiz, jstring path, jobjectArray keys, jobjectArray values) { ALOGV("setDataSource Path"); MediaMetadataRetriever* retriever = getRetriever(env, thiz); if (retriever == 0) { jniThrowException( env, "java/lang/IllegalStateException", "No retriever available"); return; } if (!path) { jniThrowException( env, "java/lang/IllegalArgumentException", "Null pointer"); return; } const char *tmp = env->GetStringUTFChars(path, NULL); if (!tmp) { // OutOfMemoryError exception already thrown return; } String8 pathStr(tmp); env->ReleaseStringUTFChars(path, tmp); tmp = NULL; // Don't let somebody trick us in to reading some random block of memory if (strncmp("mem://", pathStr.string(), 6) == 0) { jniThrowException( env, "java/lang/IllegalArgumentException", "Invalid pathname"); return; } // We build a similar KeyedVector out of it. KeyedVector<String8, String8> headersVector; if (!ConvertKeyValueArraysToKeyedVector( env, keys, values, &headersVector)) { return; } process_media_retriever_call( env, retriever->setDataSource( pathStr.string(), headersVector.size() > 0 ? &headersVector : NULL), "java/lang/RuntimeException", "setDataSource failed"); }
static jobject android_media_MediaMetadataRetriever_extractMetadata(JNIEnv *env, jobject thiz, jint keyCode) { ALOGV("extractMetadata"); MediaMetadataRetriever* retriever = getRetriever(env, thiz); if (retriever == 0) { jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); return NULL; } const char* value = retriever->extractMetadata(keyCode); if (!value) { ALOGV("extractMetadata: Metadata is not found"); return NULL; } ALOGV("extractMetadata: value (%s) for keyCode(%d)", value, keyCode); return env->NewStringUTF(value); }
static void android_media_MediaMetadataRetriever_setRetriveverSvctxPath(JNIEnv *env, jobject thiz, jstring p_svctx_path) { ALOGV("setRetriveverSvctxPath"); MediaMetadataRetriever* retriever = getRetriever(env, thiz); if (retriever == 0) { jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); return ; } const char* ptemp_path = NULL; ptemp_path = env->GetStringUTFChars(p_svctx_path, NULL); ALOGD("ptemp_path %s\n",ptemp_path); process_media_retriever_call(env, retriever->setRetriveverSvctxPath(ptemp_path), "java/lang/RuntimeException", "setRetriveverSvctxPath failed"); }
static jobject wseemann_media_FFmpegMediaMetadataRetriever_getMetadata(JNIEnv *env, jobject thiz, jboolean update_only, jboolean apply_filter, jobject reply) { //__android_log_write(ANDROID_LOG_INFO, LOG_TAG, "getMetadata"); MediaMetadataRetriever* retriever = getRetriever(env, thiz); if (retriever == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return JNI_FALSE; } // On return metadata is positioned at the beginning of the // metadata. Note however that the parcel actually starts with the // return code so you should not rewind the parcel using // setDataPosition(0). AVDictionary *metadata = NULL; if (retriever->getMetadata(update_only, apply_filter, &metadata) == 0) { jclass hashMap_Clazz = env->FindClass("java/util/HashMap"); jmethodID gHashMap_initMethodID = env->GetMethodID(hashMap_Clazz, "<init>", "()V"); jobject map = env->NewObject(hashMap_Clazz, gHashMap_initMethodID); jmethodID gHashMap_putMethodID = env->GetMethodID(hashMap_Clazz, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); int i = 0; for (i = 0; i < metadata->count; i++) { jstring jKey = NewStringUTF(env, metadata->elems[i].key); jstring jValue = NewStringUTF(env, metadata->elems[i].value); (jobject) env->CallObjectMethod(map, gHashMap_putMethodID, jKey, jValue); env->DeleteLocalRef(jKey); env->DeleteLocalRef(jValue); } if (metadata) { av_dict_free(&metadata); } return map; } else { return reply; } }
static jbyteArray android_media_MediaMetadataRetriever_getEmbeddedPicture( JNIEnv *env, jobject thiz, jint pictureType) { ALOGV("getEmbeddedPicture: %d", pictureType); MediaMetadataRetriever* retriever = getRetriever(env, thiz); if (retriever == 0) { jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); return NULL; } MediaAlbumArt* mediaAlbumArt = NULL; // FIXME: // Use pictureType to retrieve the intended embedded picture and also change // the method name to getEmbeddedPicture(). sp<IMemory> albumArtMemory = retriever->extractAlbumArt(); if (albumArtMemory != 0) { // cast the shared structure to a MediaAlbumArt object mediaAlbumArt = static_cast<MediaAlbumArt *>(albumArtMemory->pointer()); } if (mediaAlbumArt == NULL) { ALOGE("getEmbeddedPicture: Call to getEmbeddedPicture failed."); return NULL; } unsigned int len = mediaAlbumArt->mSize; char* data = (char*) mediaAlbumArt + sizeof(MediaAlbumArt); jbyteArray array = env->NewByteArray(len); if (!array) { // OutOfMemoryError exception has already been thrown. ALOGE("getEmbeddedPicture: OutOfMemoryError is thrown."); } else { jbyte* bytes = env->GetByteArrayElements(array, NULL); if (bytes != NULL) { memcpy(bytes, data, len); env->ReleaseByteArrayElements(array, bytes, 0); } } // No need to delete mediaAlbumArt here return array; }
static jobject android_media_MediaMetadataRetriever_getFrameAtTime(JNIEnv *env, jobject thiz, jlong timeUs, jint option) { ALOGV("getFrameAtTime: %lld us option: %d", timeUs, option); MediaMetadataRetriever* retriever = getRetriever(env, thiz); if (retriever == 0) { jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); return NULL; } // Call native method to retrieve a video frame VideoFrame *videoFrame = NULL; sp<IMemory> frameMemory = retriever->getFrameAtTime(timeUs, option); if (frameMemory != 0) { // cast the shared structure to a VideoFrame object videoFrame = static_cast<VideoFrame *>(frameMemory->pointer()); } if (videoFrame == NULL) { ALOGE("getFrameAtTime: videoFrame is a NULL pointer"); return NULL; } ALOGV("Dimension = %dx%d and bytes = %d", videoFrame->mDisplayWidth, videoFrame->mDisplayHeight, videoFrame->mSize); jobject config = env->CallStaticObjectMethod( fields.configClazz, fields.createConfigMethod, SkBitmap::kRGB_565_Config); size_t width, height; bool swapWidthAndHeight = false; if (videoFrame->mRotationAngle == 90 || videoFrame->mRotationAngle == 270) { width = videoFrame->mHeight; height = videoFrame->mWidth; swapWidthAndHeight = true; } else { width = videoFrame->mWidth; height = videoFrame->mHeight; } jobject jBitmap = env->CallStaticObjectMethod( fields.bitmapClazz, fields.createBitmapMethod, width, height, config); SkBitmap *bitmap = (SkBitmap *) env->GetIntField(jBitmap, fields.nativeBitmap); bitmap->lockPixels(); rotate((uint16_t*)bitmap->getPixels(), (uint16_t*)((char*)videoFrame + sizeof(VideoFrame)), videoFrame->mWidth, videoFrame->mHeight, videoFrame->mRotationAngle); bitmap->unlockPixels(); if (videoFrame->mDisplayWidth != videoFrame->mWidth || videoFrame->mDisplayHeight != videoFrame->mHeight) { size_t displayWidth = videoFrame->mDisplayWidth; size_t displayHeight = videoFrame->mDisplayHeight; if (swapWidthAndHeight) { displayWidth = videoFrame->mDisplayHeight; displayHeight = videoFrame->mDisplayWidth; } ALOGV("Bitmap dimension is scaled from %dx%d to %dx%d", width, height, displayWidth, displayHeight); jobject scaledBitmap = env->CallStaticObjectMethod(fields.bitmapClazz, fields.createScaledBitmapMethod, jBitmap, displayWidth, displayHeight, true); return scaledBitmap; } return jBitmap; }
static void wseemann_media_FFmpegMediaMetadataRetriever_setDataSourceAndHeaders( JNIEnv *env, jobject thiz, jstring path, jobjectArray keys, jobjectArray values) { __android_log_write(ANDROID_LOG_VERBOSE, LOG_TAG, "setDataSource"); MediaMetadataRetriever* retriever = getRetriever(env, thiz); if (retriever == 0) { jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); return; } if (!path) { jniThrowException(env, "java/lang/IllegalArgumentException", "Null pointer"); return; } const char *tmp = env->GetStringUTFChars(path, NULL); if (!tmp) { // OutOfMemoryError exception already thrown return; } // Don't let somebody trick us in to reading some random block of memory if (strncmp("mem://", tmp, 6) == 0) { jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid pathname"); return; } // Workaround for FFmpeg ticket #998 // "must convert mms://... streams to mmsh://... for FFmpeg to work" char *restrict_to = strstr(tmp, "mms://"); if (restrict_to) { strncpy(restrict_to, "mmsh://", 6); puts(tmp); } char *headers = NULL; if (keys && values != NULL) { int keysCount = env->GetArrayLength(keys); int valuesCount = env->GetArrayLength(values); if (keysCount != valuesCount) { __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "keys and values arrays have different length"); jniThrowException(env, "java/lang/IllegalArgumentException", NULL); return; } int i = 0; const char *rawString = NULL; char hdrs[2048]; for (i = 0; i < keysCount; i++) { jstring key = (jstring) env->GetObjectArrayElement(keys, i); rawString = env->GetStringUTFChars(key, NULL); strcat(hdrs, rawString); strcat(hdrs, ": "); env->ReleaseStringUTFChars(key, rawString); jstring value = (jstring) env->GetObjectArrayElement(values, i); rawString = env->GetStringUTFChars(value, NULL); strcat(hdrs, rawString); strcat(hdrs, "\r\n"); env->ReleaseStringUTFChars(value, rawString); } headers = &hdrs[0]; } process_media_retriever_call( env, retriever->setDataSource(tmp, headers), "java/lang/IllegalArgumentException", "setDataSource failed"); env->ReleaseStringUTFChars(path, tmp); tmp = NULL; }