I'm trying to efficiently do color conversion from I420 to rgb to implement a video player in android.
It has been stated that glTexSubImage2D() and glTexImage2D() are too slow so I'm trying to use EGL Image extensions.
Basically I'm following this example to load everything.
And then the problem arise when I want to pass the decoded frame from ffmpeg to the GraphicBuffer.
This is the function I'm calling every time I get a decoded frame:
queueBuffer(frame->data, frame->linesize[0], frame->linesize[1]);
This is the relevant code:
struct OpenGLData{
EGLDisplay dpy;
EGLContext context;
EGLSurface surface;
EGLImageKHR img;
EGLNativeWindowType window;
GLuint yuvTex;
GLuint gProgram;
GLint gvPositionHandle;
GLint gYuvTexSamplerHandle;
};
void queueBuffer(uint8_t** source, int width, int height){
sp<GraphicBuffer> yuvTexBuffer = new GraphicBuffer(width, height, HAL_PIXEL_FORMAT_YV12, GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_OFTEN);
uint8_t* buf = NULL;
status_t err = yuvTexBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf));
if (err != 0) {
LOGE(2, "yuvTexBuffer->lock(...) failed: %d\n", err);
return;
}
copyI420Buffer(source, buf, width, height, yuvTexBuffer->getStride());
yuvTexBuffer->unlock();
EGLClientBuffer clientBuffer = (EGLClientBuffer)yuvTexBuffer->getNativeBuffer();
openGLData->img = eglCreateImageKHR(openGLData->dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer, 0);
checkEglError("eglCreateImageKHR");
glGenTextures(1, &openGLData->yuvTex);
checkGlError("glGenTextures");
glBindTexture(GL_TEXTURE_EXTERNAL_OES, openGLData->yuvTex);
checkGlError("glBindTexture");
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)openGLData->img);
checkGlError("glEGLImageTargetTexture2DOES");
}
I420 to YV12 function:
void copyI420Buffer(uint8_t** src, uint8_t* dst,int srcWidth, int srcHeight, int stride) {
int strideUV = (stride / 2 + 0xf) & ~0xf;
// Y
for (int i = srcHeight; i > 0; i--) {
memcpy(dst, src[0], srcWidth);
dst += stride;
src[0] += srcWidth;
}
// The src is I420, the dst is YV12.
// U
for (int i = srcHeight / 2; i > 0; i--) {
memcpy(dst, src[1], srcWidth / 2);
dst += strideUV;
src[1] += srcWidth / 2;
}
// V
for (int i = srcHeight / 2; i > 0; i--) {
memcpy(dst, src[2], srcWidth / 2);
dst += strideUV;
src[2] += srcWidth / 2;
}
}
And then I call renderFrame routine:
void renderFrame(){
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
checkGlError("glClearColor");
glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
checkGlError("glClear");
glUseProgram(openGLData->gProgram);
checkGlError("glUseProgram");
glVertexAttribPointer(openGLData->gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices);
checkGlError("glVertexAttribPointer");
glEnableVertexAttribArray(openGLData->gvPositionHandle);
checkGlError("glEnableVertexAttribArray");
glUniform1i(openGLData->gYuvTexSamplerHandle, 0);
checkGlError("glUniform1i");
glBindTexture(GL_TEXTURE_EXTERNAL_OES, openGLData->yuvTex);
checkGlError("glBindTexture");
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
checkGlError("glDrawArrays");
eglSwapBuffers(openGLData->dpy, openGLData->surface);
checkEglError("eglSwapBuffers");
}
But I only get EGL_BAD_CONTEXT after eglSwapBuffers and GL_INVALID_VALUE.
I would appreciate any helps. Thanks.