NDK学习笔记(十四) 使用AVILib+window创建一个AVI视频播放器

1.window api

(1)从surface对象中检索原生window

从surface中检索对象window
ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface);

(2)获取原生window实例中的应用

void ANativeWindow_acquire(ANativeWindow* window);

(3)释放原生window引用

void ANativeWindow_release(ANativeWindow* window);

(4)检索原生window信息

宽度
int32_t ANativeWindow_getWidth(ANativeWindow* window);
宽度
int32_t ANativeWindow_getHeight(ANativeWindow* window);
像素格式
int32_t ANativeWindow_getFormat(ANativeWindow* window);

(5)设置原生window缓冲区的几何形状

int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window,
        int32_t width, int32_t height, int32_t format);

(6)访问原生window缓冲区

int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
        ARect* inOutDirtyBounds);

(7)释放原生window缓冲区

int32_t ANativeWindow_unlockAndPost(ANativeWindow* window);

2.主要代码

java

public class NativeWindowPlayerActivity extends AbstractPlayerActivity {

    private final AtomicBoolean isPlaying = new AtomicBoolean();

    private SurfaceHolder surfaceHolder;
    SurfaceView surfaceView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_native_window_player);

        surfaceView = findViewById(R.id.surface_view);

        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(callback);
    }

    @Override
    protected void onStart() {
        super.onStart();

        int w = getWidth(avi);
        int h = getHeight(avi);

        //设置surfaceView的带大小,防止自动填充
        ViewGroup.LayoutParams viewGroup = surfaceView.getLayoutParams();
        viewGroup.width = w;
        viewGroup.height = h;

        surfaceView.setX(50);
        surfaceView.setY(50);

    }

    private final SurfaceHolder.Callback callback = new SurfaceHolder.Callback2() {
        @Override
        public void surfaceRedrawNeeded(SurfaceHolder holder) {

        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {

            isPlaying.set(true);
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

            isPlaying.set(true);
            new Thread(renderer).start();
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {

            isPlaying.set(false);
        }
    };


    private Runnable renderer = new Runnable() {
        @Override
        public void run() {

            Surface surface = surfaceHolder.getSurface();

            init(avi, surface);

            long frameDelay = (long) (1000 / getFrameRate(avi));

            while (isPlaying.get()) {

                render(avi, surface);

                try {

                    Thread.sleep(frameDelay);
                } catch (InterruptedException e) {

                    break;
                }

            }
        }
    };


    /**
     * 初始化原生window
     *
     * @param avi
     * @param surface
     */
    private native static void init(long avi, Surface surface);

    /**
     * 渲染
     * @param avi
     * @param surface
     * @return
     */
    private native static boolean render(long avi, Surface surface);
}

原生代码

#include "cn_study_aviplayer_NativeWindowPlayerActivity.h"

extern "C" {
#include  "avilib/avilib.h"
}

#include <android/native_window.h>
#include <android/native_window_jni.h>
#include "Common.h"


extern "C"
JNIEXPORT void JNICALL
Java_cn_study_aviplayer_NativeWindowPlayerActivity_init(JNIEnv *env, jclass clazz, jlong avi,
                                                        jobject surface) {

    //从surface中获取原生window
    ANativeWindow *nativeWindow = ANativeWindow_fromSurface(env, surface);
    if (0 == nativeWindow) {

        ThrowException(env, "java/io/RuntimeException", "不能都获取window");
        goto exit;
    }
    //设置buffer大小为avi视频帧的分辨率
    //如果和window的物理大小不一致
    //buffer会被缩放来匹配这个大小
    if (0 > ANativeWindow_setBuffersGeometry(nativeWindow, AVI_video_width((avi_t *) avi),
                                             AVI_video_height((avi_t *) avi),
                                             WINDOW_FORMAT_RGB_565)) {

        ThrowException(env, "java/io/RuntimeException", "不能够设置buffers");
        nativeWindow = 0;
    }

    exit:
    return;

}


extern "C"
JNIEXPORT jboolean JNICALL
Java_cn_study_aviplayer_NativeWindowPlayerActivity_render(JNIEnv *env, jclass clazz, jlong avi,
                                                          jobject surface) {

    jboolean isFrameRead = JNI_FALSE;

    long frameSize = 0;
    int keyFrame = 0;

    ANativeWindow *nativeWindow = ANativeWindow_fromSurface(env, surface);
    if (0 == nativeWindow) {
        ThrowException(env, "java/io/RuntimeException", "不能够获取window");
        goto exit;
    }

    //锁定原生window并访问原始buffer
    ANativeWindow_Buffer windowBuffer;
    if (0 > ANativeWindow_lock(nativeWindow, &windowBuffer, 0)) {

        ThrowException(env, "java/io/RuntimeException", "不能锁住window");
        goto release;
    }
    //将avi帧的比特流读至原始缓冲区
    frameSize = AVI_read_frame((avi_t *) avi, (char *) windowBuffer.bits, &keyFrame);

    //是否读取成功
    if (0 < frameSize) {

        isFrameRead = JNI_TRUE;
    }

    //解锁并且输出缓冲区来显示
    if (0 > ANativeWindow_unlockAndPost(nativeWindow)) {

        ThrowException(env, "java/io/RuntimeException", "不能够解锁window");
        goto release;
    }

    release:
    ANativeWindow_release(nativeWindow);
    nativeWindow = 0;
    exit:
    return isFrameRead;

}

配置cmake
jnigraphics与android会冲突,所以加了前缀-l。

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
        cn_study_aviplayer_OpenGLPlayerActivity.cpp
        cn_study_aviplayer_NativeWindowPlayerActivity.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(
        GLESv2-lib
        -lGLESv2)

find_library(
        android-lib
        -landroid)


target_link_libraries( # Specifies the target library.
        native-lib
        # Links the target library to the log library
        # included in the NDK.

        -ljnigraphics#开启jnigraphics
        ${android-lib}#使用window
        ${log-lib}
        ${GLESv2-lib}
        avi-lib)

3.实现效果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值