1

首先,感谢 fadden 提供的精彩示例。

我尝试遵循 这个ContinuousCapture.java 示例,并生成了以下程序。

1)

我试图通过获取其 ANativeWwindow 引用并使用 ANative lock 和 unlockpost 方法来获取 BufferQueue并填充数据,将图像显示到本机层的 TextureView 中。

IE:

ANativeWindow_lock(*window, &buffer, NULL)

ANativeWindow_unlockAndPost(*window);

2)

同时我想从这个 Surface 检索数据并将其传递给编码器。或者,将其显示到另一个表面。

作为第一步,我创建了下面的类,它将 EglCore 初始化到不同的线程中,并尝试在 EglContext 中配置用户给定的表面。到目前为止,一切都很好。但是,当我尝试通过 lock 和 unlockAndPost 方法将数据复制到缓冲区时,我收到以下错误。

 E/BufferQueueProducer: [unnamed-7679-0] connect(P): already connected (cur=1 req=2)
E/BufferQueueProducer: [unnamed-7679-0] connect(P): already connected (cur=1 req=2)
E/BufferQueueProducer: [unnamed-7679-0] connect(P): already connected (cur=1 req=2)

问题: 这是正确的方法吗?或者我忽略了什么?

package com.super.dump

import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.opengl.EGLSurface;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.util.SparseArray;
import android.view.Surface;

import java.io.File;
import java.io.IOException;



import android.graphics.SurfaceTexture;
import android.opengl.EGL14;
import android.opengl.EGLSurface;
import android.opengl.GLES20;
import android.os.Environment;
import android.util.Log;
import android.util.SparseArray;
import android.view.Surface;
import android.view.View;
import android.widget.TextView;

import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

 public class SuperDump {

    RenderThread rT;
    Surface userProvidedSurface;


    public SuperDump() {
        userProvidedSurface = null;
        rT = null;
    }


    public void init(Surface userSurface)
    {
        if ( userSurface != null) {
            userProvidedSurface = userSurface;
            rT = new RenderThread(userProvidedSurface);
            rT.start();
            rT.waitUntilRendererReady();
        }
    }


    private class RenderThread extends Thread {

        public String TAG = "RenderThread";
        RenderHandler mHandler;
        private Object mSyncForRenderAvailability = new Object();
        boolean mIsRendererReady = false;

        private EglCore mEglCore;
        private Surface mSurfaceUser;
        private WindowSurface mSurfaceWindowUser;


        public RenderThread() {

        }

        public RenderThread(Surface userSurface) {
            mSurfaceUser = userSurface;
        }



        @Override
        public void run() {
            Looper.prepare();
            mHandler = new RenderHandler(this);

            mEglCore = new EglCore(null, EglCore.FLAG_RECORDABLE);
            mSurfaceWindowUser = new WindowSurface(mEglCore, mSurfaceUser, false);

            synchronized (mSyncForRenderAvailability) {

                mIsRendererReady = true;
                mSyncForRenderAvailability.notifyAll();
            }

            Looper.loop();
            Log.d (TAG, "End of RenderThread..");
        }

        public RenderHandler getHandler() {
            return mHandler;
        }


        public void waitUntilRendererReady()
        {
            synchronized (mSyncForRenderAvailability) {
                while(!mIsRendererReady) {
                    try {
                        mSyncForRenderAvailability.wait();
                    } catch (InterruptedException e) {
                        Log.d (TAG,  "Wait interrupted..");
                    }
                }
            }
        }

}  // RenderThread





   private static class RenderHandler extends Handler {

       public String TAG = "RenderHandler";
       private static final int MSG_RENDER_QUIT = 1;

        private WeakReference<RenderThread> mWeakRenderThread;

        public RenderHandler(RenderThread rT)
        {
            mWeakRenderThread = new WeakReference<RenderThread>(rT);
        }

       public void stopMe() {
           sendMessage(obtainMessage(MSG_RENDER_QUIT));
       }

        @Override
       public void handleMessage(Message msg) {

           Log.d (TAG, "Inside handleMessage..");

            switch(msg.what) {
                case MSG_RENDER_QUIT:
                    Looper.getMainLooper().quit();  // detaching from thread.
            }
       }




   }  // RenderHandler Class.
}; //SuperDump class

请帮助我。

4

1 回答 1

0

同时我想从这个 Surface 检索数据并将其传递给编码器

您无法从 Surface 检索数据。表面是生产者-消费者对的生产者端。

您会收到“已连接”错误,因为您正尝试将第二个生产者附加到 Surface。

(如果你想挑选 nits,BufferQueue 将重复使用缓冲区而不清除它们,因此生产者通常可以看到一两帧的数据。但是由于生产者首先创建了这些帧,所以没有太大的价值把它们拉回来。而且不能保证 BufferQueue 不会给你一个空的缓冲区,或者不按顺序显示它们。)

好消息是,对于 SurfaceTexture,消费者处于进程中,并且数据可作为 GLES“外部”纹理访问。TextureView 类提供了一种方便的getBitmap()方法,可以将最近的帧呈现为位图,从而允许直接访问像素。(您可以通过将纹理渲染到屏幕外pbuffer并使用 读取像素来做类似的事情glReadPixels()。)

因此,要实现您想要的解决方案,最简单的方法就是使用 TextureView 调用来获取位图。

有关 Surfaces 的更多信息可以在图形架构文档中找到。

于 2015-11-20T17:19:10.277 回答