SDL_mixer now playing video stream audio!

This commit is contained in:
Scott Duensing 2019-11-24 19:25:48 -06:00
parent 1f43bfc742
commit 06632fbcd7
5 changed files with 29 additions and 54 deletions

View file

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

View 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

View file

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

View file

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