From 0badb4059f172e0da92888c297bba058aa544e91 Mon Sep 17 00:00:00 2001 From: Karl Blomster Date: Wed, 16 Jul 2008 13:22:06 +0000 Subject: [PATCH] Restructured audio providing a bit. If a provider cannot provide 16-bit mono audio with a sample rate higher than 32kHz, an intermediate converting provider will be inserted to fix it. Made the lavc audio provider rely on this for downmixing instead of doing it with libavcodec (used to fail on audio with >2 channels). Originally committed to SVN as r2265. --- aegisub/audio_provider.cpp | 11 ++++++++--- aegisub/audio_provider_convert.cpp | 15 ++++++++++++++- aegisub/audio_provider_convert.h | 2 ++ aegisub/audio_provider_lavc.cpp | 22 +++++++++------------- aegisub/audio_provider_pcm.cpp | 16 ---------------- 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/aegisub/audio_provider.cpp b/aegisub/audio_provider.cpp index 5b1d53662..cb680bb4f 100644 --- a/aegisub/audio_provider.cpp +++ b/aegisub/audio_provider.cpp @@ -199,8 +199,12 @@ AudioProvider *AudioProviderFactoryManager::GetAudioProvider(wxString filename, // Try a PCM provider first provider = CreatePCMAudioProvider(filename); if (provider) { - if (provider->GetBytesPerSample() == 2 && provider->GetSampleRate() >= 32000) return provider; - return new ConvertAudioProvider(provider); + if (provider->GetBytesPerSample() == 2 && provider->GetSampleRate() >= 32000 && provider->GetChannels() == 1) + return provider; + else { + provider = CreateConvertAudioProvider(provider); + return provider; + } } } @@ -229,7 +233,8 @@ AudioProvider *AudioProviderFactoryManager::GetAudioProvider(wxString filename, if (!provider) throw error; // Give it a conversor if needed - if (provider->GetBytesPerSample() != 2 || provider->GetSampleRate() < 32000) provider = new ConvertAudioProvider(provider); + if (provider->GetBytesPerSample() != 2 || provider->GetSampleRate() < 32000 || provider->GetChannels() != 1) + provider = CreateConvertAudioProvider(provider); // Change provider to RAM/HD cache if needed if (cache == -1) cache = Options.AsInt(_T("Audio Cache")); diff --git a/aegisub/audio_provider_convert.cpp b/aegisub/audio_provider_convert.cpp index 54e2eb8a4..b00ee7ebb 100644 --- a/aegisub/audio_provider_convert.cpp +++ b/aegisub/audio_provider_convert.cpp @@ -37,13 +37,14 @@ /////////// // Headers #include "audio_provider_convert.h" +#include "audio_provider_downmix.h" /////////////// // Constructor ConvertAudioProvider::ConvertAudioProvider(AudioProvider *src) { source = src; - channels = 1; + channels = source->GetChannels(); num_samples = source->GetNumSamples(); sample_rate = source->GetSampleRate(); bytes_per_sample = 2; @@ -159,3 +160,15 @@ void ConvertAudioProvider::GetAudio(void *destination, int64_t start, int64_t co delete [] buffer2; } } + +// See if we need to downmix the number of channels +AudioProvider *CreateConvertAudioProvider(AudioProvider *source_provider) { + AudioProvider *provider = source_provider; + if (provider->GetBytesPerSample() != 2 || provider->GetSampleRate() < 32000) + provider = new ConvertAudioProvider(source_provider); + + if (provider->GetChannels() != 1) + provider = new DownmixingAudioProvider(provider); + + return provider; +} diff --git a/aegisub/audio_provider_convert.h b/aegisub/audio_provider_convert.h index e8f376f9f..16396ca01 100644 --- a/aegisub/audio_provider_convert.h +++ b/aegisub/audio_provider_convert.h @@ -59,3 +59,5 @@ public: void GetAudio(void *buf, int64_t start, int64_t count); wxString GetFilename() { return source->GetFilename(); } }; + +AudioProvider *CreateConvertAudioProvider(AudioProvider *source_provider); \ No newline at end of file diff --git a/aegisub/audio_provider_lavc.cpp b/aegisub/audio_provider_lavc.cpp index 86ba6f980..b26be8654 100644 --- a/aegisub/audio_provider_lavc.cpp +++ b/aegisub/audio_provider_lavc.cpp @@ -115,21 +115,17 @@ LAVCAudioProvider::LAVCAudioProvider(Aegisub::String _filename) if (!sample_rate) sample_rate = codecContext->sample_rate; - channels = 1; + /* rely on the downmixing audio provider to do downmixing for us later */ + channels = codecContext->channels; /* FIXME: this entire provider always assumes 16-bit audio. Currently that isn't a problem since ffmpeg always converts everything to 16-bit, but in the future it might become one. */ bytes_per_sample = 2; /* aegisub currently supports mono only, so always resample unless it's mono with the desired samplerate */ - if ((sample_rate != codecContext->sample_rate) || (codecContext->channels > 1)) { - // FIXME: ffmpeg currently doesn't support downmixing audio with more than two channels, - // remove the following line when it does. - if (codecContext->channels > 2) - throw _T("ffmpeg audio provider: Downmixing audio with more than two channels is currently not supported by ffmpeg"); - rsct = audio_resample_init(1, codecContext->channels, sample_rate, codecContext->sample_rate); + if (sample_rate != codecContext->sample_rate) { + rsct = audio_resample_init(channels, channels, sample_rate, codecContext->sample_rate); if (!rsct) throw _T("ffmpeg audio provider: Failed to initialize resampling"); - resample_ratio = (float)sample_rate / (float)codecContext->sample_rate; } @@ -141,7 +137,7 @@ LAVCAudioProvider::LAVCAudioProvider(Aegisub::String _filename) length = (double)lavcfile->fctx->duration / AV_TIME_BASE; else length = (double)stream->duration * av_q2d(stream->time_base); - num_samples = (int64_t)(length * sample_rate); + num_samples = (int64_t)(length * sample_rate); // number of samples per channel buffer = (int16_t *)malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE); if (!buffer) @@ -177,15 +173,15 @@ void LAVCAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) { int16_t *_buf = (int16_t *)buf; - int64_t samples_to_decode = num_samples - start; /* samples left to the end of the stream */ + int64_t samples_to_decode = (num_samples - start) * channels; /* samples left to the end of the stream */ if (count < samples_to_decode) /* haven't reached the end yet, so just decode the requested number of samples */ - samples_to_decode = count; + samples_to_decode = count * channels; /* times the number of channels */ if (samples_to_decode < 0) /* requested beyond the end of the stream */ samples_to_decode = 0; /* if we got asked for more samples than there are left in the stream, add zeros to the decoding buffer until we have enough to fill the request */ - memset(_buf + samples_to_decode, 0, (count - samples_to_decode) * 2); + memset(_buf + samples_to_decode, 0, ((count * channels) - samples_to_decode) * 2); /* do we have leftover samples from last time we were called? */ if (leftover_samples > 0) { @@ -220,7 +216,7 @@ void LAVCAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) decoded_bytes = temp_output_buffer_size; decoded_samples = decoded_bytes / 2; /* 2 bytes per sample */ - size -= decoded_bytes; + size -= retval; /* do we need to resample? */ if (rsct) { diff --git a/aegisub/audio_provider_pcm.cpp b/aegisub/audio_provider_pcm.cpp index 27fdc184a..779178076 100644 --- a/aegisub/audio_provider_pcm.cpp +++ b/aegisub/audio_provider_pcm.cpp @@ -37,7 +37,6 @@ #include #include #include "audio_provider_pcm.h" -#include "audio_provider_downmix.h" #include "utils.h" #include "aegisub_endian.h" #include @@ -383,21 +382,6 @@ AudioProvider *CreatePCMAudioProvider(const wxString &filename) provider = 0; wxLogDebug(_T("Creating PCM WAV reader failed with message: %s\nProceeding to try other providers."), msg); } - catch (...) { - provider = 0; - } - - if (provider && provider->GetChannels() > 1) { - // Can't feed non-mono audio to the rest of the program. - // Create a downmixing proxy and if it fails, don't provide PCM. - try { - provider = new DownmixingAudioProvider(provider); - } - catch (...) { - delete provider; - provider = 0; - } - } return provider; }