]> git.sesse.net Git - casparcg/commitdiff
2.1: -ffmpeg_producer: Improved seeking.
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Sun, 18 Mar 2012 12:12:00 +0000 (12:12 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Sun, 18 Mar 2012 12:12:00 +0000 (12:12 +0000)
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.1.0@2655 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

modules/decklink/producer/decklink_producer.cpp
modules/ffmpeg/producer/audio/audio_decoder.cpp
modules/ffmpeg/producer/ffmpeg_producer.cpp
modules/ffmpeg/producer/input/input.cpp
modules/ffmpeg/producer/muxer/frame_muxer.cpp
modules/ffmpeg/producer/muxer/frame_muxer.h
modules/ffmpeg/producer/video/video_decoder.cpp

index 886b71014598b9c88598de805ef5c43ff3e6a856..e10a45939cb92cfd22360bb14aca8fcbbf9cc642 100644 (file)
@@ -247,8 +247,11 @@ public:
                        // POLL\r
 \r
                        auto frame = core::draw_frame::late();\r
-                       if(muxer_.try_pop(frame))\r
+                       if(!muxer_.empty())\r
                        {\r
+                               frame = std::move(muxer_.front());\r
+                               muxer_.pop();\r
+\r
                                if(!frame_buffer_.try_push(frame))\r
                                {\r
                                        auto dummy = core::draw_frame::empty();\r
index 60cdf0b79c5efd1f34de70ebb4e69aef795fbf2c..2b350f9f3672ca2e76687dcd042cf995405f9b3e 100644 (file)
@@ -65,12 +65,12 @@ struct audio_decoder::impl : boost::noncopyable
        std::queue<spl::shared_ptr<AVPacket>>                                           packets_;\r
 \r
        const int64_t                                                                                           nb_frames_;\r
-       tbb::atomic<uint32_t>                                                                           file_frame_number_;\r
+       uint32_t                                                                                                        file_frame_number_;\r
 public:\r
        explicit impl() \r
                : nb_frames_(0)//context->streams[index_]->nb_frames)\r
+               , file_frame_number_(0)\r
        {               \r
-               file_frame_number_ = 0;   \r
        }\r
 \r
        explicit impl(const std::shared_ptr<AVFormatContext>& context, const core::video_format_desc& format_desc) \r
@@ -111,7 +111,7 @@ public:
                        if(packet->data == nullptr)\r
                        {\r
                                packets_.pop();\r
-                               file_frame_number_ = static_cast<uint32_t>(packet->pos);\r
+                               file_frame_number_ = static_cast<uint32_t>(packet->pts);\r
                                avcodec_flush_buffers(codec_context_.get());\r
                                return flush_audio();\r
                        }\r
@@ -147,9 +147,9 @@ public:
                                                << monitor::event("file/audio/channels")        % codec_context_->channels\r
                                                << monitor::event("file/audio/format")          % u8(av_get_sample_fmt_name(codec_context_->sample_fmt))\r
                                                << monitor::event("file/audio/codec")           % u8(codec_context_->codec->long_name);\r
-\r
-               ++file_frame_number_;\r
-\r
+               \r
+               file_frame_number_ = static_cast<uint32_t>(pkt.pts);\r
+               \r
                return std::make_shared<core::audio_buffer>(samples, samples + n_samples);\r
        }\r
 \r
index c9edc72eecf84185262d8ce88ecbf559ded1800f..6d47065197377fe0f500823d8a6777260339c2b6 100644 (file)
@@ -155,10 +155,16 @@ public:
                        return last_frame();\r
 \r
                boost::timer frame_timer;\r
-                               \r
-               auto frame = core::draw_frame::late();          \r
+                                               \r
+               decode_next_frame();\r
                \r
-               if(!try_decode_frame(frame))\r
+               auto frame = core::draw_frame::late();          \r
+               if(!muxer_.empty())\r
+               {\r
+                       frame = std::move(muxer_.front());\r
+                       muxer_.pop();\r
+               }\r
+               else\r
                {\r
                        if(!input_.eof())               \r
                                graph_->set_tag("underflow");   \r
@@ -349,19 +355,19 @@ public:
                video_decoder_.clear();\r
                audio_decoder_.clear();\r
                        \r
+               target = std::min(target, file_nb_frames()-3);\r
+\r
                input_.seek(target);\r
                                \r
-               auto frame = core::draw_frame::late();          \r
+               decode_next_frame();\r
+\r
+               for(int n = 0; n < 50 && video_decoder_.file_frame_number() != target+2 && !muxer_.empty(); ++n) // TODO: +2 since a frame can be stuck inside yadif filter.\r
+               {\r
+                       muxer_.pop();\r
+                       decode_next_frame();\r
+               }\r
                \r
-               // TODO\r
-               try_decode_frame(frame);\r
-               try_decode_frame(frame);\r
-               try_decode_frame(frame);\r
-               try_decode_frame(frame);\r
-               try_decode_frame(frame);\r
-\r
-               if(frame != core::draw_frame::late())\r
-                       last_frame_ = frame;\r
+               last_frame_ = !muxer_.empty() ? muxer_.front() : last_frame_;                   \r
        }\r
 \r
        std::wstring print_mode() const\r
@@ -369,13 +375,10 @@ public:
                return ffmpeg::print_mode(video_decoder_.width(), video_decoder_.height(), fps_, !video_decoder_.is_progressive());\r
        }\r
                        \r
-       bool try_decode_frame(core::draw_frame& result)\r
+       void decode_next_frame()\r
        {\r
-               for(int n = 0; n < 32; ++n)\r
+               for(int n = 0; n < 64 && muxer_.empty(); ++n)\r
                {\r
-                       if(muxer_.try_pop(result))                      \r
-                               return true;                    \r
-\r
                        std::shared_ptr<AVPacket> pkt;\r
                        for(int n = 0; n < 32 && (!video_decoder_.ready() || !audio_decoder_.ready()) && input_.try_pop(pkt); ++n)\r
                        {\r
@@ -403,8 +406,6 @@ public:
                        muxer_.push(video);\r
                        muxer_.push(audio);\r
                }\r
-\r
-               return false;\r
        }\r
 };\r
 \r
index 1fbbbdf412e5d61e767b22f28b0755593eadc25c..3de1ec4fe1552b5069e35e96f318807e31004089 100644 (file)
@@ -75,6 +75,7 @@ struct input::impl : boost::noncopyable
        tbb::atomic<bool>                                                                                       loop_;\r
        tbb::atomic<bool>                                                                                       eof_;\r
        uint32_t                                                                                                        frame_number_;\r
+       double                                                                                                          fps_;\r
        \r
        tbb::concurrent_bounded_queue<std::shared_ptr<AVPacket>>        buffer_;\r
        tbb::atomic<size_t>                                                                                     buffer_size_;\r
@@ -87,6 +88,7 @@ struct input::impl : boost::noncopyable
                , default_stream_index_(av_find_default_stream_index(format_context_.get()))\r
                , filename_(filename)\r
                , frame_number_(0)\r
+               , fps_(read_fps(*format_context_, 25))\r
                , executor_(print())\r
        {               \r
                start_                  = start;\r
@@ -152,12 +154,12 @@ struct input::impl : boost::noncopyable
                        auto codec  = stream->codec;\r
                        auto fixed_target = (target*stream->time_base.den*codec->time_base.num)/(stream->time_base.num*codec->time_base.den)*codec->ticks_per_frame;\r
                \r
-                       THROW_ON_ERROR2(avformat_seek_file(format_context_.get(), default_stream_index_, std::numeric_limits<int64_t>::min(), fixed_target, std::numeric_limits<int64_t>::max(), 0), print());          \r
+                       THROW_ON_ERROR2(avformat_seek_file(format_context_.get(), default_stream_index_, std::numeric_limits<int64_t>::min(), fixed_target, fixed_target, 0), print());         \r
                \r
                        auto flush_packet       = create_packet();\r
                        flush_packet->data      = nullptr;\r
                        flush_packet->size      = 0;\r
-                       flush_packet->pos       = target;\r
+                       flush_packet->pts       = target;\r
 \r
                        buffer_.push(flush_packet);\r
                        \r
@@ -225,6 +227,11 @@ struct input::impl : boost::noncopyable
                                                packet->data = data;                            \r
                                        });\r
 \r
