1 #include "../StdAfx.h"
\r
3 #include "frame_muxer.h"
\r
5 #include "filter/filter.h"
\r
9 #include <core/producer/frame_producer.h>
\r
10 #include <core/producer/frame/basic_frame.h>
\r
11 #include <core/producer/frame/frame_transform.h>
\r
12 #include <core/producer/frame/pixel_format.h>
\r
13 #include <core/producer/frame/frame_factory.h>
\r
14 #include <core/mixer/write_frame.h>
\r
16 #include <common/env.h>
\r
17 #include <common/exception/exceptions.h>
\r
18 #include <common/log/log.h>
\r
20 #if defined(_MSC_VER)
\r
21 #pragma warning (push)
\r
22 #pragma warning (disable : 4244)
\r
26 #define __STDC_CONSTANT_MACROS
\r
27 #define __STDC_LIMIT_MACROS
\r
28 #include <libavcodec/avcodec.h>
\r
29 #include <libavformat/avformat.h>
\r
31 #if defined(_MSC_VER)
\r
32 #pragma warning (pop)
\r
35 #include <boost/foreach.hpp>
\r
36 #include <boost/range/algorithm_ext/push_back.hpp>
\r
37 #include <boost/assign.hpp>
\r
39 #include <agents_extras.h>
\r
46 using namespace caspar::core;
\r
48 using namespace Concurrency;
\r
50 namespace caspar { namespace ffmpeg {
\r
61 deinterlace_bob_reinterlace,
\r
67 static std::wstring print(display_mode::type value)
\r
71 case simple: return L"simple";
\r
72 case duplicate: return L"duplicate";
\r
73 case half: return L"half";
\r
74 case interlace: return L"interlace";
\r
75 case deinterlace_bob: return L"deinterlace_bob";
\r
76 case deinterlace_bob_reinterlace: return L"deinterlace_bob_reinterlace";
\r
77 case deinterlace: return L"deinterlace";
\r
78 default: return L"invalid";
\r
83 display_mode::type get_display_mode(const core::field_mode::type in_mode, double in_fps, const core::field_mode::type out_mode, double out_fps)
\r
85 static const auto epsilon = 2.0;
\r
87 if(in_fps < 20.0 || in_fps > 80.0)
\r
89 //if(out_mode != core::field_mode::progressive && in_mode == core::field_mode::progressive)
\r
90 // return display_mode::interlace;
\r
92 if(out_mode == core::field_mode::progressive && in_mode != core::field_mode::progressive)
\r
95 return display_mode::deinterlace;
\r
97 return display_mode::deinterlace_bob;
\r
101 if(std::abs(in_fps - out_fps) < epsilon)
\r
103 if(in_mode != core::field_mode::progressive && out_mode == core::field_mode::progressive)
\r
104 return display_mode::deinterlace;
\r
105 //else if(in_mode == core::field_mode::progressive && out_mode != core::field_mode::progressive)
\r
106 // simple(); // interlace_duplicate();
\r
108 return display_mode::simple;
\r
110 else if(std::abs(in_fps/2.0 - out_fps) < epsilon)
\r
112 if(in_mode != core::field_mode::progressive)
\r
113 return display_mode::invalid;
\r
115 if(out_mode != core::field_mode::progressive)
\r
116 return display_mode::interlace;
\r
118 return display_mode::half;
\r
120 else if(std::abs(in_fps - out_fps/2.0) < epsilon)
\r
122 if(out_mode != core::field_mode::progressive)
\r
123 return display_mode::invalid;
\r
125 if(in_mode != core::field_mode::progressive)
\r
126 return display_mode::deinterlace_bob;
\r
128 return display_mode::duplicate;
\r
131 return display_mode::invalid;
\r
135 struct frame_muxer2::implementation : public Concurrency::agent, boost::noncopyable
\r
137 ITarget<safe_ptr<core::basic_frame>>& target_;
\r
138 display_mode::type display_mode_;
\r
139 const double in_fps_;
\r
140 const video_format_desc format_desc_;
\r
141 bool auto_transcode_;
\r
144 const safe_ptr<core::frame_factory> frame_factory_;
\r
146 call<safe_ptr<AVFrame>> push_video_;
\r
147 call<safe_ptr<core::audio_buffer>> push_audio_;
\r
149 unbounded_buffer<safe_ptr<AVFrame>> video_;
\r
150 unbounded_buffer<safe_ptr<core::audio_buffer>> audio_;
\r
152 core::audio_buffer audio_data_;
\r
154 Concurrency::overwrite_buffer<bool> is_running_;
\r
156 safe_ptr<semaphore> semaphore_;
\r
158 implementation(frame_muxer2::video_source_t* video_source,
\r
159 frame_muxer2::audio_source_t* audio_source,
\r
160 frame_muxer2::target_t& target,
\r
162 const safe_ptr<core::frame_factory>& frame_factory)
\r
164 , display_mode_(display_mode::invalid)
\r
166 , format_desc_(frame_factory->get_video_format_desc())
\r
167 , auto_transcode_(env::properties().get("configuration.producers.auto-transcode", false))
\r
168 , frame_factory_(make_safe<core::concrt_frame_factory>(frame_factory))
\r
169 , push_video_(std::bind(&implementation::push_video, this, std::placeholders::_1))
\r
170 , push_audio_(std::bind(&implementation::push_audio, this, std::placeholders::_1))
\r
171 , semaphore_(make_safe<semaphore>(8))
\r
174 video_source->link_target(&push_video_);
\r
176 audio_source->link_target(&push_audio_);
\r
183 send(is_running_, false);
\r
191 send(is_running_, true);
\r
192 while(is_running_.value())
\r
194 auto video = receive(video_);
\r
195 auto audio = receive(audio_);
\r
196 auto frame = make_safe<core::write_frame>(this);
\r
198 if(audio == eof_audio())
\r
200 send(is_running_ , false);
\r
204 if(video == eof_video())
\r
206 send(is_running_ , false);
\r
210 if(video != empty_video())
\r
211 frame = make_write_frame(this, video, frame_factory_, 0);
\r
212 if(audio == empty_audio())
\r
213 audio = make_safe<core::audio_buffer>(format_desc_.audio_samples_per_frame, 0);
\r
215 frame->audio_data() = std::move(*audio);
\r
217 switch(display_mode_)
\r
219 case display_mode::simple:
\r
220 case display_mode::deinterlace:
\r
221 case display_mode::deinterlace_bob:
\r
223 send(target_, safe_ptr<core::basic_frame>(frame));
\r
227 case display_mode::duplicate:
\r
229 send(target_, safe_ptr<core::basic_frame>(frame));
\r
230 send(target_, safe_ptr<core::basic_frame>(frame));
\r
234 case display_mode::half:
\r
236 receive(video_); // throw away
\r
237 send(target_, safe_ptr<core::basic_frame>(frame));
\r
241 case display_mode::deinterlace_bob_reinterlace:
\r
242 case display_mode::interlace:
\r
244 /*auto frame = safe_ptr<core::basic_frame>(frame);
\r
245 auto video2 = receive(video_);
\r
246 if(video2 != empty_video() && video2 != eof_video())
\r
247 frame = core::basic_frame::interlace(frame, safe_ptr<core::basic_frame>(video2), format_desc_.field_mode);
\r
249 send(is_running_, false);
\r
251 send(target_, frame);*/
\r
256 BOOST_THROW_EXCEPTION(invalid_operation() << msg_info("invalid display-mode"));
\r
262 CASPAR_LOG_CURRENT_EXCEPTION();
\r
265 send(is_running_ , false);
\r
266 send(target_, core::basic_frame::eof());
\r
271 void push_video(const safe_ptr<AVFrame>& video_frame)
\r
273 if(video_frame == eof_video() || video_frame == empty_video())
\r
275 send(video_, video_frame);
\r
279 if(video_frame == loop_video())
\r
282 if(display_mode_ == display_mode::invalid)
\r
284 if(auto_transcode_)
\r
286 auto in_mode = get_mode(*video_frame);
\r
287 display_mode_ = get_display_mode(in_mode, in_fps_, format_desc_.field_mode, format_desc_.fps);
\r
289 if(display_mode_ == display_mode::simple && in_mode != core::field_mode::progressive && format_desc_.field_mode != core::field_mode::progressive && video_frame->height != static_cast<int>(format_desc_.height))
\r
290 display_mode_ = display_mode::deinterlace_bob_reinterlace; // The frame will most likely be scaled, we need to deinterlace->reinterlace
\r
292 if(display_mode_ == display_mode::deinterlace)
\r
293 filter_ = filter(L"YADIF=0:-1");
\r
294 else if(display_mode_ == display_mode::deinterlace_bob || display_mode_ == display_mode::deinterlace_bob_reinterlace)
\r
295 filter_ = filter(L"YADIF=1:-1");
\r
298 display_mode_ = display_mode::simple;
\r
300 if(display_mode_ == display_mode::invalid)
\r
302 CASPAR_LOG(warning) << L"[frame_muxer] Failed to detect display-mode.";
\r
303 display_mode_ = display_mode::simple;
\r
306 // copy <= We need to release frames
\r
307 if(display_mode_ != display_mode::simple && filter_.filter_str().empty())
\r
308 filter_ = filter(L"copy");
\r
310 CASPAR_LOG(info) << "[frame_muxer] " << display_mode::print(display_mode_);
\r
313 //if(hints & core::frame_producer::ALPHA_HINT)
\r
314 // video_frame->format = make_alpha_format(video_frame->format);
\r
316 auto format = video_frame->format;
\r
317 if(video_frame->format == CASPAR_PIX_FMT_LUMA) // CASPAR_PIX_FMT_LUMA is not valid for filter, change it to GRAY8
\r
318 video_frame->format = PIX_FMT_GRAY8;
\r
320 filter_.push(video_frame);
\r
322 BOOST_FOREACH(auto av_frame, filter_.poll_all())
\r
324 av_frame->format = format;
\r
325 send(video_, av_frame);
\r
329 void push_audio(const safe_ptr<core::audio_buffer>& audio_samples)
\r
331 if(audio_samples == eof_audio() || audio_samples == empty_audio())
\r
333 send(audio_, audio_samples);
\r
337 if(audio_samples == loop_audio())
\r
340 audio_data_.insert(audio_data_.end(), audio_samples->begin(), audio_samples->end());
\r
342 while(audio_data_.size() >= format_desc_.audio_samples_per_frame)
\r
344 auto begin = audio_data_.begin();
\r
345 auto end = begin + format_desc_.audio_samples_per_frame;
\r
347 send(audio_, make_safe<core::audio_buffer>(begin, end));
\r
349 audio_data_.erase(begin, end);
\r
353 int64_t calc_nb_frames(int64_t nb_frames) const
\r
355 switch(display_mode_)
\r
357 case display_mode::interlace:
\r
358 case display_mode::half:
\r
359 return nb_frames/2;
\r
360 case display_mode::duplicate:
\r
361 case display_mode::deinterlace_bob:
\r
362 return nb_frames*2;
\r
369 frame_muxer2::frame_muxer2(video_source_t* video_source,
\r
370 audio_source_t* audio_source,
\r
373 const safe_ptr<core::frame_factory>& frame_factory)
\r
374 : impl_(new implementation(video_source, audio_source, target, in_fps, frame_factory))
\r
378 int64_t frame_muxer2::calc_nb_frames(int64_t nb_frames) const
\r
380 return impl_->calc_nb_frames(nb_frames);
\r