SDL: testffmpeg: fixed mismatch between frame size and frame texture size

From fb87f8f15c11477f294b6486f967ea167dcc20d6 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 4 Mar 2024 10:49:38 -0800
Subject: [PATCH] testffmpeg: fixed mismatch between frame size and frame
 texture size

The AVHWFramesContext associated with the frame has the texture size, and the frame width and height are the displayed size and can be smaller than the texture size
---
 test/testffmpeg.c | 93 +++++++++++++++++++----------------------------
 1 file changed, 38 insertions(+), 55 deletions(-)

diff --git a/test/testffmpeg.c b/test/testffmpeg.c
index c9811d63a5ae..d158aa658aee 100644
--- a/test/testffmpeg.c
+++ b/test/testffmpeg.c
@@ -502,16 +502,32 @@ static SDL_Colorspace GetFrameColorspace(AVFrame *frame)
     return colorspace;
 }
 
-static SDL_PropertiesID CreateVideoTextureProperties(AVFrame *frame, Uint32 format, int access, int w, int h)
+static SDL_PropertiesID CreateVideoTextureProperties(AVFrame *frame, Uint32 format, int access)
 {
     AVFrameSideData *pSideData;
     SDL_PropertiesID props;
+    int width = frame->width;
+    int height = frame->height;
     SDL_Colorspace colorspace = GetFrameColorspace(frame);
 
     /* ITU-R BT.2408-6 recommends using an SDR white point of 203 nits, which is more likely for game content */
     static const float k_flSDRWhitePoint = 203.0f;
     float flMaxLuminance = k_flSDRWhitePoint;
 
+    if (frame->hw_frames_ctx) {
+        AVHWFramesContext *frames = (AVHWFramesContext *)(frame->hw_frames_ctx->data);
+
+        width = frames->width;
+        height = frames->height;
+        if (format == SDL_PIXELFORMAT_UNKNOWN) {
+            format = GetTextureFormat(frames->sw_format);
+        }
+    } else {
+        if (format == SDL_PIXELFORMAT_UNKNOWN) {
+            format = GetTextureFormat(frame->format);
+        }
+    }
+
     props = SDL_CreateProperties();
     SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, colorspace);
     pSideData = av_frame_get_side_data(frame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA);
@@ -528,8 +544,8 @@ static SDL_PropertiesID CreateVideoTextureProperties(AVFrame *frame, Uint32 form
     }
     SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER, format);
     SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, access);
-    SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER, w);
-    SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER, h);
+    SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER, width);
+    SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER, height);
 
     return props;
 }
@@ -561,9 +577,9 @@ static SDL_bool GetTextureForMemoryFrame(AVFrame *frame, SDL_Texture **texture)
 
         SDL_PropertiesID props;
         if (frame_format == SDL_PIXELFORMAT_UNKNOWN) {
-            props = CreateVideoTextureProperties(frame, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, frame->width, frame->height);
+            props = CreateVideoTextureProperties(frame, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING);
         } else {
-            props = CreateVideoTextureProperties(frame, frame_format, SDL_TEXTUREACCESS_STREAMING, frame->width, frame->height);
+            props = CreateVideoTextureProperties(frame, frame_format, SDL_TEXTUREACCESS_STREAMING);
         }
         *texture = SDL_CreateTextureWithProperties(renderer, props);
         SDL_DestroyProperties(props);
@@ -630,6 +646,7 @@ static SDL_bool GetTextureForMemoryFrame(AVFrame *frame, SDL_Texture **texture)
 static SDL_bool GetTextureForDRMFrame(AVFrame *frame, SDL_Texture **texture)
 {
 #ifdef HAVE_EGL
+    AVHWFramesContext *frames = (AVHWFramesContext *)(frame->hw_frames_ctx->data);
     const AVDRMFrameDescriptor *desc = (const AVDRMFrameDescriptor *)frame->data[0];
     int i, j, image_index, num_planes;
     EGLDisplay display = eglGetCurrentDisplay();
@@ -654,7 +671,7 @@ static SDL_bool GetTextureForDRMFrame(AVFrame *frame, SDL_Texture **texture)
         SDL_SetHint("SDL_RENDER_OPENGL_NV12_RG_SHADER", "1");
     }
 
