xref: /aosp_15_r20/external/libdav1d/examples/dp_renderer_sdl.c (revision c09093415860a1c2373dacd84c4fde00c507cdfd)
1 /*
2  * Copyright © 2020, VideoLAN and dav1d authors
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this
9  *    list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  *    this list of conditions and the following disclaimer in the documentation
13  *    and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "dp_renderer.h"
28 
29 #include <assert.h>
30 
31 /**
32  * Renderer context for SDL
33  */
34 typedef struct renderer_priv_ctx
35 {
36     // SDL window
37     SDL_Window *win;
38     // SDL renderer
39     SDL_Renderer *renderer;
40     // Lock protecting access to the texture
41     SDL_mutex *lock;
42     // Texture to render
43     SDL_Texture *tex;
44 } Dav1dPlayRendererPrivateContext;
45 
sdl_renderer_create(const Dav1dPlaySettings * settings)46 static void *sdl_renderer_create(const Dav1dPlaySettings *settings)
47 {
48     int window_flags = 0;
49     if (settings->fullscreen)
50         window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
51 
52     SDL_Window *win = dp_create_sdl_window(window_flags);
53     if (win == NULL)
54         return NULL;
55 
56     SDL_ShowCursor(0);
57 
58     // Alloc
59     Dav1dPlayRendererPrivateContext *rd_priv_ctx = malloc(sizeof(Dav1dPlayRendererPrivateContext));
60     if (rd_priv_ctx == NULL) {
61         return NULL;
62     }
63     rd_priv_ctx->win = win;
64 
65     // Create renderer
66     rd_priv_ctx->renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
67     // Set scale quality
68     SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
69 
70     // Create Mutex
71     rd_priv_ctx->lock = SDL_CreateMutex();
72     if (rd_priv_ctx->lock == NULL) {
73         fprintf(stderr, "SDL_CreateMutex failed: %s\n", SDL_GetError());
74         free(rd_priv_ctx);
75         return NULL;
76     }
77 
78     rd_priv_ctx->tex = NULL;
79 
80     return rd_priv_ctx;
81 }
82 
sdl_renderer_destroy(void * cookie)83 static void sdl_renderer_destroy(void *cookie)
84 {
85     Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
86     assert(rd_priv_ctx != NULL);
87 
88     SDL_DestroyTexture(rd_priv_ctx->tex);
89     SDL_DestroyRenderer(rd_priv_ctx->renderer);
90     SDL_DestroyWindow(rd_priv_ctx->win);
91     SDL_DestroyMutex(rd_priv_ctx->lock);
92     free(rd_priv_ctx);
93 }
94 
sdl_render(void * cookie,const Dav1dPlaySettings * settings)95 static void sdl_render(void *cookie, const Dav1dPlaySettings *settings)
96 {
97     Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
98     assert(rd_priv_ctx != NULL);
99 
100     SDL_LockMutex(rd_priv_ctx->lock);
101 
102     if (rd_priv_ctx->tex == NULL) {
103         SDL_UnlockMutex(rd_priv_ctx->lock);
104         return;
105     }
106 
107     // Display the frame
108     SDL_RenderClear(rd_priv_ctx->renderer);
109     SDL_RenderCopy(rd_priv_ctx->renderer, rd_priv_ctx->tex, NULL, NULL);
110     SDL_RenderPresent(rd_priv_ctx->renderer);
111 
112     SDL_UnlockMutex(rd_priv_ctx->lock);
113 }
114 
sdl_update_texture(void * cookie,Dav1dPicture * dav1d_pic,const Dav1dPlaySettings * settings)115 static int sdl_update_texture(void *cookie, Dav1dPicture *dav1d_pic,
116                               const Dav1dPlaySettings *settings)
117 {
118     Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
119     assert(rd_priv_ctx != NULL);
120 
121     SDL_LockMutex(rd_priv_ctx->lock);
122 
123     if (dav1d_pic == NULL) {
124         rd_priv_ctx->tex = NULL;
125         SDL_UnlockMutex(rd_priv_ctx->lock);
126         return 0;
127     }
128 
129     int width = dav1d_pic->p.w;
130     int height = dav1d_pic->p.h;
131     int tex_w = width;
132     int tex_h = height;
133 
134     enum Dav1dPixelLayout dav1d_layout = dav1d_pic->p.layout;
135 
136     if (DAV1D_PIXEL_LAYOUT_I420 != dav1d_layout || dav1d_pic->p.bpc != 8) {
137         fprintf(stderr, "Unsupported pixel format, only 8bit 420 supported so far.\n");
138         exit(50);
139     }
140 
141     SDL_Texture *texture = rd_priv_ctx->tex;
142     if (texture != NULL) {
143         SDL_QueryTexture(texture, NULL, NULL, &tex_w, &tex_h);
144         if (tex_w != width || tex_h != height) {
145             SDL_DestroyTexture(texture);
146             texture = NULL;
147         }
148     }
149 
150     if (texture == NULL) {
151         texture = SDL_CreateTexture(rd_priv_ctx->renderer, SDL_PIXELFORMAT_IYUV,
152             SDL_TEXTUREACCESS_STREAMING, width, height);
153         SDL_RenderSetLogicalSize(rd_priv_ctx->renderer, width, height);
154     }
155 
156     SDL_UpdateYUVTexture(texture, NULL,
157         dav1d_pic->data[0], (int)dav1d_pic->stride[0], // Y
158         dav1d_pic->data[1], (int)dav1d_pic->stride[1], // U
159         dav1d_pic->data[2], (int)dav1d_pic->stride[1]  // V
160         );
161 
162     rd_priv_ctx->tex = texture;
163     SDL_UnlockMutex(rd_priv_ctx->lock);
164     return 0;
165 }
166 
167 const Dav1dPlayRenderInfo rdr_sdl = {
168     .name = "sdl",
169     .create_renderer = sdl_renderer_create,
170     .destroy_renderer = sdl_renderer_destroy,
171     .render = sdl_render,
172     .update_frame = sdl_update_texture
173 };
174