]> git.sesse.net Git - casparcg/blobdiff - modules/ffmpeg/producer/muxer/frame_muxer.cpp
* Fixed bug where a new audio stream was created in the audio mixer for each frame...
[casparcg] / modules / ffmpeg / producer / muxer / frame_muxer.cpp
index 5e9ac89cbe7da71b7c0b743e37d95fc07db7a5ba..7cb40f809ca76da73c952dac9422906b9833b464 100644 (file)
@@ -32,6 +32,7 @@
 #include <core/frame/pixel_format.h>
 #include <core/frame/frame_factory.h>
 #include <core/frame/frame.h>
+#include <core/frame/audio_channel_layout.h>
 
 #include <common/env.h>
 #include <common/except.h>
@@ -63,32 +64,51 @@ extern "C"
 using namespace caspar::core;
 
 namespace caspar { namespace ffmpeg {
+
+bool is_frame_format_changed(const AVFrame& lhs, const AVFrame& rhs)
+{
+       if (lhs.format != rhs.format)
+               return true;
+
+       for (int i = 0; i < AV_NUM_DATA_POINTERS; ++i)
+       {
+               if (lhs.linesize[i] != rhs.linesize[i])
+                       return true;
+       }
+
+       return false;
+}
        
 struct frame_muxer::impl : boost::noncopyable
 {      
        std::queue<core::mutable_frame>                                 video_stream_;
-       core::audio_buffer                                                              audio_stream_;
+       core::mutable_audio_buffer                                              audio_stream_;
        std::queue<draw_frame>                                                  frame_buffer_;
-       display_mode                                                                    display_mode_;
+       display_mode                                                                    display_mode_                   = display_mode::invalid;
        const double                                                                    in_fps_;
        const video_format_desc                                                 format_desc_;
+       audio_channel_layout                                                    channel_layout_;
        
-       std::vector<int>                                                                audio_cadence_;
+       std::vector<int>                                                                audio_cadence_                  = format_desc_.audio_cadence;
                        
        spl::shared_ptr<core::frame_factory>                    frame_factory_;
-       
+       std::shared_ptr<AVFrame>                                                previous_frame_;
+
        std::unique_ptr<filter>                                                 filter_;
        const std::wstring                                                              filter_str_;
-       bool                                                                                    force_deinterlacing_;
+       bool                                                                                    force_deinterlacing_    = env::properties().get(L"configuration.force-deinterlace", true);
                
-       impl(double in_fps, const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::wstring& filter_str)
-               : display_mode_(display_mode::invalid)
-               , in_fps_(in_fps)
+       impl(
+                       double in_fps,
+                       const spl::shared_ptr<core::frame_factory>& frame_factory,
+                       const core::video_format_desc& format_desc,
+                       const core::audio_channel_layout& channel_layout,
+                       const std::wstring& filter_str)
+               : in_fps_(in_fps)
                , format_desc_(format_desc)
-               , audio_cadence_(format_desc_.audio_cadence)
+               , channel_layout_(channel_layout)
                , frame_factory_(frame_factory)
                , filter_str_(filter_str)
-               , force_deinterlacing_(env::properties().get(L"configuration.force-deinterlace", true))
        {               
                // Note: Uses 1 step rotated cadence for 1001 modes (1602, 1602, 1601, 1602, 1601)
                // This cadence fills the audio mixer most optimally.
@@ -100,9 +120,16 @@ struct frame_muxer::impl : boost::noncopyable
                if(!video)
                        return;
 
+               if (previous_frame_ && video->data[0] && is_frame_format_changed(*previous_frame_, *video))
+               {
+                       // Fixes bug where avfilter crashes server on some DV files (starts in YUV420p but changes to YUV411p after the first frame).
+                       CASPAR_LOG(info) << L"[frame_muxer] Frame format has changed. Resetting display mode.";
+                       display_mode_ = display_mode::invalid;
+               }
+
                if(!video->data[0])
                {
-                       auto empty_frame = frame_factory_->create_frame(this, core::pixel_format_desc(core::pixel_format::invalid));
+                       auto empty_frame = frame_factory_->create_frame(this, core::pixel_format_desc(core::pixel_format::invalid), channel_layout_);
                        video_stream_.push(std::move(empty_frame));
                        display_mode_ = display_mode::simple;
                }
@@ -112,13 +139,14 @@ struct frame_muxer::impl : boost::noncopyable
                                update_display_mode(video);
                                
                        filter_->push(video);
-                       for (auto& av_frame : filter_->poll_all())                      
-                               video_stream_.push(make_frame(this, av_frame, format_desc_.fps, *frame_factory_));                      
+                       previous_frame_ = video;
+                       for (auto& av_frame : filter_->poll_all())
+                               video_stream_.push(make_frame(this, av_frame, format_desc_.fps, *frame_factory_, channel_layout_));
                }
 
                merge();
        }
-       
+
        void push_audio(const std::shared_ptr<AVFrame>& audio)
        {
                if(!audio)
@@ -126,7 +154,10 @@ struct frame_muxer::impl : boost::noncopyable
 
                if(!audio->data[0])             
                {
-                       boost::range::push_back(audio_stream_, core::audio_buffer(audio_cadence_.front() * format_desc_.audio_channels, 0));    
+                       if (channel_layout_ == core::audio_channel_layout::invalid())
+                               channel_layout_ = *core::audio_channel_layout_repository::get_default()->get_layout(L"stereo");
+
+                       boost::range::push_back(audio_stream_, core::mutable_audio_buffer(audio_cadence_.front() * channel_layout_.num_channels, 0));
                }
                else
                {
@@ -138,7 +169,7 @@ struct frame_muxer::impl : boost::noncopyable
        }
        
        bool video_ready() const
-       {               
+       {
                switch(display_mode_)
                {
                case display_mode::deinterlace_bob_reinterlace:                                 
@@ -155,9 +186,9 @@ struct frame_muxer::impl : boost::noncopyable
                switch(display_mode_)
                {
                case display_mode::duplicate:                                   
-                       return audio_stream_.size() >= static_cast<size_t>(audio_cadence_[0] + audio_cadence_[1 % audio_cadence_.size()]) * format_desc_.audio_channels;
+                       return audio_stream_.size() >= static_cast<size_t>(audio_cadence_[0] + audio_cadence_[1 % audio_cadence_.size()]) * channel_layout_.num_channels;
                default:                                                                                
-                       return audio_stream_.size() >= static_cast<size_t>(audio_cadence_.front()) * format_desc_.audio_channels;
+                       return audio_stream_.size() >= static_cast<size_t>(audio_cadence_.front()) * channel_layout_.num_channels;
                }
        }
 
@@ -210,8 +241,9 @@ struct frame_muxer::impl : boost::noncopyable
                                        auto second_audio_frame = core::mutable_frame(
                                                        std::vector<array<std::uint8_t>>(),
                                                        pop_audio(),
-                                                       frame1.data_tag(),
-                                                       core::pixel_format_desc());
+                                                       frame1.stream_tag(),
+                                                       core::pixel_format_desc(),
+                                                       channel_layout_);
                                        auto first_frame = core::draw_frame(std::move(frame1));
                                        auto muted_first_frame = core::draw_frame(first_frame);
                                        muted_first_frame.transform().audio_transform.volume = 0;
@@ -242,15 +274,15 @@ struct frame_muxer::impl : boost::noncopyable
                return std::move(frame);
        }
 
-       core::audio_buffer pop_audio()
+       core::mutable_audio_buffer pop_audio()
        {
-               if (audio_stream_.size() < audio_cadence_.front() * format_desc_.audio_channels)
+               if (audio_stream_.size() < audio_cadence_.front() * channel_layout_.num_channels)
                        CASPAR_THROW_EXCEPTION(out_of_range());
 
                auto begin = audio_stream_.begin();
-               auto end   = begin + audio_cadence_.front() * format_desc_.audio_channels;
+               auto end   = begin + audio_cadence_.front() * channel_layout_.num_channels;
 
-               core::audio_buffer samples(begin, end);
+               core::mutable_audio_buffer samples(begin, end);
                audio_stream_.erase(begin, end);
                
                boost::range::rotate(audio_cadence_, std::begin(audio_cadence_)+1);
@@ -355,8 +387,13 @@ struct frame_muxer::impl : boost::noncopyable
        }
 };
 
-frame_muxer::frame_muxer(double in_fps, const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::wstring& filter)
-       : impl_(new impl(in_fps, frame_factory, format_desc, filter)){}
+frame_muxer::frame_muxer(
+               double in_fps,
+               const spl::shared_ptr<core::frame_factory>& frame_factory,
+               const core::video_format_desc& format_desc,
+               const core::audio_channel_layout& channel_layout,
+               const std::wstring& filter)
+       : impl_(new impl(in_fps, frame_factory, format_desc, channel_layout, filter)){}
 void frame_muxer::push_video(const std::shared_ptr<AVFrame>& frame){impl_->push_video(frame);}
 void frame_muxer::push_audio(const std::shared_ptr<AVFrame>& frame){impl_->push_audio(frame);}
 bool frame_muxer::empty() const{return impl_->empty();}