diff --git a/test/testffmpeg.c b/test/testffmpeg.c index 45ddfdb71..fa17af914 100644 --- a/test/testffmpeg.c +++ b/test/testffmpeg.c @@ -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 #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; } }