]> git.sesse.net Git - casparcg/blobdiff - modules/ffmpeg/producer/video/video_decoder.cpp
2.0.1: ffmpeg: Replaced TBB implementation with better Concurrency Runtime based...
[casparcg] / modules / ffmpeg / producer / video / video_decoder.cpp
index 4e2ba9664fb22d640905e8b52af3b6ac04de1e31..cc0eaaef0d5303b0cd06cc3efd427af4488c442c 100644 (file)
 #include "../../ffmpeg_error.h"\r
 #include "../../tbb_avcodec.h"\r
 \r
-#include <core/producer/frame/frame_transform.h>\r
-#include <core/producer/frame/frame_factory.h>\r
-\r
-#include <boost/range/algorithm_ext/push_back.hpp>\r
-#include <boost/filesystem.hpp>\r
-\r
-#include <queue>\r
+#include <core/producer/frame/basic_frame.h>\r
 \r
 #if defined(_MSC_VER)\r
 #pragma warning (push)\r
@@ -50,14 +44,15 @@ extern "C"
 \r
 namespace caspar { namespace ffmpeg {\r
        \r
-struct video_decoder::implementation : boost::noncopyable\r
+struct video_decoder::implementation : public Concurrency::agent, boost::noncopyable\r
 {\r
-       const safe_ptr<core::frame_factory>             frame_factory_;\r
+       video_decoder::token_t&                                 active_token_;\r
+       video_decoder::source_t&                                source_;\r
+       video_decoder::target_t&                                target_;\r
+\r
        std::shared_ptr<AVCodecContext>                 codec_context_;\r
        int                                                                             index_;\r
 \r
-       std::queue<std::shared_ptr<AVPacket>>   packets_;\r
-\r
        filter                                                                  filter_;\r
 \r
        double                                                                  fps_;\r
@@ -65,15 +60,24 @@ struct video_decoder::implementation : boost::noncopyable
 \r
        size_t                                                                  width_;\r
        size_t                                                                  height_;\r
+       bool                                                                    is_progressive_;\r
 \r
 public:\r
-       explicit implementation(const safe_ptr<AVFormatContext>& context, const safe_ptr<core::frame_factory>& frame_factory, const std::wstring& filter) \r
-               : frame_factory_(frame_factory)\r
-               , filter_(filter)\r
-               , fps_(frame_factory_->get_video_format_desc().fps)\r
+       explicit implementation(video_decoder::token_t& active_token,\r
+                                                       video_decoder::source_t& source,\r
+                                                       video_decoder::target_t& target,\r
+                                                       const safe_ptr<AVFormatContext>& context,\r
+                                                       double fps,\r
+                                                       const std::wstring& filter) \r
+               : active_token_(active_token)\r
+               , source_(source)\r
+               , target_(target)\r
+               , filter_(filter.empty() ? L"copy" : filter)\r
+               , fps_(fps)\r
                , nb_frames_(0)\r
                , width_(0)\r
                , height_(0)\r
+               , is_progressive_(true)\r
        {\r
                try\r
                {\r
@@ -106,72 +110,77 @@ public:
                        CASPAR_LOG_CURRENT_EXCEPTION();\r
                        CASPAR_LOG(warning) << "[video_decoder] Failed to open video-stream. Running without video.";   \r
                }\r
-       }\r
 \r
-       void push(const std::shared_ptr<AVPacket>& packet)\r
+               start();\r
+       }\r
+       \r
+       ~implementation()\r
        {\r
-               if(packet && packet->stream_index != index_)\r
-                       return;\r
-\r
-               packets_.push(packet);\r
+               agent::wait(this);\r
        }\r
-\r
-       std::vector<std::shared_ptr<AVFrame>> poll()\r
-       {               \r
-               std::vector<std::shared_ptr<AVFrame>> result;\r
-\r
-               if(packets_.empty())\r
-                       return result;\r
-\r
-               if(!codec_context_)\r
-                       return empty_poll();\r
-\r
-               auto packet = packets_.front();\r
-                                       \r
-               if(packet)\r
-               {                       \r
-                       BOOST_FOREACH(auto& frame, decode(*packet))\r
-                               boost::range::push_back(result, filter_.execute(frame));\r
-\r
-                       if(packet->size == 0)\r
-                               packets_.pop();\r
-               }\r
-               else\r
+       \r
+       virtual void run()\r
+       {\r
+               try\r
                {\r
-                       if(codec_context_->codec->capabilities & CODEC_CAP_DELAY)\r
+                       while(Concurrency::receive(active_token_))\r
                        {\r
-                               AVPacket pkt;\r
-                               av_init_packet(&pkt);\r
-                               pkt.data = nullptr;\r
-                               pkt.size = 0;\r
-\r
-                               BOOST_FOREACH(auto& frame, decode(pkt))\r
-                                       boost::range::push_back(result, filter_.execute(frame));        \r
-                       }\r
-\r
-                       if(result.empty())\r
-                       {                                       \r
-                               packets_.pop();\r
-                               avcodec_flush_buffers(codec_context_.get());\r
-                               result.push_back(nullptr);\r
+                               auto packet = Concurrency::receive(source_);\r
+                               if(packet == eof_packet())\r
+                               {\r
+                                       Concurrency::send(target_, eof_video());\r
+                                       break;\r
+                               }\r
+\r
+                               if(packet == loop_packet())\r
+                               {       \r
+                                       if(codec_context_)\r
+                                       {\r
+                                               if(codec_context_->codec->capabilities & CODEC_CAP_DELAY)\r
+                                               {\r
+                                                       AVPacket pkt;\r
+                                                       av_init_packet(&pkt);\r
+                                                       pkt.data = nullptr;\r
+                                                       pkt.size = 0;\r
+                               \r
+                                                       BOOST_FOREACH(auto& frame1, decode(pkt))\r
+                                                       {\r
+                                                               BOOST_FOREACH(auto& frame2, filter_.execute(frame1))\r
+                                                                       Concurrency::send(target_, std::shared_ptr<AVFrame>(frame2));\r
+                                                       }       \r
+                                               }\r
+\r
+                                               avcodec_flush_buffers(codec_context_.get());\r
+                                       }\r
+\r
+                                       Concurrency::send(target_, loop_video());       \r
+                               }\r
+                               else if(!codec_context_)\r
+                               {\r
+                                       Concurrency::send(target_, empty_video());      \r
+                               }\r
+                               else\r
+                               {\r
+                                       while(packet->size > 0)\r
+                                       {\r
+                                               BOOST_FOREACH(auto& frame1, decode(*packet))\r
+                                               {\r
+                                                       BOOST_FOREACH(auto& frame2, filter_.execute(frame1))\r
+                                                               Concurrency::send(target_, std::shared_ptr<AVFrame>(frame2));\r
+                                               }\r
+                                       }\r
+                               }\r
                        }\r
                }\r
-               \r
-               return result;\r
-       }\r
-\r
-       std::vector<std::shared_ptr<AVFrame>> empty_poll()\r
-       {                               \r
-               auto packet = packets_.front();\r
-               packets_.pop();\r
-\r
-               if(!packet)                     \r
-                       return boost::assign::list_of(nullptr);\r
-\r
-               std::shared_ptr<AVFrame> frame(avcodec_alloc_frame(), av_free);\r
-               frame->data[0] = nullptr;\r
+               catch(...)\r
+               {\r
+                       CASPAR_LOG_CURRENT_EXCEPTION();\r
+               }\r
 \r
-               return boost::assign::list_of(frame);                                   \r
+               std::shared_ptr<AVPacket> packet;\r
+               Concurrency::try_receive(source_, packet);              \r
+               \r
+               done();\r
        }\r
 \r
        std::vector<std::shared_ptr<AVFrame>> decode(AVPacket& pkt)\r
@@ -193,27 +202,31 @@ public:
                if(decoded_frame->repeat_pict % 2 > 0)\r
                        CASPAR_LOG(warning) << "[video_decoder]: Field repeat_pict not implemented.";\r
                \r
+               is_progressive_ = decoded_frame->interlaced_frame == 0;\r
+\r
                return std::vector<std::shared_ptr<AVFrame>>(1 + decoded_frame->repeat_pict/2, decoded_frame);\r
        }\r
-       \r
-       bool ready() const\r
-       {\r
-               return !packets_.empty();\r
-       }\r
-       \r
+               \r
        double fps() const\r
        {\r
                return fps_;\r
        }\r
 };\r
 \r
-video_decoder::video_decoder(const safe_ptr<AVFormatContext>& context, const safe_ptr<core::frame_factory>& frame_factory, const std::wstring& filter) : impl_(new implementation(context, frame_factory, filter)){}\r
-void video_decoder::push(const std::shared_ptr<AVPacket>& packet){impl_->push(packet);}\r
-std::vector<std::shared_ptr<AVFrame>> video_decoder::poll(){return impl_->poll();}\r
-bool video_decoder::ready() const{return impl_->ready();}\r
+video_decoder::video_decoder(token_t& active_token,\r
+                                                        source_t& source,\r
+                                                        target_t& target,\r
+                                                        const safe_ptr<AVFormatContext>& context, \r
+                                                        double fps, \r
+                                                        const std::wstring& filter) \r
+       : impl_(new implementation(active_token, source, target, context, fps, filter))\r
+{\r
+}\r
+\r
 double video_decoder::fps() const{return impl_->fps();}\r
 int64_t video_decoder::nb_frames() const{return impl_->nb_frames_;}\r
 size_t video_decoder::width() const{return impl_->width_;}\r
 size_t video_decoder::height() const{return impl_->height_;}\r
+bool video_decoder::is_progressive() const{return impl_->is_progressive_;}\r
 \r
 }}
\ No newline at end of file