+                                       auto time_base = format_context_->streams[packet->stream_index]->time_base;\r
+                                       packet->pts = static_cast<uint64_t>((static_cast<double>(packet->pts * time_base.num)/time_base.den)*fps_);\r
+\r
+                                       CASPAR_LOG(trace) << packet->pts;\r
+\r
                                        buffer_.try_push(packet);\r
                                        buffer_size_ += packet->size;\r
                                \r
index 48bc3b479a28cd19a2836b18d8ab07597a4ce419..986d69b5ce3b741afce3e4de741239a45355a3ab 100644 (file)
@@ -100,10 +100,13 @@ struct frame_muxer::impl : boost::noncopyable
        void push(const std::shared_ptr<AVFrame>& video_frame)\r
        {               \r
                if(!video_frame)\r
+               {\r
+                       merge();\r
                        return;\r
-               \r
+               }\r
+\r
                if(video_frame == flush_video())                \r
-                       video_streams_.push(std::queue<core::mutable_frame>());         \r
+                       video_streams_.push(std::queue<core::mutable_frame>());                         \r
                else if(video_frame == empty_video())\r
                {\r
                        auto empty_frame = frame_factory_->create_frame(this, core::pixel_format_desc(core::pixel_format::invalid));\r
@@ -122,15 +125,20 @@ struct frame_muxer::impl : boost::noncopyable
 \r
                if(video_streams_.back().size() > 32)\r
                        BOOST_THROW_EXCEPTION(invalid_operation() << source_info("frame_muxer") << msg_info("video-stream overflow. This can be caused by incorrect frame-rate. Check clip meta-data."));\r
+               \r
+               merge();\r
        }\r
 \r
        void push(const std::shared_ptr<core::audio_buffer>& audio)\r
        {\r
-               if(!audio)      \r
+               if(!audio)\r
+               {\r
+                       merge();\r
                        return;\r
+               }\r
 \r
-               if(audio == flush_audio())              \r
-                       audio_streams_.push(core::audio_buffer());              \r
+               if(audio == flush_audio())                      \r
+                       audio_streams_.push(core::audio_buffer());                              \r
                else if(audio == empty_audio())         \r
                        boost::range::push_back(audio_streams_.back(), core::audio_buffer(audio_cadence_.front(), 0));          \r
                else            \r
@@ -138,6 +146,8 @@ struct frame_muxer::impl : boost::noncopyable
 \r
                if(audio_streams_.back().size() > static_cast<size_t>(32*audio_cadence_.front()))\r
                        BOOST_THROW_EXCEPTION(invalid_operation() << source_info("frame_muxer") << msg_info("audio-stream overflow. This can be caused by incorrect frame-rate. Check clip meta-data."));\r
+\r
+               merge();\r
        }\r
        \r
        bool video_ready() const\r
@@ -173,16 +183,24 @@ struct frame_muxer::impl : boost::noncopyable
                        return audio_streams_.front().size() >= static_cast<size_t>(audio_cadence_.front());\r
                }\r
        }\r
