]> git.sesse.net Git - casparcg/commitdiff
2.0.0.2: ffmpeg_producer: Yield input thread when there is enough packets.
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Sat, 14 May 2011 21:24:19 +0000 (21:24 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Sat, 14 May 2011 21:24:19 +0000 (21:24 +0000)
                          Optimized pre-compiled header. Misc cleanup.
         mixer_device: Buffer 2 frames.

git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@748 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

core/mixer/frame_mixer_device.cpp
modules/ffmpeg/StdAfx.h
modules/ffmpeg/producer/audio/audio_decoder.cpp
modules/ffmpeg/producer/audio/audio_decoder.h
modules/ffmpeg/producer/ffmpeg_producer.cpp
modules/ffmpeg/producer/input.cpp
modules/ffmpeg/producer/video/video_decoder.cpp
modules/ffmpeg/producer/video/video_decoder.h

index fc88c838653e8d82232266e12357a65c7ba9ccdd..9c7dca934db27f511984b0970cddb2431fb57c88 100644 (file)
@@ -115,7 +115,7 @@ public:
                diag_->set_color("frame-time", diagnostics::color(1.0f, 0.0f, 0.0f));\r
                diag_->set_color("tick-time", diagnostics::color(0.1f, 0.7f, 0.8f));\r
                diag_->set_color("input-buffer", diagnostics::color(1.0f, 1.0f, 0.0f)); \r
-               executor_.set_capacity(1);      \r
+               executor_.set_capacity(2);      \r
                executor_.begin_invoke([]\r
                {\r
                        SetThreadPriority(GetCurrentThread(), ABOVE_NORMAL_PRIORITY_CLASS);\r
index 5c4ac8f7f7328bcb0c12c4ecc50569dc517669b6..6e970d3d4d5670f145bcdc20f8f44195535c74a0 100644 (file)
 \r
 #include <tbb/atomic.h>\r
 #include <tbb/concurrent_queue.h>\r
-#include <tbb/concurrent_unordered_map.h>\r
 #include <tbb/parallel_invoke.h>\r
 #include <tbb/parallel_for.h>\r
-#include <tbb/parallel_for_each.h>\r
 \r
 #include <boost/assign.hpp>\r
 #include <boost/filesystem.hpp>\r
 #include <boost/foreach.hpp>\r
 #include <boost/range/algorithm.hpp>\r
 \r
-#include "../common/utility/string.h"\r
-#include "../common/memory/safe_ptr.h"\r
+#include <common/utility/string.h>\r
+#include <common/utility/assert.h>\r
+#include <common/memory/safe_ptr.h>\r
 //#include "../common/concurrency/executor.h" // Can't include this due to MSVC lambda bug\r
 \r
-#include "../common/log/Log.h"\r
-#include "../common/exception/exceptions.h"\r
-#include "../common/exception/win32_exception.h"\r
+#include <common/log/log.h>\r
+#include <common/exception/exceptions.h>\r
+#include <common/exception/win32_exception.h>\r
 \r
-#include <assert.h>\r
+#pragma warning(push, 1)\r
+\r
+extern "C" \r
+{\r
+       #define __STDC_CONSTANT_MACROS\r
+       #define __STDC_LIMIT_MACROS\r
+       #include <libavformat/avformat.h>\r
+       #include <libavcodec/avcodec.h>\r
+       #include <libswscale/swscale.h>\r
+}\r
+\r
+#pragma warning(pop)\r
 \r
 #endif\r
index 337547dc11d143fd1a98ebf2de3dca5a38ce3c8a..671bd3b979241d58dfd19801a10d948a716e97da 100644 (file)
@@ -40,33 +40,26 @@ namespace caspar {
 \r
 struct audio_decoder::implementation : boost::noncopyable\r
 {\r
-       typedef std::vector<short, tbb::cache_aligned_allocator<short>> buffer;\r
+       typedef std::vector<short, tbb::cache_aligned_allocator<short>> aligned_buffer;\r
        \r
-       AVCodecContext* codec_context_;\r
+       AVCodecContext& codec_context_;\r
                \r
        const core::video_format_desc format_desc_;\r
 \r
-       buffer current_chunk_;\r
+       aligned_buffer current_chunk_;\r
 \r
 public:\r
-       explicit implementation(AVCodecContext* codec_context, const core::video_format_desc& format_desc) \r
+       explicit implementation(AVCodecContext& codec_context, const core::video_format_desc& format_desc) \r
                : codec_context_(codec_context)\r
                , format_desc_(format_desc)             \r
        {\r
-               if(!codec_context)\r
-               {       \r
-                       BOOST_THROW_EXCEPTION(\r
-                               null_argument() << \r
-                               arg_name_info("codec_context"));        \r
-               }\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
+               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
                {       \r
                        BOOST_THROW_EXCEPTION(\r
                                file_read_error()  <<\r
                                msg_info("Invalid sample-rate or number of channels.") <<\r
-                               arg_value_info(boost::lexical_cast<std::string>(codec_context_->sample_rate)) << \r
+                               arg_value_info(boost::lexical_cast<std::string>(codec_context_.sample_rate)) << \r
                                arg_name_info("codec_context"));\r
                }\r
        }\r
@@ -78,14 +71,14 @@ public:
                switch(audio_packet.type)\r
                {\r
                case flush_packet:\r
-                       avcodec_flush_buffers(codec_context_);\r
+                       avcodec_flush_buffers(&codec_context_);\r
                        break;\r
                case data_packet:\r
                        auto s = current_chunk_.size();\r
                        current_chunk_.resize(s + 4*format_desc_.audio_sample_rate*2+FF_INPUT_BUFFER_PADDING_SIZE/2);\r
                \r
                        int written_bytes = (current_chunk_.size() - s)*2 - FF_INPUT_BUFFER_PADDING_SIZE;\r
-                       const int errn = avcodec_decode_audio2(codec_context_, &current_chunk_[s], &written_bytes, audio_packet.data->data(), audio_packet.data->size());\r
+                       const int errn = avcodec_decode_audio2(&codec_context_, &current_chunk_[s], &written_bytes, audio_packet.data->data(), audio_packet.data->size());\r
                        if(errn < 0)\r
                        {       \r
                                BOOST_THROW_EXCEPTION(\r
@@ -108,6 +101,6 @@ public:
        }\r
 };\r
 \r
-audio_decoder::audio_decoder(AVCodecContext* codec_context, const core::video_format_desc& format_desc) : impl_(new implementation(codec_context, format_desc)){}\r
+audio_decoder::audio_decoder(AVCodecContext& codec_context, const core::video_format_desc& format_desc) : impl_(new implementation(codec_context, format_desc)){}\r
 std::vector<std::vector<short>> audio_decoder::execute(const packet& audio_packet){return impl_->execute(audio_packet);}\r
 }
\ No newline at end of file
index 8296875bc7a76449e5b6947c519b92aac4cdda78..f5c705f2f8155f2cccfda8c69078af83757121a4 100644 (file)
@@ -37,7 +37,7 @@ namespace caspar {
 class audio_decoder : boost::noncopyable\r
 {\r
 public:\r
-       explicit audio_decoder(AVCodecContext* codec_context, const core::video_format_desc& format_desc);\r
+       explicit audio_decoder(AVCodecContext& codec_context, const core::video_format_desc& format_desc);\r
        std::vector<std::vector<short>> execute(const packet& audio_packet);\r
 private:\r
        struct implementation;\r
index 752e12a9862b7473a02b7bc36379ca8cbff3ee9f..b4942a3d9d23abc2cd0e0c871453c5fcb7ecedcc 100644 (file)
@@ -38,6 +38,8 @@
 #include <tbb/parallel_invoke.h>\r
 \r
 #include <boost/timer.hpp>\r
+#include <boost/range/algorithm.hpp>\r
+#include <boost/range/algorithm_ext.hpp>\r
 \r
 #include <deque>\r
 \r
@@ -45,6 +47,9 @@ namespace caspar {
        \r
 struct ffmpeg_producer : public core::frame_producer\r
 {\r
+       static const size_t                                             DECODED_PACKET_BUFFER_SIZE = 4;\r
+       static const size_t                                             MAX_PACKET_OFFSET = 64; // 64 packets should be enough. Otherwise there probably was an error and we want to avoid infinite looping.\r
+\r
        const std::wstring                                              filename_;\r
        const bool                                                              loop_;\r
        \r
@@ -79,7 +84,7 @@ public:
                try\r
                {                       \r
                        video_decoder_.reset(input_.get_video_codec_context() ? \r
-                               new video_decoder(input_.get_video_codec_context().get(), frame_factory) : nullptr);\r
+                               new video_decoder(*input_.get_video_codec_context(), frame_factory) : nullptr);\r
                }\r
                catch(...)\r
                {\r
@@ -91,7 +96,7 @@ public:
                try\r
                {                       \r
                        audio_decoder_.reset(input_.get_audio_codec_context() ? \r
-                               new audio_decoder(input_.get_audio_codec_context().get(), frame_factory->get_video_format_desc()) : nullptr);\r
+                               new audio_decoder(*input_.get_audio_codec_context(), frame_factory->get_video_format_desc()) : nullptr);\r
                }\r
                catch(...)\r
                {\r
@@ -114,24 +119,8 @@ public:
                frame_timer_.restart();\r
 \r
                std::shared_ptr<core::basic_frame> frame;       \r
-               for(size_t n = 0; !frame && input_.has_packet() && n < 64; ++n) // 64 packets should be enough. Otherwise there probably was an error and we want to avoid infinite looping.\r
-               {       \r
-                       tbb::parallel_invoke\r
-                       (\r
-                               [&]\r
-                               {\r
-                                       if(video_frame_buffer_.size() < 3)\r
-                                               try_decode_video_packet(input_.get_video_packet());\r
-                               }, \r
-                               [&]\r
-                               {\r
-                                       if(audio_chunk_buffer_.size() < 3)\r
-                                               try_decode_audio_packet(input_.get_audio_packet());\r
-                               }\r
-                       );                      \r
-\r
-                       frame = try_merge_audio_and_video();    \r
-               }\r
+               for(size_t n = 0; !frame && n < MAX_PACKET_OFFSET; ++n) \r
+                       frame = try_decode_frame();\r
                \r
                graph_->update_value("frame-time", static_cast<float>(frame_timer_.elapsed()*frame_factory_->get_video_format_desc().fps*0.5));\r
                                        \r
@@ -147,21 +136,42 @@ public:
                graph_->add_tag("underflow");\r
                return core::basic_frame::late();       \r
        }\r
-\r
+       \r
        virtual std::wstring print() const\r
        {\r
                return L"ffmpeg[" + boost::filesystem::wpath(filename_).filename() + L"]";\r
        }\r
+       \r
+       std::shared_ptr<core::basic_frame> try_decode_frame()\r
+       {\r
+               if(!input_.has_packet())\r
+                       return nullptr;\r
+\r
+               tbb::parallel_invoke\r
+               (\r
+                       [&]\r
+                       {\r
+                               if(video_frame_buffer_.size() < DECODED_PACKET_BUFFER_SIZE)\r
+                                       try_decode_video_packet(input_.get_video_packet());\r
+                       }, \r
+                       [&]\r
+                       {\r
+                               if(audio_chunk_buffer_.size() < DECODED_PACKET_BUFFER_SIZE)\r
+                                       try_decode_audio_packet(input_.get_audio_packet());\r
+                       }\r
+               );                      \r
+\r
+               return try_merge_audio_and_video();     \r
+       }\r
 \r
        void try_decode_video_packet(const packet& video_packet)\r
        {\r
-               if(!video_decoder_) // Video Decoding.\r
+               if(!video_decoder_)\r
                        return;\r
 \r
                try\r
                {\r
-                       auto frames = video_decoder_->execute(this, video_packet);\r
-                       video_frame_buffer_.insert(video_frame_buffer_.end(), frames.begin(), frames.end());\r
+                       boost::range::push_back(video_frame_buffer_, video_decoder_->execute(this, video_packet));\r
                }\r
                catch(...)\r
                {\r
@@ -173,13 +183,12 @@ public:
 \r
        void try_decode_audio_packet(const packet& audio_packet)\r
        {\r
-               if(!audio_decoder_) // Audio Decoding.\r
+               if(!audio_decoder_)\r
                        return;\r
 \r
                try\r
                {\r
-                       auto chunks = audio_decoder_->execute(audio_packet);\r
-                       audio_chunk_buffer_.insert(audio_chunk_buffer_.end(), chunks.begin(), chunks.end());\r
+                       boost::range::push_back(audio_chunk_buffer_, audio_decoder_->execute(audio_packet));\r
                }\r
                catch(...)\r
                {\r
index 8bdda005a61ea984f68af40965ab0cf743c51aad..a4e8b4c9639e24f57446997b2e28f52f0eda1b02 100644 (file)
 *    along with CasparCG.  If not, see <http://www.gnu.org/licenses/>.\r
 *\r
 */\r
+#if defined(_MSC_VER)\r
+#pragma warning (disable : 4244)\r
+#endif\r
+\r
 #include "..\stdafx.h"\r
 \r
 #include "input.h"\r
@@ -33,9 +37,6 @@
 #include <boost/range/iterator_range.hpp>\r
 #include <boost/range/algorithm.hpp>\r
 \r
-#if defined(_MSC_VER)\r
-#pragma warning (disable : 4244)\r
-#endif\r
 \r
 extern "C" \r
 {\r
@@ -48,7 +49,7 @@ namespace caspar {
                \r
 struct input::implementation : boost::noncopyable\r
 {              \r
-       static const size_t PACKET_BUFFER_COUNT = 25;\r
+       static const size_t PACKET_BUFFER_COUNT = 50;\r
 \r
        safe_ptr<diagnostics::graph> graph_;\r
 \r
@@ -211,6 +212,9 @@ private:
                \r
        void read_file()\r
        {               \r
+               if(audio_packet_buffer_.size() > 4 && video_packet_buffer_.size() > 4)\r
+                       boost::this_thread::yield(); // There is enough packets, no hurry.\r
+\r
                try\r
                {\r
                        AVPacket tmp_packet;\r
index b64e3f54674d946cc1be3303828aef3922a97de8..62a23ca61e3eda52f57e88c2cc33aba97921ffc3 100644 (file)
@@ -118,19 +118,19 @@ struct video_decoder::implementation : boost::noncopyable
 {      \r
        std::shared_ptr<SwsContext>                                     sws_context_;\r
        const std::shared_ptr<core::frame_factory>      frame_factory_;\r
-       AVCodecContext*                                                         codec_context_;\r
+       AVCodecContext&                                                         codec_context_;\r
        const int                                                                       width_;\r
        const int                                                                       height_;\r
        const PixelFormat                                                       pix_fmt_;\r
        core::pixel_format_desc                                         desc_;\r
 \r
 public:\r
-       explicit implementation(AVCodecContext* codec_context, const safe_ptr<core::frame_factory>& frame_factory) \r
+       explicit implementation(AVCodecContext& codec_context, const safe_ptr<core::frame_factory>& frame_factory) \r
                : frame_factory_(frame_factory)\r
                , codec_context_(codec_context)\r
-               , width_(codec_context_->width)\r
-               , height_(codec_context_->height)\r
-               , pix_fmt_(codec_context_->pix_fmt)\r
+               , width_(codec_context_.width)\r
+               , height_(codec_context_.height)\r
+               , pix_fmt_(codec_context_.pix_fmt)\r
                , desc_(get_pixel_format_desc(pix_fmt_, width_, height_))\r
        {\r
                if(desc_.pix_fmt == core::pixel_format::invalid)\r
@@ -154,13 +154,13 @@ public:
                switch(video_packet.type)\r
                {\r
                case flush_packet:\r
-                       avcodec_flush_buffers(codec_context_);\r
+                       avcodec_flush_buffers(&codec_context_);\r
                        break;\r
                case data_packet:               \r
                        safe_ptr<AVFrame> decoded_frame(avcodec_alloc_frame(), av_free);\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
+                       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
@@ -208,14 +208,14 @@ public:
                }       \r
 \r
                // DVVIDEO is in lower field. Make it upper field if needed.\r
-               if(codec_context_->codec_id == CODEC_ID_DVVIDEO && frame_factory_->get_video_format_desc().mode == core::video_mode::upper)\r
+               if(codec_context_.codec_id == CODEC_ID_DVVIDEO && frame_factory_->get_video_format_desc().mode == core::video_mode::upper)\r
                        write->get_image_transform().set_fill_translation(0.0f, 1.0/static_cast<double>(height_));\r
 \r
                return write;\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
+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
 \r
 }
\ No newline at end of file
index 81af067666eaaeeb24268f3cd6303aaca3e03187..4d680f2efae08852e94e21a00ebd43861954b3df 100644 (file)
@@ -35,7 +35,7 @@ namespace core {
 class video_decoder : boost::noncopyable\r
 {\r
 public:\r
-       explicit video_decoder(AVCodecContext* codec_context, const safe_ptr<core::frame_factory>& frame_factory);\r
+       explicit video_decoder(AVCodecContext& codec_context, const safe_ptr<core::frame_factory>& frame_factory);\r
        std::vector<safe_ptr<core::write_frame>> execute(void* tag, const packet& video_packet);        \r
 private:\r
        struct implementation;\r