Multiple audio tracks now supported.

This commit is contained in:
Scott Duensing 2023-11-30 20:48:13 -06:00
parent 191001e3a6
commit b0a66bf4a4
4 changed files with 353 additions and 77 deletions

View file

@ -48,7 +48,7 @@ function buildAll() {
mkdir -p ${G_GENERATED} mkdir -p ${G_GENERATED}
if [[ 1 == 1 ]]; then if [[ 0 == 1 ]]; then
pushd thirdparty/bzip2 pushd thirdparty/bzip2
clearAndEnterBuild clearAndEnterBuild
cmake ${COMMON} \ cmake ${COMMON} \
@ -94,7 +94,6 @@ if [[ 1 == 1 ]]; then
.. ..
make install make install
popd popd
fi
pushd thirdparty/SDL2_image pushd thirdparty/SDL2_image
clearAndEnterBuild clearAndEnterBuild
@ -132,7 +131,6 @@ fi
cp -f external/libwebp/libwebpdemux.a "${G_TARGET}/lib/." cp -f external/libwebp/libwebpdemux.a "${G_TARGET}/lib/."
popd popd
if [[ 1 == 1 ]]; then
pushd thirdparty/SDL2_mixer pushd thirdparty/SDL2_mixer
clearAndEnterBuild clearAndEnterBuild
cmake ${COMMON} \ cmake ${COMMON} \
@ -503,7 +501,7 @@ sudo apt-get install -y \
buildAll linux x86_64 2>&1 | tee ${G_BUILDDIR}/linux-x86_64.log buildAll linux x86_64 2>&1 | tee ${G_BUILDDIR}/linux-x86_64.log
buildAll windows x86_64 2>&1 | tee ${G_BUILDDIR}/windows-x86_64.log #buildAll windows x86_64 2>&1 | tee ${G_BUILDDIR}/windows-x86_64.log
#buildAll linux x86 #buildAll linux x86
#buildAll macos aarch64 #buildAll macos aarch64

View file

@ -63,6 +63,9 @@ LSEC_API int luaopen_ssl_config(lua_State *L);
//#define DEBUG_TOOLS //#define DEBUG_TOOLS
#define INDEX_DISPLAY_START -1
#define INDEX_DISPLAY_STOP -2
#define AUDIO_MAX_VOLUME 63 #define AUDIO_MAX_VOLUME 63
#define MAX_TITLE_LENGTH 1024 #define MAX_TITLE_LENGTH 1024
#define MAX_MICE 4 #define MAX_MICE 4
@ -197,7 +200,7 @@ enum {
INPUT_QUIT, INPUT_QUIT,
INPUT_PAUSE, INPUT_PAUSE,
INPUT_CONSOLE, INPUT_CONSOLE,
// Added in Singe 2.x // Added in Singe 2.00
INPUT_ACTION_4, INPUT_ACTION_4,
INPUT_TILT, INPUT_TILT,
INPUT_GRAB, INPUT_GRAB,
@ -304,6 +307,8 @@ int32_t apiDebugPrint(lua_State *L);
int32_t apiDiscAudio(lua_State *L); int32_t apiDiscAudio(lua_State *L);
int32_t apiDiscChangeSpeed(lua_State *L); int32_t apiDiscChangeSpeed(lua_State *L);
int32_t apiDiscGetAudioTrack(lua_State *L);
int32_t apiDiscGetAudioTracks(lua_State *L);
int32_t apiDiscGetFrame(lua_State *L); int32_t apiDiscGetFrame(lua_State *L);
int32_t apiDiscGetHeight(lua_State *L); int32_t apiDiscGetHeight(lua_State *L);
int32_t apiDiscGetState(lua_State *L); int32_t apiDiscGetState(lua_State *L);
@ -313,6 +318,7 @@ int32_t apiDiscPauseAtFrame(lua_State *L);
int32_t apiDiscPlay(lua_State *L); int32_t apiDiscPlay(lua_State *L);
int32_t apiDiscSearch(lua_State *L); int32_t apiDiscSearch(lua_State *L);
int32_t apiDiscSearchBlanking(lua_State *L); int32_t apiDiscSearchBlanking(lua_State *L);
int32_t apiDiscSetAudioTrack(lua_State *L);
int32_t apiDiscSetFps(lua_State *L); int32_t apiDiscSetFps(lua_State *L);
int32_t apiDiscSkipBackward(lua_State *L); int32_t apiDiscSkipBackward(lua_State *L);
int32_t apiDiscSkipBlanking(lua_State *L); int32_t apiDiscSkipBlanking(lua_State *L);
@ -389,6 +395,8 @@ int32_t apiSpriteScale(lua_State *L);
int32_t apiSpriteUnload(lua_State *L); int32_t apiSpriteUnload(lua_State *L);
int32_t apiVideoDraw(lua_State *L); int32_t apiVideoDraw(lua_State *L);
int32_t apiVideoGetAudioTrack(lua_State *L);
int32_t apiVideoGetAudioTracks(lua_State *L);
int32_t apiVideoGetFrame(lua_State *L); int32_t apiVideoGetFrame(lua_State *L);
int32_t apiVideoGetFrameCount(lua_State *L); int32_t apiVideoGetFrameCount(lua_State *L);
int32_t apiVideoGetHeight(lua_State *L); int32_t apiVideoGetHeight(lua_State *L);
@ -399,6 +407,7 @@ int32_t apiVideoLoad(lua_State *L);
int32_t apiVideoPause(lua_State *L); int32_t apiVideoPause(lua_State *L);
int32_t apiVideoPlay(lua_State *L); int32_t apiVideoPlay(lua_State *L);
int32_t apiVideoSeek(lua_State *L); int32_t apiVideoSeek(lua_State *L);
int32_t apiVideoSetAudioTrack(lua_State *L);
int32_t apiVideoSetVolume(lua_State *L); int32_t apiVideoSetVolume(lua_State *L);
int32_t apiVideoUnload(lua_State *L); int32_t apiVideoUnload(lua_State *L);
@ -621,6 +630,50 @@ int32_t apiDiscChangeSpeed(lua_State *L) {
} }
int32_t apiDiscGetAudioTrack(lua_State *L) {
bool result = false;
int64_t r = 0;
(void)L;
if (_global.videoHandle >= 0) {
r = videoGetAudioTrack(_global.videoHandle);
result = true;
}
if (result) {
luaTrace(L, "discGetAudioTrack", "%ld", r);
} else {
luaDie(L, "discGetAudioTrack", "Failed!");
}
lua_pushnumber(L, r);
return 1;
}
int32_t apiDiscGetAudioTracks(lua_State *L) {
bool result = false;
int64_t r = 0;
(void)L;
if (_global.videoHandle >= 0) {
r = videoGetAudioTracks(_global.videoHandle);
result = true;
}
if (result) {
luaTrace(L, "discGetAudioTracks", "%ld", r);
} else {
luaDie(L, "discGetAudioTracks", "Failed!");
}
lua_pushnumber(L, r);
return 1;
}
int32_t apiDiscGetFrame(lua_State *L) { int32_t apiDiscGetFrame(lua_State *L) {
int64_t frame = 0; int64_t frame = 0;
@ -707,6 +760,36 @@ int32_t apiDiscSearchBlanking(lua_State *L) {
} }
int32_t apiDiscSetAudioTrack(lua_State *L) {
int32_t n = lua_gettop(L);
bool result = false;
int64_t track = 0;
double d;
if (n == 1) {
if (lua_isnumber(L, 1)) {
d = lua_tonumber(L, 1); track = (int32_t)d;
if (_global.videoHandle >= 0) {
if ((track >= 0) && (track < videoGetAudioTracks(_global.videoHandle))) {
videoSetAudioTrack(_global.videoHandle, track);
} else {
luaDie(L, "discSetAudioTrack", "Invalid audio track in apiDiscSetAudioTrack.");
}
result = true;
}
}
}
if (result) {
luaTrace(L, "discSetAudioTrack", "%d", track);
} else {
luaDie(L, "discSetAudioTrack", "Failed!");
}
return 0;
}
int32_t apiDiscSetFps(lua_State *L) { int32_t apiDiscSetFps(lua_State *L) {
(void)L; (void)L;
//***REMOVED*** //***REMOVED***
@ -2251,6 +2334,66 @@ int32_t apiVideoDraw(lua_State *L) {
} }
int32_t apiVideoGetAudioTrack(lua_State *L) {
int32_t n = lua_gettop(L);
bool result = false;
int64_t r = 0;
int32_t id = -1;
double d;
VideoT *video = NULL;
if (n == 1) {
if (lua_isnumber(L, 1)) {
d = lua_tonumber(L, 1); id = (int32_t)d;
// Get our video structure
HASH_FIND_INT(_global.videoList, &id, video);
if (!video) luaDie(L, "videoGetAudioTrack", "No video at index %d in apiVideoGetAudioTrack.", id);
r = videoGetAudioTrack(video->handle);
result = true;
}
}
if (result) {
luaTrace(L, "videoGetAudioTrack", "%d %ld", id, r);
} else {
luaDie(L, "videoGetAudioTrack", "Failed!");
}
lua_pushnumber(L, r);
return 1;
}
int32_t apiVideoGetAudioTracks(lua_State *L) {
int32_t n = lua_gettop(L);
bool result = false;
int64_t r = 0;
int32_t id = -1;
double d;
VideoT *video = NULL;
if (n == 1) {
if (lua_isnumber(L, 1)) {
d = lua_tonumber(L, 1); id = (int32_t)d;
// Get our video structure
HASH_FIND_INT(_global.videoList, &id, video);
if (!video) luaDie(L, "videoGetAudioTracks", "No video at index %d in apiVideoGetAudioTracks.", id);
r = videoGetAudioTracks(video->handle);
result = true;
}
}
if (result) {
luaTrace(L, "videoGetAudioTracks", "%d %ld", id, r);
} else {
luaDie(L, "videoGetAudioTracks", "Failed!");
}
lua_pushnumber(L, r);
return 1;
}
int32_t apiVideoGetFrame(lua_State *L) { int32_t apiVideoGetFrame(lua_State *L) {
int32_t n = lua_gettop(L); int32_t n = lua_gettop(L);
bool result = false; bool result = false;
@ -2536,7 +2679,7 @@ int32_t apiVideoPlay(lua_State *L) {
} }
int32_t apiVideoSeek(lua_State *L) { int32_t apiVideoSeek(lua_State *L) {
int32_t n = lua_gettop(L); int32_t n = lua_gettop(L);
bool result = false; bool result = false;
int32_t id = -1; int32_t id = -1;
@ -2568,7 +2711,43 @@ int32_t apiVideoSeek(lua_State *L) {
} }
int32_t apiVideoSetVolume(lua_State *L) { int32_t apiVideoSetAudioTrack(lua_State *L) {
int32_t n = lua_gettop(L);
bool result = false;
int32_t id = -1;
int64_t track = 0;
double d;
VideoT *video = NULL;
if (n == 2) {
if (lua_isnumber(L, 1)) {
if (lua_isnumber(L, 2)) {
d = lua_tonumber(L, 1); id = (int32_t)d;
d = lua_tonumber(L, 2); track = (int32_t)d;
// Get our video structure
HASH_FIND_INT(_global.videoList, &id, video);
if (!video) luaDie(L, "videoSetAudioTrack", "No video at index %d in apiVideoSetAudioTrack.", id);
if ((track >= 0) && (track < videoGetAudioTracks(video->handle))) {
videoSetAudioTrack(video->handle, track);
} else {
luaDie(L, "videoSetAudioTrack", "Invalid audio track in video at index %d in apiVideoSetAudioTrack.", id);
}
result = true;
}
}
}
if (result) {
luaTrace(L, "videoSetAudioTrack", "%d %d", id, track);
} else {
luaDie(L, "videoSetAudioTrack", "Failed!");
}
return 0;
}
int32_t apiVideoSetVolume(lua_State *L) {
int32_t n = lua_gettop(L); int32_t n = lua_gettop(L);
bool result = false; bool result = false;
int32_t id = -1; int32_t id = -1;
@ -3303,7 +3482,7 @@ void doIndexDisplay(int32_t percent) {
// 'percent' 0 to 100 is the actual display. // 'percent' 0 to 100 is the actual display.
// 'percent' -2 shuts the display down. // 'percent' -2 shuts the display down.
if (percent == -1) { if (percent == INDEX_DISPLAY_START) {
// Setup // Setup
SDL_RenderGetLogicalSize(_global.renderer, &oldW, &oldH); SDL_RenderGetLogicalSize(_global.renderer, &oldW, &oldH);
SDL_RenderSetLogicalSize(_global.renderer, screenW, screenH); SDL_RenderSetLogicalSize(_global.renderer, screenW, screenH);
@ -3328,7 +3507,7 @@ void doIndexDisplay(int32_t percent) {
return; return;
} }
if (percent == -2) { if (percent == INDEX_DISPLAY_STOP) {
// Shutdown // Shutdown
SDL_DestroyTexture(texDisc); SDL_DestroyTexture(texDisc);
SDL_DestroyTexture(texGlass); SDL_DestroyTexture(texGlass);
@ -3949,6 +4128,8 @@ void singe(SDL_Window *window, SDL_Renderer *renderer, ConfigT *conf) {
lua_register(_global.luaContext, "discAudio", apiDiscAudio); lua_register(_global.luaContext, "discAudio", apiDiscAudio);
lua_register(_global.luaContext, "discChangeSpeed", apiDiscChangeSpeed); lua_register(_global.luaContext, "discChangeSpeed", apiDiscChangeSpeed);
lua_register(_global.luaContext, "discGetAudioTrack", apiDiscGetAudioTrack);
lua_register(_global.luaContext, "discGetAudioTracks", apiDiscGetAudioTracks);
lua_register(_global.luaContext, "discGetFrame", apiDiscGetFrame); lua_register(_global.luaContext, "discGetFrame", apiDiscGetFrame);
lua_register(_global.luaContext, "discGetHeight", apiDiscGetHeight); lua_register(_global.luaContext, "discGetHeight", apiDiscGetHeight);
lua_register(_global.luaContext, "discGetState", apiDiscGetState); lua_register(_global.luaContext, "discGetState", apiDiscGetState);
@ -3958,6 +4139,7 @@ void singe(SDL_Window *window, SDL_Renderer *renderer, ConfigT *conf) {
lua_register(_global.luaContext, "discPlay", apiDiscPlay); lua_register(_global.luaContext, "discPlay", apiDiscPlay);
lua_register(_global.luaContext, "discSearch", apiDiscSearch); lua_register(_global.luaContext, "discSearch", apiDiscSearch);
lua_register(_global.luaContext, "discSearchBlanking", apiDiscSearchBlanking); lua_register(_global.luaContext, "discSearchBlanking", apiDiscSearchBlanking);
lua_register(_global.luaContext, "discSetAudioTrack", apiDiscSetAudioTrack);
lua_register(_global.luaContext, "discSetFPS", apiDiscSetFps); lua_register(_global.luaContext, "discSetFPS", apiDiscSetFps);
lua_register(_global.luaContext, "discSkipBackward", apiDiscSkipBackward); lua_register(_global.luaContext, "discSkipBackward", apiDiscSkipBackward);
lua_register(_global.luaContext, "discSkipBlanking", apiDiscSkipBlanking); lua_register(_global.luaContext, "discSkipBlanking", apiDiscSkipBlanking);
@ -4034,6 +4216,8 @@ void singe(SDL_Window *window, SDL_Renderer *renderer, ConfigT *conf) {
lua_register(_global.luaContext, "spriteUnload", apiSpriteUnload); lua_register(_global.luaContext, "spriteUnload", apiSpriteUnload);
lua_register(_global.luaContext, "videoDraw", apiVideoDraw); lua_register(_global.luaContext, "videoDraw", apiVideoDraw);
lua_register(_global.luaContext, "videoGetAudioTrack", apiVideoGetAudioTrack);
lua_register(_global.luaContext, "videoGetAudioTracks", apiVideoGetAudioTracks);
lua_register(_global.luaContext, "videoGetFrame", apiVideoGetFrame); lua_register(_global.luaContext, "videoGetFrame", apiVideoGetFrame);
lua_register(_global.luaContext, "videoGetFrameCount", apiVideoGetFrameCount); lua_register(_global.luaContext, "videoGetFrameCount", apiVideoGetFrameCount);
lua_register(_global.luaContext, "videoGetHeight", apiVideoGetHeight); lua_register(_global.luaContext, "videoGetHeight", apiVideoGetHeight);
@ -4044,6 +4228,7 @@ void singe(SDL_Window *window, SDL_Renderer *renderer, ConfigT *conf) {
lua_register(_global.luaContext, "videoPause", apiVideoPause); lua_register(_global.luaContext, "videoPause", apiVideoPause);
lua_register(_global.luaContext, "videoPlay", apiVideoPlay); lua_register(_global.luaContext, "videoPlay", apiVideoPlay);
lua_register(_global.luaContext, "videoSeek", apiVideoSeek); lua_register(_global.luaContext, "videoSeek", apiVideoSeek);
lua_register(_global.luaContext, "videoSetAudioTrack", apiVideoSetAudioTrack);
lua_register(_global.luaContext, "videoSetVolume", apiVideoSetVolume); lua_register(_global.luaContext, "videoSetVolume", apiVideoSetVolume);
lua_register(_global.luaContext, "videoUnload", apiVideoUnload); lua_register(_global.luaContext, "videoUnload", apiVideoUnload);
@ -4054,7 +4239,7 @@ void singe(SDL_Window *window, SDL_Renderer *renderer, ConfigT *conf) {
// Open main video file // Open main video file
progTrace("Opening main video file"); progTrace("Opening main video file");
doIndexDisplay(-1); doIndexDisplay(INDEX_DISPLAY_START);
videoSetIndexCallback(doIndexDisplay); videoSetIndexCallback(doIndexDisplay);
if (_global.conf->isFrameFile) { if (_global.conf->isFrameFile) {
_global.frameFileHandle = frameFileLoad(_global.conf->videoFile, _global.conf->dataDir, (bool)_global.conf->stretchVideo, _global.renderer, _global.conf->showCalculated); _global.frameFileHandle = frameFileLoad(_global.conf->videoFile, _global.conf->dataDir, (bool)_global.conf->stretchVideo, _global.renderer, _global.conf->showCalculated);
@ -4066,7 +4251,7 @@ void singe(SDL_Window *window, SDL_Renderer *renderer, ConfigT *conf) {
if (_global.videoHandle < 0) utilDie("Unable to load video file: %s", _global.conf->videoFile); if (_global.videoHandle < 0) utilDie("Unable to load video file: %s", _global.conf->videoFile);
videoSetVolume(_global.videoHandle, _global.conf->volumeVldp, _global.conf->volumeVldp); videoSetVolume(_global.videoHandle, _global.conf->volumeVldp, _global.conf->volumeVldp);
videoSetIndexCallback(NULL); videoSetIndexCallback(NULL);
doIndexDisplay(-2); doIndexDisplay(INDEX_DISPLAY_STOP);
// Should we resize the window? // Should we resize the window?
if (conf->resolutionWasCalculated && !conf->fullScreen && !conf->fullScreenWindow) { if (conf->resolutionWasCalculated && !conf->fullScreen && !conf->fullScreenWindow) {

View file

@ -33,48 +33,53 @@
#define AUDIO_SILENCE_SECONDS 2 #define AUDIO_SILENCE_SECONDS 2
typedef struct AudioStreamS {
FFMS_AudioSource *audioSource;
const FFMS_AudioProperties *audioProps;
} AudioStreamT;
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpadded" #pragma GCC diagnostic ignored "-Wpadded"
typedef struct VideoPlayerS { typedef struct VideoPlayerS {
int32_t id; int32_t id;
bool playing; bool playing;
bool resetTime; bool resetTime;
byte *audioBuffer; byte *audioBuffer;
byte audioSampleBytes; byte audioSampleBytes;
byte *audioSilenceRaw; byte *audioSilenceRaw;
char errMsg[1024]; char errMsg[1024];
int32_t volumeLeft; int32_t volumeLeft;
int32_t volumeRight; int32_t volumeRight;
int32_t audioTrack; int32_t videoTrack;
int32_t videoTrack; int32_t audioSampleSize;
int32_t audioSampleSize; int32_t mixSampleSize;
int32_t mixSampleSize; int32_t audioSilenceChannel;
int32_t audioSilenceChannel; int64_t frame;
int64_t frame; int64_t audioBufferSize;
int64_t audioBufferSize; int64_t frameDeltaTime;
int64_t frameDeltaTime; int64_t lastFrameTime;
int64_t lastFrameTime; int64_t timestamp;
int64_t timestamp; int64_t audioDelta;
int64_t audioDelta; int64_t audioPosition;
int64_t audioPosition; int64_t framesPlayed;
int64_t framesPlayed; Uint16 audioFormat;
Uint16 audioFormat; Uint32 lastTickTime;
Uint32 lastTickTime; Uint32 audioSilenceSize;
Uint32 audioSilenceSize; //double audioAdjustment;
//double audioAdjustment; Mix_Chunk *silenceChunk;
Mix_Chunk *silenceChunk; SDL_AudioStream *audioStream;
SDL_AudioStream *audioStream; SDL_Texture *videoTexture;
SDL_Texture *videoTexture; FFMS_ErrorInfo errInfo;
FFMS_ErrorInfo errInfo; int32_t currentAudioTrack;
FFMS_AudioSource *audioSource; int32_t audioSourceCount;
FFMS_VideoSource *videoSource; AudioStreamT *audio;
const FFMS_AudioProperties *audioProps; FFMS_VideoSource *videoSource;
const FFMS_VideoProperties *videoProps; const FFMS_VideoProperties *videoProps;
const FFMS_Frame *propFrame; const FFMS_Frame *propFrame;
const FFMS_TrackTimeBase *videoTimeBase; const FFMS_TrackTimeBase *videoTimeBase;
const FFMS_Frame *frameData; const FFMS_Frame *frameData;
const FFMS_FrameInfo *frameInfo; const FFMS_FrameInfo *frameInfo;
UT_hash_handle hh; UT_hash_handle hh;
} VideoPlayerT; } VideoPlayerT;
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
@ -196,13 +201,18 @@ int32_t _loadVideoAndAudio(char *vFilename, char *aFilename, char *indexPath, bo
FFMS_Index *vIndex = NULL; FFMS_Index *vIndex = NULL;
FFMS_Index *aIndex = NULL; FFMS_Index *aIndex = NULL;
VideoPlayerT *v = NULL; VideoPlayerT *v = NULL;
int32_t x = 0;
int32_t count = 0;
FFMS_Track *track = NULL;
int32_t ttype = FFMS_TYPE_UNKNOWN;
// Create new videoPlayer // Create new videoPlayer
v = calloc(1, sizeof(VideoPlayerT)); v = calloc(1, sizeof(VideoPlayerT));
if (!v) utilDie("Unable to allocate new video player."); if (!v) utilDie("Unable to allocate new video player.");
// Set some starting values // Set some starting values
v->audioTrack = -1; v->audioSourceCount = 0;
v->currentAudioTrack = -1;
v->videoTrack = -1; v->videoTrack = -1;
v->audioSilenceChannel = -1; v->audioSilenceChannel = -1;
v->playing = false; // Start paused v->playing = false; // Start paused
@ -215,8 +225,8 @@ int32_t _loadVideoAndAudio(char *vFilename, char *aFilename, char *indexPath, bo
vIndex = _createIndex(vFilename, indexPath, true, false, v); vIndex = _createIndex(vFilename, indexPath, true, false, v);
aIndex = _createIndex(aFilename, indexPath, false, true, v); aIndex = _createIndex(aFilename, indexPath, false, true, v);
} else { } else {
vIndex = _createIndex(vFilename, indexPath, true, true, v); vIndex = _createIndex(vFilename, indexPath, true, true, v);
aIndex = vIndex; aIndex = vIndex;
aFilename = vFilename; aFilename = vFilename;
} }
@ -237,13 +247,50 @@ int32_t _loadVideoAndAudio(char *vFilename, char *aFilename, char *indexPath, bo
pixelFormats[1] = -1; pixelFormats[1] = -1;
if (FFMS_SetOutputFormatV2(v->videoSource, pixelFormats, v->propFrame->EncodedWidth, v->propFrame->EncodedHeight, FFMS_RESIZER_BICUBIC, &v->errInfo)) utilDie("%s", v->errInfo.Buffer); 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 // Find audio track(s)
v->audioTrack = FFMS_GetFirstTrackOfType(aIndex, FFMS_TYPE_AUDIO, &v->errInfo); //utilSay("Tracks in file: %d", FFMS_GetNumTracks(aIndex));
if (v->audioTrack >= 0) { for (x=0; x<FFMS_GetNumTracks(aIndex); x++) {
v->audioSource = FFMS_CreateAudioSource(aFilename, v->audioTrack, aIndex, FFMS_DELAY_FIRST_VIDEO_TRACK, &v->errInfo); track = FFMS_GetTrackFromIndex(aIndex, x);
if (v->audioSource == NULL) utilDie("%s", v->errInfo.Buffer); ttype = FFMS_GetTrackType(track);
// Get audio properties // Just count the tracks for now.
v->audioProps = FFMS_GetAudioProperties(v->audioSource); if (ttype == FFMS_TYPE_AUDIO) count++;
/*
switch (ttype) {
case FFMS_TYPE_UNKNOWN:
utilSay("Track %d is FFMS_TYPE_UNKNOWN", x);
break;
case FFMS_TYPE_VIDEO:
utilSay("Track %d is FFMS_TYPE_VIDEO", x);
break;
case FFMS_TYPE_AUDIO:
utilSay("Track %d is FFMS_TYPE_AUDIO", x);
break;
case FFMS_TYPE_DATA:
utilSay("Track %d is FFMS_TYPE_DATA", x);
break;
case FFMS_TYPE_SUBTITLE:
utilSay("Track %d is FFMS_TYPE_SUBTITLE", x);
break;
case FFMS_TYPE_ATTACHMENT:
utilSay("Track %d is FFMS_TYPE_ATTACHMENT", x);
break;
}
*/
}
if (count > 0) {
// Allocate space for the tracks.
v->audio = (AudioStreamT *)calloc(count, sizeof(AudioStreamT));
// Now create them.
for (x=0; x<FFMS_GetNumTracks(aIndex); x++) {
if (FFMS_GetTrackType(FFMS_GetTrackFromIndex(aIndex, x)) == FFMS_TYPE_AUDIO) {
v->audio[v->audioSourceCount].audioSource = FFMS_CreateAudioSource(aFilename, x, aIndex, FFMS_DELAY_FIRST_VIDEO_TRACK, &v->errInfo);
if (v->audio[v->audioSourceCount].audioSource == NULL) utilDie("%s", v->errInfo.Buffer);
v->audio[v->audioSourceCount].audioProps = FFMS_GetAudioProperties(v->audio[v->audioSourceCount].audioSource);
v->audioSourceCount++;
}
}
// Current audio track.
v->currentAudioTrack = 0;
} }
// Indicies are now part of audioSource & videoSource, so release these // Indicies are now part of audioSource & videoSource, so release these
@ -263,10 +310,10 @@ int32_t _loadVideoAndAudio(char *vFilename, char *aFilename, char *indexPath, bo
SDL_RenderSetLogicalSize(renderer, v->propFrame->EncodedWidth, v->propFrame->EncodedHeight); SDL_RenderSetLogicalSize(renderer, v->propFrame->EncodedWidth, v->propFrame->EncodedHeight);
} }
// Do we have audio? // Do we have audio? All audio streams must have the same format!
if (v->audioSource) { if (v->audioSourceCount > 0) {
// Determine audio format // Determine audio format
switch (v->audioProps->SampleFormat) { switch (v->audio[0].audioProps->SampleFormat) {
case FFMS_FMT_U8: case FFMS_FMT_U8:
v->audioFormat = AUDIO_U8; v->audioFormat = AUDIO_U8;
v->audioSampleBytes = 1; v->audioSampleBytes = 1;
@ -287,15 +334,15 @@ int32_t _loadVideoAndAudio(char *vFilename, char *aFilename, char *indexPath, bo
utilDie("Unknown audio sample format."); utilDie("Unknown audio sample format.");
break; break;
} }
if (v->audioProps->Channels > 2) utilDie("Only mono and stereo audio are supported."); if (v->audio[0].audioProps->Channels > 2) utilDie("Only mono and stereo audio are supported.");
// Create audio stream to convert audio to our desired format // Create audio stream to convert audio to our desired format
v->audioStream = SDL_NewAudioStream(v->audioFormat, (Uint8)v->audioProps->Channels, v->audioProps->SampleRate, _mixFormat, _mixChannels, _mixRate); v->audioStream = SDL_NewAudioStream(v->audioFormat, (Uint8)v->audio[0].audioProps->Channels, v->audio[0].audioProps->SampleRate, _mixFormat, _mixChannels, _mixRate);
if (!v->audioStream) utilDie("%s", SDL_GetError()); if (!v->audioStream) utilDie("%s", SDL_GetError());
// Create a buffer to read audio into before conversion // Create a buffer to read audio into before conversion
v->mixSampleSize = SDL_AUDIO_BITSIZE(_mixFormat) / 8 * _mixChannels; v->mixSampleSize = SDL_AUDIO_BITSIZE(_mixFormat) / 8 * _mixChannels;
v->audioSampleSize = v->audioSampleBytes * v->audioProps->Channels; v->audioSampleSize = v->audioSampleBytes * v->audio[0].audioProps->Channels;
v->audioBufferSize = v->audioSampleSize * AUDIO_SAMPLE_PREREAD; v->audioBufferSize = v->audioSampleSize * AUDIO_SAMPLE_PREREAD;
v->audioBuffer = (byte *)malloc((size_t)v->audioBufferSize * sizeof(byte)); v->audioBuffer = (byte *)malloc((size_t)v->audioBufferSize * sizeof(byte));
if (!v->audioBuffer) utilDie("Unable to allocate %ld byte audio buffer.", (size_t)v->audioBufferSize * sizeof(byte)); if (!v->audioBuffer) utilDie("Unable to allocate %ld byte audio buffer.", (size_t)v->audioBufferSize * sizeof(byte));
@ -371,6 +418,28 @@ int32_t videoIsPlaying(int32_t playerHandle) {
} }
int32_t videoGetAudioTrack(int32_t playerHandle) {
VideoPlayerT *v = NULL;
// Get our player structure
HASH_FIND_INT(_videoPlayerHash, &playerHandle, v);
if (!v) utilDie("No video player at index %d in videoGetAudioTrack.", playerHandle);
return v->currentAudioTrack;
}
int32_t videoGetAudioTracks(int32_t playerHandle) {
VideoPlayerT *v = NULL;
// Get our player structure
HASH_FIND_INT(_videoPlayerHash, &playerHandle, v);
if (!v) utilDie("No video player at index %d in videoGetAudioTracks.", playerHandle);
return v->audioSourceCount;
}
int64_t videoGetFrame(int32_t playerHandle) { int64_t videoGetFrame(int32_t playerHandle) {
VideoPlayerT *v = NULL; VideoPlayerT *v = NULL;
@ -505,6 +574,23 @@ int32_t videoSeek(int32_t playerHandle, int64_t seekFrame) {
} }
int32_t videoSetAudioTrack(int32_t playerHandle, int32_t track) {
VideoPlayerT *v = NULL;
// Get our player structure
HASH_FIND_INT(_videoPlayerHash, &playerHandle, v);
if (!v) utilDie("No video player at index %d in videoSetAudioTrack.", playerHandle);
if ((track >= 0) && (track < v->audioSourceCount)) {
v->currentAudioTrack = track;
} else {
utilDie("Invalid audio track in videoSetAudioTrack.");
}
return 0;
}
int32_t videoSetIndexCallback(videoIndexingCallback callback) { int32_t videoSetIndexCallback(videoIndexingCallback callback) {
_indexingFunction = callback; _indexingFunction = callback;
return 0; return 0;
@ -527,19 +613,23 @@ int32_t videoSetVolume(int32_t playerHandle, int32_t leftPercent, int32_t rightP
int32_t videoUnload(int32_t playerHandle) { int32_t videoUnload(int32_t playerHandle) {
VideoPlayerT *v = NULL; VideoPlayerT *v = NULL;
int32_t x = 0;
// Get our player structure // Get our player structure
HASH_FIND_INT(_videoPlayerHash, &playerHandle, v); HASH_FIND_INT(_videoPlayerHash, &playerHandle, v);
if (!v) utilDie("No video player at index %d in videoStop.", playerHandle); if (!v) utilDie("No video player at index %d in videoStop.", playerHandle);
if (v->audioSource) { if (v->audioSourceCount > 0) {
Mix_HaltChannel(v->audioSilenceChannel); Mix_HaltChannel(v->audioSilenceChannel);
Mix_UnregisterEffect(v->audioSilenceChannel, _dequeueVideoAudio); Mix_UnregisterEffect(v->audioSilenceChannel, _dequeueVideoAudio);
Mix_FreeChunk(v->silenceChunk); Mix_FreeChunk(v->silenceChunk);
free(v->audioSilenceRaw); free(v->audioSilenceRaw);
SDL_FreeAudioStream(v->audioStream); SDL_FreeAudioStream(v->audioStream);
free(v->audioBuffer); free(v->audioBuffer);
FFMS_DestroyAudioSource(v->audioSource); for (x=0; x<v->audioSourceCount; x++) {
FFMS_DestroyAudioSource(v->audio[x].audioSource);
}
free(v->audio);
} }
FFMS_DestroyVideoSource(v->videoSource); FFMS_DestroyVideoSource(v->videoSource);
@ -566,7 +656,7 @@ int32_t videoUpdate(int32_t playerHandle, SDL_Texture **texture) {
if (!v) utilDie("No video player at index %d in videoUpdate.", playerHandle); if (!v) utilDie("No video player at index %d in videoUpdate.", playerHandle);
// Audio drift limit // Audio drift limit
threshold = v->audioSource ? (v->audioProps->SampleRate / 2) : 99999; threshold = v->audio[v->currentAudioTrack].audioSource ? (v->audio[v->currentAudioTrack].audioProps->SampleRate / 2) : 99999;
// Handle video frames (and time) // Handle video frames (and time)
//if ((SDL_GetTicks() - v->lastTickTime >= v->frameDeltaTime) || (v->audioDelta > threshold) || v->resetTime) { //if ((SDL_GetTicks() - v->lastTickTime >= v->frameDeltaTime) || (v->audioDelta > threshold) || v->resetTime) {
@ -598,9 +688,9 @@ int32_t videoUpdate(int32_t playerHandle, SDL_Texture **texture) {
v->lastTickTime = SDL_GetTicks(); v->lastTickTime = SDL_GetTicks();
if (v->resetTime) { if (v->resetTime) {
if (v->audioSource) { if (v->audioSourceCount > 0) {
SDL_AudioStreamClear(v->audioStream); SDL_AudioStreamClear(v->audioStream);
v->audioPosition = (int64_t)((double)v->timestamp * 0.001 * (double)v->audioProps->SampleRate); v->audioPosition = (int64_t)((double)v->timestamp * 0.001 * (double)v->audio[v->currentAudioTrack].audioProps->SampleRate);
v->audioDelta = 0; v->audioDelta = 0;
} }
v->lastTickTime = 0; v->lastTickTime = 0;
@ -611,19 +701,19 @@ int32_t videoUpdate(int32_t playerHandle, SDL_Texture **texture) {
} }
// Handle audio samples // Handle audio samples
if (v->audioSource) { if (v->audioSourceCount > 0) {
// Add more samples to queue? // Add more samples to queue?
if ((v->playing) && (SDL_AudioStreamAvailable(v->audioStream) < AUDIO_STREAM_LOW_WATERMARK) && (v->audioPosition < v->audioProps->NumSamples)) { if ((v->playing) && (SDL_AudioStreamAvailable(v->audioStream) < AUDIO_STREAM_LOW_WATERMARK) && (v->audioPosition < v->audio[v->currentAudioTrack].audioProps->NumSamples)) {
// Maximum samples we can read at a time // Maximum samples we can read at a time
count = AUDIO_SAMPLE_PREREAD; count = AUDIO_SAMPLE_PREREAD;
// Don't read past end of audio data // Don't read past end of audio data
if (v->audioPosition + count >= v->audioProps->NumSamples) { if (v->audioPosition + count >= v->audio[v->currentAudioTrack].audioProps->NumSamples) {
count = v->audioProps->NumSamples - v->audioPosition - 1; count = v->audio[v->currentAudioTrack].audioProps->NumSamples - v->audioPosition - 1;
} }
// Are we reading anything? // Are we reading anything?
if (count > 0) { if (count > 0) {
// Get audio from video stream // Get audio from video stream
if (FFMS_GetAudio(v->audioSource, v->audioBuffer, v->audioPosition, count, &v->errInfo)) utilDie("%s", v->errInfo.Buffer); if (FFMS_GetAudio(v->audio[v->currentAudioTrack].audioSource, v->audioBuffer, v->audioPosition, count, &v->errInfo)) utilDie("%s", v->errInfo.Buffer);
// Feed it to the mixer stream // Feed it to the mixer stream
if (SDL_AudioStreamPut(v->audioStream, v->audioBuffer, (int32_t)(count * v->audioSampleSize)) < 0) utilDie("%s", SDL_GetError()); if (SDL_AudioStreamPut(v->audioStream, v->audioBuffer, (int32_t)(count * v->audioSampleSize)) < 0) utilDie("%s", SDL_GetError());
v->audioPosition += count; v->audioPosition += count;
@ -631,7 +721,7 @@ int32_t videoUpdate(int32_t playerHandle, SDL_Texture **texture) {
} }
// Used to determine if we should play two frames rapidly to catch up to audio // Used to determine if we should play two frames rapidly to catch up to audio
v->audioDelta = labs((long)(v->audioPosition - (int64_t)((double)v->timestamp * 0.001 * (double)v->audioProps->SampleRate))); v->audioDelta = labs((long)(v->audioPosition - (int64_t)((double)v->timestamp * 0.001 * (double)v->audio[v->currentAudioTrack].audioProps->SampleRate)));
// Did we trip the audio sync compensation? // Did we trip the audio sync compensation?
if (v->audioDelta > threshold) { if (v->audioDelta > threshold) {

View file

@ -34,6 +34,8 @@ typedef void (*videoIndexingCallback)(int32_t);
int32_t videoInit(void); int32_t videoInit(void);
int32_t videoIsPlaying(int32_t playerHandle); int32_t videoIsPlaying(int32_t playerHandle);
int32_t videoGetAudioTrack(int32_t playerHandle);
int32_t videoGetAudioTracks(int32_t playerHandle);
int64_t videoGetFrame(int32_t playerHandle); int64_t videoGetFrame(int32_t playerHandle);
int64_t videoGetFrameCount(int32_t playerHandle); int64_t videoGetFrameCount(int32_t playerHandle);
int32_t videoGetHeight(int32_t playerHandle); int32_t videoGetHeight(int32_t playerHandle);
@ -45,6 +47,7 @@ int32_t videoPause(int32_t playerHandle);
int32_t videoPlay(int32_t playerHandle); int32_t videoPlay(int32_t playerHandle);
int32_t videoQuit(void); int32_t videoQuit(void);
int32_t videoSeek(int32_t playerHandle, int64_t seekFrame); int32_t videoSeek(int32_t playerHandle, int64_t seekFrame);
int32_t videoSetAudioTrack(int32_t playerHandle, int32_t track);
int32_t videoSetIndexCallback(videoIndexingCallback callback); int32_t videoSetIndexCallback(videoIndexingCallback callback);
int32_t videoSetVolume(int32_t playerHandle, int32_t leftPercent, int32_t rightPercent); int32_t videoSetVolume(int32_t playerHandle, int32_t leftPercent, int32_t rightPercent);
int32_t videoUnload(int32_t playerHandle); int32_t videoUnload(int32_t playerHandle);