From 06632fbcd7a1b6a75da7936bab2734762fd360cd Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Sun, 24 Nov 2019 19:25:48 -0600 Subject: [PATCH] SDL_mixer now playing video stream audio! --- singe/main.c | 50 +++++++++++----------- singe/postLink.sh | 0 singe/{thirdparty/build.sh => preBuild.sh} | 2 +- singe/singe.pro | 8 ++-- singe/thirdparty/build.bat | 23 ---------- 5 files changed, 29 insertions(+), 54 deletions(-) mode change 100644 => 100755 singe/postLink.sh rename singe/{thirdparty/build.sh => preBuild.sh} (99%) delete mode 100644 singe/thirdparty/build.bat diff --git a/singe/main.c b/singe/main.c index ef97440a0..576f77cf3 100644 --- a/singe/main.c +++ b/singe/main.c @@ -53,9 +53,10 @@ #define true 1 #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_SILENCE_SECONDS 4 +#define AUDIO_SILENCE_SECONDS 2 +#define AUDIO_CHUNK_MULTIPLIER 2 typedef struct AudioRingBufferS { @@ -72,23 +73,19 @@ void say(char *fmt, ...); void dequeueVideoAudio(int channel, void *stream, int len, void *udata) { - int toCopy = len; - AudioRingBufferT *ring = (AudioRingBufferT *)udata; + int toCopy = len; + AudioRingBufferT *ring = (AudioRingBufferT *)udata; (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) { toCopy = (int)ring->sizeTemp; } - if (SDL_LockMutex(ring->mutex) == 0) { - ringbuf_memcpy_from(stream, ring->ring, (size_t)toCopy); - SDL_UnlockMutex(ring->mutex); - } else { - 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)); + if (SDL_LockMutex(ring->mutex) < 0) die("Unable to lock mutex for ringbuf_memcpy_from"); + ringbuf_memcpy_from(stream, ring->ring, (size_t)toCopy); + if (SDL_UnlockMutex(ring->mutex) < 0) die("Unable to unlock 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; } if (audioProps->Channels > 2) die("Only mono and stereo audio are supported."); + // 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()); + // Create a buffer for reading audio from the video stream audioSampleSize = audioSampleBytes * audioProps->Channels; 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))); + // Create a ring buffer to pass audio data from the video to the mixer audioRingBuffer.ring = ringbuf_new(AUDIO_RING_SIZE); if (!audioRingBuffer.ring) die("Unable to allocate %ld audio ring buffer.", AUDIO_RING_SIZE); audioRingBuffer.mutex = SDL_CreateMutex(); if (!audioRingBuffer.mutex) die("Unable to create audio ring buffer mutex."); + // Create a block of silent audio to overlay with video stream audio audioSilenceSize = (Uint32)audioSampleSize * (Uint32)audioProps->SampleRate * AUDIO_SILENCE_SECONDS; audioSilenceRaw = (byte *)calloc(1, (size_t)audioSilenceSize * sizeof(byte)); if (!audioSilenceRaw) die("Unable to allocate %ld silence buffer.", audioSilenceSize); + // Load silent audio silenceChunk = Mix_QuickLoad_RAW(audioSilenceRaw, audioSilenceSize); if (!silenceChunk) die("%s", Mix_GetError()); + // Start silent audio playback & immediately pause it audioSilenceChannel = Mix_PlayChannel(-1, silenceChunk, -1); if (audioSilenceChannel < 0) die("%s", Mix_GetError()); + // Register effect to provide video stream audio on this channel Mix_RegisterEffect(audioSilenceChannel, dequeueVideoAudio, NULL, &audioRingBuffer); @@ -404,12 +408,9 @@ int main(int argc, char *argv[]) { } if (resetTime) { - if (SDL_LockMutex(audioRingBuffer.mutex) == 0) { - ringbuf_reset(audioRingBuffer.ring); - SDL_UnlockMutex(audioRingBuffer.mutex); - } else { - die("Unable to lock mutex for ringbuf_reset"); - } + if (SDL_LockMutex(audioRingBuffer.mutex) < 0) die("Unable to lock mutex for ringbuf_reset"); + ringbuf_reset(audioRingBuffer.ring); + if (SDL_UnlockMutex(audioRingBuffer.mutex) < 0) die("Unable to unlock mutex for ringbuf_reset"); lastTickTime = 0; frameDeltaTime = 0; audioPosition = (int64_t)((double)(timestamp * 0.001) * (double)audioProps->SampleRate); @@ -433,12 +434,9 @@ int main(int argc, char *argv[]) { // Are we reading anything? if (audioCount > 0) { if (FFMS_GetAudio(audioSource, audioBuffer, audioPosition, audioCount, &errInfo)) die("%s", errInfo.Buffer); - if (SDL_LockMutex(audioRingBuffer.mutex) == 0) { - ringbuf_memcpy_into(audioRingBuffer.ring, audioBuffer, (size_t)(audioCount * audioSampleSize)); - SDL_UnlockMutex(audioRingBuffer.mutex); - } else { - die("Unable to lock mutex for ringbuf_memcpy_into"); - } + 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)); + if (SDL_UnlockMutex(audioRingBuffer.mutex) < 0) die("Unable to unlock 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)); audioPosition += audioCount; } diff --git a/singe/postLink.sh b/singe/postLink.sh old mode 100644 new mode 100755 diff --git a/singe/thirdparty/build.sh b/singe/preBuild.sh similarity index 99% rename from singe/thirdparty/build.sh rename to singe/preBuild.sh index c10ab50ba..918ce31ca 100755 --- a/singe/thirdparty/build.sh +++ b/singe/preBuild.sh @@ -22,7 +22,7 @@ if [[ -z $1 ]]; then BITS=64 THIRDPARTY=$(pwd) - DEST="${THIRDPARTY}/../../thirdparty-build/${BITS}" + DEST="${THIRDPARTY}/../thirdparty-build/${BITS}" else THIRDPARTY=$1 DEST=$2/$3 diff --git a/singe/singe.pro b/singe/singe.pro index 97369f59d..fa139bb84 100644 --- a/singe/singe.pro +++ b/singe/singe.pro @@ -63,9 +63,10 @@ CONFIG += bits64 BUILDTHIRDARGS = \"$$PWD/thirdparty\" \"$$OUT_PWD/../thirdparty-build\" $$BITNESS 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 { - BUILDTHIRD.commands = bash $$PWD/thirdparty/build.sh $$BUILDTHIRDARGS + BUILDTHIRD.commands = bash $$PWD/preBuild.sh $$BUILDTHIRDARGS } BUILDTHIRD.target = this PRE_TARGETDEPS += this @@ -137,8 +138,7 @@ LIBS += \ -ldl OTHER_FILES += \ - thirdparty/build.sh \ - thirdparty/build.bat \ + preBuild.sh \ postLink.sh # Strip & UPX the final result diff --git a/singe/thirdparty/build.bat b/singe/thirdparty/build.bat deleted file mode 100644 index 5e2380199..000000000 --- a/singe/thirdparty/build.bat +++ /dev/null @@ -1,23 +0,0 @@ -@echo off -goto skipLicense - -# -# Singe 2 -# Copyright (C) 2019 Scott Duensing -# -# 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