Я пытаюсь закодировать фильм с помощью MediaCodec и Surfaces (режим пиксельного буфера работает, но производительность не достаточно хорошая).Однако каждый раз, когда я пытаюсь вызвать eglSwapBuffers()
, происходит сбой с EGL_BAD_SURFACE
, и поэтому dequeueOutputBuffer()
всегда возвращает -1 (INFO_TRY_AGAIN_LATER
)
. Я видел примеры на Bigflake и Grafika иУ меня есть другой рабочий проект, где все в порядке, но мне нужно, чтобы это работало в другой настройке, которая немного отличается.
В настоящее время у меня есть GLSurfaceView, который выполняет визуализацию экрана и поставляется с пользовательским EGLContextFactory / EGLConfigChooser.Это позволяет мне создавать общие контексты, которые будут использоваться для отдельной визуализации OpenGL в собственной библиотеке.Они создаются с использованием EGL10, но это не должно вызывать проблем, поскольку базовые контексты заботятся только о версии клиента, насколько я знаю.
Я убедился, что контекст доступен для записи, используя следующую конфигурацию:
private android.opengl.EGLConfig chooseConfig14(android.opengl.EGLDisplay display) {
// Configure EGL for recording and OpenGL ES 3.x
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, EGLExt.EGL_OPENGL_ES3_BIT_KHR,
EGLExt.EGL_RECORDABLE_ANDROID, 1,
EGL14.EGL_NONE
};
android.opengl.EGLConfig[] configs = new android.opengl.EGLConfig[1];
int[] numConfigs = new int[1];
if (!EGL14.eglChooseConfig(display, attribList, 0, configs, 0,
configs.length, numConfigs, 0)) {
return null;
}
return configs[0];
}
Теперь я попытался упростить сценарий, поэтому при запуске записи я инициализирую экземпляр MediaCodec в качестве кодировщика и вызываю createInputSurface()
в потоке GLSurfaceView.Получив поверхность, я превращаю ее в EGLSurface (EGL14) следующим образом:
EGLSurface createEGLSurface(Surface surface) {
if (surface == null) return null;
int[] surfaceAttribs = { EGL14.EGL_NONE };
android.opengl.EGLDisplay display = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
android.opengl.EGLConfig config = chooseConfig14(display);
EGLSurface eglSurface = EGL14.eglCreateWindowSurface(display, config, surface, surfaceAttribs, 0);
return eglSurface;
}
Когда с камеры приходит новый кадр, я отправляю его на экран и в другой класс, который выполняет запись,Этот класс просто отображает его на EGLSurface
, построенном из входной поверхности MediaCodec, следующим образом:
public void drawToSurface(EGLSurface targetSurface, int width, int height, long timestampNano, boolean ignoreOrientation) {
if (mTextures[0] == null) {
Log.w(TAG, "Attempting to draw without a source texture");
return;
}
EGLContext currentContext = EGL14.eglGetCurrentContext();
EGLDisplay currentDisplay = EGL14.eglGetCurrentDisplay();
EGL14.eglMakeCurrent(currentDisplay, targetSurface, targetSurface, currentContext);
int error = EGL14.eglGetError();
ShaderProgram program = getProgramForTextureType(mTextures[0].getTextureType());
program.draw(width, height, TextureRendererView.LayoutType.LINEAR_HORIZONTAL, 0, 1, mTextures[0]);
error = EGL14.eglGetError();
EGLExt.eglPresentationTimeANDROID(currentDisplay, targetSurface, timestampNano);
error = EGL14.eglGetError();
EGL14.eglSwapBuffers(currentDisplay, targetSurface);
error = EGL14.eglGetError();
Log.d(TAG, "drawToSurface");
}
По какой-то причине eglSwapBuffers()
завершается неудачно и сообщает EGL_BAD_SURFACE
, и я не нашел способадалее отладка.
Обновление Я пытался запросить текущую поверхность после вызова, который делает ее текущей, и она всегда возвращает поврежденную поверхность (заглянув внутрь, я вижу, что ручка 0
и он всегда терпит неудачу при запросе).Похоже, что eglMakeCurrent()
молча не удается установить привязку поверхности к контексту.
Более того, я определил, что эта проблема появляется на чипах Qualcomm (Adreno), а не на Kirin, поэтому он определенно связан с нативнымРеализация OpenGL (это как-то забавно, потому что я всегда замечал, что Adreno более терпим, когда дело доходит до «плохих» конфигураций OpenGL)