static jbyteArray wseemann_media_FFmpegMediaMetadataRetriever_getFrameAtTime(JNIEnv *env, jobject thiz, jlong timeUs, jint option) { //__android_log_write(ANDROID_LOG_INFO, LOG_TAG, "getFrameAtTime"); 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->getFrameAtTime(timeUs, option, &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, "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 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; }