NDK学习笔记(十二) 原生图形api,使用AVILib创建一个AVI视频播放器
16lz
2021-01-26
文章目录
- 1.练练手,使用AVILib创建一个AVI视频播放器
-
- (1)首先下载transcode,并配置avilib。
- (2)创建AbstractPlayerActivity并实现native方法
- (3)配置native-lib,开启jnigraphics,连接avi-lib
- (4)jni graphics api
- (5)使用bitmap渲染来更新avi player
- 2.android studio 配置javah
1.练练手,使用AVILib创建一个AVI视频播放器
(1)首先下载transcode,并配置avilib。
http://www.linuxfromscratch.org/blfs/view/svn/multimedia/transcode.html
将transcode中的avilib文件复制到项目中。
编辑platform.h文件
#ifdef HAVE_CONFIG_H#include "config.h"#endif
在avilib创建CMakeLists.txt
add_library( # Sets the name of the library. avi-lib # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). avilib.c platform_posix.c)
(2)创建AbstractPlayerActivity并实现native方法
提取共用代码抽象成一个类
public abstract class AbstractPlayerActivity extends Activity { public static final String EXTRA_FILE_NAME = "cn.study.aviplayer.EXTRA_FILE_NAME"; protected long avi = 0; @Override protected void onStart() { super.onStart(); try { avi = open(getFileName()); } catch (IOException e) { new AlertDialog.Builder(this) .setTitle("错误提示") .setMessage(e.getMessage()) .show(); } } @Override protected void onStop() { super.onStop(); if (0 != avi) { close(avi); avi = 0; } } protected String getFileName() { return getIntent().getExtras().getString(EXTRA_FILE_NAME); } /** * 打开指定的avi文件 * * @return */ protected native static long open(String fileName) throws IOException; /** * 获取视频宽度 * * @param avi * @return */ protected native static int getWidth(long avi); /** * 获取视频高度 * * @param avi * @return */ protected native static int getHeight(long avi); /** * 获取帧速 * * @param avi * @return */ protected native static double getFrameRate(long avi); /** * 基于给定的文件描述符关闭指定的avi文件 * * @param avi */ protected native static void close(long avi);}
使用javah来生成.h文件。
/* DO NOT EDIT THIS FILE - it is machine generated */#include /* Header for class cn_study_aviplayer_AbstractPlayerActivity */#ifndef _Included_cn_study_aviplayer_AbstractPlayerActivity#define _Included_cn_study_aviplayer_AbstractPlayerActivity#ifdef __cplusplusextern "C" { #endif/* * Class: cn_study_aviplayer_AbstractPlayerActivity * Method: open * Signature: (Ljava/lang/String;)J */JNIEXPORT jlong JNICALL Java_cn_study_aviplayer_AbstractPlayerActivity_open (JNIEnv *, jclass, jstring);/* * Class: cn_study_aviplayer_AbstractPlayerActivity * Method: getWidth * Signature: (J)I */JNIEXPORT jint JNICALL Java_cn_study_aviplayer_AbstractPlayerActivity_getWidth (JNIEnv *, jclass, jlong);/* * Class: cn_study_aviplayer_AbstractPlayerActivity * Method: getHeight * Signature: (J)I */JNIEXPORT jint JNICALL Java_cn_study_aviplayer_AbstractPlayerActivity_getHeight (JNIEnv *, jclass, jlong);/* * Class: cn_study_aviplayer_AbstractPlayerActivity * Method: getFrameRate * Signature: (J)D */JNIEXPORT jdouble JNICALL Java_cn_study_aviplayer_AbstractPlayerActivity_getFrameRate (JNIEnv *, jclass, jlong);/* * Class: cn_study_aviplayer_AbstractPlayerActivity * Method: close * Signature: (J)V */JNIEXPORT void JNICALL Java_cn_study_aviplayer_AbstractPlayerActivity_close (JNIEnv *, jclass, jlong);#ifdef __cplusplus}#endif#endif
在native-lib.cpp中导入avilib.h需要。
extern "C" { #include "avilib/avilib.h"}
native-lib.cpp
#include #include #include "cn_study_aviplayer_AbstractPlayerActivity.h"#include "Common.h"#include extern "C" { #include "avilib/avilib.h"}extern "C" JNIEXPORT jstring JNICALLJava_cn_study_aviplayer_MainActivity_stringFromJNI( JNIEnv *env, jobject /* this */) { std::string hello = "Hello from C++"; return env->NewStringUTF(hello.c_str());}extern "C"JNIEXPORT jlong JNICALLJava_cn_study_aviplayer_AbstractPlayerActivity_open(JNIEnv *env, jclass clazz, jstring file_name) { avi_t *avi = 0; //获取文件名字并转换成字符串变量 const char *cFileName = env->GetStringUTFChars(file_name, 0); if (0 == cFileName) { goto exit; } avi = AVI_open_input_file(cFileName, 1); env->ReleaseStringUTFChars(file_name, cFileName); if (0 == avi) { ThrowException(env, "java/io/IOException", AVI_strerror()); } exit: return (jlong) avi;}extern "C"JNIEXPORT jint JNICALLJava_cn_study_aviplayer_AbstractPlayerActivity_getWidth(JNIEnv *env, jclass clazz, jlong avi) { return AVI_video_width((avi_t *) avi);}extern "C"JNIEXPORT jint JNICALLJava_cn_study_aviplayer_AbstractPlayerActivity_getHeight(JNIEnv *env, jclass clazz, jlong avi) { return AVI_video_height((avi_t *) avi);}extern "C"JNIEXPORT jdouble JNICALLJava_cn_study_aviplayer_AbstractPlayerActivity_getFrameRate(JNIEnv *env, jclass clazz, jlong avi) { return AVI_frame_rate((avi_t *) avi);}extern "C"JNIEXPORT void JNICALLJava_cn_study_aviplayer_AbstractPlayerActivity_close(JNIEnv *env, jclass clazz, jlong avi) { AVI_close((avi_t *) avi);}
(3)配置native-lib,开启jnigraphics,连接avi-lib
cmake_minimum_required(VERSION 3.4.1)add_library( # Sets the name of the library. native-lib # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). native-lib.cpp Common.cpp cn_study_aviplayer_BitmapPlayerActivity.cpp)#添加子目录add_subdirectory(avilib)find_library( # Sets the name of the path variable. log-lib # Specifies the name of the NDK library that # you want CMake to locate. log)find_library( # Sets the name of the path variable. jnigraphics-lib jnigraphics)target_link_libraries( # Specifies the target library. native-lib # Links the target library to the log library # included in the NDK. ${ jnigraphics-lib}#开启jnigraphics ${ log-lib} avi-lib)
(4)jni graphics api
检索bitmap对象信息,如大小、像素格式。成功返回0,失败返回一个负数。int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap,AndroidBitmapInfo* info);
访问原生像素缓存,锁定像素缓存以确保像素的内存不会移动。成功返回0,失败返回负数。int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr);
释放原生像素缓存成功返回0,失败返回负数int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap);
(5)使用bitmap渲染来更新avi player
public class BitmapPlayerActivity extends AbstractPlayerActivity { private final AtomicBoolean isPlaying = new AtomicBoolean(); private SurfaceHolder surfaceHolder; private SurfaceView surfaceView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_bitmap_player); surfaceView = findViewById(R.id.surface_view); surfaceHolder = surfaceView.getHolder(); surfaceHolder.addCallback(shCallback); } private final SurfaceHolder.Callback shCallback = new SurfaceHolder.Callback2() { @Override public void surfaceRedrawNeeded(SurfaceHolder holder) { } @Override public void surfaceCreated(SurfaceHolder holder) { isPlaying.set(true); new Thread(renderer).start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { isPlaying.set(false); } }; private final Runnable renderer = new Runnable() { @Override public void run() { Paint paint = new Paint(); paint.setAntiAlias(true); paint.setColor(Color.BLACK); paint.setStyle(Paint.Style.FILL); int width = getWidth(avi); int height = getHeight(avi); Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); float sx = 2.0f; float sy = 2.0f; Matrix matrix = new Matrix(); matrix.postScale(sx, sy); int vWidth = (int) (width * sx); int vHeight = (int) (height * sy); int x = (1080 - vWidth) / 2; int y = (1920 - vHeight) / 2; matrix.postTranslate(x, y); //延迟 long frameDelay = (long) (1000 / getFrameRate(avi)); while (isPlaying.get()) { render(avi, bitmap); Canvas canvas = surfaceHolder.lockCanvas(); canvas.drawBitmap(bitmap, matrix, null); surfaceHolder.unlockCanvasAndPost(canvas); //等待下一针 try { Thread.sleep(frameDelay); } catch (InterruptedException e) { break; } } } }; /** * 从avi文件描述符输出到指定bitmap来渲染帧 * * @param avi * @param bitmap * @return */ private native static boolean render(long avi, Bitmap bitmap);}
cn_study_aviplayer_BitmapPlayerActivity.cpp
#include "Common.h"#include "cn_study_aviplayer_BitmapPlayerActivity.h"extern "C" { #include "avilib/avilib.h"}#include extern "C"JNIEXPORT jboolean JNICALLJava_cn_study_aviplayer_BitmapPlayerActivity_render(JNIEnv *env, jclass clazz, jlong avi, jobject bitmap) { jboolean isFrameRead = JNI_FALSE; char *frameBuffer = 0; long frameSize = 0; int keyFrame = 0; if (0 > AndroidBitmap_lockPixels(env, bitmap, (void **) &frameBuffer)) { ThrowException(env, "java/io/IOException", "不能够锁定像素"); goto exit; } //将avi帧byte读取到bitmap中 frameSize = AVI_read_frame((avi_t *) avi, frameBuffer, &keyFrame); //解锁 if (0 > AndroidBitmap_unlockPixels(env, bitmap)) { ThrowException(env, "java/io/IOException", "不能够解锁像素"); goto exit; } //是否读取成功 if (0 < frameSize) { isFrameRead = JNI_TRUE; } exit: return isFrameRead;}
想使用这个avi播放器,视频文件格式必须是avi格式,希望视频负载是通过RGB565颜色空间的未压缩原始帧来提供的。
将视频放到指定目录,运行效果如下:
详细代码和视频文件
https://gitee.com/xd_box/AviPlayer
2.android studio 配置javah
file>Setting>Tools>External Tools 点击+号。
program:$JDKPath$\bin\javah.exearguments:-classpath . -jni -d $ModuleFileDir$\src\main\cpp $FileClass$working directory:$ModuleFileDir$\src\main\java
更多相关文章
- Android(安卓)Monkey 脚本编写与检查内存泄露
- Android需要提升权限的操作方法
- adnroid 学习笔记(一)
- 永久破解Tattoo root权限
- android sdk 让SDK Manager来自动安装上面下载的文件
- Android(安卓)极光推送
- eclipse 开发 jni
- Project has no default.properties file! Edit the project pro
- Android(安卓)Studio升级提示 Connection failed. Please check