From 81908c20a405191305f4f643c7a96b44e00861f8 Mon Sep 17 00:00:00 2001 From: ronag Date: Fri, 19 Aug 2011 08:22:48 +0000 Subject: [PATCH] 2.0. ffmpeg_producer: Refactored meta data fix. git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@1222 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d --- .../ffmpeg/producer/audio/audio_decoder.cpp | 8 --- modules/ffmpeg/producer/audio/audio_decoder.h | 1 - modules/ffmpeg/producer/ffmpeg_producer.cpp | 21 ++---- modules/ffmpeg/producer/util.cpp | 70 +++++++++++++++++++ modules/ffmpeg/producer/util.h | 2 + .../ffmpeg/producer/video/video_decoder.cpp | 28 ++------ 6 files changed, 83 insertions(+), 47 deletions(-) diff --git a/modules/ffmpeg/producer/audio/audio_decoder.cpp b/modules/ffmpeg/producer/audio/audio_decoder.cpp index 00848a169..ae9ef01c4 100644 --- a/modules/ffmpeg/producer/audio/audio_decoder.cpp +++ b/modules/ffmpeg/producer/audio/audio_decoder.cpp @@ -57,12 +57,10 @@ struct audio_decoder::implementation : boost::noncopyable std::queue> packets_; int64_t nb_frames_; - double duration_; public: explicit implementation(const safe_ptr& context, const core::video_format_desc& format_desc) : format_desc_(format_desc) , nb_frames_(0) - , duration_(std::numeric_limits::max()) { try { @@ -75,11 +73,6 @@ public: buffer1_.resize(AVCODEC_MAX_AUDIO_FRAME_SIZE*2); - //nb_frames_ = context->streams[index_]->nb_frames; - //if(nb_frames_ == 0) - // nb_frames_ = context->streams[index_]->duration / (codec_context_->channels*codec_context_->sample_rate); - duration_ = context->streams[index_]->duration / static_cast(codec_context_->sample_rate); - if(codec_context_->sample_rate != static_cast(format_desc_.audio_sample_rate) || codec_context_->channels != static_cast(format_desc_.audio_channels) || codec_context_->sample_fmt != AV_SAMPLE_FMT_S16) @@ -195,5 +188,4 @@ void audio_decoder::push(const std::shared_ptr& packet){impl_->push(pa bool audio_decoder::ready() const{return impl_->ready();} std::vector>> audio_decoder::poll(){return impl_->poll();} int64_t audio_decoder::nb_frames() const{return impl_->nb_frames_;} -double audio_decoder::duration() const {return impl_->duration_;} } \ No newline at end of file diff --git a/modules/ffmpeg/producer/audio/audio_decoder.h b/modules/ffmpeg/producer/audio/audio_decoder.h index b48b39c00..2ef82eaab 100644 --- a/modules/ffmpeg/producer/audio/audio_decoder.h +++ b/modules/ffmpeg/producer/audio/audio_decoder.h @@ -46,7 +46,6 @@ public: std::vector>> poll(); int64_t nb_frames() const; - double duration() const; private: struct implementation; diff --git a/modules/ffmpeg/producer/ffmpeg_producer.cpp b/modules/ffmpeg/producer/ffmpeg_producer.cpp index 97d95dd17..d6ec0d899 100644 --- a/modules/ffmpeg/producer/ffmpeg_producer.cpp +++ b/modules/ffmpeg/producer/ffmpeg_producer.cpp @@ -46,19 +46,7 @@ #include namespace caspar { - -double validate_fps(double fps, int64_t nb_frames, double duration_sec) -{ - if(fps > 20.0 && fps < 80.0) - return fps; - - auto est_fps = nb_frames/duration_sec; - - CASPAR_LOG(warning) << L"Invalid framerate detected, trying to estimate, fps: " << fps << L" nb_frames: " << nb_frames << L" duration_sec: " << duration_sec << L" => " << est_fps << L" fps."; - - return est_fps; -} - + struct ffmpeg_producer : public core::frame_producer { const std::wstring filename_; @@ -97,7 +85,7 @@ public: , input_(graph_, filename_, loop, start, length) , video_decoder_(input_.context(), frame_factory, filter) , audio_decoder_(input_.context(), frame_factory->get_video_format_desc()) - , fps_(validate_fps(video_decoder_.fps(), video_decoder_.nb_frames(), audio_decoder_.duration())) + , fps_(video_decoder_.fps()) , muxer_(fps_, frame_factory) , late_frames_(0) , start_(start) @@ -212,8 +200,9 @@ public: virtual std::wstring print() const { return L"ffmpeg[" + boost::filesystem::wpath(filename_).filename() + L"|" - + boost::lexical_cast(fps_) + (is_progressive_ ? L"p" : L"i") +L"|" - + boost::lexical_cast(width_) + L"x" + boost::lexical_cast(height_) + L"]"; + + boost::lexical_cast(width_) + L"x" + boost::lexical_cast(height_) + + (is_progressive_ ? L"p" : L"i") + boost::lexical_cast(fps_) + + L"]"; } }; diff --git a/modules/ffmpeg/producer/util.cpp b/modules/ffmpeg/producer/util.cpp index 4a5782dd7..8e1d26c48 100644 --- a/modules/ffmpeg/producer/util.cpp +++ b/modules/ffmpeg/producer/util.cpp @@ -202,4 +202,74 @@ safe_ptr make_write_frame(const void* tag, const safe_ptr(time_base.den) / static_cast(time_base.num); + return fps > 20.0 && fps < 65.0; +} + +void fix_meta_data(AVFormatContext& context) +{ + auto video_index = av_find_best_stream(&context, AVMEDIA_TYPE_VIDEO, -1, -1, 0, 0); + auto audio_index = av_find_best_stream(&context, AVMEDIA_TYPE_AUDIO, -1, -1, 0, 0); + + if(video_index < 0) + return; + + auto& video_context = *context.streams[video_index]->codec; + auto& video_stream = *context.streams[video_index]; + + if(boost::filesystem2::path(context.filename).extension() == ".flv") + { + try + { + auto meta = read_flv_meta_info(context.filename); + double fps = boost::lexical_cast(meta["framerate"]); + video_context.time_base.num = 1000000; + video_context.time_base.den = static_cast(fps*1000000.0); + video_stream.nb_frames = static_cast(boost::lexical_cast(meta["duration"])*fps); + } + catch(...){} + } + else + { + if(video_stream.nb_frames == 0) + video_stream.nb_frames = video_stream.duration; + + if(!is_sane_fps(video_context.time_base)) + { + if(video_context.time_base.num == 1) + video_context.time_base.num = static_cast(std::pow(10.0, static_cast(std::log10(static_cast(video_context.time_base.den)))-1)); + + if(!is_sane_fps(video_context.time_base) && audio_index > -1) + { + auto& audio_context = *context.streams[audio_index]->codec; + auto& audio_stream = *context.streams[audio_index]; + + double duration_sec = audio_stream.duration / static_cast(audio_context.sample_rate); + + video_context.time_base.num = static_cast(duration_sec*100000.0); + video_context.time_base.den = static_cast(video_stream.nb_frames*100000); + } + } + } + + double fps = static_cast(video_context.time_base.den) / static_cast(video_context.time_base.num); + + double closest_fps = 0.0; + for(int n = 0; n < core::video_format::count; ++n) + { + auto format = core::video_format_desc::get(static_cast(n)); + + double diff1 = std::abs(format.fps - fps); + double diff2 = std::abs(closest_fps - fps); + + if(diff1 < diff2) + closest_fps = format.fps; + } + + video_context.time_base.num = 1000000; + video_context.time_base.den = static_cast(closest_fps*1000000.0); +} + } \ No newline at end of file diff --git a/modules/ffmpeg/producer/util.h b/modules/ffmpeg/producer/util.h index f96117fc7..70b7f2b81 100644 --- a/modules/ffmpeg/producer/util.h +++ b/modules/ffmpeg/producer/util.h @@ -31,4 +31,6 @@ core::pixel_format_desc get_pixel_format_desc(PixelFormat pix_fmt, size_t width int make_alpha_format(int format); // NOTE: Be careful about CASPAR_PIX_FMT_LUMA, change it to PIX_FMT_GRAY8 if you want to use the frame inside some ffmpeg function. safe_ptr make_write_frame(const void* tag, const safe_ptr& decoded_frame, const safe_ptr& frame_factory, int hints); +void fix_meta_data(AVFormatContext& context); + } \ No newline at end of file diff --git a/modules/ffmpeg/producer/video/video_decoder.cpp b/modules/ffmpeg/producer/video/video_decoder.cpp index 4b3e2bcd4..5dba7c2f7 100644 --- a/modules/ffmpeg/producer/video/video_decoder.cpp +++ b/modules/ffmpeg/producer/video/video_decoder.cpp @@ -21,7 +21,6 @@ #include "video_decoder.h" -#include "../format/flv.h" #include "../util.h" #include "../filter/filter.h" @@ -50,7 +49,7 @@ extern "C" #endif namespace caspar { - + struct video_decoder::implementation : boost::noncopyable { const safe_ptr frame_factory_; @@ -88,26 +87,11 @@ public: CASPAR_LOG(debug) << "[video_decoder] " << context->streams[index_]->codec->codec->long_name; // Some files give an invalid time_base numerator, try to fix it. - if(codec_context_ && codec_context_->time_base.num == 1) - codec_context_->time_base.num = static_cast(std::pow(10.0, static_cast(std::log10(static_cast(codec_context_->time_base.den)))-1)); - - if(boost::filesystem2::path(context->filename).extension() == ".flv") - { - try - { - auto meta = read_flv_meta_info(context->filename); - fps_ = boost::lexical_cast(meta["framerate"]); - nb_frames_ = static_cast(boost::lexical_cast(meta["duration"])*fps_); - } - catch(...){} - } - else - { - fps_ = static_cast(codec_context_->time_base.den) / static_cast(codec_context_->time_base.num); - nb_frames_ = context->streams[index_]->nb_frames; - if(nb_frames_ == 0) - nb_frames_ = context->streams[index_]->duration;// * context->streams[index_]->time_base.den; - } + + fix_meta_data(*context); + + fps_ = static_cast(codec_context_->time_base.den) / static_cast(codec_context_->time_base.num); + nb_frames_ = context->streams[index_]->nb_frames; if(double_rate(filter)) fps_ *= 2; -- 2.39.2