mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-11 15:40:39 +00:00
Merge remote-tracking branch 'cc9cii/ffmpeg-swresample'
This commit is contained in:
commit
3f671c86a8
@ -12,7 +12,7 @@ before_install:
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq libgtest-dev google-mock
|
||||
- sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev libboost-wave-dev
|
||||
- sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev
|
||||
- sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev
|
||||
- sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev
|
||||
- sudo mkdir /usr/src/gtest/build
|
||||
- cd /usr/src/gtest/build
|
||||
|
@ -140,10 +140,24 @@ set(OPENMW_LIBS ${OENGINE_ALL})
|
||||
set(OPENMW_LIBS_HEADER)
|
||||
|
||||
# Sound setup
|
||||
set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE)
|
||||
find_package(FFmpeg REQUIRED)
|
||||
set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE AVRESAMPLE)
|
||||
unset(FFMPEG_LIBRARIES CACHE)
|
||||
find_package(FFmpeg)
|
||||
if ( NOT AVCODEC_FOUND OR NOT AVFORMAT_FOUND OR NOT AVUTIL_FOUND OR NOT SWSCALE_FOUND )
|
||||
message(FATAL_ERROR "FFmpeg component required, but not found!")
|
||||
endif()
|
||||
set(SOUND_INPUT_INCLUDES ${FFMPEG_INCLUDE_DIRS})
|
||||
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARIES})
|
||||
if( SWRESAMPLE_FOUND )
|
||||
add_definitions(-DHAVE_LIBSWRESAMPLE)
|
||||
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${SWRESAMPLE_LIBRARIES})
|
||||
else()
|
||||
if( AVRESAMPLE_FOUND )
|
||||
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${AVRESAMPLE_LIBRARIES})
|
||||
else()
|
||||
message(FATAL_ERROR "Install either libswresample (FFmpeg) or libavresample (Libav).")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# TinyXML
|
||||
option(USE_SYSTEM_TINYXML "Use system TinyXML library instead of internal." OFF)
|
||||
|
@ -55,7 +55,7 @@ add_openmw_dir (mwscript
|
||||
)
|
||||
|
||||
add_openmw_dir (mwsound
|
||||
soundmanagerimp openal_output ffmpeg_decoder sound sound_decoder sound_output loudness
|
||||
soundmanagerimp openal_output ffmpeg_decoder sound sound_decoder sound_output loudness libavwrapper
|
||||
)
|
||||
|
||||
add_openmw_dir (mwworld
|
||||
|
@ -32,10 +32,15 @@ extern "C"
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libswscale/swscale.h>
|
||||
|
||||
// From libavformat version 55.0.100 and onward the declaration of av_gettime() is removed from libavformat/avformat.h and moved
|
||||
// to libavutil/time.h
|
||||
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
|
||||
#define av_frame_alloc avcodec_alloc_frame
|
||||
#endif
|
||||
|
||||
// From libavformat version 55.0.100 and onward the declaration of av_gettime() is
|
||||
// removed from libavformat/avformat.h and moved to libavutil/time.h
|
||||
// https://github.com/FFmpeg/FFmpeg/commit/06a83505992d5f49846c18507a6c3eb8a47c650e
|
||||
#if AV_VERSION_INT(55, 0, 100) <= AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, LIBAVFORMAT_VERSION_MINOR, LIBAVFORMAT_VERSION_MICRO)
|
||||
#if AV_VERSION_INT(55, 0, 100) <= AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
|
||||
LIBAVFORMAT_VERSION_MINOR, LIBAVFORMAT_VERSION_MICRO)
|
||||
#include <libavutil/time.h>
|
||||
#endif
|
||||
|
||||
@ -46,30 +51,25 @@ extern "C"
|
||||
LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO)
|
||||
#include <libavutil/channel_layout.h>
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Decide whether to play binkaudio.
|
||||
#include <libavcodec/version.h>
|
||||
// libavcodec versions 54.10.100 (or maybe earlier) to 54.54.100 potentially crashes Windows 64bit.
|
||||
// From version 54.56 or higher, there's no sound due to the encoding format changing from S16 to FLTP
|
||||
// (see https://gitorious.org/ffmpeg/ffmpeg/commit/7bfd1766d1c18f07b0a2dd042418a874d49ea60d and
|
||||
// http://git.videolan.org/?p=ffmpeg.git;a=commitdiff;h=3049d5b9b32845c86aa5588bb3352bdeb2edfdb2;hp=43c6b45a53a186a187f7266e4d6bd3c2620519f1),
|
||||
// but does not crash (or at least no known crash).
|
||||
#if (LIBAVCODEC_VERSION_MAJOR > 54)
|
||||
#define FFMPEG_PLAY_BINKAUDIO
|
||||
// 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
|
||||
#ifdef HAVE_LIBSWRESAMPLE
|
||||
#include <libswresample/swresample.h>
|
||||
#else
|
||||
#ifdef _WIN64
|
||||
#if ((LIBAVCODEC_VERSION_MAJOR == 54) && (LIBAVCODEC_VERSION_MINOR >= 55))
|
||||
#define FFMPEG_PLAY_BINKAUDIO
|
||||
#endif
|
||||
#else
|
||||
#if ((LIBAVCODEC_VERSION_MAJOR == 54) && (LIBAVCODEC_VERSION_MINOR >= 10))
|
||||
#define FFMPEG_PLAY_BINKAUDIO
|
||||
#endif
|
||||
#endif
|
||||
/* FIXME: remove this section once libswresample is available on all platforms */
|
||||
#include <libavresample/avresample.h>
|
||||
#include <libavutil/opt.h>
|
||||
#define SwrContext AVAudioResampleContext
|
||||
int swr_init(AVAudioResampleContext *avr);
|
||||
void swr_free(AVAudioResampleContext **avr);
|
||||
int swr_convert( AVAudioResampleContext *avr, uint8_t** output, int out_samples, const uint8_t** input, int 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);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#define MAX_AUDIOQ_SIZE (5 * 16 * 1024)
|
||||
#define MAX_VIDEOQ_SIZE (5 * 256 * 1024)
|
||||
@ -317,6 +317,12 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder
|
||||
VideoState *mVideoState;
|
||||
AVStream *mAVStream;
|
||||
|
||||
SwrContext *mSwr;
|
||||
enum AVSampleFormat mOutputSampleFormat;
|
||||
uint8_t *mDataBuf;
|
||||
uint8_t **mFrameData;
|
||||
int mDataBufLen;
|
||||
|
||||
AutoAVPacket mPacket;
|
||||
AVFrame *mFrame;
|
||||
ssize_t mFramePos;
|
||||
@ -383,6 +389,28 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder
|
||||
if(!got_frame || frame->nb_samples <= 0)
|
||||
continue;
|
||||
|
||||
if(mSwr)
|
||||
{
|
||||
if(!mDataBuf || mDataBufLen < frame->nb_samples)
|
||||
{
|
||||
av_freep(&mDataBuf);
|
||||
if(av_samples_alloc(&mDataBuf, NULL, mAVStream->codec->channels,
|
||||
frame->nb_samples, mOutputSampleFormat, 0) < 0)
|
||||
break;
|
||||
else
|
||||
mDataBufLen = frame->nb_samples;
|
||||
}
|
||||
|
||||
if(swr_convert(mSwr, (uint8_t**)&mDataBuf, frame->nb_samples,
|
||||
(const uint8_t**)frame->extended_data, frame->nb_samples) < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
mFrameData = &mDataBuf;
|
||||
}
|
||||
else
|
||||
mFrameData = &frame->data[0];
|
||||
|
||||
mAudioClock += (double)frame->nb_samples /
|
||||
(double)mAVStream->codec->sample_rate;
|
||||
|
||||
@ -420,7 +448,7 @@ public:
|
||||
MovieAudioDecoder(VideoState *is)
|
||||
: mVideoState(is)
|
||||
, mAVStream(*is->audio_st)
|
||||
, mFrame(avcodec_alloc_frame())
|
||||
, mFrame(av_frame_alloc())
|
||||
, mFramePos(0)
|
||||
, mFrameSize(0)
|
||||
, mAudioClock(0.0)
|
||||
@ -429,10 +457,17 @@ public:
|
||||
/* Correct audio only if larger error than this */
|
||||
, mAudioDiffThreshold(2.0 * 0.050/* 50 ms */)
|
||||
, mAudioDiffAvgCount(0)
|
||||
, mSwr(0)
|
||||
, mOutputSampleFormat(AV_SAMPLE_FMT_NONE)
|
||||
, mDataBuf(NULL)
|
||||
, mFrameData(NULL)
|
||||
, mDataBufLen(0)
|
||||
{ }
|
||||
virtual ~MovieAudioDecoder()
|
||||
{
|
||||
av_freep(&mFrame);
|
||||
swr_free(&mSwr);
|
||||
av_freep(&mDataBuf);
|
||||
}
|
||||
|
||||
void getInfo(int *samplerate, MWSound::ChannelConfig *chans, MWSound::SampleType * type)
|
||||
@ -443,10 +478,18 @@ public:
|
||||
*type = MWSound::SampleType_Int16;
|
||||
else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_FLT)
|
||||
*type = MWSound::SampleType_Float32;
|
||||
else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_U8P)
|
||||
*type = MWSound::SampleType_UInt8;
|
||||
else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_S16P)
|
||||
*type = MWSound::SampleType_Int16;
|
||||
else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_FLTP)
|
||||
*type = MWSound::SampleType_Float32;
|
||||
else
|
||||
fail(std::string("Unsupported sample format: ")+
|
||||
av_get_sample_fmt_name(mAVStream->codec->sample_fmt));
|
||||
|
||||
int64_t ch_layout = mAVStream->codec->channel_layout;
|
||||
|
||||
if(mAVStream->codec->channel_layout == AV_CH_LAYOUT_MONO)
|
||||
*chans = MWSound::ChannelConfig_Mono;
|
||||
else if(mAVStream->codec->channel_layout == AV_CH_LAYOUT_STEREO)
|
||||
@ -461,9 +504,15 @@ public:
|
||||
{
|
||||
/* Unknown channel layout. Try to guess. */
|
||||
if(mAVStream->codec->channels == 1)
|
||||
{
|
||||
*chans = MWSound::ChannelConfig_Mono;
|
||||
ch_layout = AV_CH_LAYOUT_MONO;
|
||||
}
|
||||
else if(mAVStream->codec->channels == 2)
|
||||
{
|
||||
*chans = MWSound::ChannelConfig_Stereo;
|
||||
ch_layout = AV_CH_LAYOUT_STEREO;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::stringstream sstr("Unsupported raw channel count: ");
|
||||
@ -480,6 +529,30 @@ public:
|
||||
}
|
||||
|
||||
*samplerate = mAVStream->codec->sample_rate;
|
||||
|
||||
if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_U8P)
|
||||
mOutputSampleFormat = AV_SAMPLE_FMT_U8;
|
||||
else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_S16P)
|
||||
mOutputSampleFormat = AV_SAMPLE_FMT_S16;
|
||||
else if(mAVStream->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
|
||||
ch_layout, // output ch layout
|
||||
mOutputSampleFormat, // output sample format
|
||||
mAVStream->codec->sample_rate, // output sample rate
|
||||
ch_layout, // input ch layout
|
||||
mAVStream->codec->sample_fmt, // input sample format
|
||||
mAVStream->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 read(char *stream, size_t len)
|
||||
@ -500,7 +573,8 @@ public:
|
||||
}
|
||||
|
||||
mFramePos = std::min<ssize_t>(mFrameSize, sample_skip);
|
||||
sample_skip -= mFramePos;
|
||||
if(sample_skip > 0 || mFrameSize > -sample_skip)
|
||||
sample_skip -= mFramePos;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -508,7 +582,7 @@ public:
|
||||
if(mFramePos >= 0)
|
||||
{
|
||||
len1 = std::min<size_t>(len1, mFrameSize-mFramePos);
|
||||
memcpy(stream, mFrame->data[0]+mFramePos, len1);
|
||||
memcpy(stream, mFrameData[0]+mFramePos, len1);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -519,29 +593,29 @@ public:
|
||||
|
||||
/* add samples by copying the first sample*/
|
||||
if(n == 1)
|
||||
memset(stream, *mFrame->data[0], len1);
|
||||
memset(stream, *mFrameData[0], len1);
|
||||
else if(n == 2)
|
||||
{
|
||||
const int16_t val = *((int16_t*)mFrame->data[0]);
|
||||
const int16_t val = *((int16_t*)mFrameData[0]);
|
||||
for(size_t nb = 0;nb < len1;nb += n)
|
||||
*((int16_t*)(stream+nb)) = val;
|
||||
}
|
||||
else if(n == 4)
|
||||
{
|
||||
const int32_t val = *((int32_t*)mFrame->data[0]);
|
||||
const int32_t val = *((int32_t*)mFrameData[0]);
|
||||
for(size_t nb = 0;nb < len1;nb += n)
|
||||
*((int32_t*)(stream+nb)) = val;
|
||||
}
|
||||
else if(n == 8)
|
||||
{
|
||||
const int64_t val = *((int64_t*)mFrame->data[0]);
|
||||
const int64_t val = *((int64_t*)mFrameData[0]);
|
||||
for(size_t nb = 0;nb < len1;nb += n)
|
||||
*((int64_t*)(stream+nb)) = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(size_t nb = 0;nb < len1;nb += n)
|
||||
memcpy(stream+nb, mFrame->data[0], n);
|
||||
memcpy(stream+nb, mFrameData[0], n);
|
||||
}
|
||||
}
|
||||
|
||||
@ -768,9 +842,9 @@ void VideoState::video_thread_loop(VideoState *self)
|
||||
AVFrame *pFrame;
|
||||
double pts;
|
||||
|
||||
pFrame = avcodec_alloc_frame();
|
||||
pFrame = av_frame_alloc();
|
||||
|
||||
self->rgbaFrame = avcodec_alloc_frame();
|
||||
self->rgbaFrame = av_frame_alloc();
|
||||
avpicture_alloc((AVPicture*)self->rgbaFrame, PIX_FMT_RGBA, (*self->video_st)->codec->width, (*self->video_st)->codec->height);
|
||||
|
||||
while(self->videoq.get(packet, self) >= 0)
|
||||
@ -992,12 +1066,8 @@ void VideoState::init(const std::string& resourceName)
|
||||
|
||||
this->external_clock_base = av_gettime();
|
||||
|
||||
#if !defined(_WIN32) || defined(FFMPEG_PLAY_BINKAUDIO)
|
||||
if(audio_index >= 0)
|
||||
this->stream_open(audio_index, this->format_ctx);
|
||||
#else
|
||||
std::cout<<"FFmpeg sound disabled for \""+resourceName+"\""<<std::endl;
|
||||
#endif
|
||||
|
||||
if(video_index >= 0)
|
||||
{
|
||||
|
@ -5,6 +5,16 @@
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
extern "C" {
|
||||
#ifndef HAVE_LIBSWRESAMPLE
|
||||
/* FIXME: remove this section once libswresample is available on all platforms */
|
||||
int swr_init(AVAudioResampleContext *avr);
|
||||
void swr_free(AVAudioResampleContext **avr);
|
||||
int swr_convert( AVAudioResampleContext *avr, uint8_t** output, int out_samples, const uint8_t** input, int 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);
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace MWSound
|
||||
{
|
||||
|
||||
@ -95,6 +105,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 +155,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 +165,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 +211,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 +223,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 +248,8 @@ void FFmpeg_Decoder::close()
|
||||
|
||||
av_free_packet(&mPacket);
|
||||
av_freep(&mFrame);
|
||||
swr_free(&mSwr);
|
||||
av_freep(&mDataBuf);
|
||||
|
||||
if(mFormatCtx)
|
||||
{
|
||||
@ -268,10 +290,18 @@ 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));
|
||||
|
||||
int64_t ch_layout = (*mStream)->codec->channel_layout;
|
||||
|
||||
if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_MONO)
|
||||
*chans = ChannelConfig_Mono;
|
||||
else if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_STEREO)
|
||||
@ -286,9 +316,15 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *
|
||||
{
|
||||
/* Unknown channel layout. Try to guess. */
|
||||
if((*mStream)->codec->channels == 1)
|
||||
{
|
||||
*chans = ChannelConfig_Mono;
|
||||
ch_layout = AV_CH_LAYOUT_MONO;
|
||||
}
|
||||
else if((*mStream)->codec->channels == 2)
|
||||
{
|
||||
*chans = ChannelConfig_Stereo;
|
||||
ch_layout = AV_CH_LAYOUT_STEREO;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::stringstream sstr("Unsupported raw channel count: ");
|
||||
@ -305,6 +341,31 @@ 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
|
||||
ch_layout, // output ch layout
|
||||
mOutputSampleFormat, // output sample format
|
||||
(*mStream)->codec->sample_rate, // output sample rate
|
||||
ch_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 +384,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 +413,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;
|
||||
|
109
apps/openmw/mwsound/libavwrapper.cpp
Normal file
109
apps/openmw/mwsound/libavwrapper.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
#ifndef HAVE_LIBSWRESAMPLE
|
||||
extern "C"
|
||||
{
|
||||
#define __STDC_CONSTANT_MACROS
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
// From libavutil version 52.2.0 and onward the declaration of
|
||||
// AV_CH_LAYOUT_* is removed from libavcodec/avcodec.h and moved to
|
||||
// libavutil/channel_layout.h
|
||||
#if AV_VERSION_INT(52, 2, 0) <= AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
|
||||
LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO)
|
||||
#include <libavutil/channel_layout.h>
|
||||
#endif
|
||||
#include <libavresample/avresample.h>
|
||||
#include <libavutil/opt.h>
|
||||
|
||||
/* FIXME: delete this file once libswresample is available on all platforms */
|
||||
|
||||
int swr_init(AVAudioResampleContext *avr) { return 1; }
|
||||
|
||||
void swr_free(AVAudioResampleContext **avr) { avresample_free(avr); }
|
||||
|
||||
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;
|
||||
|
||||
int res;
|
||||
res = av_opt_set_int(avr, "out_channel_layout", out_ch_layout, 0);
|
||||
if(res < 0)
|
||||
{
|
||||
av_log(avr, AV_LOG_ERROR, "av_opt_set_int: out_ch_layout = %d\n", res);
|
||||
return 0;
|
||||
}
|
||||
res = av_opt_set_int(avr, "out_sample_fmt", out_fmt, 0);
|
||||
if(res < 0)
|
||||
{
|
||||
av_log(avr, AV_LOG_ERROR, "av_opt_set_int: out_fmt = %d\n", res);
|
||||
return 0;
|
||||
}
|
||||
res = av_opt_set_int(avr, "out_sample_rate", out_rate, 0);
|
||||
if(res < 0)
|
||||
{
|
||||
av_log(avr, AV_LOG_ERROR, "av_opt_set_int: out_rate = %d\n", res);
|
||||
return 0;
|
||||
}
|
||||
res = av_opt_set_int(avr, "in_channel_layout", in_ch_layout, 0);
|
||||
if(res < 0)
|
||||
{
|
||||
av_log(avr, AV_LOG_ERROR, "av_opt_set_int: in_ch_layout = %d\n", res);
|
||||
return 0;
|
||||
}
|
||||
res = av_opt_set_int(avr, "in_sample_fmt", in_fmt, 0);
|
||||
if(res < 0)
|
||||
{
|
||||
av_log(avr, AV_LOG_ERROR, "av_opt_set_int: in_fmt = %d\n", res);
|
||||
return 0;
|
||||
}
|
||||
res = av_opt_set_int(avr, "in_sample_rate", in_rate, 0);
|
||||
if(res < 0)
|
||||
{
|
||||
av_log(avr, AV_LOG_ERROR, "av_opt_set_int: in_rate = %d\n", res);
|
||||
return 0;
|
||||
}
|
||||
res = av_opt_set_int(avr, "internal_sample_fmt", AV_SAMPLE_FMT_FLTP, 0);
|
||||
if(res < 0)
|
||||
{
|
||||
av_log(avr, AV_LOG_ERROR, "av_opt_set_int: internal_sample_fmt\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if(avresample_open(avr) < 0)
|
||||
{
|
||||
av_log(avr, AV_LOG_ERROR, "Error opening context\n");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return avr;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
@ -14,6 +14,7 @@
|
||||
# - AVUTIL
|
||||
# - POSTPROCESS
|
||||
# - SWSCALE
|
||||
# - SWRESAMPLE
|
||||
# the following variables will be defined
|
||||
# <component>_FOUND - System has <component>
|
||||
# <component>_INCLUDE_DIRS - Include directory necessary for using the <component> headers
|
||||
@ -112,6 +113,8 @@ if (NOT FFMPEG_LIBRARIES)
|
||||
find_component(AVUTIL libavutil avutil libavutil/avutil.h)
|
||||
find_component(SWSCALE libswscale swscale libswscale/swscale.h)
|
||||
find_component(POSTPROC libpostproc postproc libpostproc/postprocess.h)
|
||||
find_component(SWRESAMPLE libswresample swresample libswresample/swresample.h)
|
||||
find_component(AVRESAMPLE libavresample avresample libavresample/avresample.h)
|
||||
|
||||
# Check if the required components were found and add their stuff to the FFMPEG_* vars.
|
||||
foreach (_component ${FFmpeg_FIND_COMPONENTS})
|
||||
@ -142,7 +145,7 @@ if (NOT FFMPEG_LIBRARIES)
|
||||
endif ()
|
||||
|
||||
# Now set the noncached _FOUND vars for the components.
|
||||
foreach (_component AVCODEC AVDEVICE AVFORMAT AVUTIL POSTPROCESS SWSCALE)
|
||||
foreach (_component AVCODEC AVDEVICE AVFORMAT AVUTIL POSTPROCESS SWSCALE SWRESAMPLE AVRESAMPLE)
|
||||
set_component_found(${_component})
|
||||
endforeach ()
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user