Initial framefile and split m2v/ogg support.
This commit is contained in:
parent
ece26e81ff
commit
bd0ab45792
10 changed files with 668 additions and 120 deletions
296
singe/frameFile.c
Normal file
296
singe/frameFile.c
Normal file
|
@ -0,0 +1,296 @@
|
|||
/*
|
||||
*
|
||||
* Singe 2
|
||||
* Copyright (C) 2006-2020 Scott Duensing <scott@kangaroopunch.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "thirdparty/uthash.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "videoPlayer.h"
|
||||
#include "frameFile.h"
|
||||
|
||||
|
||||
typedef struct FrameLineS {
|
||||
int videoHandle;
|
||||
int lastFramePlayed;
|
||||
long frame;
|
||||
char *filename;
|
||||
} FrameLineT;
|
||||
|
||||
|
||||
typedef struct FrameFileS {
|
||||
int id;
|
||||
int count;
|
||||
char *videoPath;
|
||||
FrameLineT *files;
|
||||
UT_hash_handle hh;
|
||||
} FrameFileT;
|
||||
|
||||
|
||||
static FrameFileT *_frameFileHash = NULL;
|
||||
static int _nextId = 0;
|
||||
|
||||
|
||||
void _transferProperties(int oldHandle, int newHandle);
|
||||
|
||||
|
||||
void _transferProperties(int oldHandle, int newHandle) {
|
||||
int l = 0;
|
||||
int r = 0;
|
||||
|
||||
if ((oldHandle < 0) || (newHandle < 0)) {
|
||||
// Invalid handle somewhere
|
||||
return;
|
||||
}
|
||||
|
||||
// Transfer previous video's properties to this one
|
||||
videoGetVolume(oldHandle, &l, &r);
|
||||
videoSetVolume(newHandle, l, r);
|
||||
if (videoIsPlaying(oldHandle)) {
|
||||
videoPlay(newHandle);
|
||||
} else {
|
||||
videoPause(newHandle);
|
||||
}
|
||||
videoPause(oldHandle);
|
||||
}
|
||||
|
||||
|
||||
long frameFileGetFrame(int frameFileIndex, int videoHandle) {
|
||||
int i = 0;
|
||||
FrameFileT *f = NULL;
|
||||
|
||||
// Get our framefile structure
|
||||
HASH_FIND_INT(_frameFileHash, &frameFileIndex, f);
|
||||
if (!f) utilDie("No framefile at index %d in frameFileSeek.", frameFileIndex);
|
||||
|
||||
// Search through loaded video segments
|
||||
for (i=0; i<f->count; i++) {
|
||||
if (f->files[i].videoHandle == videoHandle) {
|
||||
// Frame is in this video
|
||||
return videoGetFrame(videoHandle) + f->files[i].frame;
|
||||
}
|
||||
}
|
||||
|
||||
// Didn't find it.
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int frameFileInit(void) {
|
||||
return 0; // Nothing to do
|
||||
}
|
||||
|
||||
|
||||
int frameFileLoad(char *filename, char *indexPath, bool stretchVideo, SDL_Renderer *renderer) {
|
||||
int result = 0;
|
||||
int count = 0;
|
||||
long frame = 0;
|
||||
size_t bytes = 0;
|
||||
char *audio = NULL;
|
||||
char *data = NULL;
|
||||
char *path = NULL;
|
||||
char *offset = NULL;
|
||||
char *frameLine = NULL;
|
||||
char *space = NULL;
|
||||
char *endptr = NULL;
|
||||
char *temp = NULL;
|
||||
FrameLineT *files = NULL;
|
||||
FrameLineT *newFiles = NULL;
|
||||
FrameFileT *frameFile = NULL;
|
||||
|
||||
data = utilReadFile(filename, &bytes);
|
||||
if (!data) utilDie("Unable to open framefile: %s", filename);
|
||||
|
||||
// Get path where video files live
|
||||
path = utilReadLine(data, bytes, &offset);
|
||||
if (!path) utilDie("Cannot read video path from framefile!");
|
||||
utilFixPathSeparators(&path);
|
||||
|
||||
// If it's not an absolute path, pre-pend the path to the framefile
|
||||
if (path[0] != utilGetPathSeparator()) {
|
||||
temp = path;
|
||||
count = strlen(filename) - strlen(utilGetLastPathComponent(filename));
|
||||
path = malloc(sizeof(char) * (count + strlen(temp) + 1));
|
||||
memcpy(path, filename, count);
|
||||
memcpy(&path[count], temp, strlen(temp));
|
||||
path[count + strlen(temp)] = 0;
|
||||
free(temp);
|
||||
utilFixPathSeparators(&path);
|
||||
count = 0;
|
||||
}
|
||||
|
||||
// Read frame offsets and filenames - silently ignore bad lines
|
||||
while ((frameLine = utilReadLine(data, bytes, &offset)) != NULL) {
|
||||
// Find first space in this file.
|
||||
space = strstr(frameLine, " ");
|
||||
if (space) {
|
||||
// Write a zero in there to make it two fields.
|
||||
*space = 0;
|
||||
// Is the first part an integer?
|
||||
endptr = NULL;
|
||||
frame = strtol(frameLine, &endptr, 10);
|
||||
*space = 32;
|
||||
if (endptr == space) {
|
||||
// Got an integer. Point at filename.
|
||||
space++;
|
||||
while ((space[0] == 32) || (space[0] == 9)) {
|
||||
space++;
|
||||
}
|
||||
// Copy frame number and filename into array
|
||||
newFiles = realloc(files, sizeof(FrameLineT) * (count + 1));
|
||||
if (!newFiles) utilDie("Unable to allocate new framefile entry!");
|
||||
files = newFiles;
|
||||
files[count].lastFramePlayed = 0;
|
||||
files[count].frame = frame;
|
||||
files[count].filename = utilCreateString("%s%s", path, space);
|
||||
// Is this an old m2v/ogg pair?
|
||||
if (strncmp(utilGetFileExtension(files[count].filename), "m2v", 3) == 0) {
|
||||
// Open split video and audio files
|
||||
audio = strdup(files[count].filename);
|
||||
audio[strlen(audio) - 3] = 'o';
|
||||
audio[strlen(audio) - 2] = 'g';
|
||||
audio[strlen(audio) - 1] = 'g';
|
||||
files[count].videoHandle = videoLoadWithAudio(files[count].filename, audio, indexPath, stretchVideo, renderer);
|
||||
free(audio);
|
||||
audio = NULL;
|
||||
} else {
|
||||
// Open combined video/audio file
|
||||
files[count].videoHandle = videoLoad(files[count].filename, indexPath, stretchVideo, renderer);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
free(frameLine);
|
||||
}
|
||||
|
||||
// Allocate new framefile
|
||||
frameFile = malloc(sizeof(FrameFileT));
|
||||
frameFile->id = _nextId;
|
||||
frameFile->count = count;
|
||||
frameFile->videoPath = path;
|
||||
frameFile->files = files;
|
||||
HASH_ADD_INT(_frameFileHash, id, frameFile);
|
||||
|
||||
result = _nextId++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int frameFileSeek(int frameFileIndex, long seekFrame, int *videoHandle, int *actualFrame) {
|
||||
int i = 0;
|
||||
FrameFileT *f = NULL;
|
||||
|
||||
// Get our framefile structure
|
||||
HASH_FIND_INT(_frameFileHash, &frameFileIndex, f);
|
||||
if (!f) utilDie("No framefile at index %d in frameFileSeek.", frameFileIndex);
|
||||
|
||||
// Search through loaded video segments
|
||||
for (i=0; i<f->count; i++) {
|
||||
if ((seekFrame >= f->files[i].frame) && (seekFrame <= (f->files[i].frame + videoGetFrameCount(f->files[i].videoHandle)))) {
|
||||
// Frame is in this video
|
||||
*actualFrame = (int)(seekFrame - f->files[i].frame);
|
||||
f->files[i].lastFramePlayed = *actualFrame;
|
||||
videoSeek(f->files[i].videoHandle, *actualFrame);
|
||||
// Is this a different video from the previous one?
|
||||
if (*videoHandle != f->files[i].videoHandle) {
|
||||
// Yes
|
||||
_transferProperties(*videoHandle, f->files[i].videoHandle);
|
||||
*videoHandle = f->files[i].videoHandle;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Didn't find it
|
||||
*videoHandle = -1;
|
||||
*actualFrame = -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int frameFileQuit(void) {
|
||||
FrameFileT *f = NULL;
|
||||
FrameFileT *t = NULL;
|
||||
|
||||
// Unload any remaining frameFiles
|
||||
HASH_ITER(hh, _frameFileHash, f, t) {
|
||||
frameFileUnload(f->id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int frameFileUnload(int frameFileIndex) {
|
||||
int i = 0;
|
||||
FrameFileT *f = NULL;
|
||||
|
||||
// Get our framefile structure
|
||||
HASH_FIND_INT(_frameFileHash, &frameFileIndex, f);
|
||||
if (!f) utilDie("No framefile at index %d in frameFileUnload.", frameFileIndex);
|
||||
|
||||
// Unload videos
|
||||
for (i=0; i<f->count; i++) {
|
||||
free(f->files[i].filename);
|
||||
videoUnload(f->files[i].videoHandle);
|
||||
}
|
||||
|
||||
// Free memory
|
||||
free(f->files);
|
||||
free(f->videoPath);
|
||||
|
||||
// Remove from hash
|
||||
HASH_DEL(_frameFileHash, f);
|
||||
free(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int frameFileUpdate(int frameFileIndex, int *videoHandle) {
|
||||
int i = 0;
|
||||
int frame = 0;
|
||||
FrameFileT *f = NULL;
|
||||
|
||||
// Get our framefile structure
|
||||
HASH_FIND_INT(_frameFileHash, &frameFileIndex, f);
|
||||
if (!f) utilDie("No framefile at index %d in frameFileUpdate.", frameFileIndex);
|
||||
|
||||
// Did the current video loop? If so, move to next video.
|
||||
for (i=0; i<f->count; i++) {
|
||||
if (f->files[i].videoHandle == *videoHandle) {
|
||||
frame = videoGetFrame(*videoHandle);
|
||||
if ((f->files[i].lastFramePlayed > frame) && (frame == 0)) {
|
||||
// Switch video files
|
||||
if (i == (f->count - 1)) {
|
||||
i = 0;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
_transferProperties(*videoHandle, f->files[i].videoHandle);
|
||||
*videoHandle = f->files[i].videoHandle;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
41
singe/frameFile.h
Normal file
41
singe/frameFile.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
*
|
||||
* Singe 2
|
||||
* Copyright (C) 2006-2020 Scott Duensing <scott@kangaroopunch.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef FRAMEFILE_H
|
||||
#define FRAMEFILE_H
|
||||
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
long frameFileGetFrame(int frameFileIndex, int videoHandle);
|
||||
int frameFileInit(void);
|
||||
int frameFileLoad(char *filename, char *indexPath, bool stretchVideo, SDL_Renderer *renderer);
|
||||
int frameFileSeek(int frameFileIndex, long seekFrame, int *videoHandle, int *actualFrame);
|
||||
int frameFileQuit(void);
|
||||
int frameFileUnload(int frameFileIndex);
|
||||
int frameFileUpdate(int frameFileIndex, int *videoHandle);
|
||||
|
||||
|
||||
#endif // FRAMEFILE_H
|
15
singe/main.c
15
singe/main.c
|
@ -32,6 +32,7 @@
|
|||
#include "stddclmr.h"
|
||||
#include "common.h"
|
||||
#include "util.h"
|
||||
#include "frameFile.h"
|
||||
#include "videoPlayer.h"
|
||||
#include "singe.h"
|
||||
#include "extensions.h"
|
||||
|
@ -327,8 +328,20 @@ int main(int argc, char *argv[]) {
|
|||
x++;
|
||||
}
|
||||
free(temp);
|
||||
// If we still don't have one, try a framefile
|
||||
if (!_confVideoFile) {
|
||||
_confVideoFile = utilCreateString("%s.txt", temp);
|
||||
if (!utilFileExists(_confVideoFile)) {
|
||||
free(_confVideoFile);
|
||||
_confVideoFile = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!_confVideoFile) showUsage(argv[0], "Unable to locate video.");
|
||||
// Is it a framefile?
|
||||
if (strncmp(utilGetFileExtension(_confVideoFile), "txt", 3) == 0) {
|
||||
_confIsFrameFile = true;
|
||||
}
|
||||
|
||||
// Do we need to generate a data directory name?
|
||||
if (_confDataDir) {
|
||||
|
@ -486,6 +499,7 @@ int main(int argc, char *argv[]) {
|
|||
if (err != 0) utilDie("%s", Mix_GetError());
|
||||
|
||||
// Start our video playback system
|
||||
if (frameFileInit()) utilDie("Unable to initialize framefile handler.");
|
||||
if (videoInit()) utilDie("Unable to initialize video player.");
|
||||
|
||||
// Finish our setup
|
||||
|
@ -495,6 +509,7 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
// Shutdown
|
||||
videoQuit();
|
||||
frameFileQuit();
|
||||
Mix_CloseAudio();
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_DestroyWindow(window);
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "thirdparty/manymouse/manymouse.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "frameFile.h"
|
||||
#include "videoPlayer.h"
|
||||
#include "singe.h"
|
||||
#include "font.h"
|
||||
|
@ -145,6 +146,7 @@ enum {
|
|||
char *_confVideoFile = NULL;
|
||||
char *_confScriptFile = NULL;
|
||||
char *_confDataDir = NULL;
|
||||
bool _confIsFrameFile = false;
|
||||
bool _confStretchVideo = false;
|
||||
bool _confNoMouse = false;
|
||||
bool _confNoStats = false;
|
||||
|
@ -175,6 +177,7 @@ static int _nextSoundId = 0;
|
|||
static int _nextFontId = 0;
|
||||
static int _effectsVolume = AUDIO_MAX_VOLUME;
|
||||
static int _keyboardMode = KEYBD_NORMAL;
|
||||
static int _frameFileHandle = -1;
|
||||
static int _videoHandle = -1;
|
||||
static int _fontQuality = 1;
|
||||
static int _mouseMode = MOUSE_SINGLE;
|
||||
|
@ -494,7 +497,11 @@ int apiDiscGetFrame(lua_State *L) {
|
|||
int frame = 0;
|
||||
|
||||
if (!_discStopped) {
|
||||
frame = videoGetFrame(_videoHandle);
|
||||
if (_confIsFrameFile) {
|
||||
frame = frameFileGetFrame(_frameFileHandle, _videoHandle);
|
||||
} else {
|
||||
frame = videoGetFrame(_videoHandle);
|
||||
}
|
||||
}
|
||||
|
||||
luaTrace(L, "discGetFrame", "%d", frame);
|
||||
|
@ -534,6 +541,7 @@ int apiDiscPlay(lua_State *L) {
|
|||
int apiDiscSearch(lua_State *L) {
|
||||
int n = lua_gettop(L);
|
||||
int frame = 0;
|
||||
int aFrame = 0;
|
||||
bool result = false;
|
||||
double d = 0;
|
||||
|
||||
|
@ -542,7 +550,11 @@ int apiDiscSearch(lua_State *L) {
|
|||
if (n == 1) {
|
||||
if (lua_isnumber(L, 1)) {
|
||||
d = lua_tonumber(L, 1); frame = (int)d;
|
||||
videoSeek(_videoHandle, frame);
|
||||
if (_confIsFrameFile) {
|
||||
frameFileSeek(_frameFileHandle, frame, &_videoHandle, &aFrame);
|
||||
} else {
|
||||
videoSeek(_videoHandle, frame);
|
||||
}
|
||||
videoPause(_videoHandle);
|
||||
_discStopped = false;
|
||||
result = true;
|
||||
|
@ -578,6 +590,7 @@ int apiDiscSetFps(lua_State *L) {
|
|||
int apiDiscSkipBackward(lua_State *L) {
|
||||
int n = lua_gettop(L);
|
||||
int frame = 0;
|
||||
int aFrame = 0;
|
||||
bool result = false;
|
||||
double d = 0;
|
||||
|
||||
|
@ -587,7 +600,11 @@ int apiDiscSkipBackward(lua_State *L) {
|
|||
if (n == 1) {
|
||||
if (lua_isnumber(L, 1)) {
|
||||
d = lua_tonumber(L, 1); frame = videoGetFrame(_videoHandle) - (int)d;
|
||||
videoSeek(_videoHandle, frame);
|
||||
if (_confIsFrameFile) {
|
||||
frameFileSeek(_frameFileHandle, frame, &_videoHandle, &aFrame);
|
||||
} else {
|
||||
videoSeek(_videoHandle, frame);
|
||||
}
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
@ -617,6 +634,7 @@ int apiDiscSkipBlanking(lua_State *L) {
|
|||
int apiDiscSkipForward(lua_State *L) {
|
||||
int n = lua_gettop(L);
|
||||
int frame = 0;
|
||||
int aFrame = 0;
|
||||
bool result = false;
|
||||
double d = 0;
|
||||
|
||||
|
@ -626,7 +644,11 @@ int apiDiscSkipForward(lua_State *L) {
|
|||
if (n == 1) {
|
||||
if (lua_isnumber(L, 1)) {
|
||||
d = lua_tonumber(L, 1); frame = videoGetFrame(_videoHandle) + (int)d;
|
||||
videoSeek(_videoHandle, frame);
|
||||
if (_confIsFrameFile) {
|
||||
frameFileSeek(_frameFileHandle, frame, &_videoHandle, &aFrame);
|
||||
} else {
|
||||
videoSeek(_videoHandle, frame);
|
||||
}
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
@ -648,6 +670,7 @@ int apiDiscSkipForward(lua_State *L) {
|
|||
int apiDiscSkipToFrame(lua_State *L) {
|
||||
int n = lua_gettop(L);
|
||||
int frame = 0;
|
||||
int aFrame = 0;
|
||||
bool result = false;
|
||||
double d = 0;
|
||||
|
||||
|
@ -656,7 +679,11 @@ int apiDiscSkipToFrame(lua_State *L) {
|
|||
if (n == 1) {
|
||||
if (lua_isnumber(L, 1)) {
|
||||
d = lua_tonumber(L, 1); frame = (int)d;
|
||||
videoSeek(_videoHandle, frame);
|
||||
if (_confIsFrameFile) {
|
||||
frameFileSeek(_frameFileHandle, frame, &_videoHandle, &aFrame);
|
||||
} else {
|
||||
videoSeek(_videoHandle, frame);
|
||||
}
|
||||
videoPlay(_videoHandle);
|
||||
_discStopped = false;
|
||||
result = true;
|
||||
|
@ -675,13 +702,18 @@ int apiDiscSkipToFrame(lua_State *L) {
|
|||
|
||||
int apiDiscStepBackward(lua_State *L) {
|
||||
int frame = 0;
|
||||
int aFrame = 0;
|
||||
|
||||
(void)L;
|
||||
|
||||
// No matter disc state, go back a frame. If playing, pause.
|
||||
|
||||
frame = videoGetFrame(_videoHandle) - 1;
|
||||
videoSeek(_videoHandle, frame);
|
||||
if (_confIsFrameFile) {
|
||||
frameFileSeek(_frameFileHandle, frame, &_videoHandle, &aFrame);
|
||||
} else {
|
||||
videoSeek(_videoHandle, frame);
|
||||
}
|
||||
videoPause(_videoHandle);
|
||||
luaTrace(L, "discStepBackward", "%d", frame);
|
||||
|
||||
|
@ -691,13 +723,18 @@ int apiDiscStepBackward(lua_State *L) {
|
|||
|
||||
int apiDiscStepForward(lua_State *L) {
|
||||
int frame = 0;
|
||||
int aFrame = 0;
|
||||
|
||||
(void)L;
|
||||
|
||||
// No matter disc state, go forward a frame. If playing, pause.
|
||||
|
||||
frame = videoGetFrame(_videoHandle) + 1;
|
||||
videoSeek(_videoHandle, frame);
|
||||
if (_confIsFrameFile) {
|
||||
frameFileSeek(_frameFileHandle, frame, &_videoHandle, &aFrame);
|
||||
} else {
|
||||
videoSeek(_videoHandle, frame);
|
||||
}
|
||||
videoPause(_videoHandle);
|
||||
luaTrace(L, "discStepForward", "%d", frame);
|
||||
|
||||
|
@ -2035,7 +2072,13 @@ void singe(SDL_Window *window, SDL_Renderer *renderer) {
|
|||
lua_register(_luaContext, "singeGetScriptPath", apiSingeGetScriptPath);
|
||||
|
||||
// Open main video file
|
||||
_videoHandle = videoLoad(_confVideoFile, _confDataDir, (bool)_confStretchVideo, _renderer);
|
||||
if (_confIsFrameFile) {
|
||||
_frameFileHandle = frameFileLoad(_confVideoFile, _confDataDir, (bool)_confStretchVideo, _renderer);
|
||||
if (_frameFileHandle < 0) utilDie("Unable to load framefile: %s", _confVideoFile);
|
||||
frameFileSeek(_frameFileHandle, 0, &_videoHandle, &thisFrame); // Fills in _videoHandle
|
||||
} else {
|
||||
_videoHandle = videoLoad(_confVideoFile, _confDataDir, (bool)_confStretchVideo, _renderer);
|
||||
}
|
||||
if (_videoHandle < 0) utilDie("Unable to load video file: %s", _confVideoFile);
|
||||
videoSetVolume(_videoHandle, _confVolumeVldp, _confVolumeVldp);
|
||||
|
||||
|
@ -2239,7 +2282,10 @@ void singe(SDL_Window *window, SDL_Renderer *renderer) {
|
|||
|
||||
// Update video
|
||||
thisFrame = videoUpdate(_videoHandle, &_videoTexture);
|
||||
if ((thisFrame != lastFrame) && (thisFrame>= 0)) {
|
||||
if (_confIsFrameFile) {
|
||||
frameFileUpdate(_frameFileHandle, &_videoHandle);
|
||||
}
|
||||
if ((thisFrame != lastFrame) && (thisFrame >= 0)) {
|
||||
lastFrame = thisFrame;
|
||||
_refreshDisplay = true;
|
||||
}
|
||||
|
@ -2306,7 +2352,11 @@ void singe(SDL_Window *window, SDL_Renderer *renderer) {
|
|||
}
|
||||
|
||||
// Unload video
|
||||
videoUnload(_videoHandle);
|
||||
if (_confIsFrameFile) {
|
||||
frameFileUnload(_frameFileHandle);
|
||||
} else {
|
||||
videoUnload(_videoHandle);
|
||||
}
|
||||
|
||||
// Stop mice
|
||||
SDL_ShowCursor(SDL_ENABLE);
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
extern char *_confVideoFile;
|
||||
extern char *_confScriptFile;
|
||||
extern char *_confDataDir;
|
||||
extern bool _confIsFrameFile;
|
||||
extern bool _confStretchVideo;
|
||||
extern bool _confNoMouse;
|
||||
extern bool _confNoStats;
|
||||
|
|
|
@ -81,16 +81,19 @@ QMAKE_CFLAGS += \
|
|||
|
||||
HEADERS += \
|
||||
$$MANYMOUSE_HEADERS \
|
||||
frameFile.h \
|
||||
stddclmr.h \
|
||||
thirdparty/uthash.h \
|
||||
common.h \
|
||||
util.h \
|
||||
videoPlayer.h \
|
||||
singe.h \
|
||||
extensions.h
|
||||
extensions.h \
|
||||
font.h
|
||||
|
||||
SOURCES += \
|
||||
$$MANYMOUSE_SOURCES \
|
||||
frameFile.c \
|
||||
util.c \
|
||||
videoPlayer.c \
|
||||
singe.c \
|
||||
|
@ -112,6 +115,10 @@ OTHER_FILES += \
|
|||
postLink.sh \
|
||||
buildRelease.sh
|
||||
|
||||
#linux:QMAKE_POST_LINK += bash $$PWD/postLink.sh "$$PWD" "$$DESTDIR" "$$TARGET"
|
||||
|
||||
# === Generate some data for our buildRelease script ===
|
||||
|
||||
FILEINFO = "SOURCES=\"$$SOURCES\"" \
|
||||
"HEADERS=\"$$HEADERS\"" \
|
||||
"LINUX_LIBS=\"$$LIBS\"" \
|
||||
|
@ -119,6 +126,3 @@ FILEINFO = "SOURCES=\"$$SOURCES\"" \
|
|||
"QMAKE_CFLAGS=\"$$QMAKE_CFLAGS\""
|
||||
|
||||
write_file("source.inc.sh", FILEINFO)
|
||||
|
||||
# Strip & UPX the final result
|
||||
#linux:QMAKE_POST_LINK += bash $$PWD/postLink.sh "$$PWD" "$$DESTDIR" "$$TARGET"
|
||||
|
|
93
singe/util.c
93
singe/util.c
|
@ -96,6 +96,30 @@ bool utilFileExists(char *filename) {
|
|||
}
|
||||
|
||||
|
||||
void utilFixPathSeparators(char **path) {
|
||||
|
||||
int i = 0;
|
||||
char *temp = *path;
|
||||
|
||||
// Flip path separators to whatever our OS wants
|
||||
while (temp[i] != 0) {
|
||||
if (temp[i] == '\\' || temp[i] == '/') {
|
||||
temp[i] = utilGetPathSeparator();
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// Does this string end with a path separator?
|
||||
if (temp[strlen(temp) - 1] != utilGetPathSeparator()) {
|
||||
// No - append one.
|
||||
temp = realloc(temp, sizeof(char) * (strlen(temp) + 1));
|
||||
temp[strlen(temp) - 1] = utilGetPathSeparator();
|
||||
temp[strlen(temp)] = 0;
|
||||
*path = temp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char *utilGetFileExtension(char *filename) {
|
||||
char *start = filename + strlen(filename);
|
||||
int x;
|
||||
|
@ -149,6 +173,75 @@ bool utilPathExists(char *pathname) {
|
|||
}
|
||||
|
||||
|
||||
char *utilReadFile(char *filename, size_t *bytes) {
|
||||
char *data = NULL;
|
||||
FILE *in = fopen(filename, "rb");
|
||||
|
||||
*bytes = 0;
|
||||
|
||||
if (in) {
|
||||
fseek(in, 0, SEEK_END);
|
||||
*bytes = ftell(in);
|
||||
fseek(in, 0, SEEK_SET);
|
||||
data = malloc(sizeof(char) * (*bytes));
|
||||
fread(data, sizeof(char), *bytes, in);
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
char *utilReadLine(char *haystack, size_t length, char **offset) {
|
||||
size_t bytes = 0;
|
||||
char *temp = *offset;
|
||||
char *tail = temp;
|
||||
char *result = NULL;
|
||||
|
||||
// They didn't know where to start
|
||||
if (temp == NULL) {
|
||||
temp = haystack;
|
||||
tail = temp;
|
||||
}
|
||||
|
||||
// Is there still data to read?
|
||||
while ((size_t)(tail - haystack) < length) {
|
||||
// Is this the end of a line?
|
||||
if ((tail[0] == 10) || (tail[0] == 13)) {
|
||||
// Yep!
|
||||
bytes = tail - temp + 1;
|
||||
result = malloc(sizeof(char) * bytes);
|
||||
memcpy(result, temp, bytes - 1);
|
||||
result[bytes - 1] = 0;
|
||||
// Read past any additional CR/LFs
|
||||
while ((tail[0] == 10) || (tail[0] == 13)) {
|
||||
tail++;
|
||||
}
|
||||
// Return where we left off
|
||||
temp = tail;
|
||||
*offset = temp;
|
||||
return result;
|
||||
}
|
||||
// Next character
|
||||
tail++;
|
||||
}
|
||||
|
||||
// Was there data at the end of the block with no CR/LF?
|
||||
if (tail > temp) {
|
||||
// Yep. Treat it as a line.
|
||||
bytes = tail - temp + 1;
|
||||
result = malloc(sizeof(char) * bytes);
|
||||
memcpy(result, temp, bytes - 1);
|
||||
result[bytes] = 0;
|
||||
temp = tail;
|
||||
*offset = temp;
|
||||
}
|
||||
|
||||
// Didn't find anything
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void utilRedirectConsole(void) {
|
||||
#ifdef _WIN32
|
||||
// http://dslweb.nwnexus.com/~ast/dload/guicon.htm
|
||||
|
|
|
@ -38,10 +38,13 @@ char *utilCreateString(char *format, ...);
|
|||
char *utilCreateStringVArgs(char *format, va_list args);
|
||||
void utilDie(char *fmt, ...);
|
||||
bool utilFileExists(char *filename);
|
||||
void utilFixPathSeparators(char **path);
|
||||
char *utilGetFileExtension(char *filename);
|
||||
char *utilGetLastPathComponent(char *pathname);
|
||||
char utilGetPathSeparator(void);
|
||||
bool utilPathExists(char *pathname);
|
||||
char *utilReadFile(char *filename, size_t *bytes);
|
||||
char *utilReadLine(char *haystack, size_t length, char **offset);
|
||||
void utilRedirectConsole(void);
|
||||
void utilSay(char *fmt, ...);
|
||||
void utilTrace(char *fmt, ...);
|
||||
|
|
|
@ -77,8 +77,10 @@ typedef struct VideoPlayerS {
|
|||
#pragma GCC diagnostic pop
|
||||
|
||||
|
||||
void _dequeueVideoAudio(int channel, void *stream, int len, void *udata);
|
||||
int FFMS_CC _indexCallBack(int64_t Current, int64_t Total, void *ICPrivate);
|
||||
FFMS_Index *_createIndex(char *filename, char *indexPath, bool hasVideo, bool hasAudio, VideoPlayerT *v);
|
||||
void _dequeueVideoAudio(int channel, void *stream, int len, void *udata);
|
||||
int FFMS_CC _indexCallBack(int64_t Current, int64_t Total, void *ICPrivate);
|
||||
int _loadVideoAndAudio(char *vFilename, char *aFilename, char *indexPath, bool stretchVideo, SDL_Renderer *renderer);
|
||||
|
||||
|
||||
static VideoPlayerT *_videoPlayerHash = NULL;
|
||||
|
@ -147,104 +149,10 @@ int FFMS_CC _indexCallBack(int64_t current, int64_t total, void *ICPrivate) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int videoInit(void) {
|
||||
|
||||
int channels = _mixChannels;
|
||||
|
||||
// Start FFMS
|
||||
FFMS_Init(0, 0);
|
||||
|
||||
// Fetch mixer settings
|
||||
if (!Mix_QuerySpec(&_mixRate, &_mixFormat, &channels)) utilDie("%s", Mix_GetError());
|
||||
_mixChannels = (Uint8)channels;
|
||||
|
||||
// Volume only works with MIX_DEFAULT_FORMAT
|
||||
if (_mixFormat != MIX_DEFAULT_FORMAT) utilDie("videoInit: Only MIX_DEFAULT_FORMAT audio is supported.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int videoIsPlaying(int playerIndex) {
|
||||
VideoPlayerT *v = NULL;
|
||||
|
||||
// Get our player structure
|
||||
HASH_FIND_INT(_videoPlayerHash, &playerIndex, v);
|
||||
if (!v) utilDie("No video player at index %d in videoIsPlaying.", playerIndex);
|
||||
|
||||
return v->playing;
|
||||
}
|
||||
|
||||
|
||||
int videoGetFrame(int playerIndex) {
|
||||
VideoPlayerT *v = NULL;
|
||||
|
||||
// Get our player structure
|
||||
HASH_FIND_INT(_videoPlayerHash, &playerIndex, v);
|
||||
if (!v) utilDie("No video player at index %d in videoGetHeight.", playerIndex);
|
||||
|
||||
return v->frame;
|
||||
}
|
||||
|
||||
|
||||
int videoGetHeight(int playerIndex) {
|
||||
VideoPlayerT *v = NULL;
|
||||
|
||||
// Get our player structure
|
||||
HASH_FIND_INT(_videoPlayerHash, &playerIndex, v);
|
||||
if (!v) utilDie("No video player at index %d in videoGetHeight.", playerIndex);
|
||||
|
||||
return v->propFrame->EncodedHeight;
|
||||
}
|
||||
|
||||
|
||||
int videoGetWidth(int playerIndex) {
|
||||
VideoPlayerT *v = NULL;
|
||||
|
||||
// Get our player structure
|
||||
HASH_FIND_INT(_videoPlayerHash, &playerIndex, v);
|
||||
if (!v) utilDie("No video player at index %d in videoGetWidth.", playerIndex);
|
||||
|
||||
return v->propFrame->EncodedWidth;
|
||||
}
|
||||
|
||||
|
||||
int videoGetVolume(int playerIndex, int *leftPercent, int *rightPercent) {
|
||||
VideoPlayerT *v = NULL;
|
||||
|
||||
// Get our player structure
|
||||
HASH_FIND_INT(_videoPlayerHash, &playerIndex, v);
|
||||
if (!v) utilDie("No video player at index %d in videoGetVolume.", playerIndex);
|
||||
|
||||
if (leftPercent != NULL) *leftPercent = v->volumeLeft;
|
||||
if (rightPercent != NULL) *rightPercent = v->volumeRight;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int videoLoad(char *filename, char *indexPath, bool stretchVideo, SDL_Renderer *renderer) {
|
||||
FFMS_Index *_createIndex(char *filename, char *indexPath, bool hasVideo, bool hasAudio, VideoPlayerT *v) {
|
||||
char indexName[1024];
|
||||
int pixelFormats[2];
|
||||
int result = -1;
|
||||
FFMS_Index *index = NULL;
|
||||
FFMS_Indexer *indexer = NULL;
|
||||
VideoPlayerT *v = NULL;
|
||||
|
||||
// Create new videoPlayer
|
||||
v = calloc(1, sizeof(VideoPlayerT));
|
||||
if (!v) utilDie("Unable to allocate new video player.");
|
||||
|
||||
// Set some starting values
|
||||
v->audioTrack = -1;
|
||||
v->videoTrack = -1;
|
||||
v->audioSilenceChannel = -1;
|
||||
v->playing = false; // Start paused
|
||||
v->errInfo.Buffer = v->errMsg;
|
||||
v->errInfo.BufferSize = sizeof(v->errMsg);
|
||||
v->errInfo.ErrorType = FFMS_ERROR_SUCCESS;
|
||||
v->errInfo.SubType = FFMS_ERROR_SUCCESS;
|
||||
|
||||
// Index file
|
||||
snprintf(indexName, 1024, "%s%c%s.index", indexPath, utilGetPathSeparator(), utilGetLastPathComponent(filename));
|
||||
|
@ -264,8 +172,8 @@ int videoLoad(char *filename, char *indexPath, bool stretchVideo, SDL_Renderer *
|
|||
utilSay("Creating new index.");
|
||||
indexer = FFMS_CreateIndexer(filename, &v->errInfo);
|
||||
if (indexer == NULL) utilDie("%s", v->errInfo.Buffer);
|
||||
FFMS_TrackTypeIndexSettings(indexer, FFMS_TYPE_AUDIO, 1, 0);
|
||||
FFMS_TrackTypeIndexSettings(indexer, FFMS_TYPE_VIDEO, 1, 0);
|
||||
if (hasAudio) FFMS_TrackTypeIndexSettings(indexer, FFMS_TYPE_AUDIO, 1, 0);
|
||||
if (hasVideo) FFMS_TrackTypeIndexSettings(indexer, FFMS_TYPE_VIDEO, 1, 0);
|
||||
_indexCallBack(0, 0, v);
|
||||
FFMS_SetProgressCallback(indexer, _indexCallBack, v);
|
||||
index = FFMS_DoIndexing2(indexer, FFMS_IEH_ABORT, &v->errInfo);
|
||||
|
@ -273,10 +181,43 @@ int videoLoad(char *filename, char *indexPath, bool stretchVideo, SDL_Renderer *
|
|||
if (FFMS_WriteIndex(indexName, index, &v->errInfo)) utilDie("%s", v->errInfo.Buffer);
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
int _loadVideoAndAudio(char *vFilename, char *aFilename, char *indexPath, bool stretchVideo, SDL_Renderer *renderer) {
|
||||
int pixelFormats[2];
|
||||
int result = -1;
|
||||
FFMS_Index *vIndex = NULL;
|
||||
FFMS_Index *aIndex = NULL;
|
||||
VideoPlayerT *v = NULL;
|
||||
|
||||
// Create new videoPlayer
|
||||
v = calloc(1, sizeof(VideoPlayerT));
|
||||
if (!v) utilDie("Unable to allocate new video player.");
|
||||
|
||||
// Set some starting values
|
||||
v->audioTrack = -1;
|
||||
v->videoTrack = -1;
|
||||
v->audioSilenceChannel = -1;
|
||||
v->playing = false; // Start paused
|
||||
v->errInfo.Buffer = v->errMsg;
|
||||
v->errInfo.BufferSize = sizeof(v->errMsg);
|
||||
v->errInfo.ErrorType = FFMS_ERROR_SUCCESS;
|
||||
v->errInfo.SubType = FFMS_ERROR_SUCCESS;
|
||||
|
||||
if (aFilename) {
|
||||
vIndex = _createIndex(vFilename, indexPath, true, false, v);
|
||||
aIndex = _createIndex(aFilename, indexPath, false, true, v);
|
||||
} else {
|
||||
vIndex = _createIndex(vFilename, indexPath, true, true, v);
|
||||
aIndex = vIndex;
|
||||
}
|
||||
|
||||
// Find video track
|
||||
v->videoTrack = FFMS_GetFirstTrackOfType(index, FFMS_TYPE_VIDEO, &v->errInfo);
|
||||
v->videoTrack = FFMS_GetFirstTrackOfType(vIndex, FFMS_TYPE_VIDEO, &v->errInfo);
|
||||
if (v->videoTrack < 0) utilDie("%s", v->errInfo.Buffer);
|
||||
v->videoSource = FFMS_CreateVideoSource(filename, v->videoTrack, index, 1, FFMS_SEEK_NORMAL, &v->errInfo);
|
||||
v->videoSource = FFMS_CreateVideoSource(vFilename, v->videoTrack, vIndex, 1, FFMS_SEEK_NORMAL, &v->errInfo);
|
||||
if (v->videoSource == NULL) utilDie("%s", v->errInfo.Buffer);
|
||||
|
||||
// Get video properties
|
||||
|
@ -291,20 +232,24 @@ int videoLoad(char *filename, char *indexPath, bool stretchVideo, SDL_Renderer *
|
|||
if (FFMS_SetOutputFormatV2(v->videoSource, pixelFormats, v->propFrame->EncodedWidth, v->propFrame->EncodedHeight, FFMS_RESIZER_BICUBIC, &v->errInfo)) utilDie("%s", v->errInfo.Buffer);
|
||||
|
||||
// Find audio track
|
||||
v->audioTrack = FFMS_GetFirstTrackOfType(index, FFMS_TYPE_AUDIO, &v->errInfo);
|
||||
v->audioTrack = FFMS_GetFirstTrackOfType(aIndex, FFMS_TYPE_AUDIO, &v->errInfo);
|
||||
if (v->audioTrack < 0) utilDie("%s", v->errInfo.Buffer);
|
||||
v->audioSource = FFMS_CreateAudioSource(filename, v->audioTrack, index, FFMS_DELAY_FIRST_VIDEO_TRACK, &v->errInfo);
|
||||
v->audioSource = FFMS_CreateAudioSource(aFilename, v->audioTrack, aIndex, FFMS_DELAY_FIRST_VIDEO_TRACK, &v->errInfo);
|
||||
if (v->audioSource == NULL) utilDie("%s", v->errInfo.Buffer);
|
||||
|
||||
// Get audio properties
|
||||
v->audioProps = FFMS_GetAudioProperties(v->audioSource);
|
||||
|
||||
// Index is now part of audioSource & videoSource, so release this one
|
||||
FFMS_DestroyIndex(index);
|
||||
// Indicies are now part of audioSource & videoSource, so release these
|
||||
FFMS_DestroyIndex(vIndex);
|
||||
vIndex = NULL;
|
||||
if (aIndex) {
|
||||
FFMS_DestroyIndex(aIndex);
|
||||
aIndex = NULL;
|
||||
}
|
||||
|
||||
// Create video texture
|
||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
|
||||
//v->videoTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_BGRA32, SDL_TEXTUREACCESS_STREAMING, v->propFrame->EncodedWidth, v->propFrame->EncodedHeight);
|
||||
v->videoTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_BGRA32, SDL_TEXTUREACCESS_TARGET, v->propFrame->EncodedWidth, v->propFrame->EncodedHeight);
|
||||
if (v->videoTexture == NULL) utilDie("%s", SDL_GetError());
|
||||
if (!stretchVideo) {
|
||||
|
@ -387,6 +332,104 @@ int videoLoad(char *filename, char *indexPath, bool stretchVideo, SDL_Renderer *
|
|||
}
|
||||
|
||||
|
||||
int videoInit(void) {
|
||||
|
||||
int channels = _mixChannels;
|
||||
|
||||
// Start FFMS
|
||||
FFMS_Init(0, 0);
|
||||
|
||||
// Fetch mixer settings
|
||||
if (!Mix_QuerySpec(&_mixRate, &_mixFormat, &channels)) utilDie("%s", Mix_GetError());
|
||||
_mixChannels = (Uint8)channels;
|
||||
|
||||
// Volume only works with MIX_DEFAULT_FORMAT
|
||||
if (_mixFormat != MIX_DEFAULT_FORMAT) utilDie("videoInit: Only MIX_DEFAULT_FORMAT audio is supported.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int videoIsPlaying(int playerIndex) {
|
||||
VideoPlayerT *v = NULL;
|
||||
|
||||
// Get our player structure
|
||||
HASH_FIND_INT(_videoPlayerHash, &playerIndex, v);
|
||||
if (!v) utilDie("No video player at index %d in videoIsPlaying.", playerIndex);
|
||||
|
||||
return v->playing;
|
||||
}
|
||||
|
||||
|
||||
int videoGetFrame(int playerIndex) {
|
||||
VideoPlayerT *v = NULL;
|
||||
|
||||
// Get our player structure
|
||||
HASH_FIND_INT(_videoPlayerHash, &playerIndex, v);
|
||||
if (!v) utilDie("No video player at index %d in videoGetFrame.", playerIndex);
|
||||
|
||||
return v->frame;
|
||||
}
|
||||
|
||||
|
||||
int videoGetFrameCount(int playerIndex) {
|
||||
VideoPlayerT *v = NULL;
|
||||
|
||||
// Get our player structure
|
||||
HASH_FIND_INT(_videoPlayerHash, &playerIndex, v);
|
||||
if (!v) utilDie("No video player at index %d in videoGetFrameCount.", playerIndex);
|
||||
|
||||
return v->videoProps->NumFrames;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int videoGetHeight(int playerIndex) {
|
||||
VideoPlayerT *v = NULL;
|
||||
|
||||
// Get our player structure
|
||||
HASH_FIND_INT(_videoPlayerHash, &playerIndex, v);
|
||||
if (!v) utilDie("No video player at index %d in videoGetHeight.", playerIndex);
|
||||
|
||||
return v->propFrame->EncodedHeight;
|
||||
}
|
||||
|
||||
|
||||
int videoGetWidth(int playerIndex) {
|
||||
VideoPlayerT *v = NULL;
|
||||
|
||||
// Get our player structure
|
||||
HASH_FIND_INT(_videoPlayerHash, &playerIndex, v);
|
||||
if (!v) utilDie("No video player at index %d in videoGetWidth.", playerIndex);
|
||||
|
||||
return v->propFrame->EncodedWidth;
|
||||
}
|
||||
|
||||
|
||||
int videoGetVolume(int playerIndex, int *leftPercent, int *rightPercent) {
|
||||
VideoPlayerT *v = NULL;
|
||||
|
||||
// Get our player structure
|
||||
HASH_FIND_INT(_videoPlayerHash, &playerIndex, v);
|
||||
if (!v) utilDie("No video player at index %d in videoGetVolume.", playerIndex);
|
||||
|
||||
if (leftPercent != NULL) *leftPercent = v->volumeLeft;
|
||||
if (rightPercent != NULL) *rightPercent = v->volumeRight;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int videoLoad(char *filename, char *indexPath, bool stretchVideo, SDL_Renderer *renderer) {
|
||||
return _loadVideoAndAudio(filename, NULL, indexPath, stretchVideo, renderer);
|
||||
}
|
||||
|
||||
|
||||
int videoLoadWithAudio(char *vFilename, char *aFilename, char *indexPath, bool stretchVideo, SDL_Renderer *renderer) {
|
||||
return _loadVideoAndAudio(vFilename, aFilename, indexPath, stretchVideo, renderer);
|
||||
}
|
||||
|
||||
|
||||
int videoPause(int playerIndex) {
|
||||
VideoPlayerT *v = NULL;
|
||||
|
||||
|
|
|
@ -32,10 +32,12 @@
|
|||
int videoInit(void);
|
||||
int videoIsPlaying(int playerIndex);
|
||||
int videoGetFrame(int playerIndex);
|
||||
int videoGetFrameCount(int playerIndex);
|
||||
int videoGetHeight(int playerIndex);
|
||||
int videoGetWidth(int playerIndex);
|
||||
int videoGetVolume(int playerIndex, int *leftPercent, int *rightPercent);
|
||||
int videoLoad(char *filename, char *indexPath, bool stretchVideo, SDL_Renderer *renderer);
|
||||
int videoLoadWithAudio(char *vFilename, char *aFilename, char *indexPath, bool stretchVideo, SDL_Renderer *renderer);
|
||||
int videoPause(int playerIndex);
|
||||
int videoPlay(int playerIndex);
|
||||
int videoQuit(void);
|
||||
|
|
Loading…
Add table
Reference in a new issue