-               \r
-       bool try_pop(core::draw_frame& result)\r
+\r
+       bool empty() const\r
        {\r
-               if(!frame_buffer_.empty())\r
-               {\r
-                       result = std::move(frame_buffer_.front());\r
-                       frame_buffer_.pop();    \r
-                       return true;\r
-               }\r
+               return frame_buffer_.empty();\r
+       }\r
+\r
+       core::draw_frame front() const\r
+       {\r
+               return frame_buffer_.front();\r
+       }\r
 \r
+       void pop()\r
+       {\r
+               frame_buffer_.pop();\r
+       }\r
+               \r
+       void merge()\r
+       {\r
                if(video_streams_.size() > 1 && audio_streams_.size() > 1 && (!video_ready2() || !audio_ready2()))\r
                {\r
                        if(!video_streams_.front().empty() || !audio_streams_.front().empty())\r
@@ -193,7 +211,7 @@ struct frame_muxer::impl : boost::noncopyable
                }\r
 \r
                if(!video_ready2() || !audio_ready2() || display_mode_ == display_mode::invalid)\r
-                       return false;\r
+                       return;\r
                                \r
                auto frame1                             = pop_video();\r
                frame1.audio_data()     = pop_audio();\r
@@ -237,8 +255,6 @@ struct frame_muxer::impl : boost::noncopyable
                default:\r
                        BOOST_THROW_EXCEPTION(invalid_operation());\r
                }\r
