Измените пример ExtractMpegFramesTest для отображения декодированного вывода на экране

Я пытаюсь изменить ExtractMpegFramesTest, чтобы сделать рендеринг на экране и по-прежнему использовать glReadPixels извлечь кадры.

Я скопировал соответствующий код для извлечения кадров из ExtractMpegFramesTest (классы CodecOutputSurface и STextureRender), и извлечение кадров работает, как и ожидалось, при отрисовке за пределами экрана.

у меня есть TextureView с SurfaceTextureListener и когда я получу onSurfaceTextureAvailable Я получаю SurfaceTexture и начать процесс декодирования. Я передаю это SurfaceTexture в CodecOutputSurface но это не работает

Я не уверен, что это актуально, но onSurfaceTextureAvailable и SurfaceTexture принимаются в основном потоке, и все декодирование (включая вызов конструктора CodecOutputSurface) выполняется в другом потоке.

Я пытался работать с предложениями здесь и здесь, но я не могу заставить его работать.

Я вижу это в журналах:

E/BufferQueueProducer: [SurfaceTexture-0-11068-20] connect(P): already connected (cur=1 req=3)
I/MediaCodec: native window already connected. Assuming no change of surface
E/MediaCodec: configure failed with err 0xffffffea, resetting...

Я сделал следующие изменения в методе eglSetup ExtractMpegFramesTest:

private void eglSetup() {
    mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
    if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) {
        throw new RuntimeException("unable to get EGL14 display");
    }
    int[] version = new int[2];
    if (!EGL14.eglInitialize(mEGLDisplay, version, 0, version, 1)) {
        mEGLDisplay = null;
        throw new RuntimeException("unable to initialize EGL14");
    }

    int[] attribList = {
                    EGL14.EGL_RED_SIZE, 8,
                    EGL14.EGL_GREEN_SIZE, 8,
                    EGL14.EGL_BLUE_SIZE, 8,
                    EGL14.EGL_ALPHA_SIZE, 8,
                    EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
                    EGL14.EGL_SURFACE_TYPE, EGL14.EGL_WINDOW_BIT, // tell it to use a window
                    EGL14.EGL_NONE
    };
    EGLConfig[] configs = new EGLConfig[1];
    int[] numConfigs = new int[1];
    if (!EGL14.eglChooseConfig(mEGLDisplay, attribList, 0, configs, 0, configs.length,
                    numConfigs, 0)) {
        throw new RuntimeException("unable to find RGB888+recordable ES2 EGL config");
    }

    // Configure context for OpenGL ES 2.0.
    int[] attrib_list = {
                    EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
                    EGL14.EGL_NONE
    };

    mEGLContext = EGL14.eglCreateContext(mEGLDisplay, configs[0], EGL14.EGL_NO_CONTEXT,
                    attrib_list, 0);
    checkEglError("eglCreateContext");
    if (mEGLContext == null) {
        throw new RuntimeException("null context");
    }

    int[] surfaceAttribs = {
                    EGL14.EGL_RENDER_BUFFER, EGL14.EGL_SINGLE_BUFFER,
                    EGL14.EGL_NONE
    };

    mSurfaceTexture.setOnFrameAvailableListener(this);

    mSurface = new Surface(mSurfaceTexture);


    mPixelBuf = ByteBuffer.allocateDirect(mWidth * mHeight * 4);
    mPixelBuf.order(ByteOrder.LITTLE_ENDIAN);

    mEGLSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, configs[0], mSurface,
                    surfaceAttribs, 0); // create window surface instead of eglCreatePbufferSurface
    checkEglError("eglCreateWindowSurface");
    if (mEGLSurface == null) {
        throw new RuntimeException("surface was null");
    }
}

И метод установки ExtractMpegFramesTest:

private void setup() {
    mTextureRender = new STextureRender();
    mTextureRender.surfaceCreated();

    if (VERBOSE) Log.d(TAG, "textureID=" + mTextureRender.getTextureId());
}

Спасибо

1 ответ

Решение

Если я правильно понимаю, что вы пытаетесь сделать, вы захотите декодировать каждый кадр в SurfaceTexture, которая дает вам GLES "внешнюю" текстуру с данными в ней. Затем вы можете сделать это в TextureView, вызывая glReadPixels() как раз перед eglSwapBuffers(),

Вы не можете прочитать данные обратно после того, как они были отправлены на экранную поверхность, так как потребитель данных живет в другом процессе. Эффективный путь видео просто передает "внешнюю" текстуру на поверхность, но здесь это не сработает. В идеале вы должны клонировать ссылку на внешнюю текстуру, перенаправив одну копию на поверхность дисплея и используя другую для рендеринга в внеэкранный буфер, из которого вы можете извлекать пиксели. (Camera2 API может делать трюки с несколькими выходами, как это, но я не знаю, выставлено ли оно в MediaCodec. Хотя я давно не смотрел.)

Другие вопросы по тегам