From 6b2904ea826dd77ab150fe5c93f1c407f04fa982 Mon Sep 17 00:00:00 2001 From: havlenapetr Date: Thu, 15 Jul 2010 07:25:30 +0200 Subject: [PATCH] add AVCodecContext support --- jni/ffmpeg/Android.mk | 1 + .../com_media_ffmpeg_FFMpegAVCodecContext.cpp | 97 +++++++++++++++++++ ...dia_ffmpeg_android_FFMpegPlayerAndroid.cpp | 15 ++- jni/ffmpeg/android/methods.h | 1 + jni/ffmpeg/android/onLoad.cpp | 6 ++ .../media/ffmpeg/FFMpegAVCodecContext.java | 40 +++++++- .../ffmpeg/android/FFMpegPlayerAndroid.java | 11 ++- 7 files changed, 156 insertions(+), 15 deletions(-) create mode 100644 jni/ffmpeg/android/com_media_ffmpeg_FFMpegAVCodecContext.cpp diff --git a/jni/ffmpeg/Android.mk b/jni/ffmpeg/Android.mk index a77a67b..f754a9f 100755 --- a/jni/ffmpeg/Android.mk +++ b/jni/ffmpeg/Android.mk @@ -13,6 +13,7 @@ LOCAL_SRC_FILES := \ android/com_media_ffmpeg_FFMpegAVInputFormat.c \ android/com_media_ffmpeg_FFMpegAVRational.c \ android/com_media_ffmpeg_FFMpegAVFormatContext.c \ + android/com_media_ffmpeg_FFMpegAVCodecContext.cpp \ android/com_media_ffmpeg_FFMpeg.c \ android/com_media_ffmpeg_FFMpegUtils.cpp \ cmdutils.c diff --git a/jni/ffmpeg/android/com_media_ffmpeg_FFMpegAVCodecContext.cpp b/jni/ffmpeg/android/com_media_ffmpeg_FFMpegAVCodecContext.cpp new file mode 100644 index 0000000..188affa --- /dev/null +++ b/jni/ffmpeg/android/com_media_ffmpeg_FFMpegAVCodecContext.cpp @@ -0,0 +1,97 @@ +#define TAG "android_media_FFMpegAVCodecContext" + +#include +#include "jniUtils.h" +#include "methods.h" + +struct fields_t +{ + jmethodID constructor; +}; +static struct fields_t fields; + +jclass AVCodecContext_getClass(JNIEnv *env) { + return env->FindClass("com/media/ffmpeg/FFMpegAVCodecContext"); +} + +const char *AVCodecContext_getClassSignature() { + return "Lcom/media/ffmpeg/FFMpegAVCodecContext;"; +} + +jobject AVCodecContext_create(JNIEnv *env, AVCodecContext *codecContext) { + jclass clazz = AVCodecContext_getClass(env); + jobject result = env->NewObject(clazz, fields.constructor); + + //env->SetIntField(result, + // env->GetFieldID(clazz, "mPointer", "I"), + // (jint)frame); + env->SetIntField(result, + env->GetFieldID(clazz, "mBitRate", "I"), + codecContext->bit_rate); + env->SetIntField(result, + env->GetFieldID(clazz, "mBitRateTolerance", "I"), + codecContext->bit_rate_tolerance); + env->SetIntField(result, + env->GetFieldID(clazz, "mFlags", "I"), + codecContext->flags); + env->SetIntField(result, + env->GetFieldID(clazz, "mSubId", "I"), + codecContext->sub_id); + env->SetIntField(result, + env->GetFieldID(clazz, "mMeMethod", "I"), + codecContext->me_method); + env->SetIntField(result, + env->GetFieldID(clazz, "mExtradataSize", "I"), + codecContext->extradata_size); + env->SetIntField(result, + env->GetFieldID(clazz, "mWidth", "I"), + codecContext->width); + env->SetIntField(result, + env->GetFieldID(clazz, "mHeight", "I"), + codecContext->height); + env->SetIntField(result, + env->GetFieldID(clazz, "mGopSize", "I"), + codecContext->gop_size); + env->SetIntField(result, + env->GetFieldID(clazz, "mRateEmu", "I"), + codecContext->rate_emu); + env->SetIntField(result, + env->GetFieldID(clazz, "mSampleRate", "I"), + codecContext->sample_rate); + env->SetIntField(result, + env->GetFieldID(clazz, "mChannels", "I"), + codecContext->channels); + env->SetIntField(result, + env->GetFieldID(clazz, "mFrameSize", "I"), + codecContext->frame_size); + env->SetIntField(result, + env->GetFieldID(clazz, "mFrameNumber", "I"), + codecContext->frame_number); + + return result; +} + +static void AVCodecContext_release(JNIEnv *env, jobject thiz) { + //AVFormatContext *fileContext = (AVFormatContext *) pointer; + //__android_log_print(ANDROID_LOG_INFO, TAG, "releasing FFMpegAVCodecContext"), + //free(fileContext); +} + +/* + * JNI registration. + */ +static JNINativeMethod methods[] = { + { "release", "()V", (void*) AVCodecContext_release } +}; + +int register_android_media_FFMpegAVCodecContext(JNIEnv *env) { + jclass clazz = AVCodecContext_getClass(env); + fields.constructor = env->GetMethodID(clazz, "", "()V"); + if (fields.constructor == NULL) { + jniThrowException(env, + "java/lang/RuntimeException", + "can't load constructor"); + } + + return jniRegisterNativeMethods(env, "com/media/ffmpeg/FFMpegAVCodecContext", methods, sizeof(methods) / sizeof(methods[0])); +} diff --git a/jni/ffmpeg/android/com_media_ffmpeg_android_FFMpegPlayerAndroid.cpp b/jni/ffmpeg/android/com_media_ffmpeg_android_FFMpegPlayerAndroid.cpp index fdcceb4..c34f752 100755 --- a/jni/ffmpeg/android/com_media_ffmpeg_android_FFMpegPlayerAndroid.cpp +++ b/jni/ffmpeg/android/com_media_ffmpeg_android_FFMpegPlayerAndroid.cpp @@ -46,7 +46,7 @@ const char *FFMpegPlayerAndroid_getSignature() { return "Lcom/media/ffmpeg/android/FFMpegPlayerAndroid;"; } -static jintArray FFMpegPlayerAndroid_init(JNIEnv *env, jobject obj, jobject pAVFormatContext) { +static jobject FFMpegPlayerAndroid_init(JNIEnv *env, jobject obj, jobject pAVFormatContext) { ffmpeg_fields.pFormatCtx = (AVFormatContext *) env->GetIntField(pAVFormatContext, fields.avformatcontext); // Find the first video stream @@ -94,15 +94,12 @@ static jintArray FFMpegPlayerAndroid_init(JNIEnv *env, jobject obj, jobject pAVF // Allocate video frame ffmpeg_fields.pFrame = avcodec_alloc_frame(); - int size[2]; - size[0] = ffmpeg_fields.pCodecCtx->width; - size[1] = ffmpeg_fields.pCodecCtx->height; - ffmpeg_fields.img_convert_ctx = sws_getContext(size[0], size[1], ffmpeg_fields.pCodecCtx->pix_fmt, size[0], size[1], + int w = ffmpeg_fields.pCodecCtx->width; + int h = ffmpeg_fields.pCodecCtx->height; + ffmpeg_fields.img_convert_ctx = sws_getContext(w, h, ffmpeg_fields.pCodecCtx->pix_fmt, w, h, PIX_FMT_RGB565, SWS_POINT, NULL, NULL, NULL); - jintArray arr = env->NewIntArray(2); - env->SetIntArrayRegion(arr, 0, 2, (jint *) size); - return arr; + return AVCodecContext_create(env, ffmpeg_fields.pCodecCtx); } static AVFrame *FFMpegPlayerAndroid_createFrame(JNIEnv *env, jobject bitmap) { @@ -243,7 +240,7 @@ static void FFMpegPlayerAndroid_release(JNIEnv *env, jobject obj) { * JNI registration. */ static JNINativeMethod methods[] = { - { "nativeInit", "(Lcom/media/ffmpeg/FFMpegAVFormatContext;)[I", (void*) FFMpegPlayerAndroid_init}, + { "nativeInit", "(Lcom/media/ffmpeg/FFMpegAVFormatContext;)Lcom/media/ffmpeg/FFMpegAVCodecContext;", (void*) FFMpegPlayerAndroid_init}, { "nativeSetInputFile", "(Ljava/lang/String;)Lcom/media/ffmpeg/FFMpegAVFormatContext;", (void*) FFMpegPlayerAndroid_setInputFile }, { "nativePlay", "(Landroid/graphics/Bitmap;)V", (void*) FFMpegPlayerAndroid_play }, { "nativeStop", "()V", (void*) FFMpegPlayerAndroid_stop }, diff --git a/jni/ffmpeg/android/methods.h b/jni/ffmpeg/android/methods.h index 4ae9a6a..5f9b34b 100644 --- a/jni/ffmpeg/android/methods.h +++ b/jni/ffmpeg/android/methods.h @@ -13,6 +13,7 @@ extern "C" jobject AVFormatContext_create(JNIEnv *env, AVFormatContext *fileContext); jobject *AVRational_create(JNIEnv *env, AVRational *rational); jobject *AVInputFormat_create(JNIEnv *env, AVInputFormat *format); +jobject AVCodecContext_create(JNIEnv *env, AVCodecContext *codecContext); jclass AVFormatContext_getClass(JNIEnv *env); const char *AVInputFormat_getClassSignature(); diff --git a/jni/ffmpeg/android/onLoad.cpp b/jni/ffmpeg/android/onLoad.cpp index 69cb5fc..960b8e4 100644 --- a/jni/ffmpeg/android/onLoad.cpp +++ b/jni/ffmpeg/android/onLoad.cpp @@ -13,6 +13,7 @@ extern int register_android_media_FFMpegAVInputFormat(JNIEnv *env); } +extern int register_android_media_FFMpegAVCodecContext(JNIEnv *env); extern int register_android_media_FFMpegUtils(JNIEnv *env); extern int register_android_media_FFMpegAVFrame(JNIEnv *env); @@ -102,6 +103,11 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) { goto end; } + if(register_android_media_FFMpegAVCodecContext(env) != JNI_OK) { + __android_log_print(ANDROID_LOG_ERROR, TAG, "can't load android_media_FFMpegAVCodecContext"); + goto end; + } + if(register_android_media_FFMpegAVRational(env) != JNI_OK) { __android_log_print(ANDROID_LOG_ERROR, TAG, "can't load android_media_FFMpegAVRational"); goto end; diff --git a/src/com/media/ffmpeg/FFMpegAVCodecContext.java b/src/com/media/ffmpeg/FFMpegAVCodecContext.java index 21a00b0..6e6921b 100644 --- a/src/com/media/ffmpeg/FFMpegAVCodecContext.java +++ b/src/com/media/ffmpeg/FFMpegAVCodecContext.java @@ -2,7 +2,7 @@ public class FFMpegAVCodecContext { - protected FFMpegAVCodecContext mPointer; + private long mPointer; private FFMpegAVClass mAVClass; private int mBitRate; private int mBitRateTolerance; @@ -12,5 +12,43 @@ public class FFMpegAVCodecContext { private int mMeMethod; // Motion estimation algorithm used for video coding. private short mExtraData; // some codecs need / can use extradata like Huffman tables. private int mExtradataSize; + + // This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented. + private FFMpegAVRational mTimeBase; + + // picture width / height. + private int mWidth; + private int mHeight; + + // the number of pictures in a group of pictures, or 0 for intra_only + // encoding: Set by user. + private int mGopSize; + + // Frame rate emulation. + private int mRateEmu; + + // samples per second + private int mSampleRate; + + // number of audio channels + private int mChannels; + + // Samples per packet, initialized when calling 'init'. + private int mFrameSize; + + // audio or video frame number + private int mFrameNumber; + + + + public int getWidth() { + return mWidth; + } + + public int getHeight() { + return mHeight; + } + + protected native void release(); } diff --git a/src/com/media/ffmpeg/android/FFMpegPlayerAndroid.java b/src/com/media/ffmpeg/android/FFMpegPlayerAndroid.java index 28b97c5..4bfec4b 100644 --- a/src/com/media/ffmpeg/android/FFMpegPlayerAndroid.java +++ b/src/com/media/ffmpeg/android/FFMpegPlayerAndroid.java @@ -2,6 +2,7 @@ import java.io.IOException; +import com.media.ffmpeg.FFMpegAVCodecContext; import com.media.ffmpeg.FFMpegAVFormatContext; import com.media.ffmpeg.IFFMpegPlayer; @@ -71,7 +72,7 @@ private void attachMediaController() { (View)this.getParent() : this; mMediaController.setMediaPlayer(mMediaPlayerControl); mMediaController.setAnchorView(anchorView); - mMediaController.setEnabled(true); + mMediaController.setEnabled(false); } public void setListener(IFFMpegPlayer listener) { @@ -80,9 +81,9 @@ public void setListener(IFFMpegPlayer listener) { private void openVideo() { try { - int[] size = nativeInit(mInputVideo); - mVideoWidth = size[0]; - mVideoHeight = size[1]; + FFMpegAVCodecContext context = nativeInit(mInputVideo); + mVideoWidth = context.getWidth(); + mVideoHeight = context.getHeight(); Log.d(TAG, "Video size: " + mVideoWidth + " x " + mVideoHeight); } catch (IOException e) { if(mListener != null) { @@ -323,7 +324,7 @@ public int getBufferPercentage() { }; private native FFMpegAVFormatContext nativeSetInputFile(String filePath) throws IOException; - private native int[] nativeInit(FFMpegAVFormatContext AVFormatContext) throws IOException; + private native FFMpegAVCodecContext nativeInit(FFMpegAVFormatContext AVFormatContext) throws IOException; private native void nativePlay(Bitmap bitmap)throws IOException; private native void nativeStop(); private native void nativeSetSurface(Surface surface);