From 944f99b23a11c1d206a1dc8fa70f6e8c4c29fc6b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 31 Aug 2014 13:20:33 +1000 Subject: [PATCH 01/31] Initial commit of FLTP format binkaudio support. Converts to FLT format by manually interleaving decoded samples. swresample library is included with a view to use swr_convert() in future versions, but not used in this commit. --- CMakeLists.txt | 2 +- apps/openmw/mwrender/videoplayer.cpp | 172 ++++++++++++++++++++++----- cmake/FindFFmpeg.cmake | 6 +- 3 files changed, 150 insertions(+), 30 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 47575e0ce..e1af8b0b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,7 +139,7 @@ set(OPENMW_LIBS ${OENGINE_ALL}) set(OPENMW_LIBS_HEADER) # Sound setup -set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE) +set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE) find_package(FFmpeg REQUIRED) set(SOUND_INPUT_INCLUDES ${FFMPEG_INCLUDE_DIRS}) set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARIES}) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 2d05f2770..00443fdaa 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -32,10 +32,11 @@ 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 + // 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 +47,27 @@ 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) + // 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 + #if AV_VERSION_INT(54, 56, 0) <= AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ + LIBAVCODEC_VERSION_MINOR, LIBAVCODEC_VERSION_MICRO) + #include /* swr_init, swr_alloc, swr_convert, swr_free */ + #include /* av_opt_set_int, av_opt_set_sample_fmt */ #define FFMPEG_PLAY_BINKAUDIO - #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 + #elif defined(_WIN32) && defined(_WIN64) + // Versions up to 54.54.100 potentially crashes on Windows 64bit. + #if ((LIBAVCODEC_VERSION_MAJOR == 54) && (LIBAVCODEC_VERSION_MINOR >= 55)) + #define FFMPEG_PLAY_BINKAUDIO + #endif + #elif defined(_WIN32) + // 54.10.100 is a known working version on 32bit, but earlier ones may also work. + #if ((LIBAVCODEC_VERSION_MAJOR == 54) && (LIBAVCODEC_VERSION_MINOR >= 10)) + #define FFMPEG_PLAY_BINKAUDIO #endif #endif -#endif +} #define MAX_AUDIOQ_SIZE (5 * 16 * 1024) #define MAX_VIDEOQ_SIZE (5 * 256 * 1024) @@ -317,8 +315,12 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder VideoState *mVideoState; AVStream *mAVStream; + SwrContext *mSwr; /* non-zero indicates FLTP format */ + int mSamplesAllChannels; + int mSampleSize; + AutoAVPacket mPacket; - AVFrame *mFrame; + AVFrame *mFrame; /* AVFrame is now defined in libavutil/frame.h (used to be libavcodec/avcodec.h) */ ssize_t mFramePos; ssize_t mFrameSize; @@ -420,7 +422,11 @@ public: MovieAudioDecoder(VideoState *is) : mVideoState(is) , mAVStream(*is->audio_st) +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 28, 1) , mFrame(avcodec_alloc_frame()) +#else + , mFrame(av_frame_alloc()) +#endif , mFramePos(0) , mFrameSize(0) , mAudioClock(0.0) @@ -429,10 +435,15 @@ public: /* Correct audio only if larger error than this */ , mAudioDiffThreshold(2.0 * 0.050/* 50 ms */) , mAudioDiffAvgCount(0) + , mSwr(0) + , mSamplesAllChannels(0) + , mSampleSize(0) { } virtual ~MovieAudioDecoder() { av_freep(&mFrame); + if(mSwr) + swr_free(&mSwr); } void getInfo(int *samplerate, MWSound::ChannelConfig *chans, MWSound::SampleType * type) @@ -443,6 +454,12 @@ 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_FLTP) + { + // resample to a known format for OpenAL_SoundStream + // TODO: allow different size sample format, e.g. Int16 + *type = MWSound::SampleType_Float32; + } else fail(std::string("Unsupported sample format: ")+ av_get_sample_fmt_name(mAVStream->codec->sample_fmt)); @@ -480,17 +497,65 @@ public: } *samplerate = mAVStream->codec->sample_rate; + + // FIXME: error handling + if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_FLTP) + { + mSwr = swr_alloc(); + av_opt_set_int(mSwr, "in_channel_layout", mAVStream->codec->channel_layout, 0); + av_opt_set_int(mSwr, "out_channel_layout", mAVStream->codec->channel_layout, 0); + av_opt_set_int(mSwr, "in_sample_rate", mAVStream->codec->sample_rate, 0); + av_opt_set_int(mSwr, "out_sample_rate", mAVStream->codec->sample_rate, 0); + av_opt_set_sample_fmt(mSwr, "in_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); + av_opt_set_sample_fmt(mSwr, "out_sample_fmt", AV_SAMPLE_FMT_FLT, 0); // TODO: Try S16 + swr_init(mSwr); + } + + mSamplesAllChannels = av_get_bytes_per_sample(mAVStream->codec->sample_fmt) * + mAVStream->codec->channels; + mSampleSize = av_get_bytes_per_sample(mAVStream->codec->sample_fmt); } + /* + * stream is a ptr to vector on the stack, see OpenAL_SoundStream::process in + * mwsound/openal_output.cpp (around line 481) + * + * len is the size of the output buffer (i.e. stream) based on the number of + * channels, rate and sample type (as reported by getInfo). + * + * sample_skip is the number of bytes to skip (from all channels) or repeat (i.e. negative) + * + * mFrameSize is the number of bytes decoded audio frame (from all channels), or -1 if finished + * + * + * +---------------------------------------------------------------------------------+ + * | | + * |<------------------------------------------ len -------------------------------->| + * | | + * |<------ mFrameSize ------>| | + * | | + * +---------------------------------------------------------------------------------+ + * ^ + * | + * mFramePos >= 0 + * + * |<----- len1 -------->| + * + */ size_t read(char *stream, size_t len) { int sample_skip = synchronize_audio(); size_t total = 0; + float *outputStream = (float *)&stream[0]; + //uint16_t *intStream = (uint16_t *)&stream[0]; + while(total < len) { if(mFramePos >= mFrameSize) { + // for FLT sample format mFrameSize returned by audio_decode_frame is: + // 1920 samples x 4 bytes/sample x 2 channels = 15360 bytes /* We have already sent all our data; get more */ mFrameSize = audio_decode_frame(mFrame); if(mFrameSize < 0) @@ -508,9 +573,56 @@ public: if(mFramePos >= 0) { len1 = std::min(len1, mFrameSize-mFramePos); - memcpy(stream, mFrame->data[0]+mFramePos, len1); + + if(mSwr) + { + // Convert from AV_SAMPLE_FMT_FLTP to AV_SAMPLE_FMT_FLT + // FIXME: support channel formats other than stereo + // FIXME: support sample formats other than Float32 + float* inputChannel0 = (float*)mFrame->extended_data[0]; + float* inputChannel1 = (float*)mFrame->extended_data[1]; +#if 0 + uint16_t* inputChannel0 = (uint16_t*)mFrame->extended_data[0]; + uint16_t* inputChannel1 = (uint16_t*)mFrame->extended_data[1]; +#endif + inputChannel0 += mFramePos/mSamplesAllChannels; + inputChannel1 += mFramePos/mSamplesAllChannels; + //if(mFramePos > 0) + //std::cout << "mFramePos (bytes): " + std::to_string(mFramePos) + //<< " samples: " + std::to_string(mFramePos/mSamplesAllChannels) << std::endl; + + // samples per channel = len1 bytes / bytes per sample / number of channels + unsigned int len1Samples = len1 / mSamplesAllChannels; + // stream offset = total bytes / bytes per sample + unsigned int totalOffset = total / mSampleSize; + float sample0 = 0; + float sample1 = 0; + for (unsigned int i = 0 ; i < len1Samples ; ++i) + { + sample0 = *inputChannel0++; + sample1 = *inputChannel1++; +#if 0 + if(sample0<-1.0f) + sample0=-1.0f; + else if(sample0>1.0f) + sample0=1.0f; + if(sample1<-1.0f) + sample1=-1.0f; + else if(sample1>1.0f) + sample1=1.0f; + intStream[totalOffset+i*2] = (uint16_t) (sample0 * 32767.0f); + intStream[totalOffset+i*2+1] = (uint16_t) (sample1 * 32767.0f); +#endif + outputStream[totalOffset+i*2] = sample0; + outputStream[totalOffset+i*2+1] = sample1; + } + } + else + { + memcpy(stream, mFrame->data[0]+mFramePos, len1); + } } - else + else // repeat some samples FIXME: support ftlp { len1 = std::min(len1, -mFramePos); @@ -568,7 +680,7 @@ int VideoState::OgreResource_Read(void *user_data, uint8_t *buf, int buf_size) return stream->read(buf, buf_size); } -int VideoState::OgreResource_Write(void *user_data, uint8_t *buf, int buf_size) + int VideoState::OgreResource_Write(void *user_data, uint8_t *buf, int buf_size) { Ogre::DataStreamPtr stream = static_cast(user_data)->stream; return stream->write(buf, buf_size); @@ -768,9 +880,15 @@ void VideoState::video_thread_loop(VideoState *self) AVFrame *pFrame; double pts; +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 28, 1) pFrame = avcodec_alloc_frame(); self->rgbaFrame = avcodec_alloc_frame(); +#else + pFrame = av_frame_alloc(); + + self->rgbaFrame = av_frame_alloc(); +#endif 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) diff --git a/cmake/FindFFmpeg.cmake b/cmake/FindFFmpeg.cmake index a3509597b..d7206c022 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 @@ -32,7 +33,7 @@ include(FindPackageHandleStandardArgs) # The default components were taken from a survey over other FindFFMPEG.cmake files if (NOT FFmpeg_FIND_COMPONENTS) - set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE) + set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE) endif () # @@ -112,6 +113,7 @@ 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) # Check if the required components were found and add their stuff to the FFMPEG_* vars. foreach (_component ${FFmpeg_FIND_COMPONENTS}) @@ -142,7 +144,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) set_component_found(${_component}) endforeach () From 16c165185b9c92d7a3ea3f3f9c67fa5e346f6d07 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 31 Aug 2014 13:40:29 +1000 Subject: [PATCH 02/31] Minor cleanup. Tested successfully on windows x64 using ffmpeg-20140823-git-7444cf9-win64-dev which is on libavcodec version 56.0.101. --- apps/openmw/mwrender/videoplayer.cpp | 32 ++++++---------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 00443fdaa..998658672 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -317,7 +317,7 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder SwrContext *mSwr; /* non-zero indicates FLTP format */ int mSamplesAllChannels; - int mSampleSize; + int mOutputSampleSize; AutoAVPacket mPacket; AVFrame *mFrame; /* AVFrame is now defined in libavutil/frame.h (used to be libavcodec/avcodec.h) */ @@ -437,7 +437,7 @@ public: , mAudioDiffAvgCount(0) , mSwr(0) , mSamplesAllChannels(0) - , mSampleSize(0) + , mOutputSampleSize(0) { } virtual ~MovieAudioDecoder() { @@ -513,7 +513,7 @@ public: mSamplesAllChannels = av_get_bytes_per_sample(mAVStream->codec->sample_fmt) * mAVStream->codec->channels; - mSampleSize = av_get_bytes_per_sample(mAVStream->codec->sample_fmt); + mOutputSampleSize = av_get_bytes_per_sample(mAVStream->codec->sample_fmt); // TODO: not correct for S16 } /* @@ -548,14 +548,11 @@ public: size_t total = 0; float *outputStream = (float *)&stream[0]; - //uint16_t *intStream = (uint16_t *)&stream[0]; while(total < len) { if(mFramePos >= mFrameSize) { - // for FLT sample format mFrameSize returned by audio_decode_frame is: - // 1920 samples x 4 bytes/sample x 2 channels = 15360 bytes /* We have already sent all our data; get more */ mFrameSize = audio_decode_frame(mFrame); if(mFrameSize < 0) @@ -563,6 +560,8 @@ public: /* If error, we're done */ break; } + // for FLT sample format mFrameSize returned by audio_decode_frame is: + // 1920 samples x 4 bytes/sample x 2 channels = 15360 bytes mFramePos = std::min(mFrameSize, sample_skip); sample_skip -= mFramePos; @@ -581,38 +580,19 @@ public: // FIXME: support sample formats other than Float32 float* inputChannel0 = (float*)mFrame->extended_data[0]; float* inputChannel1 = (float*)mFrame->extended_data[1]; -#if 0 - uint16_t* inputChannel0 = (uint16_t*)mFrame->extended_data[0]; - uint16_t* inputChannel1 = (uint16_t*)mFrame->extended_data[1]; -#endif inputChannel0 += mFramePos/mSamplesAllChannels; inputChannel1 += mFramePos/mSamplesAllChannels; - //if(mFramePos > 0) - //std::cout << "mFramePos (bytes): " + std::to_string(mFramePos) - //<< " samples: " + std::to_string(mFramePos/mSamplesAllChannels) << std::endl; // samples per channel = len1 bytes / bytes per sample / number of channels unsigned int len1Samples = len1 / mSamplesAllChannels; // stream offset = total bytes / bytes per sample - unsigned int totalOffset = total / mSampleSize; + unsigned int totalOffset = total / mOutputSampleSize; float sample0 = 0; float sample1 = 0; for (unsigned int i = 0 ; i < len1Samples ; ++i) { sample0 = *inputChannel0++; sample1 = *inputChannel1++; -#if 0 - if(sample0<-1.0f) - sample0=-1.0f; - else if(sample0>1.0f) - sample0=1.0f; - if(sample1<-1.0f) - sample1=-1.0f; - else if(sample1>1.0f) - sample1=1.0f; - intStream[totalOffset+i*2] = (uint16_t) (sample0 * 32767.0f); - intStream[totalOffset+i*2+1] = (uint16_t) (sample1 * 32767.0f); -#endif outputStream[totalOffset+i*2] = sample0; outputStream[totalOffset+i*2+1] = sample1; } From 8429dab2710160b9f2fb335d0f1b505ed2822033 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 31 Aug 2014 22:01:08 +1000 Subject: [PATCH 03/31] Working version - converts FLTP to FLT. Does not work when converting to S16. --- apps/openmw/mwrender/videoplayer.cpp | 41 ++++++++++++---------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 998658672..dc065157c 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -513,7 +513,7 @@ public: mSamplesAllChannels = av_get_bytes_per_sample(mAVStream->codec->sample_fmt) * mAVStream->codec->channels; - mOutputSampleSize = av_get_bytes_per_sample(mAVStream->codec->sample_fmt); // TODO: not correct for S16 + mOutputSampleSize = av_get_bytes_per_sample(AV_SAMPLE_FMT_FLT); } /* @@ -547,8 +547,6 @@ public: int sample_skip = synchronize_audio(); size_t total = 0; - float *outputStream = (float *)&stream[0]; - while(total < len) { if(mFramePos >= mFrameSize) @@ -575,27 +573,24 @@ public: if(mSwr) { - // Convert from AV_SAMPLE_FMT_FLTP to AV_SAMPLE_FMT_FLT - // FIXME: support channel formats other than stereo - // FIXME: support sample formats other than Float32 - float* inputChannel0 = (float*)mFrame->extended_data[0]; - float* inputChannel1 = (float*)mFrame->extended_data[1]; - inputChannel0 += mFramePos/mSamplesAllChannels; - inputChannel1 += mFramePos/mSamplesAllChannels; - - // samples per channel = len1 bytes / bytes per sample / number of channels - unsigned int len1Samples = len1 / mSamplesAllChannels; - // stream offset = total bytes / bytes per sample - unsigned int totalOffset = total / mOutputSampleSize; - float sample0 = 0; - float sample1 = 0; - for (unsigned int i = 0 ; i < len1Samples ; ++i) + int convertedSamples = 0; + if(mFramePos > 0 && mFramePos < mFrameSize) { - sample0 = *inputChannel0++; - sample1 = *inputChannel1++; - outputStream[totalOffset+i*2] = sample0; - outputStream[totalOffset+i*2+1] = sample1; + if(swr_drop_output(mSwr, mFramePos/mSamplesAllChannels) < 0) + break; + + convertedSamples = swr_convert(mSwr, (uint8_t**)&stream, len1/mSamplesAllChannels, + (const uint8_t**)mFrame->extended_data, (len1+mFramePos)/mSamplesAllChannels); } + else + { + convertedSamples = swr_convert(mSwr, (uint8_t**)&stream, len1/mSamplesAllChannels, + (const uint8_t**)mFrame->extended_data, len1/mSamplesAllChannels); + } + if(convertedSamples > 0) + len1 = convertedSamples * mSamplesAllChannels; + else + break; } else { @@ -660,7 +655,7 @@ int VideoState::OgreResource_Read(void *user_data, uint8_t *buf, int buf_size) return stream->read(buf, buf_size); } - int VideoState::OgreResource_Write(void *user_data, uint8_t *buf, int buf_size) +int VideoState::OgreResource_Write(void *user_data, uint8_t *buf, int buf_size) { Ogre::DataStreamPtr stream = static_cast(user_data)->stream; return stream->write(buf, buf_size); From a7371eda4d2a6be4beae623aafee9bf8919ad0d9 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 31 Aug 2014 23:35:05 +1000 Subject: [PATCH 04/31] Now works for both FLT and S16 formats. The output format is hard coded in the MovieAudioDecoder constructor (default S16). --- apps/openmw/mwrender/videoplayer.cpp | 29 +++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index dc065157c..db0c8a79d 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -317,7 +317,8 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder SwrContext *mSwr; /* non-zero indicates FLTP format */ int mSamplesAllChannels; - int mOutputSampleSize; + float mOutputSampleRatio; + enum AVSampleFormat mOutputSampleFormat; AutoAVPacket mPacket; AVFrame *mFrame; /* AVFrame is now defined in libavutil/frame.h (used to be libavcodec/avcodec.h) */ @@ -437,7 +438,8 @@ public: , mAudioDiffAvgCount(0) , mSwr(0) , mSamplesAllChannels(0) - , mOutputSampleSize(0) + , mOutputSampleRatio(1) + , mOutputSampleFormat(AV_SAMPLE_FMT_S16) { } virtual ~MovieAudioDecoder() { @@ -457,8 +459,12 @@ public: else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_FLTP) { // resample to a known format for OpenAL_SoundStream - // TODO: allow different size sample format, e.g. Int16 - *type = MWSound::SampleType_Float32; + if(mOutputSampleFormat == AV_SAMPLE_FMT_S16) + *type = MWSound::SampleType_Int16; + else if(mOutputSampleFormat == AV_SAMPLE_FMT_FLT) + *type = MWSound::SampleType_Float32; + else + *type = MWSound::SampleType_Int16; // default } else fail(std::string("Unsupported sample format: ")+ @@ -507,13 +513,14 @@ public: av_opt_set_int(mSwr, "in_sample_rate", mAVStream->codec->sample_rate, 0); av_opt_set_int(mSwr, "out_sample_rate", mAVStream->codec->sample_rate, 0); av_opt_set_sample_fmt(mSwr, "in_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); - av_opt_set_sample_fmt(mSwr, "out_sample_fmt", AV_SAMPLE_FMT_FLT, 0); // TODO: Try S16 + av_opt_set_sample_fmt(mSwr, "out_sample_fmt", mOutputSampleFormat, 0); swr_init(mSwr); - } - mSamplesAllChannels = av_get_bytes_per_sample(mAVStream->codec->sample_fmt) * - mAVStream->codec->channels; - mOutputSampleSize = av_get_bytes_per_sample(AV_SAMPLE_FMT_FLT); + mSamplesAllChannels = av_get_bytes_per_sample(mOutputSampleFormat) + * mAVStream->codec->channels; + mOutputSampleRatio = av_get_bytes_per_sample(AV_SAMPLE_FMT_FLTP) + / av_get_bytes_per_sample(mOutputSampleFormat); + } } /* @@ -545,6 +552,7 @@ public: size_t read(char *stream, size_t len) { int sample_skip = synchronize_audio(); + if(mSwr) sample_skip /= mOutputSampleRatio; size_t total = 0; while(total < len) @@ -558,8 +566,7 @@ public: /* If error, we're done */ break; } - // for FLT sample format mFrameSize returned by audio_decode_frame is: - // 1920 samples x 4 bytes/sample x 2 channels = 15360 bytes + if(mSwr) mFrameSize /= mOutputSampleRatio; mFramePos = std::min(mFrameSize, sample_skip); sample_skip -= mFramePos; From 68cbb8989e81502e121e9542768c3f6e6ffce479 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 31 Aug 2014 23:39:17 +1000 Subject: [PATCH 05/31] Cleanup comments. --- apps/openmw/mwrender/videoplayer.cpp | 32 +++------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index db0c8a79d..ff1eda0cb 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -315,13 +315,13 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder VideoState *mVideoState; AVStream *mAVStream; - SwrContext *mSwr; /* non-zero indicates FLTP format */ + SwrContext *mSwr; int mSamplesAllChannels; float mOutputSampleRatio; enum AVSampleFormat mOutputSampleFormat; AutoAVPacket mPacket; - AVFrame *mFrame; /* AVFrame is now defined in libavutil/frame.h (used to be libavcodec/avcodec.h) */ + AVFrame *mFrame; ssize_t mFramePos; ssize_t mFrameSize; @@ -523,32 +523,6 @@ public: } } - /* - * stream is a ptr to vector on the stack, see OpenAL_SoundStream::process in - * mwsound/openal_output.cpp (around line 481) - * - * len is the size of the output buffer (i.e. stream) based on the number of - * channels, rate and sample type (as reported by getInfo). - * - * sample_skip is the number of bytes to skip (from all channels) or repeat (i.e. negative) - * - * mFrameSize is the number of bytes decoded audio frame (from all channels), or -1 if finished - * - * - * +---------------------------------------------------------------------------------+ - * | | - * |<------------------------------------------ len -------------------------------->| - * | | - * |<------ mFrameSize ------>| | - * | | - * +---------------------------------------------------------------------------------+ - * ^ - * | - * mFramePos >= 0 - * - * |<----- len1 -------->| - * - */ size_t read(char *stream, size_t len) { int sample_skip = synchronize_audio(); @@ -604,7 +578,7 @@ public: memcpy(stream, mFrame->data[0]+mFramePos, len1); } } - else // repeat some samples FIXME: support ftlp + else // FIXME: support ftlp { len1 = std::min(len1, -mFramePos); From fdee660ffb11dfbb964c2dfbb2b0cbc497f4c92c Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 1 Sep 2014 08:02:25 +1000 Subject: [PATCH 06/31] Implemented feedback review comments, removing hard coded values and adding error handling. --- apps/openmw/mwrender/videoplayer.cpp | 63 +++++++++++++++------------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index ff1eda0cb..d36d481c8 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -439,7 +439,7 @@ public: , mSwr(0) , mSamplesAllChannels(0) , mOutputSampleRatio(1) - , mOutputSampleFormat(AV_SAMPLE_FMT_S16) + , mOutputSampleFormat(AV_SAMPLE_FMT_NONE) { } virtual ~MovieAudioDecoder() { @@ -450,22 +450,15 @@ public: void getInfo(int *samplerate, MWSound::ChannelConfig *chans, MWSound::SampleType * type) { - if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_U8) + if((mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_U8) || + (mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_U8P)) *type = MWSound::SampleType_UInt8; - else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_S16) + else if((mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_S16) || + (mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_S16P)) *type = MWSound::SampleType_Int16; - else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_FLT) + else if((mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_FLT) || + (mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_FLTP)) *type = MWSound::SampleType_Float32; - else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_FLTP) - { - // resample to a known format for OpenAL_SoundStream - if(mOutputSampleFormat == AV_SAMPLE_FMT_S16) - *type = MWSound::SampleType_Int16; - else if(mOutputSampleFormat == AV_SAMPLE_FMT_FLT) - *type = MWSound::SampleType_Float32; - else - *type = MWSound::SampleType_Int16; // default - } else fail(std::string("Unsupported sample format: ")+ av_get_sample_fmt_name(mAVStream->codec->sample_fmt)); @@ -504,29 +497,43 @@ public: *samplerate = mAVStream->codec->sample_rate; - // FIXME: error handling - if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_FLTP) + 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; + else + fail(std::string("Should never reach here.")); + + if(mOutputSampleFormat != AV_SAMPLE_FMT_NONE) { - mSwr = swr_alloc(); - av_opt_set_int(mSwr, "in_channel_layout", mAVStream->codec->channel_layout, 0); - av_opt_set_int(mSwr, "out_channel_layout", mAVStream->codec->channel_layout, 0); - av_opt_set_int(mSwr, "in_sample_rate", mAVStream->codec->sample_rate, 0); - av_opt_set_int(mSwr, "out_sample_rate", mAVStream->codec->sample_rate, 0); - av_opt_set_sample_fmt(mSwr, "in_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); - av_opt_set_sample_fmt(mSwr, "out_sample_fmt", mOutputSampleFormat, 0); - swr_init(mSwr); + mSwr = swr_alloc_set_opts(mSwr, // SwrContext + mAVStream->codec->channel_layout, // output ch layout + mOutputSampleFormat, // output sample format + mAVStream->codec->sample_rate, // output sample rate + mAVStream->codec->channel_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")); mSamplesAllChannels = av_get_bytes_per_sample(mOutputSampleFormat) * mAVStream->codec->channels; - mOutputSampleRatio = av_get_bytes_per_sample(AV_SAMPLE_FMT_FLTP) - / av_get_bytes_per_sample(mOutputSampleFormat); + /* only required if output sample format size is different to input */ + //mOutputSampleRatio = av_get_bytes_per_sample(mAVStream->codec->sample_fmt) + /// av_get_bytes_per_sample(mOutputSampleFormat); } } size_t read(char *stream, size_t len) { int sample_skip = synchronize_audio(); - if(mSwr) sample_skip /= mOutputSampleRatio; + //if(mSwr) sample_skip /= mOutputSampleRatio; size_t total = 0; while(total < len) @@ -540,7 +547,7 @@ public: /* If error, we're done */ break; } - if(mSwr) mFrameSize /= mOutputSampleRatio; + //if(mSwr) mFrameSize /= mOutputSampleRatio; mFramePos = std::min(mFrameSize, sample_skip); sample_skip -= mFramePos; From 0b9d17a81da7a514d7eb6bfe1ea8af721fc891bd Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 1 Sep 2014 08:04:28 +1000 Subject: [PATCH 07/31] More cleanup. --- apps/openmw/mwrender/videoplayer.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index d36d481c8..00e4e7117 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -317,7 +317,6 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder SwrContext *mSwr; int mSamplesAllChannels; - float mOutputSampleRatio; enum AVSampleFormat mOutputSampleFormat; AutoAVPacket mPacket; @@ -438,7 +437,6 @@ public: , mAudioDiffAvgCount(0) , mSwr(0) , mSamplesAllChannels(0) - , mOutputSampleRatio(1) , mOutputSampleFormat(AV_SAMPLE_FMT_NONE) { } virtual ~MovieAudioDecoder() @@ -524,16 +522,12 @@ public: mSamplesAllChannels = av_get_bytes_per_sample(mOutputSampleFormat) * mAVStream->codec->channels; - /* only required if output sample format size is different to input */ - //mOutputSampleRatio = av_get_bytes_per_sample(mAVStream->codec->sample_fmt) - /// av_get_bytes_per_sample(mOutputSampleFormat); } } size_t read(char *stream, size_t len) { int sample_skip = synchronize_audio(); - //if(mSwr) sample_skip /= mOutputSampleRatio; size_t total = 0; while(total < len) @@ -547,7 +541,6 @@ public: /* If error, we're done */ break; } - //if(mSwr) mFrameSize /= mOutputSampleRatio; mFramePos = std::min(mFrameSize, sample_skip); sample_skip -= mFramePos; From f4dd281393db4aaafc3df93044914f9d568c7e7e Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 1 Sep 2014 21:49:37 +1000 Subject: [PATCH 08/31] Simplify the use of swr_convert and add #ifdef guards around code that require libswresample. --- CMakeLists.txt | 5 +- apps/openmw/mwrender/videoplayer.cpp | 88 ++++++++++++++++------------ 2 files changed, 53 insertions(+), 40 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e1af8b0b0..74f7dddd7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,10 +139,13 @@ set(OPENMW_LIBS ${OENGINE_ALL}) set(OPENMW_LIBS_HEADER) # Sound setup -set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE) +set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE) find_package(FFmpeg REQUIRED) set(SOUND_INPUT_INCLUDES ${FFMPEG_INCLUDE_DIRS}) set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARIES}) +if( SWRESAMPLE_FOUND ) + add_definitions(-DHAVE_LIBSWRESAMPLE) +endif() # TinyXML option(USE_SYSTEM_TINYXML "Use system TinyXML library instead of internal." OFF) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 00e4e7117..819e09826 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -53,9 +53,10 @@ extern "C" // http://ffmpeg.zeranoe.com/forum/viewtopic.php?f=15&t=872 #if AV_VERSION_INT(54, 56, 0) <= AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, LIBAVCODEC_VERSION_MICRO) - #include /* swr_init, swr_alloc, swr_convert, swr_free */ - #include /* av_opt_set_int, av_opt_set_sample_fmt */ - #define FFMPEG_PLAY_BINKAUDIO + #ifdef HAVE_LIBSWRESAMPLE + #include + #define FFMPEG_PLAY_BINKAUDIO + #endif #elif defined(_WIN32) && defined(_WIN64) // Versions up to 54.54.100 potentially crashes on Windows 64bit. #if ((LIBAVCODEC_VERSION_MAJOR == 54) && (LIBAVCODEC_VERSION_MINOR >= 55)) @@ -315,7 +316,11 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder VideoState *mVideoState; AVStream *mAVStream; +#ifdef HAVE_LIBSWRESAMPLE SwrContext *mSwr; +#else + bool mSwr; +#endif int mSamplesAllChannels; enum AVSampleFormat mOutputSampleFormat; @@ -442,21 +447,27 @@ public: virtual ~MovieAudioDecoder() { av_freep(&mFrame); - if(mSwr) - swr_free(&mSwr); +#ifdef HAVE_LIBSWRESAMPLE + swr_free(&mSwr); +#endif } void getInfo(int *samplerate, MWSound::ChannelConfig *chans, MWSound::SampleType * type) { - if((mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_U8) || - (mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_U8P)) + if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_U8) *type = MWSound::SampleType_UInt8; - else if((mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_S16) || - (mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_S16P)) + else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_S16) *type = MWSound::SampleType_Int16; - else if((mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_FLT) || - (mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_FLTP)) + else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_FLT) *type = MWSound::SampleType_Float32; +#ifdef HAVE_LIBSWRESAMPLE + 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; +#endif else fail(std::string("Unsupported sample format: ")+ av_get_sample_fmt_name(mAVStream->codec->sample_fmt)); @@ -495,6 +506,7 @@ public: *samplerate = mAVStream->codec->sample_rate; +#ifdef HAVE_LIBSWRESAMPLE if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_U8P) mOutputSampleFormat = AV_SAMPLE_FMT_U8; else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_S16P) @@ -506,15 +518,15 @@ public: if(mOutputSampleFormat != AV_SAMPLE_FMT_NONE) { - mSwr = swr_alloc_set_opts(mSwr, // SwrContext - mAVStream->codec->channel_layout, // output ch layout - mOutputSampleFormat, // output sample format - mAVStream->codec->sample_rate, // output sample rate - mAVStream->codec->channel_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 + mSwr = swr_alloc_set_opts(mSwr, // SwrContext + mAVStream->codec->channel_layout, // output ch layout + mOutputSampleFormat, // output sample format + mAVStream->codec->sample_rate, // output sample rate + mAVStream->codec->channel_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) @@ -523,12 +535,16 @@ public: mSamplesAllChannels = av_get_bytes_per_sample(mOutputSampleFormat) * mAVStream->codec->channels; } +#endif } size_t read(char *stream, size_t len) { int sample_skip = synchronize_audio(); size_t total = 0; + uint8_t *output = NULL; + if(mSwr) av_samples_alloc(&output, NULL, mAVStream->codec->channels, + len/mSamplesAllChannels, mOutputSampleFormat, 0); while(total < len) { @@ -546,7 +562,17 @@ public: sample_skip -= mFramePos; continue; } - +#ifdef HAVE_LIBSWRESAMPLE + if(mSwr) + { + int n = swr_convert(mSwr, (uint8_t**)&output, mFrame->nb_samples, + (const uint8_t**)mFrame->extended_data, mFrame->nb_samples); + if(n < 0) + break; + else if(n < mFrame->nb_samples) + std::cerr<<"swr_convert error: "+std::to_string(mFrame->nb_samples-n)<= 0) { @@ -554,24 +580,7 @@ public: if(mSwr) { - int convertedSamples = 0; - if(mFramePos > 0 && mFramePos < mFrameSize) - { - if(swr_drop_output(mSwr, mFramePos/mSamplesAllChannels) < 0) - break; - - convertedSamples = swr_convert(mSwr, (uint8_t**)&stream, len1/mSamplesAllChannels, - (const uint8_t**)mFrame->extended_data, (len1+mFramePos)/mSamplesAllChannels); - } - else - { - convertedSamples = swr_convert(mSwr, (uint8_t**)&stream, len1/mSamplesAllChannels, - (const uint8_t**)mFrame->extended_data, len1/mSamplesAllChannels); - } - if(convertedSamples > 0) - len1 = convertedSamples * mSamplesAllChannels; - else - break; + memcpy(stream, &output[0]+mFramePos, len1); } else { @@ -617,6 +626,7 @@ public: stream += len1; mFramePos += len1; } + if(mSwr) av_freep(&output); return total; } From 6138d0c98282d147b1be435934658559cd17cc1e Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 1 Sep 2014 22:09:07 +1000 Subject: [PATCH 09/31] Attempt to work around travis. --- cmake/FindFFmpeg.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/FindFFmpeg.cmake b/cmake/FindFFmpeg.cmake index d7206c022..2280d37ff 100644 --- a/cmake/FindFFmpeg.cmake +++ b/cmake/FindFFmpeg.cmake @@ -33,7 +33,7 @@ include(FindPackageHandleStandardArgs) # The default components were taken from a survey over other FindFFMPEG.cmake files if (NOT FFmpeg_FIND_COMPONENTS) - set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE) + set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE) endif () # @@ -144,7 +144,7 @@ if (NOT FFMPEG_LIBRARIES) endif () # Now set the noncached _FOUND vars for the components. -foreach (_component AVCODEC AVDEVICE AVFORMAT AVUTIL POSTPROCESS SWSCALE SWRESAMPLE) +foreach (_component AVCODEC AVDEVICE AVFORMAT AVUTIL POSTPROCESS SWSCALE) set_component_found(${_component}) endforeach () From 2d6b532ea5399f7de28bd7d9525fcb728af06ff7 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 2 Sep 2014 21:52:19 +1000 Subject: [PATCH 10/31] Minimize the use of #ifdef guards for better code legibility. --- apps/openmw/mwrender/videoplayer.cpp | 82 ++++++++++------------------ 1 file changed, 30 insertions(+), 52 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 819e09826..2399b0470 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -48,28 +48,29 @@ extern "C" #include #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 - #if AV_VERSION_INT(54, 56, 0) <= AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ - LIBAVCODEC_VERSION_MINOR, LIBAVCODEC_VERSION_MICRO) - #ifdef HAVE_LIBSWRESAMPLE - #include - #define FFMPEG_PLAY_BINKAUDIO - #endif - #elif defined(_WIN32) && defined(_WIN64) - // Versions up to 54.54.100 potentially crashes on Windows 64bit. - #if ((LIBAVCODEC_VERSION_MAJOR == 54) && (LIBAVCODEC_VERSION_MINOR >= 55)) - #define FFMPEG_PLAY_BINKAUDIO - #endif - #elif defined(_WIN32) - // 54.10.100 is a known working version on 32bit, but earlier ones may also work. - #if ((LIBAVCODEC_VERSION_MAJOR == 54) && (LIBAVCODEC_VERSION_MINOR >= 10)) - #define FFMPEG_PLAY_BINKAUDIO - #endif - #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 +#ifdef HAVE_LIBSWRESAMPLE +extern "C" { +#include +} +#else +/* some dummy definitions to make the code more legible */ +int swr_init(int *n) { n = 0; return 1; } +int swr_convert(int *s, uint8_t** output, int outs, const uint8_t** input, int ins) + { return 1; } +int * swr_alloc_set_opts(int *s, int64_t outc, AVSampleFormat outf, int outr, + int64_t inc, AVSampleFormat inf, int inr, int o, void* l) { *s = 1; return s; } +void swr_free(int **n) { } +#define SwrContext int +#undef AV_SAMPLE_FMT_FLTP +#define AV_SAMPLE_FMT_FLTP 3 +#endif + #define MAX_AUDIOQ_SIZE (5 * 16 * 1024) #define MAX_VIDEOQ_SIZE (5 * 256 * 1024) #define AV_SYNC_THRESHOLD 0.01 @@ -316,12 +317,7 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder VideoState *mVideoState; AVStream *mAVStream; -#ifdef HAVE_LIBSWRESAMPLE SwrContext *mSwr; -#else - bool mSwr; -#endif - int mSamplesAllChannels; enum AVSampleFormat mOutputSampleFormat; AutoAVPacket mPacket; @@ -441,15 +437,12 @@ public: , mAudioDiffThreshold(2.0 * 0.050/* 50 ms */) , mAudioDiffAvgCount(0) , mSwr(0) - , mSamplesAllChannels(0) , mOutputSampleFormat(AV_SAMPLE_FMT_NONE) { } virtual ~MovieAudioDecoder() { av_freep(&mFrame); -#ifdef HAVE_LIBSWRESAMPLE swr_free(&mSwr); -#endif } void getInfo(int *samplerate, MWSound::ChannelConfig *chans, MWSound::SampleType * type) @@ -460,14 +453,12 @@ public: *type = MWSound::SampleType_Int16; else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_FLT) *type = MWSound::SampleType_Float32; -#ifdef HAVE_LIBSWRESAMPLE 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; -#endif else fail(std::string("Unsupported sample format: ")+ av_get_sample_fmt_name(mAVStream->codec->sample_fmt)); @@ -506,15 +497,12 @@ public: *samplerate = mAVStream->codec->sample_rate; -#ifdef HAVE_LIBSWRESAMPLE 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; - else - fail(std::string("Should never reach here.")); if(mOutputSampleFormat != AV_SAMPLE_FMT_NONE) { @@ -531,20 +519,17 @@ public: fail(std::string("Couldn't allocate SwrContext")); if(swr_init(mSwr) < 0) fail(std::string("Couldn't initialize SwrContext")); - - mSamplesAllChannels = av_get_bytes_per_sample(mOutputSampleFormat) - * mAVStream->codec->channels; } -#endif } size_t read(char *stream, size_t len) { int sample_skip = synchronize_audio(); size_t total = 0; - uint8_t *output = NULL; + uint8_t *output = 0; if(mSwr) av_samples_alloc(&output, NULL, mAVStream->codec->channels, - len/mSamplesAllChannels, mOutputSampleFormat, 0); + len/(av_get_bytes_per_sample(mOutputSampleFormat) * mAVStream->codec->channels), + mOutputSampleFormat, 0); while(total < len) { @@ -559,11 +544,12 @@ public: } mFramePos = std::min(mFrameSize, sample_skip); - sample_skip -= mFramePos; + if(sample_skip > 0 || mFrameSize > -sample_skip) + sample_skip -= mFramePos; continue; } -#ifdef HAVE_LIBSWRESAMPLE - if(mSwr) + + if(mSwr && !sample_skip) { int n = swr_convert(mSwr, (uint8_t**)&output, mFrame->nb_samples, (const uint8_t**)mFrame->extended_data, mFrame->nb_samples); @@ -572,22 +558,18 @@ public: else if(n < mFrame->nb_samples) std::cerr<<"swr_convert error: "+std::to_string(mFrame->nb_samples-n)<= 0) { len1 = std::min(len1, mFrameSize-mFramePos); if(mSwr) - { memcpy(stream, &output[0]+mFramePos, len1); - } else - { memcpy(stream, mFrame->data[0]+mFramePos, len1); - } } - else // FIXME: support ftlp + else { len1 = std::min(len1, -mFramePos); @@ -1076,12 +1058,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) { From 5095f729b07806e64208b77a96f0386931fdb116 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 2 Sep 2014 22:05:54 +1000 Subject: [PATCH 11/31] Make travis happy again. --- apps/openmw/mwrender/videoplayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 2399b0470..881ca8d8a 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -556,7 +556,7 @@ public: if(n < 0) break; else if(n < mFrame->nb_samples) - std::cerr<<"swr_convert error: "+std::to_string(mFrame->nb_samples-n)< Date: Wed, 3 Sep 2014 18:13:43 +1000 Subject: [PATCH 12/31] More refactoring, remove more #ifdef guards and fix repeat samples for planar formats. --- apps/openmw/mwrender/videoplayer.cpp | 47 +++++++++++----------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 881ca8d8a..030940696 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -32,6 +32,10 @@ extern "C" #include #include + #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 @@ -423,11 +427,7 @@ public: MovieAudioDecoder(VideoState *is) : mVideoState(is) , mAVStream(*is->audio_st) -#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 28, 1) - , mFrame(avcodec_alloc_frame()) -#else , mFrame(av_frame_alloc()) -#endif , mFramePos(0) , mFrameSize(0) , mAudioClock(0.0) @@ -526,8 +526,9 @@ public: { int sample_skip = synchronize_audio(); size_t total = 0; - uint8_t *output = 0; - if(mSwr) av_samples_alloc(&output, NULL, mAVStream->codec->channels, + uint8_t *dataBuf = 0; + uint8_t ** data = &dataBuf; + if(mSwr) av_samples_alloc(&dataBuf, NULL, mAVStream->codec->channels, len/(av_get_bytes_per_sample(mOutputSampleFormat) * mAVStream->codec->channels), mOutputSampleFormat, 0); @@ -551,23 +552,19 @@ public: if(mSwr && !sample_skip) { - int n = swr_convert(mSwr, (uint8_t**)&output, mFrame->nb_samples, - (const uint8_t**)mFrame->extended_data, mFrame->nb_samples); - if(n < 0) + if(swr_convert(mSwr, (uint8_t**)data, mFrame->nb_samples, + (const uint8_t**)mFrame->extended_data, mFrame->nb_samples) < 0) + { break; - else if(n < mFrame->nb_samples) - std::cerr << "swr_convert error" << std::endl; + } } + if(!mSwr) data = &mFrame->data[0]; size_t len1 = len - total; if(mFramePos >= 0) { len1 = std::min(len1, mFrameSize-mFramePos); - - if(mSwr) - memcpy(stream, &output[0]+mFramePos, len1); - else - memcpy(stream, mFrame->data[0]+mFramePos, len1); + memcpy(stream, data[0]+mFramePos, len1); } else { @@ -578,29 +575,29 @@ public: /* add samples by copying the first sample*/ if(n == 1) - memset(stream, *mFrame->data[0], len1); + memset(stream, *data[0], len1); else if(n == 2) { - const int16_t val = *((int16_t*)mFrame->data[0]); + const int16_t val = *((int16_t*)data[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*)data[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*)data[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, data[0], n); } } @@ -608,7 +605,7 @@ public: stream += len1; mFramePos += len1; } - if(mSwr) av_freep(&output); + if(mSwr) av_freep(data); return total; } @@ -828,15 +825,9 @@ void VideoState::video_thread_loop(VideoState *self) AVFrame *pFrame; double pts; -#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 28, 1) - pFrame = avcodec_alloc_frame(); - - self->rgbaFrame = avcodec_alloc_frame(); -#else pFrame = av_frame_alloc(); self->rgbaFrame = av_frame_alloc(); -#endif 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) From 093c7f8882d6de11512807d49bdd1cb917131f09 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 3 Sep 2014 22:52:03 +1000 Subject: [PATCH 13/31] Moved format conversion to audio_decode_frame() --- apps/openmw/mwrender/videoplayer.cpp | 57 +++++++++++++++++----------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 030940696..77262b446 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -323,6 +323,9 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder SwrContext *mSwr; enum AVSampleFormat mOutputSampleFormat; + uint8_t *mDataBuf; + uint8_t **mData; + int mDataBufLen; AutoAVPacket mPacket; AVFrame *mFrame; @@ -390,6 +393,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; + } + mData = &mDataBuf; + } + else + mData = &frame->data[0]; + mAudioClock += (double)frame->nb_samples / (double)mAVStream->codec->sample_rate; @@ -438,11 +463,15 @@ public: , mAudioDiffAvgCount(0) , mSwr(0) , mOutputSampleFormat(AV_SAMPLE_FMT_NONE) + , mDataBuf(NULL) + , mData(NULL) + , mDataBufLen(0) { } virtual ~MovieAudioDecoder() { av_freep(&mFrame); swr_free(&mSwr); + av_freep(&mDataBuf); } void getInfo(int *samplerate, MWSound::ChannelConfig *chans, MWSound::SampleType * type) @@ -526,11 +555,6 @@ public: { int sample_skip = synchronize_audio(); size_t total = 0; - uint8_t *dataBuf = 0; - uint8_t ** data = &dataBuf; - if(mSwr) av_samples_alloc(&dataBuf, NULL, mAVStream->codec->channels, - len/(av_get_bytes_per_sample(mOutputSampleFormat) * mAVStream->codec->channels), - mOutputSampleFormat, 0); while(total < len) { @@ -550,21 +574,11 @@ public: continue; } - if(mSwr && !sample_skip) - { - if(swr_convert(mSwr, (uint8_t**)data, mFrame->nb_samples, - (const uint8_t**)mFrame->extended_data, mFrame->nb_samples) < 0) - { - break; - } - } - if(!mSwr) data = &mFrame->data[0]; - size_t len1 = len - total; if(mFramePos >= 0) { len1 = std::min(len1, mFrameSize-mFramePos); - memcpy(stream, data[0]+mFramePos, len1); + memcpy(stream, mData[0]+mFramePos, len1); } else { @@ -575,29 +589,29 @@ public: /* add samples by copying the first sample*/ if(n == 1) - memset(stream, *data[0], len1); + memset(stream, *mData[0], len1); else if(n == 2) { - const int16_t val = *((int16_t*)data[0]); + const int16_t val = *((int16_t*)mData[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*)data[0]); + const int32_t val = *((int32_t*)mData[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*)data[0]); + const int64_t val = *((int64_t*)mData[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, data[0], n); + memcpy(stream+nb, mData[0], n); } } @@ -605,7 +619,6 @@ public: stream += len1; mFramePos += len1; } - if(mSwr) av_freep(data); return total; } From 801b9446b7d8cceba62adfc4640bf4372bae8c6c Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 4 Sep 2014 07:58:46 +1000 Subject: [PATCH 14/31] Support for ubuntu/debian. Can easily be reverted if not required. --- apps/openmw/mwrender/videoplayer.cpp | 56 +++++++++++++++++++--------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 77262b446..881ab7479 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -63,16 +63,36 @@ extern "C" { #include } #else -/* some dummy definitions to make the code more legible */ -int swr_init(int *n) { n = 0; return 1; } -int swr_convert(int *s, uint8_t** output, int outs, const uint8_t** input, int ins) - { return 1; } +/* nasty hack to support FLTP, but no other formats, on systems without libswresample */ +int swr_init(int *n) { return 1; } +int swr_convert(int *s, uint8_t** output, int outs, const uint8_t** input, int ins) { + uint8_t *stream = *output; + float *outputStream = (float *)&stream[0]; + float* inputChannel0 = (float *)input[0]; + float* inputChannel1 = (float *)input[1]; + float sample0, sample1 = 0; + for (unsigned int i = 0 ; i < (unsigned int)ins ; ++i) { + sample0 = *inputChannel0++; + sample1 = *inputChannel1++; + outputStream[i*2] = sample0; + outputStream[i*2+1] = sample1; + } + return ins; +} int * swr_alloc_set_opts(int *s, int64_t outc, AVSampleFormat outf, int outr, - int64_t inc, AVSampleFormat inf, int inr, int o, void* l) { *s = 1; return s; } -void swr_free(int **n) { } + int64_t inc, AVSampleFormat inf, int inr, int o, void* l) { + if(inf == AV_SAMPLE_FMT_FLTP) { + s = new int; + *s = 1; + } + return s; +} +void swr_free(int **s) { delete *s; } #define SwrContext int -#undef AV_SAMPLE_FMT_FLTP -#define AV_SAMPLE_FMT_FLTP 3 +#undef AV_SAMPLE_FMT_U8P +#define AV_SAMPLE_FMT_U8P 0 +#undef AV_SAMPLE_FMT_S16P +#define AV_SAMPLE_FMT_S16P 1 #endif #define MAX_AUDIOQ_SIZE (5 * 16 * 1024) @@ -324,7 +344,7 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder SwrContext *mSwr; enum AVSampleFormat mOutputSampleFormat; uint8_t *mDataBuf; - uint8_t **mData; + uint8_t **mFrameData; int mDataBufLen; AutoAVPacket mPacket; @@ -410,10 +430,10 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder { break; } - mData = &mDataBuf; + mFrameData = &mDataBuf; } else - mData = &frame->data[0]; + mFrameData = &frame->data[0]; mAudioClock += (double)frame->nb_samples / (double)mAVStream->codec->sample_rate; @@ -464,7 +484,7 @@ public: , mSwr(0) , mOutputSampleFormat(AV_SAMPLE_FMT_NONE) , mDataBuf(NULL) - , mData(NULL) + , mFrameData(NULL) , mDataBufLen(0) { } virtual ~MovieAudioDecoder() @@ -578,7 +598,7 @@ public: if(mFramePos >= 0) { len1 = std::min(len1, mFrameSize-mFramePos); - memcpy(stream, mData[0]+mFramePos, len1); + memcpy(stream, mFrameData[0]+mFramePos, len1); } else { @@ -589,29 +609,29 @@ public: /* add samples by copying the first sample*/ if(n == 1) - memset(stream, *mData[0], len1); + memset(stream, *mFrameData[0], len1); else if(n == 2) { - const int16_t val = *((int16_t*)mData[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*)mData[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*)mData[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, mData[0], n); + memcpy(stream+nb, mFrameData[0], n); } } From c6cad5adc5ea80194134c1bde026234b6a0b9da8 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 4 Sep 2014 18:55:10 +1000 Subject: [PATCH 15/31] Make cmake more reliably detect libswresample --- CMakeLists.txt | 8 ++++++-- apps/openmw/mwrender/videoplayer.cpp | 7 ++----- cmake/FindFFmpeg.cmake | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 74f7dddd7..c7c3cf010 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,12 +139,16 @@ 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) +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}) endif() # TinyXML diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 881ab7479..0e90a354b 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -71,7 +71,7 @@ int swr_convert(int *s, uint8_t** output, int outs, const uint8_t** input, int float* inputChannel0 = (float *)input[0]; float* inputChannel1 = (float *)input[1]; float sample0, sample1 = 0; - for (unsigned int i = 0 ; i < (unsigned int)ins ; ++i) { + for (i = 0 ; i < ins ; ++i) { sample0 = *inputChannel0++; sample1 = *inputChannel1++; outputStream[i*2] = sample0; @@ -81,10 +81,7 @@ int swr_convert(int *s, uint8_t** output, int outs, const uint8_t** input, int } int * swr_alloc_set_opts(int *s, int64_t outc, AVSampleFormat outf, int outr, int64_t inc, AVSampleFormat inf, int inr, int o, void* l) { - if(inf == AV_SAMPLE_FMT_FLTP) { - s = new int; - *s = 1; - } + if(inf == AV_SAMPLE_FMT_FLTP) { s = new int(1); } return s; } void swr_free(int **s) { delete *s; } diff --git a/cmake/FindFFmpeg.cmake b/cmake/FindFFmpeg.cmake index 2280d37ff..c3c25d2f9 100644 --- a/cmake/FindFFmpeg.cmake +++ b/cmake/FindFFmpeg.cmake @@ -144,7 +144,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) set_component_found(${_component}) endforeach () From 7ae8d04c4779827950a5b5fe55254cbe7e0b25e8 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 4 Sep 2014 19:07:19 +1000 Subject: [PATCH 16/31] Arrgh... silly typo --- apps/openmw/mwrender/videoplayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 0e90a354b..73ff06036 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -71,7 +71,7 @@ int swr_convert(int *s, uint8_t** output, int outs, const uint8_t** input, int float* inputChannel0 = (float *)input[0]; float* inputChannel1 = (float *)input[1]; float sample0, sample1 = 0; - for (i = 0 ; i < ins ; ++i) { + for (int i = 0 ; i < ins ; ++i) { sample0 = *inputChannel0++; sample1 = *inputChannel1++; outputStream[i*2] = sample0; From c396149f23e30ce4c84371f441d4c51eb4ec7d79 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 7 Sep 2014 20:35:32 +1000 Subject: [PATCH 17/31] Code review fix. --- apps/openmw/mwrender/videoplayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 73ff06036..8b6e204e3 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -84,7 +84,7 @@ int * swr_alloc_set_opts(int *s, int64_t outc, AVSampleFormat outf, int outr, if(inf == AV_SAMPLE_FMT_FLTP) { s = new int(1); } return s; } -void swr_free(int **s) { delete *s; } +void swr_free(int **s) { delete *s; *s = NULL; } #define SwrContext int #undef AV_SAMPLE_FMT_U8P #define AV_SAMPLE_FMT_U8P 0 From f616000afb7d61b3dbd275a3da3735fea96aa572 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 7 Sep 2014 21:17:34 +1000 Subject: [PATCH 18/31] More fix based on code review. --- apps/openmw/mwrender/videoplayer.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 8b6e204e3..0b22e204c 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -81,15 +81,16 @@ int swr_convert(int *s, uint8_t** output, int outs, const uint8_t** input, int } int * swr_alloc_set_opts(int *s, int64_t outc, AVSampleFormat outf, int outr, int64_t inc, AVSampleFormat inf, int inr, int o, void* l) { - if(inf == AV_SAMPLE_FMT_FLTP) { s = new int(1); } + if(inf == AV_SAMPLE_FMT_FLTP) { + s = new int(1); + } else { + throw std::runtime_error( + std::string("Unsupported sample format: ")+ av_get_sample_fmt_name(inf)); + } return s; } void swr_free(int **s) { delete *s; *s = NULL; } #define SwrContext int -#undef AV_SAMPLE_FMT_U8P -#define AV_SAMPLE_FMT_U8P 0 -#undef AV_SAMPLE_FMT_S16P -#define AV_SAMPLE_FMT_S16P 1 #endif #define MAX_AUDIOQ_SIZE (5 * 16 * 1024) From 785d2c7cc95e816d43188e1c431b4a429ca381d3 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 8 Sep 2014 15:24:39 +1000 Subject: [PATCH 19/31] Remove incomplete implementation to support planar formats. Make libswresample a prerequisite. --- CMakeLists.txt | 11 ++------ apps/openmw/mwrender/videoplayer.cpp | 42 +++------------------------- 2 files changed, 6 insertions(+), 47 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c7c3cf010..b89844a52 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,16 +140,9 @@ set(OPENMW_LIBS_HEADER) # Sound setup set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE) -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() +find_package(FFmpeg REQUIRED) 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}) -endif() +set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARIES} ${SWRESAMPLE_LIBRARIES}) # TinyXML option(USE_SYSTEM_TINYXML "Use system TinyXML library instead of internal." OFF) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 0b22e204c..2b1612675 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -52,47 +52,13 @@ extern "C" #include #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 // WARNING: avcodec versions up to 54.54.100 potentially crashes on Windows 64bit. + #include } -// 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 -extern "C" { -#include -} -#else -/* nasty hack to support FLTP, but no other formats, on systems without libswresample */ -int swr_init(int *n) { return 1; } -int swr_convert(int *s, uint8_t** output, int outs, const uint8_t** input, int ins) { - uint8_t *stream = *output; - float *outputStream = (float *)&stream[0]; - float* inputChannel0 = (float *)input[0]; - float* inputChannel1 = (float *)input[1]; - float sample0, sample1 = 0; - for (int i = 0 ; i < ins ; ++i) { - sample0 = *inputChannel0++; - sample1 = *inputChannel1++; - outputStream[i*2] = sample0; - outputStream[i*2+1] = sample1; - } - return ins; -} -int * swr_alloc_set_opts(int *s, int64_t outc, AVSampleFormat outf, int outr, - int64_t inc, AVSampleFormat inf, int inr, int o, void* l) { - if(inf == AV_SAMPLE_FMT_FLTP) { - s = new int(1); - } else { - throw std::runtime_error( - std::string("Unsupported sample format: ")+ av_get_sample_fmt_name(inf)); - } - return s; -} -void swr_free(int **s) { delete *s; *s = NULL; } -#define SwrContext int -#endif - #define MAX_AUDIOQ_SIZE (5 * 16 * 1024) #define MAX_VIDEOQ_SIZE (5 * 256 * 1024) #define AV_SYNC_THRESHOLD 0.01 From 862c5fc8f6bd48d7104b2160bfa56c8c656e8f6b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 11 Sep 2014 16:47:00 +1000 Subject: [PATCH 20/31] Add libavresample support. Tested on windows x64 only. --- .travis.yml | 2 +- CMakeLists.txt | 19 ++++++-- apps/openmw/mwrender/videoplayer.cpp | 66 ++++++++++++++++++++++++++-- cmake/FindFFmpeg.cmake | 3 +- 4 files changed, 81 insertions(+), 9 deletions(-) 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 b89844a52..df134f9c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,10 +139,23 @@ set(OPENMW_LIBS ${OENGINE_ALL}) set(OPENMW_LIBS_HEADER) # Sound setup -set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE) -find_package(FFmpeg REQUIRED) +set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE AVRESAMPLE) +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} ${SWRESAMPLE_LIBRARIES}) +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 "FFmpeg component required, but not found!") + endif() +endif() # TinyXML option(USE_SYSTEM_TINYXML "Use system TinyXML library instead of internal." OFF) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 2b1612675..9c918814a 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -52,11 +52,69 @@ extern "C" #include #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 // WARNING: avcodec versions up to 54.54.100 potentially crashes on Windows 64bit. - #include +} + +// 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 +#else +/* nasty hack for systems without libswresample */ +#include +#include + +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; } +#define SwrContext AVAudioResampleContext +#endif } #define MAX_AUDIOQ_SIZE (5 * 16 * 1024) diff --git a/cmake/FindFFmpeg.cmake b/cmake/FindFFmpeg.cmake index c3c25d2f9..74584bf31 100644 --- a/cmake/FindFFmpeg.cmake +++ b/cmake/FindFFmpeg.cmake @@ -114,6 +114,7 @@ if (NOT FFMPEG_LIBRARIES) 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}) @@ -144,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 SWRESAMPLE) +foreach (_component AVCODEC AVDEVICE AVFORMAT AVUTIL POSTPROCESS SWSCALE SWRESAMPLE AVRESAMPLE) set_component_found(${_component}) endforeach () From 48a36442c68724c193044807942c4e4b6e03a4ea Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 11 Sep 2014 21:15:18 +1000 Subject: [PATCH 21/31] Add libswresample and libavresample support for sounds. --- apps/openmw/mwrender/videoplayer.cpp | 110 ++++++++++---------- apps/openmw/mwsound/ffmpeg_decoder.cpp | 133 +++++++++++++++++++++---- apps/openmw/mwsound/ffmpeg_decoder.hpp | 21 ++++ 3 files changed, 191 insertions(+), 73 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 9c918814a..21a0cc832 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -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 -#else -/* nasty hack for systems without libswresample */ -#include -#include + // 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 + /* 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) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 982d0c5ff..a2652ba13 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -5,6 +5,58 @@ #include +#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(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 &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 +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)); 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; From ce3077c970bdf01d45985e17cff9d759c88b9aed Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 12 Sep 2014 08:27:25 +1000 Subject: [PATCH 22/31] Test version with debug statements. Also moved some common code out to a separate file. --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwrender/videoplayer.cpp | 54 ++----------- apps/openmw/mwsound/ffmpeg_decoder.cpp | 60 +++------------ apps/openmw/mwsound/libavwrapper.cpp | 101 +++++++++++++++++++++++++ 4 files changed, 119 insertions(+), 98 deletions(-) create mode 100644 apps/openmw/mwsound/libavwrapper.cpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index babde8ff2..33433e203 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -53,7 +53,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 21a0cc832..731735c25 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -60,58 +60,14 @@ extern "C" #ifdef HAVE_LIBSWRESAMPLE #include #else + /* FIXME: remove this section once libswresample is available on all platforms */ #include #include - /* 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; } #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 } diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index a2652ba13..95c4e9c5c 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -5,57 +5,15 @@ #include +extern "C" { #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; } +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 { @@ -398,6 +356,12 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType * fail(std::string("Couldn't allocate SwrContext")); if(swr_init(mSwr) < 0) fail(std::string("Couldn't initialize SwrContext")); + +// FIXME: debug output +//#if 0 + std::cout << "channel_layout: " + std::to_string((*mStream)->codec->channel_layout) << std::endl; + std::cout << "in_channels: " + std::to_string((*mStream)->codec->channels) << std::endl; +//#endif } } diff --git a/apps/openmw/mwsound/libavwrapper.cpp b/apps/openmw/mwsound/libavwrapper.cpp new file mode 100644 index 000000000..ebf0d7777 --- /dev/null +++ b/apps/openmw/mwsound/libavwrapper.cpp @@ -0,0 +1,101 @@ +#ifndef HAVE_LIBSWRESAMPLE +extern "C" +{ +#ifdef _MSC_VER +# 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 From ecd9dd81eabf8d798c18c2134c5796cd42309136 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 12 Sep 2014 08:41:33 +1000 Subject: [PATCH 23/31] Moved debug statements before exception.. --- apps/openmw/mwsound/ffmpeg_decoder.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 95c4e9c5c..40ea85fcb 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -343,6 +343,11 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType * if(mOutputSampleFormat != AV_SAMPLE_FMT_NONE) { +// FIXME: debug output +//#if 0 + std::cout << "channel_layout: " + std::to_string((*mStream)->codec->channel_layout) << std::endl; + std::cout << "in_channels: " + std::to_string((*mStream)->codec->channels) << std::endl; +//#endif mSwr = swr_alloc_set_opts(mSwr, // SwrContext (*mStream)->codec->channel_layout, // output ch layout mOutputSampleFormat, // output sample format @@ -357,11 +362,6 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType * if(swr_init(mSwr) < 0) fail(std::string("Couldn't initialize SwrContext")); -// FIXME: debug output -//#if 0 - std::cout << "channel_layout: " + std::to_string((*mStream)->codec->channel_layout) << std::endl; - std::cout << "in_channels: " + std::to_string((*mStream)->codec->channels) << std::endl; -//#endif } } From be74db8b2437eb4c9af518c0758fe5408ad26ee1 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 12 Sep 2014 10:04:46 +1000 Subject: [PATCH 24/31] Don't use to_string() --- apps/openmw/mwsound/ffmpeg_decoder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 40ea85fcb..cbfbf436b 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -345,8 +345,8 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType * { // FIXME: debug output //#if 0 - std::cout << "channel_layout: " + std::to_string((*mStream)->codec->channel_layout) << std::endl; - std::cout << "in_channels: " + std::to_string((*mStream)->codec->channels) << std::endl; + printf("channel_layout: %" PRIu64 "\n",(*mStream)->codec->channel_layout); + printf("in_channels: %d\n",(*mStream)->codec->channels); //#endif mSwr = swr_alloc_set_opts(mSwr, // SwrContext (*mStream)->codec->channel_layout, // output ch layout From 0121fdca2ca10d47703ffa99d848b4a1f8854ffb Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 12 Sep 2014 10:31:49 +1000 Subject: [PATCH 25/31] Don't use C99 in printf. --- apps/openmw/mwsound/ffmpeg_decoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index cbfbf436b..5fca4b5b4 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -345,7 +345,7 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType * { // FIXME: debug output //#if 0 - printf("channel_layout: %" PRIu64 "\n",(*mStream)->codec->channel_layout); + printf("channel_layout: %d\n",(int)(*mStream)->codec->channel_layout); printf("in_channels: %d\n",(*mStream)->codec->channels); //#endif mSwr = swr_alloc_set_opts(mSwr, // SwrContext From de41dfc314d06ca9a226ffe9567abb10e354e25f Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 12 Sep 2014 10:52:10 +1000 Subject: [PATCH 26/31] Add includes. --- apps/openmw/mwsound/libavwrapper.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/openmw/mwsound/libavwrapper.cpp b/apps/openmw/mwsound/libavwrapper.cpp index ebf0d7777..4ba49be3b 100644 --- a/apps/openmw/mwsound/libavwrapper.cpp +++ b/apps/openmw/mwsound/libavwrapper.cpp @@ -5,6 +5,15 @@ extern "C" # include #endif +#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 From 8fe6877cb2f220c59a9017bcf05d2aa2d6f6f620 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 12 Sep 2014 11:05:02 +1000 Subject: [PATCH 27/31] More include madness b/w different systems & compilers --- apps/openmw/mwsound/libavwrapper.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwsound/libavwrapper.cpp b/apps/openmw/mwsound/libavwrapper.cpp index 4ba49be3b..114b08105 100644 --- a/apps/openmw/mwsound/libavwrapper.cpp +++ b/apps/openmw/mwsound/libavwrapper.cpp @@ -1,9 +1,7 @@ #ifndef HAVE_LIBSWRESAMPLE extern "C" { -#ifdef _MSC_VER -# include -#endif +#include #include #include From 675d11c0e5902fe49ff2f2784ae2bf4c8f29de3f Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 12 Sep 2014 11:25:11 +1000 Subject: [PATCH 28/31] Mental note: need to get a linux box --- apps/openmw/mwsound/libavwrapper.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwsound/libavwrapper.cpp b/apps/openmw/mwsound/libavwrapper.cpp index 114b08105..a12f412d1 100644 --- a/apps/openmw/mwsound/libavwrapper.cpp +++ b/apps/openmw/mwsound/libavwrapper.cpp @@ -1,6 +1,7 @@ #ifndef HAVE_LIBSWRESAMPLE extern "C" { +#define __STDC_CONSTANT_MACROS #include #include From 11071563347d5d68ccf3ef52ef61de643939fee2 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 12 Sep 2014 21:18:54 +1000 Subject: [PATCH 29/31] Workaround incorrectly reported channel_layout --- apps/openmw/mwrender/videoplayer.cpp | 26 +++++++++++++-------- apps/openmw/mwsound/ffmpeg_decoder.cpp | 31 ++++++++++++++------------ 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 731735c25..5ab504f48 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -488,6 +488,8 @@ public: 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) @@ -502,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: "); @@ -531,15 +539,15 @@ public: if(mOutputSampleFormat != AV_SAMPLE_FMT_NONE) { - mSwr = swr_alloc_set_opts(mSwr, // SwrContext - mAVStream->codec->channel_layout, // output ch layout - mOutputSampleFormat, // output sample format - mAVStream->codec->sample_rate, // output sample rate - mAVStream->codec->channel_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 + 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) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 5fca4b5b4..7b6e12576 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -300,6 +300,8 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType * 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) @@ -314,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: "); @@ -343,20 +351,15 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType * if(mOutputSampleFormat != AV_SAMPLE_FMT_NONE) { -// FIXME: debug output -//#if 0 - printf("channel_layout: %d\n",(int)(*mStream)->codec->channel_layout); - printf("in_channels: %d\n",(*mStream)->codec->channels); -//#endif - 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 + 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) From 166ee6b48325f361a4dbef6bbc048ad5984cf7df Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 15 Sep 2014 18:49:07 +1000 Subject: [PATCH 30/31] Do not use cached FFMPEG_LIBRARIES. Make error messages clearer. --- CMakeLists.txt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index df134f9c0..df2c2fdf8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,6 +140,7 @@ set(OPENMW_LIBS_HEADER) # Sound setup 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!") @@ -150,10 +151,15 @@ 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}) + # restrict the use of libavresample to debian based system only + if(EXISTS "/etc/debian_version") + if( AVRESAMPLE_FOUND ) + set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${AVRESAMPLE_LIBRARIES}) + else() + message(FATAL_ERROR "Libav libavresample required, but not found!") + endif() else() - message(FATAL_ERROR "FFmpeg component required, but not found!") + message(FATAL_ERROR "FFmpeg libswresample required, but not found!") endif() endif() From d92400e550bee35e92d805775952e404c5cde4fb Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 15 Sep 2014 19:46:11 +1000 Subject: [PATCH 31/31] Remove libavresample restriction. --- CMakeLists.txt | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index df2c2fdf8..98a190a5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -151,15 +151,10 @@ if( SWRESAMPLE_FOUND ) add_definitions(-DHAVE_LIBSWRESAMPLE) set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${SWRESAMPLE_LIBRARIES}) else() - # restrict the use of libavresample to debian based system only - if(EXISTS "/etc/debian_version") - if( AVRESAMPLE_FOUND ) - set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${AVRESAMPLE_LIBRARIES}) - else() - message(FATAL_ERROR "Libav libavresample required, but not found!") - endif() + if( AVRESAMPLE_FOUND ) + set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${AVRESAMPLE_LIBRARIES}) else() - message(FATAL_ERROR "FFmpeg libswresample required, but not found!") + message(FATAL_ERROR "Install either libswresample (FFmpeg) or libavresample (Libav).") endif() endif()