Initial framefile and split m2v/ogg support.

This commit is contained in:
Scott Duensing 2020-01-05 18:29:52 -06:00
parent ece26e81ff
commit bd0ab45792
10 changed files with 668 additions and 120 deletions

296
singe/frameFile.c Normal file
View 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
View 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

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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"

View file

@ -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

View file

@ -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, ...);

View file

@ -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;

View file

@ -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);