]> git.sesse.net Git - casparcg/commitdiff
2.0.0.2: ffmpeg_producer: Refactored and optimized.
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Wed, 25 May 2011 13:13:09 +0000 (13:13 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Wed, 25 May 2011 13:13:09 +0000 (13:13 +0000)
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@809 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

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
modules/ffmpeg/tbb_avcodec.cpp
shell/main.cpp

index bc8e2b76bdf0114df340788742f08103c187b8f3..d8eac2bb99b7ff51a1789ea8f5babae5d975b2b4 100644 (file)
@@ -40,16 +40,20 @@ namespace caspar {
 \r
 struct audio_decoder::implementation : boost::noncopyable\r
 {      \r
+       input&                                                  input_;\r
        AVCodecContext&                                 codec_context_;         \r
        const core::video_format_desc   format_desc_;\r
        std::vector<short>                              current_chunk_;\r
        std::vector<std::vector<short>> chunks_;                \r
        size_t                                                  frame_number_;\r
+       bool                                                    restarting_;\r
 public:\r
-       explicit implementation(AVCodecContext& codec_context, const core::video_format_desc& format_desc) \r
-               : codec_context_(codec_context)\r
+       explicit implementation(input& input, const core::video_format_desc& format_desc) \r
+               : input_(input)\r
+               , codec_context_(*input_.get_audio_codec_context())\r
                , format_desc_(format_desc)     \r
                , frame_number_(0)\r
+               , restarting_(false)\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
@@ -61,16 +65,33 @@ public:
                                arg_name_info("codec_context"));\r
                }\r
        }\r
-                       \r
-       void push(const std::shared_ptr<AVPacket>& audio_packet)\r
+               \r
+       std::deque<std::pair<int, std::vector<short>>> receive()\r
+       {\r
+               std::deque<std::pair<int, std::vector<short>>> result;\r
+               \r
+               std::shared_ptr<AVPacket> pkt;\r
+               for(int n = 0; n < 32 && result.empty() && input_.try_pop_audio_packet(pkt); ++n)       \r
+                       result = decode(pkt);\r
+\r
+               return result;\r
+       }\r
+\r
+       std::deque<std::pair<int, std::vector<short>>> decode(const std::shared_ptr<AVPacket>& audio_packet)\r
        {                       \r
+               std::deque<std::pair<int, std::vector<short>>> result;\r
+\r
                if(!audio_packet)\r
                {       \r
                        avcodec_flush_buffers(&codec_context_);\r
                        current_chunk_.clear();\r
                        frame_number_ = 0;\r
-                       return;\r
+                       restarting_ = false;\r
+                       return result;\r
                }\r
+\r
+               if(restarting_)\r
+                       return result;\r
                                \r
                auto s = current_chunk_.size();\r
                current_chunk_.resize(s + 4*format_desc_.audio_sample_rate*2+FF_INPUT_BUFFER_PADDING_SIZE/2, 0);\r
@@ -90,32 +111,20 @@ public:
                const auto last = current_chunk_.end() - current_chunk_.size() % format_desc_.audio_samples_per_frame;\r
                \r
                for(auto it = current_chunk_.begin(); it != last; it += format_desc_.audio_samples_per_frame)           \r
-                       chunks_.push_back(std::vector<short>(it, it + format_desc_.audio_samples_per_frame));           \r
+                       result.push_back(std::make_pair(frame_number_++, std::vector<short>(it, it + format_desc_.audio_samples_per_frame)));           \r
 \r
                current_chunk_.erase(current_chunk_.begin(), last);\r
-       }\r
-\r
-       bool empty() const\r
-       {\r
-               return chunks_.empty();\r
-       }\r
 \r
-       std::vector<short> front()\r
-       {\r
-               return chunks_.front();\r
+               return result;\r
        }\r
 \r
-       void pop()\r
+       void restart()\r
        {\r
-               ++frame_number_;\r
-               chunks_.pop_back();\r
+               restarting_ = true;\r
        }\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
-void audio_decoder::push(const std::shared_ptr<AVPacket>& audio_packet){impl_->push(std::move(audio_packet));}\r
-bool audio_decoder::empty() const {return impl_->empty();}\r
-std::vector<short> audio_decoder::front() {return impl_->front();}\r
-void audio_decoder::pop(){impl_->pop();}\r
-size_t audio_decoder::frame_number() const{return impl_->frame_number_;}\r
+audio_decoder::audio_decoder(input& input, const core::video_format_desc& format_desc) : impl_(new implementation(input, format_desc)){}\r
+std::deque<std::pair<int, std::vector<short>>> audio_decoder::receive(){return impl_->receive();}\r
+void audio_decoder::restart(){impl_->restart();}\r
 }
