Browse code

lavd: add opengl device

It can render to OpenGL context provided by application or into SDL window

Signed-off-by: Lukasz Marek <lukasz.m.luki@gmail.com>

Lukasz Marek authored on 2013/11/25 04:13:27
Showing 7 changed files
... ...
@@ -21,6 +21,7 @@ version <next>
21 21
 - framepack filter
22 22
 - XYZ12 rawvideo support in NUT
23 23
 - Exif metadata support in WebP decoder
24
+- OpenGL device
24 25
 
25 26
 
26 27
 version 2.1:
... ...
@@ -251,6 +251,7 @@ External library support:
251 251
   --enable-libzvbi         enable teletext support via libzvbi [no]
252 252
   --enable-openal          enable OpenAL 1.1 capture support [no]
253 253
   --enable-opencl          enable OpenCL code
254
+  --enable-opengl          enable OpenGL rendering [no]
254 255
   --enable-openssl         enable openssl [no]
255 256
   --enable-x11grab         enable X11 grabbing [no]
256 257
   --disable-zlib           disable zlib [autodetect]
... ...
@@ -1311,6 +1312,7 @@ EXTERNAL_LIBRARY_LIST="
1311 1311
     libzvbi
1312 1312
     openal
1313 1313
     opencl
1314
+    opengl
1314 1315
     openssl
1315 1316
     x11grab
1316 1317
     zlib
... ...
@@ -1554,6 +1556,7 @@ HAVE_LIST="
1554 1554
     dxva_h
1555 1555
     ebp_available
1556 1556
     ebx_available
1557
+    ES2_gl_h
1557 1558
     fast_64bit
1558 1559
     fast_clz
1559 1560
     fast_cmov
... ...
@@ -1570,6 +1573,7 @@ HAVE_LIST="
1570 1570
     getservbyport
1571 1571
     gettimeofday
1572 1572
     glob
1573
+    glXGetProcAddress
1573 1574
     gnu_as
1574 1575
     gnu_windres
1575 1576
     gsm_h
... ...
@@ -1603,6 +1607,7 @@ HAVE_LIST="
1603 1603
     mprotect
1604 1604
     nanosleep
1605 1605
     openjpeg_1_5_openjpeg_h
1606
+    OpenGL_gl3_h
1606 1607
     PeekNamedPipe
1607 1608
     perl
1608 1609
     pod2man
... ...
@@ -1656,6 +1661,7 @@ HAVE_LIST="
1656 1656
     vdpau_x11
1657 1657
     vfp_args
1658 1658
     VirtualAlloc
1659
+    wglGetProcAddress
1659 1660
     windows_h
1660 1661
     winsock2_h
1661 1662
     xform_asm
... ...
@@ -2262,6 +2268,7 @@ libcdio_indev_deps="libcdio"
2262 2262
 libdc1394_indev_deps="libdc1394"
2263 2263
 libv4l2_indev_deps="libv4l2"
2264 2264
 openal_indev_deps="openal"
2265
+opengl_outdev_deps="opengl"
2265 2266
 oss_indev_deps_any="soundcard_h sys_soundcard_h"
2266 2267
 oss_outdev_deps_any="soundcard_h sys_soundcard_h"
2267 2268
 pulse_indev_deps="libpulse"
