SDL_mixer now playing video stream audio!
This commit is contained in:
parent
1f43bfc742
commit
06632fbcd7
5 changed files with 29 additions and 54 deletions
50
singe/main.c
50
singe/main.c
|
@ -53,9 +53,10 @@
|
||||||
#define true 1
|
#define true 1
|
||||||
#define false 0
|
#define false 0
|
||||||
|
|
||||||
#define AUDIO_RING_SIZE 4096
|
#define AUDIO_RING_SIZE (64 * 1024)
|
||||||
#define AUDIO_SAMPLES (AUDIO_RING_SIZE / (16 /* average bytes per sample */ * 2 /* channels */))
|
#define AUDIO_SAMPLES (AUDIO_RING_SIZE / (16 /* average bytes per sample */ * 2 /* channels */))
|
||||||
#define AUDIO_SILENCE_SECONDS 4
|
#define AUDIO_SILENCE_SECONDS 2
|
||||||
|
#define AUDIO_CHUNK_MULTIPLIER 2
|
||||||
|
|
||||||
|
|
||||||
typedef struct AudioRingBufferS {
|
typedef struct AudioRingBufferS {
|
||||||
|
@ -72,23 +73,19 @@ void say(char *fmt, ...);
|
||||||
|
|
||||||
|
|
||||||
void dequeueVideoAudio(int channel, void *stream, int len, void *udata) {
|
void dequeueVideoAudio(int channel, void *stream, int len, void *udata) {
|
||||||
int toCopy = len;
|
int toCopy = len;
|
||||||
AudioRingBufferT *ring = (AudioRingBufferT *)udata;
|
AudioRingBufferT *ring = (AudioRingBufferT *)udata;
|
||||||
|
|
||||||
(void)channel;
|
(void)channel;
|
||||||
|
|
||||||
ring->sizeTemp = ringbuf_bytes_used(ring->ring);
|
ring->sizeTemp = ringbuf_bytes_used(ring->ring); // We do this in case more space is used by the mixer while we're working on this
|
||||||
if (len > (int)ring->sizeTemp) {
|
if (len > (int)ring->sizeTemp) {
|
||||||
toCopy = (int)ring->sizeTemp;
|
toCopy = (int)ring->sizeTemp;
|
||||||
}
|
}
|
||||||
if (SDL_LockMutex(ring->mutex) == 0) {
|
if (SDL_LockMutex(ring->mutex) < 0) die("Unable to lock mutex for ringbuf_memcpy_from");
|
||||||
ringbuf_memcpy_from(stream, ring->ring, (size_t)toCopy);
|
ringbuf_memcpy_from(stream, ring->ring, (size_t)toCopy);
|
||||||
SDL_UnlockMutex(ring->mutex);
|
if (SDL_UnlockMutex(ring->mutex) < 0) die("Unable to unlock mutex for ringbuf_memcpy_from");
|
||||||
} else {
|
//say("Dequeued %d bytes of audio data. Buffer is now %d.", toCopy, ringbuf_bytes_used(ring->ring));
|
||||||
die("Unable to lock mutex for ringbuf_memcpy_from");
|
|
||||||
}
|
|
||||||
|
|
||||||
// say("Dequeued %d bytes of audio data. Buffer is now %d.", toCopy, ringbuf_bytes_used(ring->ring));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -294,28 +291,35 @@ int main(int argc, char *argv[]) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (audioProps->Channels > 2) die("Only mono and stereo audio are supported.");
|
if (audioProps->Channels > 2) die("Only mono and stereo audio are supported.");
|
||||||
|
|
||||||
// Create audio mixer device
|
// Create audio mixer device
|
||||||
err = Mix_OpenAudioDevice(44100, audioFormat, 2, audioSampleSize * audioProps->Channels, NULL, 0);
|
err = Mix_OpenAudio(audioProps->SampleRate, audioFormat, 2, audioSampleSize * audioProps->Channels * AUDIO_CHUNK_MULTIPLIER);
|
||||||
if (err != 0) die("%s", Mix_GetError());
|
if (err != 0) die("%s", Mix_GetError());
|
||||||
|
|
||||||
// Create a buffer for reading audio from the video stream
|
// Create a buffer for reading audio from the video stream
|
||||||
audioSampleSize = audioSampleBytes * audioProps->Channels;
|
audioSampleSize = audioSampleBytes * audioProps->Channels;
|
||||||
audioBuffer = (byte *)malloc((size_t)(audioSampleSize * AUDIO_SAMPLES) * sizeof(byte));
|
audioBuffer = (byte *)malloc((size_t)(audioSampleSize * AUDIO_SAMPLES) * sizeof(byte));
|
||||||
if (!audioBuffer) die("Unable to allocate %ld byte audio buffer.", ((size_t)(audioSampleSize * AUDIO_SAMPLES) * sizeof(byte)));
|
if (!audioBuffer) die("Unable to allocate %ld byte audio buffer.", ((size_t)(audioSampleSize * AUDIO_SAMPLES) * sizeof(byte)));
|
||||||
|
|
||||||
// Create a ring buffer to pass audio data from the video to the mixer
|
// Create a ring buffer to pass audio data from the video to the mixer
|
||||||
audioRingBuffer.ring = ringbuf_new(AUDIO_RING_SIZE);
|
audioRingBuffer.ring = ringbuf_new(AUDIO_RING_SIZE);
|
||||||
if (!audioRingBuffer.ring) die("Unable to allocate %ld audio ring buffer.", AUDIO_RING_SIZE);
|
if (!audioRingBuffer.ring) die("Unable to allocate %ld audio ring buffer.", AUDIO_RING_SIZE);
|
||||||
audioRingBuffer.mutex = SDL_CreateMutex();
|
audioRingBuffer.mutex = SDL_CreateMutex();
|
||||||
if (!audioRingBuffer.mutex) die("Unable to create audio ring buffer mutex.");
|
if (!audioRingBuffer.mutex) die("Unable to create audio ring buffer mutex.");
|
||||||
|
|
||||||
// Create a block of silent audio to overlay with video stream audio
|
// Create a block of silent audio to overlay with video stream audio
|
||||||
audioSilenceSize = (Uint32)audioSampleSize * (Uint32)audioProps->SampleRate * AUDIO_SILENCE_SECONDS;
|
audioSilenceSize = (Uint32)audioSampleSize * (Uint32)audioProps->SampleRate * AUDIO_SILENCE_SECONDS;
|
||||||
audioSilenceRaw = (byte *)calloc(1, (size_t)audioSilenceSize * sizeof(byte));
|
audioSilenceRaw = (byte *)calloc(1, (size_t)audioSilenceSize * sizeof(byte));
|
||||||
if (!audioSilenceRaw) die("Unable to allocate %ld silence buffer.", audioSilenceSize);
|
if (!audioSilenceRaw) die("Unable to allocate %ld silence buffer.", audioSilenceSize);
|
||||||
|
|
||||||
// Load silent audio
|
// Load silent audio
|
||||||
silenceChunk = Mix_QuickLoad_RAW(audioSilenceRaw, audioSilenceSize);
|
silenceChunk = Mix_QuickLoad_RAW(audioSilenceRaw, audioSilenceSize);
|
||||||
if (!silenceChunk) die("%s", Mix_GetError());
|
if (!silenceChunk) die("%s", Mix_GetError());
|
||||||
|
|
||||||
// Start silent audio playback & immediately pause it
|
// Start silent audio playback & immediately pause it
|
||||||
audioSilenceChannel = Mix_PlayChannel(-1, silenceChunk, -1);
|
audioSilenceChannel = Mix_PlayChannel(-1, silenceChunk, -1);
|
||||||
if (audioSilenceChannel < 0) die("%s", Mix_GetError());
|
if (audioSilenceChannel < 0) die("%s", Mix_GetError());
|
||||||
|
|
||||||
// Register effect to provide video stream audio on this channel
|
// Register effect to provide video stream audio on this channel
|
||||||
Mix_RegisterEffect(audioSilenceChannel, dequeueVideoAudio, NULL, &audioRingBuffer);
|
Mix_RegisterEffect(audioSilenceChannel, dequeueVideoAudio, NULL, &audioRingBuffer);
|
||||||
|
|
||||||
|
@ -404,12 +408,9 @@ int main(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resetTime) {
|
if (resetTime) {
|
||||||
if (SDL_LockMutex(audioRingBuffer.mutex) == 0) {
|
if (SDL_LockMutex(audioRingBuffer.mutex) < 0) die("Unable to lock mutex for ringbuf_reset");
|
||||||
ringbuf_reset(audioRingBuffer.ring);
|
ringbuf_reset(audioRingBuffer.ring);
|
||||||
SDL_UnlockMutex(audioRingBuffer.mutex);
|
if (SDL_UnlockMutex(audioRingBuffer.mutex) < 0) die("Unable to unlock mutex for ringbuf_reset");
|
||||||
} else {
|
|
||||||
die("Unable to lock mutex for ringbuf_reset");
|
|
||||||
}
|
|
||||||
lastTickTime = 0;
|
lastTickTime = 0;
|
||||||
frameDeltaTime = 0;
|
frameDeltaTime = 0;
|
||||||
audioPosition = (int64_t)((double)(timestamp * 0.001) * (double)audioProps->SampleRate);
|
audioPosition = (int64_t)((double)(timestamp * 0.001) * (double)audioProps->SampleRate);
|
||||||
|
@ -433,12 +434,9 @@ int main(int argc, char *argv[]) {
|
||||||
// Are we reading anything?
|
// Are we reading anything?
|
||||||
if (audioCount > 0) {
|
if (audioCount > 0) {
|
||||||
if (FFMS_GetAudio(audioSource, audioBuffer, audioPosition, audioCount, &errInfo)) die("%s", errInfo.Buffer);
|
if (FFMS_GetAudio(audioSource, audioBuffer, audioPosition, audioCount, &errInfo)) die("%s", errInfo.Buffer);
|
||||||
if (SDL_LockMutex(audioRingBuffer.mutex) == 0) {
|
if (SDL_LockMutex(audioRingBuffer.mutex) < 0) die("Unable to lock mutex for ringbuf_memcpy_into");
|
||||||
ringbuf_memcpy_into(audioRingBuffer.ring, audioBuffer, (size_t)(audioCount * audioSampleSize));
|
ringbuf_memcpy_into(audioRingBuffer.ring, audioBuffer, (size_t)(audioCount * audioSampleSize));
|
||||||
SDL_UnlockMutex(audioRingBuffer.mutex);
|
if (SDL_UnlockMutex(audioRingBuffer.mutex) < 0) die("Unable to unlock mutex for ringbuf_memcpy_into");
|
||||||
} else {
|
|
||||||
die("Unable to lock mutex for ringbuf_memcpy_into");
|
|
||||||
}
|
|
||||||
//say("Added %d samples (%d bytes) to ring buffer. Buffer is now %d bytes", audioCount, audioCount * audioSampleSize, ringbuf_bytes_used(audioRingBuffer.ring));
|
//say("Added %d samples (%d bytes) to ring buffer. Buffer is now %d bytes", audioCount, audioCount * audioSampleSize, ringbuf_bytes_used(audioRingBuffer.ring));
|
||||||
audioPosition += audioCount;
|
audioPosition += audioCount;
|
||||||
}
|
}
|
||||||
|
|
0
singe/postLink.sh
Normal file → Executable file
0
singe/postLink.sh
Normal file → Executable file
|
@ -22,7 +22,7 @@
|
||||||
if [[ -z $1 ]]; then
|
if [[ -z $1 ]]; then
|
||||||
BITS=64
|
BITS=64
|
||||||
THIRDPARTY=$(pwd)
|
THIRDPARTY=$(pwd)
|
||||||
DEST="${THIRDPARTY}/../../thirdparty-build/${BITS}"
|
DEST="${THIRDPARTY}/../thirdparty-build/${BITS}"
|
||||||
else
|
else
|
||||||
THIRDPARTY=$1
|
THIRDPARTY=$1
|
||||||
DEST=$2/$3
|
DEST=$2/$3
|
|
@ -63,9 +63,10 @@ CONFIG += bits64
|
||||||
|
|
||||||
BUILDTHIRDARGS = \"$$PWD/thirdparty\" \"$$OUT_PWD/../thirdparty-build\" $$BITNESS
|
BUILDTHIRDARGS = \"$$PWD/thirdparty\" \"$$OUT_PWD/../thirdparty-build\" $$BITNESS
|
||||||
win32 {
|
win32 {
|
||||||
BUILDTHIRD.commands = cmd.exe /c $$PWD\\thirdparty\\build.bat $$BUILDTHIRDARGS
|
# Placeholder - doesn't work
|
||||||
|
BUILDTHIRD.commands = cmd.exe /c $$PWD\\preBuild.bat $$BUILDTHIRDARGS
|
||||||
} else {
|
} else {
|
||||||
BUILDTHIRD.commands = bash $$PWD/thirdparty/build.sh $$BUILDTHIRDARGS
|
BUILDTHIRD.commands = bash $$PWD/preBuild.sh $$BUILDTHIRDARGS
|
||||||
}
|
}
|
||||||
BUILDTHIRD.target = this
|
BUILDTHIRD.target = this
|
||||||
PRE_TARGETDEPS += this
|
PRE_TARGETDEPS += this
|
||||||
|
@ -137,8 +138,7 @@ LIBS += \
|
||||||
-ldl
|
-ldl
|
||||||
|
|
||||||
OTHER_FILES += \
|
OTHER_FILES += \
|
||||||
thirdparty/build.sh \
|
preBuild.sh \
|
||||||
thirdparty/build.bat \
|
|
||||||
postLink.sh
|
postLink.sh
|
||||||
|
|
||||||
# Strip & UPX the final result
|
# Strip & UPX the final result
|
||||||
|
|
23
singe/thirdparty/build.bat
vendored
23
singe/thirdparty/build.bat
vendored
|
@ -1,23 +0,0 @@
|
||||||
@echo off
|
|
||||||
goto skipLicense
|
|
||||||
|
|
||||||
#
|
|
||||||
# Singe 2
|
|
||||||
# Copyright (C) 2019 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
:skipLicense
|
|
Loading…
Add table
Reference in a new issue