]> git.sesse.net Git - casparcg/commitdiff
2.0. ffmpeg_producer: Refactored meta data fix.
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Fri, 19 Aug 2011 08:22:48 +0000 (08:22 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Fri, 19 Aug 2011 08:22:48 +0000 (08:22 +0000)
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@1222 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

modules/ffmpeg/producer/audio/audio_decoder.cpp
modules/ffmpeg/producer/audio/audio_decoder.h
modules/ffmpeg/producer/ffmpeg_producer.cpp
modules/ffmpeg/producer/util.cpp
modules/ffmpeg/producer/util.h
modules/ffmpeg/producer/video/video_decoder.cpp

index 00848a1696d05eeb1ecfa598255597c99120aa1d..ae9ef01c45b33e6e59e0c95cc279c706162442ab 100644 (file)
@@ -57,12 +57,10 @@ struct audio_decoder::implementation : boost::noncopyable
        std::queue<std::shared_ptr<AVPacket>>                                           packets_;\r
 \r
        int64_t                                                                                                         nb_frames_;\r
-       double                                                                                                          duration_;\r
 public:\r
        explicit implementation(const safe_ptr<AVFormatContext>& context, const core::video_format_desc& format_desc) \r
                : format_desc_(format_desc)     \r
                , nb_frames_(0)\r
-               , duration_(std::numeric_limits<double>::max())\r
        {                               \r
                try\r
                {\r
@@ -75,11 +73,6 @@ public:
 \r
                        buffer1_.resize(AVCODEC_MAX_AUDIO_FRAME_SIZE*2);\r
 \r
-                       //nb_frames_ = context->streams[index_]->nb_frames;\r
-                       //if(nb_frames_ == 0)\r
-                       //      nb_frames_ = context->streams[index_]->duration / (codec_context_->channels*codec_context_->sample_rate);\r
-                       duration_ = context->streams[index_]->duration / static_cast<double>(codec_context_->sample_rate);\r
-\r
                        if(codec_context_->sample_rate  != static_cast<int>(format_desc_.audio_sample_rate) || \r
                           codec_context_->channels             != static_cast<int>(format_desc_.audio_channels) ||\r
                           codec_context_->sample_fmt   != AV_SAMPLE_FMT_S16)\r
@@ -195,5 +188,4 @@ void audio_decoder::push(const std::shared_ptr<AVPacket>& packet){impl_->push(pa
 bool audio_decoder::ready() const{return impl_->ready();}\r
 std::vector<std::shared_ptr<std::vector<int16_t>>> audio_decoder::poll(){return impl_->poll();}\r
 int64_t audio_decoder::nb_frames() const{return impl_->nb_frames_;}\r
-double audio_decoder::duration() const {return impl_->duration_;}\r
 }
\ No newline at end of file
index b48b39c006f054d1653b02b8a72e03123192e6f8..2ef82eaabe339a55049b879fb97ee6dcabe0d296 100644 (file)
@@ -46,7 +46,6 @@ public:
        std::vector<std::shared_ptr<std::vector<int16_t>>> poll();\r
 \r
        int64_t nb_frames() const;\r
-       double duration() const;\r
 \r
 private:\r
        struct implementation;\r
index 97d95dd17866c5df3c81efe113e32062fab8b86d..d6ec0d8994eeb82a6c2a708d1666a23a585b6cbc 100644 (file)
 #include <tbb/parallel_invoke.h>\r
 \r
 namespace caspar {\r
-\r
-double validate_fps(double fps, int64_t nb_frames, double duration_sec)\r
-{\r
-       if(fps > 20.0 && fps < 80.0)\r
-               return fps;\r
-       \r
-       auto est_fps = nb_frames/duration_sec;\r
-\r
-       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.";\r
-\r
-       return est_fps;\r
-}\r
-                       \r
+                               \r
 struct ffmpeg_producer : public core::frame_producer\r
 {\r
        const std::wstring                                                              filename_;\r
@@ -97,7 +85,7 @@ public:
                , input_(graph_, filename_, loop, start, length)\r
                , video_decoder_(input_.context(), frame_factory, filter)\r
                , audio_decoder_(input_.context(), frame_factory->get_video_format_desc())\r
-               , fps_(validate_fps(video_decoder_.fps(), video_decoder_.nb_frames(), audio_decoder_.duration()))\r
+               , fps_(video_decoder_.fps())\r
                , muxer_(fps_, frame_factory)\r
                , late_frames_(0)\r
                , start_(start)\r
@@ -212,8 +200,9 @@ public:
        virtual std::wstring print() const\r
        {\r
                return L"ffmpeg[" + boost::filesystem::wpath(filename_).filename() + L"|" \r
-                                                 + boost::lexical_cast<std::wstring>(fps_) + (is_progressive_ ? L"p" : L"i") +L"|"\r
-                                                 + boost::lexical_cast<std::wstring>(width_) + L"x" + boost::lexical_cast<std::wstring>(height_) + L"]";\r
+                                                 + boost::lexical_cast<std::wstring>(width_) + L"x" + boost::lexical_cast<std::wstring>(height_)\r
+                                                 + (is_progressive_ ? L"p" : L"i")  + boost::lexical_cast<std::wstring>(fps_)\r
+                                                 + L"]";\r
        }\r
 };\r
 \r
index 4a5782dd7df274dc3eba1da7f9104121947d2d8b..8e1d26c48effc3ca49286dacb306395a0eaaf592 100644 (file)
@@ -202,4 +202,74 @@ safe_ptr<core::write_frame> make_write_frame(const void* tag, const safe_ptr<AVF
        }\r
 }\r
 \r
+bool is_sane_fps(AVRational time_base)\r
+{\r
+       double fps = static_cast<double>(time_base.den) / static_cast<double>(time_base.num);\r
+       return fps > 20.0 && fps < 65.0;\r
+}\r
+\r
+void fix_meta_data(AVFormatContext& context)\r
+{\r
+       auto video_index = av_find_best_stream(&context, AVMEDIA_TYPE_VIDEO, -1, -1, 0, 0);\r
+       auto audio_index = av_find_best_stream(&context, AVMEDIA_TYPE_AUDIO, -1, -1, 0, 0);\r
+\r
+       if(video_index < 0)\r
+               return;\r
+\r
+       auto& video_context = *context.streams[video_index]->codec;\r
+       auto& video_stream  = *context.streams[video_index];\r
+                                               \r
+       if(boost::filesystem2::path(context.filename).extension() == ".flv")\r
+       {\r
+               try\r
+               {\r
+                       auto meta = read_flv_meta_info(context.filename);\r
+                       double fps = boost::lexical_cast<double>(meta["framerate"]);\r
+                       video_context.time_base.num = 1000000;\r
+                       video_context.time_base.den = static_cast<int>(fps*1000000.0);\r
+                       video_stream.nb_frames = static_cast<int64_t>(boost::lexical_cast<double>(meta["duration"])*fps);\r
+               }\r
+               catch(...){}\r
+       }\r
+       else\r
+       {\r
+               if(video_stream.nb_frames == 0)\r
+                       video_stream.nb_frames = video_stream.duration;\r
+\r
+               if(!is_sane_fps(video_context.time_base))\r
+               {                       \r
+                       if(video_context.time_base.num == 1)\r
+                               video_context.time_base.num = static_cast<int>(std::pow(10.0, static_cast<int>(std::log10(static_cast<float>(video_context.time_base.den)))-1));        \r
+\r
+                       if(!is_sane_fps(video_context.time_base) && audio_index > -1)\r
+                       {\r
+                               auto& audio_context = *context.streams[audio_index]->codec;\r
+                               auto& audio_stream  = *context.streams[audio_index];\r
+\r
+                               double duration_sec = audio_stream.duration / static_cast<double>(audio_context.sample_rate);\r
+                                                               \r
+                               video_context.time_base.num = static_cast<int>(duration_sec*100000.0);\r
+                               video_context.time_base.den = static_cast<int>(video_stream.nb_frames*100000);\r
+                       }\r
+               }\r
+       }\r
+\r
+       double fps = static_cast<double>(video_context.time_base.den) / static_cast<double>(video_context.time_base.num);\r
+\r
+       double closest_fps = 0.0;\r
+       for(int n = 0; n < core::video_format::count; ++n)\r
+       {\r
+               auto format = core::video_format_desc::get(static_cast<core::video_format::type>(n));\r
+\r
+               double diff1 = std::abs(format.fps - fps);\r
+               double diff2 = std::abs(closest_fps - fps);\r
+\r
+               if(diff1 < diff2)\r
+                       closest_fps = format.fps;\r
+       }\r
+       \r
+       video_context.time_base.num = 1000000;\r
+       video_context.time_base.den = static_cast<int>(closest_fps*1000000.0);\r
+}\r
+\r
 }
\ No newline at end of file
index f96117fc703a8b831b554b6a86384a05d2070c0b..70b7f2b81e2f258b8e6c27b960dd5d20f1e0e056 100644 (file)
@@ -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.\r
 safe_ptr<core::write_frame> make_write_frame(const void* tag, const safe_ptr<AVFrame>& decoded_frame, const safe_ptr<core::frame_factory>& frame_factory, int hints);\r
 \r
+void fix_meta_data(AVFormatContext& context);\r
+\r
 }
\ No newline at end of file
index 4b3e2bcd4229525abedc79820886973ee53e5356..5dba7c2f7a98d9cd2e49dd333bbc9801a84740de 100644 (file)
@@ -21,7 +21,6 @@
 \r
 #include "video_decoder.h"\r
 \r
-#include "../format/flv.h"\r
 #include "../util.h"\r
 #include "../filter/filter.h"\r
 \r
@@ -50,7 +49,7 @@ extern "C"
 #endif\r
 \r
 namespace caspar {\r
-               \r
+       \r
 struct video_decoder::implementation : boost::noncopyable\r
 {\r
        const safe_ptr<core::frame_factory>             frame_factory_;\r
@@ -88,26 +87,11 @@ public:
                        CASPAR_LOG(debug) << "[video_decoder] " << context->streams[index_]->codec->codec->long_name;\r
 \r
                        // Some files give an invalid time_base numerator, try to fix it.\r
-                       if(codec_context_ && codec_context_->time_base.num == 1)\r
-                               codec_context_->time_base.num = static_cast<int>(std::pow(10.0, static_cast<int>(std::log10(static_cast<float>(codec_context_->time_base.den)))-1));    \r
-                                       \r
-                       if(boost::filesystem2::path(context->filename).extension() == ".flv")\r
-                       {\r
-                               try\r
-                               {\r
-                                       auto meta = read_flv_meta_info(context->filename);\r
-                                       fps_ = boost::lexical_cast<double>(meta["framerate"]);\r
-                                       nb_frames_ = static_cast<int64_t>(boost::lexical_cast<double>(meta["duration"])*fps_);\r
-                               }\r
-                               catch(...){}\r
-                       }\r
-                       else\r
-                       {\r
-                               fps_ = static_cast<double>(codec_context_->time_base.den) / static_cast<double>(codec_context_->time_base.num);\r
-                               nb_frames_ = context->streams[index_]->nb_frames;\r
-                               if(nb_frames_ == 0)\r
-                                       nb_frames_ = context->streams[index_]->duration;// * context->streams[index_]->time_base.den;\r
-                       }\r
+\r
+                       fix_meta_data(*context);\r
+                       \r
+                       fps_ = static_cast<double>(codec_context_->time_base.den) / static_cast<double>(codec_context_->time_base.num);\r
+                       nb_frames_ = context->streams[index_]->nb_frames;\r
 \r
                        if(double_rate(filter))\r
                                fps_ *= 2;\r