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