\ No newline at end of file
index 5d87dac72902cc63e93e179d7d58016128247d73..fe47799591bcd96dcc46c7fe7fb82f926bfcf9e4 100644 (file)
@@ -19,6 +19,8 @@
 */\r
 #pragma once\r
 \r
+#include "../input.h"\r
+\r
 #include <core/video_format.h>\r
 \r
 #include <tbb/cache_aligned_allocator.h>\r
@@ -35,14 +37,11 @@ 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(input& input, const core::video_format_desc& format_desc);\r
 \r
-       void push(const std::shared_ptr<AVPacket>& audio_packet);\r
-       std::vector<short> front();\r
-       void pop();     \r
-       bool empty() const;\r
+       std::deque<std::pair<int, std::vector<short>>> receive();\r
 \r
-       size_t frame_number() const;\r
+       void restart();\r
 private:\r
        struct implementation;\r
        std::shared_ptr<implementation> impl_;\r
index 73a3d763c984463c1d9306fe4436d5924e01a632..1ae521869c39449fd9c63c155aa478a9562922ff 100644 (file)
@@ -58,6 +58,9 @@ struct ffmpeg_producer : public core::frame_producer
        input                                                                   input_; \r
        std::unique_ptr<video_decoder>                  video_decoder_;\r
        std::unique_ptr<audio_decoder>                  audio_decoder_;\r
+\r
+       std::deque<std::pair<int, std::vector<short>>> audio_chunks_;\r
+       std::deque<std::pair<int, safe_ptr<core::write_frame>>> video_frames_;\r
 public:\r
        explicit ffmpeg_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::wstring& filename, bool loop, int start, int length) \r
                : filename_(filename)\r
@@ -75,13 +78,13 @@ public:
                        CASPAR_LOG(warning) << print() << L" Invalid framerate detected. This may cause distorted audio during playback. frame-time: " << frame_time;\r
                \r
                video_decoder_.reset(input_.get_video_codec_context() ? \r
-                       new video_decoder(*input_.get_video_codec_context(), frame_factory) : nullptr);\r
+                       new video_decoder(input_, frame_factory) : nullptr);\r
                        \r
                audio_decoder_.reset(input_.get_audio_codec_context() ? \r
-                       new audio_decoder(*input_.get_audio_codec_context(), frame_factory->get_video_format_desc()) : nullptr);                \r
+                       new audio_decoder(input_, frame_factory->get_video_format_desc()) : nullptr);           \r
                                        \r
                // Fill buffers.\r
-               decode_next_packets();\r
+               decode_packets();\r
        }\r
 \r
        virtual safe_ptr<core::basic_frame> receive()\r
@@ -100,75 +103,62 @@ public:
                return L"ffmpeg[" + boost::filesystem::wpath(filename_).filename() + L"]";\r
        }\r
 \r
