]> git.sesse.net Git - casparcg/commitdiff
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches...
authorRonag <Ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Wed, 3 Aug 2011 20:19:31 +0000 (20:19 +0000)
committerRonag <Ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Wed, 3 Aug 2011 20:19:31 +0000 (20:19 +0000)
modules/ffmpeg/producer/ffmpeg_producer.cpp
modules/ffmpeg/producer/frame_muxer.cpp
modules/ffmpeg/producer/frame_muxer.h
modules/ffmpeg/producer/video/video_decoder.cpp

index 529674b0b71ecf884cab22158105fbb8cd13a298..7af79872217e09d58230b3c3434821b240be5d64 100644 (file)
@@ -132,7 +132,7 @@ public:
 \r
        void decode_frame()\r
        {\r
-               for(int n = 0; n < 32 && ((muxer_.video_frames() < 2 && !video_decoder_.ready()) ||     (muxer_.audio_chunks() < 2 && !audio_decoder_.ready())); ++n) \r
+               for(int n = 0; n < 32 && ((!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
@@ -148,12 +148,12 @@ public:
                tbb::parallel_invoke(\r
                [&]\r
                {\r
-                       if(muxer_.video_frames() < 2)\r
+                       if(!muxer_.video_ready())\r
                                video_frames = video_decoder_.poll();\r
                },\r
                [&]\r
                {\r
-                       if(muxer_.audio_chunks() < 2)\r
+                       if(!muxer_.audio_ready())\r
                                audio_samples = audio_decoder_.poll();\r
                });\r
                \r
index 1d023230fc57c5b4d620228eaaec25f7d917c5b5..0ad91feccf80e13f4125d1d6d5378185483de5c6 100644 (file)
@@ -99,19 +99,22 @@ display_mode::type get_display_mode(const core::video_mode::type in_mode, double
 \r
 struct frame_muxer::implementation : boost::noncopyable\r
 {      \r
-       std::queue<safe_ptr<write_frame>>       video_frames_;\r
-       std::vector<int16_t>                            audio_samples_;\r
-       std::deque<safe_ptr<basic_frame>>       frame_buffer_;\r
-       display_mode::type                                      display_mode_;\r
-       const double                                            in_fps_;\r
-       const video_format_desc                         format_desc_;\r
-       bool                                                            auto_mode_;\r
-\r
-       size_t                                                          audio_sample_count_;\r
-       size_t                                                          video_frame_count_;\r
-\r
-       std::unique_ptr<filter>                         filter_;\r
-       safe_ptr<core::frame_factory>           frame_factory_;\r
+       std::deque<std::queue<safe_ptr<write_frame>>>   video_streams_;\r
+       std::deque<std::vector<int16_t>>                                audio_streams_;\r
+       std::deque<safe_ptr<basic_frame>>                               frame_buffer_;\r
+       display_mode::type                                                              display_mode_;\r
+       const double                                                                    in_fps_;\r
+       const video_format_desc                                                 format_desc_;\r
+       bool                                                                                    auto_mode_;\r
+\r
+       size_t                                                                                  audio_sample_count_;\r
+       size_t                                                                                  video_frame_count_;\r
+               \r
+       size_t                                                                                  processed_audio_sample_count_;\r
+       size_t                                                                                  processed_video_frame_count_;\r
+\r
+       std::unique_ptr<filter>                                                 filter_;\r
+       safe_ptr<core::frame_factory>                                   frame_factory_;\r
                \r
        implementation(double in_fps, const video_format_desc& format_desc, const safe_ptr<core::frame_factory>& frame_factory)\r
                : display_mode_(display_mode::invalid)\r
@@ -120,7 +123,11 @@ struct frame_muxer::implementation : boost::noncopyable
                , auto_mode_(env::properties().get("configuration.auto-mode", false))\r
                , audio_sample_count_(0)\r
                , video_frame_count_(0)\r
+               , processed_audio_sample_count_(0)\r
+               , processed_video_frame_count_(0)\r
                , frame_factory_(frame_factory)\r
+               , video_streams_(1)\r
+               , audio_streams_(1)\r
        {\r
        }\r
 \r
@@ -128,14 +135,19 @@ struct frame_muxer::implementation : boost::noncopyable
        {               \r
                if(!video_frame)\r
                {       \r
-                       CASPAR_LOG(debug) << L"video-frame-count: " << video_frame_count_;\r
+                       CASPAR_LOG(debug) << L"video-frame-count: " << static_cast<float>(video_frame_count_) << L":" << processed_video_frame_count_;\r
                        video_frame_count_ = 0;\r
+                       processed_video_frame_count_ = 0;\r
+                       video_streams_.push_back(std::queue<safe_ptr<write_frame>>());\r
                        return;\r
                }\r
                \r
                if(display_mode_ == display_mode::invalid)\r
+               {\r
                        display_mode_ = auto_mode_ ? get_display_mode(video_frame->get_type(), in_fps_, format_desc_.mode, format_desc_.fps) : display_mode::simple;\r
-                       \r
+                       CASPAR_LOG(info) << L"display_mode: " << display_mode::print(display_mode_);\r
+               }               \r
+\r
                ++video_frame_count_;\r
 \r
                // Fix field-order if needed\r
@@ -144,7 +156,7 @@ struct frame_muxer::implementation : boost::noncopyable
                else if(video_frame->get_type() == core::video_mode::upper && format_desc_.mode == core::video_mode::lower)\r
                        video_frame->get_image_transform().set_fill_translation(0.0f, -0.5/static_cast<double>(video_frame->get_pixel_format_desc().planes[0].height));\r
 \r
-               video_frames_.push(make_safe(video_frame));\r
+               video_streams_.back().push(make_safe(video_frame));\r
 \r
                process(frame_buffer_);\r
 \r
@@ -155,30 +167,24 @@ struct frame_muxer::implementation : boost::noncopyable
        {\r
                if(!audio_samples)      \r
                {\r
-                       auto truncate = audio_sample_count_ % format_desc_.audio_samples_per_frame;\r
-                       if(truncate > 0)\r
-                       {\r
-                               audio_samples_.erase(audio_samples_.end() - truncate, audio_samples_.end());\r
-                               CASPAR_LOG(info) << L"frame_muxer: Truncating " << truncate << L" audio samples.";\r
-                       }\r
-\r
-                       CASPAR_LOG(debug) << L"audio-chunk-count: " << audio_sample_count_/format_desc_.audio_samples_per_frame;\r
+                       CASPAR_LOG(debug) << L"audio-chunk-count: " << static_cast<float>(audio_sample_count_)/format_desc_.audio_samples_per_frame << L":" << processed_audio_sample_count_/format_desc_.audio_samples_per_frame;\r
+                       CASPAR_LOG(debug) << L"audio-sample-count: " << audio_sample_count_ << L":" << processed_audio_sample_count_;\r
+                       audio_streams_.push_back(std::vector<int16_t>());\r
+                       processed_audio_sample_count_ = 0;\r
                        audio_sample_count_ = 0;\r
                        return;\r
                }\r
 \r
                audio_sample_count_ += audio_samples->size();\r
 \r
-               boost::range::push_back(audio_samples_, *audio_samples);\r
-               std::deque<safe_ptr<basic_frame>> frames;\r
-               process(frames);\r
-               boost::range::push_back(frame_buffer_, frames);\r
+               boost::range::push_back(audio_streams_.back(), *audio_samples);\r
+               process(frame_buffer_);\r
        }\r
 \r
        safe_ptr<basic_frame> pop()\r
        {               \r
                auto frame = frame_buffer_.front();\r
-               frame_buffer_.pop_front();\r
+               frame_buffer_.pop_front();              \r
                return frame;\r
        }\r
 \r
@@ -189,27 +195,62 @@ struct frame_muxer::implementation : boost::noncopyable
 \r
        safe_ptr<core::write_frame> pop_video()\r
        {\r
-               auto frame = video_frames_.front();\r
-               video_frames_.pop();\r
+               auto frame = video_streams_.front().front();\r
+               video_streams_.front().pop();\r
+\r
+               ++processed_video_frame_count_;\r
+\r
                return frame;\r
        }\r
 \r
        std::vector<int16_t> pop_audio()\r
        {\r
-               CASPAR_VERIFY(audio_samples_.size() >= format_desc_.audio_samples_per_frame);\r
+               CASPAR_VERIFY(audio_streams_.front().size() >= format_desc_.audio_samples_per_frame);\r
 \r
-               auto begin = audio_samples_.begin();\r
+               auto begin = audio_streams_.front().begin();\r
                auto end   = begin + format_desc_.audio_samples_per_frame;\r
 \r
                auto samples = std::vector<int16_t>(begin, end);\r
-               audio_samples_.erase(begin, end);\r
+               audio_streams_.front().erase(begin, end);\r
+\r
+               processed_audio_sample_count_ += format_desc_.audio_samples_per_frame;\r
 \r
                return samples;\r
        }\r
+\r
+       bool video_ready() const\r
+       {\r
+               return video_frames() > 1 && video_streams_.size() >= audio_streams_.size();\r
+       }\r
+       \r
+       bool audio_ready() const\r
+       {\r
+               return audio_chunks() > 1 && audio_streams_.size() >= video_streams_.size();\r
+       }\r
+\r
+       size_t video_frames() const\r
+       {\r
+               return video_streams_.back().size();\r
+       }\r
+\r
+       size_t audio_chunks() const\r
+       {\r
+               return audio_streams_.back().size() / format_desc_.audio_samples_per_frame;\r
+       }\r
        \r
        void process(std::deque<safe_ptr<basic_frame>>& dest)\r
        {\r
-               if(video_frames_.empty() || audio_samples_.size() < format_desc_.audio_samples_per_frame)\r
+               if(video_streams_.size() > 1 && audio_streams_.size() > 1 &&\r
+                       (video_streams_.front().empty() || audio_streams_.front().empty()))\r
+               {\r
+                       if(!video_streams_.front().empty() || !audio_streams_.front().empty())\r
+                               CASPAR_LOG(debug) << " Truncating: " << video_streams_.front().size() << L" video-frames, " << audio_streams_.front().size() << L" audio-samples.";\r
+\r
+                       video_streams_.pop_front();\r
+                       audio_streams_.pop_front();\r
+               }\r
+\r
+               if(video_streams_.front().empty() || audio_streams_.front().size() < format_desc_.audio_samples_per_frame)\r
                        return;\r
                \r
                switch(display_mode_)\r
@@ -226,11 +267,11 @@ struct frame_muxer::implementation : boost::noncopyable
 \r
        void simple(std::deque<safe_ptr<basic_frame>>& dest)\r
        {\r
-               if(video_frames_.empty() || audio_samples_.size() < format_desc_.audio_samples_per_frame)\r
+               if(video_streams_.front().empty() || audio_streams_.front().size() < format_desc_.audio_samples_per_frame)\r
                        return;\r
                \r
-               if(video_frames_.front()->get_type() != core::video_mode::progressive && format_desc_.mode != core::video_mode::progressive &&\r
-                       video_frames_.front()->get_pixel_format_desc().planes.at(0).height != format_desc_.height )\r
+               if(video_streams_.front().front()->get_type() != core::video_mode::progressive && format_desc_.mode != core::video_mode::progressive &&\r
+                       video_streams_.front().front()->get_pixel_format_desc().planes.at(0).height != format_desc_.height )\r
                { // The frame will most likely be scaled, we need to deinterlace->reinterlace\r
                        if(!filter_)\r
                                filter_.reset(new filter(L"YADIF=1:-1"));\r
@@ -262,7 +303,7 @@ struct frame_muxer::implementation : boost::noncopyable
 \r
        void duplicate(std::deque<safe_ptr<basic_frame>>& dest)\r
        {               \r
-               if(video_frames_.empty() || audio_samples_.size()/2 < format_desc_.audio_samples_per_frame)\r
+               if(video_streams_.front().empty() || audio_streams_.front().size()/2 < format_desc_.audio_samples_per_frame)\r
                        return;\r
 \r
                auto frame = pop_video();\r
@@ -280,21 +321,21 @@ struct frame_muxer::implementation : boost::noncopyable
 \r
        void half(std::deque<safe_ptr<basic_frame>>& dest)\r
        {       \r
-               if(video_frames_.size() < 2 || audio_samples_.size() < format_desc_.audio_samples_per_frame)\r
+               if(video_streams_.front().size() < 2 || audio_streams_.front().size() < format_desc_.audio_samples_per_frame)\r
                        return;\r
                                                \r
                auto frame1 = pop_video();\r
                frame1->commit();\r
                frame1->audio_data() = pop_audio();\r
                                \r
-               video_frames_.pop(); // Throw away\r
+               video_streams_.front().pop(); // Throw away\r
 \r
                dest.push_back(frame1);\r
        }\r
        \r
        void interlace(std::deque<safe_ptr<basic_frame>>& dest)\r
        {               \r
-               if(video_frames_.size() < 2 || audio_samples_.size() < format_desc_.audio_samples_per_frame)\r
+               if(video_streams_.front().size() < 2 || audio_streams_.front().size() < format_desc_.audio_samples_per_frame)\r
                        return;\r
                \r
                auto frame1 = pop_video();\r
@@ -309,7 +350,7 @@ struct frame_muxer::implementation : boost::noncopyable
                \r
        void deinterlace_bob(std::deque<safe_ptr<basic_frame>>& dest)\r
        {\r
-               if(video_frames_.empty() || audio_samples_.size()/2 < format_desc_.audio_samples_per_frame)\r
+               if(video_streams_.front().empty() || audio_streams_.front().size()/2 < format_desc_.audio_samples_per_frame)\r
                        return;\r
 \r
                if(!filter_)\r
@@ -336,7 +377,7 @@ struct frame_muxer::implementation : boost::noncopyable
 \r
        void deinterlace(std::deque<safe_ptr<basic_frame>>& dest)\r
        {\r
-               if(video_frames_.empty() || audio_samples_.size() < format_desc_.audio_samples_per_frame)\r
+               if(video_streams_.front().empty() || audio_streams_.front().size() < format_desc_.audio_samples_per_frame)\r
                        return;\r
 \r
                if(!filter_)\r
@@ -364,7 +405,7 @@ void frame_muxer::push(const std::shared_ptr<std::vector<int16_t>>& audio_sample
 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
-size_t frame_muxer::video_frames() const{return impl_->video_frames_.size();}\r
-size_t frame_muxer::audio_chunks() const{return impl_->audio_samples_.size() / impl_->format_desc_.audio_samples_per_frame;}\r
+bool frame_muxer::video_ready() const{return impl_->video_ready();}\r
+bool frame_muxer::audio_ready() const{return impl_->audio_ready();}\r
 \r
 }
\ No newline at end of file
index d5640c497decfe6363fc6fe5f6bfb9c1939648da..5acccd0cde01232155082613c4d8a8bd53caf4cd 100644 (file)
@@ -26,8 +26,8 @@ public:
        void push(const std::shared_ptr<core::write_frame>& video_frame);\r
        void push(const std::shared_ptr<std::vector<int16_t>>& audio_samples);\r
        \r
-       size_t video_frames() const;\r
-       size_t audio_chunks() const;\r
+       bool video_ready() const;\r
+       bool audio_ready() const;\r
 \r
        size_t size() const;\r
        bool empty() const;\r
index 1ed6fa61e74d61d95ac3850f91bb57d325b6e417..bc51db9880a7c621dd7db7d89396e1465befef09 100644 (file)
@@ -124,6 +124,8 @@ public:
                        std::shared_ptr<AVFrame> frame;\r
 \r
                        auto packet = packet_buffer_.front();\r
+\r
+                       bool eof = false;\r
                \r
                        if(packet)\r
                        {\r
@@ -135,7 +137,10 @@ public:
                        {\r
                                if(codec_context_->codec->capabilities | CODEC_CAP_DELAY)\r
                                {\r
-                                       AVPacket pkt = {0};\r
+                                       AVPacket pkt;\r
+                                       av_init_packet(&pkt);\r
+                                       pkt.data = nullptr;\r
+                                       pkt.size = 0;\r
                                        frame = decode(pkt);\r
                                }\r
 \r
@@ -143,9 +148,12 @@ public:
                                {                                       \r
                                        packet_buffer_.pop();\r
                                        avcodec_flush_buffers(codec_context_.get());\r
+                                       eof = true;\r
                                }\r
                        }\r
 \r
+                       CASPAR_VERIFY(!frame || frame->repeat_pict == 0);\r
+\r
                        std::vector<safe_ptr<AVFrame>> av_frames;\r
 \r
                        if(filter_)                     \r
@@ -156,7 +164,7 @@ public:
                        BOOST_FOREACH(auto& frame, av_frames)\r
                                result.push_back(make_write_frame(this, frame, frame_factory_));\r
 \r
-                       if(!packet)\r
+                       if(eof)\r
                                result.push_back(nullptr);\r
                }\r
                \r
@@ -178,9 +186,12 @@ public:
                                boost::errinfo_api_function("avcodec_decode_video") <<\r
                                boost::errinfo_errno(AVUNERROR(ret)));\r
                }\r
-\r
-               pkt.size -= ret;\r
-               pkt.data += ret;\r
+               \r
+               // if a decoder consumes less then the whole packet then something is wrong\r
+               // that might be just harmless padding at the end or a problem with the\r
+               // AVParser or demuxer which puted more then one frame in a AVPacket\r
+               pkt.data = nullptr;\r
+               pkt.size = 0;\r
 \r
                if(frame_finished != 0) \r
                {\r