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.實現效果

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章