1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Copyright (c) 2014 Lukasz Marek
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * This file is part of FFmpeg.
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
7cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
8cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
9cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
10cabdff1aSopenharmony_ci *
11cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
12cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
13cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14cabdff1aSopenharmony_ci * Lesser General Public License for more details.
15cabdff1aSopenharmony_ci *
16cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
17cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
18cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19cabdff1aSopenharmony_ci */
20cabdff1aSopenharmony_ci
21cabdff1aSopenharmony_ci//TODO: support for more formats
22cabdff1aSopenharmony_ci//TODO: support for more systems.
23cabdff1aSopenharmony_ci//TODO: implement X11, Windows, Mac OS native default window. SDL 1.2 doesn't allow to render to custom thread.
24cabdff1aSopenharmony_ci
25cabdff1aSopenharmony_ci#include <stdio.h>
26cabdff1aSopenharmony_ci#include <stdlib.h>
27cabdff1aSopenharmony_ci#include <string.h>
28cabdff1aSopenharmony_ci#include <stddef.h>
29cabdff1aSopenharmony_ci
30cabdff1aSopenharmony_ci#include "config.h"
31cabdff1aSopenharmony_ci
32cabdff1aSopenharmony_ci#if HAVE_WINDOWS_H
33cabdff1aSopenharmony_ci#define WIN32_LEAN_AND_MEAN
34cabdff1aSopenharmony_ci#include <windows.h>
35cabdff1aSopenharmony_ci#endif
36cabdff1aSopenharmony_ci#if HAVE_OPENGL_GL3_H
37cabdff1aSopenharmony_ci#include <OpenGL/gl3.h>
38cabdff1aSopenharmony_ci#elif HAVE_ES2_GL_H
39cabdff1aSopenharmony_ci#include <ES2/gl.h>
40cabdff1aSopenharmony_ci#else
41cabdff1aSopenharmony_ci#include <GL/gl.h>
42cabdff1aSopenharmony_ci#include <GL/glext.h>
43cabdff1aSopenharmony_ci#endif
44cabdff1aSopenharmony_ci#if HAVE_GLXGETPROCADDRESS
45cabdff1aSopenharmony_ci#include <GL/glx.h>
46cabdff1aSopenharmony_ci#endif
47cabdff1aSopenharmony_ci
48cabdff1aSopenharmony_ci#if CONFIG_SDL2
49cabdff1aSopenharmony_ci#include <SDL.h>
50cabdff1aSopenharmony_ci#endif
51cabdff1aSopenharmony_ci
52cabdff1aSopenharmony_ci#include "libavutil/common.h"
53cabdff1aSopenharmony_ci#include "libavutil/pixdesc.h"
54cabdff1aSopenharmony_ci#include "libavutil/log.h"
55cabdff1aSopenharmony_ci#include "libavutil/opt.h"
56cabdff1aSopenharmony_ci#include "libavutil/avassert.h"
57cabdff1aSopenharmony_ci#include "libavformat/avformat.h"
58cabdff1aSopenharmony_ci#include "libavformat/internal.h"
59cabdff1aSopenharmony_ci#include "libavformat/mux.h"
60cabdff1aSopenharmony_ci#include "libavdevice/avdevice.h"
61cabdff1aSopenharmony_ci#include "opengl_enc_shaders.h"
62cabdff1aSopenharmony_ci
63cabdff1aSopenharmony_ci#ifndef APIENTRY
64cabdff1aSopenharmony_ci#define APIENTRY
65cabdff1aSopenharmony_ci#endif
66cabdff1aSopenharmony_ci
67cabdff1aSopenharmony_ci/* FF_GL_RED_COMPONENT is used for planar pixel types.
68cabdff1aSopenharmony_ci * Only red component is sampled in shaders.
69cabdff1aSopenharmony_ci * On some platforms GL_RED is not available and GL_LUMINANCE have to be used,
70cabdff1aSopenharmony_ci * but since OpenGL 3.0 GL_LUMINANCE is deprecated.
71cabdff1aSopenharmony_ci * GL_RED produces RGBA = value, 0, 0, 1.
72cabdff1aSopenharmony_ci * GL_LUMINANCE produces RGBA = value, value, value, 1.
73cabdff1aSopenharmony_ci * Note: GL_INTENSITY may also be used which produce RGBA = value, value, value, value. */
74cabdff1aSopenharmony_ci#if defined(GL_RED)
75cabdff1aSopenharmony_ci#define FF_GL_RED_COMPONENT GL_RED
76cabdff1aSopenharmony_ci#elif defined(GL_LUMINANCE)
77cabdff1aSopenharmony_ci#define FF_GL_RED_COMPONENT GL_LUMINANCE
78cabdff1aSopenharmony_ci#else
79cabdff1aSopenharmony_ci#define FF_GL_RED_COMPONENT 0x1903; //GL_RED
80cabdff1aSopenharmony_ci#endif
81cabdff1aSopenharmony_ci
82cabdff1aSopenharmony_ci/* Constants not defined for iOS */
83cabdff1aSopenharmony_ci#define FF_GL_UNSIGNED_BYTE_3_3_2 0x8032
84cabdff1aSopenharmony_ci#define FF_GL_UNSIGNED_BYTE_2_3_3_REV 0x8362
85cabdff1aSopenharmony_ci#define FF_GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
86cabdff1aSopenharmony_ci#define FF_GL_UNPACK_ROW_LENGTH          0x0CF2
87cabdff1aSopenharmony_ci
88cabdff1aSopenharmony_ci/* MinGW exposes only OpenGL 1.1 API */
89cabdff1aSopenharmony_ci#define FF_GL_ARRAY_BUFFER                0x8892
90cabdff1aSopenharmony_ci#define FF_GL_ELEMENT_ARRAY_BUFFER        0x8893
91cabdff1aSopenharmony_ci#define FF_GL_STATIC_DRAW                 0x88E4
92cabdff1aSopenharmony_ci#define FF_GL_FRAGMENT_SHADER             0x8B30
93cabdff1aSopenharmony_ci#define FF_GL_VERTEX_SHADER               0x8B31
94cabdff1aSopenharmony_ci#define FF_GL_COMPILE_STATUS              0x8B81
95cabdff1aSopenharmony_ci#define FF_GL_LINK_STATUS                 0x8B82
96cabdff1aSopenharmony_ci#define FF_GL_INFO_LOG_LENGTH             0x8B84
97cabdff1aSopenharmony_citypedef void   (APIENTRY *FF_PFNGLACTIVETEXTUREPROC) (GLenum texture);
98cabdff1aSopenharmony_citypedef void   (APIENTRY *FF_PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
99cabdff1aSopenharmony_citypedef void   (APIENTRY *FF_PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
100cabdff1aSopenharmony_citypedef void   (APIENTRY *FF_PFNGLBUFFERDATAPROC) (GLenum target, ptrdiff_t size, const GLvoid *data, GLenum usage);
101cabdff1aSopenharmony_citypedef void   (APIENTRY *FF_PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
102cabdff1aSopenharmony_citypedef GLint  (APIENTRY *FF_PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const char *name);
103cabdff1aSopenharmony_citypedef void   (APIENTRY *FF_PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
104cabdff1aSopenharmony_citypedef void   (APIENTRY *FF_PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, uintptr_t pointer);
105cabdff1aSopenharmony_citypedef GLint  (APIENTRY *FF_PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const char *name);
106cabdff1aSopenharmony_citypedef void   (APIENTRY *FF_PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0);
107cabdff1aSopenharmony_citypedef void   (APIENTRY *FF_PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
108cabdff1aSopenharmony_citypedef void   (APIENTRY *FF_PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
109cabdff1aSopenharmony_citypedef GLuint (APIENTRY *FF_PFNGLCREATEPROGRAMPROC) (void);
110cabdff1aSopenharmony_citypedef void   (APIENTRY *FF_PFNGLDELETEPROGRAMPROC) (GLuint program);
111cabdff1aSopenharmony_citypedef void   (APIENTRY *FF_PFNGLUSEPROGRAMPROC) (GLuint program);
112cabdff1aSopenharmony_citypedef void   (APIENTRY *FF_PFNGLLINKPROGRAMPROC) (GLuint program);
113cabdff1aSopenharmony_citypedef void   (APIENTRY *FF_PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
114cabdff1aSopenharmony_citypedef void   (APIENTRY *FF_PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, char *infoLog);
115cabdff1aSopenharmony_citypedef void   (APIENTRY *FF_PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
116cabdff1aSopenharmony_citypedef GLuint (APIENTRY *FF_PFNGLCREATESHADERPROC) (GLenum type);
117cabdff1aSopenharmony_citypedef void   (APIENTRY *FF_PFNGLDELETESHADERPROC) (GLuint shader);
118cabdff1aSopenharmony_citypedef void   (APIENTRY *FF_PFNGLCOMPILESHADERPROC) (GLuint shader);
119cabdff1aSopenharmony_citypedef void   (APIENTRY *FF_PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const char* *string, const GLint *length);
120cabdff1aSopenharmony_citypedef void   (APIENTRY *FF_PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
121cabdff1aSopenharmony_citypedef void   (APIENTRY *FF_PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, char *infoLog);
122cabdff1aSopenharmony_ci
123cabdff1aSopenharmony_citypedef struct FFOpenGLFunctions {
124cabdff1aSopenharmony_ci    FF_PFNGLACTIVETEXTUREPROC glActiveTexture;                     //Require GL ARB multitexture
125cabdff1aSopenharmony_ci    FF_PFNGLGENBUFFERSPROC glGenBuffers;                           //Require GL_ARB_vertex_buffer_object
126cabdff1aSopenharmony_ci    FF_PFNGLDELETEBUFFERSPROC glDeleteBuffers;                     //Require GL_ARB_vertex_buffer_object
127cabdff1aSopenharmony_ci    FF_PFNGLBUFFERDATAPROC glBufferData;                           //Require GL_ARB_vertex_buffer_object
128cabdff1aSopenharmony_ci    FF_PFNGLBINDBUFFERPROC glBindBuffer;                           //Require GL_ARB_vertex_buffer_object
129cabdff1aSopenharmony_ci    FF_PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation;             //Require GL_ARB_vertex_shader
130cabdff1aSopenharmony_ci    FF_PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; //Require GL_ARB_vertex_shader
131cabdff1aSopenharmony_ci    FF_PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;         //Require GL_ARB_vertex_shader
132cabdff1aSopenharmony_ci    FF_PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;           //Require GL_ARB_shader_objects
133cabdff1aSopenharmony_ci    FF_PFNGLUNIFORM1FPROC glUniform1f;                             //Require GL_ARB_shader_objects
134cabdff1aSopenharmony_ci    FF_PFNGLUNIFORM1IPROC glUniform1i;                             //Require GL_ARB_shader_objects
135cabdff1aSopenharmony_ci    FF_PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv;               //Require GL_ARB_shader_objects
136cabdff1aSopenharmony_ci    FF_PFNGLCREATEPROGRAMPROC glCreateProgram;                     //Require GL_ARB_shader_objects
137cabdff1aSopenharmony_ci    FF_PFNGLDELETEPROGRAMPROC glDeleteProgram;                     //Require GL_ARB_shader_objects
138cabdff1aSopenharmony_ci    FF_PFNGLUSEPROGRAMPROC glUseProgram;                           //Require GL_ARB_shader_objects
139cabdff1aSopenharmony_ci    FF_PFNGLLINKPROGRAMPROC glLinkProgram;                         //Require GL_ARB_shader_objects
140cabdff1aSopenharmony_ci    FF_PFNGLGETPROGRAMIVPROC glGetProgramiv;                       //Require GL_ARB_shader_objects
141cabdff1aSopenharmony_ci    FF_PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;             //Require GL_ARB_shader_objects
142cabdff1aSopenharmony_ci    FF_PFNGLATTACHSHADERPROC glAttachShader;                       //Require GL_ARB_shader_objects
143cabdff1aSopenharmony_ci    FF_PFNGLCREATESHADERPROC glCreateShader;                       //Require GL_ARB_shader_objects
144cabdff1aSopenharmony_ci    FF_PFNGLDELETESHADERPROC glDeleteShader;                       //Require GL_ARB_shader_objects
145cabdff1aSopenharmony_ci    FF_PFNGLCOMPILESHADERPROC glCompileShader;                     //Require GL_ARB_shader_objects
146cabdff1aSopenharmony_ci    FF_PFNGLSHADERSOURCEPROC glShaderSource;                       //Require GL_ARB_shader_objects
147cabdff1aSopenharmony_ci    FF_PFNGLGETSHADERIVPROC glGetShaderiv;                         //Require GL_ARB_shader_objects
148cabdff1aSopenharmony_ci    FF_PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;               //Require GL_ARB_shader_objects
149cabdff1aSopenharmony_ci} FFOpenGLFunctions;
150cabdff1aSopenharmony_ci
151cabdff1aSopenharmony_ci#define OPENGL_ERROR_CHECK(ctx) \
152cabdff1aSopenharmony_ci{\
153cabdff1aSopenharmony_ci    GLenum err_code; \
154cabdff1aSopenharmony_ci    if ((err_code = glGetError()) != GL_NO_ERROR) { \
155cabdff1aSopenharmony_ci        av_log(ctx, AV_LOG_ERROR, "OpenGL error occurred in '%s', line %d: %d\n", __FUNCTION__, __LINE__, err_code); \
156cabdff1aSopenharmony_ci        goto fail; \
157cabdff1aSopenharmony_ci    } \
158cabdff1aSopenharmony_ci}\
159cabdff1aSopenharmony_ci
160cabdff1aSopenharmony_citypedef struct OpenGLVertexInfo
161cabdff1aSopenharmony_ci{
162cabdff1aSopenharmony_ci    float x, y, z;    ///<Position
163cabdff1aSopenharmony_ci    float s0, t0;     ///<Texture coords
164cabdff1aSopenharmony_ci} OpenGLVertexInfo;
165cabdff1aSopenharmony_ci
166cabdff1aSopenharmony_ci/* defines 2 triangles to display */
167cabdff1aSopenharmony_cistatic const GLushort g_index[6] =
168cabdff1aSopenharmony_ci{
169cabdff1aSopenharmony_ci    0, 1, 2,
170cabdff1aSopenharmony_ci    0, 3, 2,
171cabdff1aSopenharmony_ci};
172cabdff1aSopenharmony_ci
173cabdff1aSopenharmony_citypedef struct OpenGLContext {
174cabdff1aSopenharmony_ci    AVClass *class;                    ///< class for private options
175cabdff1aSopenharmony_ci
176cabdff1aSopenharmony_ci#if CONFIG_SDL2
177cabdff1aSopenharmony_ci    SDL_Window *window;
178cabdff1aSopenharmony_ci    SDL_GLContext glcontext;
179cabdff1aSopenharmony_ci#endif
180cabdff1aSopenharmony_ci    FFOpenGLFunctions glprocs;
181cabdff1aSopenharmony_ci
182cabdff1aSopenharmony_ci    int inited;                        ///< Set to 1 when write_header was successfully called.
183cabdff1aSopenharmony_ci    uint8_t background[4];             ///< Background color
184cabdff1aSopenharmony_ci    int no_window;                     ///< 0 for create default window
185cabdff1aSopenharmony_ci    char *window_title;                ///< Title of the window
186cabdff1aSopenharmony_ci
187cabdff1aSopenharmony_ci    /* OpenGL implementation limits */
188cabdff1aSopenharmony_ci    GLint max_texture_size;            ///< Maximum texture size
189cabdff1aSopenharmony_ci    GLint max_viewport_width;          ///< Maximum viewport size
190cabdff1aSopenharmony_ci    GLint max_viewport_height;         ///< Maximum viewport size
191cabdff1aSopenharmony_ci    int non_pow_2_textures;            ///< 1 when non power of 2 textures are supported
192cabdff1aSopenharmony_ci    int unpack_subimage;               ///< 1 when GL_EXT_unpack_subimage is available
193cabdff1aSopenharmony_ci
194cabdff1aSopenharmony_ci    /* Current OpenGL configuration */
195cabdff1aSopenharmony_ci    GLuint program;                    ///< Shader program
196cabdff1aSopenharmony_ci    GLuint vertex_shader;              ///< Vertex shader
197cabdff1aSopenharmony_ci    GLuint fragment_shader;            ///< Fragment shader for current pix_pmt
198cabdff1aSopenharmony_ci    GLuint texture_name[4];            ///< Textures' IDs
199cabdff1aSopenharmony_ci    GLuint index_buffer;               ///< Index buffer
200cabdff1aSopenharmony_ci    GLuint vertex_buffer;              ///< Vertex buffer
201cabdff1aSopenharmony_ci    OpenGLVertexInfo vertex[4];        ///< VBO
202cabdff1aSopenharmony_ci    GLint projection_matrix_location;  ///< Uniforms' locations
203cabdff1aSopenharmony_ci    GLint model_view_matrix_location;
204cabdff1aSopenharmony_ci    GLint color_map_location;
205cabdff1aSopenharmony_ci    GLint chroma_div_w_location;
206cabdff1aSopenharmony_ci    GLint chroma_div_h_location;
207cabdff1aSopenharmony_ci    GLint texture_location[4];
208cabdff1aSopenharmony_ci    GLint position_attrib;             ///< Attibutes' locations
209cabdff1aSopenharmony_ci    GLint texture_coords_attrib;
210cabdff1aSopenharmony_ci
211cabdff1aSopenharmony_ci    GLfloat projection_matrix[16];     ///< Projection matrix
212cabdff1aSopenharmony_ci    GLfloat model_view_matrix[16];     ///< Modev view matrix
213cabdff1aSopenharmony_ci    GLfloat color_map[16];             ///< RGBA color map matrix
214cabdff1aSopenharmony_ci    GLfloat chroma_div_w;              ///< Chroma subsampling w ratio
215cabdff1aSopenharmony_ci    GLfloat chroma_div_h;              ///< Chroma subsampling h ratio
216cabdff1aSopenharmony_ci
217cabdff1aSopenharmony_ci    /* Stream information */
218cabdff1aSopenharmony_ci    GLenum format;
219cabdff1aSopenharmony_ci    GLenum type;
220cabdff1aSopenharmony_ci    int width;                         ///< Stream width
221cabdff1aSopenharmony_ci    int height;                        ///< Stream height
222cabdff1aSopenharmony_ci    enum AVPixelFormat pix_fmt;        ///< Stream pixel format
223cabdff1aSopenharmony_ci    int picture_width;                 ///< Rendered width
224cabdff1aSopenharmony_ci    int picture_height;                ///< Rendered height
225cabdff1aSopenharmony_ci    int window_width;
226cabdff1aSopenharmony_ci    int window_height;
227cabdff1aSopenharmony_ci} OpenGLContext;
228cabdff1aSopenharmony_ci
229cabdff1aSopenharmony_cistatic const struct OpenGLFormatDesc {
230cabdff1aSopenharmony_ci    enum AVPixelFormat fixel_format;
231cabdff1aSopenharmony_ci    const char * const * fragment_shader;
232cabdff1aSopenharmony_ci    GLenum format;
233cabdff1aSopenharmony_ci    GLenum type;
234cabdff1aSopenharmony_ci} opengl_format_desc[] = {
235cabdff1aSopenharmony_ci    { AV_PIX_FMT_YUV420P,    &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR,  FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
236cabdff1aSopenharmony_ci    { AV_PIX_FMT_YUV444P,    &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR,  FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
237cabdff1aSopenharmony_ci    { AV_PIX_FMT_YUV422P,    &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR,  FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
238cabdff1aSopenharmony_ci    { AV_PIX_FMT_YUV410P,    &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR,  FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
239cabdff1aSopenharmony_ci    { AV_PIX_FMT_YUV411P,    &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR,  FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
240cabdff1aSopenharmony_ci    { AV_PIX_FMT_YUV440P,    &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR,  FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
241cabdff1aSopenharmony_ci    { AV_PIX_FMT_YUV420P16,  &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR,  FF_GL_RED_COMPONENT, GL_UNSIGNED_SHORT },
242cabdff1aSopenharmony_ci    { AV_PIX_FMT_YUV422P16,  &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR,  FF_GL_RED_COMPONENT, GL_UNSIGNED_SHORT },
243cabdff1aSopenharmony_ci    { AV_PIX_FMT_YUV444P16,  &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR,  FF_GL_RED_COMPONENT, GL_UNSIGNED_SHORT },
244cabdff1aSopenharmony_ci    { AV_PIX_FMT_YUVA420P,   &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
245cabdff1aSopenharmony_ci    { AV_PIX_FMT_YUVA444P,   &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
246cabdff1aSopenharmony_ci    { AV_PIX_FMT_YUVA422P,   &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
247cabdff1aSopenharmony_ci    { AV_PIX_FMT_YUVA420P16, &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_SHORT },
248cabdff1aSopenharmony_ci    { AV_PIX_FMT_YUVA422P16, &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_SHORT },
249cabdff1aSopenharmony_ci    { AV_PIX_FMT_YUVA444P16, &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_SHORT },
250cabdff1aSopenharmony_ci    { AV_PIX_FMT_RGB24,      &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET,  GL_RGB, GL_UNSIGNED_BYTE },
251cabdff1aSopenharmony_ci    { AV_PIX_FMT_BGR24,      &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET,  GL_RGB, GL_UNSIGNED_BYTE },
252cabdff1aSopenharmony_ci    { AV_PIX_FMT_0RGB,       &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET,  GL_RGBA, GL_UNSIGNED_BYTE },
253cabdff1aSopenharmony_ci    { AV_PIX_FMT_RGB0,       &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET,  GL_RGBA, GL_UNSIGNED_BYTE },
254cabdff1aSopenharmony_ci    { AV_PIX_FMT_0BGR,       &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET,  GL_RGBA, GL_UNSIGNED_BYTE },
255cabdff1aSopenharmony_ci    { AV_PIX_FMT_BGR0,       &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET,  GL_RGBA, GL_UNSIGNED_BYTE },
256cabdff1aSopenharmony_ci    { AV_PIX_FMT_RGB565,     &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET,  GL_RGB, GL_UNSIGNED_SHORT_5_6_5 },
257cabdff1aSopenharmony_ci    { AV_PIX_FMT_BGR565,     &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET,  GL_RGB, GL_UNSIGNED_SHORT_5_6_5 },
258cabdff1aSopenharmony_ci    { AV_PIX_FMT_RGB555,     &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET,  GL_RGBA, FF_GL_UNSIGNED_SHORT_1_5_5_5_REV },
259cabdff1aSopenharmony_ci    { AV_PIX_FMT_BGR555,     &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET,  GL_RGBA, FF_GL_UNSIGNED_SHORT_1_5_5_5_REV },
260cabdff1aSopenharmony_ci    { AV_PIX_FMT_RGB8,       &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET,  GL_RGB, FF_GL_UNSIGNED_BYTE_3_3_2 },
261cabdff1aSopenharmony_ci    { AV_PIX_FMT_BGR8,       &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET,  GL_RGB, FF_GL_UNSIGNED_BYTE_2_3_3_REV },
262cabdff1aSopenharmony_ci    { AV_PIX_FMT_RGB48,      &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET,  GL_RGB, GL_UNSIGNED_SHORT },
263cabdff1aSopenharmony_ci    { AV_PIX_FMT_BGR48,      &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET,  GL_RGB, GL_UNSIGNED_SHORT },
264cabdff1aSopenharmony_ci    { AV_PIX_FMT_ARGB,       &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET, GL_RGBA, GL_UNSIGNED_BYTE },
265cabdff1aSopenharmony_ci    { AV_PIX_FMT_RGBA,       &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET, GL_RGBA, GL_UNSIGNED_BYTE },
266cabdff1aSopenharmony_ci    { AV_PIX_FMT_ABGR,       &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET, GL_RGBA, GL_UNSIGNED_BYTE },
267cabdff1aSopenharmony_ci    { AV_PIX_FMT_BGRA,       &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET, GL_RGBA, GL_UNSIGNED_BYTE },
268cabdff1aSopenharmony_ci    { AV_PIX_FMT_RGBA64,     &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET, GL_RGBA, GL_UNSIGNED_SHORT },
269cabdff1aSopenharmony_ci    { AV_PIX_FMT_BGRA64,     &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET, GL_RGBA, GL_UNSIGNED_SHORT },
270cabdff1aSopenharmony_ci    { AV_PIX_FMT_GBRP,       &FF_OPENGL_FRAGMENT_SHADER_RGB_PLANAR,  FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
271cabdff1aSopenharmony_ci    { AV_PIX_FMT_GBRP16,     &FF_OPENGL_FRAGMENT_SHADER_RGB_PLANAR,  FF_GL_RED_COMPONENT, GL_UNSIGNED_SHORT },
272cabdff1aSopenharmony_ci    { AV_PIX_FMT_GBRAP,      &FF_OPENGL_FRAGMENT_SHADER_RGBA_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
273cabdff1aSopenharmony_ci    { AV_PIX_FMT_GBRAP16,    &FF_OPENGL_FRAGMENT_SHADER_RGBA_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_SHORT },
274cabdff1aSopenharmony_ci    { AV_PIX_FMT_GRAY8,      &FF_OPENGL_FRAGMENT_SHADER_GRAY,        FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
275cabdff1aSopenharmony_ci    { AV_PIX_FMT_GRAY16,     &FF_OPENGL_FRAGMENT_SHADER_GRAY,        FF_GL_RED_COMPONENT, GL_UNSIGNED_SHORT },
276cabdff1aSopenharmony_ci    { AV_PIX_FMT_NONE,       NULL }
277cabdff1aSopenharmony_ci};
278cabdff1aSopenharmony_ci
279cabdff1aSopenharmony_cistatic av_cold int opengl_prepare_vertex(AVFormatContext *s);
280cabdff1aSopenharmony_cistatic int opengl_draw(AVFormatContext *h, void *intput, int repaint, int is_pkt);
281cabdff1aSopenharmony_cistatic av_cold int opengl_init_context(OpenGLContext *opengl);
282cabdff1aSopenharmony_ci
283cabdff1aSopenharmony_cistatic av_cold void opengl_deinit_context(OpenGLContext *opengl)
284cabdff1aSopenharmony_ci{
285cabdff1aSopenharmony_ci    glDeleteTextures(4, opengl->texture_name);
286cabdff1aSopenharmony_ci    opengl->texture_name[0] = opengl->texture_name[1] =
287cabdff1aSopenharmony_ci    opengl->texture_name[2] = opengl->texture_name[3] = 0;
288cabdff1aSopenharmony_ci    if (opengl->glprocs.glUseProgram)
289cabdff1aSopenharmony_ci        opengl->glprocs.glUseProgram(0);
290cabdff1aSopenharmony_ci    if (opengl->glprocs.glDeleteProgram) {
291cabdff1aSopenharmony_ci        opengl->glprocs.glDeleteProgram(opengl->program);
292cabdff1aSopenharmony_ci        opengl->program = 0;
293cabdff1aSopenharmony_ci    }
294cabdff1aSopenharmony_ci    if (opengl->glprocs.glDeleteShader) {
295cabdff1aSopenharmony_ci        opengl->glprocs.glDeleteShader(opengl->vertex_shader);
296cabdff1aSopenharmony_ci        opengl->glprocs.glDeleteShader(opengl->fragment_shader);
297cabdff1aSopenharmony_ci        opengl->vertex_shader = opengl->fragment_shader = 0;
298cabdff1aSopenharmony_ci    }
299cabdff1aSopenharmony_ci    if (opengl->glprocs.glBindBuffer) {
300cabdff1aSopenharmony_ci        opengl->glprocs.glBindBuffer(FF_GL_ARRAY_BUFFER, 0);
301cabdff1aSopenharmony_ci        opengl->glprocs.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER, 0);
302cabdff1aSopenharmony_ci    }
303cabdff1aSopenharmony_ci    if (opengl->glprocs.glDeleteBuffers) {
304cabdff1aSopenharmony_ci        opengl->glprocs.glDeleteBuffers(2, &opengl->index_buffer);
305cabdff1aSopenharmony_ci        opengl->vertex_buffer = opengl->index_buffer = 0;
306cabdff1aSopenharmony_ci    }
307cabdff1aSopenharmony_ci}
308cabdff1aSopenharmony_ci
309cabdff1aSopenharmony_cistatic int opengl_resize(AVFormatContext *h, int width, int height)
310cabdff1aSopenharmony_ci{
311cabdff1aSopenharmony_ci    int ret = 0;
312cabdff1aSopenharmony_ci    OpenGLContext *opengl = h->priv_data;
313cabdff1aSopenharmony_ci    opengl->window_width = width;
314cabdff1aSopenharmony_ci    opengl->window_height = height;
315cabdff1aSopenharmony_ci    if (opengl->inited) {
316cabdff1aSopenharmony_ci        if (opengl->no_window &&
317cabdff1aSopenharmony_ci            (ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0)) < 0) {
318cabdff1aSopenharmony_ci            av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n");
319cabdff1aSopenharmony_ci            goto end;
320cabdff1aSopenharmony_ci        }
321cabdff1aSopenharmony_ci        if ((ret = opengl_prepare_vertex(h)) < 0)
322cabdff1aSopenharmony_ci            goto end;
323cabdff1aSopenharmony_ci        ret = opengl_draw(h, NULL, 1, 0);
324cabdff1aSopenharmony_ci    }
325cabdff1aSopenharmony_ci  end:
326cabdff1aSopenharmony_ci    return ret;
327cabdff1aSopenharmony_ci}
328cabdff1aSopenharmony_ci
329cabdff1aSopenharmony_cistatic int opengl_control_message(AVFormatContext *h, int type, void *data, size_t data_size)
330cabdff1aSopenharmony_ci{
331cabdff1aSopenharmony_ci    OpenGLContext *opengl = h->priv_data;
332cabdff1aSopenharmony_ci    switch(type) {
333cabdff1aSopenharmony_ci    case AV_APP_TO_DEV_WINDOW_SIZE:
334cabdff1aSopenharmony_ci        if (data) {
335cabdff1aSopenharmony_ci            AVDeviceRect *message = data;
336cabdff1aSopenharmony_ci            return opengl_resize(h, message->width, message->height);
337cabdff1aSopenharmony_ci        }
338cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
339cabdff1aSopenharmony_ci    case AV_APP_TO_DEV_WINDOW_REPAINT:
340cabdff1aSopenharmony_ci        return opengl_resize(h, opengl->window_width, opengl->window_height);
341cabdff1aSopenharmony_ci    }
342cabdff1aSopenharmony_ci    return AVERROR(ENOSYS);
343cabdff1aSopenharmony_ci}
344cabdff1aSopenharmony_ci
345cabdff1aSopenharmony_ci#if CONFIG_SDL2
346cabdff1aSopenharmony_cistatic int opengl_sdl_process_events(AVFormatContext *h)
347cabdff1aSopenharmony_ci{
348cabdff1aSopenharmony_ci    OpenGLContext *opengl = h->priv_data;
349cabdff1aSopenharmony_ci    AVDeviceRect message;
350cabdff1aSopenharmony_ci    SDL_Event event;
351cabdff1aSopenharmony_ci    SDL_PumpEvents();
352cabdff1aSopenharmony_ci    while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT) > 0) {
353cabdff1aSopenharmony_ci        switch (event.type) {
354cabdff1aSopenharmony_ci        case SDL_QUIT:
355cabdff1aSopenharmony_ci            return AVERROR(EIO);
356cabdff1aSopenharmony_ci        case SDL_KEYDOWN:
357cabdff1aSopenharmony_ci            switch (event.key.keysym.sym) {
358cabdff1aSopenharmony_ci            case SDLK_ESCAPE:
359cabdff1aSopenharmony_ci            case SDLK_q:
360cabdff1aSopenharmony_ci                return AVERROR(EIO);
361cabdff1aSopenharmony_ci            }
362cabdff1aSopenharmony_ci            return 0;
363cabdff1aSopenharmony_ci        case SDL_WINDOWEVENT:
364cabdff1aSopenharmony_ci            switch(event.window.event) {
365cabdff1aSopenharmony_ci            case SDL_WINDOWEVENT_RESIZED:
366cabdff1aSopenharmony_ci            case SDL_WINDOWEVENT_SIZE_CHANGED:
367cabdff1aSopenharmony_ci                SDL_GL_GetDrawableSize(opengl->window, &message.width, &message.height);
368cabdff1aSopenharmony_ci                return opengl_control_message(h, AV_APP_TO_DEV_WINDOW_SIZE, &message, sizeof(AVDeviceRect));
369cabdff1aSopenharmony_ci            default:
370cabdff1aSopenharmony_ci                break;
371cabdff1aSopenharmony_ci            }
372cabdff1aSopenharmony_ci        }
373cabdff1aSopenharmony_ci    }
374cabdff1aSopenharmony_ci    return 0;
375cabdff1aSopenharmony_ci}
376cabdff1aSopenharmony_ci
377cabdff1aSopenharmony_cistatic int av_cold opengl_sdl_create_window(AVFormatContext *h)
378cabdff1aSopenharmony_ci{
379cabdff1aSopenharmony_ci    OpenGLContext *opengl = h->priv_data;
380cabdff1aSopenharmony_ci    AVDeviceRect message;
381cabdff1aSopenharmony_ci    if (SDL_Init(SDL_INIT_VIDEO)) {
382cabdff1aSopenharmony_ci        av_log(opengl, AV_LOG_ERROR, "Unable to initialize SDL: %s\n", SDL_GetError());
383cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
384cabdff1aSopenharmony_ci    }
385cabdff1aSopenharmony_ci    opengl->window = SDL_CreateWindow(opengl->window_title,
386cabdff1aSopenharmony_ci                                      SDL_WINDOWPOS_UNDEFINED,
387cabdff1aSopenharmony_ci                                      SDL_WINDOWPOS_UNDEFINED,
388cabdff1aSopenharmony_ci                                      opengl->window_width, opengl->window_height,
389cabdff1aSopenharmony_ci                                      SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL);
390cabdff1aSopenharmony_ci    if (!opengl->window) {
391cabdff1aSopenharmony_ci        av_log(opengl, AV_LOG_ERROR, "Unable to create default window: %s\n", SDL_GetError());
392cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
393cabdff1aSopenharmony_ci    }
394cabdff1aSopenharmony_ci    opengl->glcontext = SDL_GL_CreateContext(opengl->window);
395cabdff1aSopenharmony_ci    if (!opengl->glcontext) {
396cabdff1aSopenharmony_ci        av_log(opengl, AV_LOG_ERROR, "Unable to create OpenGL context on default window: %s\n", SDL_GetError());
397cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
398cabdff1aSopenharmony_ci    }
399cabdff1aSopenharmony_ci    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
400cabdff1aSopenharmony_ci    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
401cabdff1aSopenharmony_ci    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
402cabdff1aSopenharmony_ci    SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
403cabdff1aSopenharmony_ci    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
404cabdff1aSopenharmony_ci    av_log(opengl, AV_LOG_INFO, "SDL driver: '%s'.\n", SDL_GetCurrentVideoDriver());
405cabdff1aSopenharmony_ci    SDL_GL_GetDrawableSize(opengl->window, &message.width, &message.height);
406cabdff1aSopenharmony_ci    return opengl_control_message(h, AV_APP_TO_DEV_WINDOW_SIZE, &message, sizeof(AVDeviceRect));
407cabdff1aSopenharmony_ci}
408cabdff1aSopenharmony_ci
409cabdff1aSopenharmony_cistatic int av_cold opengl_sdl_load_procedures(OpenGLContext *opengl)
410cabdff1aSopenharmony_ci{
411cabdff1aSopenharmony_ci    FFOpenGLFunctions *procs = &opengl->glprocs;
412cabdff1aSopenharmony_ci
413cabdff1aSopenharmony_ci#define LOAD_OPENGL_FUN(name, type) \
414cabdff1aSopenharmony_ci    procs->name = (type)SDL_GL_GetProcAddress(#name); \
415cabdff1aSopenharmony_ci    if (!procs->name) { \
416cabdff1aSopenharmony_ci        av_log(opengl, AV_LOG_ERROR, "Cannot load OpenGL function: '%s'\n", #name); \
417cabdff1aSopenharmony_ci        return AVERROR(ENOSYS); \
418cabdff1aSopenharmony_ci    }
419cabdff1aSopenharmony_ci
420cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glActiveTexture, FF_PFNGLACTIVETEXTUREPROC)
421cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glGenBuffers, FF_PFNGLGENBUFFERSPROC)
422cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glDeleteBuffers, FF_PFNGLDELETEBUFFERSPROC)
423cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glBufferData, FF_PFNGLBUFFERDATAPROC)
424cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glBindBuffer, FF_PFNGLBINDBUFFERPROC)
425cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glGetAttribLocation, FF_PFNGLGETATTRIBLOCATIONPROC)
426cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glGetUniformLocation, FF_PFNGLGETUNIFORMLOCATIONPROC)
427cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glUniform1f, FF_PFNGLUNIFORM1FPROC)
428cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glUniform1i, FF_PFNGLUNIFORM1IPROC)
429cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glUniformMatrix4fv, FF_PFNGLUNIFORMMATRIX4FVPROC)
430cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glCreateProgram, FF_PFNGLCREATEPROGRAMPROC)
431cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glDeleteProgram, FF_PFNGLDELETEPROGRAMPROC)
432cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glUseProgram, FF_PFNGLUSEPROGRAMPROC)
433cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glLinkProgram, FF_PFNGLLINKPROGRAMPROC)
434cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glGetProgramiv, FF_PFNGLGETPROGRAMIVPROC)
435cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glGetProgramInfoLog, FF_PFNGLGETPROGRAMINFOLOGPROC)
436cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glAttachShader, FF_PFNGLATTACHSHADERPROC)
437cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glCreateShader, FF_PFNGLCREATESHADERPROC)
438cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glDeleteShader, FF_PFNGLDELETESHADERPROC)
439cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glCompileShader, FF_PFNGLCOMPILESHADERPROC)
440cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glShaderSource, FF_PFNGLSHADERSOURCEPROC)
441cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glGetShaderiv, FF_PFNGLGETSHADERIVPROC)
442cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glGetShaderInfoLog, FF_PFNGLGETSHADERINFOLOGPROC)
443cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glEnableVertexAttribArray, FF_PFNGLENABLEVERTEXATTRIBARRAYPROC)
444cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glVertexAttribPointer, FF_PFNGLVERTEXATTRIBPOINTERPROC)
445cabdff1aSopenharmony_ci
446cabdff1aSopenharmony_ci    return 0;
447cabdff1aSopenharmony_ci
448cabdff1aSopenharmony_ci#undef LOAD_OPENGL_FUN
449cabdff1aSopenharmony_ci}
450cabdff1aSopenharmony_ci#endif /* CONFIG_SDL2 */
451cabdff1aSopenharmony_ci
452cabdff1aSopenharmony_ci#if defined(__APPLE__)
453cabdff1aSopenharmony_cistatic int av_cold opengl_load_procedures(OpenGLContext *opengl)
454cabdff1aSopenharmony_ci{
455cabdff1aSopenharmony_ci    FFOpenGLFunctions *procs = &opengl->glprocs;
456cabdff1aSopenharmony_ci
457cabdff1aSopenharmony_ci#if CONFIG_SDL2
458cabdff1aSopenharmony_ci    if (!opengl->no_window)
459cabdff1aSopenharmony_ci        return opengl_sdl_load_procedures(opengl);
460cabdff1aSopenharmony_ci#endif
461cabdff1aSopenharmony_ci
462cabdff1aSopenharmony_ci    procs->glActiveTexture = glActiveTexture;
463cabdff1aSopenharmony_ci    procs->glGenBuffers = glGenBuffers;
464cabdff1aSopenharmony_ci    procs->glDeleteBuffers = glDeleteBuffers;
465cabdff1aSopenharmony_ci    procs->glBufferData = glBufferData;
466cabdff1aSopenharmony_ci    procs->glBindBuffer = glBindBuffer;
467cabdff1aSopenharmony_ci    procs->glGetAttribLocation = glGetAttribLocation;
468cabdff1aSopenharmony_ci    procs->glGetUniformLocation = glGetUniformLocation;
469cabdff1aSopenharmony_ci    procs->glUniform1f = glUniform1f;
470cabdff1aSopenharmony_ci    procs->glUniform1i = glUniform1i;
471cabdff1aSopenharmony_ci    procs->glUniformMatrix4fv = glUniformMatrix4fv;
472cabdff1aSopenharmony_ci    procs->glCreateProgram = glCreateProgram;
473cabdff1aSopenharmony_ci    procs->glDeleteProgram = glDeleteProgram;
474cabdff1aSopenharmony_ci    procs->glUseProgram = glUseProgram;
475cabdff1aSopenharmony_ci    procs->glLinkProgram = glLinkProgram;
476cabdff1aSopenharmony_ci    procs->glGetProgramiv = glGetProgramiv;
477cabdff1aSopenharmony_ci    procs->glGetProgramInfoLog = glGetProgramInfoLog;
478cabdff1aSopenharmony_ci    procs->glAttachShader = glAttachShader;
479cabdff1aSopenharmony_ci    procs->glCreateShader = glCreateShader;
480cabdff1aSopenharmony_ci    procs->glDeleteShader = glDeleteShader;
481cabdff1aSopenharmony_ci    procs->glCompileShader = glCompileShader;
482cabdff1aSopenharmony_ci    procs->glShaderSource = glShaderSource;
483cabdff1aSopenharmony_ci    procs->glGetShaderiv = glGetShaderiv;
484cabdff1aSopenharmony_ci    procs->glGetShaderInfoLog = glGetShaderInfoLog;
485cabdff1aSopenharmony_ci    procs->glEnableVertexAttribArray = glEnableVertexAttribArray;
486cabdff1aSopenharmony_ci    procs->glVertexAttribPointer = (FF_PFNGLVERTEXATTRIBPOINTERPROC) glVertexAttribPointer;
487cabdff1aSopenharmony_ci    return 0;
488cabdff1aSopenharmony_ci}
489cabdff1aSopenharmony_ci#else
490cabdff1aSopenharmony_cistatic int av_cold opengl_load_procedures(OpenGLContext *opengl)
491cabdff1aSopenharmony_ci{
492cabdff1aSopenharmony_ci    FFOpenGLFunctions *procs = &opengl->glprocs;
493cabdff1aSopenharmony_ci
494cabdff1aSopenharmony_ci#if HAVE_GLXGETPROCADDRESS
495cabdff1aSopenharmony_ci#define SelectedGetProcAddress glXGetProcAddress
496cabdff1aSopenharmony_ci#elif HAVE_WGLGETPROCADDRESS
497cabdff1aSopenharmony_ci#define SelectedGetProcAddress wglGetProcAddress
498cabdff1aSopenharmony_ci#endif
499cabdff1aSopenharmony_ci
500cabdff1aSopenharmony_ci#define LOAD_OPENGL_FUN(name, type) \
501cabdff1aSopenharmony_ci    procs->name = (type)SelectedGetProcAddress(#name); \
502cabdff1aSopenharmony_ci    if (!procs->name) { \
503cabdff1aSopenharmony_ci        av_log(opengl, AV_LOG_ERROR, "Cannot load OpenGL function: '%s'\n", #name); \
504cabdff1aSopenharmony_ci        return AVERROR(ENOSYS); \
505cabdff1aSopenharmony_ci    }
506cabdff1aSopenharmony_ci
507cabdff1aSopenharmony_ci#if CONFIG_SDL2
508cabdff1aSopenharmony_ci    if (!opengl->no_window)
509cabdff1aSopenharmony_ci        return opengl_sdl_load_procedures(opengl);
510cabdff1aSopenharmony_ci#endif
511cabdff1aSopenharmony_ci
512cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glActiveTexture, FF_PFNGLACTIVETEXTUREPROC)
513cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glGenBuffers, FF_PFNGLGENBUFFERSPROC)
514cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glDeleteBuffers, FF_PFNGLDELETEBUFFERSPROC)
515cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glBufferData, FF_PFNGLBUFFERDATAPROC)
516cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glBindBuffer, FF_PFNGLBINDBUFFERPROC)
517cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glGetAttribLocation, FF_PFNGLGETATTRIBLOCATIONPROC)
518cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glGetUniformLocation, FF_PFNGLGETUNIFORMLOCATIONPROC)
519cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glUniform1f, FF_PFNGLUNIFORM1FPROC)
520cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glUniform1i, FF_PFNGLUNIFORM1IPROC)
521cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glUniformMatrix4fv, FF_PFNGLUNIFORMMATRIX4FVPROC)
522cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glCreateProgram, FF_PFNGLCREATEPROGRAMPROC)
523cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glDeleteProgram, FF_PFNGLDELETEPROGRAMPROC)
524cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glUseProgram, FF_PFNGLUSEPROGRAMPROC)
525cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glLinkProgram, FF_PFNGLLINKPROGRAMPROC)
526cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glGetProgramiv, FF_PFNGLGETPROGRAMIVPROC)
527cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glGetProgramInfoLog, FF_PFNGLGETPROGRAMINFOLOGPROC)
528cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glAttachShader, FF_PFNGLATTACHSHADERPROC)
529cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glCreateShader, FF_PFNGLCREATESHADERPROC)
530cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glDeleteShader, FF_PFNGLDELETESHADERPROC)
531cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glCompileShader, FF_PFNGLCOMPILESHADERPROC)
532cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glShaderSource, FF_PFNGLSHADERSOURCEPROC)
533cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glGetShaderiv, FF_PFNGLGETSHADERIVPROC)
534cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glGetShaderInfoLog, FF_PFNGLGETSHADERINFOLOGPROC)
535cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glEnableVertexAttribArray, FF_PFNGLENABLEVERTEXATTRIBARRAYPROC)
536cabdff1aSopenharmony_ci    LOAD_OPENGL_FUN(glVertexAttribPointer, FF_PFNGLVERTEXATTRIBPOINTERPROC)
537cabdff1aSopenharmony_ci
538cabdff1aSopenharmony_ci    return 0;
539cabdff1aSopenharmony_ci
540cabdff1aSopenharmony_ci#undef SelectedGetProcAddress
541cabdff1aSopenharmony_ci#undef LOAD_OPENGL_FUN
542cabdff1aSopenharmony_ci}
543cabdff1aSopenharmony_ci#endif
544cabdff1aSopenharmony_ci
545cabdff1aSopenharmony_cistatic void opengl_make_identity(float matrix[16])
546cabdff1aSopenharmony_ci{
547cabdff1aSopenharmony_ci    memset(matrix, 0, 16 * sizeof(float));
548cabdff1aSopenharmony_ci    matrix[0] = matrix[5] = matrix[10] = matrix[15] = 1.0f;
549cabdff1aSopenharmony_ci}
550cabdff1aSopenharmony_ci
551cabdff1aSopenharmony_cistatic void opengl_make_ortho(float matrix[16], float left, float right,
552cabdff1aSopenharmony_ci                              float bottom, float top, float nearZ, float farZ)
553cabdff1aSopenharmony_ci{
554cabdff1aSopenharmony_ci    float ral = right + left;
555cabdff1aSopenharmony_ci    float rsl = right - left;
556cabdff1aSopenharmony_ci    float tab = top + bottom;
557cabdff1aSopenharmony_ci    float tsb = top - bottom;
558cabdff1aSopenharmony_ci    float fan = farZ + nearZ;
559cabdff1aSopenharmony_ci    float fsn = farZ - nearZ;
560cabdff1aSopenharmony_ci
561cabdff1aSopenharmony_ci    memset(matrix, 0, 16 * sizeof(float));
562cabdff1aSopenharmony_ci    matrix[0] = 2.0f / rsl;
563cabdff1aSopenharmony_ci    matrix[5] = 2.0f / tsb;
564cabdff1aSopenharmony_ci    matrix[10] = -2.0f / fsn;
565cabdff1aSopenharmony_ci    matrix[12] = -ral / rsl;
566cabdff1aSopenharmony_ci    matrix[13] = -tab / tsb;
567cabdff1aSopenharmony_ci    matrix[14] = -fan / fsn;
568cabdff1aSopenharmony_ci    matrix[15] = 1.0f;
569cabdff1aSopenharmony_ci}
570cabdff1aSopenharmony_ci
571cabdff1aSopenharmony_cistatic av_cold int opengl_read_limits(AVFormatContext *h)
572cabdff1aSopenharmony_ci{
573cabdff1aSopenharmony_ci    OpenGLContext *opengl = h->priv_data;
574cabdff1aSopenharmony_ci    static const struct{
575cabdff1aSopenharmony_ci        const char *extension;
576cabdff1aSopenharmony_ci        int major;
577cabdff1aSopenharmony_ci        int minor;
578cabdff1aSopenharmony_ci    } required_extensions[] = {
579cabdff1aSopenharmony_ci        { "GL_ARB_multitexture",         1, 3 },
580cabdff1aSopenharmony_ci        { "GL_ARB_vertex_buffer_object", 1, 5 }, //GLX_ARB_vertex_buffer_object
581cabdff1aSopenharmony_ci        { "GL_ARB_vertex_shader",        2, 0 },
582cabdff1aSopenharmony_ci        { "GL_ARB_fragment_shader",      2, 0 },
583cabdff1aSopenharmony_ci        { "GL_ARB_shader_objects",       2, 0 },
584cabdff1aSopenharmony_ci        { NULL,                          0, 0 }
585cabdff1aSopenharmony_ci    };
586cabdff1aSopenharmony_ci    int i, major, minor;
587cabdff1aSopenharmony_ci    const char *extensions, *version;
588cabdff1aSopenharmony_ci
589cabdff1aSopenharmony_ci    version = glGetString(GL_VERSION);
590cabdff1aSopenharmony_ci    extensions = glGetString(GL_EXTENSIONS);
591cabdff1aSopenharmony_ci    if (!version || !extensions) {
592cabdff1aSopenharmony_ci        av_log(h, AV_LOG_ERROR, "No OpenGL context initialized for the current thread\n");
593cabdff1aSopenharmony_ci        return AVERROR(ENOSYS);
594cabdff1aSopenharmony_ci    }
595cabdff1aSopenharmony_ci
596cabdff1aSopenharmony_ci    av_log(h, AV_LOG_DEBUG, "OpenGL version: %s\n", version);
597cabdff1aSopenharmony_ci    sscanf(version, "%d.%d", &major, &minor);
598cabdff1aSopenharmony_ci
599cabdff1aSopenharmony_ci    for (i = 0; required_extensions[i].extension; i++) {
600cabdff1aSopenharmony_ci        if (major < required_extensions[i].major &&
601cabdff1aSopenharmony_ci            (major == required_extensions[i].major && minor < required_extensions[i].minor) &&
602cabdff1aSopenharmony_ci            !strstr(extensions, required_extensions[i].extension)) {
603cabdff1aSopenharmony_ci            av_log(h, AV_LOG_ERROR, "Required extension %s is not supported.\n",
604cabdff1aSopenharmony_ci                   required_extensions[i].extension);
605cabdff1aSopenharmony_ci            av_log(h, AV_LOG_DEBUG, "Supported extensions are: %s\n", extensions);
606cabdff1aSopenharmony_ci            return AVERROR(ENOSYS);
607cabdff1aSopenharmony_ci        }
608cabdff1aSopenharmony_ci    }
609cabdff1aSopenharmony_ci    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &opengl->max_texture_size);
610cabdff1aSopenharmony_ci    glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &opengl->max_viewport_width);
611cabdff1aSopenharmony_ci    opengl->non_pow_2_textures = major >= 2 || strstr(extensions, "GL_ARB_texture_non_power_of_two");
612cabdff1aSopenharmony_ci#if defined(GL_ES_VERSION_2_0)
613cabdff1aSopenharmony_ci    opengl->unpack_subimage = !!strstr(extensions, "GL_EXT_unpack_subimage");
614cabdff1aSopenharmony_ci#else
615cabdff1aSopenharmony_ci    opengl->unpack_subimage = 1;
616cabdff1aSopenharmony_ci#endif
617cabdff1aSopenharmony_ci
618cabdff1aSopenharmony_ci    av_log(h, AV_LOG_DEBUG, "Non Power of 2 textures support: %s\n", opengl->non_pow_2_textures ? "Yes" : "No");
619cabdff1aSopenharmony_ci    av_log(h, AV_LOG_DEBUG, "Unpack Subimage extension support: %s\n", opengl->unpack_subimage ? "Yes" : "No");
620cabdff1aSopenharmony_ci    av_log(h, AV_LOG_DEBUG, "Max texture size: %dx%d\n", opengl->max_texture_size, opengl->max_texture_size);
621cabdff1aSopenharmony_ci    av_log(h, AV_LOG_DEBUG, "Max viewport size: %dx%d\n",
622cabdff1aSopenharmony_ci           opengl->max_viewport_width, opengl->max_viewport_height);
623cabdff1aSopenharmony_ci
624cabdff1aSopenharmony_ci    OPENGL_ERROR_CHECK(opengl);
625cabdff1aSopenharmony_ci    return 0;
626cabdff1aSopenharmony_ci  fail:
627cabdff1aSopenharmony_ci    return AVERROR_EXTERNAL;
628cabdff1aSopenharmony_ci}
629cabdff1aSopenharmony_ci
630cabdff1aSopenharmony_cistatic const char* opengl_get_fragment_shader_code(enum AVPixelFormat format)
631cabdff1aSopenharmony_ci{
632cabdff1aSopenharmony_ci    int i;
633cabdff1aSopenharmony_ci    for (i = 0; i < FF_ARRAY_ELEMS(opengl_format_desc); i++) {
634cabdff1aSopenharmony_ci        if (opengl_format_desc[i].fixel_format == format)
635cabdff1aSopenharmony_ci            return *opengl_format_desc[i].fragment_shader;
636cabdff1aSopenharmony_ci    }
637cabdff1aSopenharmony_ci    return NULL;
638cabdff1aSopenharmony_ci}
639cabdff1aSopenharmony_ci
640cabdff1aSopenharmony_cistatic int opengl_type_size(GLenum type)
641cabdff1aSopenharmony_ci{
642cabdff1aSopenharmony_ci    switch(type) {
643cabdff1aSopenharmony_ci    case GL_UNSIGNED_SHORT:
644cabdff1aSopenharmony_ci    case FF_GL_UNSIGNED_SHORT_1_5_5_5_REV:
645cabdff1aSopenharmony_ci    case GL_UNSIGNED_SHORT_5_6_5:
646cabdff1aSopenharmony_ci        return 2;
647cabdff1aSopenharmony_ci    case GL_UNSIGNED_BYTE:
648cabdff1aSopenharmony_ci    case FF_GL_UNSIGNED_BYTE_3_3_2:
649cabdff1aSopenharmony_ci    case FF_GL_UNSIGNED_BYTE_2_3_3_REV:
650cabdff1aSopenharmony_ci    default:
651cabdff1aSopenharmony_ci        break;
652cabdff1aSopenharmony_ci    }
653cabdff1aSopenharmony_ci    return 1;
654cabdff1aSopenharmony_ci}
655cabdff1aSopenharmony_ci
656cabdff1aSopenharmony_cistatic av_cold void opengl_get_texture_params(OpenGLContext *opengl)
657cabdff1aSopenharmony_ci{
658cabdff1aSopenharmony_ci    int i;
659cabdff1aSopenharmony_ci    for (i = 0; i < FF_ARRAY_ELEMS(opengl_format_desc); i++) {
660cabdff1aSopenharmony_ci        if (opengl_format_desc[i].fixel_format == opengl->pix_fmt) {
661cabdff1aSopenharmony_ci            opengl->format = opengl_format_desc[i].format;
662cabdff1aSopenharmony_ci            opengl->type = opengl_format_desc[i].type;
663cabdff1aSopenharmony_ci            break;
664cabdff1aSopenharmony_ci        }
665cabdff1aSopenharmony_ci    }
666cabdff1aSopenharmony_ci}
667cabdff1aSopenharmony_ci
668cabdff1aSopenharmony_cistatic void opengl_compute_display_area(AVFormatContext *s)
669cabdff1aSopenharmony_ci{
670cabdff1aSopenharmony_ci    AVRational sar, dar; /* sample and display aspect ratios */
671cabdff1aSopenharmony_ci    OpenGLContext *opengl = s->priv_data;
672cabdff1aSopenharmony_ci    AVStream *st = s->streams[0];
673cabdff1aSopenharmony_ci    AVCodecParameters *par = st->codecpar;
674cabdff1aSopenharmony_ci
675cabdff1aSopenharmony_ci    /* compute overlay width and height from the codec context information */
676cabdff1aSopenharmony_ci    sar = st->sample_aspect_ratio.num ? st->sample_aspect_ratio : (AVRational){ 1, 1 };
677cabdff1aSopenharmony_ci    dar = av_mul_q(sar, (AVRational){ par->width, par->height });
678cabdff1aSopenharmony_ci
679cabdff1aSopenharmony_ci    /* we suppose the screen has a 1/1 sample aspect ratio */
680cabdff1aSopenharmony_ci    /* fit in the window */
681cabdff1aSopenharmony_ci    if (av_cmp_q(dar, (AVRational){ opengl->window_width, opengl->window_height }) > 0) {
682cabdff1aSopenharmony_ci        /* fit in width */
683cabdff1aSopenharmony_ci        opengl->picture_width = opengl->window_width;
684cabdff1aSopenharmony_ci        opengl->picture_height = av_rescale(opengl->picture_width, dar.den, dar.num);
685cabdff1aSopenharmony_ci    } else {
686cabdff1aSopenharmony_ci        /* fit in height */
687cabdff1aSopenharmony_ci        opengl->picture_height = opengl->window_height;
688cabdff1aSopenharmony_ci        opengl->picture_width = av_rescale(opengl->picture_height, dar.num, dar.den);
689cabdff1aSopenharmony_ci    }
690cabdff1aSopenharmony_ci}
691cabdff1aSopenharmony_ci
692cabdff1aSopenharmony_cistatic av_cold void opengl_get_texture_size(OpenGLContext *opengl, int in_width, int in_height,
693cabdff1aSopenharmony_ci                                            int *out_width, int *out_height)
694cabdff1aSopenharmony_ci{
695cabdff1aSopenharmony_ci    if (opengl->non_pow_2_textures) {
696cabdff1aSopenharmony_ci        *out_width = in_width;
697cabdff1aSopenharmony_ci        *out_height = in_height;
698cabdff1aSopenharmony_ci    } else {
699cabdff1aSopenharmony_ci        int max = FFMIN(FFMAX(in_width, in_height), opengl->max_texture_size);
700cabdff1aSopenharmony_ci        unsigned power_of_2 = 1;
701cabdff1aSopenharmony_ci        while (power_of_2 < max)
702cabdff1aSopenharmony_ci            power_of_2 *= 2;
703cabdff1aSopenharmony_ci        *out_height = power_of_2;
704cabdff1aSopenharmony_ci        *out_width = power_of_2;
705cabdff1aSopenharmony_ci        av_log(opengl, AV_LOG_DEBUG, "Texture size calculated from %dx%d into %dx%d\n",
706cabdff1aSopenharmony_ci               in_width, in_height, *out_width, *out_height);
707cabdff1aSopenharmony_ci    }
708cabdff1aSopenharmony_ci}
709cabdff1aSopenharmony_ci
710cabdff1aSopenharmony_cistatic av_cold void opengl_fill_color_map(OpenGLContext *opengl)
711cabdff1aSopenharmony_ci{
712cabdff1aSopenharmony_ci    const AVPixFmtDescriptor *desc;
713cabdff1aSopenharmony_ci    int shift;
714cabdff1aSopenharmony_ci    enum AVPixelFormat pix_fmt = opengl->pix_fmt;
715cabdff1aSopenharmony_ci
716cabdff1aSopenharmony_ci    /* We need order of components, not exact position, some minor HACKs here */
717cabdff1aSopenharmony_ci    if (pix_fmt == AV_PIX_FMT_RGB565 || pix_fmt == AV_PIX_FMT_BGR555 ||
718cabdff1aSopenharmony_ci        pix_fmt == AV_PIX_FMT_BGR8   || pix_fmt == AV_PIX_FMT_RGB8)
719cabdff1aSopenharmony_ci        pix_fmt = AV_PIX_FMT_RGB24;
720cabdff1aSopenharmony_ci    else if (pix_fmt == AV_PIX_FMT_BGR565 || pix_fmt == AV_PIX_FMT_RGB555)
721cabdff1aSopenharmony_ci        pix_fmt = AV_PIX_FMT_BGR24;
722cabdff1aSopenharmony_ci
723cabdff1aSopenharmony_ci    desc = av_pix_fmt_desc_get(pix_fmt);
724cabdff1aSopenharmony_ci    if (!(desc->flags & AV_PIX_FMT_FLAG_RGB))
725cabdff1aSopenharmony_ci        return;
726cabdff1aSopenharmony_ci
727cabdff1aSopenharmony_ci#define FILL_COMPONENT(i) { \
728cabdff1aSopenharmony_ci        shift = (desc->comp[i].depth - 1) >> 3; \
729cabdff1aSopenharmony_ci        opengl->color_map[(i << 2) + (desc->comp[i].offset >> shift)] = 1.0; \
730cabdff1aSopenharmony_ci    }
731cabdff1aSopenharmony_ci
732cabdff1aSopenharmony_ci    memset(opengl->color_map, 0, sizeof(opengl->color_map));
733cabdff1aSopenharmony_ci    FILL_COMPONENT(0);
734cabdff1aSopenharmony_ci    FILL_COMPONENT(1);
735cabdff1aSopenharmony_ci    FILL_COMPONENT(2);
736cabdff1aSopenharmony_ci    if (desc->flags & AV_PIX_FMT_FLAG_ALPHA)
737cabdff1aSopenharmony_ci        FILL_COMPONENT(3);
738cabdff1aSopenharmony_ci
739cabdff1aSopenharmony_ci#undef FILL_COMPONENT
740cabdff1aSopenharmony_ci}
741cabdff1aSopenharmony_ci
742cabdff1aSopenharmony_cistatic av_cold GLuint opengl_load_shader(OpenGLContext *opengl, GLenum type, const char *source)
743cabdff1aSopenharmony_ci{
744cabdff1aSopenharmony_ci    GLuint shader = opengl->glprocs.glCreateShader(type);
745cabdff1aSopenharmony_ci    GLint result;
746cabdff1aSopenharmony_ci    if (!shader) {
747cabdff1aSopenharmony_ci        av_log(opengl, AV_LOG_ERROR, "glCreateShader() failed\n");
748cabdff1aSopenharmony_ci        return 0;
749cabdff1aSopenharmony_ci    }
750cabdff1aSopenharmony_ci    opengl->glprocs.glShaderSource(shader, 1, &source, NULL);
751cabdff1aSopenharmony_ci    opengl->glprocs.glCompileShader(shader);
752cabdff1aSopenharmony_ci
753cabdff1aSopenharmony_ci    opengl->glprocs.glGetShaderiv(shader, FF_GL_COMPILE_STATUS, &result);
754cabdff1aSopenharmony_ci    if (!result) {
755cabdff1aSopenharmony_ci        char *log;
756cabdff1aSopenharmony_ci        opengl->glprocs.glGetShaderiv(shader, FF_GL_INFO_LOG_LENGTH, &result);
757cabdff1aSopenharmony_ci        if (result) {
758cabdff1aSopenharmony_ci            if ((log = av_malloc(result))) {
759cabdff1aSopenharmony_ci                opengl->glprocs.glGetShaderInfoLog(shader, result, NULL, log);
760cabdff1aSopenharmony_ci                av_log(opengl, AV_LOG_ERROR, "Compile error: %s\n", log);
761cabdff1aSopenharmony_ci                av_free(log);
762cabdff1aSopenharmony_ci            }
763cabdff1aSopenharmony_ci        }
764cabdff1aSopenharmony_ci        goto fail;
765cabdff1aSopenharmony_ci    }
766cabdff1aSopenharmony_ci    OPENGL_ERROR_CHECK(opengl);
767cabdff1aSopenharmony_ci    return shader;
768cabdff1aSopenharmony_ci  fail:
769cabdff1aSopenharmony_ci    opengl->glprocs.glDeleteShader(shader);
770cabdff1aSopenharmony_ci    return 0;
771cabdff1aSopenharmony_ci}
772cabdff1aSopenharmony_ci
773cabdff1aSopenharmony_cistatic av_cold int opengl_compile_shaders(OpenGLContext *opengl, enum AVPixelFormat pix_fmt)
774cabdff1aSopenharmony_ci{
775cabdff1aSopenharmony_ci    GLint result;
776cabdff1aSopenharmony_ci    const char *fragment_shader_code = opengl_get_fragment_shader_code(pix_fmt);
777cabdff1aSopenharmony_ci
778cabdff1aSopenharmony_ci    if (!fragment_shader_code) {
779cabdff1aSopenharmony_ci        av_log(opengl, AV_LOG_ERROR, "Provided pixel format '%s' is not supported\n",
780cabdff1aSopenharmony_ci               av_get_pix_fmt_name(pix_fmt));
781cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
782cabdff1aSopenharmony_ci    }
783cabdff1aSopenharmony_ci
784cabdff1aSopenharmony_ci    opengl->vertex_shader = opengl_load_shader(opengl, FF_GL_VERTEX_SHADER,
785cabdff1aSopenharmony_ci                                               FF_OPENGL_VERTEX_SHADER);
786cabdff1aSopenharmony_ci    if (!opengl->vertex_shader) {
787cabdff1aSopenharmony_ci        av_log(opengl, AV_LOG_ERROR, "Vertex shader loading failed.\n");
788cabdff1aSopenharmony_ci        goto fail;
789cabdff1aSopenharmony_ci    }
790cabdff1aSopenharmony_ci    opengl->fragment_shader = opengl_load_shader(opengl, FF_GL_FRAGMENT_SHADER,
791cabdff1aSopenharmony_ci                                                 fragment_shader_code);
792cabdff1aSopenharmony_ci    if (!opengl->fragment_shader) {
793cabdff1aSopenharmony_ci        av_log(opengl, AV_LOG_ERROR, "Fragment shader loading failed.\n");
794cabdff1aSopenharmony_ci        goto fail;
795cabdff1aSopenharmony_ci    }
796cabdff1aSopenharmony_ci
797cabdff1aSopenharmony_ci    opengl->program = opengl->glprocs.glCreateProgram();
798cabdff1aSopenharmony_ci    if (!opengl->program)
799cabdff1aSopenharmony_ci        goto fail;
800cabdff1aSopenharmony_ci
801cabdff1aSopenharmony_ci    opengl->glprocs.glAttachShader(opengl->program, opengl->vertex_shader);
802cabdff1aSopenharmony_ci    opengl->glprocs.glAttachShader(opengl->program, opengl->fragment_shader);
803cabdff1aSopenharmony_ci    opengl->glprocs.glLinkProgram(opengl->program);
804cabdff1aSopenharmony_ci
805cabdff1aSopenharmony_ci    opengl->glprocs.glGetProgramiv(opengl->program, FF_GL_LINK_STATUS, &result);
806cabdff1aSopenharmony_ci    if (!result) {
807cabdff1aSopenharmony_ci        char *log;
808cabdff1aSopenharmony_ci        opengl->glprocs.glGetProgramiv(opengl->program, FF_GL_INFO_LOG_LENGTH, &result);
809cabdff1aSopenharmony_ci        if (result) {
810cabdff1aSopenharmony_ci            log = av_malloc(result);
811cabdff1aSopenharmony_ci            if (!log)
812cabdff1aSopenharmony_ci                goto fail;
813cabdff1aSopenharmony_ci            opengl->glprocs.glGetProgramInfoLog(opengl->program, result, NULL, log);
814cabdff1aSopenharmony_ci            av_log(opengl, AV_LOG_ERROR, "Link error: %s\n", log);
815cabdff1aSopenharmony_ci            av_free(log);
816cabdff1aSopenharmony_ci        }
817cabdff1aSopenharmony_ci        goto fail;
818cabdff1aSopenharmony_ci    }
819cabdff1aSopenharmony_ci
820cabdff1aSopenharmony_ci    opengl->position_attrib = opengl->glprocs.glGetAttribLocation(opengl->program, "a_position");
821cabdff1aSopenharmony_ci    opengl->texture_coords_attrib = opengl->glprocs.glGetAttribLocation(opengl->program, "a_textureCoords");
822cabdff1aSopenharmony_ci    opengl->projection_matrix_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_projectionMatrix");
823cabdff1aSopenharmony_ci    opengl->model_view_matrix_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_modelViewMatrix");
824cabdff1aSopenharmony_ci    opengl->color_map_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_colorMap");
825cabdff1aSopenharmony_ci    opengl->texture_location[0] = opengl->glprocs.glGetUniformLocation(opengl->program, "u_texture0");
826cabdff1aSopenharmony_ci    opengl->texture_location[1] = opengl->glprocs.glGetUniformLocation(opengl->program, "u_texture1");
827cabdff1aSopenharmony_ci    opengl->texture_location[2] = opengl->glprocs.glGetUniformLocation(opengl->program, "u_texture2");
828cabdff1aSopenharmony_ci    opengl->texture_location[3] = opengl->glprocs.glGetUniformLocation(opengl->program, "u_texture3");
829cabdff1aSopenharmony_ci    opengl->chroma_div_w_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_chroma_div_w");
830cabdff1aSopenharmony_ci    opengl->chroma_div_h_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_chroma_div_h");
831cabdff1aSopenharmony_ci
832cabdff1aSopenharmony_ci    OPENGL_ERROR_CHECK(opengl);
833cabdff1aSopenharmony_ci    return 0;
834cabdff1aSopenharmony_ci  fail:
835cabdff1aSopenharmony_ci    opengl->glprocs.glDeleteShader(opengl->vertex_shader);
836cabdff1aSopenharmony_ci    opengl->glprocs.glDeleteShader(opengl->fragment_shader);
837cabdff1aSopenharmony_ci    opengl->glprocs.glDeleteProgram(opengl->program);
838cabdff1aSopenharmony_ci    opengl->fragment_shader = opengl->vertex_shader = opengl->program = 0;
839cabdff1aSopenharmony_ci    return AVERROR_EXTERNAL;
840cabdff1aSopenharmony_ci}
841cabdff1aSopenharmony_ci
842cabdff1aSopenharmony_cistatic av_cold int opengl_configure_texture(OpenGLContext *opengl, GLuint texture,
843cabdff1aSopenharmony_ci                                            GLsizei width, GLsizei height)
844cabdff1aSopenharmony_ci{
845cabdff1aSopenharmony_ci    if (texture) {
846cabdff1aSopenharmony_ci        int new_width, new_height;
847cabdff1aSopenharmony_ci        opengl_get_texture_size(opengl, width, height, &new_width, &new_height);
848cabdff1aSopenharmony_ci        glBindTexture(GL_TEXTURE_2D, texture);
849cabdff1aSopenharmony_ci        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
850cabdff1aSopenharmony_ci        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
851cabdff1aSopenharmony_ci        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
852cabdff1aSopenharmony_ci        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
853cabdff1aSopenharmony_ci        glTexImage2D(GL_TEXTURE_2D, 0, opengl->format, new_width, new_height, 0,
854cabdff1aSopenharmony_ci                     opengl->format, opengl->type, NULL);
855cabdff1aSopenharmony_ci        OPENGL_ERROR_CHECK(NULL);
856cabdff1aSopenharmony_ci    }
857cabdff1aSopenharmony_ci    return 0;
858cabdff1aSopenharmony_ci  fail:
859cabdff1aSopenharmony_ci    return AVERROR_EXTERNAL;
860cabdff1aSopenharmony_ci}
861cabdff1aSopenharmony_ci
862cabdff1aSopenharmony_cistatic av_cold int opengl_prepare_vertex(AVFormatContext *s)
863cabdff1aSopenharmony_ci{
864cabdff1aSopenharmony_ci    OpenGLContext *opengl = s->priv_data;
865cabdff1aSopenharmony_ci    int tex_w, tex_h;
866cabdff1aSopenharmony_ci
867cabdff1aSopenharmony_ci    if (opengl->window_width > opengl->max_viewport_width || opengl->window_height > opengl->max_viewport_height) {
868cabdff1aSopenharmony_ci        opengl->window_width = FFMIN(opengl->window_width, opengl->max_viewport_width);
869cabdff1aSopenharmony_ci        opengl->window_height = FFMIN(opengl->window_height, opengl->max_viewport_height);
870cabdff1aSopenharmony_ci        av_log(opengl, AV_LOG_WARNING, "Too big viewport requested, limited to %dx%d", opengl->window_width, opengl->window_height);
871cabdff1aSopenharmony_ci    }
872cabdff1aSopenharmony_ci    glViewport(0, 0, opengl->window_width, opengl->window_height);
873cabdff1aSopenharmony_ci    opengl_make_ortho(opengl->projection_matrix,
874cabdff1aSopenharmony_ci                      - (float)opengl->window_width  / 2.0f, (float)opengl->window_width  / 2.0f,
875cabdff1aSopenharmony_ci                      - (float)opengl->window_height / 2.0f, (float)opengl->window_height / 2.0f,
876cabdff1aSopenharmony_ci                      1.0f, -1.0f);
877cabdff1aSopenharmony_ci    opengl_make_identity(opengl->model_view_matrix);
878cabdff1aSopenharmony_ci
879cabdff1aSopenharmony_ci    opengl_compute_display_area(s);
880cabdff1aSopenharmony_ci
881cabdff1aSopenharmony_ci    opengl->vertex[0].z = opengl->vertex[1].z = opengl->vertex[2].z = opengl->vertex[3].z = 0.0f;
882cabdff1aSopenharmony_ci    opengl->vertex[0].x = opengl->vertex[1].x = - (float)opengl->picture_width / 2.0f;
883cabdff1aSopenharmony_ci    opengl->vertex[2].x = opengl->vertex[3].x =   (float)opengl->picture_width / 2.0f;
884cabdff1aSopenharmony_ci    opengl->vertex[1].y = opengl->vertex[2].y = - (float)opengl->picture_height / 2.0f;
885cabdff1aSopenharmony_ci    opengl->vertex[0].y = opengl->vertex[3].y =   (float)opengl->picture_height / 2.0f;
886cabdff1aSopenharmony_ci
887cabdff1aSopenharmony_ci    opengl_get_texture_size(opengl, opengl->width, opengl->height, &tex_w, &tex_h);
888cabdff1aSopenharmony_ci
889cabdff1aSopenharmony_ci    opengl->vertex[0].s0 = 0.0f;
890cabdff1aSopenharmony_ci    opengl->vertex[0].t0 = 0.0f;
891cabdff1aSopenharmony_ci    opengl->vertex[1].s0 = 0.0f;
892cabdff1aSopenharmony_ci    opengl->vertex[1].t0 = (float)opengl->height / (float)tex_h;
893cabdff1aSopenharmony_ci    opengl->vertex[2].s0 = (float)opengl->width  / (float)tex_w;
894cabdff1aSopenharmony_ci    opengl->vertex[2].t0 = (float)opengl->height / (float)tex_h;
895cabdff1aSopenharmony_ci    opengl->vertex[3].s0 = (float)opengl->width  / (float)tex_w;
896cabdff1aSopenharmony_ci    opengl->vertex[3].t0 = 0.0f;
897cabdff1aSopenharmony_ci
898cabdff1aSopenharmony_ci    opengl->glprocs.glBindBuffer(FF_GL_ARRAY_BUFFER, opengl->vertex_buffer);
899cabdff1aSopenharmony_ci    opengl->glprocs.glBufferData(FF_GL_ARRAY_BUFFER, sizeof(opengl->vertex), opengl->vertex, FF_GL_STATIC_DRAW);
900cabdff1aSopenharmony_ci    opengl->glprocs.glBindBuffer(FF_GL_ARRAY_BUFFER, 0);
901cabdff1aSopenharmony_ci    OPENGL_ERROR_CHECK(opengl);
902cabdff1aSopenharmony_ci    return 0;
903cabdff1aSopenharmony_ci  fail:
904cabdff1aSopenharmony_ci    return AVERROR_EXTERNAL;
905cabdff1aSopenharmony_ci}
906cabdff1aSopenharmony_ci
907cabdff1aSopenharmony_cistatic int opengl_prepare(OpenGLContext *opengl)
908cabdff1aSopenharmony_ci{
909cabdff1aSopenharmony_ci    int i;
910cabdff1aSopenharmony_ci    opengl->glprocs.glUseProgram(opengl->program);
911cabdff1aSopenharmony_ci    opengl->glprocs.glUniformMatrix4fv(opengl->projection_matrix_location, 1, GL_FALSE, opengl->projection_matrix);
912cabdff1aSopenharmony_ci    opengl->glprocs.glUniformMatrix4fv(opengl->model_view_matrix_location, 1, GL_FALSE, opengl->model_view_matrix);
913cabdff1aSopenharmony_ci    for (i = 0; i < 4; i++)
914cabdff1aSopenharmony_ci        if (opengl->texture_location[i] != -1) {
915cabdff1aSopenharmony_ci            opengl->glprocs.glActiveTexture(GL_TEXTURE0 + i);
916cabdff1aSopenharmony_ci            glBindTexture(GL_TEXTURE_2D, opengl->texture_name[i]);
917cabdff1aSopenharmony_ci            opengl->glprocs.glUniform1i(opengl->texture_location[i], i);
918cabdff1aSopenharmony_ci        }
919cabdff1aSopenharmony_ci    if (opengl->color_map_location != -1)
920cabdff1aSopenharmony_ci        opengl->glprocs.glUniformMatrix4fv(opengl->color_map_location, 1, GL_FALSE, opengl->color_map);
921cabdff1aSopenharmony_ci    if (opengl->chroma_div_h_location != -1)
922cabdff1aSopenharmony_ci        opengl->glprocs.glUniform1f(opengl->chroma_div_h_location, opengl->chroma_div_h);
923cabdff1aSopenharmony_ci    if (opengl->chroma_div_w_location != -1)
924cabdff1aSopenharmony_ci        opengl->glprocs.glUniform1f(opengl->chroma_div_w_location, opengl->chroma_div_w);
925cabdff1aSopenharmony_ci
926cabdff1aSopenharmony_ci    OPENGL_ERROR_CHECK(opengl);
927cabdff1aSopenharmony_ci    return 0;
928cabdff1aSopenharmony_ci  fail:
929cabdff1aSopenharmony_ci    return AVERROR_EXTERNAL;
930cabdff1aSopenharmony_ci}
931cabdff1aSopenharmony_ci
932cabdff1aSopenharmony_cistatic int opengl_create_window(AVFormatContext *h)
933cabdff1aSopenharmony_ci{
934cabdff1aSopenharmony_ci    OpenGLContext *opengl = h->priv_data;
935cabdff1aSopenharmony_ci    int ret;
936cabdff1aSopenharmony_ci
937cabdff1aSopenharmony_ci    if (!opengl->no_window) {
938cabdff1aSopenharmony_ci#if CONFIG_SDL2
939cabdff1aSopenharmony_ci        if ((ret = opengl_sdl_create_window(h)) < 0) {
940cabdff1aSopenharmony_ci            av_log(opengl, AV_LOG_ERROR, "Cannot create default SDL window.\n");
941cabdff1aSopenharmony_ci            return ret;
942cabdff1aSopenharmony_ci        }
943cabdff1aSopenharmony_ci#else
944cabdff1aSopenharmony_ci        av_log(opengl, AV_LOG_ERROR, "FFmpeg is compiled without SDL. Cannot create default window.\n");
945cabdff1aSopenharmony_ci        return AVERROR(ENOSYS);
946cabdff1aSopenharmony_ci#endif
947cabdff1aSopenharmony_ci    } else {
948cabdff1aSopenharmony_ci        AVDeviceRect message;
949cabdff1aSopenharmony_ci        message.x = message.y = 0;
950cabdff1aSopenharmony_ci        message.width = opengl->window_width;
951cabdff1aSopenharmony_ci        message.height = opengl->window_height;
952cabdff1aSopenharmony_ci        if ((ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_CREATE_WINDOW_BUFFER,
953cabdff1aSopenharmony_ci                                                       &message , sizeof(message))) < 0) {
954cabdff1aSopenharmony_ci            av_log(opengl, AV_LOG_ERROR, "Application failed to create window buffer.\n");
955cabdff1aSopenharmony_ci            return ret;
956cabdff1aSopenharmony_ci        }
957cabdff1aSopenharmony_ci        if ((ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0)) < 0) {
958cabdff1aSopenharmony_ci            av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n");
959cabdff1aSopenharmony_ci            return ret;
960cabdff1aSopenharmony_ci        }
961cabdff1aSopenharmony_ci    }
962cabdff1aSopenharmony_ci    return 0;
963cabdff1aSopenharmony_ci}
964cabdff1aSopenharmony_ci
965cabdff1aSopenharmony_cistatic int opengl_release_window(AVFormatContext *h)
966cabdff1aSopenharmony_ci{
967cabdff1aSopenharmony_ci    int ret;
968cabdff1aSopenharmony_ci    OpenGLContext *opengl = h->priv_data;
969cabdff1aSopenharmony_ci    if (!opengl->no_window) {
970cabdff1aSopenharmony_ci#if CONFIG_SDL2
971cabdff1aSopenharmony_ci        SDL_GL_DeleteContext(opengl->glcontext);
972cabdff1aSopenharmony_ci        SDL_DestroyWindow(opengl->window);
973cabdff1aSopenharmony_ci        SDL_Quit();
974cabdff1aSopenharmony_ci#endif
975cabdff1aSopenharmony_ci    } else if ((ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_DESTROY_WINDOW_BUFFER, NULL , 0)) < 0) {
976cabdff1aSopenharmony_ci        av_log(opengl, AV_LOG_ERROR, "Application failed to release window buffer.\n");
977cabdff1aSopenharmony_ci        return ret;
978cabdff1aSopenharmony_ci    }
979cabdff1aSopenharmony_ci    return 0;
980cabdff1aSopenharmony_ci}
981cabdff1aSopenharmony_ci
982cabdff1aSopenharmony_cistatic av_cold int opengl_write_trailer(AVFormatContext *h)
983cabdff1aSopenharmony_ci{
984cabdff1aSopenharmony_ci    OpenGLContext *opengl = h->priv_data;
985cabdff1aSopenharmony_ci
986cabdff1aSopenharmony_ci    if (opengl->no_window &&
987cabdff1aSopenharmony_ci        avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0) < 0)
988cabdff1aSopenharmony_ci        av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n");
989cabdff1aSopenharmony_ci
990cabdff1aSopenharmony_ci    opengl_deinit_context(opengl);
991cabdff1aSopenharmony_ci    opengl_release_window(h);
992cabdff1aSopenharmony_ci
993cabdff1aSopenharmony_ci    return 0;
994cabdff1aSopenharmony_ci}
995cabdff1aSopenharmony_ci
996cabdff1aSopenharmony_cistatic av_cold int opengl_init_context(OpenGLContext *opengl)
997cabdff1aSopenharmony_ci{
998cabdff1aSopenharmony_ci    int i, ret;
999cabdff1aSopenharmony_ci    const AVPixFmtDescriptor *desc;
1000cabdff1aSopenharmony_ci
1001cabdff1aSopenharmony_ci    if ((ret = opengl_compile_shaders(opengl, opengl->pix_fmt)) < 0)
1002cabdff1aSopenharmony_ci        goto fail;
1003cabdff1aSopenharmony_ci
1004cabdff1aSopenharmony_ci    desc = av_pix_fmt_desc_get(opengl->pix_fmt);
1005cabdff1aSopenharmony_ci    av_assert0(desc->nb_components > 0 && desc->nb_components <= 4);
1006cabdff1aSopenharmony_ci    glGenTextures(desc->nb_components, opengl->texture_name);
1007cabdff1aSopenharmony_ci
1008cabdff1aSopenharmony_ci    opengl->glprocs.glGenBuffers(2, &opengl->index_buffer);
1009cabdff1aSopenharmony_ci    if (!opengl->index_buffer || !opengl->vertex_buffer) {
1010cabdff1aSopenharmony_ci        av_log(opengl, AV_LOG_ERROR, "Buffer generation failed.\n");
1011cabdff1aSopenharmony_ci        ret = AVERROR_EXTERNAL;
1012cabdff1aSopenharmony_ci        goto fail;
1013cabdff1aSopenharmony_ci    }
1014cabdff1aSopenharmony_ci
1015cabdff1aSopenharmony_ci    opengl_configure_texture(opengl, opengl->texture_name[0], opengl->width, opengl->height);
1016cabdff1aSopenharmony_ci    if (desc->nb_components > 1) {
1017cabdff1aSopenharmony_ci        int has_alpha = desc->flags & AV_PIX_FMT_FLAG_ALPHA;
1018cabdff1aSopenharmony_ci        int num_planes = desc->nb_components - (has_alpha ? 1 : 0);
1019cabdff1aSopenharmony_ci        if (opengl->non_pow_2_textures) {
1020cabdff1aSopenharmony_ci            opengl->chroma_div_w = 1.0f;
1021cabdff1aSopenharmony_ci            opengl->chroma_div_h = 1.0f;
1022cabdff1aSopenharmony_ci        } else {
1023cabdff1aSopenharmony_ci            opengl->chroma_div_w = 1 << desc->log2_chroma_w;
1024cabdff1aSopenharmony_ci            opengl->chroma_div_h = 1 << desc->log2_chroma_h;
1025cabdff1aSopenharmony_ci        }
1026cabdff1aSopenharmony_ci        for (i = 1; i < num_planes; i++)
1027cabdff1aSopenharmony_ci            if (opengl->non_pow_2_textures)
1028cabdff1aSopenharmony_ci                opengl_configure_texture(opengl, opengl->texture_name[i],
1029cabdff1aSopenharmony_ci                        AV_CEIL_RSHIFT(opengl->width, desc->log2_chroma_w),
1030cabdff1aSopenharmony_ci                        AV_CEIL_RSHIFT(opengl->height, desc->log2_chroma_h));
1031cabdff1aSopenharmony_ci            else
1032cabdff1aSopenharmony_ci                opengl_configure_texture(opengl, opengl->texture_name[i], opengl->width, opengl->height);
1033cabdff1aSopenharmony_ci        if (has_alpha)
1034cabdff1aSopenharmony_ci            opengl_configure_texture(opengl, opengl->texture_name[3], opengl->width, opengl->height);
1035cabdff1aSopenharmony_ci    }
1036cabdff1aSopenharmony_ci
1037cabdff1aSopenharmony_ci    opengl->glprocs.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER, opengl->index_buffer);
1038cabdff1aSopenharmony_ci    opengl->glprocs.glBufferData(FF_GL_ELEMENT_ARRAY_BUFFER, sizeof(g_index), g_index, FF_GL_STATIC_DRAW);
1039cabdff1aSopenharmony_ci    opengl->glprocs.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER, 0);
1040cabdff1aSopenharmony_ci
1041cabdff1aSopenharmony_ci    glEnable(GL_BLEND);
1042cabdff1aSopenharmony_ci    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1043cabdff1aSopenharmony_ci
1044cabdff1aSopenharmony_ci    glClearColor((float)opengl->background[0] / 255.0f, (float)opengl->background[1] / 255.0f,
1045cabdff1aSopenharmony_ci                 (float)opengl->background[2] / 255.0f, 1.0f);
1046cabdff1aSopenharmony_ci
1047cabdff1aSopenharmony_ci    ret = AVERROR_EXTERNAL;
1048cabdff1aSopenharmony_ci    OPENGL_ERROR_CHECK(opengl);
1049cabdff1aSopenharmony_ci
1050cabdff1aSopenharmony_ci    return 0;
1051cabdff1aSopenharmony_ci  fail:
1052cabdff1aSopenharmony_ci    return ret;
1053cabdff1aSopenharmony_ci}
1054cabdff1aSopenharmony_ci
1055cabdff1aSopenharmony_cistatic av_cold int opengl_write_header(AVFormatContext *h)
1056cabdff1aSopenharmony_ci{
1057cabdff1aSopenharmony_ci    OpenGLContext *opengl = h->priv_data;
1058cabdff1aSopenharmony_ci    AVCodecParameters *par = h->streams[0]->codecpar;
1059cabdff1aSopenharmony_ci    AVStream *st;
1060cabdff1aSopenharmony_ci    int ret;
1061cabdff1aSopenharmony_ci
1062cabdff1aSopenharmony_ci    if (h->nb_streams != 1 ||
1063cabdff1aSopenharmony_ci        par->codec_type != AVMEDIA_TYPE_VIDEO ||
1064cabdff1aSopenharmony_ci        (par->codec_id != AV_CODEC_ID_WRAPPED_AVFRAME && par->codec_id != AV_CODEC_ID_RAWVIDEO)) {
1065cabdff1aSopenharmony_ci        av_log(opengl, AV_LOG_ERROR, "Only a single raw or wrapped avframe video stream is supported.\n");
1066cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
1067cabdff1aSopenharmony_ci    }
1068cabdff1aSopenharmony_ci    st = h->streams[0];
1069cabdff1aSopenharmony_ci    opengl->width = st->codecpar->width;
1070cabdff1aSopenharmony_ci    opengl->height = st->codecpar->height;
1071cabdff1aSopenharmony_ci    opengl->pix_fmt = st->codecpar->format;
1072cabdff1aSopenharmony_ci    if (!opengl->window_width)
1073cabdff1aSopenharmony_ci        opengl->window_width = opengl->width;
1074cabdff1aSopenharmony_ci    if (!opengl->window_height)
1075cabdff1aSopenharmony_ci        opengl->window_height = opengl->height;
1076cabdff1aSopenharmony_ci
1077cabdff1aSopenharmony_ci    if (!opengl->window_title && !opengl->no_window)
1078cabdff1aSopenharmony_ci        opengl->window_title = av_strdup(h->url);
1079cabdff1aSopenharmony_ci
1080cabdff1aSopenharmony_ci    if ((ret = opengl_create_window(h)))
1081cabdff1aSopenharmony_ci        goto fail;
1082cabdff1aSopenharmony_ci
1083cabdff1aSopenharmony_ci    if ((ret = opengl_read_limits(h)) < 0)
1084cabdff1aSopenharmony_ci        goto fail;
1085cabdff1aSopenharmony_ci
1086cabdff1aSopenharmony_ci    if (opengl->width > opengl->max_texture_size || opengl->height > opengl->max_texture_size) {
1087cabdff1aSopenharmony_ci        av_log(opengl, AV_LOG_ERROR, "Too big picture %dx%d, max supported size is %dx%d\n",
1088cabdff1aSopenharmony_ci               opengl->width, opengl->height, opengl->max_texture_size, opengl->max_texture_size);
1089cabdff1aSopenharmony_ci        ret = AVERROR(EINVAL);
1090cabdff1aSopenharmony_ci        goto fail;
1091cabdff1aSopenharmony_ci    }
1092cabdff1aSopenharmony_ci
1093cabdff1aSopenharmony_ci    if ((ret = opengl_load_procedures(opengl)) < 0)
1094cabdff1aSopenharmony_ci        goto fail;
1095cabdff1aSopenharmony_ci
1096cabdff1aSopenharmony_ci    opengl_fill_color_map(opengl);
1097cabdff1aSopenharmony_ci    opengl_get_texture_params(opengl);
1098cabdff1aSopenharmony_ci
1099cabdff1aSopenharmony_ci    if ((ret = opengl_init_context(opengl)) < 0)
1100cabdff1aSopenharmony_ci        goto fail;
1101cabdff1aSopenharmony_ci
1102cabdff1aSopenharmony_ci    if ((ret = opengl_prepare_vertex(h)) < 0)
1103cabdff1aSopenharmony_ci        goto fail;
1104cabdff1aSopenharmony_ci
1105cabdff1aSopenharmony_ci    glClear(GL_COLOR_BUFFER_BIT);
1106cabdff1aSopenharmony_ci
1107cabdff1aSopenharmony_ci#if CONFIG_SDL2
1108cabdff1aSopenharmony_ci    if (!opengl->no_window)
1109cabdff1aSopenharmony_ci        SDL_GL_SwapWindow(opengl->window);
1110cabdff1aSopenharmony_ci#endif
1111cabdff1aSopenharmony_ci    if (opengl->no_window &&
1112cabdff1aSopenharmony_ci        (ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_DISPLAY_WINDOW_BUFFER, NULL , 0)) < 0) {
1113cabdff1aSopenharmony_ci        av_log(opengl, AV_LOG_ERROR, "Application failed to display window buffer.\n");
1114cabdff1aSopenharmony_ci        goto fail;
1115cabdff1aSopenharmony_ci    }
1116cabdff1aSopenharmony_ci
1117cabdff1aSopenharmony_ci    ret = AVERROR_EXTERNAL;
1118cabdff1aSopenharmony_ci    OPENGL_ERROR_CHECK(opengl);
1119cabdff1aSopenharmony_ci
1120cabdff1aSopenharmony_ci    opengl->inited = 1;
1121cabdff1aSopenharmony_ci    return 0;
1122cabdff1aSopenharmony_ci
1123cabdff1aSopenharmony_ci  fail:
1124cabdff1aSopenharmony_ci    opengl_write_trailer(h);
1125cabdff1aSopenharmony_ci    return ret;
1126cabdff1aSopenharmony_ci}
1127cabdff1aSopenharmony_ci
1128cabdff1aSopenharmony_cistatic uint8_t* opengl_get_plane_pointer(OpenGLContext *opengl, AVPacket *pkt, int comp_index,
1129cabdff1aSopenharmony_ci                                         const AVPixFmtDescriptor *desc)
1130cabdff1aSopenharmony_ci{
1131cabdff1aSopenharmony_ci    uint8_t *data = pkt->data;
1132cabdff1aSopenharmony_ci    int wordsize = opengl_type_size(opengl->type);
1133cabdff1aSopenharmony_ci    int width_chroma = AV_CEIL_RSHIFT(opengl->width, desc->log2_chroma_w);
1134cabdff1aSopenharmony_ci    int height_chroma = AV_CEIL_RSHIFT(opengl->height, desc->log2_chroma_h);
1135cabdff1aSopenharmony_ci    int plane = desc->comp[comp_index].plane;
1136cabdff1aSopenharmony_ci
1137cabdff1aSopenharmony_ci    switch(plane) {
1138cabdff1aSopenharmony_ci    case 0:
1139cabdff1aSopenharmony_ci        break;
1140cabdff1aSopenharmony_ci    case 1:
1141cabdff1aSopenharmony_ci        data += opengl->width * opengl->height * wordsize;
1142cabdff1aSopenharmony_ci        break;
1143cabdff1aSopenharmony_ci    case 2:
1144cabdff1aSopenharmony_ci        data += opengl->width * opengl->height * wordsize;
1145cabdff1aSopenharmony_ci        data += width_chroma * height_chroma * wordsize;
1146cabdff1aSopenharmony_ci        break;
1147cabdff1aSopenharmony_ci    case 3:
1148cabdff1aSopenharmony_ci        data += opengl->width * opengl->height * wordsize;
1149cabdff1aSopenharmony_ci        data += 2 * width_chroma * height_chroma * wordsize;
1150cabdff1aSopenharmony_ci        break;
1151cabdff1aSopenharmony_ci    default:
1152cabdff1aSopenharmony_ci        return NULL;
1153cabdff1aSopenharmony_ci    }
1154cabdff1aSopenharmony_ci    return data;
1155cabdff1aSopenharmony_ci}
1156cabdff1aSopenharmony_ci
1157cabdff1aSopenharmony_ci#define LOAD_TEXTURE_DATA(comp_index, sub)                                                  \
1158cabdff1aSopenharmony_ci{                                                                                           \
1159cabdff1aSopenharmony_ci    int width = sub ? AV_CEIL_RSHIFT(opengl->width, desc->log2_chroma_w) : opengl->width;   \
1160cabdff1aSopenharmony_ci    int height = sub ? AV_CEIL_RSHIFT(opengl->height, desc->log2_chroma_h): opengl->height; \
1161cabdff1aSopenharmony_ci    uint8_t *data;                                                                          \
1162cabdff1aSopenharmony_ci    int plane = desc->comp[comp_index].plane;                                               \
1163cabdff1aSopenharmony_ci                                                                                            \
1164cabdff1aSopenharmony_ci    glBindTexture(GL_TEXTURE_2D, opengl->texture_name[comp_index]);                         \
1165cabdff1aSopenharmony_ci    if (!is_pkt) {                                                                          \
1166cabdff1aSopenharmony_ci        GLint length = ((AVFrame *)input)->linesize[plane];                                 \
1167cabdff1aSopenharmony_ci        int bytes_per_pixel = opengl_type_size(opengl->type);                               \
1168cabdff1aSopenharmony_ci        if (!(desc->flags & AV_PIX_FMT_FLAG_PLANAR))                                        \
1169cabdff1aSopenharmony_ci            bytes_per_pixel *= desc->nb_components;                                         \
1170cabdff1aSopenharmony_ci        data = ((AVFrame *)input)->data[plane];                                             \
1171cabdff1aSopenharmony_ci        if (!(length % bytes_per_pixel) &&                                                  \
1172cabdff1aSopenharmony_ci            (opengl->unpack_subimage || ((length / bytes_per_pixel) == width))) {           \
1173cabdff1aSopenharmony_ci            length /= bytes_per_pixel;                                                      \
1174cabdff1aSopenharmony_ci            if (length != width)                                                            \
1175cabdff1aSopenharmony_ci                glPixelStorei(FF_GL_UNPACK_ROW_LENGTH, length);                             \
1176cabdff1aSopenharmony_ci            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height,                          \
1177cabdff1aSopenharmony_ci                            opengl->format, opengl->type, data);                            \
1178cabdff1aSopenharmony_ci            if (length != width)                                                            \
1179cabdff1aSopenharmony_ci                glPixelStorei(FF_GL_UNPACK_ROW_LENGTH, 0);                                  \
1180cabdff1aSopenharmony_ci        } else {                                                                            \
1181cabdff1aSopenharmony_ci            int h;                                                                          \
1182cabdff1aSopenharmony_ci            for (h = 0; h < height; h++) {                                                  \
1183cabdff1aSopenharmony_ci                glTexSubImage2D(GL_TEXTURE_2D, 0, 0, h, width, 1,                           \
1184cabdff1aSopenharmony_ci                                opengl->format, opengl->type, data);                        \
1185cabdff1aSopenharmony_ci                data += length;                                                             \
1186cabdff1aSopenharmony_ci            }                                                                               \
1187cabdff1aSopenharmony_ci        }                                                                                   \
1188cabdff1aSopenharmony_ci    } else {                                                                                \
1189cabdff1aSopenharmony_ci        data = opengl_get_plane_pointer(opengl, input, comp_index, desc);                   \
1190cabdff1aSopenharmony_ci        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height,                              \
1191cabdff1aSopenharmony_ci                        opengl->format, opengl->type, data);                                \
1192cabdff1aSopenharmony_ci    }                                                                                       \
1193cabdff1aSopenharmony_ci}
1194cabdff1aSopenharmony_ci
1195cabdff1aSopenharmony_cistatic int opengl_draw(AVFormatContext *h, void *input, int repaint, int is_pkt)
1196cabdff1aSopenharmony_ci{
1197cabdff1aSopenharmony_ci    OpenGLContext *opengl = h->priv_data;
1198cabdff1aSopenharmony_ci    enum AVPixelFormat pix_fmt = h->streams[0]->codecpar->format;
1199cabdff1aSopenharmony_ci    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
1200cabdff1aSopenharmony_ci    int ret;
1201cabdff1aSopenharmony_ci
1202cabdff1aSopenharmony_ci#if CONFIG_SDL2
1203cabdff1aSopenharmony_ci    if (!opengl->no_window && (ret = opengl_sdl_process_events(h)) < 0)
1204cabdff1aSopenharmony_ci        goto fail;
1205cabdff1aSopenharmony_ci#endif
1206cabdff1aSopenharmony_ci    if (opengl->no_window &&
1207cabdff1aSopenharmony_ci        (ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0)) < 0) {
1208cabdff1aSopenharmony_ci        av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n");
1209cabdff1aSopenharmony_ci        goto fail;
1210cabdff1aSopenharmony_ci    }
1211cabdff1aSopenharmony_ci
1212cabdff1aSopenharmony_ci    glClear(GL_COLOR_BUFFER_BIT);
1213cabdff1aSopenharmony_ci
1214cabdff1aSopenharmony_ci    if (!repaint) {
1215cabdff1aSopenharmony_ci        if (is_pkt)
1216cabdff1aSopenharmony_ci            glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1217cabdff1aSopenharmony_ci        LOAD_TEXTURE_DATA(0, 0)
1218cabdff1aSopenharmony_ci        if (desc->flags & AV_PIX_FMT_FLAG_PLANAR) {
1219cabdff1aSopenharmony_ci            LOAD_TEXTURE_DATA(1, 1)
1220cabdff1aSopenharmony_ci            LOAD_TEXTURE_DATA(2, 1)
1221cabdff1aSopenharmony_ci            if (desc->flags & AV_PIX_FMT_FLAG_ALPHA)
1222cabdff1aSopenharmony_ci                LOAD_TEXTURE_DATA(3, 0)
1223cabdff1aSopenharmony_ci        }
1224cabdff1aSopenharmony_ci    }
1225cabdff1aSopenharmony_ci    ret = AVERROR_EXTERNAL;
1226cabdff1aSopenharmony_ci    OPENGL_ERROR_CHECK(opengl);
1227cabdff1aSopenharmony_ci
1228cabdff1aSopenharmony_ci    if ((ret = opengl_prepare(opengl)) < 0)
1229cabdff1aSopenharmony_ci        goto fail;
1230cabdff1aSopenharmony_ci
1231cabdff1aSopenharmony_ci    opengl->glprocs.glBindBuffer(FF_GL_ARRAY_BUFFER, opengl->vertex_buffer);
1232cabdff1aSopenharmony_ci    opengl->glprocs.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER, opengl->index_buffer);
1233cabdff1aSopenharmony_ci    opengl->glprocs.glVertexAttribPointer(opengl->position_attrib, 3, GL_FLOAT, GL_FALSE, sizeof(OpenGLVertexInfo), 0);
1234cabdff1aSopenharmony_ci    opengl->glprocs.glEnableVertexAttribArray(opengl->position_attrib);
1235cabdff1aSopenharmony_ci    opengl->glprocs.glVertexAttribPointer(opengl->texture_coords_attrib, 2, GL_FLOAT, GL_FALSE, sizeof(OpenGLVertexInfo), 12);
1236cabdff1aSopenharmony_ci    opengl->glprocs.glEnableVertexAttribArray(opengl->texture_coords_attrib);
1237cabdff1aSopenharmony_ci
1238cabdff1aSopenharmony_ci    glDrawElements(GL_TRIANGLES, FF_ARRAY_ELEMS(g_index), GL_UNSIGNED_SHORT, 0);
1239cabdff1aSopenharmony_ci
1240cabdff1aSopenharmony_ci    ret = AVERROR_EXTERNAL;
1241cabdff1aSopenharmony_ci    OPENGL_ERROR_CHECK(opengl);
1242cabdff1aSopenharmony_ci
1243cabdff1aSopenharmony_ci#if CONFIG_SDL2
1244cabdff1aSopenharmony_ci    if (!opengl->no_window)
1245cabdff1aSopenharmony_ci        SDL_GL_SwapWindow(opengl->window);
1246cabdff1aSopenharmony_ci#endif
1247cabdff1aSopenharmony_ci    if (opengl->no_window &&
1248cabdff1aSopenharmony_ci        (ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_DISPLAY_WINDOW_BUFFER, NULL , 0)) < 0) {
1249cabdff1aSopenharmony_ci        av_log(opengl, AV_LOG_ERROR, "Application failed to display window buffer.\n");
1250cabdff1aSopenharmony_ci        goto fail;
1251cabdff1aSopenharmony_ci    }
1252cabdff1aSopenharmony_ci
1253cabdff1aSopenharmony_ci    return 0;
1254cabdff1aSopenharmony_ci  fail:
1255cabdff1aSopenharmony_ci    return ret;
1256cabdff1aSopenharmony_ci}
1257cabdff1aSopenharmony_ci
1258cabdff1aSopenharmony_cistatic int opengl_write_packet(AVFormatContext *h, AVPacket *pkt)
1259cabdff1aSopenharmony_ci{
1260cabdff1aSopenharmony_ci    AVCodecParameters *par = h->streams[0]->codecpar;
1261cabdff1aSopenharmony_ci    if (par->codec_id == AV_CODEC_ID_WRAPPED_AVFRAME) {
1262cabdff1aSopenharmony_ci        AVFrame *frame = (AVFrame *)pkt->data;
1263cabdff1aSopenharmony_ci        return opengl_draw(h, frame, 0, 0);
1264cabdff1aSopenharmony_ci    } else {
1265cabdff1aSopenharmony_ci        return opengl_draw(h, pkt, 0, 1);
1266cabdff1aSopenharmony_ci    }
1267cabdff1aSopenharmony_ci}
1268cabdff1aSopenharmony_ci
1269cabdff1aSopenharmony_cistatic int opengl_write_frame(AVFormatContext *h, int stream_index,
1270cabdff1aSopenharmony_ci                              AVFrame **frame, unsigned flags)
1271cabdff1aSopenharmony_ci{
1272cabdff1aSopenharmony_ci    if ((flags & AV_WRITE_UNCODED_FRAME_QUERY))
1273cabdff1aSopenharmony_ci        return 0;
1274cabdff1aSopenharmony_ci    return opengl_draw(h, *frame, 0, 0);
1275cabdff1aSopenharmony_ci}
1276cabdff1aSopenharmony_ci
1277cabdff1aSopenharmony_ci#define OFFSET(x) offsetof(OpenGLContext, x)
1278cabdff1aSopenharmony_ci#define ENC AV_OPT_FLAG_ENCODING_PARAM
1279cabdff1aSopenharmony_cistatic const AVOption options[] = {
1280cabdff1aSopenharmony_ci    { "background",   "set background color",   OFFSET(background),   AV_OPT_TYPE_COLOR,  {.str = "black"}, 0, 0, ENC },
1281cabdff1aSopenharmony_ci    { "no_window",    "disable default window", OFFSET(no_window),    AV_OPT_TYPE_INT,    {.i64 = 0}, INT_MIN, INT_MAX, ENC },
1282cabdff1aSopenharmony_ci    { "window_title", "set window title",       OFFSET(window_title), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, ENC },
1283cabdff1aSopenharmony_ci    { "window_size",  "set window size",        OFFSET(window_width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, ENC },
1284cabdff1aSopenharmony_ci    { NULL }
1285cabdff1aSopenharmony_ci};
1286cabdff1aSopenharmony_ci
1287cabdff1aSopenharmony_cistatic const AVClass opengl_class = {
1288cabdff1aSopenharmony_ci    .class_name = "opengl outdev",
1289cabdff1aSopenharmony_ci    .item_name  = av_default_item_name,
1290cabdff1aSopenharmony_ci    .option     = options,
1291cabdff1aSopenharmony_ci    .version    = LIBAVUTIL_VERSION_INT,
1292cabdff1aSopenharmony_ci    .category   = AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT,
1293cabdff1aSopenharmony_ci};
1294cabdff1aSopenharmony_ci
1295cabdff1aSopenharmony_ciconst AVOutputFormat ff_opengl_muxer = {
1296cabdff1aSopenharmony_ci    .name           = "opengl",
1297cabdff1aSopenharmony_ci    .long_name      = NULL_IF_CONFIG_SMALL("OpenGL output"),
1298cabdff1aSopenharmony_ci    .priv_data_size = sizeof(OpenGLContext),
1299cabdff1aSopenharmony_ci    .audio_codec    = AV_CODEC_ID_NONE,
1300cabdff1aSopenharmony_ci    .video_codec    = AV_CODEC_ID_WRAPPED_AVFRAME,
1301cabdff1aSopenharmony_ci    .write_header   = opengl_write_header,
1302cabdff1aSopenharmony_ci    .write_packet   = opengl_write_packet,
1303cabdff1aSopenharmony_ci    .write_uncoded_frame = opengl_write_frame,
1304cabdff1aSopenharmony_ci    .write_trailer  = opengl_write_trailer,
1305cabdff1aSopenharmony_ci    .control_message = opengl_control_message,
1306cabdff1aSopenharmony_ci    .flags          = AVFMT_NOFILE | AVFMT_VARIABLE_FPS | AVFMT_NOTIMESTAMPS,
1307cabdff1aSopenharmony_ci    .priv_class     = &opengl_class,
1308cabdff1aSopenharmony_ci};
1309