It can render to OpenGL context provided by application or into SDL window
Signed-off-by: Lukasz Marek <lukasz.m.luki@gmail.com>
... | ... |
@@ -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 */ |