]> git.sesse.net Git - casparcg/commitdiff
2.0. ffmpeg: Optimized.
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Tue, 9 Aug 2011 09:50:12 +0000 (09:50 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Tue, 9 Aug 2011 09:50:12 +0000 (09:50 +0000)
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@1102 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

core/producer/stage.cpp
modules/decklink/producer/decklink_producer.cpp
modules/ffmpeg/StdAfx.h
modules/ffmpeg/producer/audio/audio_decoder.cpp
modules/ffmpeg/producer/ffmpeg_producer.cpp
modules/ffmpeg/producer/frame_muxer.cpp
modules/ffmpeg/producer/frame_muxer.h
modules/ffmpeg/producer/util.cpp
modules/ffmpeg/producer/video/video_decoder.cpp

index d8e1d262ca7c394c8c068cec131f51e1e6abc41e..fa16845922355fd532b6aeb79834401bee0bd4fc 100644 (file)
@@ -33,8 +33,6 @@
 \r
 #include <boost/foreach.hpp>\r
 \r
-#include <tbb/parallel_for_each.h>\r
-\r
 #include <map>\r
 #include <set>\r
 \r
@@ -90,15 +88,8 @@ public:
 \r
                try\r
                {\r
-                       // Allocate placeholders.\r
-                       BOOST_FOREACH(auto layer, layers_)\r
-                               frames[layer.first] = basic_frame::empty();\r
-\r
-                       // Render layers\r
-                       tbb::parallel_for_each(layers_.begin(), layers_.end(), [&](std::map<int, layer>::value_type& layer)\r
-                       {\r
+                       BOOST_FOREACH(auto& layer, layers_)\r
                                frames[layer.first] = layer.second.receive();\r
-                       });\r
                }\r
                catch(...)\r
                {\r
index f5e152efffa4fd814c1f6e8c9ba433788f19e8d9..e59699a012c9b5605e73ac96a407118ccbc19e50 100644 (file)
@@ -198,6 +198,8 @@ public:
                        else\r
                                muxer_.push(std::make_shared<std::vector<int16_t>>(frame_factory_->get_video_format_desc().audio_samples_per_frame, 0));\r
                                        \r
+                       muxer_.commit();\r
+\r
                        while(!muxer_.empty())\r
                        {\r
                                if(!frame_buffer_.try_push(muxer_.pop()))\r
index a1d0a2b901bbfb65226daf3416af359152a5e964..fb398771232803c06fbc1e4c1009b53fec784dbd 100644 (file)
@@ -43,7 +43,6 @@
 \r
 #include <tbb/atomic.h>\r
 #include <tbb/concurrent_queue.h>\r
-#include <tbb/parallel_invoke.h>\r
 #include <tbb/parallel_for.h>\r
 \r
 #include <boost/assign.hpp>\r
index bb40ef7d2cf62a8574f96991032fdbf4780c5bb6..eabf4429e57acba62d86b07b97c318c37690dcd8 100644 (file)
@@ -120,23 +120,23 @@ public:
 \r
                std::vector<std::shared_ptr<std::vector<int16_t>>> result;\r
 \r
-               if(packets_.empty())\r
-                       return result;\r
-                                               \r
-               auto packet = packets_.front();\r
-\r
-               if(packet)              \r
-               {\r
-                       result.push_back(decode(*packet));\r
-                       if(packet->size == 0)                                   \r
+               while(!packets_.empty() && result.empty())\r
+               {                                               \r
+                       auto packet = packets_.front();\r
+\r
+                       if(packet)              \r
+                       {\r
+                               result.push_back(decode(*packet));\r
+                               if(packet->size == 0)                                   \r
+                                       packets_.pop();\r
+                       }\r
+                       else                    \r
+                       {       \r
+                               avcodec_flush_buffers(codec_context_.get());\r
+                               result.push_back(nullptr);\r
                                packets_.pop();\r
+                       }               \r
                }\r
-               else                    \r
-               {       \r
-                       avcodec_flush_buffers(codec_context_.get());\r
-                       result.push_back(nullptr);\r
-                       packets_.pop();\r
-               }               \r
 \r
                return result;\r
        }\r
@@ -183,7 +183,7 @@ public:
 \r
        bool ready() const\r
        {\r
-               return !codec_context_ || !packets_.empty();\r
+               return !codec_context_ || packets_.size() > 2;\r
        }\r
 };\r
 \r
index bb5d727cb0bd497c050b99a4bc97122a61c898a4..d8da6102dbf0f32c8f15d1a35686f4a5b1700503 100644 (file)
@@ -44,7 +44,6 @@
 #include <boost/range/algorithm/find.hpp>\r
 \r
 #include <tbb/task_group.h>\r
-#include <tbb/parallel_invoke.h>\r
 \r
 namespace caspar {\r
                        \r
@@ -54,6 +53,8 @@ struct ffmpeg_producer : public core::frame_producer
        \r
        const safe_ptr<diagnostics::graph>                              graph_;\r
        boost::timer                                                                    frame_timer_;\r
+       boost::timer                                                                    video_timer_;\r
+       boost::timer                                                                    audio_timer_;\r
                                        \r
        const safe_ptr<core::frame_factory>                             frame_factory_;\r
        const core::video_format_desc                                   format_desc_;\r
@@ -69,6 +70,8 @@ struct ffmpeg_producer : public core::frame_producer
        const bool                                                                              loop_;\r
 \r
        safe_ptr<core::basic_frame>                                             last_frame_;\r
+\r
+       tbb::task_group                                                                 tasks_;\r
        \r
 public:\r
        explicit ffmpeg_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::wstring& filename, const std::wstring& filter, bool loop, int start, int length) \r
@@ -87,21 +90,29 @@ public:
        {\r
                graph_->add_guide("frame-time", 0.5);\r
                graph_->set_color("frame-time", diagnostics::color(1.0f, 0.0f, 0.0f));\r
+               graph_->set_color("video-time", diagnostics::color(1.0f, 1.0f, 0.0f));\r
+               graph_->set_color("audio-time", diagnostics::color(0.2f, 1.0f, 0.2f));\r
                graph_->set_color("underflow", diagnostics::color(0.6f, 0.3f, 0.9f));           \r
                \r
                for(int n = 0; n < 128 && muxer_.size() < 2; ++n)\r
                        decode_frame(0);\r
        }\r
+\r
+       ~ffmpeg_producer()\r
+       {\r
+               tasks_.cancel();\r
+               tasks_.wait();\r
+       }\r
                \r
        virtual safe_ptr<core::basic_frame> receive(int hints)\r
        {\r
                auto frame = core::basic_frame::late();\r
                \r
                frame_timer_.restart();\r
-\r
-               for(int n = 0; n < 64 && muxer_.size() < 2; ++n)\r
-                       decode_frame(hints);\r
                \r
+               for(int n = 0; n < 8 && muxer_.empty(); ++n)\r
+                       decode_frame(hints);\r
+\r
                if(!muxer_.empty())\r
                        frame = last_frame_ = muxer_.pop();     \r
                else\r
@@ -127,7 +138,11 @@ public:
 \r
        void decode_frame(int hints)\r
        {\r
-               for(int n = 0; n < 32 && ((!muxer_.video_ready() && !video_decoder_.ready()) || (!muxer_.audio_ready() && !audio_decoder_.ready())); ++n) \r
+               tasks_.wait();\r
+\r
+               muxer_.commit();\r
+\r
+               for(int n = 0; n < 16 && ((!muxer_.video_ready() && !video_decoder_.ready()) || (!muxer_.audio_ready() && !audio_decoder_.ready())); ++n) \r
                {\r
                        std::shared_ptr<AVPacket> pkt;\r
                        if(input_.try_pop(pkt))\r
@@ -136,27 +151,34 @@ public:
                                audio_decoder_.push(pkt);\r
                        }\r
                }\r
-\r
-               decltype(video_decoder_.poll()) video_frames;\r
-               decltype(audio_decoder_.poll()) audio_samples;\r
                \r
-               tbb::parallel_invoke(\r
-               [&]\r
+               if(!muxer_.video_ready())\r
                {\r
-                       if(!muxer_.video_ready())\r
-                               video_frames = video_decoder_.poll();\r
-               },\r
-               [&]\r
+                       tasks_.run([=]\r
+                       {\r
+                               video_timer_.restart();\r
+\r
+                               auto video_frames = video_decoder_.poll();\r
+                               BOOST_FOREACH(auto& video, video_frames)                \r
+                                       muxer_.push(video, hints);      \r
+\r
+                               graph_->update_value("video-time", static_cast<float>(video_timer_.elapsed()*format_desc_.fps*0.5));\r
+                       });\r
+               }               \r
+\r
+               if(!muxer_.audio_ready())\r
                {\r
-                       if(!muxer_.audio_ready())\r
-                               audio_samples = audio_decoder_.poll();\r
-               });\r
-               \r
-               BOOST_FOREACH(auto& audio, audio_samples)\r
-                       muxer_.push(audio);\r
+                       tasks_.run([=]\r
+                       {\r
+                               audio_timer_.restart();\r
+                                       \r
+                               auto audio_samples = audio_decoder_.poll();\r
+                               BOOST_FOREACH(auto& audio, audio_samples)\r
+                                       muxer_.push(audio);                             \r
 \r
-               BOOST_FOREACH(auto& video, video_frames)                \r
-                       muxer_.push(video, hints);              \r
+                               graph_->update_value("audio-time", static_cast<float>(audio_timer_.elapsed()*format_desc_.fps*0.5));\r
+                       });     \r
+               }\r
        }\r
 \r
        virtual int64_t nb_frames() const\r
