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