]> git.sesse.net Git - casparcg/commitdiff
Support boost::rational framerates instead of inexact double in ffmpeg::read_framerate()
authorHelge Norberg <helge.norberg@svt.se>
Tue, 1 Mar 2016 17:31:11 +0000 (18:31 +0100)
committerHelge Norberg <helge.norberg@svt.se>
Tue, 1 Mar 2016 17:31:11 +0000 (18:31 +0100)
modules/ffmpeg/producer/util/util.cpp
modules/ffmpeg/producer/util/util.h
modules/ffmpeg/producer/video/video_decoder.cpp
modules/ffmpeg/producer/video/video_decoder.h

index 0f525d6f02f5649981b17d031bc1c9c4380f98d2..f8b8894b436ea0a261da9d0d45200b3487241e3f 100644 (file)
@@ -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<int>(static_cast<int>(fail_value * 1000000.0), 1000000));
+       
+       return static_cast<double>(framerate.numerator()) / static_cast<double>(framerate.denominator());
+}
+
+boost::rational<int> read_framerate(AVFormatContext& context, const boost::rational<int>& 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<double>(frame_rate_time_base.den) / static_cast<double>(frame_rate_time_base.num);
+                       return boost::rational<int>(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<double>(meta["framerate"]);
+                               return boost::rational<int>(static_cast<int>(boost::lexical_cast<double>(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<double>(audio_context.sample_rate);
-                                                               
+
                                        time_base.num = static_cast<int>(duration_sec*100000.0);
-                                       time_base.den = static_cast<int>(video_stream->nb_frames*100000);
+                                       time_base.den = static_cast<int>(video_stream->nb_frames * 100000);
                                }
                        }
                }
-               
-               double fps = static_cast<double>(time_base.den) / static_cast<double>(time_base.num);
 
-               double closest_fps = 0.0;
+               boost::rational<int> fps(time_base.den, time_base.num);
+               boost::rational<int> closest_fps(0);
 
                for (auto video_mode : enum_constants<core::video_format>())
                {
                        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<int>(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<int>(format.time_scale, format.duration);
                }
-       
+
                return closest_fps;
        }
 
-       return fail_value;      
+       return fail_value;
 }
 
 void fix_meta_data(AVFormatContext& context)
index 9d2f4e4587ec22bc9f3e15a328198c0a60b9f840..fd7aebae0ec58ad4e50797936d835a1ce7a261ca 100644 (file)
@@ -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<int> read_framerate(AVFormatContext& context, const boost::rational<int>& fail_value);
 
 std::wstring print_mode(int width, int height, double fps, bool interlaced);
 
index 2778a5cebe08b9646d766a52263280f55c9884b4..429f78ff31c3c91ca94cb796fb856be0bc59f0e4 100644 (file)
@@ -67,7 +67,7 @@ struct video_decoder::impl : boost::noncopyable
 
        bool                                                                    is_progressive_;
        uint32_t                                                                file_frame_number_;
-       double                                                                  fps_;
+       boost::rational<int>                                    framerate_;
        
        std::shared_ptr<AVPacket>                               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<uint32_t>((static_cast<double>(pkt.pts * stream_time_base.num) / stream_time_base.den) * fps_);
+               auto stream_time_base           = stream_->time_base;
+               auto fps = static_cast<double>(framerate_.numerator()) / static_cast<double>(framerate_.denominator());
+               auto packet_frame_number        = static_cast<uint32_t>((static_cast<double>(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<int> 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_; }
index f5768f675702be6bfe0a76a25159db2be8a6df76..5cc1aea1dcca1ab2867ee8bc5553e328003049a8 100644 (file)
@@ -27,6 +27,7 @@
 #include <core/monitor/monitor.h>
 
 #include <boost/noncopyable.hpp>
+#include <boost/rational.hpp>
 
 struct AVFormatContext;
 struct AVFrame;
@@ -48,6 +49,7 @@ public:
        int      height() const;
        bool is_progressive() const;
        uint32_t file_frame_number() const;
+       boost::rational<int> framerate() const;
 
        uint32_t nb_frames() const;