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