-    props = CreateVideoTextureProperties(frame, SDL_PIXELFORMAT_NV12, SDL_TEXTUREACCESS_STATIC, frame->width, frame->height);
+    props = CreateVideoTextureProperties(frame, SDL_PIXELFORMAT_UNKNOWN, SDL_TEXTUREACCESS_STATIC);
     *texture = SDL_CreateTextureWithProperties(renderer, props);
     SDL_DestroyProperties(props);
     if (!*texture) {
@@ -687,10 +704,10 @@ static SDL_bool GetTextureForDRMFrame(AVFrame *frame, SDL_Texture **texture)
             attr[k++] = formats[i];
 
             attr[k++] = EGL_WIDTH;
-            attr[k++] = frame->width  / ( image_index + 1 ); /* half size for chroma */
+            attr[k++] = frames->width  / ( image_index + 1 ); /* half size for chroma */
 
             attr[k++] = EGL_HEIGHT;
-            attr[k++] = frame->height / ( image_index + 1 );
+            attr[k++] = frames->height / ( image_index + 1 );
 
             attr[k++] = EGL_DMA_BUF_PLANE0_FD_EXT;
             attr[k++] = object->fd;
@@ -747,38 +764,20 @@ static SDL_bool GetTextureForVAAPIFrame(AVFrame *frame, SDL_Texture **texture)
 static SDL_bool GetTextureForD3D11Frame(AVFrame *frame, SDL_Texture **texture)
 {
 #ifdef SDL_PLATFORM_WIN32
+    AVHWFramesContext *frames = (AVHWFramesContext *)(frame->hw_frames_ctx->data);
     int texture_width = 0, texture_height = 0;
     ID3D11Texture2D *pTexture = (ID3D11Texture2D *)frame->data[0];
     UINT iSliceIndex = (UINT)(uintptr_t)frame->data[1];
 
-    D3D11_TEXTURE2D_DESC desc;
-    SDL_zero(desc);
-    ID3D11Texture2D_GetDesc(pTexture, &desc);
-
     if (*texture) {
         SDL_QueryTexture(*texture, NULL, NULL, &texture_width, &texture_height);
     }
-    if (!*texture || (UINT)texture_width != desc.Width || (UINT)texture_height != desc.Height) {
-        Uint32 format;
-
-        switch (desc.Format) {
-        case DXGI_FORMAT_NV12:
-            format = SDL_PIXELFORMAT_NV12;
-            break;
-        case DXGI_FORMAT_P010:
-            format = SDL_PIXELFORMAT_P010;
-            break;
-        default:
-            SDL_SetError("Unsupported texture format %d", desc.Format);
-            return SDL_FALSE;
-        }
-
+    if (!*texture || texture_width != frames->width || texture_height != frames->height) {
         if (*texture) {
             SDL_DestroyTexture(*texture);
         }
 
-        SDL_PropertiesID props = CreateVideoTextureProperties(frame, format, SDL_TEXTUREACCESS_STATIC, desc.Width, desc.Height);
-        SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER, desc.Height);
+        SDL_PropertiesID props = CreateVideoTextureProperties(frame, SDL_PIXELFORMAT_UNKNOWN, SDL_TEXTUREACCESS_STATIC);
         *texture = SDL_CreateTextureWithProperties(renderer, props);
         SDL_DestroyProperties(props);
         if (!*texture) {
@@ -803,29 +802,7 @@ static SDL_bool GetTextureForVideoToolboxFrame(AVFrame *frame, SDL_Texture **tex
 {
 #ifdef SDL_PLATFORM_APPLE
     CVPixelBufferRef pPixelBuffer = (CVPixelBufferRef)frame->data[3];
-    OSType nPixelBufferType = CVPixelBufferGetPixelFormatType(pPixelBuffer);
-    size_t nPixelBufferWidth = CVPixelBufferGetWidthOfPlane(pPixelBuffer, 0);
-    size_t nPixelBufferHeight = CVPixelBufferGetHeightOfPlane(pPixelBuffer, 0);
     SDL_PropertiesID props;
-    Uint32 format;
-
-    switch (nPixelBufferType) {
-    case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
-    case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
-        format = SDL_PIXELFORMAT_NV12;
-        break;
-    case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange:
-    case kCVPixelFormatType_420YpCbCr10BiPlanarFullRange:
-        format = SDL_PIXELFORMAT_P010;
-        break;
-    default:
-        SDL_SetError("Unsupported texture format %c%c%c%c",
-            (char)((nPixelBufferType >> 24) & 0xFF),
-            (char)((nPixelBufferType >> 16) & 0xFF),
-            (char)((nPixelBufferType >> 8) & 0xFF),
-            (char)((nPixelBufferType >> 0) & 0xFF));
-        return SDL_FALSE;
-    }
 
     if (*texture) {
         /* Free the previous texture now that we're about to render a new one */
@@ -833,7 +810,7 @@ static SDL_bool GetTextureForVideoToolboxFrame(AVFrame *frame, SDL_Texture **tex
         SDL_DestroyTexture(*texture);
     }
 
-    props = CreateVideoTextureProperties(frame, format, SDL_TEXTUREACCESS_STATIC, nPixelBufferWidth, nPixelBufferHeight);
+    props = CreateVideoTextureProperties(frame, SDL_PIXELFORMAT_UNKNOWN, SDL_TEXTUREACCESS_STATIC);
     SDL_SetProperty(props, SDL_PROP_TEXTURE_CREATE_METAL_PIXELBUFFER_POINTER, pPixelBuffer);
     *texture = SDL_CreateTextureWithProperties(renderer, props);
     SDL_DestroyProperties(props);
@@ -850,11 +827,12 @@ static SDL_bool GetTextureForVideoToolboxFrame(AVFrame *frame, SDL_Texture **tex
 static SDL_bool GetTextureForVulkanFrame(AVFrame *frame, SDL_Texture **texture)
 {
     SDL_PropertiesID props;
+
     if (*texture) {
         SDL_DestroyTexture(*texture);
     }
 
-    props = CreateVideoTextureProperties(frame, SDL_PIXELFORMAT_UNKNOWN, SDL_TEXTUREACCESS_STATIC, frame->width, frame->height);
+    props = CreateVideoTextureProperties(frame, SDL_PIXELFORMAT_UNKNOWN, SDL_TEXTUREACCESS_STATIC);
     *texture = CreateVulkanVideoTexture(vulkan_context, frame, renderer, props);
     SDL_DestroyProperties(props);
     if (!*texture) {
@@ -905,10 +883,15 @@ static void DisplayVideoTexture(AVFrame *frame)
         return;
     }
 
+    SDL_FRect src;
+    src.x = 0.0f;
+    src.y = 0.0f;
+    src.w = (float)frame->width;
+    src.h = (float)frame->height;
     if (frame->linesize[0] < 0) {
-        SDL_RenderTextureRotated(renderer, video_texture, NULL, NULL, 0.0, NULL, SDL_FLIP_VERTICAL);
+        SDL_RenderTextureRotated(renderer, video_texture, &src, NULL, 0.0, NULL, SDL_FLIP_VERTICAL);
     } else {
-        SDL_RenderTexture(renderer, video_texture, NULL, NULL);
+        SDL_RenderTexture(renderer, video_texture, &src, NULL);
     }
 }