-       void decode_next_packets()\r
+       void decode_packets()\r
        {\r
                tbb::parallel_invoke\r
                (\r
                        [&]\r
                        {\r
-                               if(!video_decoder_)\r
-                                       return;\r
-\r
-                               std::shared_ptr<AVPacket> pkt;\r
-                               for(int n = 0; n < 16 && video_decoder_->empty() && input_.try_pop_video_packet(pkt); ++n)                              \r
-                                       video_decoder_->push(pkt);                              \r
+                               if(video_decoder_ && video_frames_.empty())\r
+                                       video_frames_ = video_decoder_->receive();              \r
                        }, \r
                        [&]\r
                        {\r
-                               if(!audio_decoder_)\r
-                                       return;\r
-                               \r
-                               std::shared_ptr<AVPacket> pkt;  \r
-                               for(int n = 0; n < 16 && audio_decoder_->empty() && input_.try_pop_audio_packet(pkt); ++n)                              \r
-                                       audio_decoder_->push(pkt);                              \r
+                               if(audio_decoder_ && audio_chunks_.empty())\r
+                                       audio_chunks_ = audio_decoder_->receive();                      \r
                        }\r
                );\r
                \r
-               // Sync up audio with video on start. Last frame sometimes have more samples than required. Remove those.\r
-               if(audio_decoder_ && video_decoder_ && video_decoder_->frame_number() == 0)\r
+               if(audio_decoder_ && video_decoder_ && !video_frames_.empty() && !audio_chunks_.empty() &&\r
+                  video_frames_.front().first == 0 && audio_chunks_.front().first != 0)\r
                {\r
-                       std::shared_ptr<AVPacket> pkt;\r
-                       while(audio_decoder_->frame_number() > 0 && input_.try_pop_audio_packet(pkt))\r
-                       {\r
-                               audio_decoder_->push(pkt);\r
-                               if(audio_decoder_->frame_number() > 0)\r
-                                       audio_decoder_->pop();\r
-                       }\r
-                       \r
-                       for(int n = 0; n < 16 && audio_decoder_->empty() && input_.try_pop_audio_packet(pkt); ++n)                              \r
-                               audio_decoder_->push(pkt);              \r
+                       audio_decoder_->restart();\r
+                       audio_chunks_ = audio_decoder_->receive();              \r
                }\r
+               \r
+               CASPAR_ASSERT(!(video_decoder_ && audio_decoder_ && !video_frames_.empty() && !audio_chunks_.empty()) ||\r
+                                     video_frames_.front().first == audio_chunks_.front().first);\r
        }\r
 \r
        safe_ptr<core::basic_frame> decode_frame()\r
        {\r
-               decode_next_packets();\r
+               decode_packets();\r
 \r
-               if(video_decoder_ && !video_decoder_->empty() && audio_decoder_ && !audio_decoder_->empty())\r
+               if(video_decoder_ && audio_decoder_ && !video_frames_.empty() && !audio_chunks_.empty())\r
                {\r
-                       auto frame = std::move(video_decoder_->front());                                \r
-                       video_decoder_->pop();\r
+                       auto frame = std::move(video_frames_.front().second);                           \r
+                       video_frames_.pop_front();\r
                                \r
-                       frame->audio_data() = std::move(audio_decoder_->front());\r
-                       audio_decoder_->pop();\r
+                       frame->audio_data() = std::move(audio_chunks_.front().second);\r
+                       audio_chunks_.pop_front();\r
                        \r
                        return frame;\r
                }\r
-               else if(video_decoder_ && !video_decoder_->empty() && !audio_decoder_)\r
+               else if(video_decoder_ && !audio_decoder_ && !video_frames_.empty())\r
                {\r
-                       auto frame = std::move(video_decoder_->front());                                \r
-                       video_decoder_->pop();\r
+                       auto frame = std::move(video_frames_.front().second);                           \r
+                       video_frames_.pop_front();\r
                        frame->get_audio_transform().set_has_audio(false);      \r
                        \r
                        return frame;\r
                }\r
-               else if(audio_decoder_ && !audio_decoder_->empty() && !video_decoder_)\r
+               else if(audio_decoder_ && !video_decoder_ && !audio_chunks_.empty())\r
                {\r
                        auto frame = frame_factory_->create_frame(this, 1, 1);\r
                        std::fill(frame->image_data().begin(), frame->image_data().end(), 0);\r
                                \r
-                       frame->audio_data() = std::move(audio_decoder_->front());\r
-                       audio_decoder_->pop();\r
+                       frame->audio_data() = std::move(audio_chunks_.front().second);\r
+                       audio_chunks_.pop_front();\r
 \r
                        return frame;\r
                }\r
index ce4b1b47ff42329948e57f6036972f3ae139a2be..d0f3983b42b73980e9fc1a01fd7d92c51ba7fd60 100644 (file)
@@ -61,33 +61,28 @@ public:
        {\r
                buffer_.set_capacity(PACKET_BUFFER_COUNT);\r
        }\r
-\r
-       ~stream()\r
-       {\r
-               CASPAR_LOG(trace) << "##: " << size();\r
-       }\r
-\r
+       \r
        int open(std::shared_ptr<AVFormatContext>& fctx, AVMediaType media_type)\r
        {               \r
                const auto streams = boost::iterator_range<AVStream**>(fctx->streams, fctx->streams+fctx->nb_streams);\r
-               const auto stream = boost::find_if(streams, [&](AVStream* stream) \r
+               const auto it = boost::find_if(streams, [&](AVStream* stream) \r
                {\r
                        return stream && stream->codec->codec_type == media_type;\r
                });\r
                \r
-               if(stream == streams.end()) \r
+               if(it == streams.end()) \r
                        return AVERROR_STREAM_NOT_FOUND;\r
                \r
-               auto codec = avcodec_find_decoder((*stream)->codec->codec_id);                  \r
+               auto codec = avcodec_find_decoder((*it)->codec->codec_id);                      \r
                if(!codec)\r
                        return AVERROR_DECODER_NOT_FOUND;\r
                        \r
-               index_ = (*stream)->index;\r
+               index_ = (*it)->index;\r
 \r
-               int errn = tbb_avcodec_open((*stream)->codec, codec);\r
+               int errn = tbb_avcodec_open((*it)->codec, codec);\r
                if(errn >= 0)\r
                {\r
-                       ctx_.reset((*stream)->codec, tbb_avcodec_close);\r
+                       ctx_.reset((*it)->codec, tbb_avcodec_close);\r
 \r
                        // Some files give an invalid time_base numerator, try to fix it.\r
                        if(ctx_ && ctx_->time_base.num == 1)\r
@@ -216,12 +211,18 @@ public:
                \r
        bool try_pop_video_packet(std::shared_ptr<AVPacket>& packet)\r
        {\r
-               return video_stream_.try_pop(packet);\r
+               bool result = video_stream_.try_pop(packet);\r
+               if(result && !packet)\r
+                       graph_->add_tag("video-input-buffer");\r
+               return result;\r
        }\r
 \r
        bool try_pop_audio_packet(std::shared_ptr<AVPacket>& packet)\r
        {       \r
-               return audio_stream_.try_pop(packet);\r
+               bool result = audio_stream_.try_pop(packet);\r
+               if(result && !packet)\r
+                       graph_->add_tag("audio-input-buffer");\r
+               return result;\r
        }\r
 \r
        double fps()\r
index 53a115e139dee1e3a29410962b507051192602aa..d768059c54ed0fe588cdc62d258fd919ef0f09d2 100644 (file)
@@ -116,7 +116,8 @@ core::pixel_format_desc get_pixel_format_desc(PixelFormat pix_fmt, size_t width,
 }\r
 \r
 struct video_decoder::implementation : boost::noncopyable\r
-{      \r
+{\r
+       input& input_;\r
        std::shared_ptr<SwsContext>                                     sws_context_;\r
        const std::shared_ptr<core::frame_factory>      frame_factory_;\r
        AVCodecContext&                                                         codec_context_;\r
@@ -124,13 +125,13 @@ 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
-               : frame_factory_(frame_factory)\r
-               , codec_context_(codec_context)\r
+       explicit implementation(input& input, const safe_ptr<core::frame_factory>& frame_factory) \r
+               : input_(input)\r
+               , frame_factory_(frame_factory)\r
+               , codec_context_(*input_.get_video_codec_context())\r
                , width_(codec_context_.width)\r
                , height_(codec_context_.height)\r
                , pix_fmt_(codec_context_.pix_fmt)\r
@@ -151,13 +152,26 @@ public:
                }\r
        }\r
 \r
-       void push(const std::shared_ptr<AVPacket>& video_packet)\r
-       {                               \r
+       std::deque<std::pair<int, safe_ptr<core::write_frame>>> receive()\r
+       {\r
+               std::deque<std::pair<int, safe_ptr<core::write_frame>>> result;\r
+               \r
+               std::shared_ptr<AVPacket> pkt;\r
+               for(int n = 0; n < 32 && result.empty() && input_.try_pop_video_packet(pkt); ++n)       \r
+                       result = decode(pkt);\r
+\r
+               return result;\r
+       }\r
+\r
+       std::deque<std::pair<int, safe_ptr<core::write_frame>>> decode(const std::shared_ptr<AVPacket>& video_packet)\r
+       {                       \r
+               std::deque<std::pair<int, safe_ptr<core::write_frame>>> result;\r
+\r
                if(!video_packet)\r
                {       \r
                        avcodec_flush_buffers(&codec_context_);\r
                        frame_number_ = 0;\r
-                       return;\r
+                       return result;\r
                }\r
 \r
                safe_ptr<AVFrame> decoded_frame(avcodec_alloc_frame(), av_free);\r
@@ -175,7 +189,9 @@ public:
                }\r
                \r
                if(frame_finished != 0)         \r
-                       frames_.push_back(make_write_frame(decoded_frame));\r
+                       result.push_back(std::make_pair(frame_number_++, make_write_frame(decoded_frame)));\r
+\r
+               return result;\r
        }\r
 \r
        safe_ptr<core::write_frame> make_write_frame(safe_ptr<AVFrame> decoded_frame)\r
@@ -214,29 +230,9 @@ 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
-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
+video_decoder::video_decoder(input& input, const safe_ptr<core::frame_factory>& frame_factory) : impl_(new implementation(input, frame_factory)){}\r
+std::deque<std::pair<int, safe_ptr<core::write_frame>>> video_decoder::receive(){return impl_->receive();}\r
 \r
 }
\ No newline at end of file
index e7b1ad5b3f3f80f86734e3d0940e44befd895762..e3bdf0d1815065c75d3d998a26b7fd61d89ac5da 100644 (file)
@@ -21,8 +21,7 @@
 \r
 #include <common/memory/safe_ptr.h>\r
 \r
-struct AVCodecContext;\r
-\r
+#include "../input.h"\r
 namespace caspar {\r
        \r
 namespace core {\r
@@ -33,14 +32,8 @@ 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
-       void push(const std::shared_ptr<AVPacket>& video_packet);       \r
-\r
-       bool empty() const;\r
-       safe_ptr<core::write_frame> front();\r
-       void pop();\r
-       \r
-       size_t frame_number() const;\r
+       explicit video_decoder(input& input, const safe_ptr<core::frame_factory>& frame_factory);\r
+       std::deque<std::pair<int, safe_ptr<core::write_frame>>> receive();      \r
 \r
 private:\r
        struct implementation;\r
index 203890da27663e554a945107ccfb66ee37b0531a..f88bac0c4003268699466d4100bfa22ae125d4f6 100644 (file)
@@ -78,7 +78,7 @@ void thread_free(AVCodecContext* s)
                return;\r
 \r
        s->thread_opaque = nullptr;\r
-\r
+       \r
        CASPAR_LOG(info) << "Released ffmpeg tbb context.";\r
 }\r
 \r
index 757e8f49e64838a8e53933b7aff99be4cc42419d..c260e020399475c53e7ac70272005fbf95a332b3 100644 (file)
@@ -186,16 +186,19 @@ int main(int argc, wchar_t* argv[])
                        std::getline(std::wcin, wcmd); // TODO: It's blocking...\r
 \r
                        is_running = wcmd != L"exit" && wcmd != L"q";\r
-                       if(wcmd.substr(0, 2) == L"12")\r
+                       if(wcmd.substr(0, 2) == L"11")\r
                        {\r
-                               wcmd = L"LOADBG 1-1 A LOOP \r\nPLAY 1-1\r\n";\r
-                               amcp.Parse(wcmd.c_str(), wcmd.length(), dummy);\r
-                               wcmd = L"LOADBG 1-2 DV LOOP AUTOPLAY\r\nnPLAY 1-1\r\n";\r
-                               amcp.Parse(wcmd.c_str(), wcmd.length(), dummy);\r
-                               wcmd = L"MIXER 1-1 VIDEO FIX_RECT 0.0 0.0 0.5 0.5\r\n";\r
-                               amcp.Parse(wcmd.c_str(), wcmd.length(), dummy);\r
-                               wcmd = L"MIXER 1-2 VIDEO FIX_RECT 0.5 0.0 0.5 0.5\r\n";\r
-                               amcp.Parse(wcmd.c_str(), wcmd.length(), dummy);\r
+                               auto file = wcmd.substr(3, wcmd.length()-1);\r
+                               wcmd = L"MIXER 1 VIDEO GRID 3";\r
+                               wcmd += L"\r\nPLAY 1-1 " + file + L" SLIDE 100 LOOP";\r
+                               wcmd += L"\r\nPLAY 1-2 " + file + L" SLIDE 100 LOOP";\r
+                               wcmd += L"\r\nPLAY 1-3 " + file + L" SLIDE 100 LOOP";\r
+                               wcmd += L"\r\nPLAY 1-4 " + file + L" SLIDE 100 LOOP";\r
+                               wcmd += L"\r\nPLAY 1-5 " + file + L" SLIDE 100 LOOP";\r
+                               wcmd += L"\r\nPLAY 1-6 " + file + L" SLIDE 100 LOOP";\r
+                               wcmd += L"\r\nPLAY 1-7 " + file + L" SLIDE 100 LOOP";\r
+                               wcmd += L"\r\nPLAY 1-8 " + file + L" SLIDE 100 LOOP";\r
+                               wcmd += L"\r\nPLAY 1-9 " + file + L" SLIDE 100 LOOP";\r
                        }\r
                        else if(wcmd.substr(0, 2) == L"10")\r
                                wcmd = L"MIXER 1-1 VIDEO CLIP_RECT 0.4 0.4 0.5 0.5";\r