forked from mia/Aegisub
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.
This commit is contained in:
parent
2bd33541c1
commit
0badb4059f
5 changed files with 33 additions and 33 deletions
|
@ -199,8 +199,12 @@ AudioProvider *AudioProviderFactoryManager::GetAudioProvider(wxString filename,
|
||||||
// Try a PCM provider first
|
// Try a PCM provider first
|
||||||
provider = CreatePCMAudioProvider(filename);
|
provider = CreatePCMAudioProvider(filename);
|
||||||
if (provider) {
|
if (provider) {
|
||||||
if (provider->GetBytesPerSample() == 2 && provider->GetSampleRate() >= 32000) return provider;
|
if (provider->GetBytesPerSample() == 2 && provider->GetSampleRate() >= 32000 && provider->GetChannels() == 1)
|
||||||
return new ConvertAudioProvider(provider);
|
return provider;
|
||||||
|
else {
|
||||||
|
provider = CreateConvertAudioProvider(provider);
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,7 +233,8 @@ AudioProvider *AudioProviderFactoryManager::GetAudioProvider(wxString filename,
|
||||||
if (!provider) throw error;
|
if (!provider) throw error;
|
||||||
|
|
||||||
// Give it a conversor if needed
|
// 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
|
// Change provider to RAM/HD cache if needed
|
||||||
if (cache == -1) cache = Options.AsInt(_T("Audio Cache"));
|
if (cache == -1) cache = Options.AsInt(_T("Audio Cache"));
|
||||||
|
|
|
@ -37,13 +37,14 @@
|
||||||
///////////
|
///////////
|
||||||
// Headers
|
// Headers
|
||||||
#include "audio_provider_convert.h"
|
#include "audio_provider_convert.h"
|
||||||
|
#include "audio_provider_downmix.h"
|
||||||
|
|
||||||
|
|
||||||
///////////////
|
///////////////
|
||||||
// Constructor
|
// Constructor
|
||||||
ConvertAudioProvider::ConvertAudioProvider(AudioProvider *src) {
|
ConvertAudioProvider::ConvertAudioProvider(AudioProvider *src) {
|
||||||
source = src;
|
source = src;
|
||||||
channels = 1;
|
channels = source->GetChannels();
|
||||||
num_samples = source->GetNumSamples();
|
num_samples = source->GetNumSamples();
|
||||||
sample_rate = source->GetSampleRate();
|
sample_rate = source->GetSampleRate();
|
||||||
bytes_per_sample = 2;
|
bytes_per_sample = 2;
|
||||||
|
@ -159,3 +160,15 @@ void ConvertAudioProvider::GetAudio(void *destination, int64_t start, int64_t co
|
||||||
delete [] buffer2;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -59,3 +59,5 @@ public:
|
||||||
void GetAudio(void *buf, int64_t start, int64_t count);
|
void GetAudio(void *buf, int64_t start, int64_t count);
|
||||||
wxString GetFilename() { return source->GetFilename(); }
|
wxString GetFilename() { return source->GetFilename(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AudioProvider *CreateConvertAudioProvider(AudioProvider *source_provider);
|
|
@ -115,21 +115,17 @@ LAVCAudioProvider::LAVCAudioProvider(Aegisub::String _filename)
|
||||||
if (!sample_rate)
|
if (!sample_rate)
|
||||||
sample_rate = codecContext->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
|
/* 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. */
|
ffmpeg always converts everything to 16-bit, but in the future it might become one. */
|
||||||
bytes_per_sample = 2;
|
bytes_per_sample = 2;
|
||||||
|
|
||||||
/* aegisub currently supports mono only, so always resample unless it's mono with the desired samplerate */
|
/* 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)) {
|
if (sample_rate != codecContext->sample_rate) {
|
||||||
// FIXME: ffmpeg currently doesn't support downmixing audio with more than two channels,
|
rsct = audio_resample_init(channels, channels, sample_rate, codecContext->sample_rate);
|
||||||
// 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 (!rsct)
|
if (!rsct)
|
||||||
throw _T("ffmpeg audio provider: Failed to initialize resampling");
|
throw _T("ffmpeg audio provider: Failed to initialize resampling");
|
||||||
|
|
||||||
resample_ratio = (float)sample_rate / (float)codecContext->sample_rate;
|
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;
|
length = (double)lavcfile->fctx->duration / AV_TIME_BASE;
|
||||||
else
|
else
|
||||||
length = (double)stream->duration * av_q2d(stream->time_base);
|
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);
|
buffer = (int16_t *)malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
|
@ -177,15 +173,15 @@ void LAVCAudioProvider::GetAudio(void *buf, int64_t start, int64_t count)
|
||||||
{
|
{
|
||||||
int16_t *_buf = (int16_t *)buf;
|
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 */
|
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 */
|
if (samples_to_decode < 0) /* requested beyond the end of the stream */
|
||||||
samples_to_decode = 0;
|
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
|
/* 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 */
|
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? */
|
/* do we have leftover samples from last time we were called? */
|
||||||
if (leftover_samples > 0) {
|
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_bytes = temp_output_buffer_size;
|
||||||
decoded_samples = decoded_bytes / 2; /* 2 bytes per sample */
|
decoded_samples = decoded_bytes / 2; /* 2 bytes per sample */
|
||||||
size -= decoded_bytes;
|
size -= retval;
|
||||||
|
|
||||||
/* do we need to resample? */
|
/* do we need to resample? */
|
||||||
if (rsct) {
|
if (rsct) {
|
||||||
|
|
|
@ -37,7 +37,6 @@
|
||||||
#include <wx/filename.h>
|
#include <wx/filename.h>
|
||||||
#include <wx/file.h>
|
#include <wx/file.h>
|
||||||
#include "audio_provider_pcm.h"
|
#include "audio_provider_pcm.h"
|
||||||
#include "audio_provider_downmix.h"
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "aegisub_endian.h"
|
#include "aegisub_endian.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -383,21 +382,6 @@ AudioProvider *CreatePCMAudioProvider(const wxString &filename)
|
||||||
provider = 0;
|
provider = 0;
|
||||||
wxLogDebug(_T("Creating PCM WAV reader failed with message: %s\nProceeding to try other providers."), msg);
|
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;
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue