testffmpeg: added support for EGL OES frame formats

This commit is contained in:
Sam Lantinga 2024-03-12 16:12:08 -07:00
parent d79f865251
commit 41b7036f37
1 changed files with 211 additions and 3 deletions

View File

@ -46,6 +46,21 @@
#endif
#endif
#define DRM_FORMAT_MOD_VENDOR_NONE 0
#define DRM_FORMAT_RESERVED ((1ULL << 56) - 1)
#define fourcc_mod_get_vendor(modifier) \
(((modifier) >> 56) & 0xff)
#define fourcc_mod_is_vendor(modifier, vendor) \
(fourcc_mod_get_vendor(modifier) == DRM_FORMAT_MOD_VENDOR_## vendor)
#define fourcc_mod_code(vendor, val) \
((((__u64)DRM_FORMAT_MOD_VENDOR_## vendor) << 56) | ((val) & 0x00ffffffffffffffULL))
#define DRM_FORMAT_MOD_INVALID fourcc_mod_code(NONE, DRM_FORMAT_RESERVED)
#define DRM_FORMAT_MOD_LINEAR fourcc_mod_code(NONE, 0)
#ifdef SDL_PLATFORM_APPLE
#include <CoreVideo/CoreVideo.h>
#endif
@ -635,6 +650,189 @@ static SDL_bool GetTextureForMemoryFrame(AVFrame *frame, SDL_Texture **texture)
return SDL_TRUE;
}
#ifdef HAVE_EGL
static SDL_bool GetOESTextureForDRMFrame(AVFrame *frame, SDL_Texture **texture)
{
AVHWFramesContext *frames = (AVHWFramesContext *)(frame->hw_frames_ctx->data);
const AVDRMFrameDescriptor *desc = (const AVDRMFrameDescriptor *)frame->data[0];
int i, j, k, image_index;
EGLDisplay display = eglGetCurrentDisplay();
SDL_PropertiesID props;
GLuint textureID;
EGLAttrib attr[64];
SDL_Colorspace colorspace;
if (*texture) {
/* Free the previous texture now that we're about to render a new one */
SDL_DestroyTexture(*texture);
}
props = CreateVideoTextureProperties(frame, SDL_PIXELFORMAT_EXTERNAL_OES, SDL_TEXTUREACCESS_STATIC);
*texture = SDL_CreateTextureWithProperties(renderer, props);
SDL_DestroyProperties(props);
if (!*texture) {
return SDL_FALSE;
}
SDL_SetTextureBlendMode(*texture, SDL_BLENDMODE_NONE);
SDL_SetTextureScaleMode(*texture, SDL_SCALEMODE_LINEAR);
props = SDL_GetTextureProperties(*texture);
textureID = (GLuint)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_NUMBER, 0);
if (!textureID) {
SDL_SetError("Couldn't get OpenGL texture");
return SDL_FALSE;
}
colorspace = (SDL_Colorspace)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_COLORSPACE_NUMBER, SDL_COLORSPACE_UNKNOWN);
/* import the frame into OpenGL */
k = 0;
attr[k++] = EGL_LINUX_DRM_FOURCC_EXT;
attr[k++] = desc->layers[0].format;
attr[k++] = EGL_WIDTH;
attr[k++] = frames->width;
attr[k++] = EGL_HEIGHT;
attr[k++] = frames->height;
image_index = 0;
for (i = 0; i < desc->nb_layers; ++i) {
const AVDRMLayerDescriptor *layer = &desc->layers[i];
for (j = 0; j < layer->nb_planes; ++j) {
const AVDRMPlaneDescriptor *plane = &layer->planes[j];
const AVDRMObjectDescriptor *object = &desc->objects[plane->object_index];
switch (image_index) {
case 0:
attr[k++] = EGL_DMA_BUF_PLANE0_FD_EXT;
attr[k++] = object->fd;
attr[k++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
attr[k++] = plane->offset;
attr[k++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
attr[k++] = plane->pitch;
if (has_EGL_EXT_image_dma_buf_import_modifiers && object->format_modifier != DRM_FORMAT_MOD_INVALID) {
attr[k++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
attr[k++] = (object->format_modifier & 0xFFFFFFFF);
attr[k++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
attr[k++] = (object->format_modifier >> 32);
}
break;
case 1:
attr[k++] = EGL_DMA_BUF_PLANE1_FD_EXT;
attr[k++] = object->fd;
attr[k++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT;
attr[k++] = plane->offset;
attr[k++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
attr[k++] = plane->pitch;
if (has_EGL_EXT_image_dma_buf_import_modifiers && object->format_modifier != DRM_FORMAT_MOD_INVALID) {
attr[k++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT;
attr[k++] = (object->format_modifier & 0xFFFFFFFF);
attr[k++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT;
attr[k++] = (object->format_modifier >> 32);
}
break;
case 2:
attr[k++] = EGL_DMA_BUF_PLANE2_FD_EXT;
attr[k++] = object->fd;
attr[k++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT;
attr[k++] = plane->offset;
attr[k++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
attr[k++] = plane->pitch;
if (has_EGL_EXT_image_dma_buf_import_modifiers && object->format_modifier != DRM_FORMAT_MOD_INVALID) {
attr[k++] = EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT;
attr[k++] = (object->format_modifier & 0xFFFFFFFF);
attr[k++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT;
attr[k++] = (object->format_modifier >> 32);
}
break;
case 3:
attr[k++] = EGL_DMA_BUF_PLANE3_FD_EXT;
attr[k++] = object->fd;
attr[k++] = EGL_DMA_BUF_PLANE3_OFFSET_EXT;
attr[k++] = plane->offset;
attr[k++] = EGL_DMA_BUF_PLANE3_PITCH_EXT;
attr[k++] = plane->pitch;
if (has_EGL_EXT_image_dma_buf_import_modifiers && object->format_modifier != DRM_FORMAT_MOD_INVALID) {
attr[k++] = EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT;
attr[k++] = (object->format_modifier & 0xFFFFFFFF);
attr[k++] = EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT;
attr[k++] = (object->format_modifier >> 32);
}
break;
default:
break;
}
++image_index;
}
}
switch (SDL_COLORSPACEPRIMARIES(colorspace)) {
case SDL_COLOR_PRIMARIES_BT601:
case SDL_COLOR_PRIMARIES_SMPTE240:
attr[k++] = EGL_YUV_COLOR_SPACE_HINT_EXT;
attr[k++] = EGL_ITU_REC601_EXT;
break;
case SDL_COLOR_PRIMARIES_BT709:
attr[k++] = EGL_YUV_COLOR_SPACE_HINT_EXT;
attr[k++] = EGL_ITU_REC709_EXT;
break;
case SDL_COLOR_PRIMARIES_BT2020:
attr[k++] = EGL_YUV_COLOR_SPACE_HINT_EXT;
attr[k++] = EGL_ITU_REC2020_EXT;
default:
break;
}
switch (SDL_COLORSPACERANGE(colorspace)) {
case SDL_COLOR_RANGE_FULL:
attr[k++] = EGL_SAMPLE_RANGE_HINT_EXT;
attr[k++] = EGL_YUV_FULL_RANGE_EXT;
break;
case SDL_COLOR_RANGE_LIMITED:
default:
attr[k++] = EGL_SAMPLE_RANGE_HINT_EXT;
attr[k++] = EGL_YUV_NARROW_RANGE_EXT;
break;
}
switch (SDL_COLORSPACECHROMA(colorspace)) {
case SDL_CHROMA_LOCATION_LEFT:
attr[k++] = EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT;
attr[k++] = EGL_YUV_CHROMA_SITING_0_EXT;
attr[k++] = EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT;
attr[k++] = EGL_YUV_CHROMA_SITING_0_5_EXT;
break;
case SDL_CHROMA_LOCATION_CENTER:
attr[k++] = EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT;
attr[k++] = EGL_YUV_CHROMA_SITING_0_5_EXT;
attr[k++] = EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT;
attr[k++] = EGL_YUV_CHROMA_SITING_0_5_EXT;
break;
case SDL_CHROMA_LOCATION_TOPLEFT:
attr[k++] = EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT;
attr[k++] = EGL_YUV_CHROMA_SITING_0_EXT;
attr[k++] = EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT;
attr[k++] = EGL_YUV_CHROMA_SITING_0_EXT;
break;
default:
break;
}
SDL_assert(k < SDL_arraysize(attr));
attr[k++] = EGL_NONE;
EGLImage image = eglCreateImage(display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attr);
if (image == EGL_NO_IMAGE) {
SDL_Log("Couldn't create image: %d\n", glGetError());
return SDL_FALSE;
}
glActiveTextureARBFunc(GL_TEXTURE0_ARB);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureID);
glEGLImageTargetTexture2DOESFunc(GL_TEXTURE_EXTERNAL_OES, image);
return SDL_TRUE;
}
#endif // HAVE_EGL
static SDL_bool GetTextureForDRMFrame(AVFrame *frame, SDL_Texture **texture)
{
#ifdef HAVE_EGL
@ -644,6 +842,12 @@ static SDL_bool GetTextureForDRMFrame(AVFrame *frame, SDL_Texture **texture)
EGLDisplay display = eglGetCurrentDisplay();
SDL_PropertiesID props;
GLuint textures[2];
uint64_t format_modifier = desc->objects[0].format_modifier;
if (format_modifier != DRM_FORMAT_MOD_INVALID &&
format_modifier != DRM_FORMAT_MOD_LINEAR) {
return GetOESTextureForDRMFrame(frame, texture);
}
/* FIXME: Assuming NV12 data format */
num_planes = 0;
@ -663,7 +867,7 @@ static SDL_bool GetTextureForDRMFrame(AVFrame *frame, SDL_Texture **texture)
SDL_SetHint("SDL_RENDER_OPENGL_NV12_RG_SHADER", "1");
}
props = CreateVideoTextureProperties(frame, SDL_PIXELFORMAT_UNKNOWN, SDL_TEXTUREACCESS_STATIC);
props = CreateVideoTextureProperties(frame, SDL_PIXELFORMAT_NV12, SDL_TEXTUREACCESS_STATIC);
*texture = SDL_CreateTextureWithProperties(renderer, props);
SDL_DestroyProperties(props);
if (!*texture) {
@ -720,11 +924,15 @@ static SDL_bool GetTextureForDRMFrame(AVFrame *frame, SDL_Texture **texture)
attr[k++] = EGL_NONE;
EGLImage pImage = eglCreateImage(display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attr);
EGLImage image = eglCreateImage(display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attr);
if (image == EGL_NO_IMAGE) {
SDL_Log("Couldn't create image: %d\n", glGetError());
return SDL_FALSE;
}
glActiveTextureARBFunc(GL_TEXTURE0_ARB + image_index);
glBindTexture(GL_TEXTURE_2D, textures[image_index]);
glEGLImageTargetTexture2DOESFunc(GL_TEXTURE_2D, pImage);
glEGLImageTargetTexture2DOESFunc(GL_TEXTURE_2D, image);
++image_index;
}
}