index 9267f7ec7fab4178c61cb12ff5c22be48974d176..ba3d0ae0d6e6298663ca24bca51c62af19cf6fae 100644 (file)
@@ -166,7 +166,6 @@ struct frame_muxer::implementation : boost::noncopyable
                        video_streams_.back().push(make_safe<core::write_frame>(this));\r
                        ++video_frame_count_;\r
                        display_mode_ = display_mode::simple;\r
-                       put_frames(frame_buffer_);\r
                        return;\r
                }\r
 \r
@@ -206,8 +205,6 @@ struct frame_muxer::implementation : boost::noncopyable
 \r
                        video_streams_.back().push(frame);\r
                        ++video_frame_count_;\r
-\r
-                       put_frames(frame_buffer_);\r
                }\r
        }\r
 \r
@@ -224,7 +221,6 @@ struct frame_muxer::implementation : boost::noncopyable
                audio_sample_count_ += audio_samples->size();\r
 \r
                boost::range::push_back(audio_streams_.back(), *audio_samples);\r
-               put_frames(frame_buffer_);\r
        }\r
 \r
        safe_ptr<basic_frame> pop()\r
@@ -280,7 +276,7 @@ struct frame_muxer::implementation : boost::noncopyable
                return audio_streams_.back().size() / format_desc_.audio_samples_per_frame;\r
        }\r
        \r
