diff --git a/.travis.yml b/.travis.yml index b5c113af0..9308ccf87 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/CMakeLists.txt b/CMakeLists.txt index 407f616c4..2252ec9da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index ff583fe5c..0ad2cbd2a 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -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 diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 08d047472..aa2f24101 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -32,10 +32,15 @@ extern "C" #include #include - // 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 #endif @@ -46,30 +51,25 @@ extern "C" LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO) #include #endif -} -#ifdef _WIN32 - // Decide whether to play binkaudio. - #include - // 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 #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 + #include + #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(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(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+"\""<= 0) { diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 982d0c5ff..7b6e12576 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -5,6 +5,16 @@ #include +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(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 &output) { size_t got = mFrame->nb_samples * (*mStream)->codec->channels * av_get_bytes_per_sample((*mStream)->codec->sample_fmt); - const char *inbuf = reinterpret_cast(mFrame->data[0]); + const char *inbuf = reinterpret_cast(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)); diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpeg_decoder.hpp index 8276b45c7..dc9937e81 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.hpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.hpp @@ -18,6 +18,21 @@ extern "C" LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO) #include #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 +#else +#include +#include +#define SwrContext AVAudioResampleContext +#endif } #include @@ -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; diff --git a/apps/openmw/mwsound/libavwrapper.cpp b/apps/openmw/mwsound/libavwrapper.cpp new file mode 100644 index 000000000..a12f412d1 --- /dev/null +++ b/apps/openmw/mwsound/libavwrapper.cpp @@ -0,0 +1,109 @@ +#ifndef HAVE_LIBSWRESAMPLE +extern "C" +{ +#define __STDC_CONSTANT_MACROS +#include + +#include +#include +// 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 +#endif +#include +#include + +/* 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 diff --git a/cmake/FindFFmpeg.cmake b/cmake/FindFFmpeg.cmake index a3509597b..74584bf31 100644 --- a/cmake/FindFFmpeg.cmake +++ b/cmake/FindFFmpeg.cmake @@ -14,6 +14,7 @@ # - AVUTIL # - POSTPROCESS # - SWSCALE +# - SWRESAMPLE # the following variables will be defined # _FOUND - System has # _INCLUDE_DIRS - Include directory necessary for using the 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 ()