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 <stddef.h>
29
30 #include "config.h"
31
32 #if HAVE_WINDOWS_H
33 #define WIN32_LEAN_AND_MEAN
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 CONFIG_SDL2
49 #include <SDL.h>
50 #endif
51
62
63 #ifndef APIENTRY
65 #endif
66
67 /* FF_GL_RED_COMPONENT is used for planar 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
122
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
161 {
162 float x,
y,
z;
///<Position
163 float s0,
t0;
///<Texture coords
165
166 /* defines 2 triangles to display */
168 {
169 0, 1, 2,
170 0, 3, 2,
171 };
172
174 AVClass *
class;
///< class for private options
175
176 #if CONFIG_SDL2
178 SDL_GLContext glcontext;
179 #endif
181
182 int inited;
///< Set to 1 when write_header was successfully called.
186
187 /* OpenGL implementation limits */
193
194 /* Current OpenGL configuration */
210
216
217 /* Stream information */
228
277 };
278
282
284 {
293 }
298 }
302 }
306 }
307 }
308
310 {
319 goto end;
320 }
322 goto end;
324 }
325 end:
327 }
328
330 {
337 }
341 }
343 }
344
345 #if CONFIG_SDL2
347 {
350 SDL_Event event;
351 SDL_PumpEvents();
352 while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT) > 0) {
353 switch (event.type) {
354 case SDL_QUIT:
356 case SDL_KEYDOWN:
357 switch (event.key.keysym.sym) {
358 case SDLK_ESCAPE:
359 case SDLK_q:
361 }
362 return 0;
363 case SDL_WINDOWEVENT:
364 switch(event.window.event) {
365 case SDL_WINDOWEVENT_RESIZED:
366 case SDL_WINDOWEVENT_SIZE_CHANGED:
367 SDL_GL_GetDrawableSize(opengl->window, &
message.width, &
message.height);
369 default:
370 break;
371 }
372 }
373 }
374 return 0;
375 }
376
378 {
381 if (SDL_Init(SDL_INIT_VIDEO)) {
384 }
386 SDL_WINDOWPOS_UNDEFINED,
387 SDL_WINDOWPOS_UNDEFINED,
389 SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL);
390 if (!opengl->window) {
391 av_log(opengl,
AV_LOG_ERROR,
"Unable to create default window: %s\n", SDL_GetError());
393 }
394 opengl->glcontext = SDL_GL_CreateContext(opengl->window);
395 if (!opengl->glcontext) {
396 av_log(opengl,
AV_LOG_ERROR,
"Unable to create OpenGL context on default window: %s\n", SDL_GetError());
398 }
399 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
400 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
401 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
402 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
403 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
405 SDL_GL_GetDrawableSize(opengl->window, &
message.width, &
message.height);
407 }
408
410 {
412
413 #define LOAD_OPENGL_FUN(name, type) \
414 procs->name = (type)SDL_GL_GetProcAddress(#name); \
415 if (!procs->name) { \
416 av_log(opengl, AV_LOG_ERROR, "Cannot load OpenGL function: '%s'\n", #name); \
417 return AVERROR(ENOSYS); \
418 }
419
445
446 return 0;
447
448 #undef LOAD_OPENGL_FUN
449 }
450 #endif /* CONFIG_SDL2 */
451
452 #if defined(__APPLE__)
454 {
456
457 #if CONFIG_SDL2
459 return opengl_sdl_load_procedures(opengl);
460 #endif
461
487 return 0;
488 }
489 #else
491 {
493
494 #if HAVE_GLXGETPROCADDRESS
495 #define SelectedGetProcAddress glXGetProcAddress
496 #elif HAVE_WGLGETPROCADDRESS
497 #define SelectedGetProcAddress wglGetProcAddress
498 #endif
499
500 #define LOAD_OPENGL_FUN(name, type) \
501 procs->name = (type)SelectedGetProcAddress(#name); \
502 if (!procs->name) { \
503 av_log(opengl, AV_LOG_ERROR, "Cannot load OpenGL function: '%s'\n", #name); \
504 return AVERROR(ENOSYS); \
505 }
506
507 #if CONFIG_SDL2
509 return opengl_sdl_load_procedures(opengl);
510 #endif
511
537
538 return 0;
539
540 #undef SelectedGetProcAddress
541 #undef LOAD_OPENGL_FUN
542 }
543 #endif
544
546 {
547 memset(matrix, 0, 16 * sizeof(float));
548 matrix[0] = matrix[5] = matrix[10] = matrix[15] = 1.0f;
549 }
550
552 float bottom, float top, float nearZ, float farZ)
553 {
554 float ral = right +
left;
555 float rsl = right -
left;
556 float tab = top + bottom;
557 float tsb = top - bottom;
558 float fan = farZ + nearZ;
559 float fsn = farZ - nearZ;
560
561 memset(matrix, 0, 16 * sizeof(float));
562 matrix[0] = 2.0f / rsl;
563 matrix[5] = 2.0f / tsb;
564 matrix[10] = -2.0f / fsn;
565 matrix[12] = -ral / rsl;
566 matrix[13] = -
tab / tsb;
567 matrix[14] = -fan / fsn;
568 matrix[15] = 1.0f;
569 }
570
572 {
574 static const struct{
575 const char *extension;
578 } required_extensions[] = {
579 { "GL_ARB_multitexture", 1, 3 },
580 { "GL_ARB_vertex_buffer_object", 1, 5 }, //GLX_ARB_vertex_buffer_object
581 { "GL_ARB_vertex_shader", 2, 0 },
582 { "GL_ARB_fragment_shader", 2, 0 },
583 { "GL_ARB_shader_objects", 2, 0 },
585 };
587 const char *extensions, *
version;
588
589 version = glGetString(GL_VERSION);
590 extensions = glGetString(GL_EXTENSIONS);
594 }
595
598
599 for (
i = 0; required_extensions[
i].extension;
i++) {
602 !strstr(extensions, required_extensions[
i].extension)) {
604 required_extensions[
i].extension);
607 }
608 }
612 #if defined(GL_ES_VERSION_2_0)
613 opengl->
unpack_subimage = !!strstr(extensions,
"GL_EXT_unpack_subimage");
614 #else
616 #endif
617
623
625 return 0;
628 }
629
631 {
636 }
638 }
639
641 {
643 case GL_UNSIGNED_SHORT:
645 case GL_UNSIGNED_SHORT_5_6_5:
646 return 2;
647 case GL_UNSIGNED_BYTE:
650 default:
651 break;
652 }
653 return 1;
654 }
655
657 {
663 break;
664 }
665 }
666 }
667
669 {
670 AVRational sar, dar;
/* sample and display aspect ratios */
674
675 /* compute overlay width and height from the codec context information */
678
679 /* we suppose the screen has a 1/1 sample aspect ratio */
680 /* fit in the window */
682 /* fit in width */
685 } else {
686 /* fit in height */
689 }
690 }
691
693 int *out_width, int *out_height)
694 {
696 *out_width = in_width;
697 *out_height = in_height;
698 } else {
700 unsigned power_of_2 = 1;
701 while (power_of_2 <
max)
702 power_of_2 *= 2;
703 *out_height = power_of_2;
704 *out_width = power_of_2;
706 in_width, in_height, *out_width, *out_height);
707 }
708 }
709
711 {
715
716 /* We need order of components, not exact position, some minor HACKs here */
722
725 return;
726
727 #define FILL_COMPONENT(i) { \
728 shift = (desc->comp[i].depth - 1) >> 3; \
729 opengl->color_map[(i << 2) + (desc->comp[i].offset >> shift)] = 1.0; \
730 }
731
738
739 #undef FILL_COMPONENT
740 }
741
743 {
746 if (!shader) {
748 return 0;
749 }
752
755 char *log;
762 }
763 }
765 }
767 return shader;
770 return 0;
771 }
772
774 {
777
778 if (!fragment_shader_code) {
782 }
783
789 }
791 fragment_shader_code);
795 }
796
800
804
807 char *log;
811 if (!log)
816 }
818 }
819
831
833 return 0;
840 }
841
844 {
845 if (texture) {
846 int new_width, new_height;
848 glBindTexture(GL_TEXTURE_2D, texture);
849 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
850 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
851 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
852 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
853 glTexImage2D(GL_TEXTURE_2D, 0, opengl->
format, new_width, new_height, 0,
856 }
857 return 0;
860 }
861
863 {
865 int tex_w, tex_h;
866
871 }
876 1.0f, -1.0f);
878
880
886
888
897
902 return 0;
905 }
906
908 {
913 for (
i = 0;
i < 4;
i++)
918 }
925
927 return 0;
930 }
931
933 {
936
938 #if CONFIG_SDL2
939 if ((
ret = opengl_sdl_create_window(
h)) < 0) {
942 }
943 #else
944 av_log(opengl,
AV_LOG_ERROR,
"FFmpeg is compiled without SDL. Cannot create default window.\n");
946 #endif
947 } else {
956 }
960 }
961 }
962 return 0;
963 }
964
966 {
970 #if CONFIG_SDL2
971 SDL_GL_DeleteContext(opengl->glcontext);
972 SDL_DestroyWindow(opengl->window);
973 SDL_Quit();
974 #endif
978 }
979 return 0;
980 }
981
983 {
985
989
992
993 return 0;
994 }
995
997 {
1000
1003
1007
1013 }
1014
1016 if (
desc->nb_components > 1) {
1018 int num_planes =
desc->nb_components - (has_alpha ? 1 : 0);
1022 } else {
1025 }
1026 for (
i = 1;
i < num_planes;
i++)
1031 else
1033 if (has_alpha)
1035 }
1036
1040
1041 glEnable(GL_BLEND);
1042 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1043
1045 (
float)opengl->
background[2] / 255.0f, 1.0f);
1046
1049
1050 return 0;
1053 }
1054
1056 {
1061
1062 if (
h->nb_streams != 1 ||
1065 av_log(opengl,
AV_LOG_ERROR,
"Only a single raw or wrapped avframe video stream is supported.\n");
1067 }
1076
1079
1082
1085
1091 }
1092
1095
1098
1101
1104
1105 glClear(GL_COLOR_BUFFER_BIT);
1106
1107 #if CONFIG_SDL2
1109 SDL_GL_SwapWindow(opengl->window);
1110 #endif
1115 }
1116
1119
1121 return 0;
1122
1126 }
1127
1130 {
1135 int plane =
desc->comp[comp_index].plane;
1136
1137 switch(plane) {
1138 case 0:
1139 break;
1140 case 1:
1142 break;
1143 case 2:
1145 data += width_chroma * height_chroma * wordsize;
1146 break;
1147 case 3:
1149 data += 2 * width_chroma * height_chroma * wordsize;
1150 break;
1151 default:
1153 }
1155 }
1156
1157 #define LOAD_TEXTURE_DATA(comp_index, sub) \
1158 { \
1159 int width = sub ? AV_CEIL_RSHIFT(opengl->width, desc->log2_chroma_w) : opengl->width; \
1160 int height = sub ? AV_CEIL_RSHIFT(opengl->height, desc->log2_chroma_h): opengl->height; \
1161 uint8_t *data; \
1162 int plane = desc->comp[comp_index].plane; \
1163 \
1164 glBindTexture(GL_TEXTURE_2D, opengl->texture_name[comp_index]); \
1165 if (!is_pkt) { \
1166 GLint length = ((AVFrame *)input)->linesize[plane]; \
1167 int bytes_per_pixel = opengl_type_size(opengl->type); \
1168 if (!(desc->flags & AV_PIX_FMT_FLAG_PLANAR)) \
1169 bytes_per_pixel *= desc->nb_components; \
1170 data = ((AVFrame *)input)->data[plane]; \
1171 if (!(length % bytes_per_pixel) && \
1172 (opengl->unpack_subimage || ((length / bytes_per_pixel) == width))) { \
1173 length /= bytes_per_pixel; \
1174 if (length != width) \
1175 glPixelStorei(FF_GL_UNPACK_ROW_LENGTH, length); \
1176 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, \
1177 opengl->format, opengl->type, data); \
1178 if (length != width) \
1179 glPixelStorei(FF_GL_UNPACK_ROW_LENGTH, 0); \
1180 } else { \
1181 int h; \
1182 for (h = 0; h < height; h++) { \
1183 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, h, width, 1, \
1184 opengl->format, opengl->type, data); \
1185 data += length; \
1186 } \
1187 } \
1188 } else { \
1189 data = opengl_get_plane_pointer(opengl, input, comp_index, desc); \
1190 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, \
1191 opengl->format, opengl->type, data); \
1192 } \
1193 }
1194
1196 {
1201
1202 #if CONFIG_SDL2
1203 if (!opengl->
no_window && (
ret = opengl_sdl_process_events(
h)) < 0)
1205 #endif
1210 }
1211
1212 glClear(GL_COLOR_BUFFER_BIT);
1213
1214 if (!repaint) {
1215 if (is_pkt)
1216 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1223 }
1224 }
1227
1230
1237
1239
1242
1243 #if CONFIG_SDL2
1245 SDL_GL_SwapWindow(opengl->window);
1246 #endif
1251 }
1252
1253 return 0;
1256 }
1257
1259 {
1264 } else {
1266 }
1267 }
1268
1271 {
1273 return 0;
1275 }
1276
1277 #define OFFSET(x) offsetof(OpenGLContext, x)
1278 #define ENC AV_OPT_FLAG_ENCODING_PARAM
1285 };
1286
1293 };
1294
1308 };