From 944f99b23a11c1d206a1dc8fa70f6e8c4c29fc6b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 31 Aug 2014 13:20:33 +1000 Subject: [PATCH 01/56] 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/56] 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/56] 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/56] 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/56] 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/56] 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/56] 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/56] 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/56] 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/56] 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/56] 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/56] 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 fd5f81421897dc31291be22aaf127f2f07a1864a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 3 Sep 2014 20:06:43 +1000 Subject: [PATCH 13/56] Trivial change from "Musics" to "Music Files" --- apps/opencs/model/world/universalid.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 7ee767354..7b5349db2 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -46,7 +46,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Filters, "Filters", 0 }, { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Meshes, "Meshes", 0 }, { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Icons, "Icons", 0 }, - { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Musics, "Musics", 0 }, + { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Musics, "Music Files", 0 }, { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_SoundsRes, "Sound Files", 0 }, { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Textures, "Textures", 0 }, { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Videos, "Videos", 0 }, From 093c7f8882d6de11512807d49bdd1cb917131f09 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 3 Sep 2014 22:52:03 +1000 Subject: [PATCH 14/56] 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 15/56] 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 16/56] 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 17/56] 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 dba352fd6f056ee85307efa3ce112d6f0c656336 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 7 Sep 2014 18:35:50 +1000 Subject: [PATCH 18/56] Check all views before exiting. --- apps/opencs/view/doc/viewmanager.cpp | 41 ++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 6f4217aa8..e7d948ee7 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -174,15 +174,15 @@ bool CSVDoc::ViewManager::closeRequest (View *view) bool continueWithClose = true; - if (iter!=mViews.end()) + if (iter!=mViews.end()) // found view in mViews { bool last = countViews (view->getDocument())<=1; - if (last) + if (last) // only this view for the document continueWithClose = notifySaveOnClose (view); else { - (*iter)->deleteLater(); + (*iter)->deleteLater(); // there are other views, delete this one mViews.erase (iter); updateIndices(); @@ -343,6 +343,37 @@ void CSVDoc::ViewManager::onExitWarningHandler (int state, CSMDoc::Document *doc void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view) { - if (notifySaveOnClose (view)) - QApplication::instance()->exit(); + // close the current view first + if(!closeRequest(view)) + return; // don't exit the application + else + { + view->deleteLater(); // ok to close the current view + view->setVisible(false); + std::vector::iterator iter = std::find (mViews.begin(), mViews.end(), view); + if (iter!=mViews.end()) + { + mViews.erase (iter); + updateIndices(); + } + + // attempt to close all other views + while(!mViews.empty()) + { + // raise the window + mViews.back()->activateWindow(); + mViews.back()->raise(); + // attempt to close it + if (!closeRequest(mViews.back())) + return; + else + { + mViews.back()->deleteLater(); + mViews.back()->setVisible(false); + mViews.pop_back(); + updateIndices(); + } + } + } + QApplication::instance()->exit(); } From cedf1171e3936724ad4ffdcb811fc83b70ce0231 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 7 Sep 2014 18:37:33 +1000 Subject: [PATCH 19/56] Cleanup comments. --- apps/opencs/view/doc/viewmanager.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index e7d948ee7..5b6dbaaf6 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -174,15 +174,15 @@ bool CSVDoc::ViewManager::closeRequest (View *view) bool continueWithClose = true; - if (iter!=mViews.end()) // found view in mViews + if (iter!=mViews.end()) { bool last = countViews (view->getDocument())<=1; - if (last) // only this view for the document + if (last) continueWithClose = notifySaveOnClose (view); else { - (*iter)->deleteLater(); // there are other views, delete this one + (*iter)->deleteLater(); mViews.erase (iter); updateIndices(); @@ -345,10 +345,10 @@ void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view) { // close the current view first if(!closeRequest(view)) - return; // don't exit the application + return; else { - view->deleteLater(); // ok to close the current view + view->deleteLater(); view->setVisible(false); std::vector::iterator iter = std::find (mViews.begin(), mViews.end(), view); if (iter!=mViews.end()) @@ -363,7 +363,6 @@ void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view) // raise the window mViews.back()->activateWindow(); mViews.back()->raise(); - // attempt to close it if (!closeRequest(mViews.back())) return; else From c396149f23e30ce4c84371f441d4c51eb4ec7d79 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 7 Sep 2014 20:35:32 +1000 Subject: [PATCH 20/56] 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 21/56] 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 22/56] 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 ad8d722763a322255c6b52a7e1cb924383b3d8a7 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 9 Sep 2014 10:05:06 +1000 Subject: [PATCH 23/56] Close documents rather than views. --- apps/opencs/view/doc/viewmanager.cpp | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 5b6dbaaf6..e31540173 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -343,36 +343,33 @@ void CSVDoc::ViewManager::onExitWarningHandler (int state, CSMDoc::Document *doc void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view) { - // close the current view first - if(!closeRequest(view)) + // close the current document first + if(!notifySaveOnClose(view)) return; else { - view->deleteLater(); + CSMDoc::Document * document = view->getDocument(); + if(document) + mDocumentManager.removeDocument(document); view->setVisible(false); - std::vector::iterator iter = std::find (mViews.begin(), mViews.end(), view); - if (iter!=mViews.end()) - { - mViews.erase (iter); - updateIndices(); - } - // attempt to close all other views + // attempt to close all other documents while(!mViews.empty()) { // raise the window mViews.back()->activateWindow(); mViews.back()->raise(); - if (!closeRequest(mViews.back())) + if (!notifySaveOnClose(mViews.back())) return; else { - mViews.back()->deleteLater(); + document = mViews.back()->getDocument(); + if(document) + mDocumentManager.removeDocument(document); mViews.back()->setVisible(false); mViews.pop_back(); - updateIndices(); } } } - QApplication::instance()->exit(); + // Editor exits (via a signal) when the last document is deleted } From 84f57845755954d36c4003b0bd05236aed25b72b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 9 Sep 2014 13:04:48 +1000 Subject: [PATCH 24/56] Remove document when closing the last view. Should resolve Bug #1292. --- apps/opencs/view/doc/view.cpp | 5 +++++ apps/opencs/view/doc/viewmanager.cpp | 12 ++++++++---- apps/opencs/view/doc/viewmanager.hpp | 1 + 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 4868f20ff..384ae6c54 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -24,6 +24,11 @@ void CSVDoc::View::closeEvent (QCloseEvent *event) { if (!mViewManager.closeRequest (this)) event->ignore(); + else + { + // closeRequest() returns true if last document + mViewManager.removeDocument(mDocument); + } } void CSVDoc::View::setupFileMenu() diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index e31540173..47a52891e 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -192,6 +192,12 @@ bool CSVDoc::ViewManager::closeRequest (View *view) return continueWithClose; } +void CSVDoc::ViewManager::removeDocument (CSMDoc::Document *document) +{ + if(document) + mDocumentManager.removeDocument(document); +} + bool CSVDoc::ViewManager::notifySaveOnClose (CSVDoc::View *view) { bool result = true; @@ -349,8 +355,7 @@ void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view) else { CSMDoc::Document * document = view->getDocument(); - if(document) - mDocumentManager.removeDocument(document); + removeDocument(document); view->setVisible(false); // attempt to close all other documents @@ -364,8 +369,7 @@ void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view) else { document = mViews.back()->getDocument(); - if(document) - mDocumentManager.removeDocument(document); + removeDocument(document); mViews.back()->setVisible(false); mViews.pop_back(); } diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index 8cc92774b..6be3aba5a 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -55,6 +55,7 @@ namespace CSVDoc ///< Return number of views for \a document. bool closeRequest (View *view); + void removeDocument (CSMDoc::Document *document); signals: From 4471fe771ee6790eee7e5e4e65120360c42a5664 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 9 Sep 2014 21:09:37 +1000 Subject: [PATCH 25/56] Fix logic errors. --- apps/opencs/view/doc/view.cpp | 2 +- apps/opencs/view/doc/viewmanager.cpp | 48 ++++++++++++++++++++++------ apps/opencs/view/doc/viewmanager.hpp | 2 +- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 384ae6c54..63bb9efb1 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -27,7 +27,7 @@ void CSVDoc::View::closeEvent (QCloseEvent *event) else { // closeRequest() returns true if last document - mViewManager.removeDocument(mDocument); + mViewManager.removeDocAndView(mDocument); } } diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 47a52891e..a037219a4 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -172,7 +172,7 @@ bool CSVDoc::ViewManager::closeRequest (View *view) { std::vector::iterator iter = std::find (mViews.begin(), mViews.end(), view); - bool continueWithClose = true; + bool continueWithClose = false; if (iter!=mViews.end()) { @@ -192,10 +192,22 @@ bool CSVDoc::ViewManager::closeRequest (View *view) return continueWithClose; } -void CSVDoc::ViewManager::removeDocument (CSMDoc::Document *document) +// NOTE: This method assumes that it is called only if the last document +void CSVDoc::ViewManager::removeDocAndView (CSMDoc::Document *document) { - if(document) - mDocumentManager.removeDocument(document); + for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) + { + // the first match should also be the only match + if((*iter)->getDocument() == document) + { + mDocumentManager.removeDocument(document); + (*iter)->deleteLater(); + mViews.erase (iter); + + updateIndices(); + return; + } + } } bool CSVDoc::ViewManager::notifySaveOnClose (CSVDoc::View *view) @@ -354,14 +366,23 @@ void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view) return; else { + // don't bother closing views or updating indicies, but remove from mViews CSMDoc::Document * document = view->getDocument(); - removeDocument(document); - view->setVisible(false); + std::vector remainingViews; + for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) + { + if(document == (*iter)->getDocument()) + (*iter)->setVisible(false); + else + remainingViews.push_back(*iter); + } + mDocumentManager.removeDocument(document); + mViews = remainingViews; // attempt to close all other documents while(!mViews.empty()) { - // raise the window + // raise the window to alert the user mViews.back()->activateWindow(); mViews.back()->raise(); if (!notifySaveOnClose(mViews.back())) @@ -369,9 +390,16 @@ void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view) else { document = mViews.back()->getDocument(); - removeDocument(document); - mViews.back()->setVisible(false); - mViews.pop_back(); + remainingViews.clear(); + for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) + { + if(document == (*iter)->getDocument()) + (*iter)->setVisible(false); + else + remainingViews.push_back(*iter); + } + mDocumentManager.removeDocument(document); + mViews = remainingViews; } } } diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index 6be3aba5a..e0121a7fb 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -55,7 +55,7 @@ namespace CSVDoc ///< Return number of views for \a document. bool closeRequest (View *view); - void removeDocument (CSMDoc::Document *document); + void removeDocAndView (CSMDoc::Document *document); signals: From fdc20c595dea9a36f00a975581cc3183a7204fcb Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 9 Sep 2014 21:24:54 +1000 Subject: [PATCH 26/56] Fix gcc compile error. --- apps/opencs/view/doc/viewmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index a037219a4..7690af401 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -195,7 +195,7 @@ bool CSVDoc::ViewManager::closeRequest (View *view) // NOTE: This method assumes that it is called only if the last document void CSVDoc::ViewManager::removeDocAndView (CSMDoc::Document *document) { - for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) + for (std::vector::iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) { // the first match should also be the only match if((*iter)->getDocument() == document) From 77171b788bcd8c53c816c2fb091e39048bd0e46f Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 10 Sep 2014 14:03:25 +1000 Subject: [PATCH 27/56] Made popup messagebox non-modal. --- apps/opencs/view/doc/viewmanager.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 7690af401..03d7a2638 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -228,13 +228,18 @@ bool CSVDoc::ViewManager::notifySaveOnClose (CSVDoc::View *view) bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (CSVDoc::View *view) { - QMessageBox messageBox; + emit closeMessageBox(); + + QMessageBox messageBox(view); CSMDoc::Document *document = view->getDocument(); messageBox.setText ("The document has been modified."); messageBox.setInformativeText ("Do you want to save your changes?"); messageBox.setStandardButtons (QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); messageBox.setDefaultButton (QMessageBox::Save); + messageBox.setWindowModality (Qt::NonModal); + messageBox.hide(); + messageBox.show(); bool retVal = true; From 89f76080225f270ebfd7a54a19b3c74331742d12 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 10 Sep 2014 14:40:41 +1000 Subject: [PATCH 28/56] Refactor for better legibility. --- apps/opencs/view/doc/viewmanager.cpp | 45 +++++++++++----------------- apps/opencs/view/doc/viewmanager.hpp | 1 + 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 03d7a2638..a058ea7a2 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -364,17 +364,17 @@ void CSVDoc::ViewManager::onExitWarningHandler (int state, CSMDoc::Document *doc } } -void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view) +bool CSVDoc::ViewManager::removeDocument (CSVDoc::View *view) { - // close the current document first if(!notifySaveOnClose(view)) - return; + return false; else { // don't bother closing views or updating indicies, but remove from mViews CSMDoc::Document * document = view->getDocument(); std::vector remainingViews; - for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) + std::vector::const_iterator iter = mViews.begin(); + for (; iter!=mViews.end(); ++iter) { if(document == (*iter)->getDocument()) (*iter)->setVisible(false); @@ -383,30 +383,21 @@ void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view) } mDocumentManager.removeDocument(document); mViews = remainingViews; + } + return true; +} - // attempt to close all other documents - while(!mViews.empty()) - { - // raise the window to alert the user - mViews.back()->activateWindow(); - mViews.back()->raise(); - if (!notifySaveOnClose(mViews.back())) - return; - else - { - document = mViews.back()->getDocument(); - remainingViews.clear(); - for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) - { - if(document == (*iter)->getDocument()) - (*iter)->setVisible(false); - else - remainingViews.push_back(*iter); - } - mDocumentManager.removeDocument(document); - mViews = remainingViews; - } - } +void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view) +{ + if(!removeDocument(view)) // close the current document first + return; + + while(!mViews.empty()) // attempt to close all other documents + { + mViews.back()->activateWindow(); + mViews.back()->raise(); // raise the window to alert the user + if(!removeDocument(mViews.back())) + return; } // Editor exits (via a signal) when the last document is deleted } diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index e0121a7fb..753d7f0cb 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -41,6 +41,7 @@ namespace CSVDoc bool notifySaveOnClose (View *view = 0); bool showModifiedDocumentMessageBox (View *view); bool showSaveInProgressMessageBox (View *view); + bool removeDocument(View *view); public: From f7c1b169b38b60ff9dd9d2cbcb3a5207b407f519 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 10 Sep 2014 20:00:07 +1000 Subject: [PATCH 29/56] Place the settings window on the center of window with keyboard focus. Should resolve Bug #1838. --- apps/opencs/view/settings/dialog.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/settings/dialog.cpp b/apps/opencs/view/settings/dialog.cpp index 56bc1fdfe..72a022c9d 100644 --- a/apps/opencs/view/settings/dialog.cpp +++ b/apps/opencs/view/settings/dialog.cpp @@ -114,8 +114,20 @@ void CSVSettings::Dialog::show() setViewValues(); } - QPoint screenCenter = QApplication::desktop()->screenGeometry().center(); - - move (screenCenter - geometry().center()); + QWidget *currView = QApplication::activeWindow(); + if(currView) + { + // place at the center of the window with focus + QSize size = currView->size(); + move(currView->geometry().x()+(size.width() - frameGeometry().width())/2, + currView->geometry().y()+(size.height() - frameGeometry().height())/2); + } + else + { + // something's gone wrong, place at the center of the screen + QPoint screenCenter = QApplication::desktop()->screenGeometry().center(); + move(screenCenter - QPoint(frameGeometry().width()/2, + frameGeometry().height()/2)); + } QWidget::show(); } From 227eb12295415c1755e3b954c08fdaac9046022c Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 10 Sep 2014 20:29:47 +1000 Subject: [PATCH 30/56] Added document name to showModifiedDocumentMessageBox. --- apps/opencs/view/doc/viewmanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index a058ea7a2..638b42d5f 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -233,6 +233,7 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (CSVDoc::View *view) QMessageBox messageBox(view); CSMDoc::Document *document = view->getDocument(); + messageBox.setWindowTitle (document->getSavePath().filename().string().c_str()); messageBox.setText ("The document has been modified."); messageBox.setInformativeText ("Do you want to save your changes?"); messageBox.setStandardButtons (QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); From ae0fb77e30b0f437ca2086b0af03c69a771e79bb Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 10 Sep 2014 21:23:38 +1000 Subject: [PATCH 31/56] Move recordfilterbox label 2 pixels to right. Resolves Bug #1839. --- apps/opencs/view/filter/recordfilterbox.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/filter/recordfilterbox.cpp b/apps/opencs/view/filter/recordfilterbox.cpp index ec5647618..ef2aeb4d3 100644 --- a/apps/opencs/view/filter/recordfilterbox.cpp +++ b/apps/opencs/view/filter/recordfilterbox.cpp @@ -13,7 +13,9 @@ CSVFilter::RecordFilterBox::RecordFilterBox (CSMWorld::Data& data, QWidget *pare layout->setContentsMargins (0, 0, 0, 0); - layout->addWidget (new QLabel ("Record Filter", this)); + QLabel *label = new QLabel("Record Filter", this); + label->setIndent(2); + layout->addWidget (label); mEdit = new EditWidget (data, this); From 85596322f33160fbc0482261d2bd9652d4f82c33 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 10 Sep 2014 23:13:56 +1000 Subject: [PATCH 32/56] Update status bar when record filter is changed. Should resolve Bug #1290. --- apps/opencs/view/world/table.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 43a34e41d..a9b0373c8 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -448,12 +448,12 @@ void CSVWorld::Table::tableSizeUpdate() size = rows; } - tableSizeChanged (size, deleted, modified); + emit tableSizeChanged (size, deleted, modified); } void CSVWorld::Table::selectionSizeUpdate() { - selectionSizeChanged (selectionModel()->selectedRows().size()); + emit selectionSizeChanged (selectionModel()->selectedRows().size()); } void CSVWorld::Table::requestFocus (const std::string& id) @@ -467,6 +467,8 @@ void CSVWorld::Table::requestFocus (const std::string& id) void CSVWorld::Table::recordFilterChanged (boost::shared_ptr filter) { mProxyModel->setFilter (filter); + tableSizeUpdate(); + selectionSizeUpdate(); } void CSVWorld::Table::mouseMoveEvent (QMouseEvent* event) From faac91472c1bcb208cc944f9cfd6fe80e136677f Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 10 Sep 2014 23:30:42 +1000 Subject: [PATCH 33/56] Allow '-' and '_' in new addon name. Resolves Bug #1789. --- apps/opencs/view/doc/filewidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/doc/filewidget.cpp b/apps/opencs/view/doc/filewidget.cpp index 9cd2fad42..f18fe695a 100644 --- a/apps/opencs/view/doc/filewidget.cpp +++ b/apps/opencs/view/doc/filewidget.cpp @@ -17,7 +17,7 @@ CSVDoc::FileWidget::FileWidget (QWidget *parent) : QWidget (parent), mAddon (fal QHBoxLayout *layout = new QHBoxLayout (this); mInput = new QLineEdit (this); - mInput->setValidator (new QRegExpValidator(QRegExp("^[a-zA-Z0-9\\s]*$"))); + mInput->setValidator (new QRegExpValidator(QRegExp("^[a-zA-Z0-9_-\\s]*$"))); layout->addWidget (mInput, 1); From 862c5fc8f6bd48d7104b2160bfa56c8c656e8f6b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 11 Sep 2014 16:47:00 +1000 Subject: [PATCH 34/56] 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 35/56] 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 36/56] 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 37/56] 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 38/56] 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 39/56] 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 40/56] 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 41/56] 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 42/56] 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 43/56] 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 6882f069b2f589bb3c1902e45edf7d61f6c8d3ef Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 15 Sep 2014 09:25:45 +0200 Subject: [PATCH 44/56] updated credits --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index 893c8a4e5..1096e85d8 100644 --- a/credits.txt +++ b/credits.txt @@ -67,6 +67,7 @@ Nolan Poe (nopoe) Paul McElroy (Greendogo) Pieter van der Kloet (pvdk) Radu-Marius Popovici (rpopovici) +Robert MacGregor (Ragora) Roman Melnik (Kromgart) Roman Proskuryakov (humbug) sandstranger From 3d8216ee1793d299f53677410460521b3588a325 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 15 Sep 2014 09:51:39 +0200 Subject: [PATCH 45/56] fixed broken content file list in case of newly created addons --- apps/opencs/editor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index e8e2d9077..794ca3d7b 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -189,7 +189,7 @@ void CS::Editor::createNewFile (const boost::filesystem::path &savePath) files.push_back(path.toUtf8().constData()); } - files.push_back(mFileDialog.filename().toUtf8().constData()); + files.push_back (savePath); mDocumentManager.addDocument (files, savePath, true); From e3cffbd7686210f8db339557eb630a64200143a2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Sep 2014 10:35:42 +0200 Subject: [PATCH 46/56] Add missing authors to credits.txt --- credits.txt | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/credits.txt b/credits.txt index 1096e85d8..49e5a646e 100644 --- a/credits.txt +++ b/credits.txt @@ -30,22 +30,28 @@ darkf Dmitry Shkurskiy (endorph) Douglas Diniz (Dgdiniz) Douglas Mencken (dougmencken) +dreamer-dead Edmondo Tommasina (edmondo) Eduard Cot (trombonecot) Eli2 Emanuel Guével (potatoesmaster) +eroen Fil Krynicki (filkry) +Gašper Sedej gugus/gus Hallfaer Tuilinn Jacob Essex (Yacoby) Jannik Heller (scrawl) Jason Hooks (jhooks) +jeaye Jeffrey Haines (Jyby) Joel Graff (graffy) John Blomberg (fstp) +Jordan Ayers Jordan Milne Julien Voisin (jvoisin/ap0) Karl-Felix Glatzer (k1ll) +Kevin Poitra (PuppyKevin) Lars Söderberg (Lazaroth) lazydev Leon Saunders (emoose) @@ -61,17 +67,23 @@ Michael Hogan (Xethik) Michael Mc Donnell Michael Papageorgiou (werdanith) Michał Bień (Glorf) +Miroslav Puda (pakanek) +MiroslavR Nathan Jeffords (blunted2night) Nikolay Kasyanov (corristo) +nobrakal Nolan Poe (nopoe) Paul McElroy (Greendogo) Pieter van der Kloet (pvdk) Radu-Marius Popovici (rpopovici) +riothamus Robert MacGregor (Ragora) +Rohit Nirmal Roman Melnik (Kromgart) Roman Proskuryakov (humbug) sandstranger Sandy Carter (bwrsandman) +Scott Howard Sebastian Wick (swick) Sergey Shambir sir_herrbatka @@ -81,6 +93,7 @@ Sylvain Thesnieres (Garvek) Thomas Luppi (Digmaster) Tom Mason (wheybags) Torben Leif Carrington (TorbenC) +Vincent Heuken Packagers: Alexander Olofsson (Ace) - Windows @@ -125,11 +138,12 @@ Sadler Artwork: Necrod - OpenMW Logo Mickey Lyle (raevol) - Wordpress Theme -Okulo - OpenMW Editor Icons +Okulo, SirHerrbatka, crysthala - OpenMW Editor Icons Inactive Contributors: Ardekantur Armin Preiml +Berulacks Carl Maxwell Diggory Hardy Dmitry Marakasov (AMDmi3) From 157c53bed42753944cfd77404c055c683008297f Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Sep 2014 00:29:21 +0200 Subject: [PATCH 47/56] Handle spellcasting for creatures with no casting animation (Fixes #1856) --- apps/openmw/mwclass/creature.cpp | 3 + apps/openmw/mwmechanics/aicombataction.cpp | 3 + apps/openmw/mwmechanics/character.cpp | 72 ++++++++++++++++------ apps/openmw/mwmechanics/character.hpp | 2 + apps/openmw/mwworld/worldimp.cpp | 6 +- 5 files changed, 65 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index c31ab2a2a..8d8a2f823 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -209,6 +209,9 @@ namespace MWClass const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); MWMechanics::CreatureStats &stats = getCreatureStats(ptr); + if (stats.getDrawState() != MWMechanics::DrawState_Weapon) + return; + // Get the weapon used (if hand-to-hand, weapon = inv.end()) MWWorld::Ptr weapon; if (ptr.getClass().hasInventoryStore(ptr)) diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 1c18dd028..651cf5c02 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -292,6 +292,9 @@ namespace MWMechanics case ESM::MagicEffect::CurePoison: return 1001.f * numEffectsToCure(actor, ESM::MagicEffect::Poison); + case ESM::MagicEffect::DisintegrateArmor: // TODO: check if actor is wearing armor + case ESM::MagicEffect::DisintegrateWeapon: // TODO: check if actor is wearing weapon + default: break; } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9d1e5e52f..825d77869 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -690,11 +690,52 @@ void CharacterController::updateIdleStormState() } } +void CharacterController::castSpell(const std::string &spellid) +{ + static const std::string schools[] = { + "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" + }; + + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Spell *spell = store.get().find(spellid); + const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0); + + const ESM::MagicEffect *effect; + effect = store.get().find(effectentry.mEffectID); + + const ESM::Static* castStatic; + if (!effect->mCasting.empty()) + castStatic = store.get().find (effect->mCasting); + else + castStatic = store.get().find ("VFX_DefaultCast"); + + mAnimation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex); + + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + if(!effect->mCastSound.empty()) + sndMgr->playSound3D(mPtr, effect->mCastSound, 1.0f, 1.0f); + else + sndMgr->playSound3D(mPtr, schools[effect->mData.mSchool]+" cast", 1.0f, 1.0f); +} + bool CharacterController::updateCreatureState() { const MWWorld::Class &cls = mPtr.getClass(); CreatureStats &stats = cls.getCreatureStats(mPtr); + WeaponType weapType = WeapType_None; + if(stats.getDrawState() == DrawState_Weapon) + weapType = WeapType_HandToHand; + else if (stats.getDrawState() == DrawState_Spell) + weapType = WeapType_Spell; + + if (weapType != mWeaponType) + { + mWeaponType = weapType; + if (mAnimation->isPlaying(mCurrentWeapon)) + mAnimation->disable(mCurrentWeapon); + } + if(stats.getAttackingOrSpell()) { if(mUpperBodyState == UpperCharState_Nothing && mHitState == CharState_None) @@ -715,7 +756,18 @@ bool CharacterController::updateCreatureState() 1, "start", "stop", 0.0f, 0); mUpperBodyState = UpperCharState_StartToMinAttack; + + if (weapType == WeapType_Spell) + { + const std::string spellid = stats.getSpells().getSelectedSpell(); + if (!spellid.empty() && MWBase::Environment::get().getWorld()->startSpellCast(mPtr)) + { + castSpell(spellid); + MWBase::Environment::get().getWorld()->castSpell(mPtr); + } + } } + stats.setAttackingOrSpell(false); } @@ -854,9 +906,7 @@ bool CharacterController::updateWeaponState() if(!spellid.empty() && MWBase::Environment::get().getWorld()->startSpellCast(mPtr)) { - static const std::string schools[] = { - "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" - }; + castSpell(spellid); const ESM::Spell *spell = store.get().find(spellid); const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0); @@ -864,15 +914,7 @@ bool CharacterController::updateWeaponState() const ESM::MagicEffect *effect; effect = store.get().find(effectentry.mEffectID); - const ESM::Static* castStatic; - if (!effect->mCasting.empty()) - castStatic = store.get().find (effect->mCasting); - else - castStatic = store.get().find ("VFX_DefaultCast"); - - mAnimation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex); - - castStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Hands"); + const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Hands"); if (mAnimation->getNode("Left Hand")) { mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Left Hand", effect->mParticle); @@ -896,12 +938,6 @@ bool CharacterController::updateWeaponState() weapSpeed, mAttackType+" start", mAttackType+" stop", 0.0f, 0); mUpperBodyState = UpperCharState_CastingSpell; - - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - if(!effect->mCastSound.empty()) - sndMgr->playSound3D(mPtr, effect->mCastSound, 1.0f, 1.0f); - else - sndMgr->playSound3D(mPtr, schools[effect->mData.mSchool]+" cast", 1.0f, 1.0f); } if (inv.getSelectedEnchantItem() != inv.end()) { diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 8110c88cd..12a68970b 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -181,6 +181,8 @@ class CharacterController bool updateCreatureState(); void updateIdleStormState(); + void castSpell(const std::string& spellid); + void updateVisibility(); void playDeath(float startpoint, CharacterState death); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4a2f79b0d..e62ee72c3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2502,9 +2502,9 @@ namespace MWWorld { const ESM::Spell* spell = getStore().get().search(selectedSpell); - // A power can be used once per 24h - if (spell->mData.mType == ESM::Spell::ST_Power) - stats.getSpells().usePower(spell->mId); + // A power can be used once per 24h + if (spell->mData.mType == ESM::Spell::ST_Power) + stats.getSpells().usePower(spell->mId); cast.cast(spell); } From 0c75c6bf1bcc4d07ebffdf162087ea509984d524 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Sep 2014 07:02:41 +0200 Subject: [PATCH 48/56] Improve spellcasting AI for Drain/Damage effects --- apps/openmw/mwmechanics/aicombataction.cpp | 31 +++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 651cf5c02..67afad7a5 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -8,7 +8,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/actionequip.hpp" -#include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/npcstats.hpp" #include #include @@ -294,6 +294,35 @@ namespace MWMechanics case ESM::MagicEffect::DisintegrateArmor: // TODO: check if actor is wearing armor case ESM::MagicEffect::DisintegrateWeapon: // TODO: check if actor is wearing weapon + break; + + case ESM::MagicEffect::DamageAttribute: + case ESM::MagicEffect::DrainAttribute: + if (!target.isEmpty() && target.getClass().getCreatureStats(target).getAttribute(effect.mAttribute).getModified() <= 0) + return 0.f; + { + const float attributePriorities[ESM::Attribute::Length] = { + 1.f, // Strength + 0.5, // Intelligence + 0.6, // Willpower + 0.7, // Agility + 0.5, // Speed + 0.8, // Endurance + 0.7, // Personality + 0.3 // Luck + }; + if (effect.mAttribute >= 0 && effect.mAttribute < ESM::Attribute::Length) + rating *= attributePriorities[effect.mAttribute]; + } + break; + + case ESM::MagicEffect::DamageSkill: + case ESM::MagicEffect::DrainSkill: + if (target.isEmpty() || !target.getClass().isNpc()) + return 0.f; + if (target.getClass().getNpcStats(target).getSkill(effect.mSkill).getModified() <= 0) + return 0.f; + break; default: break; From 166ee6b48325f361a4dbef6bbc048ad5984cf7df Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 15 Sep 2014 18:49:07 +1000 Subject: [PATCH 49/56] 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 50/56] 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() From 4c285151a3789105489259f3b01e5114a9a5d3a0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 16 Sep 2014 02:38:49 +0200 Subject: [PATCH 51/56] Fix incorrect movement animation for some creatures (Fixes #1924) --- apps/openmw/mwmechanics/character.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 825d77869..249cb13bf 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -258,6 +258,8 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType)); + if (!mPtr.getClass().hasInventoryStore(mPtr)) + weap = sWeaponTypeListEnd; if(force || idle != mIdleState) { From b6a89c78453e8d51ca7130351413fc18e766bd9d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 16 Sep 2014 03:01:48 +0200 Subject: [PATCH 52/56] Fix idlestorm animation conflict with torch animation --- apps/openmw/mwmechanics/character.cpp | 6 +++--- apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 249cb13bf..566ca77aa 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -668,10 +668,10 @@ void CharacterController::updateIdleStormState() mAnimation->getInfo("idlestorm", &complete); if (complete == 0) - mAnimation->play("idlestorm", Priority_Torch, MWRender::Animation::Group_RightArm, false, + mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::Group_RightArm, false, 1.0f, "start", "loop start", 0.0f, 0); else if (complete == 1) - mAnimation->play("idlestorm", Priority_Torch, MWRender::Animation::Group_RightArm, false, + mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::Group_RightArm, false, 1.0f, "loop start", "loop stop", 0.0f, ~0ul); } else @@ -682,7 +682,7 @@ void CharacterController::updateIdleStormState() { if (mAnimation->getCurrentTime("idlestorm") < mAnimation->getTextKeyTime("idlestorm: loop stop")) { - mAnimation->play("idlestorm", Priority_Torch, MWRender::Animation::Group_RightArm, true, + mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::Group_RightArm, true, 1.0f, "loop stop", "stop", 0.0f, 0); } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 12a68970b..d09d2df52 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -32,6 +32,7 @@ enum Priority { Priority_Weapon, Priority_Knockdown, Priority_Torch, + Priority_Storm, Priority_Death, From 269c200c8f5e659189579c2b93e91d2a93e609ac Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 16 Sep 2014 03:15:04 +0200 Subject: [PATCH 53/56] Fix jump velocity mechanics (Fixes #1708) --- apps/openmw/mwmechanics/character.cpp | 38 +++++++++------------------ apps/openmw/mwworld/physicssystem.cpp | 20 +++++++------- 2 files changed, 24 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 566ca77aa..cba51b835 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1277,15 +1277,7 @@ void CharacterController::update(float duration) //Ogre::Vector3 vec = cls.getMovementVector(mPtr); Ogre::Vector3 vec(cls.getMovementSettings(mPtr).mPosition); - if(vec.z > 0.0f) // to avoid slow-down when jumping - { - Ogre::Vector2 vecXY = Ogre::Vector2(vec.x, vec.y); - vecXY.normalise(); - vec.x = vecXY.x; - vec.y = vecXY.y; - } - else - vec.normalise(); + vec.normalise(); if(mHitState != CharState_None && mJumpState == JumpState_None) vec = Ogre::Vector3(0.0f); @@ -1383,28 +1375,24 @@ void CharacterController::update(float duration) mJumpState = JumpState_Falling; // This is a guess. All that seems to be known is that "While the player is in the - // air, fJumpMoveBase and fJumpMoveMult governs air control." Assuming Acrobatics - // plays a role, this makes the most sense. - float mult = 0.0f; - if(cls.isNpc()) - { - const NpcStats &stats = cls.getNpcStats(mPtr); - static const float fJumpMoveBase = gmst.find("fJumpMoveBase")->getFloat(); - static const float fJumpMoveMult = gmst.find("fJumpMoveMult")->getFloat(); + // air, fJumpMoveBase and fJumpMoveMult governs air control". What does fJumpMoveMult do? + static const float fJumpMoveBase = gmst.find("fJumpMoveBase")->getFloat(); - mult = fJumpMoveBase + - (stats.getSkill(ESM::Skill::Acrobatics).getModified()/100.0f * - fJumpMoveMult); - } - - vec.x *= mult; - vec.y *= mult; + vec.x *= fJumpMoveBase; + vec.y *= fJumpMoveBase; vec.z = 0.0f; } else if(vec.z > 0.0f && mJumpState == JumpState_None) { // Started a jump. - vec.z = cls.getJump(mPtr); + float z = cls.getJump(mPtr); + if(vec.x == 0 && vec.y == 0) + vec = Ogre::Vector3(0.0f, 0.0f, z); + else + { + Ogre::Vector3 lat = Ogre::Vector3(vec.x, vec.y, 0.0f).normalisedCopy(); + vec = Ogre::Vector3(lat.x, lat.y, 1.0f) * z * 0.707f; + } // advance acrobatics if (mPtr.getRefData().getHandle() == "player") diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 51aae2bc3..5a28e4460 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -299,18 +299,20 @@ namespace MWWorld // not in water nor can fly, so need to deal with gravity if(!physicActor->getOnGround()) // if current OnGround status is false, must be falling or jumping { - // If falling, add part of the incoming velocity with the current inertia - // TODO: but we could be jumping up? - velocity = velocity * time + physicActor->getInertialForce(); - - // avoid getting infinite inertia in air + // If falling or jumping up, add part of the incoming velocity with the current inertia, + // but don't allow increasing inertia beyond actor's speed (except on the initial jump impulse) float actorSpeed = ptr.getClass().getSpeed(ptr); - float speedXY = Ogre::Vector2(velocity.x, velocity.y).length(); - if (speedXY > actorSpeed) + float cap = std::max(actorSpeed, Ogre::Vector2(physicActor->getInertialForce().x, physicActor->getInertialForce().y).length()); + Ogre::Vector3 newVelocity = velocity + physicActor->getInertialForce(); + if (Ogre::Vector2(newVelocity.x, newVelocity.y).squaredLength() > cap*cap) { - velocity.x *= actorSpeed / speedXY; - velocity.y *= actorSpeed / speedXY; + velocity = newVelocity; + float speedXY = Ogre::Vector2(velocity.x, velocity.y).length(); + velocity.x *= cap / speedXY; + velocity.y *= cap / speedXY; } + else + velocity = newVelocity; } inertia = velocity; // NOTE: velocity is for z axis only in this code block From 6debd21ec6f989ab8b36743aa6c187faf0aa2b4d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Sep 2014 02:20:46 +0200 Subject: [PATCH 54/56] Make sure the Jump control is always handled by the PhysicsSystem even if game runs faster than the minimum physics timestep --- apps/openmw/mwmechanics/character.cpp | 13 +++++++------ apps/openmw/mwmechanics/character.hpp | 2 +- apps/openmw/mwworld/physicssystem.cpp | 3 +++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index cba51b835..104c2bae3 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -310,7 +310,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } } - if(mJumpState == JumpState_Falling) + if(mJumpState == JumpState_InAir) { int mode = ((jump == mCurrentJump) ? 2 : 1); @@ -1275,7 +1275,6 @@ void CharacterController::update(float duration) } } - //Ogre::Vector3 vec = cls.getMovementVector(mPtr); Ogre::Vector3 vec(cls.getMovementSettings(mPtr).mPosition); vec.normalise(); @@ -1371,8 +1370,8 @@ void CharacterController::update(float duration) cls.getCreatureStats(mPtr).land(); } - forcestateupdate = (mJumpState != JumpState_Falling); - mJumpState = JumpState_Falling; + forcestateupdate = (mJumpState != JumpState_InAir); + mJumpState = JumpState_InAir; // This is a guess. All that seems to be known is that "While the player is in the // air, fJumpMoveBase and fJumpMoveMult governs air control". What does fJumpMoveMult do? @@ -1408,7 +1407,7 @@ void CharacterController::update(float duration) fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease); cls.getCreatureStats(mPtr).setFatigue(fatigue); } - else if(mJumpState == JumpState_Falling) + else if(mJumpState == JumpState_InAir) { forcestateupdate = true; mJumpState = JumpState_Landing; @@ -1529,7 +1528,9 @@ void CharacterController::update(float duration) world->queueMovement(mPtr, Ogre::Vector3(0.0f)); movement = vec; - cls.getMovementSettings(mPtr).mPosition[0] = cls.getMovementSettings(mPtr).mPosition[1] = cls.getMovementSettings(mPtr).mPosition[2] = 0; + cls.getMovementSettings(mPtr).mPosition[0] = cls.getMovementSettings(mPtr).mPosition[1] = 0; + // Can't reset jump state (mPosition[2]) here; we don't know for sure whether the PhysicSystem will actually handle it in this frame + // due to the fixed minimum timestep used for the physics update. It will be reset in PhysicSystem::move once the jump is handled. } else if(cls.getCreatureStats(mPtr).isDead()) { diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index d09d2df52..6528c041f 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -130,7 +130,7 @@ enum UpperBodyCharacterState { enum JumpingState { JumpState_None, - JumpState_Falling, + JumpState_InAir, JumpState_Landing }; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 5a28e4460..31d52e39d 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -23,6 +23,7 @@ #include "../mwbase/environment.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/movement.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" @@ -296,6 +297,7 @@ namespace MWWorld else { velocity = Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * movement; + // not in water nor can fly, so need to deal with gravity if(!physicActor->getOnGround()) // if current OnGround status is false, must be falling or jumping { @@ -333,6 +335,7 @@ namespace MWWorld } } } + ptr.getClass().getMovementSettings(ptr).mPosition[2] = 0; // Now that we have the effective movement vector, apply wind forces to it if (MWBase::Environment::get().getWorld()->isInStorm()) From 3ce3f31452fa271e9297079fb50f66238f42bf10 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Sep 2014 05:20:10 +0200 Subject: [PATCH 55/56] Adjust turning animation speed multiplier based on turning speed --- apps/openmw/mwmechanics/character.cpp | 18 +++++++++++++++++- apps/openmw/mwmechanics/character.hpp | 2 ++ apps/openmw/mwrender/animation.cpp | 7 +++++++ apps/openmw/mwrender/animation.hpp | 4 ++++ 4 files changed, 30 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 104c2bae3..fe316b768 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -416,7 +416,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat speedmult = mMovementSpeed / vel; } else if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight) - speedmult = 1.f; // TODO: should get a speed mult depending on the current turning speed + speedmult = 1.f; // adjusted each frame else if (mMovementSpeed > 0.0f) { // The first person anims don't have any velocity to calculate a speed multiplier from. @@ -592,6 +592,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim , mSkipAnim(false) , mSecondsOfRunning(0) , mSecondsOfSwimming(0) + , mTurnAnimationThreshold(0) { if(!mAnimation) return; @@ -1480,6 +1481,15 @@ void CharacterController::update(float duration) } } + mTurnAnimationThreshold -= duration; + if (movestate == CharState_TurnRight || movestate == CharState_TurnLeft) + mTurnAnimationThreshold = 0.05; + else if (movestate == CharState_None && (mMovementState == CharState_TurnRight || mMovementState == CharState_TurnLeft) + && mTurnAnimationThreshold > 0) + { + movestate = mMovementState; + } + if (onground) cls.getCreatureStats(mPtr).land(); @@ -1510,6 +1520,12 @@ void CharacterController::update(float duration) if (inJump) mMovementAnimationControlled = false; + if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight) + { + if (duration > 0) + mAnimation->adjustSpeedMult(mCurrentMovement, std::min(1.5f, std::abs(rot.z) / duration / Ogre::Math::PI)); + } + if (!mSkipAnim) { rot *= Ogre::Math::RadiansToDegrees(1.0f); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 6528c041f..550cae5fc 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -171,6 +171,8 @@ class CharacterController float mSecondsOfSwimming; float mSecondsOfRunning; + float mTurnAnimationThreshold; // how long to continue playing turning animation after actor stopped turning + std::string mAttackType; // slash, chop or thrust void determineAttackType(); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 81b92dcbf..e2f3ce62f 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -914,6 +914,13 @@ void Animation::play(const std::string &groupname, int priority, int groups, boo } } +void Animation::adjustSpeedMult(const std::string &groupname, float speedmult) +{ + AnimStateMap::iterator state(mStates.find(groupname)); + if(state != mStates.end()) + state->second.mSpeedMult = speedmult; +} + bool Animation::isPlaying(const std::string &groupname) const { AnimStateMap::const_iterator state(mStates.find(groupname)); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 4f53a737b..8ca3582dc 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -260,6 +260,10 @@ public: float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops); + /** Adjust the speed multiplier of an already playing animation. + */ + void adjustSpeedMult (const std::string& groupname, float speedmult); + /** Returns true if the named animation group is playing. */ bool isPlaying(const std::string &groupname) const; From 441073b475c05b8300735f03a203cc565de4add1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Sep 2014 06:53:30 +0200 Subject: [PATCH 56/56] Remove ancient comment --- apps/openmw/mwworld/worldimp.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e62ee72c3..425fa20e5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -162,7 +162,6 @@ namespace MWWorld mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); - // NOTE: We might need to reserve one more for the running game / save. mEsm.resize(contentFiles.size()); Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); listener->loadingOn();