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)