-       void put_frames(std::deque<safe_ptr<basic_frame>>& dest)\r
+       void commit()\r
        {\r
                if(video_streams_.size() > 1 && audio_streams_.size() > 1 &&\r
                        (video_streams_.front().empty() || audio_streams_.front().empty()))\r
@@ -297,13 +293,13 @@ struct frame_muxer::implementation : boost::noncopyable
                \r
                switch(display_mode_)\r
                {\r
-               case display_mode::simple:                                              return simple(dest);\r
-               case display_mode::duplicate:                                   return duplicate(dest);\r
-               case display_mode::half:                                                return half(dest);\r
-               case display_mode::interlace:                                   return interlace(dest);\r
-               case display_mode::deinterlace_bob:                             return simple(dest);\r
-               case display_mode::deinterlace_bob_reinterlace: return interlace(dest);\r
-               case display_mode::deinterlace:                                 return simple(dest);\r
+               case display_mode::simple:                                              return simple(frame_buffer_);\r
+               case display_mode::duplicate:                                   return duplicate(frame_buffer_);\r
+               case display_mode::half:                                                return half(frame_buffer_);\r
+               case display_mode::interlace:                                   return interlace(frame_buffer_);\r
+               case display_mode::deinterlace_bob:                             return simple(frame_buffer_);\r
+               case display_mode::deinterlace_bob_reinterlace: return interlace(frame_buffer_);\r
+               case display_mode::deinterlace:                                 return simple(frame_buffer_);\r
                default:                                                                                BOOST_THROW_EXCEPTION(invalid_operation() << msg_info("invalid display-mode"));\r
                }\r
        }\r
