Проблема при передаче настроенной Egl поверхности на родную и пуш данных
Во-первых, спасибо Фаддену за ваши замечательные примеры.
Я попытался следовать этому примеру ContinuousCapture.java и создал следующую программу.
1)
Я пытаюсь отобразить изображение в TextureView на собственном слое, получив ссылку ANativeWwindow и используя методы ANative lock и unlockpost, чтобы получитьBufferQueue и заполнить данные.
То есть:
ANativeWindow_lock(*window, &buffer, NULL)
ANativeWindow_unlockAndPost(*window);
2)
В то же время я хочу получить данные с этой поверхности и передать их кодировщику. Или отобразить его на другой поверхности.
В качестве первого шага я создал приведенный ниже класс, который инициализирует 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
Пожалуйста, помогите мне.
1 ответ
В то же время я хочу получить данные с этой поверхности и передать их кодировщику
Вы не можете получить данные с поверхности. Поверхности являются стороной производителя пары производитель-потребитель.
Вы получаете "уже подключенные" ошибки, потому что вы пытаетесь подключить второго производителя к Surface.
(Если вы хотите выбрать nits, BufferQueue будет повторно использовать буферы, не очищая их, поэтому производитель часто может видеть данные из кадра или двух назад. Но, поскольку производитель создал эти кадры в первую очередь, в этом нет особой ценности. вытаскивая их обратно. И нет никакой гарантии, что BufferQueue не даст вам пустой буфер или не выведет их из строя.)
Хорошей новостью является то, что для SurfaceTexture потребитель находится в процессе, и данные доступны в виде "внешней" текстуры GLES. Класс TextureView предоставляет удобный getBitmap()
метод, который отображает самый последний кадр в растровое изображение, предоставляя прямой доступ к пикселям. (Вы можете сделать что-то подобное, отрисовав текстуру за кадром pbuffer
и чтение пикселей с glReadPixels()
.)
Таким образом, для реализации желаемого решения проще всего было бы просто использовать вызов TextureView для получения растрового изображения.
Более подробную информацию о Surfaces можно найти в документации по графической архитектуре.