From 2ad082d0d6b09aa61b5782bec11ebab17794eaca Mon Sep 17 00:00:00 2001 From: Helge Norberg Date: Tue, 1 Mar 2016 18:31:11 +0100 Subject: [PATCH] Support boost::rational framerates instead of inexact double in ffmpeg::read_framerate() --- modules/ffmpeg/producer/util/util.cpp | 54 ++++++++++--------- modules/ffmpeg/producer/util/util.h | 1 + .../ffmpeg/producer/video/video_decoder.cpp | 10 ++-- modules/ffmpeg/producer/video/video_decoder.h | 2 + 4 files changed, 39 insertions(+), 28 deletions(-) diff --git a/modules/ffmpeg/producer/util/util.cpp b/modules/ffmpeg/producer/util/util.cpp index 0f525d6f0..f8b8894b4 100644 --- a/modules/ffmpeg/producer/util/util.cpp +++ b/modules/ffmpeg/producer/util/util.cpp @@ -360,77 +360,83 @@ AVRational fix_time_base(AVRational time_base) } double read_fps(AVFormatContext& context, double fail_value) -{ +{ + auto framerate = read_framerate(context, boost::rational(static_cast(fail_value * 1000000.0), 1000000)); + + return static_cast(framerate.numerator()) / static_cast(framerate.denominator()); +} + +boost::rational read_framerate(AVFormatContext& context, const boost::rational& fail_value) +{ 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 > -1) + + if (video_index > -1) { const auto video_context = context.streams[video_index]->codec; - const auto video_stream = context.streams[video_index]; + const auto video_stream = context.streams[video_index]; auto frame_rate_time_base = video_stream->avg_frame_rate; std::swap(frame_rate_time_base.num, frame_rate_time_base.den); if (is_sane_fps(frame_rate_time_base)) { - return static_cast(frame_rate_time_base.den) / static_cast(frame_rate_time_base.num); + return boost::rational(frame_rate_time_base.den, frame_rate_time_base.num); } AVRational time_base = video_context->time_base; - if(boost::filesystem::path(context.filename).extension().string() == ".flv") + if (boost::filesystem::path(context.filename).extension().string() == ".flv") { try { auto meta = read_flv_meta_info(context.filename); - return boost::lexical_cast(meta["framerate"]); + return boost::rational(static_cast(boost::lexical_cast(meta["framerate"]) * 1000000.0), 1000000); } - catch(...) + catch (...) { - return 0.0; + return fail_value; } } else { time_base.num *= video_context->ticks_per_frame; - if(!is_sane_fps(time_base)) - { + if (!is_sane_fps(time_base)) + { time_base = fix_time_base(time_base); - if(!is_sane_fps(time_base) && audio_index > -1) + if (!is_sane_fps(time_base) && audio_index > -1) { auto& audio_context = *context.streams[audio_index]->codec; - auto& audio_stream = *context.streams[audio_index]; + auto& audio_stream = *context.streams[audio_index]; double duration_sec = audio_stream.duration / static_cast(audio_context.sample_rate); - + time_base.num = static_cast(duration_sec*100000.0); - time_base.den = static_cast(video_stream->nb_frames*100000); + time_base.den = static_cast(video_stream->nb_frames * 100000); } } } - - double fps = static_cast(time_base.den) / static_cast(time_base.num); - double closest_fps = 0.0; + boost::rational fps(time_base.den, time_base.num); + boost::rational closest_fps(0); for (auto video_mode : enum_constants()) { auto format = core::video_format_desc(core::video_format(video_mode)); - double diff1 = std::abs(format.fps - fps); - double diff2 = std::abs(closest_fps - fps); + auto diff1 = boost::abs(boost::rational(format.time_scale, format.duration) - fps); + auto diff2 = boost::abs(closest_fps - fps); - if(diff1 < diff2) - closest_fps = format.fps; + if (diff1 < diff2) + closest_fps = boost::rational(format.time_scale, format.duration); } - + return closest_fps; } - return fail_value; + return fail_value; } void fix_meta_data(AVFormatContext& context) diff --git a/modules/ffmpeg/producer/util/util.h b/modules/ffmpeg/producer/util/util.h index 9d2f4e458..fd7aebae0 100644 --- a/modules/ffmpeg/producer/util/util.h +++ b/modules/ffmpeg/producer/util/util.h @@ -72,6 +72,7 @@ bool is_sane_fps(AVRational time_base); AVRational fix_time_base(AVRational time_base); double read_fps(AVFormatContext& context, double fail_value); +boost::rational read_framerate(AVFormatContext& context, const boost::rational& fail_value); std::wstring print_mode(int width, int height, double fps, bool interlaced); diff --git a/modules/ffmpeg/producer/video/video_decoder.cpp b/modules/ffmpeg/producer/video/video_decoder.cpp index 2778a5ceb..429f78ff3 100644 --- a/modules/ffmpeg/producer/video/video_decoder.cpp +++ b/modules/ffmpeg/producer/video/video_decoder.cpp @@ -67,7 +67,7 @@ struct video_decoder::impl : boost::noncopyable bool is_progressive_; uint32_t file_frame_number_; - double fps_; + boost::rational framerate_; std::shared_ptr current_packet_; @@ -80,7 +80,7 @@ public: , width_(codec_context_->width) , height_(codec_context_->height) , file_frame_number_(0) - , fps_(read_fps(input_->context(), 0.0)) + , framerate_(read_framerate(input_->context(), 0)) { } @@ -133,8 +133,9 @@ public: if(got_frame == 0) return nullptr; - auto stream_time_base = stream_->time_base; - auto packet_frame_number = static_cast((static_cast(pkt.pts * stream_time_base.num) / stream_time_base.den) * fps_); + auto stream_time_base = stream_->time_base; + auto fps = static_cast(framerate_.numerator()) / static_cast(framerate_.denominator()); + auto packet_frame_number = static_cast((static_cast(pkt.pts * stream_time_base.num) / stream_time_base.den) * fps); file_frame_number_ = packet_frame_number; @@ -170,6 +171,7 @@ int video_decoder::width() const{return impl_->width_;} int video_decoder::height() const{return impl_->height_;} uint32_t video_decoder::nb_frames() const{return impl_->nb_frames();} uint32_t video_decoder::file_frame_number() const{return impl_->file_frame_number_;} +boost::rational video_decoder::framerate() const { return impl_->framerate_; } bool video_decoder::is_progressive() const{return impl_->is_progressive_;} std::wstring video_decoder::print() const{return impl_->print();} core::monitor::subject& video_decoder::monitor_output() { return impl_->monitor_subject_; } diff --git a/modules/ffmpeg/producer/video/video_decoder.h b/modules/ffmpeg/producer/video/video_decoder.h index f5768f675..5cc1aea1d 100644 --- a/modules/ffmpeg/producer/video/video_decoder.h +++ b/modules/ffmpeg/producer/video/video_decoder.h @@ -27,6 +27,7 @@ #include #include +#include struct AVFormatContext; struct AVFrame; @@ -48,6 +49,7 @@ public: int height() const; bool is_progressive() const; uint32_t file_frame_number() const; + boost::rational framerate() const; uint32_t nb_frames() const; -- 2.39.2