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.
37 #include <OpenGL/gl3.h>
44 #if HAVE_GLXGETPROCADDRESS
52 #include "libavutil/common.h"
53 #include "libavutil/pixdesc.h"
54 #include "libavutil/log.h"
55 #include "libavutil/opt.h"
56 #include "libavutil/avassert.h"
57 #include "libavutil/avstring.h"
58 #include "libavformat/avformat.h"
59 #include "libavformat/internal.h"
60 #include "libavdevice/avdevice.h"
61 #include "opengl_enc_shaders.h"
67 /* FF_GL_RED_COMPONENT is used for plannar pixel types.
68 * Only red component is sampled in shaders.
69 * On some platforms GL_RED is not available and GL_LUMINANCE have to be used,
70 * but since OpenGL 3.0 GL_LUMINANCE is deprecated.
71 * GL_RED produces RGBA = value, 0, 0, 1.
72 * GL_LUMINANCE produces RGBA = value, value, value, 1.
73 * Note: GL_INTENSITY may also be used which produce RGBA = value, value, value, value. */
75 #define FF_GL_RED_COMPONENT GL_RED
76 #elif defined(GL_LUMINANCE)
77 #define FF_GL_RED_COMPONENT GL_LUMINANCE
79 #define FF_GL_RED_COMPONENT 0x1903; //GL_RED
82 /* Constants not defined for iOS */
83 #define FF_GL_UNSIGNED_BYTE_3_3_2 0x8032
84 #define FF_GL_UNSIGNED_BYTE_2_3_3_REV 0x8362
85 #define FF_GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
86 #define FF_GL_UNPACK_ROW_LENGTH 0x0CF2
88 /* MinGW exposes only OpenGL 1.1 API */
89 #define FF_GL_ARRAY_BUFFER 0x8892
90 #define FF_GL_ELEMENT_ARRAY_BUFFER 0x8893
91 #define FF_GL_STATIC_DRAW 0x88E4
92 #define FF_GL_FRAGMENT_SHADER 0x8B30
93 #define FF_GL_VERTEX_SHADER 0x8B31
94 #define FF_GL_COMPILE_STATUS 0x8B81
95 #define FF_GL_LINK_STATUS 0x8B82
96 #define FF_GL_INFO_LOG_LENGTH 0x8B84
97 typedef void (APIENTRY
*FF_PFNGLACTIVETEXTUREPROC
) (GLenum texture
);
98 typedef void (APIENTRY
*FF_PFNGLGENBUFFERSPROC
) (GLsizei n
, GLuint
*buffers
);
99 typedef void (APIENTRY
*FF_PFNGLDELETEBUFFERSPROC
) (GLsizei n
, const GLuint
*buffers
);
100 typedef void (APIENTRY
*FF_PFNGLBUFFERDATAPROC
) (GLenum target
, ptrdiff_t size
, const GLvoid
*data
, GLenum usage
);
101 typedef void (APIENTRY
*FF_PFNGLBINDBUFFERPROC
) (GLenum target
, GLuint buffer
);
102 typedef GLint (APIENTRY
*FF_PFNGLGETATTRIBLOCATIONPROC
) (GLuint program
, const char *name
);
103 typedef void (APIENTRY
*FF_PFNGLENABLEVERTEXATTRIBARRAYPROC
) (GLuint index
);
104 typedef void (APIENTRY
*FF_PFNGLVERTEXATTRIBPOINTERPROC
) (GLuint index
, GLint size
, GLenum type
, GLboolean normalized
, GLsizei stride
, uintptr_t pointer
);
105 typedef GLint (APIENTRY
*FF_PFNGLGETUNIFORMLOCATIONPROC
) (GLuint program
, const char *name
);
106 typedef void (APIENTRY
*FF_PFNGLUNIFORM1FPROC
) (GLint location
, GLfloat v0
);
107 typedef void (APIENTRY
*FF_PFNGLUNIFORM1IPROC
) (GLint location
, GLint v0
);
108 typedef void (APIENTRY
*FF_PFNGLUNIFORMMATRIX4FVPROC
) (GLint location
, GLsizei count
, GLboolean transpose
, const GLfloat
*value
);
109 typedef GLuint (APIENTRY
*FF_PFNGLCREATEPROGRAMPROC
) (void);
110 typedef void (APIENTRY
*FF_PFNGLDELETEPROGRAMPROC
) (GLuint program
);
111 typedef void (APIENTRY
*FF_PFNGLUSEPROGRAMPROC
) (GLuint program
);
112 typedef void (APIENTRY
*FF_PFNGLLINKPROGRAMPROC
) (GLuint program
);
113 typedef void (APIENTRY
*FF_PFNGLGETPROGRAMIVPROC
) (GLuint program
, GLenum pname
, GLint
*params
);
114 typedef void (APIENTRY
*FF_PFNGLGETPROGRAMINFOLOGPROC
) (GLuint program
, GLsizei bufSize
, GLsizei
*length
, char *infoLog
);
115 typedef void (APIENTRY
*FF_PFNGLATTACHSHADERPROC
) (GLuint program
, GLuint shader
);
116 typedef GLuint (APIENTRY
*FF_PFNGLCREATESHADERPROC
) (GLenum type
);
117 typedef void (APIENTRY
*FF_PFNGLDELETESHADERPROC
) (GLuint shader
);
118 typedef void (APIENTRY
*FF_PFNGLCOMPILESHADERPROC
) (GLuint shader
);
119 typedef void (APIENTRY
*FF_PFNGLSHADERSOURCEPROC
) (GLuint shader
, GLsizei count
, const char* *string
, const GLint
*length
);
120 typedef void (APIENTRY
*FF_PFNGLGETSHADERIVPROC
) (GLuint shader
, GLenum pname
, GLint
*params
);
121 typedef void (APIENTRY
*FF_PFNGLGETSHADERINFOLOGPROC
) (GLuint shader
, GLsizei bufSize
, GLsizei
*length
, char *infoLog
);
123 typedef struct FFOpenGLFunctions
{
124 FF_PFNGLACTIVETEXTUREPROC glActiveTexture
; //Require GL ARB multitexture
125 FF_PFNGLGENBUFFERSPROC glGenBuffers
; //Require GL_ARB_vertex_buffer_object
126 FF_PFNGLDELETEBUFFERSPROC glDeleteBuffers
; //Require GL_ARB_vertex_buffer_object
127 FF_PFNGLBUFFERDATAPROC glBufferData
; //Require GL_ARB_vertex_buffer_object
128 FF_PFNGLBINDBUFFERPROC glBindBuffer
; //Require GL_ARB_vertex_buffer_object
129 FF_PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation
; //Require GL_ARB_vertex_shader
130 FF_PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray
; //Require GL_ARB_vertex_shader
131 FF_PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer
; //Require GL_ARB_vertex_shader
132 FF_PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation
; //Require GL_ARB_shader_objects
133 FF_PFNGLUNIFORM1FPROC glUniform1f
; //Require GL_ARB_shader_objects
134 FF_PFNGLUNIFORM1IPROC glUniform1i
; //Require GL_ARB_shader_objects
135 FF_PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv
; //Require GL_ARB_shader_objects
136 FF_PFNGLCREATEPROGRAMPROC glCreateProgram
; //Require GL_ARB_shader_objects
137 FF_PFNGLDELETEPROGRAMPROC glDeleteProgram
; //Require GL_ARB_shader_objects
138 FF_PFNGLUSEPROGRAMPROC glUseProgram
; //Require GL_ARB_shader_objects
139 FF_PFNGLLINKPROGRAMPROC glLinkProgram
; //Require GL_ARB_shader_objects
140 FF_PFNGLGETPROGRAMIVPROC glGetProgramiv
; //Require GL_ARB_shader_objects
141 FF_PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog
; //Require GL_ARB_shader_objects
142 FF_PFNGLATTACHSHADERPROC glAttachShader
; //Require GL_ARB_shader_objects
143 FF_PFNGLCREATESHADERPROC glCreateShader
; //Require GL_ARB_shader_objects
144 FF_PFNGLDELETESHADERPROC glDeleteShader
; //Require GL_ARB_shader_objects
145 FF_PFNGLCOMPILESHADERPROC glCompileShader
; //Require GL_ARB_shader_objects
146 FF_PFNGLSHADERSOURCEPROC glShaderSource
; //Require GL_ARB_shader_objects
147 FF_PFNGLGETSHADERIVPROC glGetShaderiv
; //Require GL_ARB_shader_objects
148 FF_PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog
; //Require GL_ARB_shader_objects
151 #define OPENGL_ERROR_CHECK(ctx) \
154 if ((err_code = glGetError()) != GL_NO_ERROR) { \
155 av_log(ctx, AV_LOG_ERROR, "OpenGL error occurred in '%s', line %d: %d\n", __FUNCTION__, __LINE__, err_code); \
160 typedef struct OpenGLVertexInfo
162 float x
, y
, z
; ///<Position
163 float s0
, t0
; ///<Texture coords
166 /* defines 2 triangles to display */
167 static const GLushort g_index
[6] =
173 typedef struct OpenGLContext
{
174 AVClass
*class; ///< class for private options
177 SDL_Surface
*surface
;
179 FFOpenGLFunctions glprocs
;
181 int inited
; ///< Set to 1 when write_header was successfully called.
182 uint8_t background
[4]; ///< Background color
183 int no_window
; ///< 0 for create default window
184 char *window_title
; ///< Title of the window
186 /* OpenGL implementation limits */
187 GLint max_texture_size
; ///< Maximum texture size
188 GLint max_viewport_width
; ///< Maximum viewport size
189 GLint max_viewport_height
; ///< Maximum viewport size
190 int non_pow_2_textures
; ///< 1 when non power of 2 textures are supported
191 int unpack_subimage
; ///< 1 when GL_EXT_unpack_subimage is available
193 /* Current OpenGL configuration */
194 GLuint program
; ///< Shader program
195 GLuint vertex_shader
; ///< Vertex shader
196 GLuint fragment_shader
; ///< Fragment shader for current pix_pmt
197 GLuint texture_name
[4]; ///< Textures' IDs
198 GLuint index_buffer
; ///< Index buffer
199 GLuint vertex_buffer
; ///< Vertex buffer
200 OpenGLVertexInfo vertex
[4]; ///< VBO
201 GLint projection_matrix_location
; ///< Uniforms' locations
202 GLint model_view_matrix_location
;
203 GLint color_map_location
;
204 GLint chroma_div_w_location
;
205 GLint chroma_div_h_location
;
206 GLint texture_location
[4];
207 GLint position_attrib
; ///< Attibutes' locations
208 GLint texture_coords_attrib
;
210 GLfloat projection_matrix
[16]; ///< Projection matrix
211 GLfloat model_view_matrix
[16]; ///< Modev view matrix
212 GLfloat color_map
[16]; ///< RGBA color map matrix
213 GLfloat chroma_div_w
; ///< Chroma subsampling w ratio
214 GLfloat chroma_div_h
; ///< Chroma subsampling h ratio
216 /* Stream information */
219 int width
; ///< Stream width
220 int height
; ///< Stream height
221 enum AVPixelFormat pix_fmt
; ///< Stream pixel format
222 int picture_width
; ///< Rendered width
223 int picture_height
; ///< Rendered height
228 static const struct OpenGLFormatDesc
{
229 enum AVPixelFormat fixel_format
;
230 const char * const * fragment_shader
;
233 } opengl_format_desc
[] = {
234 { AV_PIX_FMT_YUV420P
, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
235 { AV_PIX_FMT_YUV444P
, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
236 { AV_PIX_FMT_YUV422P
, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
237 { AV_PIX_FMT_YUV410P
, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
238 { AV_PIX_FMT_YUV411P
, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
239 { AV_PIX_FMT_YUV440P
, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
240 { AV_PIX_FMT_YUV420P16
, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_SHORT
},
241 { AV_PIX_FMT_YUV422P16
, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_SHORT
},
242 { AV_PIX_FMT_YUV444P16
, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_SHORT
},
243 { AV_PIX_FMT_YUVA420P
, &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
244 { AV_PIX_FMT_YUVA444P
, &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
245 { AV_PIX_FMT_YUVA422P
, &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
246 { AV_PIX_FMT_YUVA420P16
, &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_SHORT
},
247 { AV_PIX_FMT_YUVA422P16
, &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_SHORT
},
248 { AV_PIX_FMT_YUVA444P16
, &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_SHORT
},
249 { AV_PIX_FMT_RGB24
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGB
, GL_UNSIGNED_BYTE
},
250 { AV_PIX_FMT_BGR24
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGB
, GL_UNSIGNED_BYTE
},
251 { AV_PIX_FMT_0RGB
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGBA
, GL_UNSIGNED_BYTE
},
252 { AV_PIX_FMT_RGB0
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGBA
, GL_UNSIGNED_BYTE
},
253 { AV_PIX_FMT_0BGR
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGBA
, GL_UNSIGNED_BYTE
},
254 { AV_PIX_FMT_BGR0
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGBA
, GL_UNSIGNED_BYTE
},
255 { AV_PIX_FMT_RGB565
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGB
, GL_UNSIGNED_SHORT_5_6_5
},
256 { AV_PIX_FMT_BGR565
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGB
, GL_UNSIGNED_SHORT_5_6_5
},
257 { AV_PIX_FMT_RGB555
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGBA
, FF_GL_UNSIGNED_SHORT_1_5_5_5_REV
},
258 { AV_PIX_FMT_BGR555
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGBA
, FF_GL_UNSIGNED_SHORT_1_5_5_5_REV
},
259 { AV_PIX_FMT_RGB8
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGB
, FF_GL_UNSIGNED_BYTE_3_3_2
},
260 { AV_PIX_FMT_BGR8
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGB
, FF_GL_UNSIGNED_BYTE_2_3_3_REV
},
261 { AV_PIX_FMT_RGB48
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET
, GL_RGB
, GL_UNSIGNED_SHORT
},
262 { AV_PIX_FMT_ARGB
, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET
, GL_RGBA
, GL_UNSIGNED_BYTE
},
263 { AV_PIX_FMT_RGBA
, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET
, GL_RGBA
, GL_UNSIGNED_BYTE
},
264 { AV_PIX_FMT_ABGR
, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET
, GL_RGBA
, GL_UNSIGNED_BYTE
},
265 { AV_PIX_FMT_BGRA
, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET
, GL_RGBA
, GL_UNSIGNED_BYTE
},
266 { AV_PIX_FMT_RGBA64
, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET
, GL_RGBA
, GL_UNSIGNED_SHORT
},
267 { AV_PIX_FMT_BGRA64
, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET
, GL_RGBA
, GL_UNSIGNED_SHORT
},
268 { AV_PIX_FMT_GBRP
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
269 { AV_PIX_FMT_GBRP16
, &FF_OPENGL_FRAGMENT_SHADER_RGB_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_SHORT
},
270 { AV_PIX_FMT_GBRAP
, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
271 { AV_PIX_FMT_GBRAP16
, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PLANAR
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_SHORT
},
272 { AV_PIX_FMT_GRAY8
, &FF_OPENGL_FRAGMENT_SHADER_GRAY
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_BYTE
},
273 { AV_PIX_FMT_GRAY16
, &FF_OPENGL_FRAGMENT_SHADER_GRAY
, FF_GL_RED_COMPONENT
, GL_UNSIGNED_SHORT
},
274 { AV_PIX_FMT_NONE
, NULL
}
277 static av_cold
int opengl_prepare_vertex(AVFormatContext
*s
);
278 static int opengl_draw(AVFormatContext
*h
, void *intput
, int repaint
, int is_pkt
);
279 static av_cold
int opengl_init_context(OpenGLContext
*opengl
);
281 static av_cold
void opengl_deinit_context(OpenGLContext
*opengl
)
283 glDeleteTextures(4, opengl
->texture_name
);
284 opengl
->texture_name
[0] = opengl
->texture_name
[1] =
285 opengl
->texture_name
[2] = opengl
->texture_name
[3] = 0;
286 if (opengl
->glprocs
.glUseProgram
)
287 opengl
->glprocs
.glUseProgram(0);
288 if (opengl
->glprocs
.glDeleteProgram
) {
289 opengl
->glprocs
.glDeleteProgram(opengl
->program
);
292 if (opengl
->glprocs
.glDeleteShader
) {
293 opengl
->glprocs
.glDeleteShader(opengl
->vertex_shader
);
294 opengl
->glprocs
.glDeleteShader(opengl
->fragment_shader
);
295 opengl
->vertex_shader
= opengl
->fragment_shader
= 0;
297 if (opengl
->glprocs
.glBindBuffer
) {
298 opengl
->glprocs
.glBindBuffer(FF_GL_ARRAY_BUFFER
, 0);
299 opengl
->glprocs
.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER
, 0);
301 if (opengl
->glprocs
.glDeleteBuffers
) {
302 opengl
->glprocs
.glDeleteBuffers(2, &opengl
->index_buffer
);
303 opengl
->vertex_buffer
= opengl
->index_buffer
= 0;
307 static int opengl_resize(AVFormatContext
*h
, int width
, int height
)
310 OpenGLContext
*opengl
= h
->priv_data
;
311 opengl
->window_width
= width
;
312 opengl
->window_height
= height
;
313 if (opengl
->inited
) {
314 if (opengl
->no_window
&&
315 (ret
= avdevice_dev_to_app_control_message(h
, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER
, NULL
, 0)) < 0) {
316 av_log(opengl
, AV_LOG_ERROR
, "Application failed to prepare window buffer.\n");
319 if ((ret
= opengl_prepare_vertex(h
)) < 0)
321 ret
= opengl_draw(h
, NULL
, 1, 0);
327 static int opengl_control_message(AVFormatContext
*h
, int type
, void *data
, size_t data_size
)
329 OpenGLContext
*opengl
= h
->priv_data
;
331 case AV_APP_TO_DEV_WINDOW_SIZE
:
333 AVDeviceRect
*message
= data
;
334 return opengl_resize(h
, message
->width
, message
->height
);
336 return AVERROR(EINVAL
);
337 case AV_APP_TO_DEV_WINDOW_REPAINT
:
338 return opengl_resize(h
, opengl
->window_width
, opengl
->window_height
);
340 return AVERROR(ENOSYS
);
344 static int opengl_sdl_recreate_window(OpenGLContext
*opengl
, int width
, int height
)
346 opengl
->surface
= SDL_SetVideoMode(width
, height
,
347 32, SDL_OPENGL
| SDL_RESIZABLE
);
348 if (!opengl
->surface
) {
349 av_log(opengl
, AV_LOG_ERROR
, "Unable to set video mode: %s\n", SDL_GetError());
350 return AVERROR_EXTERNAL
;
352 SDL_GL_SetAttribute(SDL_GL_RED_SIZE
, 8);
353 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE
, 8);
354 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE
, 8);
355 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE
, 8);
356 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER
, 1);
360 static int opengl_sdl_process_events(AVFormatContext
*h
)
363 OpenGLContext
*opengl
= h
->priv_data
;
366 while (SDL_PeepEvents(&event
, 1, SDL_GETEVENT
, SDL_ALLEVENTS
) > 0) {
367 switch (event
.type
) {
371 switch (event
.key
.keysym
.sym
) {
377 case SDL_VIDEORESIZE
: {
380 AVDeviceRect message
;
381 /* clean up old context because SDL_SetVideoMode may lose its state. */
382 SDL_VideoDriverName(buffer
, sizeof(buffer
));
383 reinit
= !av_strncasecmp(buffer
, "quartz", sizeof(buffer
));
385 opengl_deinit_context(opengl
);
387 if ((ret
= opengl_sdl_recreate_window(opengl
, event
.resize
.w
, event
.resize
.h
)) < 0)
389 if (reinit
&& (ret
= opengl_init_context(opengl
)) < 0)
391 message
.width
= opengl
->surface
->w
;
392 message
.height
= opengl
->surface
->h
;
393 return opengl_control_message(h
, AV_APP_TO_DEV_WINDOW_SIZE
, &message
, sizeof(AVDeviceRect
));
400 static int av_cold
opengl_sdl_create_window(AVFormatContext
*h
)
404 OpenGLContext
*opengl
= h
->priv_data
;
405 AVDeviceRect message
;
406 if (SDL_Init(SDL_INIT_VIDEO
)) {
407 av_log(opengl
, AV_LOG_ERROR
, "Unable to initialize SDL: %s\n", SDL_GetError());
408 return AVERROR_EXTERNAL
;
410 if ((ret
= opengl_sdl_recreate_window(opengl
, opengl
->window_width
,
411 opengl
->window_height
)) < 0)
413 av_log(opengl
, AV_LOG_INFO
, "SDL driver: '%s'.\n", SDL_VideoDriverName(buffer
, sizeof(buffer
)));
414 message
.width
= opengl
->surface
->w
;
415 message
.height
= opengl
->surface
->h
;
416 SDL_WM_SetCaption(opengl
->window_title
, NULL
);
417 opengl_control_message(h
, AV_APP_TO_DEV_WINDOW_SIZE
, &message
, sizeof(AVDeviceRect
));
421 static int av_cold
opengl_sdl_load_procedures(OpenGLContext
*opengl
)
423 FFOpenGLFunctions
*procs
= &opengl
->glprocs
;
425 #define LOAD_OPENGL_FUN(name, type) \
426 procs->name = (type)SDL_GL_GetProcAddress(#name); \
427 if (!procs->name) { \
428 av_log(opengl, AV_LOG_ERROR, "Cannot load OpenGL function: '%s'\n", #name); \
429 return AVERROR(ENOSYS); \
432 LOAD_OPENGL_FUN(glActiveTexture
, FF_PFNGLACTIVETEXTUREPROC
)
433 LOAD_OPENGL_FUN(glGenBuffers
, FF_PFNGLGENBUFFERSPROC
)
434 LOAD_OPENGL_FUN(glDeleteBuffers
, FF_PFNGLDELETEBUFFERSPROC
)
435 LOAD_OPENGL_FUN(glBufferData
, FF_PFNGLBUFFERDATAPROC
)
436 LOAD_OPENGL_FUN(glBindBuffer
, FF_PFNGLBINDBUFFERPROC
)
437 LOAD_OPENGL_FUN(glGetAttribLocation
, FF_PFNGLGETATTRIBLOCATIONPROC
)
438 LOAD_OPENGL_FUN(glGetUniformLocation
, FF_PFNGLGETUNIFORMLOCATIONPROC
)
439 LOAD_OPENGL_FUN(glUniform1f
, FF_PFNGLUNIFORM1FPROC
)
440 LOAD_OPENGL_FUN(glUniform1i
, FF_PFNGLUNIFORM1IPROC
)
441 LOAD_OPENGL_FUN(glUniformMatrix4fv
, FF_PFNGLUNIFORMMATRIX4FVPROC
)
442 LOAD_OPENGL_FUN(glCreateProgram
, FF_PFNGLCREATEPROGRAMPROC
)
443 LOAD_OPENGL_FUN(glDeleteProgram
, FF_PFNGLDELETEPROGRAMPROC
)
444 LOAD_OPENGL_FUN(glUseProgram
, FF_PFNGLUSEPROGRAMPROC
)
445 LOAD_OPENGL_FUN(glLinkProgram
, FF_PFNGLLINKPROGRAMPROC
)
446 LOAD_OPENGL_FUN(glGetProgramiv
, FF_PFNGLGETPROGRAMIVPROC
)
447 LOAD_OPENGL_FUN(glGetProgramInfoLog
, FF_PFNGLGETPROGRAMINFOLOGPROC
)
448 LOAD_OPENGL_FUN(glAttachShader
, FF_PFNGLATTACHSHADERPROC
)
449 LOAD_OPENGL_FUN(glCreateShader
, FF_PFNGLCREATESHADERPROC
)
450 LOAD_OPENGL_FUN(glDeleteShader
, FF_PFNGLDELETESHADERPROC
)
451 LOAD_OPENGL_FUN(glCompileShader
, FF_PFNGLCOMPILESHADERPROC
)
452 LOAD_OPENGL_FUN(glShaderSource
, FF_PFNGLSHADERSOURCEPROC
)
453 LOAD_OPENGL_FUN(glGetShaderiv
, FF_PFNGLGETSHADERIVPROC
)
454 LOAD_OPENGL_FUN(glGetShaderInfoLog
, FF_PFNGLGETSHADERINFOLOGPROC
)
455 LOAD_OPENGL_FUN(glEnableVertexAttribArray
, FF_PFNGLENABLEVERTEXATTRIBARRAYPROC
)
456 LOAD_OPENGL_FUN(glVertexAttribPointer
, FF_PFNGLVERTEXATTRIBPOINTERPROC
)
460 #undef LOAD_OPENGL_FUN
462 #endif /* HAVE_SDL */
464 #if defined(__APPLE__)
465 static int av_cold
opengl_load_procedures(OpenGLContext
*opengl
)
467 FFOpenGLFunctions
*procs
= &opengl
->glprocs
;
470 if (!opengl
->no_window
)
471 return opengl_sdl_load_procedures(opengl
);
474 procs
->glActiveTexture
= glActiveTexture
;
475 procs
->glGenBuffers
= glGenBuffers
;
476 procs
->glDeleteBuffers
= glDeleteBuffers
;
477 procs
->glBufferData
= glBufferData
;
478 procs
->glBindBuffer
= glBindBuffer
;
479 procs
->glGetAttribLocation
= glGetAttribLocation
;
480 procs
->glGetUniformLocation
= glGetUniformLocation
;
481 procs
->glUniform1f
= glUniform1f
;
482 procs
->glUniform1i
= glUniform1i
;
483 procs
->glUniformMatrix4fv
= glUniformMatrix4fv
;
484 procs
->glCreateProgram
= glCreateProgram
;
485 procs
->glDeleteProgram
= glDeleteProgram
;
486 procs
->glUseProgram
= glUseProgram
;
487 procs
->glLinkProgram
= glLinkProgram
;
488 procs
->glGetProgramiv
= glGetProgramiv
;
489 procs
->glGetProgramInfoLog
= glGetProgramInfoLog
;
490 procs
->glAttachShader
= glAttachShader
;
491 procs
->glCreateShader
= glCreateShader
;
492 procs
->glDeleteShader
= glDeleteShader
;
493 procs
->glCompileShader
= glCompileShader
;
494 procs
->glShaderSource
= glShaderSource
;
495 procs
->glGetShaderiv
= glGetShaderiv
;
496 procs
->glGetShaderInfoLog
= glGetShaderInfoLog
;
497 procs
->glEnableVertexAttribArray
= glEnableVertexAttribArray
;
498 procs
->glVertexAttribPointer
= (FF_PFNGLVERTEXATTRIBPOINTERPROC
) glVertexAttribPointer
;
502 static int av_cold
opengl_load_procedures(OpenGLContext
*opengl
)
504 FFOpenGLFunctions
*procs
= &opengl
->glprocs
;
506 #if HAVE_GLXGETPROCADDRESS
507 #define SelectedGetProcAddress glXGetProcAddress
508 #elif HAVE_WGLGETPROCADDRESS
509 #define SelectedGetProcAddress wglGetProcAddress
512 #define LOAD_OPENGL_FUN(name, type) \
513 procs->name = (type)SelectedGetProcAddress(#name); \
514 if (!procs->name) { \
515 av_log(opengl, AV_LOG_ERROR, "Cannot load OpenGL function: '%s'\n", #name); \
516 return AVERROR(ENOSYS); \
520 if (!opengl
->no_window
)
521 return opengl_sdl_load_procedures(opengl
);
524 LOAD_OPENGL_FUN(glActiveTexture
, FF_PFNGLACTIVETEXTUREPROC
)
525 LOAD_OPENGL_FUN(glGenBuffers
, FF_PFNGLGENBUFFERSPROC
)
526 LOAD_OPENGL_FUN(glDeleteBuffers
, FF_PFNGLDELETEBUFFERSPROC
)
527 LOAD_OPENGL_FUN(glBufferData
, FF_PFNGLBUFFERDATAPROC
)
528 LOAD_OPENGL_FUN(glBindBuffer
, FF_PFNGLBINDBUFFERPROC
)
529 LOAD_OPENGL_FUN(glGetAttribLocation
, FF_PFNGLGETATTRIBLOCATIONPROC
)
530 LOAD_OPENGL_FUN(glGetUniformLocation
, FF_PFNGLGETUNIFORMLOCATIONPROC
)
531 LOAD_OPENGL_FUN(glUniform1f
, FF_PFNGLUNIFORM1FPROC
)
532 LOAD_OPENGL_FUN(glUniform1i
, FF_PFNGLUNIFORM1IPROC
)
533 LOAD_OPENGL_FUN(glUniformMatrix4fv
, FF_PFNGLUNIFORMMATRIX4FVPROC
)
534 LOAD_OPENGL_FUN(glCreateProgram
, FF_PFNGLCREATEPROGRAMPROC
)
535 LOAD_OPENGL_FUN(glDeleteProgram
, FF_PFNGLDELETEPROGRAMPROC
)
536 LOAD_OPENGL_FUN(glUseProgram
, FF_PFNGLUSEPROGRAMPROC
)
537 LOAD_OPENGL_FUN(glLinkProgram
, FF_PFNGLLINKPROGRAMPROC
)
538 LOAD_OPENGL_FUN(glGetProgramiv
, FF_PFNGLGETPROGRAMIVPROC
)
539 LOAD_OPENGL_FUN(glGetProgramInfoLog
, FF_PFNGLGETPROGRAMINFOLOGPROC
)
540 LOAD_OPENGL_FUN(glAttachShader
, FF_PFNGLATTACHSHADERPROC
)
541 LOAD_OPENGL_FUN(glCreateShader
, FF_PFNGLCREATESHADERPROC
)
542 LOAD_OPENGL_FUN(glDeleteShader
, FF_PFNGLDELETESHADERPROC
)
543 LOAD_OPENGL_FUN(glCompileShader
, FF_PFNGLCOMPILESHADERPROC
)
544 LOAD_OPENGL_FUN(glShaderSource
, FF_PFNGLSHADERSOURCEPROC
)
545 LOAD_OPENGL_FUN(glGetShaderiv
, FF_PFNGLGETSHADERIVPROC
)
546 LOAD_OPENGL_FUN(glGetShaderInfoLog
, FF_PFNGLGETSHADERINFOLOGPROC
)
547 LOAD_OPENGL_FUN(glEnableVertexAttribArray
, FF_PFNGLENABLEVERTEXATTRIBARRAYPROC
)
548 LOAD_OPENGL_FUN(glVertexAttribPointer
, FF_PFNGLVERTEXATTRIBPOINTERPROC
)
552 #undef SelectedGetProcAddress
553 #undef LOAD_OPENGL_FUN
557 static void opengl_make_identity(float matrix
[16])
559 memset(matrix
, 0, 16 * sizeof(float));
560 matrix
[0] = matrix
[5] = matrix
[10] = matrix
[15] = 1.0f
;
563 static void opengl_make_ortho(float matrix
[16], float left
, float right
,
564 float bottom
, float top
, float nearZ
, float farZ
)
566 float ral
= right
+ left
;
567 float rsl
= right
- left
;
568 float tab
= top
+ bottom
;
569 float tsb
= top
- bottom
;
570 float fan
= farZ
+ nearZ
;
571 float fsn
= farZ
- nearZ
;
573 memset(matrix
, 0, 16 * sizeof(float));
574 matrix
[0] = 2.0f
/ rsl
;
575 matrix
[5] = 2.0f
/ tsb
;
576 matrix
[10] = -2.0f
/ fsn
;
577 matrix
[12] = -ral
/ rsl
;
578 matrix
[13] = -tab
/ tsb
;
579 matrix
[14] = -fan
/ fsn
;
583 static av_cold
int opengl_read_limits(OpenGLContext
*opengl
)
586 const char *extension
;
589 } required_extensions
[] = {
590 { "GL_ARB_multitexture", 1, 3 },
591 { "GL_ARB_vertex_buffer_object", 1, 5 }, //GLX_ARB_vertex_buffer_object
592 { "GL_ARB_vertex_shader", 2, 0 },
593 { "GL_ARB_fragment_shader", 2, 0 },
594 { "GL_ARB_shader_objects", 2, 0 },
598 const char *extensions
, *version
;
600 version
= glGetString(GL_VERSION
);
601 extensions
= glGetString(GL_EXTENSIONS
);
603 av_log(opengl
, AV_LOG_DEBUG
, "OpenGL version: %s\n", version
);
604 sscanf(version
, "%d.%d", &major
, &minor
);
606 for (i
= 0; required_extensions
[i
].extension
; i
++) {
607 if (major
< required_extensions
[i
].major
&&
608 (major
== required_extensions
[i
].major
&& minor
< required_extensions
[i
].minor
) &&
609 !strstr(extensions
, required_extensions
[i
].extension
)) {
610 av_log(opengl
, AV_LOG_ERROR
, "Required extension %s is not supported.\n",
611 required_extensions
[i
].extension
);
612 av_log(opengl
, AV_LOG_DEBUG
, "Supported extensions are: %s\n", extensions
);
613 return AVERROR(ENOSYS
);
616 glGetIntegerv(GL_MAX_TEXTURE_SIZE
, &opengl
->max_texture_size
);
617 glGetIntegerv(GL_MAX_VIEWPORT_DIMS
, &opengl
->max_viewport_width
);
618 opengl
->non_pow_2_textures
= major
>= 2 || strstr(extensions
, "GL_ARB_texture_non_power_of_two");
619 #if defined(GL_ES_VERSION_2_0)
620 opengl
->unpack_subimage
= !!strstr(extensions
, "GL_EXT_unpack_subimage");
622 opengl
->unpack_subimage
= 1;
625 av_log(opengl
, AV_LOG_DEBUG
, "Non Power of 2 textures support: %s\n", opengl
->non_pow_2_textures
? "Yes" : "No");
626 av_log(opengl
, AV_LOG_DEBUG
, "Unpack Subimage extension support: %s\n", opengl
->unpack_subimage
? "Yes" : "No");
627 av_log(opengl
, AV_LOG_DEBUG
, "Max texture size: %dx%d\n", opengl
->max_texture_size
, opengl
->max_texture_size
);
628 av_log(opengl
, AV_LOG_DEBUG
, "Max viewport size: %dx%d\n",
629 opengl
->max_viewport_width
, opengl
->max_viewport_height
);
631 OPENGL_ERROR_CHECK(opengl
);
634 return AVERROR_EXTERNAL
;
637 static const char* opengl_get_fragment_shader_code(enum AVPixelFormat format
)
640 for (i
= 0; i
< FF_ARRAY_ELEMS(opengl_format_desc
); i
++) {
641 if (opengl_format_desc
[i
].fixel_format
== format
)
642 return *opengl_format_desc
[i
].fragment_shader
;
647 static int opengl_type_size(GLenum type
)
650 case GL_UNSIGNED_SHORT
:
651 case FF_GL_UNSIGNED_SHORT_1_5_5_5_REV
:
652 case GL_UNSIGNED_SHORT_5_6_5
:
654 case GL_UNSIGNED_BYTE
:
655 case FF_GL_UNSIGNED_BYTE_3_3_2
:
656 case FF_GL_UNSIGNED_BYTE_2_3_3_REV
:
663 static av_cold
void opengl_get_texture_params(OpenGLContext
*opengl
)
666 for (i
= 0; i
< FF_ARRAY_ELEMS(opengl_format_desc
); i
++) {
667 if (opengl_format_desc
[i
].fixel_format
== opengl
->pix_fmt
) {
668 opengl
->format
= opengl_format_desc
[i
].format
;
669 opengl
->type
= opengl_format_desc
[i
].type
;
675 static void opengl_compute_display_area(AVFormatContext
*s
)
677 AVRational sar
, dar
; /* sample and display aspect ratios */
678 OpenGLContext
*opengl
= s
->priv_data
;
679 AVStream
*st
= s
->streams
[0];
680 AVCodecContext
*encctx
= st
->codec
;
682 /* compute overlay width and height from the codec context information */
683 sar
= st
->sample_aspect_ratio
.num
? st
->sample_aspect_ratio
: (AVRational
){ 1, 1 };
684 dar
= av_mul_q(sar
, (AVRational
){ encctx
->width
, encctx
->height
});
686 /* we suppose the screen has a 1/1 sample aspect ratio */
687 /* fit in the window */
688 if (av_cmp_q(dar
, (AVRational
){ opengl
->window_width
, opengl
->window_height
}) > 0) {
690 opengl
->picture_width
= opengl
->window_width
;
691 opengl
->picture_height
= av_rescale(opengl
->picture_width
, dar
.den
, dar
.num
);
694 opengl
->picture_height
= opengl
->window_height
;
695 opengl
->picture_width
= av_rescale(opengl
->picture_height
, dar
.num
, dar
.den
);
699 static av_cold
void opengl_get_texture_size(OpenGLContext
*opengl
, int in_width
, int in_height
,
700 int *out_width
, int *out_height
)
702 if (opengl
->non_pow_2_textures
) {
703 *out_width
= in_width
;
704 *out_height
= in_height
;
706 int max
= FFMIN(FFMAX(in_width
, in_height
), opengl
->max_texture_size
);
707 unsigned power_of_2
= 1;
708 while (power_of_2
< max
)
710 *out_height
= power_of_2
;
711 *out_width
= power_of_2
;
712 av_log(opengl
, AV_LOG_DEBUG
, "Texture size calculated from %dx%d into %dx%d\n",
713 in_width
, in_height
, *out_width
, *out_height
);
717 static av_cold
void opengl_fill_color_map(OpenGLContext
*opengl
)
719 const AVPixFmtDescriptor
*desc
;
721 enum AVPixelFormat pix_fmt
= opengl
->pix_fmt
;
723 /* We need order of components, not exact position, some minor HACKs here */
724 if (pix_fmt
== AV_PIX_FMT_RGB565
|| pix_fmt
== AV_PIX_FMT_BGR555
||
725 pix_fmt
== AV_PIX_FMT_BGR8
|| pix_fmt
== AV_PIX_FMT_RGB8
)
726 pix_fmt
= AV_PIX_FMT_RGB24
;
727 else if (pix_fmt
== AV_PIX_FMT_BGR565
|| pix_fmt
== AV_PIX_FMT_RGB555
)
728 pix_fmt
= AV_PIX_FMT_BGR24
;
730 desc
= av_pix_fmt_desc_get(pix_fmt
);
731 if (!(desc
->flags
& AV_PIX_FMT_FLAG_RGB
))
734 #define FILL_COMPONENT(i) { \
735 shift = desc->comp[i].depth_minus1 >> 3; \
736 opengl->color_map[(i << 2) + ((desc->comp[i].offset_plus1 - 1) >> shift)] = 1.0; \
739 memset(opengl
->color_map
, 0, sizeof(opengl
->color_map
));
743 if (desc
->flags
& AV_PIX_FMT_FLAG_ALPHA
)
746 #undef FILL_COMPONENT
749 static av_cold GLuint
opengl_load_shader(OpenGLContext
*opengl
, GLenum type
, const char *source
)
751 GLuint shader
= opengl
->glprocs
.glCreateShader(type
);
754 av_log(opengl
, AV_LOG_ERROR
, "glCreateShader() failed\n");
757 opengl
->glprocs
.glShaderSource(shader
, 1, &source
, NULL
);
758 opengl
->glprocs
.glCompileShader(shader
);
760 opengl
->glprocs
.glGetShaderiv(shader
, FF_GL_COMPILE_STATUS
, &result
);
763 opengl
->glprocs
.glGetShaderiv(shader
, FF_GL_INFO_LOG_LENGTH
, &result
);
765 if ((log
= av_malloc(result
))) {
766 opengl
->glprocs
.glGetShaderInfoLog(shader
, result
, NULL
, log
);
767 av_log(opengl
, AV_LOG_ERROR
, "Compile error: %s\n", log
);
773 OPENGL_ERROR_CHECK(opengl
);
776 opengl
->glprocs
.glDeleteShader(shader
);
780 static av_cold
int opengl_compile_shaders(OpenGLContext
*opengl
, enum AVPixelFormat pix_fmt
)
783 const char *fragment_shader_code
= opengl_get_fragment_shader_code(pix_fmt
);
785 if (!fragment_shader_code
) {
786 av_log(opengl
, AV_LOG_ERROR
, "Provided pixel format '%s' is not supported\n",
787 av_get_pix_fmt_name(pix_fmt
));
788 return AVERROR(EINVAL
);
791 opengl
->vertex_shader
= opengl_load_shader(opengl
, FF_GL_VERTEX_SHADER
,
792 FF_OPENGL_VERTEX_SHADER
);
793 if (!opengl
->vertex_shader
) {
794 av_log(opengl
, AV_LOG_ERROR
, "Vertex shader loading failed.\n");
797 opengl
->fragment_shader
= opengl_load_shader(opengl
, FF_GL_FRAGMENT_SHADER
,
798 fragment_shader_code
);
799 if (!opengl
->fragment_shader
) {
800 av_log(opengl
, AV_LOG_ERROR
, "Fragment shader loading failed.\n");
804 opengl
->program
= opengl
->glprocs
.glCreateProgram();
805 if (!opengl
->program
)
808 opengl
->glprocs
.glAttachShader(opengl
->program
, opengl
->vertex_shader
);
809 opengl
->glprocs
.glAttachShader(opengl
->program
, opengl
->fragment_shader
);
810 opengl
->glprocs
.glLinkProgram(opengl
->program
);
812 opengl
->glprocs
.glGetProgramiv(opengl
->program
, FF_GL_LINK_STATUS
, &result
);
815 opengl
->glprocs
.glGetProgramiv(opengl
->program
, FF_GL_INFO_LOG_LENGTH
, &result
);
817 log
= av_malloc(result
);
820 opengl
->glprocs
.glGetProgramInfoLog(opengl
->program
, result
, NULL
, log
);
821 av_log(opengl
, AV_LOG_ERROR
, "Link error: %s\n", log
);
827 opengl
->position_attrib
= opengl
->glprocs
.glGetAttribLocation(opengl
->program
, "a_position");
828 opengl
->texture_coords_attrib
= opengl
->glprocs
.glGetAttribLocation(opengl
->program
, "a_textureCoords");
829 opengl
->projection_matrix_location
= opengl
->glprocs
.glGetUniformLocation(opengl
->program
, "u_projectionMatrix");
830 opengl
->model_view_matrix_location
= opengl
->glprocs
.glGetUniformLocation(opengl
->program
, "u_modelViewMatrix");
831 opengl
->color_map_location
= opengl
->glprocs
.glGetUniformLocation(opengl
->program
, "u_colorMap");
832 opengl
->texture_location
[0] = opengl
->glprocs
.glGetUniformLocation(opengl
->program
, "u_texture0");
833 opengl
->texture_location
[1] = opengl
->glprocs
.glGetUniformLocation(opengl
->program
, "u_texture1");
834 opengl
->texture_location
[2] = opengl
->glprocs
.glGetUniformLocation(opengl
->program
, "u_texture2");
835 opengl
->texture_location
[3] = opengl
->glprocs
.glGetUniformLocation(opengl
->program
, "u_texture3");
836 opengl
->chroma_div_w_location
= opengl
->glprocs
.glGetUniformLocation(opengl
->program
, "u_chroma_div_w");
837 opengl
->chroma_div_h_location
= opengl
->glprocs
.glGetUniformLocation(opengl
->program
, "u_chroma_div_h");
839 OPENGL_ERROR_CHECK(opengl
);
842 opengl
->glprocs
.glDeleteShader(opengl
->vertex_shader
);
843 opengl
->glprocs
.glDeleteShader(opengl
->fragment_shader
);
844 opengl
->glprocs
.glDeleteProgram(opengl
->program
);
845 opengl
->fragment_shader
= opengl
->vertex_shader
= opengl
->program
= 0;
846 return AVERROR_EXTERNAL
;
849 static av_cold
int opengl_configure_texture(OpenGLContext
*opengl
, GLuint texture
,
850 GLsizei width
, GLsizei height
)
853 int new_width
, new_height
;
854 opengl_get_texture_size(opengl
, width
, height
, &new_width
, &new_height
);
855 glBindTexture(GL_TEXTURE_2D
, texture
);
856 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
857 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
858 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
859 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
860 glTexImage2D(GL_TEXTURE_2D
, 0, opengl
->format
, new_width
, new_height
, 0,
861 opengl
->format
, opengl
->type
, NULL
);
862 OPENGL_ERROR_CHECK(NULL
);
866 return AVERROR_EXTERNAL
;
869 static av_cold
int opengl_prepare_vertex(AVFormatContext
*s
)
871 OpenGLContext
*opengl
= s
->priv_data
;
874 if (opengl
->window_width
> opengl
->max_viewport_width
|| opengl
->window_height
> opengl
->max_viewport_height
) {
875 opengl
->window_width
= FFMIN(opengl
->window_width
, opengl
->max_viewport_width
);
876 opengl
->window_height
= FFMIN(opengl
->window_height
, opengl
->max_viewport_height
);
877 av_log(opengl
, AV_LOG_WARNING
, "Too big viewport requested, limited to %dx%d", opengl
->window_width
, opengl
->window_height
);
879 glViewport(0, 0, opengl
->window_width
, opengl
->window_height
);
880 opengl_make_ortho(opengl
->projection_matrix
,
881 - (float)opengl
->window_width
/ 2.0f
, (float)opengl
->window_width
/ 2.0f
,
882 - (float)opengl
->window_height
/ 2.0f
, (float)opengl
->window_height
/ 2.0f
,
884 opengl_make_identity(opengl
->model_view_matrix
);
886 opengl_compute_display_area(s
);
888 opengl
->vertex
[0].z
= opengl
->vertex
[1].z
= opengl
->vertex
[2].z
= opengl
->vertex
[3].z
= 0.0f
;
889 opengl
->vertex
[0].x
= opengl
->vertex
[1].x
= - (float)opengl
->picture_width
/ 2.0f
;
890 opengl
->vertex
[2].x
= opengl
->vertex
[3].x
= (float)opengl
->picture_width
/ 2.0f
;
891 opengl
->vertex
[1].y
= opengl
->vertex
[2].y
= - (float)opengl
->picture_height
/ 2.0f
;
892 opengl
->vertex
[0].y
= opengl
->vertex
[3].y
= (float)opengl
->picture_height
/ 2.0f
;
894 opengl_get_texture_size(opengl
, opengl
->width
, opengl
->height
, &tex_w
, &tex_h
);
896 opengl
->vertex
[0].s0
= 0.0f
;
897 opengl
->vertex
[0].t0
= 0.0f
;
898 opengl
->vertex
[1].s0
= 0.0f
;
899 opengl
->vertex
[1].t0
= (float)opengl
->height
/ (float)tex_h
;
900 opengl
->vertex
[2].s0
= (float)opengl
->width
/ (float)tex_w
;
901 opengl
->vertex
[2].t0
= (float)opengl
->height
/ (float)tex_h
;
902 opengl
->vertex
[3].s0
= (float)opengl
->width
/ (float)tex_w
;
903 opengl
->vertex
[3].t0
= 0.0f
;
905 opengl
->glprocs
.glBindBuffer(FF_GL_ARRAY_BUFFER
, opengl
->vertex_buffer
);
906 opengl
->glprocs
.glBufferData(FF_GL_ARRAY_BUFFER
, sizeof(opengl
->vertex
), opengl
->vertex
, FF_GL_STATIC_DRAW
);
907 opengl
->glprocs
.glBindBuffer(FF_GL_ARRAY_BUFFER
, 0);
908 OPENGL_ERROR_CHECK(opengl
);
911 return AVERROR_EXTERNAL
;
914 static int opengl_prepare(OpenGLContext
*opengl
)
917 opengl
->glprocs
.glUseProgram(opengl
->program
);
918 opengl
->glprocs
.glUniformMatrix4fv(opengl
->projection_matrix_location
, 1, GL_FALSE
, opengl
->projection_matrix
);
919 opengl
->glprocs
.glUniformMatrix4fv(opengl
->model_view_matrix_location
, 1, GL_FALSE
, opengl
->model_view_matrix
);
920 for (i
= 0; i
< 4; i
++)
921 if (opengl
->texture_location
[i
] != -1) {
922 opengl
->glprocs
.glActiveTexture(GL_TEXTURE0
+ i
);
923 glBindTexture(GL_TEXTURE_2D
, opengl
->texture_name
[i
]);
924 opengl
->glprocs
.glUniform1i(opengl
->texture_location
[i
], i
);
926 if (opengl
->color_map_location
!= -1)
927 opengl
->glprocs
.glUniformMatrix4fv(opengl
->color_map_location
, 1, GL_FALSE
, opengl
->color_map
);
928 if (opengl
->chroma_div_h_location
!= -1)
929 opengl
->glprocs
.glUniform1f(opengl
->chroma_div_h_location
, opengl
->chroma_div_h
);
930 if (opengl
->chroma_div_w_location
!= -1)
931 opengl
->glprocs
.glUniform1f(opengl
->chroma_div_w_location
, opengl
->chroma_div_w
);
933 OPENGL_ERROR_CHECK(opengl
);
936 return AVERROR_EXTERNAL
;
939 static int opengl_create_window(AVFormatContext
*h
)
941 OpenGLContext
*opengl
= h
->priv_data
;
944 if (!opengl
->no_window
) {
946 if ((ret
= opengl_sdl_create_window(h
)) < 0) {
947 av_log(opengl
, AV_LOG_ERROR
, "Cannot create default SDL window.\n");
951 av_log(opengl
, AV_LOG_ERROR
, "FFmpeg is compiled without SDL. Cannot create default window.\n");
952 return AVERROR(ENOSYS
);
955 AVDeviceRect message
;
956 message
.x
= message
.y
= 0;
957 message
.width
= opengl
->window_width
;
958 message
.height
= opengl
->window_height
;
959 if ((ret
= avdevice_dev_to_app_control_message(h
, AV_DEV_TO_APP_CREATE_WINDOW_BUFFER
,
960 &message
, sizeof(message
))) < 0) {
961 av_log(opengl
, AV_LOG_ERROR
, "Application failed to create window buffer.\n");
964 if ((ret
= avdevice_dev_to_app_control_message(h
, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER
, NULL
, 0)) < 0) {
965 av_log(opengl
, AV_LOG_ERROR
, "Application failed to prepare window buffer.\n");
972 static int opengl_release_window(AVFormatContext
*h
)
975 OpenGLContext
*opengl
= h
->priv_data
;
976 if (!opengl
->no_window
) {
980 } else if ((ret
= avdevice_dev_to_app_control_message(h
, AV_DEV_TO_APP_DESTROY_WINDOW_BUFFER
, NULL
, 0)) < 0) {
981 av_log(opengl
, AV_LOG_ERROR
, "Application failed to release window buffer.\n");
987 static av_cold
int opengl_write_trailer(AVFormatContext
*h
)
989 OpenGLContext
*opengl
= h
->priv_data
;
991 if (opengl
->no_window
&&
992 avdevice_dev_to_app_control_message(h
, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER
, NULL
, 0) < 0)
993 av_log(opengl
, AV_LOG_ERROR
, "Application failed to prepare window buffer.\n");
995 opengl_deinit_context(opengl
);
996 opengl_release_window(h
);
1001 static av_cold
int opengl_init_context(OpenGLContext
*opengl
)
1004 const AVPixFmtDescriptor
*desc
;
1006 if ((ret
= opengl_compile_shaders(opengl
, opengl
->pix_fmt
)) < 0)
1009 desc
= av_pix_fmt_desc_get(opengl
->pix_fmt
);
1010 av_assert0(desc
->nb_components
> 0 && desc
->nb_components
<= 4);
1011 glGenTextures(desc
->nb_components
, opengl
->texture_name
);
1013 opengl
->glprocs
.glGenBuffers(2, &opengl
->index_buffer
);
1014 if (!opengl
->index_buffer
|| !opengl
->vertex_buffer
) {
1015 av_log(opengl
, AV_LOG_ERROR
, "Buffer generation failed.\n");
1016 ret
= AVERROR_EXTERNAL
;
1020 opengl_configure_texture(opengl
, opengl
->texture_name
[0], opengl
->width
, opengl
->height
);
1021 if (desc
->nb_components
> 1) {
1022 int has_alpha
= desc
->flags
& AV_PIX_FMT_FLAG_ALPHA
;
1023 int num_planes
= desc
->nb_components
- (has_alpha
? 1 : 0);
1024 if (opengl
->non_pow_2_textures
) {
1025 opengl
->chroma_div_w
= 1.0f
;
1026 opengl
->chroma_div_h
= 1.0f
;
1028 opengl
->chroma_div_w
= 1 << desc
->log2_chroma_w
;
1029 opengl
->chroma_div_h
= 1 << desc
->log2_chroma_h
;
1031 for (i
= 1; i
< num_planes
; i
++)
1032 if (opengl
->non_pow_2_textures
)
1033 opengl_configure_texture(opengl
, opengl
->texture_name
[i
],
1034 FF_CEIL_RSHIFT(opengl
->width
, desc
->log2_chroma_w
),
1035 FF_CEIL_RSHIFT(opengl
->height
, desc
->log2_chroma_h
));
1037 opengl_configure_texture(opengl
, opengl
->texture_name
[i
], opengl
->width
, opengl
->height
);
1039 opengl_configure_texture(opengl
, opengl
->texture_name
[3], opengl
->width
, opengl
->height
);
1042 opengl
->glprocs
.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER
, opengl
->index_buffer
);
1043 opengl
->glprocs
.glBufferData(FF_GL_ELEMENT_ARRAY_BUFFER
, sizeof(g_index
), g_index
, FF_GL_STATIC_DRAW
);
1044 opengl
->glprocs
.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER
, 0);
1047 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1049 glClearColor((float)opengl
->background
[0] / 255.0f
, (float)opengl
->background
[1] / 255.0f
,
1050 (float)opengl
->background
[2] / 255.0f
, 1.0f
);
1052 ret
= AVERROR_EXTERNAL
;
1053 OPENGL_ERROR_CHECK(opengl
);
1060 static av_cold
int opengl_write_header(AVFormatContext
*h
)
1062 OpenGLContext
*opengl
= h
->priv_data
;
1066 if (h
->nb_streams
!= 1 ||
1067 h
->streams
[0]->codec
->codec_type
!= AVMEDIA_TYPE_VIDEO
||
1068 h
->streams
[0]->codec
->codec_id
!= AV_CODEC_ID_RAWVIDEO
) {
1069 av_log(opengl
, AV_LOG_ERROR
, "Only a single video stream is supported.\n");
1070 return AVERROR(EINVAL
);
1073 opengl
->width
= st
->codec
->width
;
1074 opengl
->height
= st
->codec
->height
;
1075 opengl
->pix_fmt
= st
->codec
->pix_fmt
;
1076 if (!opengl
->window_width
)
1077 opengl
->window_width
= opengl
->width
;
1078 if (!opengl
->window_height
)
1079 opengl
->window_height
= opengl
->height
;
1081 if (!opengl
->window_title
&& !opengl
->no_window
)
1082 opengl
->window_title
= av_strdup(h
->filename
);
1084 if ((ret
= opengl_create_window(h
)))
1087 if ((ret
= opengl_read_limits(opengl
)) < 0)
1090 if (opengl
->width
> opengl
->max_texture_size
|| opengl
->height
> opengl
->max_texture_size
) {
1091 av_log(opengl
, AV_LOG_ERROR
, "Too big picture %dx%d, max supported size is %dx%d\n",
1092 opengl
->width
, opengl
->height
, opengl
->max_texture_size
, opengl
->max_texture_size
);
1093 ret
= AVERROR(EINVAL
);
1097 if ((ret
= opengl_load_procedures(opengl
)) < 0)
1100 opengl_fill_color_map(opengl
);
1101 opengl_get_texture_params(opengl
);
1103 if ((ret
= opengl_init_context(opengl
)) < 0)
1106 if ((ret
= opengl_prepare_vertex(h
)) < 0)
1109 glClear(GL_COLOR_BUFFER_BIT
);
1112 if (!opengl
->no_window
)
1113 SDL_GL_SwapBuffers();
1115 if (opengl
->no_window
&&
1116 (ret
= avdevice_dev_to_app_control_message(h
, AV_DEV_TO_APP_DISPLAY_WINDOW_BUFFER
, NULL
, 0)) < 0) {
1117 av_log(opengl
, AV_LOG_ERROR
, "Application failed to display window buffer.\n");
1121 ret
= AVERROR_EXTERNAL
;
1122 OPENGL_ERROR_CHECK(opengl
);
1128 opengl_write_trailer(h
);
1132 static uint8_t* opengl_get_plane_pointer(OpenGLContext
*opengl
, AVPacket
*pkt
, int comp_index
,
1133 const AVPixFmtDescriptor
*desc
)
1135 uint8_t *data
= pkt
->data
;
1136 int wordsize
= opengl_type_size(opengl
->type
);
1137 int width_chroma
= FF_CEIL_RSHIFT(opengl
->width
, desc
->log2_chroma_w
);
1138 int height_chroma
= FF_CEIL_RSHIFT(opengl
->height
, desc
->log2_chroma_h
);
1139 int plane
= desc
->comp
[comp_index
].plane
;
1145 data
+= opengl
->width
* opengl
->height
* wordsize
;
1148 data
+= opengl
->width
* opengl
->height
* wordsize
;
1149 data
+= width_chroma
* height_chroma
* wordsize
;
1152 data
+= opengl
->width
* opengl
->height
* wordsize
;
1153 data
+= 2 * width_chroma
* height_chroma
* wordsize
;
1161 #define LOAD_TEXTURE_DATA(comp_index, sub) \
1163 int width = sub ? FF_CEIL_RSHIFT(opengl->width, desc->log2_chroma_w) : opengl->width; \
1164 int height = sub ? FF_CEIL_RSHIFT(opengl->height, desc->log2_chroma_h): opengl->height; \
1166 int plane = desc->comp[comp_index].plane; \
1168 glBindTexture(GL_TEXTURE_2D, opengl->texture_name[comp_index]); \
1170 GLint length = ((AVFrame *)input)->linesize[plane]; \
1171 int bytes_per_pixel = opengl_type_size(opengl->type); \
1172 if (!(desc->flags & AV_PIX_FMT_FLAG_PLANAR)) \
1173 bytes_per_pixel *= desc->nb_components; \
1174 data = ((AVFrame *)input)->data[plane]; \
1175 if (!(length % bytes_per_pixel) && \
1176 (opengl->unpack_subimage || ((length / bytes_per_pixel) == width))) { \
1177 length /= bytes_per_pixel; \
1178 if (length != width) \
1179 glPixelStorei(FF_GL_UNPACK_ROW_LENGTH, length); \
1180 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, \
1181 opengl->format, opengl->type, data); \
1182 if (length != width) \
1183 glPixelStorei(FF_GL_UNPACK_ROW_LENGTH, 0); \
1186 for (h = 0; h < height; h++) { \
1187 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, h, width, 1, \
1188 opengl->format, opengl->type, data); \
1193 data = opengl_get_plane_pointer(opengl, input, comp_index, desc); \
1194 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, \
1195 opengl->format, opengl->type, data); \
1199 static int opengl_draw(AVFormatContext
*h
, void *input
, int repaint
, int is_pkt
)
1201 OpenGLContext
*opengl
= h
->priv_data
;
1202 enum AVPixelFormat pix_fmt
= h
->streams
[0]->codec
->pix_fmt
;
1203 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(pix_fmt
);
1207 if (!opengl
->no_window
&& (ret
= opengl_sdl_process_events(h
)) < 0)
1210 if (opengl
->no_window
&&
1211 (ret
= avdevice_dev_to_app_control_message(h
, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER
, NULL
, 0)) < 0) {
1212 av_log(opengl
, AV_LOG_ERROR
, "Application failed to prepare window buffer.\n");
1216 glClear(GL_COLOR_BUFFER_BIT
);
1220 glPixelStorei(GL_UNPACK_ALIGNMENT
, 1);
1221 LOAD_TEXTURE_DATA(0, 0)
1222 if (desc
->flags
& AV_PIX_FMT_FLAG_PLANAR
) {
1223 LOAD_TEXTURE_DATA(1, 1)
1224 LOAD_TEXTURE_DATA(2, 1)
1225 if (desc
->flags
& AV_PIX_FMT_FLAG_ALPHA
)
1226 LOAD_TEXTURE_DATA(3, 0)
1229 ret
= AVERROR_EXTERNAL
;
1230 OPENGL_ERROR_CHECK(opengl
);
1232 if ((ret
= opengl_prepare(opengl
)) < 0)
1235 opengl
->glprocs
.glBindBuffer(FF_GL_ARRAY_BUFFER
, opengl
->vertex_buffer
);
1236 opengl
->glprocs
.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER
, opengl
->index_buffer
);
1237 opengl
->glprocs
.glVertexAttribPointer(opengl
->position_attrib
, 3, GL_FLOAT
, GL_FALSE
, sizeof(OpenGLVertexInfo
), 0);
1238 opengl
->glprocs
.glEnableVertexAttribArray(opengl
->position_attrib
);
1239 opengl
->glprocs
.glVertexAttribPointer(opengl
->texture_coords_attrib
, 2, GL_FLOAT
, GL_FALSE
, sizeof(OpenGLVertexInfo
), 12);
1240 opengl
->glprocs
.glEnableVertexAttribArray(opengl
->texture_coords_attrib
);
1242 glDrawElements(GL_TRIANGLES
, FF_ARRAY_ELEMS(g_index
), GL_UNSIGNED_SHORT
, 0);
1244 ret
= AVERROR_EXTERNAL
;
1245 OPENGL_ERROR_CHECK(opengl
);
1248 if (!opengl
->no_window
)
1249 SDL_GL_SwapBuffers();
1251 if (opengl
->no_window
&&
1252 (ret
= avdevice_dev_to_app_control_message(h
, AV_DEV_TO_APP_DISPLAY_WINDOW_BUFFER
, NULL
, 0)) < 0) {
1253 av_log(opengl
, AV_LOG_ERROR
, "Application failed to display window buffer.\n");
1262 static int opengl_write_packet(AVFormatContext
*h
, AVPacket
*pkt
)
1264 return opengl_draw(h
, pkt
, 0, 1);
1267 static int opengl_write_frame(AVFormatContext
*h
, int stream_index
,
1268 AVFrame
**frame
, unsigned flags
)
1270 if ((flags
& AV_WRITE_UNCODED_FRAME_QUERY
))
1272 return opengl_draw(h
, *frame
, 0, 0);
1275 #define OFFSET(x) offsetof(OpenGLContext, x)
1276 #define ENC AV_OPT_FLAG_ENCODING_PARAM
1277 static const AVOption options
[] = {
1278 { "background", "set background color", OFFSET(background
), AV_OPT_TYPE_COLOR
, {.str
= "black"}, CHAR_MIN
, CHAR_MAX
, ENC
},
1279 { "no_window", "disable default window", OFFSET(no_window
), AV_OPT_TYPE_INT
, {.i64
= 0}, INT_MIN
, INT_MAX
, ENC
},
1280 { "window_title", "set window title", OFFSET(window_title
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, ENC
},
1281 { "window_size", "set window size", OFFSET(window_width
), AV_OPT_TYPE_IMAGE_SIZE
, {.str
= NULL
}, 0, 0, ENC
},
1285 static const AVClass opengl_class
= {
1286 .class_name
= "opengl outdev",
1287 .item_name
= av_default_item_name
,
1289 .version
= LIBAVUTIL_VERSION_INT
,
1290 .category
= AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT
,
1293 AVOutputFormat ff_opengl_muxer
= {
1295 .long_name
= NULL_IF_CONFIG_SMALL("OpenGL output"),
1296 .priv_data_size
= sizeof(OpenGLContext
),
1297 .audio_codec
= AV_CODEC_ID_NONE
,
1298 .video_codec
= AV_CODEC_ID_RAWVIDEO
,
1299 .write_header
= opengl_write_header
,
1300 .write_packet
= opengl_write_packet
,
1301 .write_uncoded_frame
= opengl_write_frame
,
1302 .write_trailer
= opengl_write_trailer
,
1303 .control_message
= opengl_control_message
,
1304 .flags
= AVFMT_NOFILE
| AVFMT_VARIABLE_FPS
| AVFMT_NOTIMESTAMPS
,
1305 .priv_class
= &opengl_class
,