@@ -367,6 +363,7 @@ frame_muxer::frame_muxer(double in_fps, const safe_ptr<core::frame_factory>& fra
        : impl_(new implementation(in_fps, frame_factory)){}\r
 void frame_muxer::push(const std::shared_ptr<AVFrame>& video_frame, int hints){impl_->push(video_frame, hints);}\r
 void frame_muxer::push(const std::shared_ptr<std::vector<int16_t>>& audio_samples){return impl_->push(audio_samples);}\r
+void frame_muxer::commit(){impl_->commit();}\r
 safe_ptr<basic_frame> frame_muxer::pop(){return impl_->pop();}\r
 size_t frame_muxer::size() const {return impl_->size();}\r
 bool frame_muxer::empty() const {return impl_->size() == 0;}\r
index 59632adb32817e051f0bf4eba72d29d87654e3da..deee975614ce78dc2b0cf8c64ecc1e0e9ed30aa1 100644 (file)
@@ -26,6 +26,8 @@ public:
        void push(const std::shared_ptr<AVFrame>& video_frame, int hints = 0);\r
        void push(const std::shared_ptr<std::vector<int16_t>>& audio_samples);\r
        \r
+       void commit();\r
+\r
        bool video_ready() const;\r
        bool audio_ready() const;\r
 \r
index d688b54484b9ce805e01e7eaa4e5c8399190d0e5..493203fe6619a09f34b5a8ed638f4aac7da321ef 100644 (file)
@@ -11,7 +11,8 @@
 #include <core/mixer/write_frame.h>\r
 \r
 #include <common/exception/exceptions.h>\r
-#include <common/memory/memcpy.h>\r
+\r
+#include <tbb/parallel_for.h>\r
 \r
 #if defined(_MSC_VER)\r
 #pragma warning (push)\r
@@ -224,7 +225,7 @@ safe_ptr<core::write_frame> make_write_frame(const void* tag, const safe_ptr<AVF
                auto write = frame_factory->create_frame(tag, desc.pix_fmt != core::pixel_format::invalid ? desc : get_pixel_format_desc(PIX_FMT_BGRA, width, height));\r
                write->set_type(get_mode(*decoded_frame));\r
 \r
-               tbb::parallel_for(0, static_cast<int>(desc.planes.size()), 1, [&](int n)\r
+               for(int n = 0; n < static_cast<int>(desc.planes.size()); ++n)\r
                {\r
                        auto plane            = desc.planes[n];\r
                        auto result           = write->image_data(n).begin();\r
@@ -232,14 +233,28 @@ safe_ptr<core::write_frame> make_write_frame(const void* tag, const safe_ptr<AVF
                        auto decoded_linesize = decoded_frame->linesize[n];\r
                                \r
                        // Copy line by line since ffmpeg sometimes pads each line.\r
+                       tbb::affinity_partitioner ap;\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
                                for(size_t y = r.begin(); y != r.end(); ++y)\r
-                                       fast_memcpy(result + y*plane.linesize, decoded + y*decoded_linesize, plane.linesize);\r
-                       });\r
+                                       memcpy(result + y*plane.linesize, decoded + y*decoded_linesize, plane.linesize);\r
+                       }, ap);\r
 \r
                        write->commit(n);\r
-               });\r
+               }\r
+\r
+               //for(int n = 0; n < static_cast<int>(desc.planes.size()); ++n)\r
+               //{\r
+               //      auto plane            = desc.planes[n];\r
+               //      auto result           = write->image_data(n).begin();\r
+               //      auto decoded          = decoded_frame->data[n];\r
+               //      auto decoded_linesize = decoded_frame->linesize[n];\r
+               //              \r
+               //      for(size_t y = 0; y < static_cast<int>(desc.planes[n].height); ++y)\r
+               //              fast_memcpy(result + y*plane.linesize, decoded + y*decoded_linesize, plane.linesize);\r
+\r
+               //      write->commit(n);\r
+               //}\r
 \r
                return write;\r
        }\r
index c05d87b4fcf72b6bc26bfd25b027e66458cac453..b426131e97c7b9c2b01a014f0c3bd4ef38a6febb 100644 (file)
@@ -113,35 +113,35 @@ public:
 \r
                std::vector<std::shared_ptr<AVFrame>> result;\r
 \r
-               if(packets_.empty())\r
-                       return result;\r
-\r
-               auto packet = packets_.front();\r
-                                       \r
-               if(packet)\r
+               while(!packets_.empty() && result.empty())\r
                {\r
-                       auto frame = decode(*packet);\r
-                       boost::range::push_back(result, filter_.execute(frame));\r
-                       if(packet->size == 0)\r
-                               packets_.pop();\r
-               }\r
-               else\r
-               {\r
-                       if(codec_context_->codec->capabilities & CODEC_CAP_DELAY)\r
+                       auto packet = packets_.front();\r
+                                       \r
+                       if(packet)\r
                        {\r
-                               AVPacket pkt;\r
-                               av_init_packet(&pkt);\r
-                               pkt.data = nullptr;\r
-                               pkt.size = 0;\r
-                               auto frame = decode(pkt);\r
-                               boost::range::push_back(result, filter_.execute(frame));        \r
+                               auto frame = decode(*packet);\r
+                               boost::range::push_back(result, filter_.execute(frame));\r
+                               if(packet->size == 0)\r
+                                       packets_.pop();\r
                        }\r
-\r
-                       if(result.empty())\r
-                       {                                       \r
-                               packets_.pop();\r
-                               avcodec_flush_buffers(codec_context_.get());\r
-                               result.push_back(nullptr);\r
+                       else\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
+                                       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
+                               }\r
                        }\r
                }\r
                \r
@@ -190,7 +190,7 @@ public:
        \r
        bool ready() const\r
        {\r
-               return !codec_context_ || !packets_.empty();\r
+               return !codec_context_ || packets_.size() > 2;\r
        }\r
        \r
        double fps() const\r