-               \r
-               return try_pop(result);\r
        }\r
        \r
        core::mutable_frame pop_video()\r
@@ -349,7 +365,9 @@ frame_muxer::frame_muxer(double in_fps, const spl::shared_ptr<core::frame_factor
        : impl_(new impl(in_fps, frame_factory, format_desc, filter)){}\r
 void frame_muxer::push(const std::shared_ptr<AVFrame>& video_frame){impl_->push(video_frame);}\r
 void frame_muxer::push(const std::shared_ptr<core::audio_buffer>& audio_samples){return impl_->push(audio_samples);}\r
-bool frame_muxer::try_pop(core::draw_frame& result){return impl_->try_pop(result);}\r
+bool frame_muxer::empty() const{return impl_->empty();}\r
+core::draw_frame frame_muxer::front() const{return impl_->front();}\r
+void frame_muxer::pop(){return impl_->pop();}\r
 void frame_muxer::clear(){impl_->clear();}\r
 uint32_t frame_muxer::calc_nb_frames(uint32_t nb_frames) const {return impl_->calc_nb_frames(nb_frames);}\r
 bool frame_muxer::video_ready() const{return impl_->video_ready();}\r
index b5943d7bed11130c2c65765a512c4c2185d2c55c..faec16ff6bffb62fc7ec750ab227a5c629bdac25 100644 (file)
@@ -54,7 +54,10 @@ public:
        bool audio_ready() const;\r
 \r
        void clear();\r
-       bool try_pop(core::draw_frame& result);\r
+\r
+       bool empty() const;\r
+       core::draw_frame front() const;\r
+       void pop();\r
 \r
        uint32_t calc_nb_frames(uint32_t nb_frames) const;\r
 private:\r
index 620b62dc2d75144f61037be9f4d59b6d484a50e9..d5ffe1abc873a06e66d53fba329762e090cf9c31 100644 (file)
@@ -65,7 +65,7 @@ struct video_decoder::impl : boost::noncopyable
        const int                                                               height_;\r
        bool                                                                    is_progressive_;\r
 \r
-       tbb::atomic<uint32_t>                                   file_frame_number_;\r
+       uint32_t                                                                file_frame_number_;\r
 \r
 public:\r
        explicit impl() \r
@@ -73,8 +73,8 @@ public:
                , width_(0)\r
                , height_(0)\r
                , is_progressive_(true)\r
+               , file_frame_number_(0)\r
        {\r
-               file_frame_number_ = 0;\r
        }\r
 \r
        explicit impl(const spl::shared_ptr<AVFormatContext>& context) \r
@@ -119,8 +119,9 @@ public:
                                }\r
                                        \r
                                packets_.pop();\r
-                               file_frame_number_ = static_cast<uint32_t>(packet->pos);\r
+                               file_frame_number_ = static_cast<uint32_t>(packet->pts);\r
                                avcodec_flush_buffers(codec_context_.get());\r
+                               \r
                                return flush_video();   \r
                        }\r
                        \r
@@ -153,8 +154,10 @@ public:
                                                << monitor::event("file/video/height")  % height_\r
                                                << monitor::event("file/video/field")   % u8(!decoded_frame->interlaced_frame ? "progressive" : (decoded_frame->top_field_first ? "upper" : "lower"))\r
                                                << monitor::event("file/video/codec")   % u8(codec_context_->codec->long_name);\r
+               \r
+               file_frame_number_ = static_cast<uint32_t>(pkt.pts);\r
 \r
-               ++file_frame_number_;\r
+               decoded_frame->pts = file_frame_number_;\r
 \r
                return decoded_frame;\r
        }\r