void traceVdpVideoSurfaceGetBitsYCbCr(const char *impl_state, VdpVideoSurface surface, VdpYCbCrFormat destination_ycbcr_format, void *const *destination_data, uint32_t const *destination_pitches) { (void)destination_data; (void)destination_pitches; if (!enabled) return; fprintf(tlog, "%s%s VdpVideoSurfaceGetBitsYCbCr surface=%d, destination_ycbcr_format=%s\n", trace_header, impl_state, surface, reverse_ycbcr_format(destination_ycbcr_format)); }
void traceVdpVideoSurfacePutBitsYCbCr(const char *impl_state, VdpVideoSurface surface, VdpYCbCrFormat source_ycbcr_format, void const *const *source_data, uint32_t const *source_pitches) { (void)source_data; (void)source_pitches; if (!enabled) return; fprintf(tlog, "%s%s VdpVideoSurfacePutBitsYCbCr surface=%d, source_ycbcr_format=%s\n", trace_header, impl_state, surface, reverse_ycbcr_format(source_ycbcr_format)); }
void traceVdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities(const char *impl_state, VdpDevice device, VdpChromaType surface_chroma_type, VdpYCbCrFormat bits_ycbcr_format, VdpBool *is_supported) { (void)is_supported; if (!enabled) return; fprintf(tlog, "%s%s VdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities device=%d, " "surface_chroma_type=%s, bits_ycbcr_format=%s\n", trace_header, impl_state, device, reverse_chroma_type(surface_chroma_type), reverse_ycbcr_format(bits_ycbcr_format)); }
void traceVdpOutputSurfaceQueryPutBitsYCbCrCapabilities(const char *impl_state, VdpDevice device, VdpRGBAFormat surface_rgba_format, VdpYCbCrFormat bits_ycbcr_format, VdpBool *is_supported) { (void)is_supported; if (!enabled) return; fprintf(tlog, "%s%s VdpOutputSurfaceQueryPutBitsYCbCrCapabilities device=%d, " "surface_rgba_format=%s, bits_ycbcr_format=%s\n", trace_header, impl_state, device, reverse_rgba_format(surface_rgba_format), reverse_ycbcr_format(bits_ycbcr_format)); }
void traceVdpOutputSurfacePutBitsYCbCr(const char *impl_state, VdpOutputSurface surface, VdpYCbCrFormat source_ycbcr_format, void const *const *source_data, uint32_t const *source_pitches, VdpRect const *destination_rect, VdpCSCMatrix const *csc_matrix) { (void)source_data; (void)source_pitches; if (!enabled) return; fprintf(tlog, "%s%s VdpOutputSurfacePutBitsYCbCr surface=%d, source_ycbcr_format=%s, " "destination_rect=%s, csc_matrix=%p\n", trace_header, impl_state, surface, reverse_ycbcr_format(source_ycbcr_format), rect2string(destination_rect), csc_matrix); }
static VdpStatus vdpVideoSurfacePutBitsYCbCr_glsl(VdpVideoSurface surface, VdpYCbCrFormat source_ycbcr_format, void const *const *source_data, uint32_t const *source_pitches) { VdpStatus err_code; if (!source_data || !source_pitches) return VDP_STATUS_INVALID_POINTER; // TODO: implement VDP_YCBCR_FORMAT_UYVY // TODO: implement VDP_YCBCR_FORMAT_YUYV // TODO: implement VDP_YCBCR_FORMAT_Y8U8V8A8 // TODO: implement VDP_YCBCR_FORMAT_V8U8Y8A8 VdpVideoSurfaceData *dstSurfData = handle_acquire(surface, HANDLETYPE_VIDEO_SURFACE); if (NULL == dstSurfData) return VDP_STATUS_INVALID_HANDLE; VdpDeviceData *deviceData = dstSurfData->deviceData; switch (source_ycbcr_format) { case VDP_YCBCR_FORMAT_NV12: case VDP_YCBCR_FORMAT_YV12: /* do nothing */ break; case VDP_YCBCR_FORMAT_UYVY: case VDP_YCBCR_FORMAT_YUYV: case VDP_YCBCR_FORMAT_Y8U8V8A8: case VDP_YCBCR_FORMAT_V8U8Y8A8: default: traceError("error (%s): not implemented source YCbCr format '%s'\n", __func__, reverse_ycbcr_format(source_ycbcr_format)); err_code = VDP_STATUS_INVALID_Y_CB_CR_FORMAT; goto err; } glx_ctx_push_thread_local(deviceData); glBindFramebuffer(GL_FRAMEBUFFER, dstSurfData->fbo_id); GLuint tex_id[2]; glGenTextures(2, tex_id); glEnable(GL_TEXTURE_2D); switch (source_ycbcr_format) { case VDP_YCBCR_FORMAT_NV12: glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, tex_id[1]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // UV plane glPixelStorei(GL_UNPACK_ROW_LENGTH, source_pitches[1]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dstSurfData->width/2, dstSurfData->height/2, 0, GL_RG, GL_UNSIGNED_BYTE, source_data[1]); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex_id[0]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Y plane glPixelStorei(GL_UNPACK_ROW_LENGTH, source_pitches[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dstSurfData->width, dstSurfData->height, 0, GL_RED, GL_UNSIGNED_BYTE, source_data[0]); break; case VDP_YCBCR_FORMAT_YV12: glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, tex_id[1]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dstSurfData->width/2, dstSurfData->height, 0, GL_RED, GL_UNSIGNED_BYTE, NULL); // U plane glPixelStorei(GL_UNPACK_ROW_LENGTH, source_pitches[2]); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, dstSurfData->width/2, dstSurfData->height/2, GL_RED, GL_UNSIGNED_BYTE, source_data[2]); // V plane glPixelStorei(GL_UNPACK_ROW_LENGTH, source_pitches[1]); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, dstSurfData->height/2, dstSurfData->width/2, dstSurfData->height/2, GL_RED, GL_UNSIGNED_BYTE, source_data[1]); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex_id[0]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Y plane glPixelStorei(GL_UNPACK_ROW_LENGTH, source_pitches[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dstSurfData->width, dstSurfData->height, 0, GL_RED, GL_UNSIGNED_BYTE, source_data[0]); break; } glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, dstSurfData->width, 0, dstSurfData->height, -1.0f, 1.0f); glViewport(0, 0, dstSurfData->width, dstSurfData->height); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glDisable(GL_BLEND); switch (source_ycbcr_format) { case VDP_YCBCR_FORMAT_NV12: glUseProgram(deviceData->shaders[glsl_NV12_RGBA].program); glUniform1i(deviceData->shaders[glsl_NV12_RGBA].uniform.tex_0, 0); glUniform1i(deviceData->shaders[glsl_NV12_RGBA].uniform.tex_1, 1); break; case VDP_YCBCR_FORMAT_YV12: glUseProgram(deviceData->shaders[glsl_YV12_RGBA].program); glUniform1i(deviceData->shaders[glsl_YV12_RGBA].uniform.tex_0, 0); glUniform1i(deviceData->shaders[glsl_YV12_RGBA].uniform.tex_1, 1); break; } glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex2f(0, 0); glTexCoord2f(1, 0); glVertex2f(dstSurfData->width, 0); glTexCoord2f(1, 1); glVertex2f(dstSurfData->width, dstSurfData->height); glTexCoord2f(0, 1); glVertex2f(0, dstSurfData->height); glEnd(); glUseProgram(0); glFinish(); glBindFramebuffer(GL_FRAMEBUFFER, 0); glDeleteTextures(2, tex_id); GLenum gl_error = glGetError(); glx_ctx_pop(); if (GL_NO_ERROR != gl_error) { traceError("error (%s): gl error %d\n", __func__, gl_error); err_code = VDP_STATUS_ERROR; goto err; } err_code = VDP_STATUS_OK; err: handle_release(surface); return err_code; }
VdpStatus vdpVideoSurfaceGetBitsYCbCr(VdpVideoSurface surface, VdpYCbCrFormat destination_ycbcr_format, void *const *destination_data, uint32_t const *destination_pitches) { VdpStatus err_code; if (!destination_data || !destination_pitches) return VDP_STATUS_INVALID_POINTER; VdpVideoSurfaceData *srcSurfData = handle_acquire(surface, HANDLETYPE_VIDEO_SURFACE); if (NULL == srcSurfData) return VDP_STATUS_INVALID_HANDLE; VdpDeviceData *deviceData = srcSurfData->deviceData; VADisplay va_dpy = deviceData->va_dpy; if (deviceData->va_available) { VAImage q; vaDeriveImage(va_dpy, srcSurfData->va_surf, &q); if (VA_FOURCC('N', 'V', '1', '2') == q.format.fourcc && VDP_YCBCR_FORMAT_NV12 == destination_ycbcr_format) { uint8_t *img_data; vaMapBuffer(va_dpy, q.buf, (void **)&img_data); if (destination_pitches[0] == q.pitches[0] && destination_pitches[1] == q.pitches[1]) { const uint32_t sz = (uint32_t)q.width * (uint32_t)q.height; memcpy(destination_data[0], img_data + q.offsets[0], sz); memcpy(destination_data[1], img_data + q.offsets[1], sz / 2); } else { uint8_t *src = img_data + q.offsets[0]; uint8_t *dst = destination_data[0]; for (unsigned int y = 0; y < q.height; y ++) { // Y plane memcpy (dst, src, q.width); src += q.pitches[0]; dst += destination_pitches[0]; } src = img_data + q.offsets[1]; dst = destination_data[1]; for (unsigned int y = 0; y < q.height / 2; y ++) { // UV plane memcpy(dst, src, q.width); // q.width/2 samples of U and V each, hence q.width src += q.pitches[1]; dst += destination_pitches[1]; } } vaUnmapBuffer(va_dpy, q.buf); } else if (VA_FOURCC('N', 'V', '1', '2') == q.format.fourcc && VDP_YCBCR_FORMAT_YV12 == destination_ycbcr_format) { uint8_t *img_data; vaMapBuffer(va_dpy, q.buf, (void **)&img_data); // Y plane if (destination_pitches[0] == q.pitches[0]) { const uint32_t sz = (uint32_t)q.width * (uint32_t)q.height; memcpy(destination_data[0], img_data + q.offsets[0], sz); } else { uint8_t *src = img_data + q.offsets[0]; uint8_t *dst = destination_data[0]; for (unsigned int y = 0; y < q.height; y ++) { memcpy (dst, src, q.width); src += q.pitches[0]; dst += destination_pitches[0]; } } // unpack mixed UV to separate planes for (unsigned int y = 0; y < q.height/2; y ++) { uint8_t *src = img_data + q.offsets[1] + y * q.pitches[1]; uint8_t *dst_u = destination_data[1] + y * destination_pitches[1]; uint8_t *dst_v = destination_data[2] + y * destination_pitches[2]; for (unsigned int x = 0; x < q.width/2; x++) { *dst_v++ = *src++; *dst_u++ = *src++; } } vaUnmapBuffer(va_dpy, q.buf); } else { const char *c = (const char *)&q.format.fourcc; traceError("error (%s): not implemented conversion VA FOURCC %c%c%c%c -> %s\n", __func__, *c, *(c+1), *(c+2), *(c+3), reverse_ycbcr_format(destination_ycbcr_format)); vaDestroyImage(va_dpy, q.image_id); err_code = VDP_STATUS_INVALID_Y_CB_CR_FORMAT; goto quit; } vaDestroyImage(va_dpy, q.image_id); } else { // software fallback traceError("error (%s): not implemented software fallback\n", __func__); err_code = VDP_STATUS_ERROR; goto quit; } GLenum gl_error = glGetError(); if (GL_NO_ERROR != gl_error) { traceError("error (%s): gl error %d\n", __func__, gl_error); err_code = VDP_STATUS_ERROR; goto quit; } err_code = VDP_STATUS_OK; quit: handle_release(surface); return err_code; }