... ...
@@ -4498,6 +4505,12 @@ enabled opencl            && { check_lib2 OpenCL/cl.h clEnqueueNDRangeKernel -Wl
4498 4498
                              { check_cpp_condition "OpenCL/cl.h" "defined(CL_VERSION_1_2)" ||
4499 4499
                                check_cpp_condition "CL/cl.h" "defined(CL_VERSION_1_2)" ||
4500 4500
                                die "ERROR: opencl must be installed and version must be 1.2 or compatible"; }
4501
+enabled opengl            && { check_lib GL/glx.h glXGetProcAddress "-lGL" ||
4502
+                               check_lib2 windows.h wglGetProcAddress "-lopengl32 -lgdi32" ||
4503
+                               check_lib2 OpenGL/gl3.h glGetError "-Wl,-framework,OpenGL" ||
4504
+                               check_lib2 ES2/gl.h glGetError "-isysroot=${sysroot} -Wl,-framework,OpenGLES" ||
4505
+                               die "ERROR: opengl not found."
4506
+                             }
4501 4507
 enabled openssl           && { check_lib openssl/ssl.h SSL_library_init -lssl -lcrypto ||
4502 4508
                                check_lib openssl/ssl.h SSL_library_init -lssl32 -leay32 ||
4503 4509
                                check_lib openssl/ssl.h SSL_library_init -lssl -lcrypto -lws2_32 -lgdi32 ||
... ...
@@ -149,6 +149,41 @@ ffmpeg -re -i INPUT -vcodec rawvideo -pix_fmt bgra -f fbdev /dev/fb0
149 149
 
150 150
 See also @url{http://linux-fbdev.sourceforge.net/}, and fbset(1).
151 151
 
152
+@section opengl
153
+OpenGL output device.
154
+
155
+To enable this output device you need to configure FFmpeg with @code{--enable-opengl}.
156
+
157
+Device allows to render to OpenGL context.
158
+Context may be provided by application or default SDL window is created.
159
+
160
+When device renders to external context, application must implement handlers for following messages:
161
+@code{AV_CTL_MESSAGE_CREATE_WINDOW_BUFFER} - create OpenGL context on current thread.
162
+@code{AV_CTL_MESSAGE_PREPARE_WINDOW_BUFFER} - make OpenGL context current.
163
+@code{AV_CTL_MESSAGE_DISPLAY_WINDOW_BUFFER} - swap buffers.
164
+@code{AV_CTL_MESSAGE_DESTROY_WINDOW_BUFFER} - destroy OpenGL context.
165
+Application is also required to inform a device about current resolution by sending @code{AV_DEVICE_WINDOW_RESIZED} message.
166
+
167
+@subsection Options
168
+@table @option
169
+
170
+@item background
171
+Set background color. Black is a default.
172
+@item no_window
173
+Disables default SDL window when set to non-zero value.
174
+Application must provide OpenGL context and both @code{window_size_cb} and @code{window_swap_buffers_cb} callbacks when set.
175
+@item window_title
176
+Set the SDL window title, if not specified default to the filename specified for the output device.
177
+Ignored when @option{no_window} is set.
178
+
179
+@end table
180
+
181
+@subsection Examples
182
+Play a file on SDL window using OpenGL rendering:
183
+@example
184
+ffmpeg  -i INPUT -f opengl "window title"
185
+@end example
186
+
152 187
 @section oss
153 188
 
154 189
 OSS (Open Sound System) output device.
... ...
@@ -29,6 +29,7 @@ OBJS-$(CONFIG_IEC61883_INDEV)            += iec61883.o
29 29
 OBJS-$(CONFIG_JACK_INDEV)                += jack_audio.o timefilter.o
30 30
 OBJS-$(CONFIG_LAVFI_INDEV)               += lavfi.o
31 31
 OBJS-$(CONFIG_OPENAL_INDEV)              += openal-dec.o
32
+OBJS-$(CONFIG_OPENGL_OUTDEV)             += opengl_enc.o
32 33
 OBJS-$(CONFIG_OSS_INDEV)                 += oss_audio.o
33 34
 OBJS-$(CONFIG_OSS_OUTDEV)                += oss_audio.o
34 35
 OBJS-$(CONFIG_PULSE_INDEV)               += pulse_audio_dec.o \
... ...
@@ -56,6 +56,7 @@ void avdevice_register_all(void)
56 56
     REGISTER_INDEV   (JACK,             jack);
57 57
     REGISTER_INDEV   (LAVFI,            lavfi);
58 58
     REGISTER_INDEV   (OPENAL,           openal);
59
+    REGISTER_OUTDEV  (OPENGL,           opengl);
59 60
     REGISTER_INOUTDEV(OSS,              oss);
60 61
     REGISTER_INOUTDEV(PULSE,            pulse);
61 62
     REGISTER_OUTDEV  (SDL,              sdl);
62 63
new file mode 100644
... ...
@@ -0,0 +1,1221 @@
0
+/*
1
+ * Copyright (c) 2014 Lukasz Marek
2
+ *
3
+ * This file is part of FFmpeg.
4
+ *
5
+ * FFmpeg is free software; you can redistribute it and/or
6
+ * modify it under the terms of the GNU Lesser General Public
7
+ * License as published by the Free Software Foundation; either
8
+ * version 2.1 of the License, or (at your option) any later version.
9
+ *
10
+ * FFmpeg is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Lesser General Public
16
+ * License along with FFmpeg; if not, write to the Free Software
17
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+ */
19
+
20
+//TODO: support for more formats
21
+//TODO: support for more systems.
22
+//TODO: implement X11, Windows, Mac OS native default window. SDL 1.2 doesn't allow to render to custom thread.
23
+
24
+#include <stdio.h>
25
+#include <stdlib.h>
26
+#include <string.h>
27
+#include <unistd.h>
28
+#include <stddef.h>
29
+
30
+#include "config.h"
31
+
32
+#if HAVE_OPENGL_GL3_H
33
+#include <OpenGL/gl3.h>
34
+#elif HAVE_ES2_GL_H
35
+#include <ES2/gl.h>
36
+#else
37
+#include <GL/gl.h>
38
+#include <GL/glext.h>
39
+#endif
40
+#if HAVE_GLXGETPROCADDRESS
41
+#include <GL/glx.h>
42
+#endif
43
+#if HAVE_WINDOWS_H
44
+#include <windows.h>
45
+#endif
46
+
47
+#if HAVE_SDL
48
+#include <SDL.h>
49
+#endif
50
+
51
+#include "libavutil/common.h"
52
+#include "libavutil/pixdesc.h"
53
+#include "libavutil/log.h"
54
+#include "libavutil/opt.h"
55
+#include "libavutil/avassert.h"
56
+#include "libavutil/avstring.h"
57
+#include "libavformat/avformat.h"
58
+#include "libavdevice/avdevice.h"
59
+#include "opengl_enc_shaders.h"
60
+
61
+#ifndef APIENTRY
62
+#define APIENTRY
63
+#endif
64
+
65
+/* GL_RED_COMPONENT is used for plannar pixel types.
66
+ * Only red component is sampled in shaders.
67
+ * On some platforms GL_RED is not availabe and GL_LUMINANCE have to be used,
68
+ * but since OpenGL 3.0 GL_LUMINANCE is deprecated.
69
+ * GL_RED produces RGBA = value, 0, 0, 1.
70
+ * GL_LUMINANCE produces RGBA = value, value, value, 1.
71
+ * Note: GL_INTENSITY may also be used which produce RGBA = value, value, value, value. */
72
+#if defined(GL_RED)
73
+#define GL_RED_COMPONENT GL_RED
74
+#elif defined(GL_LUMINANCE)
75
+#define GL_RED_COMPONENT GL_LUMINANCE
76
+#else
77
+#define GL_RED_COMPONENT 0x1903; //GL_RED
78
+#endif
79
+
80
+/* Constants not defined for iOS */
81
+#define FF_GL_UNSIGNED_BYTE_3_3_2 0x8032
82
+#define FF_GL_UNSIGNED_BYTE_2_3_3_REV 0x8362
83
+#define FF_GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
84
+
85
+/* MinGW exposes only OpenGL 1.1 API */
86
+#define FF_GL_ARRAY_BUFFER                0x8892
87
+#define FF_GL_ELEMENT_ARRAY_BUFFER        0x8893
88
+#define FF_GL_STATIC_DRAW                 0x88E4
89
+#define FF_GL_FRAGMENT_SHADER             0x8B30
90
+#define FF_GL_VERTEX_SHADER               0x8B31
91
+#define FF_GL_COMPILE_STATUS              0x8B81
92
+#define FF_GL_LINK_STATUS                 0x8B82
93
+#define FF_GL_INFO_LOG_LENGTH             0x8B84
94
+typedef void   (APIENTRY *FF_PFNGLACTIVETEXTUREPROC) (GLenum texture);
95
+typedef void   (APIENTRY *FF_PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
96
+typedef void   (APIENTRY *FF_PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
97
+typedef void   (APIENTRY *FF_PFNGLBUFFERDATAPROC) (GLenum target, ptrdiff_t size, const GLvoid *data, GLenum usage);
98
+typedef void   (APIENTRY *FF_PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
99
+typedef GLint  (APIENTRY *FF_PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const char *name);
100
+typedef void   (APIENTRY *FF_PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
101
+typedef void   (APIENTRY *FF_PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, uintptr_t pointer);
102
+typedef GLint  (APIENTRY *FF_PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const char *name);
103
+typedef void   (APIENTRY *FF_PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0);
104
+typedef void   (APIENTRY *FF_PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
105
+typedef void   (APIENTRY *FF_PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
106
+typedef GLuint (APIENTRY *FF_PFNGLCREATEPROGRAMPROC) (void);
107
+typedef void   (APIENTRY *FF_PFNGLDELETEPROGRAMPROC) (GLuint program);
108
+typedef void   (APIENTRY *FF_PFNGLUSEPROGRAMPROC) (GLuint program);
109
+typedef void   (APIENTRY *FF_PFNGLLINKPROGRAMPROC) (GLuint program);
110
+typedef void   (APIENTRY *FF_PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
111
+typedef void   (APIENTRY *FF_PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, char *infoLog);
112
+typedef void   (APIENTRY *FF_PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
113
+typedef GLuint (APIENTRY *FF_PFNGLCREATESHADERPROC) (GLenum type);
114
+typedef void   (APIENTRY *FF_PFNGLDELETESHADERPROC) (GLuint shader);
115
+typedef void   (APIENTRY *FF_PFNGLCOMPILESHADERPROC) (GLuint shader);
116
+typedef void   (APIENTRY *FF_PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const char* *string, const GLint *length);
117
+typedef void   (APIENTRY *FF_PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
118
+typedef void   (APIENTRY *FF_PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, char *infoLog);
119
+
120
+typedef struct FFOpenGLFunctions {
121
+    FF_PFNGLACTIVETEXTUREPROC glActiveTexture;                     //Require GL ARB multitexture
122
+    FF_PFNGLGENBUFFERSPROC glGenBuffers;                           //Require GL_ARB_vertex_buffer_object
123
+    FF_PFNGLDELETEBUFFERSPROC glDeleteBuffers;                     //Require GL_ARB_vertex_buffer_object
124
+    FF_PFNGLBUFFERDATAPROC glBufferData;                           //Require GL_ARB_vertex_buffer_object
125
+    FF_PFNGLBINDBUFFERPROC glBindBuffer;                           //Require GL_ARB_vertex_buffer_object
126
+    FF_PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation;             //Require GL_ARB_vertex_shader
127
+    FF_PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; //Require GL_ARB_vertex_shader
128
+    FF_PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;         //Require GL_ARB_vertex_shader
129
+    FF_PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;           //Require GL_ARB_shader_objects
130
+    FF_PFNGLUNIFORM1FPROC glUniform1f;                             //Require GL_ARB_shader_objects
131
+    FF_PFNGLUNIFORM1IPROC glUniform1i;                             //Require GL_ARB_shader_objects
132
+    FF_PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv;               //Require GL_ARB_shader_objects
133
+    FF_PFNGLCREATEPROGRAMPROC glCreateProgram;                     //Require GL_ARB_shader_objects
134
+    FF_PFNGLDELETEPROGRAMPROC glDeleteProgram;                     //Require GL_ARB_shader_objects
135
+    FF_PFNGLUSEPROGRAMPROC glUseProgram;                           //Require GL_ARB_shader_objects
136
+    FF_PFNGLLINKPROGRAMPROC glLinkProgram;                         //Require GL_ARB_shader_objects
137
+    FF_PFNGLGETPROGRAMIVPROC glGetProgramiv;                       //Require GL_ARB_shader_objects
138
+    FF_PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;             //Require GL_ARB_shader_objects
139
+    FF_PFNGLATTACHSHADERPROC glAttachShader;                       //Require GL_ARB_shader_objects
140
+    FF_PFNGLCREATESHADERPROC glCreateShader;                       //Require GL_ARB_shader_objects
141
+    FF_PFNGLDELETESHADERPROC glDeleteShader;                       //Require GL_ARB_shader_objects
142
+    FF_PFNGLCOMPILESHADERPROC glCompileShader;                     //Require GL_ARB_shader_objects
143
+    FF_PFNGLSHADERSOURCEPROC glShaderSource;                       //Require GL_ARB_shader_objects
144
+    FF_PFNGLGETSHADERIVPROC glGetShaderiv;                         //Require GL_ARB_shader_objects
145
+    FF_PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;               //Require GL_ARB_shader_objects
146
+} FFOpenGLFunctions;
147
+
148
+#define OPENGL_ERROR_CHECK(ctx) \
149
+{\
150
+    GLenum err_code; \
151
+    if ((err_code = glGetError()) != GL_NO_ERROR) { \
152
+        av_log(ctx, AV_LOG_ERROR, "OpenGL error occurred in '%s', line %d: %d\n", __FUNCTION__, __LINE__, err_code); \
153
+        goto fail; \
154
+    } \
155
+}\
156
+
157
+typedef struct OpenGLVertexInfo
158
+{
159
+    float x, y, z;    ///<Position
160
+    float s0, t0;     ///<Texture coords
161
+} OpenGLVertexInfo;
162
+
163
+/* defines 2 triangles to display */
164
+static GLushort g_index[6] =
165
+{
166
+    0, 1, 2,
167
+    0, 3, 2,
168
+};
169
+
170
+typedef struct OpenGLContext {
171
+    AVClass *class;                    ///< class for private options
172
+
173
+#if HAVE_SDL
174
+    SDL_Surface *surface;
175
+#endif
176
+    FFOpenGLFunctions glprocs;
177
+
178
+    uint8_t background[4];             ///< Background color
179
+    int no_window;                     ///< 0 for create default window
180
+    char *window_title;                ///< Title of the window
181
+
182
+    /* OpenGL implementation limits */
183
+    GLint max_texture_size;            ///< Maximum texture size
184
+    GLint max_viewport_width;          ///< Maximum viewport size
185
+    GLint max_viewport_height;         ///< Maximum viewport size
186
+    int non_pow_2_textures;            ///< 1 when non power of 2 textures are supported
187
+
188
+    /* Current OpenGL configuration */
189
+    GLuint program;                    ///< Shader program
190
+    GLuint texture_name[4];            ///< Textures' IDs
191
+    GLuint index_buffer;               ///< Index buffer
192
+    GLuint vertex_buffer;              ///< Vertex buffer
193
+    OpenGLVertexInfo vertex[4];        ///< VBO
194
+    GLint projection_matrix_location;  ///< Uniforms' locations
195
+    GLint model_view_matrix_location;
196
+    GLint color_map_location;
197
+    GLint chroma_div_w_location;
198
+    GLint chroma_div_h_location;
199
+    GLint texture_location[4];
200
+    GLint position_attrib;             ///< Attibutes' locations
201
+    GLint texture_coords_attrib;
202
+
203
+    GLfloat projection_matrix[16];     ///< Projection matrix
204
+    GLfloat model_view_matrix[16];     ///< Modev view matrix
205
+    GLfloat color_map[16];             ///< RGBA color map matrix
206
+    GLfloat chroma_div_w;              ///< Chroma subsampling w ratio
207
+    GLfloat chroma_div_h;              ///< Chroma subsampling h ratio
208
+
209
+    /* Stream information */
210
+    GLenum format;
211
+    GLenum type;
212
+    int width;                         ///< Stream width
213
+    int height;                        ///< Stream height
214
+    enum AVPixelFormat pix_fmt;        ///< Stream pixel format
215
+    int picture_width;                 ///< Rendered width
216
+    int picture_height;                ///< Rendered height
217
+    int window_width;
218
+    int window_height;
219
+} OpenGLContext;
220
+
221
+static av_cold int opengl_prepare_vertex(AVFormatContext *s);
222
+static int opengl_draw(AVFormatContext *h, AVPacket *pkt, int repaint);
223
+static av_cold int opengl_init_context(OpenGLContext *opengl);
224
+
225
+static int opengl_resize(AVFormatContext *h, int width, int height)
226
+{
227
+    int ret = 0;
228
+    OpenGLContext *opengl = h->priv_data;
229
+    opengl->window_width = width;
230
+    opengl->window_height = height;
231
+    /* max_viewport_width == 0 means write_header was not called yet. */
232
+    if (opengl->max_viewport_width) {
233
+        if (opengl->no_window &&
234
+            (ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0)) < 0) {
235
+            av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n");
236
+            goto end;
237
+        }
238
+        if ((ret = opengl_prepare_vertex(h)) < 0)
239
+            goto end;
240
+        ret = opengl_draw(h, NULL, 1);
241
+    }
242
+  end:
243
+    return ret;
244
+}
245
+
246
+static int opengl_control_message(AVFormatContext *h, int type, void *data, size_t data_size)
247
+{
248
+    OpenGLContext *opengl = h->priv_data;
249
+    switch(type) {
250
+    case AV_APP_TO_DEV_WINDOW_SIZE:
251
+        if (data) {
252
+            AVDeviceRect *message = data;
253
+            return opengl_resize(h, message->width, message->height);
254
+        }
255
+        return AVERROR(EINVAL);
256
+    case AV_APP_TO_DEV_WINDOW_REPAINT:
257
+        return opengl_resize(h, opengl->window_width, opengl->window_height);
258
+    }
259
+    return AVERROR(ENOSYS);
260
+}
261
+
262
+#if HAVE_SDL
263
+static int opengl_sdl_recreate_window(OpenGLContext *opengl, int width, int height)
264
+{
265
+    opengl->surface = SDL_SetVideoMode(width, height,
266
+                                       32, SDL_OPENGL | SDL_RESIZABLE);
267
+    if (!opengl->surface) {
268
+        av_log(opengl, AV_LOG_ERROR, "Unable to set video mode: %s\n", SDL_GetError());
269
+        return AVERROR_EXTERNAL;
270
+    }
271
+    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
272
+    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
273
+    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
274
+    SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
275
+    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
276
+    return 0;
277
+}
278
+
279
+static int opengl_sdl_process_events(AVFormatContext *h)
280
+{
281
+    int ret;
282
+    OpenGLContext *opengl = h->priv_data;
283
+    SDL_Event event;
284
+    SDL_PumpEvents();
285
+    while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_ALLEVENTS) > 0) {
286
+        switch (event.type) {
287
+        case SDL_QUIT:
288
+            return AVERROR(EIO);
289
+        case SDL_KEYDOWN:
290
+            switch (event.key.keysym.sym) {
291
+            case SDLK_ESCAPE:
292
+            case SDLK_q:
293
+                return AVERROR(EIO);
294
+            }
295
+            return 0;
296
+        case SDL_VIDEORESIZE: {
297
+            char buffer[100];
298
+            int reinit;
299
+            AVDeviceRect message;
300
+            /* clean up old context because SDL_SetVideoMode may lose its state. */
301
+            SDL_VideoDriverName(buffer, sizeof(buffer));
302
+            reinit = !av_strncasecmp(buffer, "quartz", sizeof(buffer));
303
+            if (reinit) {
304
+                glDeleteTextures(4, opengl->texture_name);
305
+                opengl->glprocs.glDeleteBuffers(2, &opengl->index_buffer);
306
+            }
307
+            if ((ret = opengl_sdl_recreate_window(opengl, event.resize.w, event.resize.h)) < 0)
308
+                return ret;
309
+            if (reinit && (ret = opengl_init_context(opengl)) < 0)
310
+                return ret;
311
+            message.width = opengl->surface->w;
312
+            message.height = opengl->surface->h;
313
+            return opengl_control_message(h, AV_APP_TO_DEV_WINDOW_SIZE, &message, sizeof(AVDeviceRect));
314
+            }
315
+        }
316
+    }
317
+    return 0;
318
+}
319
+
320
+static int av_cold opengl_sdl_create_window(AVFormatContext *h)
321
+{
322
+    int ret;
323
+    char buffer[100];
324
+    OpenGLContext *opengl = h->priv_data;
325
+    AVDeviceRect message;
326
+    if (SDL_Init(SDL_INIT_VIDEO)) {
327
+        av_log(opengl, AV_LOG_ERROR, "Unable to initialize SDL: %s\n", SDL_GetError());
328
+        return AVERROR_EXTERNAL;
329
+    }
330
+    if ((ret = opengl_sdl_recreate_window(opengl, opengl->width, opengl->height)) < 0)
331
+        return ret;
332
+    av_log(opengl, AV_LOG_INFO, "SDL driver: '%s'.\n", SDL_VideoDriverName(buffer, sizeof(buffer)));
333
+    message.width = opengl->surface->w;
334
+    message.height = opengl->surface->h;
335
+    opengl_control_message(h, AV_APP_TO_DEV_WINDOW_SIZE, &message, sizeof(AVDeviceRect));
336
+    return 0;
337
+}
338
+
339
+static int av_cold opengl_sdl_load_procedures(OpenGLContext *opengl)
340
+{
341
+    FFOpenGLFunctions *procs = &opengl->glprocs;
342
+
343
+#define LOAD_OPENGL_FUN(name, type) \
344
+    procs->name = (type)SDL_GL_GetProcAddress(#name); \
345
+    if (!procs->name) { \
346
+        av_log(opengl, AV_LOG_ERROR, "Cannot load OpenGL function: '%s'\n", #name); \
347
+        return AVERROR(ENOSYS); \
348
+    }
349
+
350
+    LOAD_OPENGL_FUN(glActiveTexture, FF_PFNGLACTIVETEXTUREPROC)
351
+    LOAD_OPENGL_FUN(glGenBuffers, FF_PFNGLGENBUFFERSPROC)
352
+    LOAD_OPENGL_FUN(glDeleteBuffers, FF_PFNGLDELETEBUFFERSPROC)
353
+    LOAD_OPENGL_FUN(glBufferData, FF_PFNGLBUFFERDATAPROC)
354
+    LOAD_OPENGL_FUN(glBindBuffer, FF_PFNGLBINDBUFFERPROC)
355
+    LOAD_OPENGL_FUN(glGetAttribLocation, FF_PFNGLGETATTRIBLOCATIONPROC)
356
+    LOAD_OPENGL_FUN(glGetUniformLocation, FF_PFNGLGETUNIFORMLOCATIONPROC)
357
+    LOAD_OPENGL_FUN(glUniform1f, FF_PFNGLUNIFORM1FPROC)
358
+    LOAD_OPENGL_FUN(glUniform1i, FF_PFNGLUNIFORM1IPROC)
359
+    LOAD_OPENGL_FUN(glUniformMatrix4fv, FF_PFNGLUNIFORMMATRIX4FVPROC)
360
+    LOAD_OPENGL_FUN(glCreateProgram, FF_PFNGLCREATEPROGRAMPROC)
361
+    LOAD_OPENGL_FUN(glDeleteProgram, FF_PFNGLDELETEPROGRAMPROC)
362
+    LOAD_OPENGL_FUN(glUseProgram, FF_PFNGLUSEPROGRAMPROC)
363
+    LOAD_OPENGL_FUN(glLinkProgram, FF_PFNGLLINKPROGRAMPROC)
364
+    LOAD_OPENGL_FUN(glGetProgramiv, FF_PFNGLGETPROGRAMIVPROC)
365
+    LOAD_OPENGL_FUN(glGetProgramInfoLog, FF_PFNGLGETPROGRAMINFOLOGPROC)
366
+    LOAD_OPENGL_FUN(glAttachShader, FF_PFNGLATTACHSHADERPROC)
367
+    LOAD_OPENGL_FUN(glCreateShader, FF_PFNGLCREATESHADERPROC)
368
+    LOAD_OPENGL_FUN(glDeleteShader, FF_PFNGLDELETESHADERPROC)
369
+    LOAD_OPENGL_FUN(glCompileShader, FF_PFNGLCOMPILESHADERPROC)
370
+    LOAD_OPENGL_FUN(glShaderSource, FF_PFNGLSHADERSOURCEPROC)
371
+    LOAD_OPENGL_FUN(glGetShaderiv, FF_PFNGLGETSHADERIVPROC)
372
+    LOAD_OPENGL_FUN(glGetShaderInfoLog, FF_PFNGLGETSHADERINFOLOGPROC)
373
+    LOAD_OPENGL_FUN(glEnableVertexAttribArray, FF_PFNGLENABLEVERTEXATTRIBARRAYPROC)
374
+    LOAD_OPENGL_FUN(glVertexAttribPointer, FF_PFNGLVERTEXATTRIBPOINTERPROC)
375
+
376
+    return 0;
377
+
378
+#undef LOAD_OPENGL_FUN
379
+}
380
+#endif /* HAVE_SDL */
381
+
382
+#if defined(__APPLE__)
383
+static int av_cold opengl_load_procedures(OpenGLContext *opengl)
384
+{
385
+    FFOpenGLFunctions *procs = &opengl->glprocs;
386
+
387
+    procs->glActiveTexture = glActiveTexture;
388
+    procs->glGenBuffers = glGenBuffers;
389
+    procs->glDeleteBuffers = glDeleteBuffers;
390
+    procs->glBufferData = glBufferData;
391
+    procs->glBindBuffer = glBindBuffer;
392
+    procs->glGetAttribLocation = glGetAttribLocation;
393
+    procs->glGetUniformLocation = glGetUniformLocation;
394
+    procs->glUniform1f = glUniform1f;
395
+    procs->glUniform1i = glUniform1i;
396
+    procs->glUniformMatrix4fv = glUniformMatrix4fv;
397
+    procs->glCreateProgram = glCreateProgram;
398
+    procs->glDeleteProgram = glDeleteProgram;
399
+    procs->glUseProgram = glUseProgram;
400
+    procs->glLinkProgram = glLinkProgram;
401
+    procs->glGetProgramiv = glGetProgramiv;
402
+    procs->glGetProgramInfoLog = glGetProgramInfoLog;
403
+    procs->glAttachShader = glAttachShader;
404
+    procs->glCreateShader = glCreateShader;
405
+    procs->glDeleteShader = glDeleteShader;
406
+    procs->glCompileShader = glCompileShader;
407
+    procs->glShaderSource = glShaderSource;
408
+    procs->glGetShaderiv = glGetShaderiv;
409
+    procs->glGetShaderInfoLog = glGetShaderInfoLog;
410
+    procs->glEnableVertexAttribArray = glEnableVertexAttribArray;
411
+    procs->glVertexAttribPointer = (FF_PFNGLVERTEXATTRIBPOINTERPROC) glVertexAttribPointer;
412
+    return 0;
413
+}
414
+#else
415
+static int av_cold opengl_load_procedures(OpenGLContext *opengl)
416
+{
417
+    FFOpenGLFunctions *procs = &opengl->glprocs;
418
+
419
+#if HAVE_GLXGETPROCADDRESS
420
+#define SelectedGetProcAddress glXGetProcAddress
421
+#elif HAVE_WGLGETPROCADDRESS
422
+#define SelectedGetProcAddress wglGetProcAddress
423
+#endif
424
+
425
+#define LOAD_OPENGL_FUN(name, type) \
426
+    procs->name = (type)SelectedGetProcAddress(#name); \
427
+    if (!procs->name) { \
428
+        av_log(opengl, AV_LOG_ERROR, "Cannot load OpenGL function: '%s'\n", #name); \
429
+        return AVERROR(ENOSYS); \
430
+    }
431
+
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)
457
+
458
+    return 0;
459
+
460
+#undef SelectedGetProcAddress
461
+#undef LOAD_OPENGL_FUN
462
+}
463
+#endif
464
+
465
+static av_always_inline void opengl_make_identity(float matrix[16])
466
+{
467
+    memset(matrix, 0, 16 * sizeof(float));
468
+    matrix[0] = matrix[5] = matrix[10] = matrix[15] = 1.0f;
469
+}
470
+
471
+static av_always_inline void opengl_make_ortho(float matrix[16],
472
+                                               float left,   float right,
473
+                                               float bottom, float top,
474
+                                               float nearZ,  float farZ)
475
+{
476
+    float ral = right + left;
477
+    float rsl = right - left;
478
+    float tab = top + bottom;
479
+    float tsb = top - bottom;
480
+    float fan = farZ + nearZ;
481
+    float fsn = farZ - nearZ;
482
+
483
+    memset(matrix, 0, 16 * sizeof(float));
484
+    matrix[0] = 2.0f / rsl;
485
+    matrix[5] = 2.0f / tsb;
486
+    matrix[10] = -2.0f / fsn;
487
+    matrix[12] = -ral / rsl;
488
+    matrix[13] = -tab / tsb;
489
+    matrix[14] = -fan / fsn;
490
+    matrix[15] = 1.0f;
491
+}
492
+
493
+static av_cold int opengl_read_limits(OpenGLContext *opengl)
494
+{
495
+    static const struct{
496
+        const char *extention;
497
+        int major;
498
+        int minor;
499
+    } required_extensions[] = {
500
+        { "GL_ARB_multitexture",         1, 3 },
501
+        { "GL_ARB_vertex_buffer_object", 1, 5 }, //GLX_ARB_vertex_buffer_object
502
+        { "GL_ARB_vertex_shader",        2, 0 },
503
+        { "GL_ARB_fragment_shader",      2, 0 },
504
+        { "GL_ARB_shader_objects",       2, 0 },
505
+        { NULL,                          0, 0 }
506
+    };
507
+    int i, major, minor;
508
+    const char *extensions, *version;
509
+
510
+    version = glGetString(GL_VERSION);
511
+    extensions = glGetString(GL_EXTENSIONS);
512
+
513
+    av_log(opengl, AV_LOG_DEBUG, "OpenGL version: %s\n", version);
514
+    sscanf(version, "%d.%d", &major, &minor);
515
+
516
+    for (i = 0; required_extensions[i].extention; i++) {
517
+        if (major < required_extensions[i].major &&
518
+            (major == required_extensions[i].major && minor < required_extensions[i].minor) &&
519
+            !strstr(extensions, required_extensions[i].extention)) {
520
+            av_log(opengl, AV_LOG_ERROR, "Required extension %s is not supported.\n",
521
+                   required_extensions[i].extention);
522
+            av_log(opengl, AV_LOG_DEBUG, "Supported extensions are: %s\n", extensions);
523
+            return AVERROR(ENOSYS);
524
+        }
525
+    }
526
+    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &opengl->max_texture_size);
527
+    glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &opengl->max_viewport_width);
528
+    opengl->non_pow_2_textures = major >= 2 || strstr(extensions, "GL_ARB_texture_non_power_of_two");
529
+
530
+    av_log(opengl, AV_LOG_DEBUG, "Non Power of 2 textures support: %s\n", opengl->non_pow_2_textures ? "Yes" : "No");
531
+    av_log(opengl, AV_LOG_DEBUG, "Max texture size: %dx%d\n", opengl->max_texture_size, opengl->max_texture_size);
532
+    av_log(opengl, AV_LOG_DEBUG, "Max viewport size: %dx%d\n",
533
+           opengl->max_viewport_width, opengl->max_viewport_height);
534
+
535
+    OPENGL_ERROR_CHECK(opengl);
536
+    return 0;
537
+  fail:
538
+    return AVERROR_EXTERNAL;
539
+}
540
+
541
+static av_always_inline const char * opengl_get_fragment_shader_code(enum AVPixelFormat format)
542
+{
543
+    switch (format) {
544
+    case AV_PIX_FMT_YUV420P:    case AV_PIX_FMT_YUV444P:
545
+    case AV_PIX_FMT_YUV422P:    case AV_PIX_FMT_YUV410P:
546
+    case AV_PIX_FMT_YUV411P:    case AV_PIX_FMT_YUV440P:
547
+    case AV_PIX_FMT_YUV420P16:  case AV_PIX_FMT_YUV422P16:
548
+    case AV_PIX_FMT_YUV444P16:
549
+        return FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR;
550
+    case AV_PIX_FMT_YUVA420P:   case AV_PIX_FMT_YUVA444P:
551
+    case AV_PIX_FMT_YUVA422P:
552
+    case AV_PIX_FMT_YUVA420P16: case AV_PIX_FMT_YUVA422P16:
553
+    case AV_PIX_FMT_YUVA444P16:
554
+        return FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR;
555
+    case AV_PIX_FMT_RGB24:      case AV_PIX_FMT_BGR24:
556
+    case AV_PIX_FMT_0RGB:       case AV_PIX_FMT_RGB0:
557
+    case AV_PIX_FMT_0BGR:       case AV_PIX_FMT_BGR0:
558
+    case AV_PIX_FMT_RGB565:     case AV_PIX_FMT_BGR565:
559
+    case AV_PIX_FMT_RGB555:     case AV_PIX_FMT_BGR555:
560
+    case AV_PIX_FMT_RGB8:       case AV_PIX_FMT_BGR8:
561
+    case AV_PIX_FMT_RGB48:
562
+        return FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET;
563
+    case AV_PIX_FMT_ARGB:       case AV_PIX_FMT_RGBA:
564
+    case AV_PIX_FMT_ABGR:       case AV_PIX_FMT_BGRA:
565
+    case AV_PIX_FMT_RGBA64:     case AV_PIX_FMT_BGRA64:
566
+        return FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET;
567
+    case AV_PIX_FMT_GBRP:       case AV_PIX_FMT_GBRP16:
568
+        return FF_OPENGL_FRAGMENT_SHADER_RGB_PLANAR;
569
+    case AV_PIX_FMT_GBRAP: case AV_PIX_FMT_GBRAP16:
570
+        return FF_OPENGL_FRAGMENT_SHADER_RGBA_PLANAR;
571
+    default:
572
+        break;
573
+    }
574
+    return NULL;
575
+}
576
+
577
+static av_always_inline int opengl_type_size(GLenum type)
578
+{
579
+    switch(type) {
580
+    case GL_UNSIGNED_SHORT:
581
+    case FF_GL_UNSIGNED_SHORT_1_5_5_5_REV:
582
+    case GL_UNSIGNED_SHORT_5_6_5:
583
+        return 2;
584
+    case GL_UNSIGNED_BYTE:
585
+    case FF_GL_UNSIGNED_BYTE_3_3_2:
586
+    case FF_GL_UNSIGNED_BYTE_2_3_3_REV:
587
+    default:
588
+        break;
589
+    }
590
+    return 1;
591
+}
592
+
593
+static av_cold void opengl_get_texture_params(OpenGLContext *opengl)
594
+{
595
+    switch(opengl->pix_fmt) {
596
+    case AV_PIX_FMT_YUV420P:    case AV_PIX_FMT_YUV444P:
597
+    case AV_PIX_FMT_YUV422P:    case AV_PIX_FMT_YUV410P:
598
+    case AV_PIX_FMT_YUV411P:    case AV_PIX_FMT_YUV440P:
599
+    case AV_PIX_FMT_YUVA420P:   case AV_PIX_FMT_YUVA444P:
600
+    case AV_PIX_FMT_YUVA422P:
601
+    case AV_PIX_FMT_GBRP:       case AV_PIX_FMT_GBRAP:
602
+        opengl->format = GL_RED_COMPONENT;
603
+        opengl->type   = GL_UNSIGNED_BYTE;
604
+        break;
605
+    case AV_PIX_FMT_YUV420P16:  case AV_PIX_FMT_YUV422P16:
606
+    case AV_PIX_FMT_YUV444P16:
607
+    case AV_PIX_FMT_YUVA420P16: case AV_PIX_FMT_YUVA422P16:
608
+    case AV_PIX_FMT_YUVA444P16:
609
+    case AV_PIX_FMT_GBRP16:     case AV_PIX_FMT_GBRAP16:
610
+        opengl->format = GL_RED_COMPONENT;
611
+        opengl->type   = GL_UNSIGNED_SHORT;
612
+        break;
613
+    case AV_PIX_FMT_RGB24:      case AV_PIX_FMT_BGR24:
614
+        opengl->format = GL_RGB;
615
+        opengl->type   = GL_UNSIGNED_BYTE;
616
+        break;
617
+    case AV_PIX_FMT_ARGB:       case AV_PIX_FMT_RGBA:
618
+    case AV_PIX_FMT_ABGR:       case AV_PIX_FMT_BGRA:
619
+    case AV_PIX_FMT_0RGB:       case AV_PIX_FMT_RGB0:
620
+    case AV_PIX_FMT_0BGR:       case AV_PIX_FMT_BGR0:
621
+        opengl->format = GL_RGBA;
622
+        opengl->type   = GL_UNSIGNED_BYTE;
623
+        break;
624
+    case AV_PIX_FMT_RGB8:
625
+        opengl->format = GL_RGB;
626
+        opengl->type   = FF_GL_UNSIGNED_BYTE_3_3_2;
627
+        break;
628
+    case AV_PIX_FMT_BGR8:
629
+        opengl->format = GL_RGB;
630
+        opengl->type   = FF_GL_UNSIGNED_BYTE_2_3_3_REV;
631
+        break;
632
+    case AV_PIX_FMT_RGB555:     case AV_PIX_FMT_BGR555:
633
+        opengl->format = GL_RGBA;
634
+        opengl->type   = FF_GL_UNSIGNED_SHORT_1_5_5_5_REV;
635
+        break;
636
+    case AV_PIX_FMT_RGB565:     case AV_PIX_FMT_BGR565:
637
+        opengl->format = GL_RGB;
638
+        opengl->type   = GL_UNSIGNED_SHORT_5_6_5;
639
+        break;
640
+    case AV_PIX_FMT_RGB48:
641
+        opengl->format = GL_RGB;
642
+        opengl->type   = GL_UNSIGNED_SHORT;
643
+        break;
644
+    case AV_PIX_FMT_RGBA64:     case AV_PIX_FMT_BGRA64:
645
+        opengl->format = GL_RGBA;
646
+        opengl->type   = GL_UNSIGNED_SHORT;
647
+        break;
648
+    }
649
+}
650
+
651
+static void opengl_compute_display_area(AVFormatContext *s)
652
+{
653
+    AVRational sar, dar; /* sample and display aspect ratios */
654
+    OpenGLContext *opengl = s->priv_data;
655
+    AVStream *st = s->streams[0];
656
+    AVCodecContext *encctx = st->codec;
657
+
658
+    /* compute overlay width and height from the codec context information */
659
+    sar = st->sample_aspect_ratio.num ? st->sample_aspect_ratio : (AVRational){ 1, 1 };
660
+    dar = av_mul_q(sar, (AVRational){ encctx->width, encctx->height });
661
+
662
+    /* we suppose the screen has a 1/1 sample aspect ratio */
663
+    /* fit in the window */
664
+    if (av_cmp_q(dar, (AVRational){ opengl->window_width, opengl->window_height }) > 0) {
665
+        /* fit in width */
666
+        opengl->picture_width = opengl->window_width;
667
+        opengl->picture_height = av_rescale(opengl->picture_width, dar.den, dar.num);
668
+    } else {
669
+        /* fit in height */
670
+        opengl->picture_height = opengl->window_height;
671
+        opengl->picture_width = av_rescale(opengl->picture_height, dar.num, dar.den);
672
+    }
673
+}
674
+
675
+static av_cold void opengl_get_texture_size(OpenGLContext *opengl, int in_width, int in_height,
676
+                                            int *out_width, int *out_height)
677
+{
678
+    if (opengl->non_pow_2_textures) {
679
+        *out_width = in_width;
680
+        *out_height = in_height;
681
+    } else {
682
+        int max = FFMIN(FFMAX(in_width, in_height), opengl->max_texture_size);
683
+        unsigned power_of_2 = 1;
684
+        while (power_of_2 < max)
685
+            power_of_2 *= 2;
686
+        *out_height = power_of_2;
687
+        *out_width = power_of_2;
688
+        av_log(opengl, AV_LOG_DEBUG, "Texture size calculated from %dx%d into %dx%d\n",
689
+               in_width, in_height, *out_width, *out_height);
690
+    }
691
+}
692
+
693
+static av_cold void opengl_fill_color_map(OpenGLContext *opengl)
694
+{
695
+    const AVPixFmtDescriptor *desc;
696
+    int shift;
697
+    enum AVPixelFormat pix_fmt = opengl->pix_fmt;
698
+
699
+    /* We need order of components, not exact position, some minor HACKs here */
700
+    if (pix_fmt == AV_PIX_FMT_RGB565 || pix_fmt == AV_PIX_FMT_BGR555 ||
701
+        pix_fmt == AV_PIX_FMT_BGR8   || pix_fmt == AV_PIX_FMT_RGB8)
702
+        pix_fmt = AV_PIX_FMT_RGB24;
703
+    else if (pix_fmt == AV_PIX_FMT_BGR565 || pix_fmt == AV_PIX_FMT_RGB555)
704
+        pix_fmt = AV_PIX_FMT_BGR24;
705
+
706
+    desc = av_pix_fmt_desc_get(pix_fmt);
707
+    if (!(desc->flags & AV_PIX_FMT_FLAG_RGB))
708
+        return;
709
+
710
+#define FILL_COMPONENT(i) { \
711
+        shift = desc->comp[i].depth_minus1 >> 3; \
712
+        opengl->color_map[(i << 2) + ((desc->comp[i].offset_plus1 - 1) >> shift)] = 1.0; \
713
+    }
714
+
715
+    memset(opengl->color_map, 0, sizeof(opengl->color_map));
716
+    FILL_COMPONENT(0);
717
+    FILL_COMPONENT(1);
718
+    FILL_COMPONENT(2);
719
+    if (desc->flags & AV_PIX_FMT_FLAG_ALPHA)
720
+        FILL_COMPONENT(3);
721
+
722
+#undef FILL_COMPONENT
723
+}
724
+
725
+static av_cold GLuint opengl_load_shader(OpenGLContext *opengl, GLenum type, const char *source)
726
+{
727
+    GLuint shader = opengl->glprocs.glCreateShader(type);
728
+    GLint result;
729
+    if (!shader) {
730
+        av_log(opengl, AV_LOG_ERROR, "glCreateShader() failed\n");
731
+        return 0;
732
+    }
733
+    opengl->glprocs.glShaderSource(shader, 1, &source, NULL);
734
+    opengl->glprocs.glCompileShader(shader);
735
+
736
+    opengl->glprocs.glGetShaderiv(shader, FF_GL_COMPILE_STATUS, &result);
737
+    if (!result) {
738
+        char *log;
739
+        opengl->glprocs.glGetShaderiv(shader, FF_GL_INFO_LOG_LENGTH, &result);
740
+        if (result) {
741
+            if ((log = av_malloc(result))) {
742
+                opengl->glprocs.glGetShaderInfoLog(shader, result, NULL, log);
743
+                av_log(opengl, AV_LOG_ERROR, "Compile error: %s\n", log);
744
+                av_free(log);
745
+            }
746
+        }
747
+        goto fail;
748
+    }
749
+    OPENGL_ERROR_CHECK(opengl);
750
+    return shader;
751
+  fail:
752
+    opengl->glprocs.glDeleteShader(shader);
753
+    return 0;
754
+}
755
+
756
+static av_cold int opengl_compile_shaders(OpenGLContext *opengl, enum AVPixelFormat pix_fmt)
757
+{
758
+    GLuint vertex_shader = 0, fragment_shader = 0;
759
+    GLint result;
760
+    const char *fragment_shader_code = opengl_get_fragment_shader_code(pix_fmt);
761
+
762
+    if (!fragment_shader_code) {
763
+        av_log(opengl, AV_LOG_ERROR, "Provided pixel format '%s' is not supported\n",
764
+               av_get_pix_fmt_name(pix_fmt));
765
+        return AVERROR(EINVAL);
766
+    }
767
+
768
+    vertex_shader = opengl_load_shader(opengl, FF_GL_VERTEX_SHADER,
769
+                                       FF_OPENGL_VERTEX_SHADER);
770
+    if (!vertex_shader) {
771
+        av_log(opengl, AV_LOG_ERROR, "Vertex shader loading failed.\n");
772
+        goto fail;
773
+    }
774
+    fragment_shader = opengl_load_shader(opengl, FF_GL_FRAGMENT_SHADER,
775
+                                         fragment_shader_code);
776
+    if (!fragment_shader) {
777
+        av_log(opengl, AV_LOG_ERROR, "Fragment shader loading failed.\n");
778
+        goto fail;
779
+    }
780
+
781
+    opengl->program = opengl->glprocs.glCreateProgram();
782
+    if (!opengl->program)
783
+        goto fail;
784
+
785
+    opengl->glprocs.glAttachShader(opengl->program, vertex_shader);
786
+    opengl->glprocs.glAttachShader(opengl->program, fragment_shader);
787
+    opengl->glprocs.glLinkProgram(opengl->program);
788
+
789
+    opengl->glprocs.glGetProgramiv(opengl->program, FF_GL_LINK_STATUS, &result);
790
+    if (!result) {
791
+        char *log;
792
+        opengl->glprocs.glGetProgramiv(opengl->program, FF_GL_INFO_LOG_LENGTH, &result);
793
+        if (result) {
794
+            log = av_malloc(result);
795
+            if (!log)
796
+                goto fail;
797
+            opengl->glprocs.glGetProgramInfoLog(opengl->program, result, NULL, log);
798
+            av_log(opengl, AV_LOG_ERROR, "Link error: %s\n", log);
799
+            av_free(log);
800
+        }
801
+        goto fail;
802
+    }
803
+
804
+    opengl->position_attrib = opengl->glprocs.glGetAttribLocation(opengl->program, "a_position");
805
+    opengl->texture_coords_attrib = opengl->glprocs.glGetAttribLocation(opengl->program, "a_textureCoords");
806
+    opengl->projection_matrix_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_projectionMatrix");
807
+    opengl->model_view_matrix_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_modelViewMatrix");
808
+    opengl->color_map_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_colorMap");
809
+    opengl->texture_location[0] = opengl->glprocs.glGetUniformLocation(opengl->program, "u_texture0");
810
+    opengl->texture_location[1] = opengl->glprocs.glGetUniformLocation(opengl->program, "u_texture1");
811
+    opengl->texture_location[2] = opengl->glprocs.glGetUniformLocation(opengl->program, "u_texture2");
812
+    opengl->texture_location[3] = opengl->glprocs.glGetUniformLocation(opengl->program, "u_texture3");
813
+    opengl->chroma_div_w_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_chroma_div_w");
814
+    opengl->chroma_div_h_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_chroma_div_h");
815
+
816
+    OPENGL_ERROR_CHECK(opengl);
817
+    return 0;
818
+  fail:
819
+    opengl->glprocs.glDeleteShader(vertex_shader);
820
+    opengl->glprocs.glDeleteShader(fragment_shader);
821
+    opengl->glprocs.glDeleteProgram(opengl->program);
822
+    opengl->program = 0;
823
+    return AVERROR_EXTERNAL;
824
+}
825
+
826
+static av_cold int opengl_configure_texture(OpenGLContext *opengl, GLuint texture,
827
+                                            GLsizei width, GLsizei height)
828
+{
829
+    if (texture) {
830
+        int new_width, new_height;
831
+        opengl_get_texture_size(opengl, width, height, &new_width, &new_height);
832
+        glBindTexture(GL_TEXTURE_2D, texture);
833
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
834
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
835
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
836
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
837
+        glTexImage2D(GL_TEXTURE_2D, 0, opengl->format, new_width, new_height, 0,
838
+                     opengl->format, opengl->type, NULL);
839
+        OPENGL_ERROR_CHECK(NULL);
840
+    }
841
+    return 0;
842
+  fail:
843
+    return AVERROR_EXTERNAL;
844
+}
845
+
846
+static av_cold int opengl_prepare_vertex(AVFormatContext *s)
847
+{
848
+    OpenGLContext *opengl = s->priv_data;
849
+    int tex_w, tex_h;
850
+
851
+    if (opengl->window_width > opengl->max_viewport_width || opengl->window_height > opengl->max_viewport_height) {
852
+        opengl->window_width = FFMAX(opengl->window_width, opengl->max_viewport_width);
853
+        opengl->window_height = FFMAX(opengl->window_height, opengl->max_viewport_height);
854
+        av_log(opengl, AV_LOG_WARNING, "Too big viewport requested, limited to %dx%d", opengl->window_width, opengl->window_height);
855
+    }
856
+    glViewport(0, 0, opengl->window_width, opengl->window_height);
857
+    opengl_make_ortho(opengl->projection_matrix,
858
+                      - (float)opengl->window_width  / 2.0f, (float)opengl->window_width  / 2.0f,
859
+                      - (float)opengl->window_height / 2.0f, (float)opengl->window_height / 2.0f,
860
+                      1.0f, -1.0f);
861
+    opengl_make_identity(opengl->model_view_matrix);
862
+
863
+    opengl_compute_display_area(s);
864
+
865
+    opengl->vertex[0].z = opengl->vertex[1].z = opengl->vertex[2].z = opengl->vertex[3].z = 0.0f;
866
+    opengl->vertex[0].x = opengl->vertex[1].x = - (float)opengl->picture_width / 2.0f;
867
+    opengl->vertex[2].x = opengl->vertex[3].x =   (float)opengl->picture_width / 2.0f;
868
+    opengl->vertex[1].y = opengl->vertex[2].y = - (float)opengl->picture_height / 2.0f;
869
+    opengl->vertex[0].y = opengl->vertex[3].y =   (float)opengl->picture_height / 2.0f;
870
+
871
+    opengl_get_texture_size(opengl, opengl->width, opengl->height, &tex_w, &tex_h);
872
+
873
+    opengl->vertex[0].s0 = 0.0f;
874
+    opengl->vertex[0].t0 = 0.0f;
875
+    opengl->vertex[1].s0 = 0.0f;
876
+    opengl->vertex[1].t0 = (float)opengl->height / (float)tex_h;
877
+    opengl->vertex[2].s0 = (float)opengl->width  / (float)tex_w;
878
+    opengl->vertex[2].t0 = (float)opengl->height / (float)tex_h;
879
+    opengl->vertex[3].s0 = (float)opengl->width  / (float)tex_w;
880
+    opengl->vertex[3].t0 = 0.0f;
881
+
882
+    opengl->glprocs.glBindBuffer(FF_GL_ARRAY_BUFFER, opengl->vertex_buffer);
883
+    opengl->glprocs.glBufferData(FF_GL_ARRAY_BUFFER, sizeof(opengl->vertex), opengl->vertex, FF_GL_STATIC_DRAW);
884
+    opengl->glprocs.glBindBuffer(FF_GL_ARRAY_BUFFER, 0);
885
+    OPENGL_ERROR_CHECK(opengl);
886
+    return 0;
887
+  fail:
888
+    return AVERROR_EXTERNAL;
889
+}
890
+
891
+static int opengl_prepare(OpenGLContext *opengl)
892
+{
893
+    int i;
894
+    opengl->glprocs.glUseProgram(opengl->program);
895
+    opengl->glprocs.glUniformMatrix4fv(opengl->projection_matrix_location, 1, GL_FALSE, opengl->projection_matrix);
896
+    opengl->glprocs.glUniformMatrix4fv(opengl->model_view_matrix_location, 1, GL_FALSE, opengl->model_view_matrix);
897
+    for (i = 0; i < 4; i++)
898
+        if (opengl->texture_location[i] != -1) {
899
+            opengl->glprocs.glActiveTexture(GL_TEXTURE0 + i);
900
+            glBindTexture(GL_TEXTURE_2D, opengl->texture_name[i]);
901
+            opengl->glprocs.glUniform1i(opengl->texture_location[i], i);
902
+        }
903
+    if (opengl->color_map_location != -1)
904
+        opengl->glprocs.glUniformMatrix4fv(opengl->color_map_location, 1, GL_FALSE, opengl->color_map);
905
+    if (opengl->chroma_div_h_location != -1)
906
+        opengl->glprocs.glUniform1f(opengl->chroma_div_h_location, opengl->chroma_div_h);
907
+    if (opengl->chroma_div_w_location != -1)
908
+        opengl->glprocs.glUniform1f(opengl->chroma_div_w_location, opengl->chroma_div_w);
909
+
910
+    OPENGL_ERROR_CHECK(opengl);
911
+    return 0;
912
+  fail:
913
+    return AVERROR_EXTERNAL;
914
+}
915
+
916
+static av_cold int opengl_write_trailer(AVFormatContext *h)
917
+{
918
+    OpenGLContext *opengl = h->priv_data;
919
+
920
+    if (opengl->no_window &&
921
+        avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0) < 0)
922
+        av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n");
923
+
924
+    glDeleteTextures(4, opengl->texture_name);
925
+    if (opengl && opengl->glprocs.glDeleteBuffers)
926
+        opengl->glprocs.glDeleteBuffers(2, &opengl->index_buffer);
927
+
928
+#if HAVE_SDL
929
+    if (!opengl->no_window)
930
+        SDL_Quit();
931
+#endif
932
+    if (opengl->no_window &&
933
+        avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_DESTROY_WINDOW_BUFFER, NULL , 0) < 0)
934
+        av_log(opengl, AV_LOG_ERROR, "Application failed to release window buffer.\n");
935
+
936
+    return 0;
937
+}
938
+
939
+static av_cold int opengl_init_context(OpenGLContext *opengl)
940
+{
941
+    int i, ret;
942
+    const AVPixFmtDescriptor *desc;
943
+
944
+    if ((ret = opengl_compile_shaders(opengl, opengl->pix_fmt)) < 0)
945
+        goto fail;
946
+
947
+    desc = av_pix_fmt_desc_get(opengl->pix_fmt);
948
+    av_assert0(desc->nb_components > 0 && desc->nb_components <= 4);
949
+    glGenTextures(desc->nb_components, opengl->texture_name);
950
+
951
+    opengl->glprocs.glGenBuffers(2, &opengl->index_buffer);
952
+    if (!opengl->index_buffer || !opengl->vertex_buffer) {
953
+        av_log(opengl, AV_LOG_ERROR, "Buffer generation failed.\n");
954
+        ret = AVERROR_EXTERNAL;
955
+        goto fail;
956
+    }
957
+
958
+    opengl_configure_texture(opengl, opengl->texture_name[0], opengl->width, opengl->height);
959
+    if (desc->nb_components > 1) {
960
+        int has_alpha = desc->flags & AV_PIX_FMT_FLAG_ALPHA;
961
+        int num_planes = desc->nb_components - (has_alpha ? 1 : 0);
962
+        if (opengl->non_pow_2_textures) {
963
+            opengl->chroma_div_w = 1.0f;
964
+            opengl->chroma_div_h = 1.0f;
965
+        } else {
966
+            opengl->chroma_div_w = 1 << desc->log2_chroma_w;
967
+            opengl->chroma_div_h = 1 << desc->log2_chroma_h;
968
+        }
969
+        for (i = 1; i < num_planes; i++)
970
+            if (opengl->non_pow_2_textures)
971
+                opengl_configure_texture(opengl, opengl->texture_name[i],
972
+                        FF_CEIL_RSHIFT(opengl->width, desc->log2_chroma_w),
973
+                        FF_CEIL_RSHIFT(opengl->height, desc->log2_chroma_h));
974
+            else
975
+                opengl_configure_texture(opengl, opengl->texture_name[i], opengl->width, opengl->height);
976
+        if (has_alpha)
977
+            opengl_configure_texture(opengl, opengl->texture_name[3], opengl->width, opengl->height);
978
+    }
979
+
980
+    opengl->glprocs.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER, opengl->index_buffer);
981
+    opengl->glprocs.glBufferData(FF_GL_ELEMENT_ARRAY_BUFFER, sizeof(g_index), g_index, FF_GL_STATIC_DRAW);
982
+    opengl->glprocs.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER, 0);
983
+
984
+    glEnable(GL_BLEND);
985
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
986
+
987
+    glClearColor((float)opengl->background[0] / 255.0f, (float)opengl->background[1] / 255.0f,
988
+                 (float)opengl->background[2] / 255.0f, 1.0f);
989
+
990
+    ret = AVERROR_EXTERNAL;
991
+    OPENGL_ERROR_CHECK(opengl);
992
+
993
+    return 0;
994
+  fail:
995
+    return ret;
996
+}
997
+
998
+static av_cold int opengl_write_header(AVFormatContext *h)
999
+{
1000
+    OpenGLContext *opengl = h->priv_data;
1001
+    AVStream *st;
1002
+    int ret;
1003
+
1004
+    if (h->nb_streams != 1 ||
1005
+        h->streams[0]->codec->codec_type != AVMEDIA_TYPE_VIDEO ||
1006
+        h->streams[0]->codec->codec_id != AV_CODEC_ID_RAWVIDEO) {
1007
+        av_log(opengl, AV_LOG_ERROR, "Only a single video stream is supported.\n");
1008
+        return AVERROR(EINVAL);
1009
+    }
1010
+    st = h->streams[0];
1011
+    opengl->width = st->codec->width;
1012
+    opengl->height = st->codec->height;
1013
+    opengl->pix_fmt = st->codec->pix_fmt;
1014
+
1015
+    if (!opengl->window_title && !opengl->no_window)
1016
+        opengl->window_title = av_strdup(h->filename);
1017
+
1018
+    if (!opengl->no_window) {
1019
+#if HAVE_SDL
1020
+        if ((ret = opengl_sdl_create_window(h)) < 0)
1021
+            goto fail;
1022
+#else
1023
+        av_log(opengl, AV_LOG_ERROR, "FFmpeg is compiled without SDL. Cannot create default window.\n");
1024
+        ret = AVERROR(ENOSYS);
1025
+        goto fail;
1026
+#endif
1027
+    } else {
1028
+        if ((ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_CREATE_WINDOW_BUFFER, NULL , 0)) < 0) {
1029
+            av_log(opengl, AV_LOG_ERROR, "Application failed to create window buffer.\n");
1030
+            goto fail;
1031
+        }
1032
+        if ((ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0)) < 0) {
1033
+            av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n");
1034
+            goto fail;
1035
+        }
1036
+    }
1037
+
1038
+    if ((ret = opengl_read_limits(opengl)) < 0)
1039
+        goto fail;
1040
+
1041
+    if (opengl->width > opengl->max_texture_size || opengl->height > opengl->max_texture_size) {
1042
+        av_log(opengl, AV_LOG_ERROR, "Too big picture %dx%d, max supported size is %dx%d\n",
1043
+               opengl->width, opengl->height, opengl->max_texture_size, opengl->max_texture_size);
1044
+        ret = AVERROR(EINVAL);
1045
+        goto fail;
1046
+    }
1047
+
1048
+    if (!opengl->no_window) {
1049
+#if HAVE_SDL
1050
+        if ((ret = opengl_sdl_load_procedures(opengl)) < 0)
1051
+            goto fail;
1052
+#endif
1053
+    } else if ((ret = opengl_load_procedures(opengl)) < 0)
1054
+        goto fail;
1055
+
1056
+    opengl_fill_color_map(opengl);
1057
+    opengl_get_texture_params(opengl);
1058
+
1059
+    if ((ret = opengl_init_context(opengl)) < 0)
1060
+        goto fail;
1061
+
1062
+    if ((ret = opengl_prepare_vertex(h)) < 0)
1063
+        goto fail;
1064
+
1065
+    glClear(GL_COLOR_BUFFER_BIT);
1066
+
1067
+#if HAVE_SDL
1068
+    if (!opengl->no_window)
1069
+        SDL_GL_SwapBuffers();
1070
+#endif
1071
+    if (opengl->no_window &&
1072
+        (ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_DISPLAY_WINDOW_BUFFER, NULL , 0)) < 0) {
1073
+        av_log(opengl, AV_LOG_ERROR, "Application failed to display window buffer.\n");
1074
+        goto fail;
1075
+    }
1076
+
1077
+    ret = AVERROR_EXTERNAL;
1078
+    OPENGL_ERROR_CHECK(opengl);
1079
+    return 0;
1080
+
1081
+  fail:
1082
+    opengl_write_trailer(h);
1083
+    return ret;
1084
+}
1085
+
1086
+static uint8_t* opengl_get_plane_pointer(OpenGLContext *opengl, AVPacket *pkt, int comp_index,
1087
+                                         const AVPixFmtDescriptor *desc)
1088
+{
1089
+    uint8_t *data = pkt->data;
1090
+    int wordsize = opengl_type_size(opengl->type);
1091
+    int width_chroma = FF_CEIL_RSHIFT(opengl->width, desc->log2_chroma_w);
1092
+    int height_chroma = FF_CEIL_RSHIFT(opengl->height, desc->log2_chroma_h);
1093
+    int plane = desc->comp[comp_index].plane;
1094
+
1095
+    switch(plane) {
1096
+    case 0:
1097
+        break;
1098
+    case 1:
1099
+        data += opengl->width * opengl->height * wordsize;
1100
+        break;
1101
+    case 2:
1102
+        data += opengl->width * opengl->height * wordsize;
1103
+        data += width_chroma * height_chroma * wordsize;
1104
+        break;
1105
+    case 3:
1106
+        data += opengl->width * opengl->height * wordsize;
1107
+        data += 2 * width_chroma * height_chroma * wordsize;
1108
+        break;
1109
+    default:
1110
+        return NULL;
1111
+    }
1112
+    return data;
1113
+}
1114
+
1115
+static int opengl_draw(AVFormatContext *h, AVPacket *pkt, int repaint)
1116
+{
1117
+    OpenGLContext *opengl = h->priv_data;
1118
+    enum AVPixelFormat pix_fmt = h->streams[0]->codec->pix_fmt;
1119
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
1120
+    int ret;
1121
+
1122
+#if HAVE_SDL
1123
+    if (!opengl->no_window && (ret = opengl_sdl_process_events(h)) < 0)
1124
+        goto fail;
1125
+#endif
1126
+    if (opengl->no_window &&
1127
+        (ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0)) < 0) {
1128
+        av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n");
1129
+        goto fail;
1130
+    }
1131
+
1132
+    glClear(GL_COLOR_BUFFER_BIT);
1133
+
1134
+    if (!repaint) {
1135
+        glBindTexture(GL_TEXTURE_2D, opengl->texture_name[0]);
1136
+        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, opengl->width, opengl->height, opengl->format, opengl->type,
1137
+                        opengl_get_plane_pointer(opengl, pkt, 0, desc));
1138
+        if (desc->flags & AV_PIX_FMT_FLAG_PLANAR) {
1139
+            int width_chroma = FF_CEIL_RSHIFT(opengl->width, desc->log2_chroma_w);
1140
+            int height_chroma = FF_CEIL_RSHIFT(opengl->height, desc->log2_chroma_h);
1141
+            glBindTexture(GL_TEXTURE_2D, opengl->texture_name[1]);
1142
+            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_chroma, height_chroma, opengl->format, opengl->type,
1143
+                            opengl_get_plane_pointer(opengl, pkt, 1, desc));
1144
+            glBindTexture(GL_TEXTURE_2D, opengl->texture_name[2]);
1145
+            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_chroma, height_chroma, opengl->format, opengl->type,
1146
+                            opengl_get_plane_pointer(opengl, pkt, 2, desc));
1147
+            if (desc->flags & AV_PIX_FMT_FLAG_ALPHA) {
1148
+                glBindTexture(GL_TEXTURE_2D, opengl->texture_name[3]);
1149
+                glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, opengl->width, opengl->height, opengl->format, opengl->type,
1150
+                                opengl_get_plane_pointer(opengl, pkt, 3, desc));
1151
+            }
1152
+        }
1153
+    }
1154
+    ret = AVERROR_EXTERNAL;
1155
+    OPENGL_ERROR_CHECK(opengl);
1156
+
1157
+    if ((ret = opengl_prepare(opengl)) < 0)
1158
+        goto fail;
1159
+
1160
+    opengl->glprocs.glBindBuffer(FF_GL_ARRAY_BUFFER, opengl->vertex_buffer);
1161
+    opengl->glprocs.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER, opengl->index_buffer);
1162
+    opengl->glprocs.glVertexAttribPointer(opengl->position_attrib, 3, GL_FLOAT, GL_FALSE, sizeof(OpenGLVertexInfo), 0);
1163
+    opengl->glprocs.glEnableVertexAttribArray(opengl->position_attrib);
1164
+    opengl->glprocs.glVertexAttribPointer(opengl->texture_coords_attrib, 2, GL_FLOAT, GL_FALSE, sizeof(OpenGLVertexInfo), 12);
1165
+    opengl->glprocs.glEnableVertexAttribArray(opengl->texture_coords_attrib);
1166
+
1167
+    glDrawElements(GL_TRIANGLES, FF_ARRAY_ELEMS(g_index), GL_UNSIGNED_SHORT, 0);
1168
+
1169
+    ret = AVERROR_EXTERNAL;
1170
+    OPENGL_ERROR_CHECK(opengl);
1171
+
1172
+#if HAVE_SDL
1173
+    if (!opengl->no_window)
1174
+        SDL_GL_SwapBuffers();
1175
+#endif
1176
+    if (opengl->no_window &&
1177
+        (ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_DISPLAY_WINDOW_BUFFER, NULL , 0)) < 0) {
1178
+        av_log(opengl, AV_LOG_ERROR, "Application failed to display window buffer.\n");
1179
+        goto fail;
1180
+    }
1181
+
1182
+    return 0;
1183
+  fail:
1184
+    return ret;
1185
+}
1186
+
1187
+static int opengl_write_packet(AVFormatContext *h, AVPacket *pkt)
1188
+{
1189
+    return opengl_draw(h, pkt, 0);
1190
+}
1191
+
1192
+#define OFFSET(x) offsetof(OpenGLContext, x)
1193
+#define ENC AV_OPT_FLAG_ENCODING_PARAM
1194
+static const AVOption options[] = {
1195
+    { "background",   "set background color",   OFFSET(background),   AV_OPT_TYPE_COLOR,  {.str = "black"}, CHAR_MIN, CHAR_MAX, ENC },
1196
+    { "no_window",    "disable default window", OFFSET(no_window),    AV_OPT_TYPE_INT,    {.i64 = 0}, INT_MIN, INT_MAX, ENC },
1197
+    { "window_title", "set window title",       OFFSET(window_title), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, ENC },
1198
+    { NULL }
1199
+};
1200
+
1201
+static const AVClass opengl_class = {
1202
+    .class_name = "opengl outdev",
1203
+    .item_name  = av_default_item_name,
1204
+    .option     = options,
1205
+    .version    = LIBAVUTIL_VERSION_INT,
1206
+};
1207
+
1208
+AVOutputFormat ff_opengl_muxer = {
1209
+    .name           = "opengl",
1210
+    .long_name      = NULL_IF_CONFIG_SMALL("OpenGL output"),
1211
+    .priv_data_size = sizeof(OpenGLContext),
1212
+    .audio_codec    = AV_CODEC_ID_NONE,
1213
+    .video_codec    = AV_CODEC_ID_RAWVIDEO,
1214
+    .write_header   = opengl_write_header,
1215
+    .write_packet   = opengl_write_packet,
1216
+    .write_trailer  = opengl_write_trailer,
1217
+    .control_message = opengl_control_message,
1218
+    .flags          = AVFMT_NOFILE | AVFMT_VARIABLE_FPS | AVFMT_NOTIMESTAMPS,
1219
+    .priv_class     = &opengl_class,
1220
+};
0 1221
new file mode 100644
... ...
@@ -0,0 +1,176 @@
0
+/*
1
+ * Copyright (c) 2014 Lukasz Marek
2
+ *
3
+ * This file is part of FFmpeg.
4
+ *
5
+ * FFmpeg is free software; you can redistribute it and/or
6
+ * modify it under the terms of the GNU Lesser General Public
7
+ * License as published by the Free Software Foundation; either
8
+ * version 2.1 of the License, or (at your option) any later version.
9
+ *
10
+ * FFmpeg is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Lesser General Public
16
+ * License along with FFmpeg; if not, write to the Free Software
17
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+ */
19
+
20
+#ifndef AVDEVICE_OPENGL_SHADERS_H
21
+#define AVDEVICE_OPENGL_SHADERS_H
22
+
23
+#include "libavutil/pixfmt.h"
24
+
25
+const char *FF_OPENGL_VERTEX_SHADER =
26
+    "uniform mat4 u_projectionMatrix;"
27
+    "uniform mat4 u_modelViewMatrix;"
28
+
29
+    "attribute vec4 a_position;"
30
+    "attribute vec2 a_textureCoords;"
31
+
32
+    "varying vec2 texture_coordinate;"
33
+
34
+    "void main()"
35
+    "{"
36
+        "gl_Position = u_projectionMatrix * (a_position * u_modelViewMatrix);"
37
+        "texture_coordinate = a_textureCoords;"
38
+    "}";
39
+
40
+/**
41
+ * Fragment shader for packet RGBA formats.
42
+ */
43
+const char *FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET =
44
+#if defined(GL_ES_VERSION_2_0)
45
+    "precision mediump float;"
46
+#endif
47
+    "uniform sampler2D u_texture0;"
48
+    "uniform mat4 u_colorMap;"
49
+
50
+    "varying vec2 texture_coordinate;"
51
+
52
+    "void main()"
53
+    "{"
54
+        "gl_FragColor = texture2D(u_texture0, texture_coordinate) * u_colorMap;"
55
+    "}";
56
+
57
+/**
58
+ * Fragment shader for packet RGB formats.
59
+ */
60
+const char *FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET =
61
+#if defined(GL_ES_VERSION_2_0)
62
+    "precision mediump float;"
63
+#endif
64
+    "uniform sampler2D u_texture0;"
65
+    "uniform mat4 u_colorMap;"
66
+
67
+    "varying vec2 texture_coordinate;"
68
+
69
+    "void main()"
70
+    "{"
71
+        "gl_FragColor = vec4((texture2D(u_texture0, texture_coordinate) * u_colorMap).rgb, 1.0);"
72
+    "}";
73
+
74
+/**
75
+ * Fragment shader for planar RGBA formats.
76
+ */
77
+const char *FF_OPENGL_FRAGMENT_SHADER_RGBA_PLANAR =
78
+#if defined(GL_ES_VERSION_2_0)
79
+    "precision mediump float;"
80
+#endif
81
+    "uniform sampler2D u_texture0;"
82
+    "uniform sampler2D u_texture1;"
83
+    "uniform sampler2D u_texture2;"
84
+    "uniform sampler2D u_texture3;"
85
+
86
+    "varying vec2 texture_coordinate;"
87
+
88
+    "void main()"
89
+    "{"
90
+        "gl_FragColor = vec4(texture2D(u_texture0, texture_coordinate).r,"
91
+                            "texture2D(u_texture1, texture_coordinate).r,"
92
+                            "texture2D(u_texture2, texture_coordinate).r,"
93
+                            "texture2D(u_texture3, texture_coordinate).r);"
94
+    "}";
95
+
96
+/**
97
+ * Fragment shader for planar RGB formats.
98
+ */
99
+const char *FF_OPENGL_FRAGMENT_SHADER_RGB_PLANAR =
100
+#if defined(GL_ES_VERSION_2_0)
101
+    "precision mediump float;"
102
+#endif
103
+    "uniform sampler2D u_texture0;"
104
+    "uniform sampler2D u_texture1;"
105
+    "uniform sampler2D u_texture2;"
106
+
107
+    "varying vec2 texture_coordinate;"
108
+
109
+    "void main()"
110
+    "{"
111
+        "gl_FragColor = vec4(texture2D(u_texture0, texture_coordinate).r,"
112
+                            "texture2D(u_texture1, texture_coordinate).r,"
113
+                            "texture2D(u_texture2, texture_coordinate).r,"
114
+                            "1.0);"
115
+    "}";
116
+
117
+/**
118
+ * Fragment shader for planar YUV formats.
119
+ */
120
+const char *FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR =
121
+#if defined(GL_ES_VERSION_2_0)
122
+    "precision mediump float;"
123
+#endif
124
+    "uniform sampler2D u_texture0;"
125
+    "uniform sampler2D u_texture1;"
126
+    "uniform sampler2D u_texture2;"
127
+    "uniform float u_chroma_div_w;"
128
+    "uniform float u_chroma_div_h;"
129
+
130
+    "varying vec2 texture_coordinate;"
131
+
132
+    "void main()"
133
+    "{"
134
+        "vec3 yuv;"
135
+
136
+        "yuv.r = texture2D(u_texture0, texture_coordinate).r - 0.0625;"
137
+        "yuv.g = texture2D(u_texture1, vec2(texture_coordinate.x / u_chroma_div_w, texture_coordinate.y / u_chroma_div_h)).r - 0.5;"
138
+        "yuv.b = texture2D(u_texture2, vec2(texture_coordinate.x / u_chroma_div_w, texture_coordinate.y / u_chroma_div_h)).r - 0.5;"
139
+
140
+        "gl_FragColor = clamp(vec4(mat3(1.1643,  1.16430, 1.1643,"
141
+                                       "0.0,    -0.39173, 2.0170,"
142
+                                       "1.5958, -0.81290, 0.0) * yuv, 1.0), 0.0, 1.0);"
143
+
144
+    "}";
145
+
146
+/**
147
+ * Fragment shader for planar YUVA formats.
148
+ */
149
+const char *FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR =
150
+#if defined(GL_ES_VERSION_2_0)
151
+    "precision mediump float;"
152
+#endif
153
+    "uniform sampler2D u_texture0;"
154
+    "uniform sampler2D u_texture1;"
155
+    "uniform sampler2D u_texture2;"
156
+    "uniform sampler2D u_texture3;"
157
+    "uniform float u_chroma_div_w;"
158
+    "uniform float u_chroma_div_h;"
159
+
160
+    "varying vec2 texture_coordinate;"
161
+
162
+    "void main()"
163
+    "{"
164
+        "vec3 yuv;"
165
+
166
+        "yuv.r = texture2D(u_texture0, texture_coordinate).r - 0.0625;"
167
+        "yuv.g = texture2D(u_texture1, vec2(texture_coordinate.x / u_chroma_div_w, texture_coordinate.y / u_chroma_div_h)).r - 0.5;"
168
+        "yuv.b = texture2D(u_texture2, vec2(texture_coordinate.x / u_chroma_div_w, texture_coordinate.y / u_chroma_div_h)).r - 0.5;"
169
+
170
+        "gl_FragColor = clamp(vec4(mat3(1.1643,  1.16430, 1.1643,"
171
+                                       "0.0,    -0.39173, 2.0170,"
172
+                                       "1.5958, -0.81290, 0.0) * yuv, texture2D(u_texture3, texture_coordinate).r), 0.0, 1.0);"
173
+    "}";
174
+
175
+#endif /* AVDEVICE_OPENGL_SHADERS_H */