[Android] 在Jni中对SurfaceView渲染一张图片

来源:互联网 发布:js数组赋值 编辑:程序博客网 时间:2024/06/05 23:25

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

0 0
原创粉丝点击