2 * Copyright (c) 2014 Lukasz Marek
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 //TODO: support for more formats
22 //TODO: support for more systems.
23 //TODO: implement X11, Windows, Mac OS native default window. SDL 1.2 doesn't allow to render to custom thread.
34 #define WIN32_LEAN_AND_MEAN
38 #include <OpenGL/gl3.h>
45 #if HAVE_GLXGETPROCADDRESS
53 #include "libavutil/common.h"
54 #include "libavutil/pixdesc.h"
55 #include "libavutil/log.h"
56 #include "libavutil/opt.h"
57 #include "libavutil/avassert.h"
58 #include "libavutil/avstring.h"
59 #include "libavformat/avformat.h"
60 #include "libavformat/internal.h"
61 #include "libavdevice/avdevice.h"
62 #include "opengl_enc_shaders.h"
68 /* FF_GL_RED_COMPONENT is used for plannar pixel types.
69 * Only red component is sampled in shaders.
70 * On some platforms GL_RED is not available and GL_LUMINANCE have to be used,
71 * but since OpenGL 3.0 GL_LUMINANCE is deprecated.
72 * GL_RED produces RGBA = value, 0, 0, 1.
73 * GL_LUMINANCE produces RGBA = value, value, value, 1.
74 * Note: GL_INTENSITY may also be used which produce RGBA = value, value, value, value. */
76 #define FF_GL_RED_COMPONENT GL_RED
77 #elif defined(GL_LUMINANCE)
78 #define FF_GL_RED_COMPONENT GL_LUMINANCE
80 #define FF_GL_RED_COMPONENT 0x1903; //GL_RED
83 /* Constants not defined for iOS */
84 #define FF_GL_UNSIGNED_BYTE_3_3_2 0x8032
85 #define FF_GL_UNSIGNED_BYTE_2_3_3_REV 0x8362
86 #define FF_GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
87 #define FF_GL_UNPACK_ROW_LENGTH 0x0CF2
89 /* MinGW exposes only OpenGL 1.1 API */
90 #define FF_GL_ARRAY_BUFFER 0x8892
91 #define FF_GL_ELEMENT_ARRAY_BUFFER 0x8893
92 #define FF_GL_STATIC_DRAW 0x88E4
93 #define FF_GL_FRAGMENT_SHADER 0x8B30
94 #define FF_GL_VERTEX_SHADER 0x8B31
95 #define FF_GL_COMPILE_STATUS 0x8B81
96 #define FF_GL_LINK_STATUS 0x8B82
97 #define FF_GL_INFO_LOG_LENGTH 0x8B84
98 typedef void (APIENTRY
*FF_PFNGLACTIVETEXTUREPROC
) (GLenum texture
);
99 typedef void (APIENTRY
*FF_PFNGLGENBUFFERSPROC
) (GLsizei n
, GLuint
*buffers
);
100 typedef void (APIENTRY
*FF_PFNGLDELETEBUFFERSPROC
) (GLsizei n
, const GLuint
*buffers
);
101 typedef void (APIENTRY
*FF_PFNGLBUFFERDATAPROC
) (GLenum target
, ptrdiff_t size
, const GLvoid
*data
, GLenum usage
);
102 typedef void (APIENTRY
*FF_PFNGLBINDBUFFERPROC
) (GLenum target
, GLuint buffer
);
103 typedef GLint (APIENTRY
*FF_PFNGLGETATTRIBLOCATIONPROC
) (GLuint program
, const char *name
);
104 typedef void (APIENTRY
*FF_PFNGLENABLEVERTEXATTRIBARRAYPROC
) (GLuint index
);
105 typedef void (APIENTRY
*FF_PFNGLVERTEXATTRIBPOINTERPROC
) (GLuint index
, GLint size
, GLenum type
, GLboolean normalized
, GLsizei stride
, uintptr_t pointer
);
106 typedef GLint (APIENTRY
*FF_PFNGLGETUNIFORMLOCATIONPROC
) (GLuint program
, const char *name
);
107 typedef void (APIENTRY
*FF_PFNGLUNIFORM1FPROC
) (GLint location
, GLfloat v0
);
108 typedef void (APIENTRY
*FF_PFNGLUNIFORM1IPROC
) (GLint location
, GLint v0
);
109 typedef void (APIENTRY
*FF_PFNGLUNIFORMMATRIX4FVPROC
) (GLint location
, GLsizei count
, GLboolean transpose
, const GLfloat
*value
);
110 typedef GLuint (APIENTRY
*FF_PFNGLCREATEPROGRAMPROC
) (void);
111 typedef void (APIENTRY
*FF_PFNGLDELETEPROGRAMPROC
) (GLuint program
);
112 typedef void (APIENTRY
*FF_PFNGLUSEPROGRAMPROC
) (GLuint program
);
113 typedef void (APIENTRY
*FF_PFNGLLINKPROGRAMPROC
) (GLuint program
);
114 typedef void (APIENTRY
*FF_PFNGLGETPROGRAMIVPROC
) (GLuint program
, GLenum pname
, GLint
*params
);
115 typedef void (APIENTRY
*FF_PFNGLGETPROGRAMINFOLOGPROC
) (GLuint program
, GLsizei bufSize
, GLsizei
*length
, char *infoLog
);
116 typedef void (APIENTRY
*FF_PFNGLATTACHSHADERPROC
) (GLuint program
, GLuint shader
);
117 typedef GLuint (APIENTRY
*FF_PFNGLCREATESHADERPROC
) (GLenum type
);
118 typedef void (APIENTRY
*FF_PFNGLDELETESHADERPROC
) (GLuint shader
);
119 typedef void (APIENTRY
*FF_PFNGLCOMPILESHADERPROC
) (GLuint shader
);
120 typedef void (APIENTRY
*FF_PFNGLSHADERSOURCEPROC
) (GLuint shader
, GLsizei count
, const char* *string
, const GLint
*length
);
121 typedef void (APIENTRY
*FF_PFNGLGETSHADERIVPROC
) (GLuint shader
, GLenum pname
, GLint
*params
);
122 typedef void (APIENTRY
*FF_PFNGLGETSHADERINFOLOGPROC
) (GLuint shader
, GLsizei bufSize
, GLsizei
*length
, char *infoLog
);
124 typedef struct FFOpenGLFunctions
{
125 FF_PFNGLACTIVETEXTUREPROC glActiveTexture
; //Require GL ARB multitexture
126 FF_PFNGLGENBUFFERSPROC glGenBuffers
; //Require GL_ARB_vertex_buffer_object
127 FF_PFNGLDELETEBUFFERSPROC glDeleteBuffers
; //Require GL_ARB_vertex_buffer_object
128 FF_PFNGLBUFFERDATAPROC glBufferData
; //Require GL_ARB_vertex_buffer_object
129 FF_PFNGLBINDBUFFERPROC glBindBuffer
; //Require GL_ARB_vertex_buffer_object
130 FF_PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation
; //Require GL_ARB_vertex_shader
131 FF_PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray
; //Require GL_ARB_vertex_shader
132 FF_PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer
; //Require GL_ARB_vertex_shader
133 FF_PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation
; //Require GL_ARB_shader_objects
134 FF_PFNGLUNIFORM1FPROC glUniform1f
; //Require GL_ARB_shader_objects
135 FF_PFNGLUNIFORM1IPROC glUniform1i
; //Require GL_ARB_shader_objects
136 FF_PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv
; //Require GL_ARB_shader_objects
137 FF_PFNGLCREATEPROGRAMPROC glCreateProgram
; //Require GL_ARB_shader_objects
138 FF_PFNGLDELETEPROGRAMPROC glDeleteProgram
; //Require GL_ARB_shader_objects
139 FF_PFNGLUSEPROGRAMPROC glUseProgram
; //Require GL_ARB_shader_objects
140 FF_PFNGLLINKPROGRAMPROC glLinkProgram
; //Require GL_ARB_shader_objects
141 FF_PFNGLGETPROGRAMIVPROC glGetProgramiv
; //Require GL_ARB_shader_objects
142 FF_PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog
; //Require GL_ARB_shader_objects
143 FF_PFNGLATTACHSHADERPROC glAttachShader
; //Require GL_ARB_shader_objects
144 FF_PFNGLCREATESHADERPROC glCreateShader
; //Require GL_ARB_shader_objects
145 FF_PFNGLDELETESHADERPROC glDeleteShader
; //Require GL_ARB_shader_objects
146 FF_PFNGLCOMPILESHADERPROC glCompileShader
; //Require GL_ARB_shader_objects
147 FF_PFNGLSHADERSOURCEPROC glShaderSource
; //Require GL_ARB_shader_objects
148 FF_PFNGLGETSHADERIVPROC glGetShaderiv
; //Require GL_ARB_shader_objects
149 FF_PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog
; //Require GL_ARB_shader_objects
152 #define OPENGL_ERROR_CHECK(ctx) \
155 if ((err_code = glGetError()) != GL_NO_ERROR) { \
156 av_log(ctx, AV_LOG_ERROR, "OpenGL error occurred in '%s', line %d: %d\n", __FUNCTION__, __LINE__, err_code); \
161 typedef struct OpenGLVertexInfo
163 float x
, y
, z
; ///<Position
164 float s0
, t0
; ///<Texture coords
167 /* defines 2 triangles to display */
168 static const GLushort g_index
[6] =
174 typedef struct OpenGLContext
{
175 AVClass
*class; ///< class for private options
178 SDL_Surface
*surface
;
180 FFOpenGLFunctions glprocs
;
182 int inited
; ///< Set to 1 when write_header was successfully called.
183 uint8_t background
[4]; ///< Background color
184 int no_window
; ///< 0 for create default window
185 char *window_title
; ///< Title of the window
187 /* OpenGL implementation limits */
188 GLint max_texture_size
; ///< Maximum texture size
189 GLint max_viewport_width
; ///< Maximum viewport size
190 GLint max_viewport_height
; ///< Maximum viewport size
191 int non_pow_2_textures
; ///< 1 when non power of 2 textures are supported
192 int unpack_subimage
; ///< 1 when GL_EXT_unpack_subimage is available
194 /* Current OpenGL configuration */
195 GLuint program
; ///< Shader program
196 GLuint vertex_shader
; ///< Vertex shader
197 GLuint fragment_shader
; ///< Fragment shader for current pix_pmt
198 GLuint texture_name
[4]; ///< Textures' IDs
199 GLuint index_buffer
; ///< Index buffer
200 GLuint vertex_buffer
; ///< Vertex buffer
201 OpenGLVertexInfo vertex
[4]; ///< VBO
202 GLint projection_matrix_location
; ///< Uniforms' locations
203 GLint model_view_matrix_location
;
204 GLint color_map_location
;
205 GLint chroma_div_w_location
;
206 GLint chroma_div_h_location
;
207 GLint texture_location
[4];
208 GLint position_attrib
; ///< Attibutes' locations
209 GLint texture_coords_attrib
;
211 GLfloat projection_matrix
[16]; ///< Projection matrix
212 GLfloat model_view_matrix
[16]; ///< Modev view matrix
213 GLfloat color_map
[16]; ///< RGBA color map matrix
214 GLfloat chroma_div_w
; ///< Chroma subsampling w ratio
215 GLfloat chroma_div_h
; ///< Chroma subsampling h ratio
217 /* Stream information */
220 int width
; ///< Stream width
221 int height
; ///< Stream height
222 enum AVPixelFormat pix_fmt
; ///< Stream pixel format
223 int picture_width
; ///< Rendered width
224 int picture_height
; ///< Rendered height
229 static const struct OpenGLFormatDesc
{
230 enum AVPixelFormat fixel_format
;
231 const char * const * fragment_shader
;
234 } opengl_format_desc
[] = {
235 { AV_PIX_FMT_YUV420P
, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
236 { AV_PIX_FMT_YUV444P
, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
237 { AV_PIX_FMT_YUV422P
, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
238 { AV_PIX_FMT_YUV410P
, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
239 { AV_PIX_FMT_YUV411P
, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
240 { AV_PIX_FMT_YUV440P
, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
241 { AV_PIX_FMT_YUV420P16
, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_SHORT
},
242 { AV_PIX_FMT_YUV422P16
, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_SHORT
},
243 { AV_PIX_FMT_YUV444P16
, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_SHORT
},
244 { AV_PIX_FMT_YUVA420P
, &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
245 { AV_PIX_FMT_YUVA444P
, &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
246 { AV_PIX_FMT_YUVA422P
, &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
247 { AV_PIX_FMT_YUVA420P16
, &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_SHORT
},
248 { AV_PIX_FMT_YUVA422P16
, &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_SHORT
},
249 { AV_PIX_FMT_YUVA444P16
, &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_SHORT
},
250 { AV_PIX_FMT_RGB24
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGB
, GL_UNSIGNED_BYTE
},
251 { AV_PIX_FMT_BGR24
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGB
, GL_UNSIGNED_BYTE
},
252 { AV_PIX_FMT_0RGB
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGBA
, GL_UNSIGNED_BYTE
},
253 { AV_PIX_FMT_RGB0
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGBA
, GL_UNSIGNED_BYTE
},
254 { AV_PIX_FMT_0BGR
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGBA
, GL_UNSIGNED_BYTE
},
255 { AV_PIX_FMT_BGR0
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGBA
, GL_UNSIGNED_BYTE
},
256 { AV_PIX_FMT_RGB565
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGB
, GL_UNSIGNED_SHORT_5_6_5
},
257 { AV_PIX_FMT_BGR565
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGB
, GL_UNSIGNED_SHORT_5_6_5
},
258 { AV_PIX_FMT_RGB555
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGBA
, FF_GL_UNSIGNED_SHORT_1_5_5_5_REV
},
259 { AV_PIX_FMT_BGR555
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGBA
, FF_GL_UNSIGNED_SHORT_1_5_5_5_REV
},
260 { AV_PIX_FMT_RGB8
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGB
, FF_GL_UNSIGNED_BYTE_3_3_2
},
261 { AV_PIX_FMT_BGR8
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGB
, FF_GL_UNSIGNED_BYTE_2_3_3_REV
},
262 { AV_PIX_FMT_RGB48
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGB
, GL_UNSIGNED_SHORT
},
263 { AV_PIX_FMT_ARGB
, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET
, GL_RGBA
, GL_UNSIGNED_BYTE
},
264 { AV_PIX_FMT_RGBA
, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET
, GL_RGBA
, GL_UNSIGNED_BYTE
},
265 { AV_PIX_FMT_ABGR
, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET
, GL_RGBA
, GL_UNSIGNED_BYTE
},
266 { AV_PIX_FMT_BGRA
, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET
, GL_RGBA
, GL_UNSIGNED_BYTE
},
267 { AV_PIX_FMT_RGBA64
, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET
, GL_RGBA
, GL_UNSIGNED_SHORT
},
268 { AV_PIX_FMT_BGRA64
, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET
, GL_RGBA
, GL_UNSIGNED_SHORT
},
269 { AV_PIX_FMT_GBRP
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
270 { AV_PIX_FMT_GBRP16
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_SHORT
},
271 { AV_PIX_FMT_GBRAP
, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
272 { AV_PIX_FMT_GBRAP16
, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_SHORT
},
273 { AV_PIX_FMT_GRAY8
, &FF_OPENGL_FRAGMENT_SHADER_GRAY
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
274 { AV_PIX_FMT_GRAY16
, &FF_OPENGL_FRAGMENT_SHADER_GRAY
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_SHORT
},
275 { AV_PIX_FMT_NONE
, NULL
}
278 static av_cold
int opengl_prepare_vertex(AVFormatContext
*s
);
279 static int opengl_draw(AVFormatContext
*h
, void *intput
, int repaint
, int is_pkt
);
280 static av_cold
int opengl_init_context(OpenGLContext
*opengl
);
282 static av_cold
void opengl_deinit_context(OpenGLContext
*opengl
)
284 glDeleteTextures(4, opengl
->texture_name
);
285 opengl
->texture_name
[0] = opengl
->texture_name
[1] =
286 opengl
->texture_name
[2] = opengl
->texture_name
[3] = 0;
287 if (opengl
->glprocs
.glUseProgram
)
288 opengl
->glprocs
.glUseProgram(0);
289 if (opengl
->glprocs
.glDeleteProgram
) {
290 opengl
->glprocs
.glDeleteProgram(opengl
->program
);
293 if (opengl
->glprocs
.glDeleteShader
) {
294 opengl
->glprocs
.glDeleteShader(opengl
->vertex_shader
);
295 opengl
->glprocs
.glDeleteShader(opengl
->fragment_shader
);
296 opengl
->vertex_shader
= opengl
->fragment_shader
= 0;
298 if (opengl
->glprocs
.glBindBuffer
) {
299 opengl
->glprocs
.glBindBuffer(FF_GL_ARRAY_BUFFER
, 0);
300 opengl
->glprocs
.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER
, 0);
302 if (opengl
->glprocs
.glDeleteBuffers
) {
303 opengl
->glprocs
.glDeleteBuffers(2, &opengl
->index_buffer
);
304 opengl
->vertex_buffer
= opengl
->index_buffer
= 0;
308 static int opengl_resize(AVFormatContext
*h
, int width
, int height
)
311 OpenGLContext
*opengl
= h
->priv_data
;
312 opengl
->window_width
= width
;
313 opengl
->window_height
= height
;
314 if (opengl
->inited
) {
315 if (opengl
->no_window
&&
316 (ret
= avdevice_dev_to_app_control_message(h
, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER
, NULL
, 0)) < 0) {
317 av_log(opengl
, AV_LOG_ERROR
, "Application failed to prepare window buffer.\n");
320 if ((ret
= opengl_prepare_vertex(h
)) < 0)
322 ret
= opengl_draw(h
, NULL
, 1, 0);
328 static int opengl_control_message(AVFormatContext
*h
, int type
, void *data
, size_t data_size
)
330 OpenGLContext
*opengl
= h
->priv_data
;
332 case AV_APP_TO_DEV_WINDOW_SIZE
:
334 AVDeviceRect
*message
= data
;
335 return opengl_resize(h
, message
->width
, message
->height
);
337 return AVERROR(EINVAL
);
338 case AV_APP_TO_DEV_WINDOW_REPAINT
:
339 return opengl_resize(h
, opengl
->window_width
, opengl
->window_height
);
341 return AVERROR(ENOSYS
);
345 static int opengl_sdl_recreate_window(OpenGLContext
*opengl
, int width
, int height
)
347 opengl
->surface
= SDL_SetVideoMode(width
, height
,
348 32, SDL_OPENGL
| SDL_RESIZABLE
);
349 if (!opengl
->surface
) {
350 av_log(opengl
, AV_LOG_ERROR
, "Unable to set video mode: %s\n", SDL_GetError());
351 return AVERROR_EXTERNAL
;
353 SDL_GL_SetAttribute(SDL_GL_RED_SIZE
, 8);
354 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE
, 8);
355 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE
, 8);
356 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE
, 8);
357 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER
, 1);
361 static int opengl_sdl_process_events(AVFormatContext
*h
)
364 OpenGLContext
*opengl
= h
->priv_data
;
367 while (SDL_PeepEvents(&event
, 1, SDL_GETEVENT
, SDL_ALLEVENTS
) > 0) {
368 switch (event
.type
) {
372 switch (event
.key
.keysym
.sym
) {
378 case SDL_VIDEORESIZE
: {
381 AVDeviceRect message
;
382 /* clean up old context because SDL_SetVideoMode may lose its state. */
383 SDL_VideoDriverName(buffer
, sizeof(buffer
));
384 reinit
= !av_strncasecmp(buffer
, "quartz", sizeof(buffer
));
386 opengl_deinit_context(opengl
);
388 if ((ret
= opengl_sdl_recreate_window(opengl
, event
.resize
.w
, event
.resize
.h
)) < 0)
390 if (reinit
&& (ret
= opengl_init_context(opengl
)) < 0)
392 message
.width
= opengl
->surface
->w
;
393 message
.height
= opengl
->surface
->h
;
394 return opengl_control_message(h
, AV_APP_TO_DEV_WINDOW_SIZE
, &message
, sizeof(AVDeviceRect
));
401 static int av_cold
opengl_sdl_create_window(AVFormatContext
*h
)
405 OpenGLContext
*opengl
= h
->priv_data
;
406 AVDeviceRect message
;
407 if (SDL_Init(SDL_INIT_VIDEO
)) {
408 av_log(opengl
, AV_LOG_ERROR
, "Unable to initialize SDL: %s\n", SDL_GetError());
409 return AVERROR_EXTERNAL
;
411 if ((ret
= opengl_sdl_recreate_window(opengl
, opengl
->window_width
,
412 opengl
->window_height
)) < 0)
414 av_log(opengl
, AV_LOG_INFO
, "SDL driver: '%s'.\n", SDL_VideoDriverName(buffer
, sizeof(buffer
)));
415 message
.width
= opengl
->surface
->w
;
416 message
.height
= opengl
->surface
->h
;
417 SDL_WM_SetCaption(opengl
->window_title
, NULL
);
418 opengl_control_message(h
, AV_APP_TO_DEV_WINDOW_SIZE
, &message
, sizeof(AVDeviceRect
));
422 static int av_cold
opengl_sdl_load_procedures(OpenGLContext
*opengl
)
424 FFOpenGLFunctions
*procs
= &opengl
->glprocs
;
426 #define LOAD_OPENGL_FUN(name, type) \
427 procs->name = (type)SDL_GL_GetProcAddress(#name); \
428 if (!procs->name) { \
429 av_log(opengl, AV_LOG_ERROR, "Cannot load OpenGL function: '%s'\n", #name); \
430 return AVERROR(ENOSYS); \
433 LOAD_OPENGL_FUN(glActiveTexture
, FF_PFNGLACTIVETEXTUREPROC
)
434 LOAD_OPENGL_FUN(glGenBuffers
, FF_PFNGLGENBUFFERSPROC
)
435 LOAD_OPENGL_FUN(glDeleteBuffers
, FF_PFNGLDELETEBUFFERSPROC
)
436 LOAD_OPENGL_FUN(glBufferData
, FF_PFNGLBUFFERDATAPROC
)
437 LOAD_OPENGL_FUN(glBindBuffer
, FF_PFNGLBINDBUFFERPROC
)
438 LOAD_OPENGL_FUN(glGetAttribLocation
, FF_PFNGLGETATTRIBLOCATIONPROC
)
439 LOAD_OPENGL_FUN(glGetUniformLocation
, FF_PFNGLGETUNIFORMLOCATIONPROC
)
440 LOAD_OPENGL_FUN(glUniform1f
, FF_PFNGLUNIFORM1FPROC
)
441 LOAD_OPENGL_FUN(glUniform1i
, FF_PFNGLUNIFORM1IPROC
)
442 LOAD_OPENGL_FUN(glUniformMatrix4fv
, FF_PFNGLUNIFORMMATRIX4FVPROC
)
443 LOAD_OPENGL_FUN(glCreateProgram
, FF_PFNGLCREATEPROGRAMPROC
)
444 LOAD_OPENGL_FUN(glDeleteProgram
, FF_PFNGLDELETEPROGRAMPROC
)
445 LOAD_OPENGL_FUN(glUseProgram
, FF_PFNGLUSEPROGRAMPROC
)
446 LOAD_OPENGL_FUN(glLinkProgram
, FF_PFNGLLINKPROGRAMPROC
)
447 LOAD_OPENGL_FUN(glGetProgramiv
, FF_PFNGLGETPROGRAMIVPROC
)
448 LOAD_OPENGL_FUN(glGetProgramInfoLog
, FF_PFNGLGETPROGRAMINFOLOGPROC
)
449 LOAD_OPENGL_FUN(glAttachShader
, FF_PFNGLATTACHSHADERPROC
)
450 LOAD_OPENGL_FUN(glCreateShader
, FF_PFNGLCREATESHADERPROC
)
451 LOAD_OPENGL_FUN(glDeleteShader
, FF_PFNGLDELETESHADERPROC
)
452 LOAD_OPENGL_FUN(glCompileShader
, FF_PFNGLCOMPILESHADERPROC
)
453 LOAD_OPENGL_FUN(glShaderSource
, FF_PFNGLSHADERSOURCEPROC
)
454 LOAD_OPENGL_FUN(glGetShaderiv
, FF_PFNGLGETSHADERIVPROC
)
455 LOAD_OPENGL_FUN(glGetShaderInfoLog
, FF_PFNGLGETSHADERINFOLOGPROC
)
456 LOAD_OPENGL_FUN(glEnableVertexAttribArray
, FF_PFNGLENABLEVERTEXATTRIBARRAYPROC
)
457 LOAD_OPENGL_FUN(glVertexAttribPointer
, FF_PFNGLVERTEXATTRIBPOINTERPROC
)
461 #undef LOAD_OPENGL_FUN
463 #endif /* HAVE_SDL */
465 #if defined(__APPLE__)
466 static int av_cold
opengl_load_procedures(OpenGLContext
*opengl
)
468 FFOpenGLFunctions
*procs
= &opengl
->glprocs
;
471 if (!opengl
->no_window
)
472 return opengl_sdl_load_procedures(opengl
);
475 procs
->glActiveTexture
= glActiveTexture
;
476 procs
->glGenBuffers
= glGenBuffers
;
477 procs
->glDeleteBuffers
= glDeleteBuffers
;
478 procs
->glBufferData
= glBufferData
;
479 procs
->glBindBuffer
= glBindBuffer
;
480 procs
->glGetAttribLocation
= glGetAttribLocation
;
481 procs
->glGetUniformLocation
= glGetUniformLocation
;
482 procs
->glUniform1f
= glUniform1f
;
483 procs
->glUniform1i
= glUniform1i
;
484 procs
->glUniformMatrix4fv
= glUniformMatrix4fv
;
485 procs
->glCreateProgram
= glCreateProgram
;
486 procs
->glDeleteProgram
= glDeleteProgram
;
487 procs
->glUseProgram
= glUseProgram
;
488 procs
->glLinkProgram
= glLinkProgram
;
489 procs
->glGetProgramiv
= glGetProgramiv
;
490 procs
->glGetProgramInfoLog
= glGetProgramInfoLog
;
491 procs
->glAttachShader
= glAttachShader
;
492 procs
->glCreateShader
= glCreateShader
;
493 procs
->glDeleteShader
= glDeleteShader
;
494 procs
->glCompileShader
= glCompileShader
;
495 procs
->glShaderSource
= glShaderSource
;
496 procs
->glGetShaderiv
= glGetShaderiv
;
497 procs
->glGetShaderInfoLog
= glGetShaderInfoLog
;
498 procs
->glEnableVertexAttribArray
= glEnableVertexAttribArray
;
499 procs
->glVertexAttribPointer
= (FF_PFNGLVERTEXATTRIBPOINTERPROC
) glVertexAttribPointer
;
503 static int av_cold
opengl_load_procedures(OpenGLContext
*opengl
)
505 FFOpenGLFunctions
*procs
= &opengl
->glprocs
;
507 #if HAVE_GLXGETPROCADDRESS
508 #define SelectedGetProcAddress glXGetProcAddress
509 #elif HAVE_WGLGETPROCADDRESS
510 #define SelectedGetProcAddress wglGetProcAddress
513 #define LOAD_OPENGL_FUN(name, type) \
514 procs->name = (type)SelectedGetProcAddress(#name); \
515 if (!procs->name) { \
516 av_log(opengl, AV_LOG_ERROR, "Cannot load OpenGL function: '%s'\n", #name); \
517 return AVERROR(ENOSYS); \
521 if (!opengl
->no_window
)
522 return opengl_sdl_load_procedures(opengl
);
525 LOAD_OPENGL_FUN(glActiveTexture
, FF_PFNGLACTIVETEXTUREPROC
)
526 LOAD_OPENGL_FUN(glGenBuffers
, FF_PFNGLGENBUFFERSPROC
)
527 LOAD_OPENGL_FUN(glDeleteBuffers
, FF_PFNGLDELETEBUFFERSPROC
)
528 LOAD_OPENGL_FUN(glBufferData
, FF_PFNGLBUFFERDATAPROC
)
529 LOAD_OPENGL_FUN(glBindBuffer
, FF_PFNGLBINDBUFFERPROC
)
530 LOAD_OPENGL_FUN(glGetAttribLocation
, FF_PFNGLGETATTRIBLOCATIONPROC
)
531 LOAD_OPENGL_FUN(glGetUniformLocation
, FF_PFNGLGETUNIFORMLOCATIONPROC
)
532 LOAD_OPENGL_FUN(glUniform1f
, FF_PFNGLUNIFORM1FPROC
)
533 LOAD_OPENGL_FUN(glUniform1i
, FF_PFNGLUNIFORM1IPROC
)
534 LOAD_OPENGL_FUN(glUniformMatrix4fv
, FF_PFNGLUNIFORMMATRIX4FVPROC
)
535 LOAD_OPENGL_FUN(glCreateProgram
, FF_PFNGLCREATEPROGRAMPROC
)
536 LOAD_OPENGL_FUN(glDeleteProgram
, FF_PFNGLDELETEPROGRAMPROC
)
537 LOAD_OPENGL_FUN(glUseProgram
, FF_PFNGLUSEPROGRAMPROC
)
538 LOAD_OPENGL_FUN(glLinkProgram
, FF_PFNGLLINKPROGRAMPROC
)
539 LOAD_OPENGL_FUN(glGetProgramiv
, FF_PFNGLGETPROGRAMIVPROC
)
540 LOAD_OPENGL_FUN(glGetProgramInfoLog
, FF_PFNGLGETPROGRAMINFOLOGPROC
)
541 LOAD_OPENGL_FUN(glAttachShader
, FF_PFNGLATTACHSHADERPROC
)
542 LOAD_OPENGL_FUN(glCreateShader
, FF_PFNGLCREATESHADERPROC
)
543 LOAD_OPENGL_FUN(glDeleteShader
, FF_PFNGLDELETESHADERPROC
)
544 LOAD_OPENGL_FUN(glCompileShader
, FF_PFNGLCOMPILESHADERPROC
)
545 LOAD_OPENGL_FUN(glShaderSource
, FF_PFNGLSHADERSOURCEPROC
)
546 LOAD_OPENGL_FUN(glGetShaderiv
, FF_PFNGLGETSHADERIVPROC
)
547 LOAD_OPENGL_FUN(glGetShaderInfoLog
, FF_PFNGLGETSHADERINFOLOGPROC
)
548 LOAD_OPENGL_FUN(glEnableVertexAttribArray
, FF_PFNGLENABLEVERTEXATTRIBARRAYPROC
)
549 LOAD_OPENGL_FUN(glVertexAttribPointer
, FF_PFNGLVERTEXATTRIBPOINTERPROC
)
553 #undef SelectedGetProcAddress
554 #undef LOAD_OPENGL_FUN
558 static void opengl_make_identity(float matrix
[16])
560 memset(matrix
, 0, 16 * sizeof(float));
561 matrix
[0] = matrix
[5] = matrix
[10] = matrix
[15] = 1.0f
;
564 static void opengl_make_ortho(float matrix
[16], float left
, float right
,
565 float bottom
, float top
, float nearZ
, float farZ
)
567 float ral
= right
+ left
;
568 float rsl
= right
- left
;
569 float tab
= top
+ bottom
;
570 float tsb
= top
- bottom
;
571 float fan
= farZ
+ nearZ
;
572 float fsn
= farZ
- nearZ
;
574 memset(matrix
, 0, 16 * sizeof(float));
575 matrix
[0] = 2.0f
/ rsl
;
576 matrix
[5] = 2.0f
/ tsb
;
577 matrix
[10] = -2.0f
/ fsn
;
578 matrix
[12] = -ral
/ rsl
;
579 matrix
[13] = -tab
/ tsb
;
580 matrix
[14] = -fan
/ fsn
;
584 static av_cold
int opengl_read_limits(OpenGLContext
*opengl
)
587 const char *extension
;
590 } required_extensions
[] = {
591 { "GL_ARB_multitexture", 1, 3 },
592 { "GL_ARB_vertex_buffer_object", 1, 5 }, //GLX_ARB_vertex_buffer_object
593 { "GL_ARB_vertex_shader", 2, 0 },
594 { "GL_ARB_fragment_shader", 2, 0 },
595 { "GL_ARB_shader_objects", 2, 0 },
599 const char *extensions
, *version
;
601 version
= glGetString(GL_VERSION
);
602 extensions
= glGetString(GL_EXTENSIONS
);
604 av_log(opengl
, AV_LOG_DEBUG
, "OpenGL version: %s\n", version
);
605 sscanf(version
, "%d.%d", &major
, &minor
);
607 for (i
= 0; required_extensions
[i
].extension
; i
++) {
608 if (major
< required_extensions
[i
].major
&&
609 (major
== required_extensions
[i
].major
&& minor
< required_extensions
[i
].minor
) &&
610 !strstr(extensions
, required_extensions
[i
].extension
)) {
611 av_log(opengl
, AV_LOG_ERROR
, "Required extension %s is not supported.\n",
612 required_extensions
[i
].extension
);
613 av_log(opengl
, AV_LOG_DEBUG
, "Supported extensions are: %s\n", extensions
);
614 return AVERROR(ENOSYS
);
617 glGetIntegerv(GL_MAX_TEXTURE_SIZE
, &opengl
->max_texture_size
);
618 glGetIntegerv(GL_MAX_VIEWPORT_DIMS
, &opengl
->max_viewport_width
);
619 opengl
->non_pow_2_textures
= major
>= 2 || strstr(extensions
, "GL_ARB_texture_non_power_of_two");
620 #if defined(GL_ES_VERSION_2_0)
621 opengl
->unpack_subimage
= !!strstr(extensions
, "GL_EXT_unpack_subimage");
623 opengl
->unpack_subimage
= 1;
626 av_log(opengl
, AV_LOG_DEBUG
, "Non Power of 2 textures support: %s\n", opengl
->non_pow_2_textures
? "Yes" : "No");
627 av_log(opengl
, AV_LOG_DEBUG
, "Unpack Subimage extension support: %s\n", opengl
->unpack_subimage
? "Yes" : "No");
628 av_log(opengl
, AV_LOG_DEBUG
, "Max texture size: %dx%d\n", opengl
->max_texture_size
, opengl
->max_texture_size
);
629 av_log(opengl
, AV_LOG_DEBUG
, "Max viewport size: %dx%d\n",
630 opengl
->max_viewport_width
, opengl
->max_viewport_height
);
632 OPENGL_ERROR_CHECK(opengl
);
635 return AVERROR_EXTERNAL
;
638 static const char* opengl_get_fragment_shader_code(enum AVPixelFormat format
)
641 for (i
= 0; i
< FF_ARRAY_ELEMS(opengl_format_desc
); i
++) {
642 if (opengl_format_desc
[i
].fixel_format
== format
)
643 return *opengl_format_desc
[i
].fragment_shader
;
648 static int opengl_type_size(GLenum type
)
651 case GL_UNSIGNED_SHORT
:
652 case FF_GL_UNSIGNED_SHORT_1_5_5_5_REV
:
653 case GL_UNSIGNED_SHORT_5_6_5
:
655 case GL_UNSIGNED_BYTE
:
656 case FF_GL_UNSIGNED_BYTE_3_3_2
:
657 case FF_GL_UNSIGNED_BYTE_2_3_3_REV
:
664 static av_cold
void opengl_get_texture_params(OpenGLContext
*opengl
)
667 for (i
= 0; i
< FF_ARRAY_ELEMS(opengl_format_desc
); i
++) {
668 if (opengl_format_desc
[i
].fixel_format
== opengl
->pix_fmt
) {
669 opengl
->format
= opengl_format_desc
[i
].format
;
670 opengl
->type
= opengl_format_desc
[i
].type
;
676 static void opengl_compute_display_area(AVFormatContext
*s
)
678 AVRational sar
, dar
; /* sample and display aspect ratios */
679 OpenGLContext
*opengl
= s
->priv_data
;
680 AVStream
*st
= s
->streams
[0];
681 AVCodecContext
*encctx
= st
->codec
;
683 /* compute overlay width and height from the codec context information */
684 sar
= st
->sample_aspect_ratio
.num
? st
->sample_aspect_ratio
: (AVRational
){ 1, 1 };
685 dar
= av_mul_q(sar
, (AVRational
){ encctx
->width
, encctx
->height
});
687 /* we suppose the screen has a 1/1 sample aspect ratio */
688 /* fit in the window */
689 if (av_cmp_q(dar
, (AVRational
){ opengl
->window_width
, opengl
->window_height
}) > 0) {
691 opengl
->picture_width
= opengl
->window_width
;
692 opengl
->picture_height
= av_rescale(opengl
->picture_width
, dar
.den
, dar
.num
);
695 opengl
->picture_height
= opengl
->window_height
;
696 opengl
->picture_width
= av_rescale(opengl
->picture_height
, dar
.num
, dar
.den
);
700 static av_cold
void opengl_get_texture_size(OpenGLContext
*opengl
, int in_width
, int in_height
,
701 int *out_width
, int *out_height
)
703 if (opengl
->non_pow_2_textures
) {
704 *out_width
= in_width
;
705 *out_height
= in_height
;
707 int max
= FFMIN(FFMAX(in_width
, in_height
), opengl
->max_texture_size
);
708 unsigned power_of_2
= 1;
709 while (power_of_2
< max
)
711 *out_height
= power_of_2
;
712 *out_width
= power_of_2
;
713 av_log(opengl
, AV_LOG_DEBUG
, "Texture size calculated from %dx%d into %dx%d\n",
714 in_width
, in_height
, *out_width
, *out_height
);
718 static av_cold
void opengl_fill_color_map(OpenGLContext
*opengl
)
720 const AVPixFmtDescriptor
*desc
;
722 enum AVPixelFormat pix_fmt
= opengl
->pix_fmt
;
724 /* We need order of components, not exact position, some minor HACKs here */
725 if (pix_fmt
== AV_PIX_FMT_RGB565
|| pix_fmt
== AV_PIX_FMT_BGR555
||
726 pix_fmt
== AV_PIX_FMT_BGR8
|| pix_fmt
== AV_PIX_FMT_RGB8
)
727 pix_fmt
= AV_PIX_FMT_RGB24
;
728 else if (pix_fmt
== AV_PIX_FMT_BGR565
|| pix_fmt
== AV_PIX_FMT_RGB555
)
729 pix_fmt
= AV_PIX_FMT_BGR24
;
731 desc
= av_pix_fmt_desc_get(pix_fmt
);
732 if (!(desc
->flags
& AV_PIX_FMT_FLAG_RGB
))
735 #define FILL_COMPONENT(i) { \
736 shift = desc->comp[i].depth_minus1 >> 3; \
737 opengl->color_map[(i << 2) + ((desc->comp[i].offset_plus1 - 1) >> shift)] = 1.0; \
740 memset(opengl
->color_map
, 0, sizeof(opengl
->color_map
));
744 if (desc
->flags
& AV_PIX_FMT_FLAG_ALPHA
)
747 #undef FILL_COMPONENT
750 static av_cold GLuint
opengl_load_shader(OpenGLContext
*opengl
, GLenum type
, const char *source
)
752 GLuint shader
= opengl
->glprocs
.glCreateShader(type
);
755 av_log(opengl
, AV_LOG_ERROR
, "glCreateShader() failed\n");
758 opengl
->glprocs
.glShaderSource(shader
, 1, &source
, NULL
);
759 opengl
->glprocs
.glCompileShader(shader
);
761 opengl
->glprocs
.glGetShaderiv(shader
, FF_GL_COMPILE_STATUS
, &result
);
764 opengl
->glprocs
.glGetShaderiv(shader
, FF_GL_INFO_LOG_LENGTH
, &result
);
766 if ((log
= av_malloc(result
))) {
767 opengl
->glprocs
.glGetShaderInfoLog(shader
, result
, NULL
, log
);
768 av_log(opengl
, AV_LOG_ERROR
, "Compile error: %s\n", log
);
774 OPENGL_ERROR_CHECK(opengl
);
777 opengl
->glprocs
.glDeleteShader(shader
);
781 static av_cold
int opengl_compile_shaders(OpenGLContext
*opengl
, enum AVPixelFormat pix_fmt
)
784 const char *fragment_shader_code
= opengl_get_fragment_shader_code(pix_fmt
);
786 if (!fragment_shader_code
) {
787 av_log(opengl
, AV_LOG_ERROR
, "Provided pixel format '%s' is not supported\n",
788 av_get_pix_fmt_name(pix_fmt
));
789 return AVERROR(EINVAL
);
792 opengl
->vertex_shader
= opengl_load_shader(opengl
, FF_GL_VERTEX_SHADER
,
793 FF_OPENGL_VERTEX_SHADER
);
794 if (!opengl
->vertex_shader
) {
795 av_log(opengl
, AV_LOG_ERROR
, "Vertex shader loading failed.\n");
798 opengl
->fragment_shader
= opengl_load_shader(opengl
, FF_GL_FRAGMENT_SHADER
,
799 fragment_shader_code
);
800 if (!opengl
->fragment_shader
) {
801 av_log(opengl
, AV_LOG_ERROR
, "Fragment shader loading failed.\n");
805 opengl
->program
= opengl
->glprocs
.glCreateProgram();
806 if (!opengl
->program
)
809 opengl
->glprocs
.glAttachShader(opengl
->program
, opengl
->vertex_shader
);
810 opengl
->glprocs
.glAttachShader(opengl
->program
, opengl
->fragment_shader
);
811 opengl
->glprocs
.glLinkProgram(opengl
->program
);
813 opengl
->glprocs
.glGetProgramiv(opengl
->program
, FF_GL_LINK_STATUS
, &result
);
816 opengl
->glprocs
.glGetProgramiv(opengl
->program
, FF_GL_INFO_LOG_LENGTH
, &result
);
818 log
= av_malloc(result
);
821 opengl
->glprocs
.glGetProgramInfoLog(opengl
->program
, result
, NULL
, log
);
822 av_log(opengl
, AV_LOG_ERROR
, "Link error: %s\n", log
);
828 opengl
->position_attrib
= opengl
->glprocs
.glGetAttribLocation(opengl
->program
, "a_position");
829 opengl
->texture_coords_attrib
= opengl
->glprocs
.glGetAttribLocation(opengl
->program
, "a_textureCoords");
830 opengl
->projection_matrix_location
= opengl
->glprocs
.glGetUniformLocation(opengl
->program
, "u_projectionMatrix");
831 opengl
->model_view_matrix_location
= opengl
->glprocs
.glGetUniformLocation(opengl
->program
, "u_modelViewMatrix");
832 opengl
->color_map_location
= opengl
->glprocs
.glGetUniformLocation(opengl
->program
, "u_colorMap");
833 opengl
->texture_location
[0] = opengl
->glprocs
.glGetUniformLocation(opengl
->program
, "u_texture0");
834 opengl
->texture_location
[1] = opengl
->glprocs
.glGetUniformLocation(opengl
->program
, "u_texture1");
835 opengl
->texture_location
[2] = opengl
->glprocs
.glGetUniformLocation(opengl
->program
, "u_texture2");
836 opengl
->texture_location
[3] = opengl
->glprocs
.glGetUniformLocation(opengl
->program
, "u_texture3");
837 opengl
->chroma_div_w_location
= opengl
->glprocs
.glGetUniformLocation(opengl
->program
, "u_chroma_div_w");
838 opengl
->chroma_div_h_location
= opengl
->glprocs
.glGetUniformLocation(opengl
->program
, "u_chroma_div_h");
840 OPENGL_ERROR_CHECK(opengl
);
843 opengl
->glprocs
.glDeleteShader(opengl
->vertex_shader
);
844 opengl
->glprocs
.glDeleteShader(opengl
->fragment_shader
);
845 opengl
->glprocs
.glDeleteProgram(opengl
->program
);
846 opengl
->fragment_shader
= opengl
->vertex_shader
= opengl
->program
= 0;
847 return AVERROR_EXTERNAL
;
850 static av_cold
int opengl_configure_texture(OpenGLContext
*opengl
, GLuint texture
,
851 GLsizei width
, GLsizei height
)
854 int new_width
, new_height
;
855 opengl_get_texture_size(opengl
, width
, height
, &new_width
, &new_height
);
856 glBindTexture(GL_TEXTURE_2D
, texture
);
857 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
858 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
859 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
860 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
861 glTexImage2D(GL_TEXTURE_2D
, 0, opengl
->format
, new_width
, new_height
, 0,
862 opengl
->format
, opengl
->type
, NULL
);
863 OPENGL_ERROR_CHECK(NULL
);
867 return AVERROR_EXTERNAL
;
870 static av_cold
int opengl_prepare_vertex(AVFormatContext
*s
)
872 OpenGLContext
*opengl
= s
->priv_data
;
875 if (opengl
->window_width
> opengl
->max_viewport_width
|| opengl
->window_height
> opengl
->max_viewport_height
) {
876 opengl
->window_width
= FFMIN(opengl
->window_width
, opengl
->max_viewport_width
);
877 opengl
->window_height
= FFMIN(opengl
->window_height
, opengl
->max_viewport_height
);
878 av_log(opengl
, AV_LOG_WARNING
, "Too big viewport requested, limited to %dx%d", opengl
->window_width
, opengl
->window_height
);
880 glViewport(0, 0, opengl
->window_width
, opengl
->window_height
);
881 opengl_make_ortho(opengl
->projection_matrix
,
882 - (float)opengl
->window_width
/ 2.0f
, (float)opengl
->window_width
/ 2.0f
,
883 - (float)opengl
->window_height
/ 2.0f
, (float)opengl
->window_height
/ 2.0f
,
885 opengl_make_identity(opengl
->model_view_matrix
);
887 opengl_compute_display_area(s
);
889 opengl
->vertex
[0].z
= opengl
->vertex
[1].z
= opengl
->vertex
[2].z
= opengl
->vertex
[3].z
= 0.0f
;
890 opengl
->vertex
[0].x
= opengl
->vertex
[1].x
= - (float)opengl
->picture_width
/ 2.0f
;
891 opengl
->vertex
[2].x
= opengl
->vertex
[3].x
= (float)opengl
->picture_width
/ 2.0f
;
892 opengl
->vertex
[1].y
= opengl
->vertex
[2].y
= - (float)opengl
->picture_height
/ 2.0f
;
893 opengl
->vertex
[0].y
= opengl
->vertex
[3].y
= (float)opengl
->picture_height
/ 2.0f
;
895 opengl_get_texture_size(opengl
, opengl
->width
, opengl
->height
, &tex_w
, &tex_h
);
897 opengl
->vertex
[0].s0
= 0.0f
;
898 opengl
->vertex
[0].t0
= 0.0f
;
899 opengl
->vertex
[1].s0
= 0.0f
;
900 opengl
->vertex
[1].t0
= (float)opengl
->height
/ (float)tex_h
;
901 opengl
->vertex
[2].s0
= (float)opengl
->width
/ (float)tex_w
;
902 opengl
->vertex
[2].t0
= (float)opengl
->height
/ (float)tex_h
;
903 opengl
->vertex
[3].s0
= (float)opengl
->width
/ (float)tex_w
;
904 opengl
->vertex
[3].t0
= 0.0f
;
906 opengl
->glprocs
.glBindBuffer(FF_GL_ARRAY_BUFFER
, opengl
->vertex_buffer
);
907 opengl
->glprocs
.glBufferData(FF_GL_ARRAY_BUFFER
, sizeof(opengl
->vertex
), opengl
->vertex
, FF_GL_STATIC_DRAW
);
908 opengl
->glprocs
.glBindBuffer(FF_GL_ARRAY_BUFFER
, 0);
909 OPENGL_ERROR_CHECK(opengl
);
912 return AVERROR_EXTERNAL
;
915 static int opengl_prepare(OpenGLContext
*opengl
)
918 opengl
->glprocs
.glUseProgram(opengl
->program
);
919 opengl
->glprocs
.glUniformMatrix4fv(opengl
->projection_matrix_location
, 1, GL_FALSE
, opengl
->projection_matrix
);
920 opengl
->glprocs
.glUniformMatrix4fv(opengl
->model_view_matrix_location
, 1, GL_FALSE
, opengl
->model_view_matrix
);
921 for (i
= 0; i
< 4; i
++)
922 if (opengl
->texture_location
[i
] != -1) {
923 opengl
->glprocs
.glActiveTexture(GL_TEXTURE0
+ i
);
924 glBindTexture(GL_TEXTURE_2D
, opengl
->texture_name
[i
]);
925 opengl
->glprocs
.glUniform1i(opengl
->texture_location
[i
], i
);
927 if (opengl
->color_map_location
!= -1)
928 opengl
->glprocs
.glUniformMatrix4fv(opengl
->color_map_location
, 1, GL_FALSE
, opengl
->color_map
);
929 if (opengl
->chroma_div_h_location
!= -1)
930 opengl
->glprocs
.glUniform1f(opengl
->chroma_div_h_location
, opengl
->chroma_div_h
);
931 if (opengl
->chroma_div_w_location
!= -1)
932 opengl
->glprocs
.glUniform1f(opengl
->chroma_div_w_location
, opengl
->chroma_div_w
);
934 OPENGL_ERROR_CHECK(opengl
);
937 return AVERROR_EXTERNAL
;
940 static int opengl_create_window(AVFormatContext
*h
)
942 OpenGLContext
*opengl
= h
->priv_data
;
945 if (!opengl
->no_window
) {
947 if ((ret
= opengl_sdl_create_window(h
)) < 0) {
948 av_log(opengl
, AV_LOG_ERROR
, "Cannot create default SDL window.\n");
952 av_log(opengl
, AV_LOG_ERROR
, "FFmpeg is compiled without SDL. Cannot create default window.\n");
953 return AVERROR(ENOSYS
);
956 AVDeviceRect message
;
957 message
.x
= message
.y
= 0;
958 message
.width
= opengl
->window_width
;
959 message
.height
= opengl
->window_height
;
960 if ((ret
= avdevice_dev_to_app_control_message(h
, AV_DEV_TO_APP_CREATE_WINDOW_BUFFER
,
961 &message
, sizeof(message
))) < 0) {
962 av_log(opengl
, AV_LOG_ERROR
, "Application failed to create window buffer.\n");
965 if ((ret
= avdevice_dev_to_app_control_message(h
, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER
, NULL
, 0)) < 0) {
966 av_log(opengl
, AV_LOG_ERROR
, "Application failed to prepare window buffer.\n");
973 static int opengl_release_window(AVFormatContext
*h
)
976 OpenGLContext
*opengl
= h
->priv_data
;
977 if (!opengl
->no_window
) {
981 } else if ((ret
= avdevice_dev_to_app_control_message(h
, AV_DEV_TO_APP_DESTROY_WINDOW_BUFFER
, NULL
, 0)) < 0) {
982 av_log(opengl
, AV_LOG_ERROR
, "Application failed to release window buffer.\n");
988 static av_cold
int opengl_write_trailer(AVFormatContext
*h
)
990 OpenGLContext
*opengl
= h
->priv_data
;
992 if (opengl
->no_window
&&
993 avdevice_dev_to_app_control_message(h
, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER
, NULL
, 0) < 0)
994 av_log(opengl
, AV_LOG_ERROR
, "Application failed to prepare window buffer.\n");
996 opengl_deinit_context(opengl
);
997 opengl_release_window(h
);
1002 static av_cold
int opengl_init_context(OpenGLContext
*opengl
)
1005 const AVPixFmtDescriptor
*desc
;
1007 if ((ret
= opengl_compile_shaders(opengl
, opengl
->pix_fmt
)) < 0)
1010 desc
= av_pix_fmt_desc_get(opengl
->pix_fmt
);
1011 av_assert0(desc
->nb_components
> 0 && desc
->nb_components
<= 4);
1012 glGenTextures(desc
->nb_components
, opengl
->texture_name
);
1014 opengl
->glprocs
.glGenBuffers(2, &opengl
->index_buffer
);
1015 if (!opengl
->index_buffer
|| !opengl
->vertex_buffer
) {
1016 av_log(opengl
, AV_LOG_ERROR
, "Buffer generation failed.\n");
1017 ret
= AVERROR_EXTERNAL
;
1021 opengl_configure_texture(opengl
, opengl
->texture_name
[0], opengl
->width
, opengl
->height
);
1022 if (desc
->nb_components
> 1) {
1023 int has_alpha
= desc
->flags
& AV_PIX_FMT_FLAG_ALPHA
;
1024 int num_planes
= desc
->nb_components
- (has_alpha
? 1 : 0);
1025 if (opengl
->non_pow_2_textures
) {
1026 opengl
->chroma_div_w
= 1.0f
;
1027 opengl
->chroma_div_h
= 1.0f
;
1029 opengl
->chroma_div_w
= 1 << desc
->log2_chroma_w
;
1030 opengl
->chroma_div_h
= 1 << desc
->log2_chroma_h
;
1032 for (i
= 1; i
< num_planes
; i
++)
1033 if (opengl
->non_pow_2_textures
)
1034 opengl_configure_texture(opengl
, opengl
->texture_name
[i
],
1035 FF_CEIL_RSHIFT(opengl
->width
, desc
->log2_chroma_w
),
1036 FF_CEIL_RSHIFT(opengl
->height
, desc
->log2_chroma_h
));
1038 opengl_configure_texture(opengl
, opengl
->texture_name
[i
], opengl
->width
, opengl
->height
);
1040 opengl_configure_texture(opengl
, opengl
->texture_name
[3], opengl
->width
, opengl
->height
);
1043 opengl
->glprocs
.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER
, opengl
->index_buffer
);
1044 opengl
->glprocs
.glBufferData(FF_GL_ELEMENT_ARRAY_BUFFER
, sizeof(g_index
), g_index
, FF_GL_STATIC_DRAW
);
1045 opengl
->glprocs
.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER
, 0);
1048 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1050 glClearColor((float)opengl
->background
[0] / 255.0f
, (float)opengl
->background
[1] / 255.0f
,
1051 (float)opengl
->background
[2] / 255.0f
, 1.0f
);
1053 ret
= AVERROR_EXTERNAL
;
1054 OPENGL_ERROR_CHECK(opengl
);
1061 static av_cold
int opengl_write_header(AVFormatContext
*h
)
1063 OpenGLContext
*opengl
= h
->priv_data
;
1067 if (h
->nb_streams
!= 1 ||
1068 h
->streams
[0]->codec
->codec_type
!= AVMEDIA_TYPE_VIDEO
||
1069 h
->streams
[0]->codec
->codec_id
!= AV_CODEC_ID_RAWVIDEO
) {
1070 av_log(opengl
, AV_LOG_ERROR
, "Only a single video stream is supported.\n");
1071 return AVERROR(EINVAL
);
1074 opengl
->width
= st
->codec
->width
;
1075 opengl
->height
= st
->codec
->height
;
1076 opengl
->pix_fmt
= st
->codec
->pix_fmt
;
1077 if (!opengl
->window_width
)
1078 opengl
->window_width
= opengl
->width
;
1079 if (!opengl
->window_height
)
1080 opengl
->window_height
= opengl
->height
;
1082 if (!opengl
->window_title
&& !opengl
->no_window
)
1083 opengl
->window_title
= av_strdup(h
->filename
);
1085 if ((ret
= opengl_create_window(h
)))
1088 if ((ret
= opengl_read_limits(opengl
)) < 0)
1091 if (opengl
->width
> opengl
->max_texture_size
|| opengl
->height
> opengl
->max_texture_size
) {
1092 av_log(opengl
, AV_LOG_ERROR
, "Too big picture %dx%d, max supported size is %dx%d\n",
1093 opengl
->width
, opengl
->height
, opengl
->max_texture_size
, opengl
->max_texture_size
);
1094 ret
= AVERROR(EINVAL
);
1098 if ((ret
= opengl_load_procedures(opengl
)) < 0)
1101 opengl_fill_color_map(opengl
);
1102 opengl_get_texture_params(opengl
);
1104 if ((ret
= opengl_init_context(opengl
)) < 0)
1107 if ((ret
= opengl_prepare_vertex(h
)) < 0)
1110 glClear(GL_COLOR_BUFFER_BIT
);
1113 if (!opengl
->no_window
)
1114 SDL_GL_SwapBuffers();
1116 if (opengl
->no_window
&&
1117 (ret
= avdevice_dev_to_app_control_message(h
, AV_DEV_TO_APP_DISPLAY_WINDOW_BUFFER
, NULL
, 0)) < 0) {
1118 av_log(opengl
, AV_LOG_ERROR
, "Application failed to display window buffer.\n");
1122 ret
= AVERROR_EXTERNAL
;
1123 OPENGL_ERROR_CHECK(opengl
);
1129 opengl_write_trailer(h
);
1133 static uint8_t* opengl_get_plane_pointer(OpenGLContext
*opengl
, AVPacket
*pkt
, int comp_index
,
1134 const AVPixFmtDescriptor
*desc
)
1136 uint8_t *data
= pkt
->data
;
1137 int wordsize
= opengl_type_size(opengl
->type
);
1138 int width_chroma
= FF_CEIL_RSHIFT(opengl
->width
, desc
->log2_chroma_w
);
1139 int height_chroma
= FF_CEIL_RSHIFT(opengl
->height
, desc
->log2_chroma_h
);
1140 int plane
= desc
->comp
[comp_index
].plane
;
1146 data
+= opengl
->width
* opengl
->height
* wordsize
;
1149 data
+= opengl
->width
* opengl
->height
* wordsize
;
1150 data
+= width_chroma
* height_chroma
* wordsize
;
1153 data
+= opengl
->width
* opengl
->height
* wordsize
;
1154 data
+= 2 * width_chroma
* height_chroma
* wordsize
;
1162 #define LOAD_TEXTURE_DATA(comp_index, sub) \
1164 int width = sub ? FF_CEIL_RSHIFT(opengl->width, desc->log2_chroma_w) : opengl->width; \
1165 int height = sub ? FF_CEIL_RSHIFT(opengl->height, desc->log2_chroma_h): opengl->height; \
1167 int plane = desc->comp[comp_index].plane; \
1169 glBindTexture(GL_TEXTURE_2D, opengl->texture_name[comp_index]); \
1171 GLint length = ((AVFrame *)input)->linesize[plane]; \
1172 int bytes_per_pixel = opengl_type_size(opengl->type); \
1173 if (!(desc->flags & AV_PIX_FMT_FLAG_PLANAR)) \
1174 bytes_per_pixel *= desc->nb_components; \
1175 data = ((AVFrame *)input)->data[plane]; \
1176 if (!(length % bytes_per_pixel) && \
1177 (opengl->unpack_subimage || ((length / bytes_per_pixel) == width))) { \
1178 length /= bytes_per_pixel; \
1179 if (length != width) \
1180 glPixelStorei(FF_GL_UNPACK_ROW_LENGTH, length); \
1181 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, \
1182 opengl->format, opengl->type, data); \
1183 if (length != width) \
1184 glPixelStorei(FF_GL_UNPACK_ROW_LENGTH, 0); \
1187 for (h = 0; h < height; h++) { \
1188 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, h, width, 1, \
1189 opengl->format, opengl->type, data); \
1194 data = opengl_get_plane_pointer(opengl, input, comp_index, desc); \
1195 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, \
1196 opengl->format, opengl->type, data); \
1200 static int opengl_draw(AVFormatContext
*h
, void *input
, int repaint
, int is_pkt
)
1202 OpenGLContext
*opengl
= h
->priv_data
;
1203 enum AVPixelFormat pix_fmt
= h
->streams
[0]->codec
->pix_fmt
;
1204 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(pix_fmt
);
1208 if (!opengl
->no_window
&& (ret
= opengl_sdl_process_events(h
)) < 0)
1211 if (opengl
->no_window
&&
1212 (ret
= avdevice_dev_to_app_control_message(h
, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER
, NULL
, 0)) < 0) {
1213 av_log(opengl
, AV_LOG_ERROR
, "Application failed to prepare window buffer.\n");
1217 glClear(GL_COLOR_BUFFER_BIT
);
1221 glPixelStorei(GL_UNPACK_ALIGNMENT
, 1);
1222 LOAD_TEXTURE_DATA(0, 0)
1223 if (desc
->flags
& AV_PIX_FMT_FLAG_PLANAR
) {
1224 LOAD_TEXTURE_DATA(1, 1)
1225 LOAD_TEXTURE_DATA(2, 1)
1226 if (desc
->flags
& AV_PIX_FMT_FLAG_ALPHA
)
1227 LOAD_TEXTURE_DATA(3, 0)
1230 ret
= AVERROR_EXTERNAL
;
1231 OPENGL_ERROR_CHECK(opengl
);
1233 if ((ret
= opengl_prepare(opengl
)) < 0)
1236 opengl
->glprocs
.glBindBuffer(FF_GL_ARRAY_BUFFER
, opengl
->vertex_buffer
);
1237 opengl
->glprocs
.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER
, opengl
->index_buffer
);
1238 opengl
->glprocs
.glVertexAttribPointer(opengl
->position_attrib
, 3, GL_FLOAT
, GL_FALSE
, sizeof(OpenGLVertexInfo
), 0);
1239 opengl
->glprocs
.glEnableVertexAttribArray(opengl
->position_attrib
);
1240 opengl
->glprocs
.glVertexAttribPointer(opengl
->texture_coords_attrib
, 2, GL_FLOAT
, GL_FALSE
, sizeof(OpenGLVertexInfo
), 12);
1241 opengl
->glprocs
.glEnableVertexAttribArray(opengl
->texture_coords_attrib
);
1243 glDrawElements(GL_TRIANGLES
, FF_ARRAY_ELEMS(g_index
), GL_UNSIGNED_SHORT
, 0);
1245 ret
= AVERROR_EXTERNAL
;
1246 OPENGL_ERROR_CHECK(opengl
);
1249 if (!opengl
->no_window
)
1250 SDL_GL_SwapBuffers();
1252 if (opengl
->no_window
&&
1253 (ret
= avdevice_dev_to_app_control_message(h
, AV_DEV_TO_APP_DISPLAY_WINDOW_BUFFER
, NULL
, 0)) < 0) {
1254 av_log(opengl
, AV_LOG_ERROR
, "Application failed to display window buffer.\n");
1263 static int opengl_write_packet(AVFormatContext
*h
, AVPacket
*pkt
)
1265 return opengl_draw(h
, pkt
, 0, 1);
1268 static int opengl_write_frame(AVFormatContext
*h
, int stream_index
,
1269 AVFrame
**frame
, unsigned flags
)
1271 if ((flags
& AV_WRITE_UNCODED_FRAME_QUERY
))
1273 return opengl_draw(h
, *frame
, 0, 0);
1276 #define OFFSET(x) offsetof(OpenGLContext, x)
1277 #define ENC AV_OPT_FLAG_ENCODING_PARAM
1278 static const AVOption options
[] = {
1279 { "background", "set background color", OFFSET(background
), AV_OPT_TYPE_COLOR
, {.str
= "black"}, CHAR_MIN
, CHAR_MAX
, ENC
},
1280 { "no_window", "disable default window", OFFSET(no_window
), AV_OPT_TYPE_INT
, {.i64
= 0}, INT_MIN
, INT_MAX
, ENC
},
1281 { "window_title", "set window title", OFFSET(window_title
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, ENC
},
1282 { "window_size", "set window size", OFFSET(window_width
), AV_OPT_TYPE_IMAGE_SIZE
, {.str
= NULL
}, 0, 0, ENC
},
1286 static const AVClass opengl_class
= {
1287 .class_name
= "opengl outdev",
1288 .item_name
= av_default_item_name
,
1290 .version
= LIBAVUTIL_VERSION_INT
,
1291 .category
= AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT
,
1294 AVOutputFormat ff_opengl_muxer
= {
1296 .long_name
= NULL_IF_CONFIG_SMALL("OpenGL output"),
1297 .priv_data_size
= sizeof(OpenGLContext
),
1298 .audio_codec
= AV_CODEC_ID_NONE
,
1299 .video_codec
= AV_CODEC_ID_RAWVIDEO
,
1300 .write_header
= opengl_write_header
,
1301 .write_packet
= opengl_write_packet
,
1302 .write_uncoded_frame
= opengl_write_frame
,
1303 .write_trailer
= opengl_write_trailer
,
1304 .control_message
= opengl_control_message
,
1305 .flags
= AVFMT_NOFILE
| AVFMT_VARIABLE_FPS
| AVFMT_NOTIMESTAMPS
,
1306 .priv_class
= &opengl_class
,