mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-03-14 01:19:59 +00:00
Add libswresample and libavresample support for sounds.
This commit is contained in:
parent
862c5fc8f6
commit
48a36442c6
@ -53,68 +53,66 @@ extern "C"
|
||||
#endif
|
||||
|
||||
// WARNING: avcodec versions up to 54.54.100 potentially crashes on Windows 64bit.
|
||||
}
|
||||
|
||||
// From version 54.56 binkaudio encoding format changed from S16 to FLTP. See:
|
||||
// https://gitorious.org/ffmpeg/ffmpeg/commit/7bfd1766d1c18f07b0a2dd042418a874d49ea60d
|
||||
// http://ffmpeg.zeranoe.com/forum/viewtopic.php?f=15&t=872
|
||||
extern "C" {
|
||||
#ifdef HAVE_LIBSWRESAMPLE
|
||||
#include <libswresample/swresample.h>
|
||||
#else
|
||||
/* nasty hack for systems without libswresample */
|
||||
#include <libavresample/avresample.h>
|
||||
#include <libavutil/opt.h>
|
||||
// From version 54.56 binkaudio encoding format changed from S16 to FLTP. See:
|
||||
// https://gitorious.org/ffmpeg/ffmpeg/commit/7bfd1766d1c18f07b0a2dd042418a874d49ea60d
|
||||
// http://ffmpeg.zeranoe.com/forum/viewtopic.php?f=15&t=872
|
||||
#ifdef HAVE_LIBSWRESAMPLE
|
||||
#include <libswresample/swresample.h>
|
||||
#else
|
||||
#include <libavresample/avresample.h>
|
||||
#include <libavutil/opt.h>
|
||||
/* FIXME: remove this section once libswresample is available on all platforms */
|
||||
|
||||
int swr_convert(
|
||||
AVAudioResampleContext *avr,
|
||||
uint8_t** output,
|
||||
int out_samples,
|
||||
const uint8_t** input,
|
||||
int in_samples)
|
||||
{
|
||||
// FIXME: potential performance hit
|
||||
int out_plane_size = 0;
|
||||
int in_plane_size = 0;
|
||||
return avresample_convert(avr, output, out_plane_size, out_samples,
|
||||
(uint8_t **)input, in_plane_size, in_samples);
|
||||
}
|
||||
|
||||
AVAudioResampleContext * swr_alloc_set_opts(
|
||||
AVAudioResampleContext *avr,
|
||||
int64_t out_ch_layout,
|
||||
AVSampleFormat out_fmt,
|
||||
int out_rate,
|
||||
int64_t in_ch_layout,
|
||||
AVSampleFormat in_fmt,
|
||||
int in_rate,
|
||||
int o,
|
||||
void* l)
|
||||
{
|
||||
avr = avresample_alloc_context();
|
||||
if(!avr)
|
||||
return 0;
|
||||
|
||||
if ((av_opt_set_int(avr, "out_channel_layout", out_ch_layout, 0) < 0) ||
|
||||
(av_opt_set_int(avr, "out_sample_fmt", out_fmt, 0) < 0) ||
|
||||
(av_opt_set_int(avr, "out_sample_rate", out_rate, 0) < 0) ||
|
||||
(av_opt_set_int(avr, "in_channel_layout", in_ch_layout, 0) < 0) ||
|
||||
(av_opt_set_int(avr, "in_sample_fmt", in_fmt, 0) < 0) ||
|
||||
(av_opt_set_int(avr, "in_sample_rate", in_rate, 0) < 0))
|
||||
int swr_convert(
|
||||
AVAudioResampleContext *avr,
|
||||
uint8_t** output,
|
||||
int out_samples,
|
||||
const uint8_t** input,
|
||||
int in_samples)
|
||||
{
|
||||
return 0;
|
||||
// FIXME: potential performance hit
|
||||
int out_plane_size = 0;
|
||||
int in_plane_size = 0;
|
||||
return avresample_convert(avr, output, out_plane_size, out_samples,
|
||||
(uint8_t **)input, in_plane_size, in_samples);
|
||||
}
|
||||
|
||||
if(avresample_open(avr) < 0)
|
||||
return 0;
|
||||
else
|
||||
return avr;
|
||||
}
|
||||
AVAudioResampleContext * swr_alloc_set_opts(
|
||||
AVAudioResampleContext *avr,
|
||||
int64_t out_ch_layout,
|
||||
AVSampleFormat out_fmt,
|
||||
int out_rate,
|
||||
int64_t in_ch_layout,
|
||||
AVSampleFormat in_fmt,
|
||||
int in_rate,
|
||||
int o,
|
||||
void* l)
|
||||
{
|
||||
avr = avresample_alloc_context();
|
||||
if(!avr)
|
||||
return 0;
|
||||
|
||||
void swr_free(AVAudioResampleContext **avr) { avresample_free(avr); }
|
||||
int swr_init(AVAudioResampleContext *avr) { return 1; }
|
||||
#define SwrContext AVAudioResampleContext
|
||||
#endif
|
||||
if ((av_opt_set_int(avr, "out_channel_layout", out_ch_layout, 0) < 0) ||
|
||||
(av_opt_set_int(avr, "out_sample_fmt", out_fmt, 0) < 0) ||
|
||||
(av_opt_set_int(avr, "out_sample_rate", out_rate, 0) < 0) ||
|
||||
(av_opt_set_int(avr, "in_channel_layout", in_ch_layout, 0) < 0) ||
|
||||
(av_opt_set_int(avr, "in_sample_fmt", in_fmt, 0) < 0) ||
|
||||
(av_opt_set_int(avr, "in_sample_rate", in_rate, 0) < 0))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(avresample_open(avr) < 0)
|
||||
return 0;
|
||||
else
|
||||
return avr;
|
||||
}
|
||||
|
||||
void swr_free(AVAudioResampleContext **avr) { avresample_free(avr); }
|
||||
int swr_init(AVAudioResampleContext *avr) { return 1; }
|
||||
#define SwrContext AVAudioResampleContext
|
||||
#endif
|
||||
}
|
||||
|
||||
#define MAX_AUDIOQ_SIZE (5 * 16 * 1024)
|
||||
|
@ -5,6 +5,58 @@
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#ifndef HAVE_LIBSWRESAMPLE
|
||||
/* FIXME: remove this section once libswresample is available on all platforms */
|
||||
|
||||
int swr_convert(
|
||||
AVAudioResampleContext *avr,
|
||||
uint8_t** output,
|
||||
int out_samples,
|
||||
const uint8_t** input,
|
||||
int in_samples)
|
||||
{
|
||||
// FIXME: potential performance hit
|
||||
int out_plane_size = 0;
|
||||
int in_plane_size = 0;
|
||||
return avresample_convert(avr, output, out_plane_size, out_samples,
|
||||
(uint8_t **)input, in_plane_size, in_samples);
|
||||
}
|
||||
|
||||
AVAudioResampleContext * swr_alloc_set_opts(
|
||||
AVAudioResampleContext *avr,
|
||||
int64_t out_ch_layout,
|
||||
AVSampleFormat out_fmt,
|
||||
int out_rate,
|
||||
int64_t in_ch_layout,
|
||||
AVSampleFormat in_fmt,
|
||||
int in_rate,
|
||||
int o,
|
||||
void* l)
|
||||
{
|
||||
avr = avresample_alloc_context();
|
||||
if(!avr)
|
||||
return 0;
|
||||
|
||||
if ((av_opt_set_int(avr, "out_channel_layout", out_ch_layout, 0) < 0) ||
|
||||
(av_opt_set_int(avr, "out_sample_fmt", out_fmt, 0) < 0) ||
|
||||
(av_opt_set_int(avr, "out_sample_rate", out_rate, 0) < 0) ||
|
||||
(av_opt_set_int(avr, "in_channel_layout", in_ch_layout, 0) < 0) ||
|
||||
(av_opt_set_int(avr, "in_sample_fmt", in_fmt, 0) < 0) ||
|
||||
(av_opt_set_int(avr, "in_sample_rate", in_rate, 0) < 0))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(avresample_open(avr) < 0)
|
||||
return 0;
|
||||
else
|
||||
return avr;
|
||||
}
|
||||
|
||||
void swr_free(AVAudioResampleContext **avr) { avresample_free(avr); }
|
||||
int swr_init(AVAudioResampleContext *avr) { return 1; }
|
||||
#endif
|
||||
|
||||
namespace MWSound
|
||||
{
|
||||
|
||||
@ -95,6 +147,29 @@ bool FFmpeg_Decoder::getAVAudioData()
|
||||
memmove(mPacket.data, &mPacket.data[len], remaining);
|
||||
av_shrink_packet(&mPacket, remaining);
|
||||
}
|
||||
|
||||
if(mSwr)
|
||||
{
|
||||
if(!mDataBuf || mDataBufLen < mFrame->nb_samples)
|
||||
{
|
||||
av_freep(&mDataBuf);
|
||||
if(av_samples_alloc(&mDataBuf, NULL, (*mStream)->codec->channels,
|
||||
mFrame->nb_samples, mOutputSampleFormat, 0) < 0)
|
||||
break;
|
||||
else
|
||||
mDataBufLen = mFrame->nb_samples;
|
||||
}
|
||||
|
||||
if(swr_convert(mSwr, (uint8_t**)&mDataBuf, mFrame->nb_samples,
|
||||
(const uint8_t**)mFrame->extended_data, mFrame->nb_samples) < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
mFrameData = &mDataBuf;
|
||||
}
|
||||
else
|
||||
mFrameData = &mFrame->data[0];
|
||||
|
||||
} while(got_frame == 0 || mFrame->nb_samples == 0);
|
||||
mNextPts += (double)mFrame->nb_samples / (double)(*mStream)->codec->sample_rate;
|
||||
|
||||
@ -122,7 +197,7 @@ size_t FFmpeg_Decoder::readAVAudioData(void *data, size_t length)
|
||||
size_t rem = std::min<size_t>(length-dec, mFrameSize-mFramePos);
|
||||
|
||||
/* Copy the data to the app's buffer and increment */
|
||||
memcpy(data, mFrame->data[0]+mFramePos, rem);
|
||||
memcpy(data, mFrameData[0]+mFramePos, rem);
|
||||
data = (char*)data + rem;
|
||||
dec += rem;
|
||||
mFramePos += rem;
|
||||
@ -132,19 +207,6 @@ size_t FFmpeg_Decoder::readAVAudioData(void *data, size_t length)
|
||||
return dec;
|
||||
}
|
||||
|
||||
static AVSampleFormat ffmpegNonPlanarSampleFormat (AVSampleFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case AV_SAMPLE_FMT_U8P: return AV_SAMPLE_FMT_U8;
|
||||
case AV_SAMPLE_FMT_S16P: return AV_SAMPLE_FMT_S16;
|
||||
case AV_SAMPLE_FMT_S32P: return AV_SAMPLE_FMT_S32;
|
||||
case AV_SAMPLE_FMT_FLTP: return AV_SAMPLE_FMT_FLT;
|
||||
case AV_SAMPLE_FMT_DBLP: return AV_SAMPLE_FMT_DBL;
|
||||
default:return format;
|
||||
}
|
||||
}
|
||||
|
||||
void FFmpeg_Decoder::open(const std::string &fname)
|
||||
{
|
||||
close();
|
||||
@ -191,7 +253,7 @@ void FFmpeg_Decoder::open(const std::string &fname)
|
||||
if(!mStream)
|
||||
fail("No audio streams in "+fname);
|
||||
|
||||
(*mStream)->codec->request_sample_fmt = ffmpegNonPlanarSampleFormat ((*mStream)->codec->sample_fmt);
|
||||
(*mStream)->codec->request_sample_fmt = (*mStream)->codec->sample_fmt;
|
||||
|
||||
AVCodec *codec = avcodec_find_decoder((*mStream)->codec->codec_id);
|
||||
if(!codec)
|
||||
@ -203,7 +265,7 @@ void FFmpeg_Decoder::open(const std::string &fname)
|
||||
if(avcodec_open2((*mStream)->codec, codec, NULL) < 0)
|
||||
fail("Failed to open audio codec " + std::string(codec->long_name));
|
||||
|
||||
mFrame = avcodec_alloc_frame();
|
||||
mFrame = av_frame_alloc();
|
||||
}
|
||||
catch(std::exception&)
|
||||
{
|
||||
@ -228,6 +290,8 @@ void FFmpeg_Decoder::close()
|
||||
|
||||
av_free_packet(&mPacket);
|
||||
av_freep(&mFrame);
|
||||
swr_free(&mSwr);
|
||||
av_freep(&mDataBuf);
|
||||
|
||||
if(mFormatCtx)
|
||||
{
|
||||
@ -268,6 +332,12 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *
|
||||
*type = SampleType_Int16;
|
||||
else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLT)
|
||||
*type = SampleType_Float32;
|
||||
else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_U8P)
|
||||
*type = SampleType_UInt8;
|
||||
else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_S16P)
|
||||
*type = SampleType_Int16;
|
||||
else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLTP)
|
||||
*type = SampleType_Float32;
|
||||
else
|
||||
fail(std::string("Unsupported sample format: ")+
|
||||
av_get_sample_fmt_name((*mStream)->codec->sample_fmt));
|
||||
@ -305,6 +375,30 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *
|
||||
}
|
||||
|
||||
*samplerate = (*mStream)->codec->sample_rate;
|
||||
|
||||
if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_U8P)
|
||||
mOutputSampleFormat = AV_SAMPLE_FMT_U8;
|
||||
else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_S16P)
|
||||
mOutputSampleFormat = AV_SAMPLE_FMT_S16;
|
||||
else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLTP)
|
||||
mOutputSampleFormat = AV_SAMPLE_FMT_FLT;
|
||||
|
||||
if(mOutputSampleFormat != AV_SAMPLE_FMT_NONE)
|
||||
{
|
||||
mSwr = swr_alloc_set_opts(mSwr, // SwrContext
|
||||
(*mStream)->codec->channel_layout, // output ch layout
|
||||
mOutputSampleFormat, // output sample format
|
||||
(*mStream)->codec->sample_rate, // output sample rate
|
||||
(*mStream)->codec->channel_layout, // input ch layout
|
||||
(*mStream)->codec->sample_fmt, // input sample format
|
||||
(*mStream)->codec->sample_rate, // input sample rate
|
||||
0, // logging level offset
|
||||
NULL); // log context
|
||||
if(!mSwr)
|
||||
fail(std::string("Couldn't allocate SwrContext"));
|
||||
if(swr_init(mSwr) < 0)
|
||||
fail(std::string("Couldn't initialize SwrContext"));
|
||||
}
|
||||
}
|
||||
|
||||
size_t FFmpeg_Decoder::read(char *buffer, size_t bytes)
|
||||
@ -323,7 +417,7 @@ void FFmpeg_Decoder::readAll(std::vector<char> &output)
|
||||
{
|
||||
size_t got = mFrame->nb_samples * (*mStream)->codec->channels *
|
||||
av_get_bytes_per_sample((*mStream)->codec->sample_fmt);
|
||||
const char *inbuf = reinterpret_cast<char*>(mFrame->data[0]);
|
||||
const char *inbuf = reinterpret_cast<char*>(mFrameData[0]);
|
||||
output.insert(output.end(), inbuf, inbuf+got);
|
||||
}
|
||||
}
|
||||
@ -352,6 +446,11 @@ FFmpeg_Decoder::FFmpeg_Decoder()
|
||||
, mFrameSize(0)
|
||||
, mFramePos(0)
|
||||
, mNextPts(0.0)
|
||||
, mSwr(0)
|
||||
, mOutputSampleFormat(AV_SAMPLE_FMT_NONE)
|
||||
, mDataBuf(NULL)
|
||||
, mFrameData(NULL)
|
||||
, mDataBufLen(0)
|
||||
{
|
||||
memset(&mPacket, 0, sizeof(mPacket));
|
||||
|
||||
|
@ -18,6 +18,21 @@ extern "C"
|
||||
LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO)
|
||||
#include <libavutil/channel_layout.h>
|
||||
#endif
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
|
||||
#define av_frame_alloc avcodec_alloc_frame
|
||||
#endif
|
||||
|
||||
// From version 54.56 binkaudio encoding format changed from S16 to FLTP. See:
|
||||
// https://gitorious.org/ffmpeg/ffmpeg/commit/7bfd1766d1c18f07b0a2dd042418a874d49ea60d
|
||||
// http://ffmpeg.zeranoe.com/forum/viewtopic.php?f=15&t=872
|
||||
#ifdef HAVE_LIBSWRESAMPLE
|
||||
#include <libswresample/swresample.h>
|
||||
#else
|
||||
#include <libavresample/avresample.h>
|
||||
#include <libavutil/opt.h>
|
||||
#define SwrContext AVAudioResampleContext
|
||||
#endif
|
||||
}
|
||||
|
||||
#include <string>
|
||||
@ -40,6 +55,12 @@ namespace MWSound
|
||||
|
||||
double mNextPts;
|
||||
|
||||
SwrContext *mSwr;
|
||||
enum AVSampleFormat mOutputSampleFormat;
|
||||
uint8_t *mDataBuf;
|
||||
uint8_t **mFrameData;
|
||||
int mDataBufLen;
|
||||
|
||||
bool getNextPacket();
|
||||
|
||||
Ogre::DataStreamPtr mDataStream;
|
||||
|
Loading…
x
Reference in New Issue
Block a user