]> git.sesse.net Git - casparcg/blobdiff - modules/ffmpeg/producer/video/video_decoder.cpp
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches...
[casparcg] / modules / ffmpeg / producer / video / video_decoder.cpp
index 62a23ca61e3eda52f57e88c2cc33aba97921ffc3..53a115e139dee1e3a29410962b507051192602aa 100644 (file)
@@ -26,7 +26,7 @@
 \r
 #include <core/video_format.h>\r
 #include <core/producer/frame/basic_frame.h>\r
-#include <core/producer/frame/write_frame.h>\r
+#include <core/mixer/write_frame.h>\r
 #include <core/producer/frame/image_transform.h>\r
 #include <core/producer/frame/pixel_format.h>\r
 #include <core/producer/frame/frame_factory.h>\r
@@ -43,6 +43,7 @@ extern "C"
        #define __STDC_LIMIT_MACROS\r
        #include <libswscale/swscale.h>\r
        #include <libavformat/avformat.h>\r
+       #include <libavcodec/avcodec.h>\r
 }\r
 #if defined(_MSC_VER)\r
 #pragma warning (pop)\r
@@ -123,6 +124,8 @@ struct video_decoder::implementation : boost::noncopyable
        const int                                                                       height_;\r
        const PixelFormat                                                       pix_fmt_;\r
        core::pixel_format_desc                                         desc_;\r
+       std::deque<safe_ptr<core::write_frame>>         frames_;\r
+       size_t                                                                          frame_number_;\r
 \r
 public:\r
        explicit implementation(AVCodecContext& codec_context, const safe_ptr<core::frame_factory>& frame_factory) \r
@@ -132,6 +135,7 @@ public:
                , height_(codec_context_.height)\r
                , pix_fmt_(codec_context_.pix_fmt)\r
                , desc_(get_pixel_format_desc(pix_fmt_, width_, height_))\r
+               , frame_number_(0)\r
        {\r
                if(desc_.pix_fmt == core::pixel_format::invalid)\r
                {\r
@@ -146,41 +150,37 @@ public:
                                                                          boost::errinfo_api_function("sws_getContext"));\r
                }\r
        }\r
-       \r
-       std::vector<safe_ptr<core::write_frame>> execute(void* tag, const packet& video_packet)\r
-       {                               \r
-               std::vector<safe_ptr<core::write_frame>> result;\r
 \r
-               switch(video_packet.type)\r
-               {\r
-               case flush_packet:\r
+       void push(const std::shared_ptr<AVPacket>& video_packet)\r
+       {                               \r
+               if(!video_packet)\r
+               {       \r
                        avcodec_flush_buffers(&codec_context_);\r
-                       break;\r
-               case data_packet:               \r
-                       safe_ptr<AVFrame> decoded_frame(avcodec_alloc_frame(), av_free);\r
+                       frame_number_ = 0;\r
+                       return;\r
+               }\r
 \r
-                       int frame_finished = 0;\r
-                       const int errn = avcodec_decode_video(&codec_context_, decoded_frame.get(), &frame_finished, video_packet.data->data(), video_packet.data->size());\r
-               \r
-                       if(errn < 0)\r
-                       {\r
-                               BOOST_THROW_EXCEPTION(\r
-                                       invalid_operation() <<\r
-                                       msg_info(av_error_str(errn)) <<\r
-                                       boost::errinfo_api_function("avcodec_decode_video") <<\r
-                                       boost::errinfo_errno(AVUNERROR(errn)));\r
-                       }\r
+               safe_ptr<AVFrame> decoded_frame(avcodec_alloc_frame(), av_free);\r
+\r
+               int frame_finished = 0;\r
+               const int errn = avcodec_decode_video2(&codec_context_, decoded_frame.get(), &frame_finished, video_packet.get());\r
                \r
-                       if(frame_finished != 0)         \r
-                               result.push_back(make_write_frame(tag, decoded_frame));\r
+               if(errn < 0)\r
+               {\r
+                       BOOST_THROW_EXCEPTION(\r
+                               invalid_operation() <<\r
+                               msg_info(av_error_str(errn)) <<\r
+                               boost::errinfo_api_function("avcodec_decode_video") <<\r
+                               boost::errinfo_errno(AVUNERROR(errn)));\r
                }\r
-\r
-               return result;\r
+               \r
+               if(frame_finished != 0)         \r
+                       frames_.push_back(make_write_frame(decoded_frame));\r
        }\r
 \r
-       safe_ptr<core::write_frame> make_write_frame(void* tag, safe_ptr<AVFrame> decoded_frame)\r
+       safe_ptr<core::write_frame> make_write_frame(safe_ptr<AVFrame> decoded_frame)\r
        {               \r
-               auto write = frame_factory_->create_frame(tag, desc_);\r
+               auto write = frame_factory_->create_frame(this, desc_);\r
                if(sws_context_ == nullptr)\r
                {\r
                        tbb::parallel_for(0, static_cast<int>(desc_.planes.size()), 1, [&](int n)\r
@@ -191,9 +191,10 @@ public:
                                auto decoded_linesize = decoded_frame->linesize[n];\r
                                \r
                                // Copy line by line since ffmpeg sometimes pads each line.\r
-                               tbb::parallel_for(0, static_cast<int>(desc_.planes[n].height), 1, [&](int y)\r
+                               tbb::parallel_for(tbb::blocked_range<size_t>(0, static_cast<int>(desc_.planes[n].height)), [&](const tbb::blocked_range<size_t>& r)\r
                                {\r
-                                       fast_memcpy(result + y*plane.linesize, decoded + y*decoded_linesize, plane.linesize);\r
+                                       for(size_t y = r.begin(); y != r.end(); ++y)\r
+                                               memcpy(result + y*plane.linesize, decoded + y*decoded_linesize, plane.linesize);\r
                                });\r
                        });\r
                }\r
@@ -213,9 +214,29 @@ public:
 \r
                return write;\r
        }\r
+\r
+       bool empty() const\r
+       {\r
+               return frames_.empty();\r
+       }\r
+\r
+       safe_ptr<core::write_frame> front()\r
+       {\r
+               return frames_.front();\r
+       }\r
+\r
+       void pop()\r
+       {\r
+               ++frame_number_;\r
+               frames_.pop_front();\r
+       }\r
 };\r
 \r
 video_decoder::video_decoder(AVCodecContext& codec_context, const safe_ptr<core::frame_factory>& frame_factory) : impl_(new implementation(codec_context, frame_factory)){}\r
-std::vector<safe_ptr<core::write_frame>> video_decoder::execute(void* tag, const packet& video_packet){return impl_->execute(tag, video_packet);}\r
+void video_decoder::push(const std::shared_ptr<AVPacket>& video_packet){impl_->push(std::move(video_packet));}\r
+bool video_decoder::empty() const {return impl_->empty();}\r
+safe_ptr<core::write_frame> video_decoder::front() {return impl_->front();}\r
+void video_decoder::pop(){impl_->pop();}\r
+size_t video_decoder::frame_number() const{return impl_->frame_number_;}\r
 \r
 }
\ No newline at end of file