ANativeWindow渲染RGB
在jni渲染图片有很多方式,比如OpenGL,这里介绍实现方式最简单的一种:直接对surface进行操作。
原理也很简单,我们直接将数据拷贝到ANativeWindow的缓存队列中,然后由系统进行处理现实到屏幕上。
- 首先创建surfaceView,只需要通过jni传入surface对象即可:
import android.content.Context;
import android.util.AttributeSet;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MyVideoView extends SurfaceView implements SurfaceHolder.Callback {
private OnSurfaceListener listener;
private SurfaceHolder mHolder;
public MyVideoView(Context context) {
super(context);
init();
}
public MyVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyVideoView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
mHolder = this.getHolder();
mHolder.addCallback(this);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
setSurface(holder.getSurface()); //初始化
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
setSurface(null); //通知jni层释放surface
}
@Override
public Surface getSurface() {
SurfaceHolder holder = getHolder();
if (holder != null) {
return holder.getSurface();
}
return null;
}
}
public static native void setSurface(Surface surface);
jni相关接口的实现这里不做讨论
- 接下来是在native中获取surface对象并进行初始化:
ANativeWindow *mANativeWindow = (ANativeWindow *)ANativeWindow_fromSurface(env, jsurface);
// 需要先设定图像的尺寸和格式
ANativeWindow_setBuffersGeometry(mANativeWindow, videoWidth, videoHeight, WINDOW_FORMAT_RGBA_8888);
mANativeWindow 既是surface在jni层的映射
- 开始进行渲染(data是传入的RGB图像数据):
ANativeWindow_Buffer nwBuffer;
if (0 != ANativeWindow_lock(mANativeWindow, &nwBuffer, NULL)) {
LOGE("ANativeWindow_lock() error");
return;
}
if (nwBuffer.width >= nwBuffer.stride) {
memcpy(nwBuffer.bits, data, len);
} else {
/*fixed花屏问题:
* 输出stride和width的日志发现,如果正常显示则stride==width, 通过注释可以看出应该是内存对齐问题导致的, 调整代码:
*/
int i;
for (i = 0; i < height; ++i) {
memcpy(nwBuffer.bits + nwBuffer.stride * i * RGB_SIZE, data + width * i * RGB_SIZE, width * RGB_SIZE);
}
}
if (0 != ANativeWindow_unlockAndPost(player->mANativeWindow)) {
LOGE("ANativeWindow_unlockAndPost error");
return;
}
需要注意的是 nwBuffer.stride >= nwBuffer.width。因为nwBuffer.stride 为 POT 即2的n次方
- 完成渲染后必须对surface进行释放:
ANativeWindow_release(mANativeWindow);
参考:
http://blog.csdn.net/lsingle/article/details/38174049?utm_source=tuicool&utm_medium=referral