Add: jni method of media retriever

pull/209/head
xufulong 3 years ago
parent 84e64c159b
commit a8b1c59365
  1. 14
      app/src/main/cpp/ffmpeg_jni_define.h
  2. 69
      app/src/main/cpp/metadata/media_retriever_jni.cpp

@ -34,16 +34,16 @@ extern "C" { \
JNIEXPORT RETURN_TYPE JNICALL Java_com_frank_ffmpeg_VideoPlayer_ ## FUNC_NAME \ JNIEXPORT RETURN_TYPE JNICALL Java_com_frank_ffmpeg_VideoPlayer_ ## FUNC_NAME \
(JNIEnv *env, jobject thiz, ##__VA_ARGS__)\ (JNIEnv *env, jobject thiz, ##__VA_ARGS__)\
#define MEDIA_PLAYER_FUNC(RETURN_TYPE, FUNC_NAME, ...) \ #define PUSHER_FUNC(RETURN_TYPE, FUNC_NAME, ...) \
JNIEXPORT RETURN_TYPE JNICALL Java_com_frank_ffmpeg_Pusher_ ## FUNC_NAME \
(JNIEnv *env, jobject thiz, ##__VA_ARGS__)\
#define RETRIEVER_FUNC(RETURN_TYPE, FUNC_NAME, ...) \
extern "C" { \ extern "C" { \
JNIEXPORT RETURN_TYPE JNICALL Java_com_frank_ffmpeg_MediaPlayer_ ## FUNC_NAME \ JNIEXPORT RETURN_TYPE JNICALL Java_com_frank_ffmpeg_metadata_FFmpegMediaRetriever_ ## FUNC_NAME \
(JNIEnv *env, jobject thiz, ##__VA_ARGS__);\ (JNIEnv *env, jobject thiz, ##__VA_ARGS__);\
}\ }\
JNIEXPORT RETURN_TYPE JNICALL Java_com_frank_ffmpeg_MediaPlayer_ ## FUNC_NAME \ JNIEXPORT RETURN_TYPE JNICALL Java_com_frank_ffmpeg_metadata_FFmpegMediaRetriever_ ## FUNC_NAME \
(JNIEnv *env, jobject thiz, ##__VA_ARGS__)\
#define PUSHER_FUNC(RETURN_TYPE, FUNC_NAME, ...) \
JNIEXPORT RETURN_TYPE JNICALL Java_com_frank_ffmpeg_Pusher_ ## FUNC_NAME \
(JNIEnv *env, jobject thiz, ##__VA_ARGS__)\ (JNIEnv *env, jobject thiz, ##__VA_ARGS__)\
#endif //FFMPEGANDROID_FFMPEG_JNI_DEFINE_H #endif //FFMPEGANDROID_FFMPEG_JNI_DEFINE_H

@ -9,14 +9,9 @@
#include "jni.h" #include "jni.h"
#include <android/bitmap.h> #include <android/bitmap.h>
#include "ffmpeg_jni_define.h"
#define LOG_TAG "FFmpegMediaRetrieverJNI" #define LOG_TAG "FFmpegMediaRetriever"
extern "C" {
#include "ffmpeg_media_retriever.h"
}
using namespace std;
struct fields_t { struct fields_t {
jfieldID context; jfieldID context;
@ -26,16 +21,16 @@ static fields_t fields;
static ANativeWindow* theNativeWindow; static ANativeWindow* theNativeWindow;
static const char* kClassPathName = "com/frank/ffmpeg/metadata/FFmpegMediaRetriever"; static const char* kClassPathName = "com/frank/ffmpeg/metadata/FFmpegMediaRetriever";
static jstring NewStringUTF(JNIEnv* env, const char * data) { static jstring NewStringUTF(JNIEnv* env, const char* data) {
jstring str = nullptr; jstring str = nullptr;
int size = strlen(data); int size = strlen(data);
jbyteArray array = env->NewByteArray(size); jbyteArray array = env->NewByteArray(size);
if (!array) { if (!array) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "convertString: OutOfMemoryError is thrown."); LOGE(LOG_TAG, "convertString: OutOfMemoryError is thrown.");
} else { } else {
jbyte* bytes = env->GetByteArrayElements(array, nullptr); jbyte* bytes = env->GetByteArrayElements(array, nullptr);
if (bytes != nullptr) { if (bytes != nullptr) {
memcpy(bytes, data, size); strcpy((char *)bytes, data);
env->ReleaseByteArrayElements(array, bytes, 0); env->ReleaseByteArrayElements(array, bytes, 0);
jclass string_Clazz = env->FindClass("java/lang/String"); jclass string_Clazz = env->FindClass("java/lang/String");
@ -57,16 +52,16 @@ void jniThrowException(JNIEnv* env, const char* className,
env->ThrowNew(exception, msg); env->ThrowNew(exception, msg);
} }
static void process_retriever_call(JNIEnv *env, int opStatus, const char* exception, const char *message) static void process_retriever_call(JNIEnv *env, int status, const char* exception, const char *message)
{ {
if (opStatus == -2) { if (status == -2) {
jniThrowException(env, "java/lang/IllegalStateException", nullptr); jniThrowException(env, "java/lang/IllegalStateException", nullptr);
} else if (opStatus == -1) { } else if (status == -1) {
if (strlen(message) > 520) { if (strlen(message) > 520) {
jniThrowException( env, exception, message); jniThrowException( env, exception, message);
} else { } else {
char msg[256]; char msg[256];
sprintf(msg, "%s: status = 0x%X", message, opStatus); sprintf(msg, "%s: status = 0x%X", message, status);
jniThrowException( env, exception, msg); jniThrowException( env, exception, msg);
} }
} }
@ -80,17 +75,16 @@ static MediaRetriever* getRetriever(JNIEnv* env, jobject thiz)
static void setRetriever(JNIEnv* env, jobject thiz, long retriever) static void setRetriever(JNIEnv* env, jobject thiz, long retriever)
{ {
auto *old = (MediaRetriever*) env->GetLongField(thiz, fields.context);
env->SetLongField(thiz, fields.context, retriever); env->SetLongField(thiz, fields.context, retriever);
} }
static void native_setup(JNIEnv *env, jobject thiz) RETRIEVER_FUNC(void, native_setup)
{ {
auto* retriever = new MediaRetriever(); auto* retriever = new MediaRetriever();
setRetriever(env, thiz, (long)retriever); setRetriever(env, thiz, (long)retriever);
} }
static void native_init(JNIEnv *env, jobject thiz) RETRIEVER_FUNC(void, native_init)
{ {
jclass clazz = env->FindClass(kClassPathName); jclass clazz = env->FindClass(kClassPathName);
if (!clazz) { if (!clazz) {
@ -106,7 +100,7 @@ static void native_init(JNIEnv *env, jobject thiz)
avformat_network_init(); avformat_network_init();
} }
static void native_set_dataSource(JNIEnv *env, jobject thiz, jstring path) { RETRIEVER_FUNC(void, native_set_dataSource, jstring path) {
MediaRetriever* retriever = getRetriever(env, thiz); MediaRetriever* retriever = getRetriever(env, thiz);
if (retriever == nullptr) { if (retriever == nullptr) {
jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
@ -130,7 +124,7 @@ static void native_set_dataSource(JNIEnv *env, jobject thiz, jstring path) {
env->ReleaseStringUTFChars(path, tmp); env->ReleaseStringUTFChars(path, tmp);
} }
static int jniGetFDFromFileDescriptor(JNIEnv * env, jobject fileDescriptor) { static int getFileDescriptor(JNIEnv * env, jobject fileDescriptor) {
jint fd = -1; jint fd = -1;
jclass fdClass = env->FindClass("java/io/FileDescriptor"); jclass fdClass = env->FindClass("java/io/FileDescriptor");
@ -144,8 +138,11 @@ static int jniGetFDFromFileDescriptor(JNIEnv * env, jobject fileDescriptor) {
return fd; return fd;
} }
static void native_set_dataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length) RETRIEVER_FUNC(void, native_set_dataSourceFD, jobject fileDescriptor, jlong offset, jlong length)
{ {
if (offset < 0 || length < 0) {
return;
}
MediaRetriever* retriever = getRetriever(env, thiz); MediaRetriever* retriever = getRetriever(env, thiz);
if (retriever == nullptr) { if (retriever == nullptr) {
jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
@ -155,39 +152,30 @@ static void native_set_dataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescr
jniThrowException(env, "java/lang/IllegalArgumentException", nullptr); jniThrowException(env, "java/lang/IllegalArgumentException", nullptr);
return; return;
} }
int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); int fd = getFileDescriptor(env, fileDescriptor);
if (offset < 0 || length < 0 || fd < 0) {
if (offset < 0) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "negative offset (%ld)", offset);
}
if (length < 0) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "negative length (%ld)", length);
}
if (fd < 0) { if (fd < 0) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "invalid file descriptor"); LOGE(LOG_TAG, "invalid file descriptor!");
}
jniThrowException(env, "java/lang/IllegalArgumentException", nullptr); jniThrowException(env, "java/lang/IllegalArgumentException", nullptr);
return; return;
} }
process_retriever_call(env, retriever->setDataSource(fd, offset, length), "java/lang/RuntimeException", "setDataSource failed"); process_retriever_call(env, retriever->setDataSource(fd, offset, length),
"java/lang/RuntimeException", "setDataSource failed");
} }
static void native_set_surface(JNIEnv *env, jclass thiz, jobject surface) RETRIEVER_FUNC(void, native_set_surface, jobject surface)
{ {
MediaRetriever* retriever = getRetriever(env, thiz); MediaRetriever* retriever = getRetriever(env, thiz);
if (retriever == nullptr) { if (retriever == nullptr) {
jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
return; return;
} }
theNativeWindow = ANativeWindow_fromSurface(env, surface); theNativeWindow = ANativeWindow_fromSurface(env, surface);
if (theNativeWindow != nullptr) { if (theNativeWindow != nullptr) {
retriever->setNativeWindow(theNativeWindow); retriever->setNativeWindow(theNativeWindow);
} }
} }
static jobject native_extract_metadata(JNIEnv *env, jobject thiz, jstring jkey) RETRIEVER_FUNC(jobject, native_extract_metadata, jstring jkey)
{ {
MediaRetriever* retriever = getRetriever(env, thiz); MediaRetriever* retriever = getRetriever(env, thiz);
if (retriever == nullptr) { if (retriever == nullptr) {
@ -210,7 +198,7 @@ static jobject native_extract_metadata(JNIEnv *env, jobject thiz, jstring jkey)
return NewStringUTF(env, value); return NewStringUTF(env, value);
} }
static jbyteArray native_get_frameAtTime(JNIEnv *env, jobject thiz, jlong timeUs, jint option) RETRIEVER_FUNC(jbyteArray, native_get_frameAtTime, jlong timeUs, jint option)
{ {
MediaRetriever* retriever = getRetriever(env, thiz); MediaRetriever* retriever = getRetriever(env, thiz);
if (retriever == nullptr) { if (retriever == nullptr) {
@ -227,7 +215,7 @@ static jbyteArray native_get_frameAtTime(JNIEnv *env, jobject thiz, jlong timeUs
uint8_t* data = packet.data; uint8_t* data = packet.data;
array = env->NewByteArray(size); array = env->NewByteArray(size);
if (!array) { if (!array) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "getFrameAtTime: OutOfMemoryError is thrown."); LOGE(LOG_TAG, "getFrameAtTime: OutOfMemoryError is thrown.");
} else { } else {
jbyte* bytes = env->GetByteArrayElements(array, nullptr); jbyte* bytes = env->GetByteArrayElements(array, nullptr);
if (bytes != nullptr) { if (bytes != nullptr) {
@ -242,8 +230,7 @@ static jbyteArray native_get_frameAtTime(JNIEnv *env, jobject thiz, jlong timeUs
return array; return array;
} }
static jbyteArray native_get_scaleFrameAtTime(JNIEnv *env, jobject thiz, jlong timeUs, jint option, RETRIEVER_FUNC(jbyteArray, native_get_scaleFrameAtTime, jlong timeUs, jint option, jint width, jint height)
jint width, jint height)
{ {
MediaRetriever* retriever = getRetriever(env, thiz); MediaRetriever* retriever = getRetriever(env, thiz);
if (retriever == nullptr) { if (retriever == nullptr) {
@ -260,7 +247,7 @@ static jbyteArray native_get_scaleFrameAtTime(JNIEnv *env, jobject thiz, jlong t
uint8_t* data = packet.data; uint8_t* data = packet.data;
array = env->NewByteArray(size); array = env->NewByteArray(size);
if (!array) { if (!array) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "getFrameAtTime: OutOfMemoryError is thrown."); LOGE(LOG_TAG, "getFrameAtTime: OutOfMemoryError is thrown.");
} else { } else {
jbyte* bytes = env->GetByteArrayElements(array, nullptr); jbyte* bytes = env->GetByteArrayElements(array, nullptr);
if (bytes != nullptr) { if (bytes != nullptr) {
@ -275,7 +262,7 @@ static jbyteArray native_get_scaleFrameAtTime(JNIEnv *env, jobject thiz, jlong t
return array; return array;
} }
static void native_release(JNIEnv *env, jobject thiz) RETRIEVER_FUNC(void, native_release)
{ {
MediaRetriever* retriever = getRetriever(env, thiz); MediaRetriever* retriever = getRetriever(env, thiz);
delete retriever; delete retriever;

Loading…
Cancel
Save