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)