FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
opengl_enc.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 Lukasz Marek
3  *
4  * This file is part of FFmpeg.
5  *
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.
10  *
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.
15  *
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
19  */
20 
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.
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <stddef.h>
30 
31 #include "config.h"
32 
33 #if HAVE_WINDOWS_H
34 #define WIN32_LEAN_AND_MEAN
35 #include <windows.h>
36 #endif
37 #if HAVE_OPENGL_GL3_H
38 #include <OpenGL/gl3.h>
39 #elif HAVE_ES2_GL_H
40 #include <ES2/gl.h>
41 #else
42 #include <GL/gl.h>
43 #include <GL/glext.h>
44 #endif
45 #if HAVE_GLXGETPROCADDRESS
46 #include <GL/glx.h>
47 #endif
48 
49 #if HAVE_SDL
50 #include <SDL.h>
51 #endif
52 
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"
63 
64 #ifndef APIENTRY
65 #define APIENTRY
66 #endif
67 
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. */
75 #if defined(GL_RED)
76 #define FF_GL_RED_COMPONENT GL_RED
77 #elif defined(GL_LUMINANCE)
78 #define FF_GL_RED_COMPONENT GL_LUMINANCE
79 #else
80 #define FF_GL_RED_COMPONENT 0x1903; //GL_RED
81 #endif
82 
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
88 
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);
123 
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
151 
152 #define OPENGL_ERROR_CHECK(ctx) \
153 {\
154  GLenum err_code; \
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); \
157  goto fail; \
158  } \
159 }\
160 
161 typedef struct OpenGLVertexInfo
162 {
163  float x, y, z; ///<Position
164  float s0, t0; ///<Texture coords
166 
167 /* defines 2 triangles to display */
168 static const GLushort g_index[6] =
169 {
170  0, 1, 2,
171  0, 3, 2,
172 };
173 
174 typedef struct OpenGLContext {
175  AVClass *class; ///< class for private options
176 
177 #if HAVE_SDL
178  SDL_Surface *surface;
179 #endif
181 
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
186 
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
193 
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
202  GLint projection_matrix_location; ///< Uniforms' locations
208  GLint position_attrib; ///< Attibutes' locations
210 
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
216 
217  /* Stream information */
218  GLenum format;
219  GLenum type;
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
227 } OpenGLContext;
228 
229 static const struct OpenGLFormatDesc {
231  const char * const * fragment_shader;
232  GLenum format;
233  GLenum type;
234 } opengl_format_desc[] = {
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 },
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 },
275  { AV_PIX_FMT_NONE, NULL }
276 };
277 
279 static int opengl_draw(AVFormatContext *h, void *intput, int repaint, int is_pkt);
280 static av_cold int opengl_init_context(OpenGLContext *opengl);
281 
283 {
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);
291  opengl->program = 0;
292  }
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;
297  }
298  if (opengl->glprocs.glBindBuffer) {
301  }
302  if (opengl->glprocs.glDeleteBuffers) {
303  opengl->glprocs.glDeleteBuffers(2, &opengl->index_buffer);
304  opengl->vertex_buffer = opengl->index_buffer = 0;
305  }
306 }
307 
308 static int opengl_resize(AVFormatContext *h, int width, int height)
309 {
310  int ret = 0;
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 &&
317  av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n");
318  goto end;
319  }
320  if ((ret = opengl_prepare_vertex(h)) < 0)
321  goto end;
322  ret = opengl_draw(h, NULL, 1, 0);
323  }
324  end:
325  return ret;
326 }
327 
328 static int opengl_control_message(AVFormatContext *h, int type, void *data, size_t data_size)
329 {
330  OpenGLContext *opengl = h->priv_data;
331  switch(type) {
333  if (data) {
334  AVDeviceRect *message = data;
335  return opengl_resize(h, message->width, message->height);
336  }
337  return AVERROR(EINVAL);
339  return opengl_resize(h, opengl->window_width, opengl->window_height);
340  }
341  return AVERROR(ENOSYS);
342 }
343 
344 #if HAVE_SDL
345 static int opengl_sdl_recreate_window(OpenGLContext *opengl, int width, int height)
346 {
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;
352  }
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);
358  return 0;
359 }
360 
361 static int opengl_sdl_process_events(AVFormatContext *h)
362 {
363  int ret;
364  OpenGLContext *opengl = h->priv_data;
365  SDL_Event event;
366  SDL_PumpEvents();
367  while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_ALLEVENTS) > 0) {
368  switch (event.type) {
369  case SDL_QUIT:
370  return AVERROR(EIO);
371  case SDL_KEYDOWN:
372  switch (event.key.keysym.sym) {
373  case SDLK_ESCAPE:
374  case SDLK_q:
375  return AVERROR(EIO);
376  }
377  return 0;
378  case SDL_VIDEORESIZE: {
379  char buffer[100];
380  int reinit;
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));
385  if (reinit) {
386  opengl_deinit_context(opengl);
387  }
388  if ((ret = opengl_sdl_recreate_window(opengl, event.resize.w, event.resize.h)) < 0)
389  return ret;
390  if (reinit && (ret = opengl_init_context(opengl)) < 0)
391  return ret;
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));
395  }
396  }
397  }
398  return 0;
399 }
400 
401 static int av_cold opengl_sdl_create_window(AVFormatContext *h)
402 {
403  int ret;
404  char buffer[100];
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;
410  }
411  if ((ret = opengl_sdl_recreate_window(opengl, opengl->window_width,
412  opengl->window_height)) < 0)
413  return ret;
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);
419  return 0;
420 }
421 
422 static int av_cold opengl_sdl_load_procedures(OpenGLContext *opengl)
423 {
424  FFOpenGLFunctions *procs = &opengl->glprocs;
425 
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); \
431  }
432 
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)
458 
459  return 0;
460 
461 #undef LOAD_OPENGL_FUN
462 }
463 #endif /* HAVE_SDL */
464 
465 #if defined(__APPLE__)
466 static int av_cold opengl_load_procedures(OpenGLContext *opengl)
467 {
468  FFOpenGLFunctions *procs = &opengl->glprocs;
469 
470 #if HAVE_SDL
471  if (!opengl->no_window)
472  return opengl_sdl_load_procedures(opengl);
473 #endif
474 
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;
500  return 0;
501 }
502 #else
504 {
505  FFOpenGLFunctions *procs = &opengl->glprocs;
506 
507 #if HAVE_GLXGETPROCADDRESS
508 #define SelectedGetProcAddress glXGetProcAddress
509 #elif HAVE_WGLGETPROCADDRESS
510 #define SelectedGetProcAddress wglGetProcAddress
511 #endif
512 
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); \
518  }
519 
520 #if HAVE_SDL
521  if (!opengl->no_window)
522  return opengl_sdl_load_procedures(opengl);
523 #endif
524 
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)
550 
551  return 0;
552 
553 #undef SelectedGetProcAddress
554 #undef LOAD_OPENGL_FUN
555 }
556 #endif
557 
558 static void opengl_make_identity(float matrix[16])
559 {
560  memset(matrix, 0, 16 * sizeof(float));
561  matrix[0] = matrix[5] = matrix[10] = matrix[15] = 1.0f;
562 }
563 
564 static void opengl_make_ortho(float matrix[16], float left, float right,
565  float bottom, float top, float nearZ, float farZ)
566 {
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;
573 
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;
581  matrix[15] = 1.0f;
582 }
583 
585 {
586  static const struct{
587  const char *extension;
588  int major;
589  int minor;
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 },
596  { NULL, 0, 0 }
597  };
598  int i, major, minor;
599  const char *extensions, *version;
600 
601  version = glGetString(GL_VERSION);
602  extensions = glGetString(GL_EXTENSIONS);
603 
604  av_log(opengl, AV_LOG_DEBUG, "OpenGL version: %s\n", version);
605  sscanf(version, "%d.%d", &major, &minor);
606 
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);
615  }
616  }
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");
622 #else
623  opengl->unpack_subimage = 1;
624 #endif
625 
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);
631 
632  OPENGL_ERROR_CHECK(opengl);
633  return 0;
634  fail:
635  return AVERROR_EXTERNAL;
636 }
637 
638 static const char* opengl_get_fragment_shader_code(enum AVPixelFormat format)
639 {
640  int i;
641  for (i = 0; i < FF_ARRAY_ELEMS(opengl_format_desc); i++) {
642  if (opengl_format_desc[i].fixel_format == format)
644  }
645  return NULL;
646 }
647 
648 static int opengl_type_size(GLenum type)
649 {
650  switch(type) {
651  case GL_UNSIGNED_SHORT:
653  case GL_UNSIGNED_SHORT_5_6_5:
654  return 2;
655  case GL_UNSIGNED_BYTE:
658  default:
659  break;
660  }
661  return 1;
662 }
663 
665 {
666  int i;
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;
671  break;
672  }
673  }
674 }
675 
677 {
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;
682 
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 });
686 
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) {
690  /* fit in width */
691  opengl->picture_width = opengl->window_width;
692  opengl->picture_height = av_rescale(opengl->picture_width, dar.den, dar.num);
693  } else {
694  /* fit in height */
695  opengl->picture_height = opengl->window_height;
696  opengl->picture_width = av_rescale(opengl->picture_height, dar.num, dar.den);
697  }
698 }
699 
700 static av_cold void opengl_get_texture_size(OpenGLContext *opengl, int in_width, int in_height,
701  int *out_width, int *out_height)
702 {
703  if (opengl->non_pow_2_textures) {
704  *out_width = in_width;
705  *out_height = in_height;
706  } else {
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)
710  power_of_2 *= 2;
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);
715  }
716 }
717 
719 {
720  const AVPixFmtDescriptor *desc;
721  int shift;
722  enum AVPixelFormat pix_fmt = opengl->pix_fmt;
723 
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;
730 
731  desc = av_pix_fmt_desc_get(pix_fmt);
732  if (!(desc->flags & AV_PIX_FMT_FLAG_RGB))
733  return;
734 
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; \
738  }
739 
740  memset(opengl->color_map, 0, sizeof(opengl->color_map));
741  FILL_COMPONENT(0);
742  FILL_COMPONENT(1);
743  FILL_COMPONENT(2);
744  if (desc->flags & AV_PIX_FMT_FLAG_ALPHA)
745  FILL_COMPONENT(3);
746 
747 #undef FILL_COMPONENT
748 }
749 
750 static av_cold GLuint opengl_load_shader(OpenGLContext *opengl, GLenum type, const char *source)
751 {
752  GLuint shader = opengl->glprocs.glCreateShader(type);
753  GLint result;
754  if (!shader) {
755  av_log(opengl, AV_LOG_ERROR, "glCreateShader() failed\n");
756  return 0;
757  }
758  opengl->glprocs.glShaderSource(shader, 1, &source, NULL);
759  opengl->glprocs.glCompileShader(shader);
760 
761  opengl->glprocs.glGetShaderiv(shader, FF_GL_COMPILE_STATUS, &result);
762  if (!result) {
763  char *log;
764  opengl->glprocs.glGetShaderiv(shader, FF_GL_INFO_LOG_LENGTH, &result);
765  if (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);
769  av_free(log);
770  }
771  }
772  goto fail;
773  }
774  OPENGL_ERROR_CHECK(opengl);
775  return shader;
776  fail:
777  opengl->glprocs.glDeleteShader(shader);
778  return 0;
779 }
780 
782 {
783  GLint result;
784  const char *fragment_shader_code = opengl_get_fragment_shader_code(pix_fmt);
785 
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);
790  }
791 
794  if (!opengl->vertex_shader) {
795  av_log(opengl, AV_LOG_ERROR, "Vertex shader loading failed.\n");
796  goto fail;
797  }
799  fragment_shader_code);
800  if (!opengl->fragment_shader) {
801  av_log(opengl, AV_LOG_ERROR, "Fragment shader loading failed.\n");
802  goto fail;
803  }
804 
805  opengl->program = opengl->glprocs.glCreateProgram();
806  if (!opengl->program)
807  goto fail;
808 
809  opengl->glprocs.glAttachShader(opengl->program, opengl->vertex_shader);
810  opengl->glprocs.glAttachShader(opengl->program, opengl->fragment_shader);
811  opengl->glprocs.glLinkProgram(opengl->program);
812 
813  opengl->glprocs.glGetProgramiv(opengl->program, FF_GL_LINK_STATUS, &result);
814  if (!result) {
815  char *log;
816  opengl->glprocs.glGetProgramiv(opengl->program, FF_GL_INFO_LOG_LENGTH, &result);
817  if (result) {
818  log = av_malloc(result);
819  if (!log)
820  goto fail;
821  opengl->glprocs.glGetProgramInfoLog(opengl->program, result, NULL, log);
822  av_log(opengl, AV_LOG_ERROR, "Link error: %s\n", log);
823  av_free(log);
824  }
825  goto fail;
826  }
827 
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");
839 
840  OPENGL_ERROR_CHECK(opengl);
841  return 0;
842  fail:
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;
848 }
849 
851  GLsizei width, GLsizei height)
852 {
853  if (texture) {
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);
864  }
865  return 0;
866  fail:
867  return AVERROR_EXTERNAL;
868 }
869 
871 {
872  OpenGLContext *opengl = s->priv_data;
873  int tex_w, tex_h;
874 
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);
879  }
880  glViewport(0, 0, opengl->window_width, opengl->window_height);
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,
884  1.0f, -1.0f);
886 
888 
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;
894 
895  opengl_get_texture_size(opengl, opengl->width, opengl->height, &tex_w, &tex_h);
896 
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;
905 
907  opengl->glprocs.glBufferData(FF_GL_ARRAY_BUFFER, sizeof(opengl->vertex), opengl->vertex, FF_GL_STATIC_DRAW);
909  OPENGL_ERROR_CHECK(opengl);
910  return 0;
911  fail:
912  return AVERROR_EXTERNAL;
913 }
914 
915 static int opengl_prepare(OpenGLContext *opengl)
916 {
917  int i;
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);
926  }
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);
933 
934  OPENGL_ERROR_CHECK(opengl);
935  return 0;
936  fail:
937  return AVERROR_EXTERNAL;
938 }
939 
941 {
942  OpenGLContext *opengl = h->priv_data;
943  int ret;
944 
945  if (!opengl->no_window) {
946 #if HAVE_SDL
947  if ((ret = opengl_sdl_create_window(h)) < 0) {
948  av_log(opengl, AV_LOG_ERROR, "Cannot create default SDL window.\n");
949  return ret;
950  }
951 #else
952  av_log(opengl, AV_LOG_ERROR, "FFmpeg is compiled without SDL. Cannot create default window.\n");
953  return AVERROR(ENOSYS);
954 #endif
955  } else {
956  AVDeviceRect message;
957  message.x = message.y = 0;
958  message.width = opengl->window_width;
959  message.height = opengl->window_height;
961  &message , sizeof(message))) < 0) {
962  av_log(opengl, AV_LOG_ERROR, "Application failed to create window buffer.\n");
963  return ret;
964  }
966  av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n");
967  return ret;
968  }
969  }
970  return 0;
971 }
972 
974 {
975  int ret;
976  OpenGLContext *opengl = h->priv_data;
977  if (!opengl->no_window) {
978 #if HAVE_SDL
979  SDL_Quit();
980 #endif
982  av_log(opengl, AV_LOG_ERROR, "Application failed to release window buffer.\n");
983  return ret;
984  }
985  return 0;
986 }
987 
989 {
990  OpenGLContext *opengl = h->priv_data;
991 
992  if (opengl->no_window &&
994  av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n");
995 
996  opengl_deinit_context(opengl);
998 
999  return 0;
1000 }
1001 
1003 {
1004  int i, ret;
1005  const AVPixFmtDescriptor *desc;
1006 
1007  if ((ret = opengl_compile_shaders(opengl, opengl->pix_fmt)) < 0)
1008  goto fail;
1009 
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);
1013 
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;
1018  goto fail;
1019  }
1020 
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;
1028  } else {
1029  opengl->chroma_div_w = 1 << desc->log2_chroma_w;
1030  opengl->chroma_div_h = 1 << desc->log2_chroma_h;
1031  }
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));
1037  else
1038  opengl_configure_texture(opengl, opengl->texture_name[i], opengl->width, opengl->height);
1039  if (has_alpha)
1040  opengl_configure_texture(opengl, opengl->texture_name[3], opengl->width, opengl->height);
1041  }
1042 
1046 
1047  glEnable(GL_BLEND);
1048  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1049 
1050  glClearColor((float)opengl->background[0] / 255.0f, (float)opengl->background[1] / 255.0f,
1051  (float)opengl->background[2] / 255.0f, 1.0f);
1052 
1053  ret = AVERROR_EXTERNAL;
1054  OPENGL_ERROR_CHECK(opengl);
1055 
1056  return 0;
1057  fail:
1058  return ret;
1059 }
1060 
1062 {
1063  OpenGLContext *opengl = h->priv_data;
1064  AVStream *st;
1065  int ret;
1066 
1067  if (h->nb_streams != 1 ||
1070  av_log(opengl, AV_LOG_ERROR, "Only a single video stream is supported.\n");
1071  return AVERROR(EINVAL);
1072  }
1073  st = h->streams[0];
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;
1081 
1082  if (!opengl->window_title && !opengl->no_window)
1083  opengl->window_title = av_strdup(h->filename);
1084 
1085  if ((ret = opengl_create_window(h)))
1086  goto fail;
1087 
1088  if ((ret = opengl_read_limits(opengl)) < 0)
1089  goto fail;
1090 
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);
1095  goto fail;
1096  }
1097 
1098  if ((ret = opengl_load_procedures(opengl)) < 0)
1099  goto fail;
1100 
1101  opengl_fill_color_map(opengl);
1102  opengl_get_texture_params(opengl);
1103 
1104  if ((ret = opengl_init_context(opengl)) < 0)
1105  goto fail;
1106 
1107  if ((ret = opengl_prepare_vertex(h)) < 0)
1108  goto fail;
1109 
1110  glClear(GL_COLOR_BUFFER_BIT);
1111 
1112 #if HAVE_SDL
1113  if (!opengl->no_window)
1114  SDL_GL_SwapBuffers();
1115 #endif
1116  if (opengl->no_window &&
1118  av_log(opengl, AV_LOG_ERROR, "Application failed to display window buffer.\n");
1119  goto fail;
1120  }
1121 
1122  ret = AVERROR_EXTERNAL;
1123  OPENGL_ERROR_CHECK(opengl);
1124 
1125  opengl->inited = 1;
1126  return 0;
1127 
1128  fail:
1130  return ret;
1131 }
1132 
1133 static uint8_t* opengl_get_plane_pointer(OpenGLContext *opengl, AVPacket *pkt, int comp_index,
1134  const AVPixFmtDescriptor *desc)
1135 {
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;
1141 
1142  switch(plane) {
1143  case 0:
1144  break;
1145  case 1:
1146  data += opengl->width * opengl->height * wordsize;
1147  break;
1148  case 2:
1149  data += opengl->width * opengl->height * wordsize;
1150  data += width_chroma * height_chroma * wordsize;
1151  break;
1152  case 3:
1153  data += opengl->width * opengl->height * wordsize;
1154  data += 2 * width_chroma * height_chroma * wordsize;
1155  break;
1156  default:
1157  return NULL;
1158  }
1159  return data;
1160 }
1161 
1162 #define LOAD_TEXTURE_DATA(comp_index, sub) \
1163 { \
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; \
1166  uint8_t *data; \
1167  int plane = desc->comp[comp_index].plane; \
1168  \
1169  glBindTexture(GL_TEXTURE_2D, opengl->texture_name[comp_index]); \
1170  if (!is_pkt) { \
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); \
1185  } else { \
1186  int h; \
1187  for (h = 0; h < height; h++) { \
1188  glTexSubImage2D(GL_TEXTURE_2D, 0, 0, h, width, 1, \
1189  opengl->format, opengl->type, data); \
1190  data += length; \
1191  } \
1192  } \
1193  } else { \
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); \
1197  } \
1198 }
1199 
1200 static int opengl_draw(AVFormatContext *h, void *input, int repaint, int is_pkt)
1201 {
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);
1205  int ret;
1206 
1207 #if HAVE_SDL
1208  if (!opengl->no_window && (ret = opengl_sdl_process_events(h)) < 0)
1209  goto fail;
1210 #endif
1211  if (opengl->no_window &&
1213  av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n");
1214  goto fail;
1215  }
1216 
1217  glClear(GL_COLOR_BUFFER_BIT);
1218 
1219  if (!repaint) {
1220  if (is_pkt)
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)
1228  }
1229  }
1230  ret = AVERROR_EXTERNAL;
1231  OPENGL_ERROR_CHECK(opengl);
1232 
1233  if ((ret = opengl_prepare(opengl)) < 0)
1234  goto fail;
1235 
1238  opengl->glprocs.glVertexAttribPointer(opengl->position_attrib, 3, GL_FLOAT, GL_FALSE, sizeof(OpenGLVertexInfo), 0);
1240  opengl->glprocs.glVertexAttribPointer(opengl->texture_coords_attrib, 2, GL_FLOAT, GL_FALSE, sizeof(OpenGLVertexInfo), 12);
1242 
1243  glDrawElements(GL_TRIANGLES, FF_ARRAY_ELEMS(g_index), GL_UNSIGNED_SHORT, 0);
1244 
1245  ret = AVERROR_EXTERNAL;
1246  OPENGL_ERROR_CHECK(opengl);
1247 
1248 #if HAVE_SDL
1249  if (!opengl->no_window)
1250  SDL_GL_SwapBuffers();
1251 #endif
1252  if (opengl->no_window &&
1254  av_log(opengl, AV_LOG_ERROR, "Application failed to display window buffer.\n");
1255  goto fail;
1256  }
1257 
1258  return 0;
1259  fail:
1260  return ret;
1261 }
1262 
1264 {
1265  return opengl_draw(h, pkt, 0, 1);
1266 }
1267 
1268 static int opengl_write_frame(AVFormatContext *h, int stream_index,
1269  AVFrame **frame, unsigned flags)
1270 {
1271  if ((flags & AV_WRITE_UNCODED_FRAME_QUERY))
1272  return 0;
1273  return opengl_draw(h, *frame, 0, 0);
1274 }
1275 
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 },
1283  { NULL }
1284 };
1285 
1286 static const AVClass opengl_class = {
1287  .class_name = "opengl outdev",
1288  .item_name = av_default_item_name,
1289  .option = options,
1290  .version = LIBAVUTIL_VERSION_INT,
1292 };
1293 
1295  .name = "opengl",
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,
1302  .write_uncoded_frame = opengl_write_frame,
1304  .control_message = opengl_control_message,
1306  .priv_class = &opengl_class,
1307 };