blob: a9fea08d9da4200ba808831b92ae5bf69d0155b7 [file] [edit]
/*
* GPAC - Multimedia Framework C SDK
*
* Authors: Jean Le Feuvre - Romain Bouqueau
* Copyright (c) Telecom ParisTech 2000-2026
* All rights reserved
*
* This file is part of GPAC / SDL audio and video module
*
* GPAC is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* GPAC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "sdl_out.h"
#ifdef WIN32
#include <windows.h>
#endif
#ifdef GPAC_CONFIG_IOS
#include <OpenGLES/ES1/gl.h>
#include <OpenGLES/ES1/glext.h>
#endif
#ifndef _WIN32_WCE
#include <locale.h>
#endif
/*cursors data*/
static char hand_data[] =
{
0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,1,2,2,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,1,2,2,1,2,2,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,1,2,2,1,2,2,1,2,2,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,1,2,2,1,2,2,1,2,2,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,0,1,2,2,1,2,2,1,2,2,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,2,2,1,1,2,2,2,2,2,2,2,2,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,2,2,1,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,2,1,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,1,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,1,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,1,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,1,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,1,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,1,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
static char collide_data[] =
{
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,1,1,1,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,1,1,1,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,1,1,1,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,1,1,1,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
#define SDLVID() SDLVidCtx *ctx = (SDLVidCtx *)dr->opaque
#if SDL_VERSION_ATLEAST(2,0,0)
void SDLVid_SetCaption(SDL_Window* window)
{
if (SDL_GetCurrentVideoDriver()) {
char szCap[1024];
sprintf(szCap, "SDL Video Output (%s)", SDL_GetCurrentVideoDriver());
SDL_SetWindowTitle(window, szCap);
} else {
SDL_SetWindowTitle(window, "SDL Video Output");
}
}
#else
#define SDLK_KP_0 SDLK_KP0
#define SDLK_KP_1 SDLK_KP1
#define SDLK_KP_2 SDLK_KP2
#define SDLK_KP_3 SDLK_KP3
#define SDLK_KP_4 SDLK_KP4
#define SDLK_KP_5 SDLK_KP5
#define SDLK_KP_6 SDLK_KP6
#define SDLK_KP_7 SDLK_KP7
#define SDLK_KP_8 SDLK_KP8
#define SDLK_KP_9 SDLK_KP9
#define SDLK_NUMLOCKCLEAR SDLK_NUMLOCK
#define SDLK_SCROLLLOCK SDLK_SCROLLOCK
#define SDLK_APPLICATION SDLK_COMPOSE
#define SDLK_PRINTSCREEN SDLK_PRINT
#define SDL_WINDOW_RESIZABLE SDL_RESIZABLE
static u32 video_modes[] =
{
320, 200,
320, 240,
400, 300,
600, 400,
800, 600,
1024, 768,
1152, 864,
1280, 1024
};
static const u32 nb_video_modes = 8;
void SDLVid_SetCaption()
{
char szName[100];
if (SDL_VideoDriverName(szName, 100)) {
char szCap[1024];
sprintf(szCap, "SDL Video Output (%s)", szName);
SDL_WM_SetCaption(szCap, NULL);
} else {
SDL_WM_SetCaption("SDL Video Output", NULL);
}
}
#endif
SDL_Cursor *SDLVid_LoadCursor(char *maskdata)
{
s32 ind, i, j;
u8 data[4*32];
u8 mask[4*32];
ind = -1;
for (i=0; i<32; i++) {
for (j=0; j<32; j++) {
if (j%8) {
data[ind] <<= 1;
mask[ind] <<= 1;
} else {
ind++;
data[ind] = mask[ind] = 0;
}
switch (maskdata[j+32*i]) {
/*black*/
case 1:
data[ind] |= 0x01;
/*white*/
case 2:
mask[ind] |= 0x01;
break;
}
}
}
return SDL_CreateCursor(data, mask, 32, 32, 0, 0);
}
typedef struct
{
u32 sdl_key;
u32 gf_key;
u32 gf_flags;
} SDLKeyToGPAC;
static SDLKeyToGPAC SDLKeys[] =
{
{SDLK_BACKSPACE, GF_KEY_BACKSPACE, 0},
{SDLK_TAB, GF_KEY_TAB, 0},
{SDLK_CLEAR, GF_KEY_CLEAR, 0},
{SDLK_PAUSE, GF_KEY_PAUSE, 0},
{SDLK_ESCAPE, GF_KEY_ESCAPE, 0},
{SDLK_SPACE, GF_KEY_SPACE, 0},
{SDLK_KP_ENTER, GF_KEY_EXT_NUMPAD, 0},
{SDLK_RETURN, GF_KEY_ENTER, 0},
{SDLK_KP_MULTIPLY, GF_KEY_EXT_NUMPAD, 0},
{SDLK_ASTERISK, GF_KEY_STAR, 0},
{SDLK_KP_PLUS, GF_KEY_EXT_NUMPAD, 0},
{SDLK_PLUS, GF_KEY_PLUS, 0},
{SDLK_KP_MINUS, GF_KEY_EXT_NUMPAD, 0},
{SDLK_MINUS, GF_KEY_HYPHEN, 0},
{SDLK_KP_DIVIDE, GF_KEY_EXT_NUMPAD, 0},
{SDLK_SLASH, GF_KEY_SLASH, 0},
{SDLK_KP_0, GF_KEY_0, GF_KEY_EXT_NUMPAD},
{SDLK_0, GF_KEY_0, 0},
{SDLK_KP_1, GF_KEY_1, GF_KEY_EXT_NUMPAD},
{SDLK_1, GF_KEY_1, 0},
{SDLK_KP_2, GF_KEY_2, GF_KEY_EXT_NUMPAD},
{SDLK_2, GF_KEY_2, 0},
{SDLK_KP_3, GF_KEY_3, GF_KEY_EXT_NUMPAD},
{SDLK_3, GF_KEY_3, 0},
{SDLK_KP_4, GF_KEY_4, GF_KEY_EXT_NUMPAD},
{SDLK_4, GF_KEY_4, 0},
{SDLK_KP_5, GF_KEY_5, GF_KEY_EXT_NUMPAD},
{SDLK_5, GF_KEY_5, 0},
{SDLK_KP_6, GF_KEY_6, GF_KEY_EXT_NUMPAD},
{SDLK_6, GF_KEY_6, 0},
{SDLK_KP_7, GF_KEY_7, GF_KEY_EXT_NUMPAD},
{SDLK_7, GF_KEY_7, 0},
{SDLK_KP_8, GF_KEY_8, GF_KEY_EXT_NUMPAD},
{SDLK_8, GF_KEY_8, 0},
{SDLK_KP_9, GF_KEY_9, GF_KEY_EXT_NUMPAD},
{SDLK_9, GF_KEY_9, 0},
{SDLK_KP_PERIOD, GF_KEY_FULLSTOP, GF_KEY_EXT_NUMPAD},
{SDLK_PERIOD, GF_KEY_FULLSTOP, 0},
{SDLK_KP_EQUALS, GF_KEY_EQUALS, GF_KEY_EXT_NUMPAD},
{SDLK_EQUALS, GF_KEY_EQUALS, 0},
{SDLK_EXCLAIM, GF_KEY_EXCLAMATION, 0},
{SDLK_QUOTEDBL, GF_KEY_QUOTATION, 0},
{SDLK_HASH, GF_KEY_NUMBER, 0},
{SDLK_DOLLAR, GF_KEY_DOLLAR, 0},
{SDLK_AMPERSAND, GF_KEY_AMPERSAND, 0},
{SDLK_QUOTE, GF_KEY_APOSTROPHE, 0},
{SDLK_LEFTPAREN, GF_KEY_LEFTPARENTHESIS, 0},
{SDLK_RIGHTPAREN, GF_KEY_RIGHTPARENTHESIS, 0},
{SDLK_COMMA, GF_KEY_COMMA, 0},
{SDLK_COLON, GF_KEY_COLON, 0},
{SDLK_SEMICOLON, GF_KEY_SEMICOLON, 0},
{SDLK_LESS, GF_KEY_LESSTHAN, 0},
{SDLK_GREATER, GF_KEY_GREATERTHAN, 0},
{SDLK_QUESTION, GF_KEY_QUESTION, 0},
{SDLK_AT, GF_KEY_AT, 0},
{SDLK_LEFTBRACKET, GF_KEY_LEFTSQUAREBRACKET, 0},
{SDLK_RIGHTBRACKET, GF_KEY_RIGHTSQUAREBRACKET, 0},
{SDLK_BACKSLASH, GF_KEY_BACKSLASH, 0},
{SDLK_UNDERSCORE, GF_KEY_UNDERSCORE, 0},
{SDLK_BACKQUOTE, GF_KEY_GRAVEACCENT, 0},
{SDLK_DELETE, GF_KEY_DEL, 0},
{SDLK_UNDO, GF_KEY_UNDO, 0},
{SDLK_UP, GF_KEY_UP, 0},
{SDLK_DOWN, GF_KEY_DOWN, 0},
{SDLK_RIGHT, GF_KEY_RIGHT, 0},
{SDLK_LEFT, GF_KEY_LEFT, 0},
{SDLK_INSERT, GF_KEY_INSERT, 0},
{SDLK_HOME, GF_KEY_HOME, 0},
{SDLK_END, GF_KEY_END, 0},
{SDLK_PAGEUP, GF_KEY_PAGEUP, 0},
{SDLK_PAGEDOWN, GF_KEY_PAGEDOWN, 0},
{SDLK_F1, GF_KEY_F1, 0},
{SDLK_F2, GF_KEY_F2, 0},
{SDLK_F3, GF_KEY_F3, 0},
{SDLK_F4, GF_KEY_F4, 0},
{SDLK_F5, GF_KEY_F5, 0},
{SDLK_F6, GF_KEY_F6, 0},
{SDLK_F7, GF_KEY_F7, 0},
{SDLK_F8, GF_KEY_F8, 0},
{SDLK_F9, GF_KEY_F9, 0},
{SDLK_F10, GF_KEY_F10, 0},
{SDLK_F11, GF_KEY_F11, 0},
{SDLK_F12, GF_KEY_F12, 0},
{SDLK_F13, GF_KEY_F13, 0},
{SDLK_F14, GF_KEY_F14, 0},
{SDLK_F15, GF_KEY_F15, 0},
{SDLK_NUMLOCKCLEAR, GF_KEY_NUMLOCK, 0},
{SDLK_CAPSLOCK, GF_KEY_CAPSLOCK, 0},
{SDLK_SCROLLLOCK, GF_KEY_SCROLL, 0},
{SDLK_RSHIFT, GF_KEY_SHIFT, GF_KEY_EXT_RIGHT},
{SDLK_LSHIFT, GF_KEY_SHIFT, GF_KEY_EXT_LEFT},
{SDLK_LCTRL, GF_KEY_CONTROL, GF_KEY_EXT_LEFT},
{SDLK_RCTRL, GF_KEY_CONTROL, GF_KEY_EXT_RIGHT},
{SDLK_LALT, GF_KEY_ALT, GF_KEY_EXT_LEFT},
{SDLK_RALT, GF_KEY_ALT, GF_KEY_EXT_RIGHT},
#if (SDL_MAJOR_VERSION<=1) && (SDL_MINOR_VERSION<3)
{SDLK_LMETA, GF_KEY_META, GF_KEY_EXT_LEFT},
{SDLK_LSUPER, GF_KEY_META, GF_KEY_EXT_LEFT},
#else
{SDLK_LGUI, GF_KEY_META, GF_KEY_EXT_LEFT},
#endif
#if (SDL_MAJOR_VERSION<=1) && (SDL_MINOR_VERSION<3)
{SDLK_RMETA, GF_KEY_META, GF_KEY_EXT_RIGHT},
{SDLK_RSUPER, GF_KEY_META, GF_KEY_EXT_RIGHT},
#else
{SDLK_RGUI, GF_KEY_META, GF_KEY_EXT_RIGHT},
#endif
{SDLK_MODE, GF_KEY_MODECHANGE, 0},
{SDLK_APPLICATION, GF_KEY_COMPOSE, 0},
{SDLK_HELP, GF_KEY_HELP, 0},
{SDLK_PRINTSCREEN, GF_KEY_PRINTSCREEN, 0}
};
static u32 num_sdl_keys = sizeof(SDLKeys) / sizeof(SDLKeyToGPAC);
static void sdl_translate_key(u32 SDLkey, GF_EventKey *evt)
{
u32 i;
evt->flags = 0;
evt->hw_code = SDLkey;
for (i=0; i<num_sdl_keys; i++) {
if (SDLKeys[i].sdl_key == SDLkey) {
evt->key_code = SDLKeys[i].gf_key;
evt->flags = SDLKeys[i].gf_flags;
return;
}
}
if ((SDLkey>=0x30) && (SDLkey<=0x39))
evt->key_code = GF_KEY_0 + SDLkey-0x30;
else if ((SDLkey>=0x41) && (SDLkey<=0x5A))
evt->key_code = GF_KEY_A + SDLkey-0x41;
else if ((SDLkey>=0x61) && (SDLkey<=0x7A))
evt->key_code = GF_KEY_A + SDLkey-0x61;
else {
GF_LOG(GF_LOG_WARNING, GF_LOG_MMIO, ("[SDL] Unrecognized key %X\n", SDLkey));
evt->key_code = GF_KEY_UNIDENTIFIED;
}
}
#if 0
void SDLVid_SetHack(void *os_handle, Bool set_on)
{
char buf[50];
if (set_on && os_handle) {
sprintf(buf, "SDL_WINDOWID=%u", (u32) os_handle);
} else {
gf_strcpy(buf, "SDL_WINDOWID=");
}
#ifdef WIN32
putenv(buf);
#else
if (set_on) unsetenv("SDL_WINDOWID=");
else putenv(buf);
#endif
}
#endif
static void SDLVid_DestroyObjects(SDLVidCtx *ctx)
{
#if SDL_VERSION_ATLEAST(2,0,0)
if (ctx->pool_rgb) SDL_DestroyTexture(ctx->pool_rgb);
ctx->pool_rgb = NULL;
if (ctx->pool_rgba) SDL_DestroyTexture(ctx->pool_rgba);
ctx->pool_rgba = NULL;
if (ctx->pool_yuv) SDL_DestroyTexture(ctx->pool_yuv);
ctx->pool_yuv = NULL;
if (ctx->tx_back_buffer) SDL_DestroyTexture(ctx->tx_back_buffer);
ctx->tx_back_buffer = NULL;
if (ctx->back_buffer_pixels) gf_free(ctx->back_buffer_pixels);
ctx->back_buffer_pixels = NULL;
#else
if (ctx->back_buffer) SDL_FreeSurface(ctx->back_buffer);
ctx->back_buffer = NULL;
if (ctx->pool_rgb) SDL_FreeSurface(ctx->pool_rgb);
ctx->pool_rgb = NULL;
if (ctx->pool_rgba) SDL_FreeSurface(ctx->pool_rgba);
ctx->pool_rgba = NULL;
SDL_FreeYUVOverlay(ctx->yuv_overlay);
ctx->yuv_overlay=NULL;
#endif
}
#if SDL_VERSION_ATLEAST(2,0,0)
#ifdef GPAC_CONFIG_IOS
#define SDL_WINDOW_FLAGS SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE
#define SDL_FULLSCREEN_FLAGS SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE
#define SDL_GL_WINDOW_FLAGS SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE
#define SDL_GL_FULLSCREEN_FLAGS SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE
#else
#define SDL_WINDOW_FLAGS SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE
#define SDL_FULLSCREEN_FLAGS SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN
#define SDL_GL_WINDOW_FLAGS SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE
#define SDL_GL_FULLSCREEN_FLAGS SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN
#endif
#else
#ifdef GPAC_CONFIG_IOS
#define SDL_WINDOW_FLAGS SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL | SDL_RESIZABLE | SDL_NOFRAME
#define SDL_FULLSCREEN_FLAGS SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL | SDL_FULLSCREEN | SDL_NOFRAME
#define SDL_GL_WINDOW_FLAGS SDL_HWSURFACE | SDL_OPENGL | SDL_HWACCEL | SDL_RESIZABLE | SDL_NOFRAME
#define SDL_GL_FULLSCREEN_FLAGS SDL_HWSURFACE | SDL_OPENGL | SDL_HWACCEL | SDL_FULLSCREEN | SDL_NOFRAME
#else
#define SDL_WINDOW_FLAGS SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL | SDL_RESIZABLE
#define SDL_FULLSCREEN_FLAGS SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL | SDL_FULLSCREEN
#define SDL_GL_WINDOW_FLAGS SDL_HWSURFACE | SDL_OPENGL | SDL_HWACCEL | SDL_RESIZABLE
#define SDL_GL_FULLSCREEN_FLAGS SDL_HWSURFACE | SDL_OPENGL | SDL_HWACCEL | SDL_FULLSCREEN
#endif
#endif
#include <gpac/media_tools.h>
void SDLVid_SetIcon(SDLVidCtx *ctx)
{
#if SDL_VERSION_ATLEAST(2,0,0) && !defined(GPAC_CONFIG_IOS) && !defined(GPAC_DISABLE_AV_PARSERS)
u8 *buffer, *dec_buf;
u32 size, w, h, pf, Bpp, dst_size=0;
char cfg[GF_MAX_PATH];
if (!gf_opts_default_shared_directory((char *) cfg))
return;
gf_strcat(cfg, "/res/gpac.png");
if (gf_file_load_data(cfg, &buffer, &size) != GF_OK) {
GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDLOut] failed to load icon file %s\n", cfg ));
return;
}
gf_img_png_dec(buffer, size, &w, &h, &pf, NULL, &dst_size);
Bpp = gf_pixel_get_bytes_per_pixel(pf);
dec_buf = gf_malloc(sizeof(char)*dst_size);
gf_img_png_dec(buffer, size, &w, &h, &pf, dec_buf, &dst_size);
//RGBA only
SDL_Surface *surface = SDL_CreateRGBSurfaceFrom(dec_buf, w, h, Bpp*8, w*Bpp, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
if (!surface) {
GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDLOut] failed to create surface from icon: %s\n", SDL_GetError() ));
} else {
SDL_SetWindowIcon(ctx->screen, surface);
SDL_FreeSurface(surface);
}
gf_free(buffer);
gf_free(dec_buf);
#endif
}
GF_Err SDLVid_ResizeWindow(GF_VideoOutput *dr, u32 width, u32 height)
{
Bool hw_reset;
SDLVID();
GF_Event evt;
if (!width || !height) return GF_BAD_PARAM;
/*lock X mutex to make sure the event queue is not being processed*/
gf_mx_p(ctx->evt_mx);
GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[SDL] Resizing window %dx%d\n", width, height));
if (ctx->output_3d) {
u32 flags, nb_bits;
const char *opt;
if (ctx->screen && (ctx->width==width) && (ctx->height==height) ) {
gf_mx_v(ctx->evt_mx);
return GF_OK;
}
#if SDL_VERSION_ATLEAST(2,0,0)
flags = SDL_GL_WINDOW_FLAGS;
if (ctx->os_handle) flags &= ~SDL_WINDOW_RESIZABLE;
if (ctx->fullscreen) flags |= SDL_FULLSCREEN_FLAGS;
#ifdef GPAC_CONFIG_IOS
flags |= SDL_FULLSCREEN_FLAGS | SDL_WINDOW_ALLOW_HIGHDPI;
#endif
#else
flags = SDL_GL_WINDOW_FLAGS;
if (ctx->os_handle) flags &= ~SDL_RESIZABLE;
if (ctx->fullscreen) flags |= SDL_FULLSCREEN_FLAGS;
if (!ctx->screen) ctx->screen = SDL_SetVideoMode(width, height, 0, flags);
#endif
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
opt = gf_opts_get_key("core", "gl-bits-depth");
nb_bits = opt ? atoi(opt) : 16;
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, nb_bits);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0);
opt = gf_opts_get_key("core", "gl-bits-comp");
nb_bits = opt ? atoi(opt) : 8;
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, nb_bits);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, nb_bits);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, nb_bits);
#if SDL_VERSION_ATLEAST(2,0,0)
if (ctx->hidden)
flags |= SDL_WINDOW_HIDDEN;
hw_reset = GF_FALSE;
#ifdef GPAC_USE_GLES2
/* Set the correct attributes for MASK and MAJOR version */
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
#ifdef GPAC_CONFIG_EMSCRIPTEN
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
#endif
#endif
if (!ctx->screen) {
if (!(ctx->screen = SDL_CreateWindow("", 0, 0, width, height, flags))) {
GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Cannot create window: %s\n", SDL_GetError()));
gf_mx_v(ctx->evt_mx);
return GF_IO_ERR;
}
GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[SDL] Window created\n"));
dr->window_id = SDL_GetWindowID(ctx->screen);
SDLVid_SetIcon(ctx);
/*creating a window, at least on OSX, changes the locale and screws up float parsing !!
force setting the local back and pray that it will be changed before any other atof/strtod is called
!! it also looks like the locale is not enforced synchronously on OSX: adding
assert(strtod(0.5)) in gf_malloc proto would lead to random crashes
*/
#ifndef _WIN32_WCE
setlocale( LC_NUMERIC, "C" );
#endif
}
if ( !ctx->gl_context ) {
//in case we created a headless context before loading vout, create a shared context
SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
if (!(ctx->gl_context = SDL_GL_CreateContext(ctx->screen))) {
GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Cannot initialize gl context: %s\n", SDL_GetError()));
gf_mx_v(ctx->evt_mx);
return GF_IO_ERR;
}
if (SDL_GL_MakeCurrent(ctx->screen, ctx->gl_context)) {
GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Cannot make context current: %s\n", SDL_GetError()));
gf_mx_v(ctx->evt_mx);
return GF_IO_ERR;
}
hw_reset = GF_TRUE;
}
if (flags & SDL_WINDOW_ALLOW_HIGHDPI) {
int w, h;
SDL_GL_GetDrawableSize(ctx->screen, &w, &h);
#if SDL_VERSION_ATLEAST(2,0,9)
int _h;
switch (SDL_GetDisplayOrientation(0)) {
case SDL_ORIENTATION_LANDSCAPE:
case SDL_ORIENTATION_LANDSCAPE_FLIPPED:
break;
default:
_h = h;
h = w;
w = _h;
break;
}
#endif
if ((u32) w > dr->max_screen_width) dr->max_screen_width = w;
if ((u32) h > dr->max_screen_height) dr->max_screen_height = h;
}
if (!ctx->disable_vsync)
ctx->disable_vsync = !gf_module_get_bool((GF_BaseInterface *)dr, "vsync");
if (ctx->disable_vsync) {
#if defined(__APPLE__) && !defined(GPAC_CONFIG_IOS)
#else
SDL_GL_SetSwapInterval(0);
#endif
}
SDL_SetWindowSize(ctx->screen, width, height);
#else
hw_reset = GF_TRUE;
ctx->screen = SDL_SetVideoMode(width, height, 0, flags);
if (!ctx->screen) {
GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Cannot create window: %s\n", SDL_GetError()));
gf_mx_v(ctx->evt_mx);
return GF_IO_ERR;
}
#endif
ctx->width = width;
ctx->height = height;
memset(&evt, 0, sizeof(GF_Event));
evt.type = GF_EVENT_VIDEO_SETUP;
evt.setup.hw_reset = hw_reset;
dr->on_event(dr->evt_cbk_hdl, &evt);
GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[SDL] 3D Setup done\n"));
} else {
u32 flags;
#ifdef GPAC_CONFIG_IOS
flags = SDL_FULLSCREEN_FLAGS;
//SDL readme says it would make us faster
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
#else
flags = SDL_WINDOW_FLAGS | SDL_WINDOW_RESIZABLE;
if (ctx->os_handle) flags &= ~SDL_WINDOW_RESIZABLE;
#endif
#if SDL_VERSION_ATLEAST(2,0,0)
#ifdef GPAC_CONFIG_IOS
//still some issues with render to tager and landscape orientation, we need to reset everything ...
if (ctx->enable_defer_mode) {
if (ctx->renderer) SDL_DestroyRenderer(ctx->renderer);
ctx->renderer=NULL;
if (ctx->screen) SDL_DestroyWindow(ctx->screen);
ctx->screen=NULL;
}
#endif
#if SDL_VERSION_ATLEAST(2,0,0)
if (ctx->hidden)
flags |= SDL_WINDOW_HIDDEN;
#endif
if (!ctx->screen) {
ctx->screen = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags);
if (!ctx->screen) {
GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Cannot create window: %s\n", SDL_GetError()));
gf_mx_v(ctx->evt_mx);
return GF_IO_ERR;
}
dr->window_id = SDL_GetWindowID(ctx->screen);
SDLVid_SetIcon(ctx);
/*see above note*/
#ifndef _WIN32_WCE
setlocale( LC_NUMERIC, "C" );
#endif
GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[SDL] Window created\n"));
SDL_RaiseWindow(ctx->screen);
}
if ( !ctx->renderer ) {
u32 flags = SDL_RENDERER_ACCELERATED;
if (gf_module_get_bool((GF_BaseInterface *)dr, "vsync")) {
flags |= SDL_RENDERER_PRESENTVSYNC;
}
if (!(ctx->renderer = SDL_CreateRenderer(ctx->screen, -1, flags))) {
GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Cannot create renderer: %s\n", SDL_GetError()));
gf_mx_v(ctx->evt_mx);
return GF_IO_ERR;
}
}
#ifndef GPAC_CONFIG_IOS
SDL_SetWindowSize(ctx->screen, width, height);
#endif
SDL_SetRenderDrawColor(ctx->renderer, 0, 0, 0, 255);
SDL_RenderClear(ctx->renderer);
#else
ctx->screen = SDL_SetVideoMode(width, height, 0, flags);
#endif
GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[SDL] 2D Setup done\n"));
}
gf_mx_v(ctx->evt_mx);
return ctx->screen ? GF_OK : GF_IO_ERR;
}
static void SDLVid_SetCursor(GF_VideoOutput *dr, u32 cursor_type)
{
#ifndef GPAC_CONFIG_IOS
SDLVID();
switch (cursor_type) {
case GF_CURSOR_ANCHOR:
case GF_CURSOR_TOUCH:
case GF_CURSOR_ROTATE:
case GF_CURSOR_PROXIMITY:
case GF_CURSOR_PLANE:
SDL_SetCursor(ctx->curs_hand);
break;
case GF_CURSOR_COLLIDE:
SDL_SetCursor(ctx->curs_collide);
break;
default:
SDL_SetCursor(ctx->curs_def);
break;
}
#endif
}
#include <gpac/list.h>
static GF_List *video_outputs = NULL;
static u32 nb_video_outputs=0;
static Bool SDLVid_InitializeWindow(SDLVidCtx *ctx, GF_VideoOutput *dr)
{
u32 flags;
#if SDL_VERSION_ATLEAST(2,0,0)
SDL_DisplayMode vinf;
#else
#if SDL_VERSION_ATLEAST(1, 2, 10)
const SDL_VideoInfo *vinf;
#endif
#endif
#ifdef WIN32
putenv("directx");
#endif
if (!video_outputs) {
flags = SDL_WasInit(SDL_INIT_VIDEO);
if (!(flags & SDL_INIT_VIDEO)) {
if (SDL_InitSubSystem(SDL_INIT_VIDEO)) {
return GF_FALSE;
}
}
video_outputs = gf_list_new();
}
if (gf_list_find(video_outputs, dr)<0) {
gf_list_add(video_outputs, dr);
nb_video_outputs = gf_list_count(video_outputs);
}
ctx->curs_def = SDL_GetCursor();
ctx->curs_hand = SDLVid_LoadCursor(hand_data);
ctx->curs_collide = SDLVid_LoadCursor(collide_data);
#if SDL_VERSION_ATLEAST(2,0,0)
#else
SDL_EnableUNICODE(1);
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
#endif
ctx->last_mouse_move = SDL_GetTicks();
ctx->cursor_on = GF_TRUE;
/*save display resolution - SDL seems to get the screen resolution if asked for video info before
changing the video mode - to check on other platforms*/
#if SDL_VERSION_ATLEAST(2,0,0)
SDL_GetDesktopDisplayMode(0,&vinf);
dr->max_screen_width = vinf.w;
dr->max_screen_height = vinf.h;
dr->max_screen_bpp = 8;
#else
#if SDL_VERSION_ATLEAST(1, 2, 10)
vinf = SDL_GetVideoInfo();
if (vinf) {
dr->max_screen_width = vinf->current_w;
dr->max_screen_height = vinf->current_h;
}
dr->max_screen_bpp = 8;
#else
{
SDL_Rect** modes;
modes = SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE);
if ( modes == (SDL_Rect**)-1 ) {
fprintf(stderr, "SDL : DONT KNOW WHICH MODE TO USE, using 640x480\n");
dr->max_screen_width = 640;
dr->max_screen_height = 480;
} else if (modes) {
int i;
dr->max_screen_width = 0;
for (i=0; modes[i]; ++i) {
int w = modes[i]->w;
if (w > dr->max_screen_width) {
dr->max_screen_width = w;
dr->max_screen_height = modes[i]->h;
}
}
}
}
dr->max_screen_bpp = 8;
#endif /* versions prior to 1.2.10 do not have the size of screen */
#endif
if (!ctx->os_handle)
#if SDL_VERSION_ATLEAST(2,0,0)
SDLVid_SetCaption(ctx->screen);
#else
SDLVid_SetCaption();
#endif
GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[SDL] Video output initialized - screen resolution %d %d\n", dr->max_screen_width, dr->max_screen_height));
return GF_TRUE;
}
static void SDLVid_ResetWindow(SDLVidCtx *ctx)
{
SDLVid_DestroyObjects(ctx);
#if SDL_VERSION_ATLEAST(2,0,0)
if ( ctx->gl_context ) {
SDL_GL_DeleteContext(ctx->gl_context);
ctx->gl_context = NULL;
}
if ( ctx->renderer ) {
SDL_DestroyRenderer(ctx->renderer);
ctx->renderer = NULL;
}
/*iOS SDL2 has a nasty bug that breaks switching between 2D and GL context if we don't re-init the video subsystem*/
#ifdef GPAC_CONFIG_IOS
if ( ctx->screen ) {
SDL_DestroyWindow(ctx->screen);
ctx->screen=NULL;
}
SDL_QuitSubSystem(SDL_INIT_VIDEO);
SDL_InitSubSystem(SDL_INIT_VIDEO);
#endif
#endif
}
static void SDLVid_ShutdownWindow(SDLVidCtx *ctx)
{
SDLVid_DestroyObjects(ctx);
SDLVid_ResetWindow(ctx);
#if SDL_VERSION_ATLEAST(2,0,0)
if (ctx->screen) SDL_DestroyWindow(ctx->screen);
ctx->screen = NULL;
#endif
}
#if defined SDL_TEXTINPUTEVENT_TEXT_SIZE /*&& !defined GPAC_CONFIG_IOS*/
#include <gpac/utf.h>
#endif
Bool SDLVid_ProcessMessageQueue(SDLVidCtx *ctx, GF_VideoOutput *dr)
{
SDL_Event sdl_evt;
GF_Event gpac_evt;
#ifdef GPAC_CONFIG_IOS
while (SDL_WaitEventTimeout(&sdl_evt, 1)) {
#else
while (1) {
if (nb_video_outputs>1) {
u32 win_id=0;
if (!SDL_PollEvent(NULL)) return GF_TRUE;
SDL_PeepEvents(&sdl_evt, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
switch (sdl_evt.type) {
case SDL_WINDOWEVENT: win_id = sdl_evt.window.windowID; break;
#ifdef SDL_TEXTINPUTEVENT_TEXT_SIZE
case SDL_TEXTINPUT: /* Since SDL 1.3, text-input is handled in a specific event */
win_id = sdl_evt.text.windowID; break;
#endif
case SDL_KEYDOWN:
case SDL_KEYUP:
win_id = sdl_evt.key.windowID; break;
case SDL_MOUSEMOTION:
win_id = sdl_evt.motion.windowID; break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
win_id = sdl_evt.button.windowID; break;
case SDL_MOUSEWHEEL:
win_id = sdl_evt.wheel.windowID; break;
#if SDL_VERSION_ATLEAST(2,0,5)
case SDL_DROPFILE:
win_id = sdl_evt.drop.windowID; break;
#endif
}
//we may get events from destroyed windows still in the queue, flush them
if (win_id!=dr->window_id) {
Bool found=GF_FALSE;
u32 i;
for (i=0; i<nb_video_outputs; i++) {
GF_VideoOutput *dr2 = gf_list_get(video_outputs, i);
if (win_id==dr2->window_id) {
found=GF_TRUE;
break;
}
}
if (found) return GF_TRUE;
else if (win_id) {
fprintf(stderr, "Purging event from window id %d\n", win_id);
}
}
}
if (!SDL_PollEvent(&sdl_evt)) return GF_TRUE;
#endif
switch (sdl_evt.type) {
#if SDL_VERSION_ATLEAST(2,0,0)
case SDL_WINDOWEVENT:
switch (sdl_evt.window.event) {
case SDL_WINDOWEVENT_SIZE_CHANGED:
gpac_evt.type = GF_EVENT_SIZE;
#if SDL_VERSION_ATLEAST(2,0,10) && GPAC_CONFIG_IOS
{
int w, h;
SDL_GL_GetDrawableSize(ctx->screen, &w, &h);
gpac_evt.size.width = w;
gpac_evt.size.height = h;
ctx->high_dpi_w = w;
ctx->low_dpi_w = sdl_evt.window.data1;
ctx->high_dpi_h = h;
ctx->low_dpi_h = sdl_evt.window.data2;
}
#else
gpac_evt.size.width = sdl_evt.window.data1;
gpac_evt.size.height = sdl_evt.window.data2;
gpac_evt.size.window_id = dr->window_id;
#endif
#if SDL_VERSION_ATLEAST(2,0,9)
switch (SDL_GetDisplayOrientation(0)) {
case SDL_ORIENTATION_UNKNOWN: gpac_evt.size.orientation = GF_DISPLAY_MODE_UNKNOWN; break;
case SDL_ORIENTATION_LANDSCAPE: gpac_evt.size.orientation = GF_DISPLAY_MODE_LANDSCAPE; break;
case SDL_ORIENTATION_LANDSCAPE_FLIPPED: gpac_evt.size.orientation = GF_DISPLAY_MODE_LANDSCAPE_INV; break;
case SDL_ORIENTATION_PORTRAIT: gpac_evt.size.orientation = GF_DISPLAY_MODE_PORTRAIT; break;
case SDL_ORIENTATION_PORTRAIT_FLIPPED: gpac_evt.size.orientation = GF_DISPLAY_MODE_PORTRAIT_INV; break;
}
#endif
dr->on_event(dr->evt_cbk_hdl, &gpac_evt);
break;
case SDL_WINDOWEVENT_EXPOSED:
case SDL_WINDOWEVENT_SHOWN:
gpac_evt.type = GF_EVENT_REFRESH;
gpac_evt.show.window_id = dr->window_id;
dr->on_event(dr->evt_cbk_hdl, &gpac_evt);
break;
case SDL_WINDOWEVENT_MOVED:
gpac_evt.type = GF_EVENT_MOVE;
gpac_evt.move.x = sdl_evt.window.data1;
gpac_evt.move.y = sdl_evt.window.data2;
gpac_evt.move.window_id = dr->window_id;
dr->on_event(dr->evt_cbk_hdl, &gpac_evt);
break;
case SDL_WINDOWEVENT_CLOSE:
memset(&gpac_evt, 0, sizeof(GF_Event));
gpac_evt.type = GF_EVENT_QUIT;
gpac_evt.show.window_id = dr->window_id;
dr->on_event(dr->evt_cbk_hdl, &gpac_evt);
return GF_FALSE;
case SDL_WINDOWEVENT_MINIMIZED:
memset(&gpac_evt, 0, sizeof(GF_Event));
gpac_evt.type = GF_EVENT_SHOWHIDE;
gpac_evt.show.show_type = 0;
gpac_evt.show.window_id = dr->window_id;
dr->on_event(dr->evt_cbk_hdl, &gpac_evt);
return GF_FALSE;
}
break;
#else
case SDL_VIDEORESIZE:
gpac_evt.type = GF_EVENT_SIZE;
gpac_evt.size.width = sdl_evt.resize.w;
gpac_evt.size.height = sdl_evt.resize.h;
dr->on_event(dr->evt_cbk_hdl, &gpac_evt);
break;
case SDL_VIDEOEXPOSE:
gpac_evt.type = GF_EVENT_REFRESH;
dr->on_event(dr->evt_cbk_hdl, &gpac_evt);
break;
#endif
case SDL_QUIT:
memset(&gpac_evt, 0, sizeof(GF_Event));
gpac_evt.type = GF_EVENT_QUIT;
gpac_evt.show.window_id = 0;
dr->on_event(dr->evt_cbk_hdl, &gpac_evt);
return GF_FALSE;
#ifdef SDL_TEXTINPUTEVENT_TEXT_SIZE
/*keyboard*/
case SDL_TEXTINPUT: /* Since SDL 1.3, text-input is handled in a specific event */
{
u32 len = (u32) strlen( sdl_evt.text.text);
if (len < 5 ) {
gpac_evt.character.window_id = dr->window_id;
u32 ucs4_len = utf8_to_ucs4 (&(gpac_evt.character.unicode_char), len, (unsigned char*)(sdl_evt.text.text));
if (ucs4_len) {
gpac_evt.type = GF_EVENT_TEXTINPUT;
dr->on_event(dr->evt_cbk_hdl, &gpac_evt);
}
}
break;
}
#endif /* SDL_TEXTINPUTEVENT_TEXT_SIZE */
case SDL_KEYDOWN:
case SDL_KEYUP:
sdl_translate_key(sdl_evt.key.keysym.sym, &gpac_evt.key);
gpac_evt.type = (sdl_evt.key.type==SDL_KEYDOWN) ? GF_EVENT_KEYDOWN : GF_EVENT_KEYUP;
gpac_evt.key.window_id = dr->window_id;
dr->on_event(dr->evt_cbk_hdl, &gpac_evt);
if (gpac_evt.key.key_code==GF_KEY_CONTROL) ctx->ctrl_down = (sdl_evt.key.type==SDL_KEYDOWN) ? GF_TRUE : GF_FALSE;
else if (gpac_evt.key.key_code==GF_KEY_ALT) ctx->alt_down = (sdl_evt.key.type==SDL_KEYDOWN) ? GF_TRUE : GF_FALSE;
else if (gpac_evt.key.key_code==GF_KEY_META) ctx->meta_down = (sdl_evt.key.type==SDL_KEYDOWN) ? GF_TRUE : GF_FALSE;
#ifdef SDL_TEXTINPUTEVENT_TEXT_SIZE
if (sdl_evt.type==SDL_KEYDOWN) {
if ((gpac_evt.key.key_code==GF_KEY_ENTER) || (gpac_evt.key.key_code==GF_KEY_BACKSPACE)) {
gpac_evt.type = GF_EVENT_TEXTINPUT;
gpac_evt.character.unicode_char = (gpac_evt.key.key_code==GF_KEY_ENTER) ? '\r' : '\b';
gpac_evt.character.window_id = dr->window_id;
dr->on_event(dr->evt_cbk_hdl, &gpac_evt);
}
}
#endif
#if SDL_VERSION_ATLEAST(2,0,0)
if ((gpac_evt.type==GF_EVENT_KEYUP) && (gpac_evt.key.key_code==GF_KEY_V)
#if defined(__DARWIN__) || defined(__APPLE__)
&& ctx->meta_down
#else
&& ctx->ctrl_down
#endif
) {
gpac_evt.type = GF_EVENT_PASTE_TEXT;
gpac_evt.clipboard.text = (char *) SDL_GetClipboardText();
gpac_evt.clipboard.window_id = dr->window_id;
dr->on_event(dr->evt_cbk_hdl, &gpac_evt);
SDL_free(gpac_evt.clipboard.text);
}
else if ((gpac_evt.type==GF_EVENT_KEYUP) && (gpac_evt.key.key_code==GF_KEY_C)
#if defined(__DARWIN__) || defined(__APPLE__)
&& ctx->meta_down
#else
&& ctx->ctrl_down
#endif
) {
gpac_evt.type = GF_EVENT_COPY_TEXT;
if (dr->on_event(dr->evt_cbk_hdl, &gpac_evt) && gpac_evt.clipboard.text) {
SDL_SetClipboardText(gpac_evt.clipboard.text );
gf_free(gpac_evt.clipboard.text);
}
}
#endif
#ifndef SDL_TEXTINPUTEVENT_TEXT_SIZE
if ((sdl_evt.key.type==SDL_KEYDOWN)
&& sdl_evt.key.keysym.unicode
&& ((sdl_evt.key.keysym.unicode=='\r') || (sdl_evt.key.keysym.unicode=='\n') || (sdl_evt.key.keysym.unicode=='\b') || (sdl_evt.key.keysym.unicode=='\t') )
) {
gpac_evt.character.unicode_char = sdl_evt.key.keysym.unicode;
gpac_evt.character.window_id = dr->window_id;
gpac_evt.type = GF_EVENT_TEXTINPUT;
dr->on_event(dr->evt_cbk_hdl, &gpac_evt);
}
#else
#endif
break;
/* rescale mouse event (not multitouch) to highDPI coords - not yet supported in SDL, see https://github.com/libsdl-org/SDL/issues/2999*/
/*mouse*/
case SDL_MOUSEMOTION:
ctx->last_mouse_move = SDL_GetTicks();
gpac_evt.type = GF_EVENT_MOUSEMOVE;
gpac_evt.mouse.window_id = dr->window_id;
#if SDL_VERSION_ATLEAST(2,0,0)
if (ctx->low_dpi_w && ctx->low_dpi_h) {
gpac_evt.mouse.x = (u32) ( (u64) sdl_evt.motion.x * ctx->high_dpi_w / ctx->low_dpi_w);
gpac_evt.mouse.y = (u32) ( (u64) sdl_evt.motion.y * ctx->high_dpi_h / ctx->low_dpi_h);
} else
#endif
{
gpac_evt.mouse.x = sdl_evt.motion.x;
gpac_evt.mouse.y = sdl_evt.motion.y;
}
dr->on_event(dr->evt_cbk_hdl, &gpac_evt);
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
ctx->last_mouse_move = SDL_GetTicks();
#if SDL_VERSION_ATLEAST(2,0,0)
if (ctx->low_dpi_w && ctx->low_dpi_h) {
gpac_evt.mouse.x = (u32) ( (u64) sdl_evt.motion.x * ctx->high_dpi_w / ctx->low_dpi_w);
gpac_evt.mouse.y = (u32) ( (u64) sdl_evt.motion.y * ctx->high_dpi_h / ctx->low_dpi_h);
} else
#endif
{
gpac_evt.mouse.x = sdl_evt.motion.x;
gpac_evt.mouse.y = sdl_evt.motion.y;
}
gpac_evt.type = (sdl_evt.type==SDL_MOUSEBUTTONUP) ? GF_EVENT_MOUSEUP : GF_EVENT_MOUSEDOWN;
gpac_evt.mouse.window_id = dr->window_id;
switch (sdl_evt.button.button) {
case SDL_BUTTON_LEFT:
gpac_evt.mouse.button = GF_MOUSE_LEFT;
dr->on_event(dr->evt_cbk_hdl, &gpac_evt);
break;
case SDL_BUTTON_MIDDLE:
gpac_evt.mouse.button = GF_MOUSE_MIDDLE;
dr->on_event(dr->evt_cbk_hdl, &gpac_evt);
break;
case SDL_BUTTON_RIGHT:
gpac_evt.mouse.button = GF_MOUSE_RIGHT;
dr->on_event(dr->evt_cbk_hdl, &gpac_evt);
break;
#ifdef SDL_BUTTON_WHEELUP
case SDL_BUTTON_WHEELUP:
case SDL_BUTTON_WHEELDOWN:
/*SDL handling is not perfect there, it just says up/down but no info on how much
the wheel was rotated...*/
gpac_evt.mouse.wheel_pos = (sdl_evt.button.button==SDL_BUTTON_WHEELUP) ? FIX_ONE : -FIX_ONE;
gpac_evt.type = GF_EVENT_MOUSEWHEEL;
dr->on_event(dr->evt_cbk_hdl, &gpac_evt);
break;
#endif
}
break;
#if SDL_VERSION_ATLEAST(2,0,0)
case SDL_MOUSEWHEEL:
/*SDL handling is not perfect there, it just says up/down but no info on how much
the wheel was rotated...*/
gpac_evt.mouse.wheel_pos = INT2FIX(sdl_evt.wheel.y);
gpac_evt.type = GF_EVENT_MOUSEWHEEL;
gpac_evt.mouse.window_id = dr->window_id;
dr->on_event(dr->evt_cbk_hdl, &gpac_evt);
break;
case SDL_MULTIGESTURE:
gpac_evt.mtouch.x = FLT2FIX(sdl_evt.mgesture.x);
gpac_evt.mtouch.y = FLT2FIX(sdl_evt.mgesture.y);
gpac_evt.mtouch.num_fingers = sdl_evt.mgesture.numFingers;
gpac_evt.mtouch.rotation = sdl_evt.mgesture.dTheta;
gpac_evt.mtouch.pinch = sdl_evt.mgesture.dDist;
gpac_evt.mtouch.window_id = dr->window_id;
gpac_evt.type = GF_EVENT_MULTITOUCH;
dr->on_event(dr->evt_cbk_hdl, &gpac_evt);
break;
case SDL_DROPFILE:
gpac_evt.type = GF_EVENT_DROPFILE;
gpac_evt.open_file.nb_files = 1;
gpac_evt.open_file.files = &sdl_evt.drop.file;
gpac_evt.open_file.window_id = dr->window_id;
dr->on_event(dr->evt_cbk_hdl, &gpac_evt);
#endif
}
}
return GF_TRUE;
}
#ifdef SDL_WINDOW_THREAD
u32 SDLVid_EventProc(void *par)
{
#if 0
u32 last_mouse_move;
#endif
Bool ret;
GF_VideoOutput *dr = (GF_VideoOutput *)par;
SDLVID();
if (!SDLVid_InitializeWindow(ctx, dr)) {
ctx->sdl_th_state = SDL_STATE_STOP_REQ;
return 1;
}
ctx->sdl_th_state = SDL_STATE_RUNNING;
while (ctx->sdl_th_state==SDL_STATE_RUNNING) {
/*after much testing: we must ensure nothing is using the event queue when resizing window.
-- under X, it throws Xlib "unexpected async reply" under linux, therefore we don't wait events,
we check for events and execute them if any
-- under Win32, the SDL_SetVideoMode deadlocks, so we don't force exclusive access to events
*/
#ifndef WIN32
gf_mx_p(ctx->evt_mx);
#endif
ret = SDLVid_ProcessMessageQueue(ctx, dr);
#ifndef WIN32
gf_mx_v(ctx->evt_mx);
#endif
/*looks like this hides the cursor for ever when switching back from FS*/
#if 0
if (ctx->fullscreen && (last_mouse_move + 2000 < SDL_GetTicks()) ) {
if (cursor_on) SDL_ShowCursor(0);
cursor_on = 0;
} else if (!cursor_on) {
SDL_ShowCursor(1);
cursor_on = 1;
}
#endif
/*QUIT message has been processed*/
if (!ret) {
ctx->sdl_th_state = SDL_STATE_STOP_REQ;
break;
}
gf_sleep(2);
}
while (ctx->sdl_th_state == SDL_STATE_STOP_REQ)
gf_sleep(10);
SDLVid_ShutdownWindow(ctx);
ctx->sdl_th_state = SDL_STATE_STOPPED;
return 0;
}
#endif /*SDL_WINDOW_THREAD*/
GF_Err SDLVid_Setup(struct _video_out *dr, void *os_handle, void *os_display, u32 init_flags)
{
Bool show_window = GF_TRUE;
SDLVID();
/*we don't allow SDL hack, not stable enough*/
//if (os_handle) SDLVid_SetHack(os_handle, 1);
ctx->os_handle = os_handle;
if (!ctx->is_init) {
ctx->output_3d = GF_FALSE;
show_window = GF_TRUE;
}
ctx->force_alpha = (init_flags & GF_VOUT_WINDOW_TRANSPARENT) ? GF_TRUE : GF_FALSE;
ctx->hidden = (init_flags & GF_VOUT_INIT_HIDE) ? GF_TRUE : GF_FALSE;
if (!ctx->hidden && show_window) {
#if SDL_VERSION_ATLEAST(2,0,0)
SDL_ShowWindow(ctx->screen);
#else
#endif
}
if (!SDLOUT_InitSDL())
return GF_IO_ERR;
#ifdef SDL_WINDOW_THREAD
ctx->sdl_th_state = SDL_STATE_STOPPED;
gf_th_run(ctx->sdl_th, SDLVid_EventProc, dr);
while (!ctx->sdl_th_state)
gf_sleep(10);
if (ctx->sdl_th_state==SDL_STATE_STOP_REQ) {
SDLOUT_CloseSDL();
ctx->sdl_th_state = SDL_STATE_STOPPED;
return GF_IO_ERR;
}
#else
if (!SDLVid_InitializeWindow(ctx, dr)) {
if (!gf_list_count(video_outputs)) {
SDL_QuitSubSystem(SDL_INIT_VIDEO);
gf_list_del(video_outputs);
video_outputs=NULL;
}
SDLOUT_CloseSDL();
return GF_IO_ERR;
}
#endif
//coverage
#ifdef GPAC_ENABLE_COVERAGE
if (gf_sys_is_cov_mode()) {
GF_Event evt;
sdl_translate_key(SDLK_BACKSPACE, &evt.key);
SDLVid_SetCursor(dr, GF_CURSOR_NORMAL);
}
#endif
ctx->is_init = GF_TRUE;
return GF_OK;
}
static void SDLVid_Shutdown(GF_VideoOutput *dr)
{
SDLVID();
/*remove all surfaces*/
if (!ctx->is_init) return;
#ifdef SDL_WINDOW_THREAD
if (ctx->sdl_th_state==SDL_STATE_RUNNING) {
SDL_Event evt;
evt.type = SDL_QUIT;
SDL_PushEvent(&evt);
}
/*wait until thread say it is stopped*/
ctx->sdl_th_state = SDL_STATE_WAIT_FOR_THREAD_TERMINATION;
while (ctx->sdl_th_state != SDL_STATE_STOPPED)
gf_sleep(10);
#else
SDLVid_ShutdownWindow(ctx);
#endif
SDLOUT_CloseSDL();
ctx->is_init = GF_FALSE;
dr->window_id = 0;
}
GF_Err SDLVid_SetFullScreen(GF_VideoOutput *dr, Bool bFullScreenOn, u32 *screen_width, u32 *screen_height)
{
int bpp;
u32 pref_bpp;
SDLVID();
#if SDL_VERSION_ATLEAST(2,0,0)
SDL_DisplayMode goodMode;
u32 numDisplayModes;
u32 mask;
#endif
if (ctx->fullscreen==bFullScreenOn) return GF_OK;
/*lock to get sure the event queue is not processed under X*/
gf_mx_p(ctx->evt_mx);
ctx->fullscreen = bFullScreenOn;
#if SDL_VERSION_ATLEAST(2,0,0)
SDL_GetCurrentDisplayMode(0, &goodMode);
SDL_PixelFormatEnumToMasks(goodMode.format, &bpp, &mask, &mask, &mask, &mask);
pref_bpp = bpp;
#else
pref_bpp = bpp = ctx->screen->format->BitsPerPixel;
#endif
if (ctx->fullscreen) {
#if ! ( SDL_VERSION_ATLEAST(2,0,0) )
u32 flags = ctx->output_3d ? SDL_GL_FULLSCREEN_FLAGS : SDL_FULLSCREEN_FLAGS;
#endif
Bool switch_res = gf_module_get_bool((GF_BaseInterface*)dr, "switch-vres");
if (!dr->max_screen_width || !dr->max_screen_height) switch_res = GF_TRUE;
ctx->store_width = *screen_width;
ctx->store_height = *screen_height;
if (switch_res) {
u32 i;
ctx->fs_width = *screen_width;
ctx->fs_height = *screen_height;
#if SDL_VERSION_ATLEAST(2,0,0)
numDisplayModes = SDL_GetNumDisplayModes(0);
for(i=0; i<numDisplayModes; i++) {
SDL_GetDisplayMode(0, i, &goodMode);
if ((ctx->fs_width <= (u32) goodMode.w) && (ctx->fs_height <= (u32) goodMode.h)) {
s32 bppDisp;
ctx->fs_width = goodMode.w;
ctx->fs_height = goodMode.h;
SDL_PixelFormatEnumToMasks(goodMode.format, &bppDisp, &mask, &mask, &mask, &mask);
pref_bpp = bppDisp;
break;
}
}
#else
for(i=0; i<nb_video_modes; i++) {
if (ctx->fs_width<=video_modes[2*i] && ctx->fs_height<=video_modes[2*i + 1]) {
if ((pref_bpp = SDL_VideoModeOK(video_modes[2*i], video_modes[2*i+1], bpp, flags))) {
ctx->fs_width = video_modes[2*i];
ctx->fs_height = video_modes[2*i + 1];
break;
}
}
}
#endif
} else {
#if SDL_VERSION_ATLEAST(2,0,0)
SDL_GetCurrentDisplayMode(0, &goodMode);
#endif
ctx->fs_width = dr->max_screen_width;
ctx->fs_height = dr->max_screen_height;
}
#if SDL_VERSION_ATLEAST(2,0,0)
SDL_SetWindowDisplayMode(ctx->screen, &goodMode);
SDL_SetWindowFullscreen(ctx->screen, SDL_WINDOW_FULLSCREEN_DESKTOP);
#else
ctx->screen = SDL_SetVideoMode(ctx->fs_width, ctx->fs_height, pref_bpp, flags);
#endif
/*we switched bpp, clean all objects*/
if (bpp != pref_bpp) SDLVid_DestroyObjects(ctx);
*screen_width = ctx->fs_width;
*screen_height = ctx->fs_height;
/*GL has changed*/
if (ctx->output_3d) {
GF_Event evt;
memset(&evt, 0, sizeof(GF_Event));
evt.type = GF_EVENT_VIDEO_SETUP;
evt.setup.use_opengl = GF_TRUE;
dr->on_event(dr->evt_cbk_hdl, &evt);
}
} else {
#if SDL_VERSION_ATLEAST(2,0,0)
SDL_SetWindowFullscreen(ctx->screen, 0);
#endif
SDLVid_ResizeWindow(dr, ctx->store_width, ctx->store_height);
*screen_width = ctx->store_width;
*screen_height = ctx->store_height;
}
gf_mx_v(ctx->evt_mx);
if (!ctx->screen) return GF_IO_ERR;
return GF_OK;
}
GF_Err SDLVid_SetBackbufferSize(GF_VideoOutput *dr, u32 newWidth, u32 newHeight, Bool system_mem)
{
const char *opt;
SDLVID();
#if SDL_VERSION_ATLEAST(2,0,0)
#else
u32 col;
#endif
if (ctx->output_3d) return GF_BAD_PARAM;
opt = gf_module_get_key((GF_BaseInterface*)dr, "hwvmem");
if (system_mem) {
if (opt && !strcmp(opt, "always")) system_mem = GF_FALSE;
} else {
if (opt && !strcmp(opt, "never")) system_mem = GF_TRUE;
}
ctx->use_systems_memory = system_mem;
/*clear screen*/
#if SDL_VERSION_ATLEAST(2,0,0)
if (ctx->tx_back_buffer) SDL_DestroyTexture(ctx->tx_back_buffer);
if (ctx->back_buffer_pixels) gf_free(ctx->back_buffer_pixels);
ctx->tx_back_buffer = SDL_CreateTexture(ctx->renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, newWidth, newHeight);
ctx->back_buffer_pixels = gf_malloc(sizeof(char)*3*newWidth*newHeight);
SDL_SetRenderDrawColor(ctx->renderer, 0, 0, 0, 255);
SDL_RenderClear(ctx->renderer);
SDL_RenderPresent(ctx->renderer);
#else
if(ctx->screen) {
col = SDL_MapRGB(ctx->screen->format, 0, 0, 0);
SDL_FillRect(ctx->screen, NULL, col);
SDL_Flip(ctx->screen);
}
if (ctx->back_buffer && ((u32) ctx->back_buffer->w==newWidth) && ((u32) ctx->back_buffer->h==newHeight)) {
return GF_OK;
}
if (ctx->back_buffer) SDL_FreeSurface(ctx->back_buffer);
if (ctx->screen) ctx->back_buffer = SDL_CreateRGBSurface(ctx->use_systems_memory ? SDL_SWSURFACE : SDL_HWSURFACE, newWidth, newHeight, ctx->screen->format->BitsPerPixel, ctx->screen->format->Rmask, ctx->screen->format->Gmask, ctx->screen->format->Bmask, 0);
if (!ctx->back_buffer) return GF_IO_ERR;
#endif
ctx->width = newWidth;
ctx->height = newHeight;
return GF_OK;
}
u32 SDLVid_MapPixelFormat(SDL_PixelFormat *format, Bool force_alpha)
{
if (!format || format->palette) return 0;
switch (format->BitsPerPixel) {
case 16:
if ((format->Rmask==0x7c00) && (format->Gmask==0x03e0) && (format->Bmask==0x001f) ) return GF_PIXEL_RGB_555;
if ((format->Rmask==0xf800) && (format->Gmask==0x07e0) && (format->Bmask==0x001f) ) return GF_PIXEL_RGB_565;
return 0;
case 24:
if (format->Rmask==0x00FF0000) return GF_PIXEL_RGB;
if (format->Rmask==0x000000FF) return GF_PIXEL_BGR;
return 0;
case 32:
if (format->Amask==0xFF000000) return GF_PIXEL_ARGB;
if (format->Rmask==0x00FF0000) return force_alpha ? GF_PIXEL_ARGB : GF_PIXEL_RGBX;
if (format->Rmask==0x000000FF) return force_alpha ? GF_PIXEL_RGBA : GF_PIXEL_BGRX;
return 0;
default:
return 0;
}
}
#if SDL_VERSION_ATLEAST(2,0,0)
static GF_Err SDLVid_LockBackBuffer(GF_VideoOutput *dr, GF_VideoSurface *video_info, Bool do_lock)
{
SDLVID();
if (do_lock) {
memset(video_info, 0, sizeof(GF_VideoSurface));
video_info->width = ctx->width;
video_info->height = ctx->height;
video_info->pitch_x = 0;
video_info->pitch_y = ctx->width*3;
video_info->video_buffer = ctx->back_buffer_pixels;
video_info->pixel_format = GF_PIXEL_RGB;
video_info->is_hardware_memory = 0;
if (ctx->needs_bb_grab) {
SDL_RenderReadPixels(ctx->renderer, NULL, SDL_PIXELFORMAT_RGB24, video_info->video_buffer, video_info->pitch_y);
ctx->needs_bb_grab = 0;
}
} else {
SDL_UpdateTexture(ctx->tx_back_buffer, NULL, video_info->video_buffer, video_info->pitch_y);
SDL_RenderCopy(ctx->renderer, ctx->tx_back_buffer, NULL, NULL);
}
return GF_OK;
}
#else
static GF_Err SDLVid_LockBackBuffer(GF_VideoOutput *dr, GF_VideoSurface *video_info, Bool do_lock)
{
SDLVID();
if (!ctx->back_buffer) return GF_BAD_PARAM;
if (do_lock) {
if (!video_info) return GF_BAD_PARAM;
if (SDL_LockSurface(ctx->back_buffer)<0) return GF_IO_ERR;
memset(video_info, 0, sizeof(GF_VideoSurface));
video_info->width = ctx->back_buffer->w;
video_info->height = ctx->back_buffer->h;
video_info->pitch_x = 0;
video_info->pitch_y = ctx->back_buffer->pitch;
video_info->video_buffer = (char*)ctx->back_buffer->pixels;
video_info->pixel_format = SDLVid_MapPixelFormat(ctx->back_buffer->format, ctx->force_alpha);
video_info->is_hardware_memory = !ctx->use_systems_memory;
} else {
SDL_UnlockSurface(ctx->back_buffer);
}
return GF_OK;
}
#endif
#if SDL_VERSION_ATLEAST(2,0,0)
//for CGLSetParameter
#if defined(__APPLE__) && !defined(GPAC_CONFIG_IOS)
#include <OpenGL/OpenGL.h>
#endif
static GF_Err SDLVid_Flush(GF_VideoOutput *dr, GF_Window *dest)
{
SDLVID();
/*if resizing don't process otherwise we may deadlock*/
if (!ctx->screen) return GF_OK;
GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[SDL] swapping video buffers\n"));
if (ctx->output_3d) {
//with SDL2 we have to disable vsync by overriding swap interval
#if defined(__APPLE__) && !defined(GPAC_CONFIG_IOS) && !defined(GPAC_DISABLE_3D)
if (ctx->disable_vsync) {
GLint sync = 0;
CGLContextObj gl_ctx = CGLGetCurrentContext();
CGLSetParameter(gl_ctx, kCGLCPSwapInterval, &sync);
}
#endif
#ifdef GPAC_CONFIG_EMSCRIPTEN
void gpac_on_video_swap();
gpac_on_video_swap();
#endif
SDL_GL_SwapWindow(ctx->screen);
return GF_OK;
}
if (ctx->enable_defer_mode) {
if (ctx->needs_bb_flush) {
SDL_UpdateTexture(ctx->tx_back_buffer, NULL, ctx->back_buffer_pixels, 3*ctx->width);
SDL_RenderCopy(ctx->renderer, ctx->tx_back_buffer, NULL, NULL);
}
SDL_RenderReadPixels(ctx->renderer, NULL, SDL_PIXELFORMAT_RGB24, ctx->back_buffer_pixels, 3*ctx->width);
ctx->needs_bb_grab = 0;
ctx->needs_bb_flush = 0;
SDL_RenderPresent(ctx->renderer);
//push back texture after SDL flip
SDL_RenderCopy(ctx->renderer, ctx->tx_back_buffer, NULL, NULL);
} else {
ctx->needs_clear = 1;
SDL_RenderPresent(ctx->renderer);
}
return GF_OK;
}
#else
static GF_Err SDLVid_Flush(GF_VideoOutput *dr, GF_Window *dest)
{
SDL_Rect rc;
SDLVID();
/*if resizing don't process otherwise we may deadlock*/
if (!ctx->screen) return GF_OK;
//GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Flush\n"));
if (ctx->output_3d) {
SDL_GL_SwapBuffers();
return GF_OK;
}
if (!ctx->back_buffer) return GF_BAD_PARAM;
if ((dest->w != (u32) ctx->back_buffer->w) || (dest->h != (u32) ctx->back_buffer->h)) {
GF_VideoSurface src, dst;
SDL_LockSurface(ctx->back_buffer);
memset(&src, 0, sizeof(GF_VideoSurface));
src.height = ctx->back_buffer->h;
src.width = ctx->back_buffer->w;
src.pitch_x = 0;
src.pitch_y = ctx->back_buffer->pitch;
src.pixel_format = SDLVid_MapPixelFormat(ctx->back_buffer->format, ctx->force_alpha);
src.video_buffer = (char*)ctx->back_buffer->pixels;
SDL_LockSurface(ctx->screen);
dst.height = ctx->screen->h;
dst.width = ctx->screen->w;
dst.pitch_x = 0;
dst.pitch_y = ctx->screen->pitch;
dst.pixel_format = SDLVid_MapPixelFormat(ctx->screen->format, GF_FALSE);
dst.video_buffer = (char*)ctx->screen->pixels;
gf_stretch_bits(&dst, &src, dest, NULL, 0xFF, GF_FALSE, NULL, NULL);
SDL_UnlockSurface(ctx->screen);
SDL_UnlockSurface(ctx->back_buffer);
} else {
rc.x = dest->x;
rc.y = dest->y;
rc.w = dest->w;
rc.h = dest->h;
SDL_BlitSurface(ctx->back_buffer, NULL, ctx->screen, &rc);
}
SDL_Flip(ctx->screen);
return GF_OK;
}
#endif
#ifdef WIN32
static u32 get_sys_col(int idx)
{
u32 res;
DWORD val = GetSysColor(idx);
res = (val)&0xFF;
res<<=8;
res |= (val>>8)&0xFF;
res<<=8;
res |= (val>>16)&0xFF;
return res;
}
#endif
static GF_Err SDLVid_ProcessEvent(GF_VideoOutput *dr, GF_Event *evt)
{
if (!evt) {
#ifndef SDL_WINDOW_THREAD
SDLVID();
SDLVid_ProcessMessageQueue(ctx, dr);
#endif
return GF_OK;
}
switch (evt->type) {
case GF_EVENT_SET_CURSOR:
#ifndef GPAC_CONFIG_IOS
SDLVid_SetCursor(dr, evt->cursor.cursor_type);
#endif
break;
case GF_EVENT_SET_CAPTION:
#ifdef SDL_WINDOW_THREAD
{
SDLVID();
if (ctx->sdl_th_state != SDL_STATE_RUNNING)
break;
}
#endif
#if SDL_VERSION_ATLEAST(2,0,0)
{
#if !defined(GPAC_CONFIG_IOS)
SDLVID();
SDL_SetWindowTitle(ctx->screen, evt->caption.caption);
SDLVid_ProcessEvent(dr, NULL);
#endif
}
#else
SDL_WM_SetCaption(evt->caption.caption, NULL);
#endif
break;
case GF_EVENT_SHOWHIDE:
/*the only way to have proper show/hide with SDL is to shutdown the video system and reset it up
which we don't want to do since the setup MUST occur in the rendering thread for some configs (OpenGL)*/
return GF_NOT_SUPPORTED;
case GF_EVENT_SIZE:
{
SDLVID();
#ifdef GPAC_CONFIG_IOS
if (ctx->fullscreen) {
} else {
SDLVid_ResizeWindow(dr, evt->size.width, evt->size.height);
}
#else
if (ctx->fullscreen) {
//ctx->store_width = evt->size.width;
//ctx->store_height = evt->size.height;
} else {
SDLVid_ResizeWindow(dr, evt->size.width, evt->size.height);
}
#endif
}
break;
case GF_EVENT_MOVE:
#if !defined(GPAC_CONFIG_IOS) && SDL_VERSION_ATLEAST(2,0,0)
{
SDLVID();
if (ctx->fullscreen) return GF_OK;
if (evt->move.relative == 2) {
}
else if (evt->move.relative) {
s32 x, y;
x = y = 0;
SDL_GetWindowPosition(ctx->screen, &x, &y);
SDL_SetWindowPosition(ctx->screen, x + evt->move.x, y + evt->move.y);
} else {
SDL_SetWindowPosition(ctx->screen, evt->move.x, evt->move.y);
}
}
#endif
break;
case GF_EVENT_VIDEO_SETUP:
{
SDLVID();
ctx->disable_vsync=evt->setup.disable_vsync;
if (!evt->setup.use_opengl) {
/*force a resetup of the window*/
if (ctx->output_3d) {
ctx->width = ctx->height = 0;
ctx->output_3d = GF_FALSE;
SDLVid_ResetWindow(ctx);
SDLVid_ResizeWindow(dr, evt->setup.width, evt->setup.height);
} else {
#if SDL_VERSION_ATLEAST(2,0,0)
SDLVid_ResizeWindow(dr, evt->setup.width, evt->setup.height);
#endif
}
ctx->output_3d = GF_FALSE;
return SDLVid_SetBackbufferSize(dr, evt->setup.width, evt->setup.height, evt->setup.system_memory);
} else {
/*force a resetup of the window*/
if (!ctx->output_3d) {
ctx->width = ctx->height = 0;
SDLVid_ResetWindow(ctx);
}
ctx->output_3d = GF_TRUE;
GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[SDL] Setting up 3D in SDL.\n"));
#ifdef GPAC_CONFIG_IOS
// return SDLVid_ResizeWindow(dr, dr->max_screen_width, dr->max_screen_height);
return SDLVid_ResizeWindow(dr, evt->setup.width, evt->setup.height);
#else
return SDLVid_ResizeWindow(dr, evt->setup.width, evt->setup.height);
#endif
}
}
break;
case GF_EVENT_SYS_COLORS:
#ifdef WIN32
evt->sys_cols.sys_colors[0] = get_sys_col(COLOR_ACTIVEBORDER);
evt->sys_cols.sys_colors[1] = get_sys_col(COLOR_ACTIVECAPTION);
evt->sys_cols.sys_colors[2] = get_sys_col(COLOR_APPWORKSPACE);
evt->sys_cols.sys_colors[3] = get_sys_col(COLOR_BACKGROUND);
evt->sys_cols.sys_colors[4] = get_sys_col(COLOR_BTNFACE);
evt->sys_cols.sys_colors[5] = get_sys_col(COLOR_BTNHIGHLIGHT);
evt->sys_cols.sys_colors[6] = get_sys_col(COLOR_BTNSHADOW);
evt->sys_cols.sys_colors[7] = get_sys_col(COLOR_BTNTEXT);
evt->sys_cols.sys_colors[8] = get_sys_col(COLOR_CAPTIONTEXT);
evt->sys_cols.sys_colors[9] = get_sys_col(COLOR_GRAYTEXT);
evt->sys_cols.sys_colors[10] = get_sys_col(COLOR_HIGHLIGHT);
evt->sys_cols.sys_colors[11] = get_sys_col(COLOR_HIGHLIGHTTEXT);
evt->sys_cols.sys_colors[12] = get_sys_col(COLOR_INACTIVEBORDER);
evt->sys_cols.sys_colors[13] = get_sys_col(COLOR_INACTIVECAPTION);
evt->sys_cols.sys_colors[14] = get_sys_col(COLOR_INACTIVECAPTIONTEXT);
evt->sys_cols.sys_colors[15] = get_sys_col(COLOR_INFOBK);
evt->sys_cols.sys_colors[16] = get_sys_col(COLOR_INFOTEXT);
evt->sys_cols.sys_colors[17] = get_sys_col(COLOR_MENU);
evt->sys_cols.sys_colors[18] = get_sys_col(COLOR_MENUTEXT);
evt->sys_cols.sys_colors[19] = get_sys_col(COLOR_SCROLLBAR);
evt->sys_cols.sys_colors[20] = get_sys_col(COLOR_3DDKSHADOW);
evt->sys_cols.sys_colors[21] = get_sys_col(COLOR_3DFACE);
evt->sys_cols.sys_colors[22] = get_sys_col(COLOR_3DHIGHLIGHT);
evt->sys_cols.sys_colors[23] = get_sys_col(COLOR_3DLIGHT);
evt->sys_cols.sys_colors[24] = get_sys_col(COLOR_3DSHADOW);
evt->sys_cols.sys_colors[25] = get_sys_col(COLOR_WINDOW);
evt->sys_cols.sys_colors[26] = get_sys_col(COLOR_WINDOWFRAME);
evt->sys_cols.sys_colors[27] = get_sys_col(COLOR_WINDOWTEXT);
return GF_OK;
#else
return GF_NOT_SUPPORTED;
#endif
case GF_EVENT_TEXT_EDITING_START:
case GF_EVENT_TEXT_EDITING_END:
#if defined(GPAC_CONFIG_IOS) && SDL_VERSION_ATLEAST(2,0,0)
if (evt->type==GF_EVENT_TEXT_EDITING_START) {
SDL_StartTextInput();
} else {
SDL_StopTextInput();
}
return GF_OK;
#else
return GF_NOT_SUPPORTED;
#endif
case GF_EVENT_SET_GL:
{
#if SDL_VERSION_ATLEAST(2,0,0)
SDLVID();
if (SDL_GL_MakeCurrent(ctx->screen, ctx->gl_context)) {
GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Cannot make context current: %s\n", SDL_GetError()));
return GF_IO_ERR;
}
#endif
}
return GF_OK;
#if SDL_VERSION_ATLEAST(2,0,0)
case GF_EVENT_SET_ORIENTATION:
{
switch (evt->size.orientation) {
case GF_DISPLAY_MODE_PORTRAIT: SDL_SetHint(SDL_HINT_ORIENTATIONS, "Portrait"); break;
case GF_DISPLAY_MODE_PORTRAIT_INV: SDL_SetHint(SDL_HINT_ORIENTATIONS, "PortraitUpsideDown"); break;
case GF_DISPLAY_MODE_LANDSCAPE: SDL_SetHint(SDL_HINT_ORIENTATIONS, "LandscapeRight"); break;
case GF_DISPLAY_MODE_LANDSCAPE_INV: SDL_SetHint(SDL_HINT_ORIENTATIONS, "LandscapeLeft"); break;
case GF_DISPLAY_MODE_UNKNOWN:
SDL_SetHint(SDL_HINT_ORIENTATIONS, "LandscapeLeft LandscapeRight Portrait PortraitUpsideDown");
break;
}
return GF_OK;
}
#endif
}
return GF_OK;
}
#if SDL_VERSION_ATLEAST(2,0,0)
static GF_Err SDL_Blit(GF_VideoOutput *dr, GF_VideoSurface *video_src, GF_Window *src_wnd, GF_Window *dst_wnd, u32 overlay_type)
{
SDLVID();
Bool need_copy=0;
u32 format;
s32 acc, w, h;
int res;
Bool set_blend=0;
SDL_Rect dstrc;
SDL_Texture **pool;
SDL_Rect srcrc, *src_ptr=NULL;
GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[SDL] Bliting surface (overlay type %d)\n", overlay_type));
if (ctx->needs_bb_flush) {
SDL_UpdateTexture(ctx->tx_back_buffer, NULL, ctx->back_buffer_pixels, 3*ctx->width);
SDL_RenderCopy(ctx->renderer, ctx->tx_back_buffer, NULL, NULL);
ctx->needs_bb_grab = 1;
}
ctx->needs_bb_grab = 1;
if (ctx->needs_clear) {
SDL_RenderClear(ctx->renderer);
ctx->needs_clear = 0;
}
dstrc.w = dst_wnd->w;
dstrc.h = dst_wnd->h;
dstrc.x = dst_wnd->x;
dstrc.y = dst_wnd->y;
if (src_wnd) {
srcrc.x = src_wnd->x;
srcrc.y = src_wnd->y;
srcrc.w = src_wnd->w;
srcrc.h = src_wnd->h;
src_ptr = &srcrc;
}
//this is a clear (not very elegant ...)
if ((video_src->width<=2) && (video_src->height<=2)) {
u8 *pix =(u8 *) video_src->video_buffer;
if (video_src->pixel_format == GF_PIXEL_RGB) {
SDL_SetRenderDrawColor(ctx->renderer, pix[0], pix[1], pix[2], 0xFF);
} else {
SDL_SetRenderDrawColor(ctx->renderer, pix[0], pix[1], pix[2], pix[3]);
}
res = SDL_RenderFillRect(ctx->renderer, &dstrc);
if (res<0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL2] Clear error: %s\n", SDL_GetError()));
return GF_IO_ERR;
}
return GF_OK;
}
switch (video_src->pixel_format) {
case GF_PIXEL_RGB:
pool = &ctx->pool_rgb;
format=SDL_PIXELFORMAT_RGB24;
break;
case GF_PIXEL_XRGB:
pool = &ctx->pool_rgb;
format=SDL_PIXELFORMAT_BGRX8888;
break;
case GF_PIXEL_RGBX:
pool = &ctx->pool_rgb;
format=SDL_PIXELFORMAT_BGR888;
break;
case GF_PIXEL_XBGR:
pool = &ctx->pool_rgb;
format=SDL_PIXELFORMAT_RGBX8888;
break;
case GF_PIXEL_BGRX:
pool = &ctx->pool_rgb;
format=SDL_PIXELFORMAT_RGB888;
break;
case GF_PIXEL_RGBA:
pool = &ctx->pool_rgba;
format=SDL_PIXELFORMAT_ABGR8888;
set_blend=1;
break;
case GF_PIXEL_YUV:
pool = &ctx->pool_yuv;
format=SDL_PIXELFORMAT_IYUV;
break;
case GF_PIXEL_YVU:
pool = &ctx->pool_yuv;
format=SDL_PIXELFORMAT_YV12;
break;
case GF_PIXEL_YUV422:
case GF_PIXEL_YUV444:
case GF_PIXEL_YUV444_10:
case GF_PIXEL_YUV422_10:
case GF_PIXEL_YUV_10:
need_copy=1;
pool = &ctx->pool_yuv;
format=SDL_PIXELFORMAT_IYUV;
break;
/*FIXME we need to upgrade our SDL build*/
#if !defined(GPAC_CONFIG_IOS) && SDL_VERSION_ATLEAST(2,0,0)
case GF_PIXEL_NV12:
pool = &ctx->pool_yuv;
format=SDL_PIXELFORMAT_NV12;
break;
case GF_PIXEL_NV21:
pool = &ctx->pool_yuv;
format=SDL_PIXELFORMAT_NV21;
break;
#endif
case GF_PIXEL_UYVY:
pool = &ctx->pool_yuv;
format=SDL_PIXELFORMAT_UYVY;
break;
case GF_PIXEL_YUYV:
pool = &ctx->pool_yuv;
format=SDL_PIXELFORMAT_YUY2;
break;
default:
return GF_NOT_SUPPORTED;
}
if (*pool ) {
SDL_QueryTexture(*pool, &format, &acc, &w, &h);
if ((w != video_src->width) || (h != video_src->height) ) {
SDL_DestroyTexture(*pool);
*pool = NULL;
}
}
if (!(*pool)) {
(*pool) = SDL_CreateTexture(ctx->renderer, format, SDL_TEXTUREACCESS_STREAMING, video_src->width, video_src->height);
if (!(*pool)) return GF_NOT_SUPPORTED;
}
SDL_QueryTexture((*pool), &format, &acc, &w, &h);
if (need_copy) {
GF_VideoSurface dst_v;
u8 *pixels;
int pitch;
GF_Window swnd;
/*copy pixels*/
if (SDL_LockTexture(*pool, NULL, (void**)&pixels, &pitch) < 0) {
return GF_NOT_SUPPORTED;
}
if (!src_wnd) {
swnd.x = swnd.y=0;
swnd.w = video_src->width;
swnd.h = video_src->height;
src_wnd = &swnd;
}
memset(&dst_v, 0, sizeof(GF_VideoSurface));
dst_v.video_buffer = pixels;
dst_v.u_ptr = pixels + h*pitch;
dst_v.v_ptr = pixels + 5*h*pitch/4;
dst_v.pitch_y = pitch;
dst_v.pixel_format = GF_PIXEL_YUV;
dst_v.width = video_src->width;
dst_v.height = video_src->height;
gf_stretch_bits(&dst_v, video_src, NULL, src_wnd, 0xFF, GF_FALSE, NULL, NULL);
SDL_UnlockTexture(*pool);
} else {
SDL_UpdateTexture(*pool, NULL, video_src->video_buffer, video_src->pitch_y);
}
if (set_blend || (video_src->global_alpha!=0xFF)) {
res = SDL_SetTextureBlendMode(*pool, SDL_BLENDMODE_BLEND);
if (res<0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL2] Cannot change texture blend mode: %s\n", SDL_GetError()));
return GF_IO_ERR;
}
res = SDL_SetTextureAlphaMod(*pool, video_src->global_alpha);
if (res<0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL2] Cannot change global alpha of texture: %s\n", SDL_GetError()));
return GF_IO_ERR;
}
} else {
res = SDL_SetTextureBlendMode(*pool, SDL_BLENDMODE_NONE);
if (res<0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL2] Cannot change texture blend mode: %s\n", SDL_GetError()));
return GF_IO_ERR;
}
}
res = SDL_RenderCopy(ctx->renderer, *pool, src_ptr, &dstrc);
if (res<0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL2] Blit error: %s\n", SDL_GetError()));
return GF_IO_ERR;
}
return GF_OK;
}
#else
static GF_Err SDL_Blit(GF_VideoOutput *dr, GF_VideoSurface *video_src, GF_Window *src_wnd, GF_Window *dst_wnd, u32 overlay_type)
{
SDLVID();
u32 amask = 0;
u32 bpp;
GF_Err e = GF_OK;
u32 i;
u8 *dst, *src;
SDL_Rect dstrc;
SDL_Surface **pool;
GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[SDL] Bliting surface (overlay type %d)\n", overlay_type));
if (overlay_type) {
GF_VideoSurface dst_v;
if (!video_src) {
if (ctx->yuv_overlay) {
SDL_FreeYUVOverlay(ctx->yuv_overlay);
ctx->yuv_overlay=NULL;
}
return GF_OK;
}
if (!ctx->yuv_overlay || (ctx->yuv_overlay->w != src_wnd->w) || (ctx->yuv_overlay->h != src_wnd->h) ) {
if (ctx->yuv_overlay) SDL_FreeYUVOverlay(ctx->yuv_overlay);
ctx->yuv_overlay = SDL_CreateYUVOverlay(src_wnd->w, src_wnd->h, SDL_YV12_OVERLAY, ctx->screen);
if (!ctx->yuv_overlay) return GF_NOT_SUPPORTED;
}
/*copy pixels*/
SDL_LockYUVOverlay(ctx->yuv_overlay);
memset(&dst_v, 0, sizeof(GF_VideoSurface));
dst_v.video_buffer = (char *) ctx->yuv_overlay->pixels[0];
dst_v.u_ptr = (char *) ctx->yuv_overlay->pixels[1];
dst_v.v_ptr = (char *) ctx->yuv_overlay->pixels[2];
dst_v.pitch_y = ctx->yuv_overlay->pitches[0];
dst_v.pixel_format = GF_PIXEL_YUV;
dst_v.width = video_src->width;
dst_v.height = video_src->height;
gf_stretch_bits(&dst_v, video_src, NULL, src_wnd, 0xFF, GF_FALSE, NULL, NULL);
SDL_UnlockYUVOverlay(ctx->yuv_overlay);
dstrc.w = dst_wnd->w;
dstrc.h = dst_wnd->h;
dstrc.x = dst_wnd->x;
dstrc.y = dst_wnd->y;
SDL_DisplayYUVOverlay(ctx->yuv_overlay, &dstrc);
return GF_OK;
}
/*SDL doesn't support stretching ...*/
if ((src_wnd->w != dst_wnd->w) || (src_wnd->h!=dst_wnd->h))
return GF_NOT_SUPPORTED;
switch (video_src->pixel_format) {
case GF_PIXEL_RGB:
pool = &ctx->pool_rgb;
bpp = 3;
break;
case GF_PIXEL_RGBA:
pool = &ctx->pool_rgba;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
amask = 0x000000FF;
#else
amask = 0xFF000000;
#endif
bpp = 4;
break;
default:
return GF_NOT_SUPPORTED;
}
if (! *pool || ((*pool)->w < (int) src_wnd->w) || ((*pool)->h < (int) src_wnd->h) ) {
if ((*pool)) SDL_FreeSurface((*pool));
(*pool) = SDL_CreateRGBSurface(ctx->use_systems_memory ? SDL_SWSURFACE : SDL_HWSURFACE,
src_wnd->w, src_wnd->h, 8*bpp,
0x000000FF, 0x0000FF00, 0x00FF0000, amask);
if (! (*pool) ) return GF_IO_ERR;
}
SDL_LockSurface(*pool);
dst = (u8 *) ( (*pool)->pixels);
src = (u8*)video_src->video_buffer + video_src->pitch_y*src_wnd->y + src_wnd->x*bpp;
for (i=0; i<src_wnd->h; i++) {
memcpy(dst, src, bpp * src_wnd->w);
src += video_src->pitch_y;
dst += (*pool)->pitch;
}
SDL_UnlockSurface(*pool);
dstrc.w = dst_wnd->w;
dstrc.h = dst_wnd->h;
dstrc.x = dst_wnd->x;
dstrc.y = dst_wnd->y;
if (SDL_BlitSurface(*pool, NULL, ctx->back_buffer, &dstrc))
GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Blit error: %s\n", SDL_GetError()));
return e;
}
#endif
static GF_GPACArg SDLArgs[] = {
GF_DEF_ARG("vsync", NULL, "enable vertical synchro", "true", NULL, GF_ARG_BOOL, 0),
GF_DEF_ARG("switch-vres", NULL, "enable resolution switching of display", "false", NULL, GF_ARG_BOOL, 0),
GF_DEF_ARG("defer", NULL, "enable defer mode when bliting", "false", NULL, GF_ARG_BOOL, 0),
GF_DEF_ARG("hwvmem", NULL, "specify (2D rendering only) memory type of main video backbuffer. Depending on the scene type, this may drastically change the playback speed\n"
"- always: always on hardware\n"
"- never: always on system memory\n"
"- auto: selected by GPAC based on content type (graphics or video)", "auto", "auto|always|never", GF_ARG_INT, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_VIDEO),
{0},
};
void *SDL_NewVideo()
{
SDLVidCtx *ctx;
GF_VideoOutput *driv;
driv = (GF_VideoOutput*)gf_malloc(sizeof(GF_VideoOutput));
memset(driv, 0, sizeof(GF_VideoOutput));
GF_REGISTER_MODULE_INTERFACE(driv, GF_VIDEO_OUTPUT_INTERFACE, "sdl", "gpac distribution");
ctx = (SDLVidCtx*)gf_malloc(sizeof(SDLVidCtx));
memset(ctx, 0, sizeof(SDLVidCtx));
#ifdef SDL_WINDOW_THREAD
ctx->sdl_th = gf_th_new("SDLVideo");
#endif
ctx->evt_mx = gf_mx_new("SDLEvents");
driv->opaque = ctx;
driv->Setup = SDLVid_Setup;
driv->Shutdown = SDLVid_Shutdown;
driv->SetFullScreen = SDLVid_SetFullScreen;
driv->Flush = SDLVid_Flush;
driv->ProcessEvent = SDLVid_ProcessEvent;
driv->args = SDLArgs;
driv->description = "Video output using SDL";
/*no offscreen opengl with SDL*/
driv->hw_caps |= GF_VIDEO_HW_OPENGL;
/*no YUV hardware blitting in SDL (only overlays)*/
driv->hw_caps |= GF_VIDEO_HW_HAS_RGB ;
#if SDL_VERSION_ATLEAST(2,0,0)
driv->hw_caps |= GF_VIDEO_HW_HAS_YUV | GF_VIDEO_HW_HAS_STRETCH | GF_VIDEO_HW_HAS_RGBA;
ctx->enable_defer_mode = gf_module_get_bool((GF_BaseInterface *)driv, "defer");
if (! ctx->enable_defer_mode)
driv->hw_caps |= GF_VIDEO_HW_DIRECT_ONLY;
#else
driv->hw_caps |= GF_VIDEO_HW_HAS_YUV_OVERLAY;
#endif
#ifdef GPAC_ENABLE_COVERAGE
SDLVid_MapPixelFormat(NULL, GF_FALSE);
#endif
driv->Blit = SDL_Blit;
driv->LockBackBuffer = SDLVid_LockBackBuffer;
driv->LockOSContext = NULL;
#ifndef SDL_TEXTINPUTEVENT_TEXT_SIZE
SDL_EnableUNICODE(1);
#else
SDL_StartTextInput();
#endif /* SDL_TEXTINPUTEVENT_TEXT_SIZE */
return driv;
}
void SDL_DeleteVideo(void *ifce)
{
GF_VideoOutput *dr = (GF_VideoOutput *)ifce;
SDLVID();
#ifdef SDL_WINDOW_THREAD
gf_th_del(ctx->sdl_th);
#endif
gf_mx_del(ctx->evt_mx);
gf_list_del_item(video_outputs, dr);
nb_video_outputs = gf_list_count(video_outputs);
if (!nb_video_outputs) {
gf_list_del(video_outputs);
video_outputs = NULL;
SDL_QuitSubSystem(SDL_INIT_VIDEO);
}
gf_free(ctx);
gf_free(dr);
}