1 #include "../StdAfx.h"
\r
3 #include "frame_muxer.h"
\r
5 #include "frame/basic_frame.h"
\r
6 #include "../mixer/write_frame.h"
\r
8 namespace caspar { namespace core {
\r
24 static std::wstring print(display_mode::type value)
\r
31 return L"duplicate";
\r
35 return L"interlace";
\r
37 return L"deinterlace";
\r
38 case deinterlace_half:
\r
39 return L"deinterlace_half";
\r
46 display_mode::type get_display_mode(const core::video_mode::type in_mode, double in_fps, const core::video_mode::type out_mode, double out_fps)
\r
48 if(in_mode == core::video_mode::invalid || out_mode == core::video_mode::invalid)
\r
49 return display_mode::invalid;
\r
51 static const auto epsilon = 2.0;
\r
53 if(std::abs(in_fps - out_fps) < epsilon)
\r
55 if(in_mode != core::video_mode::progressive && out_mode == core::video_mode::progressive)
\r
56 return display_mode::deinterlace_half;
\r
57 //else if(in_mode == core::video_mode::progressive && out_mode != core::video_mode::progressive)
\r
58 // simple(); // interlace_duplicate();
\r
60 return display_mode::simple;
\r
62 else if(std::abs(in_fps/2.0 - out_fps) < epsilon)
\r
64 if(in_mode != core::video_mode::progressive)
\r
65 return display_mode::invalid;
\r
67 if(out_mode != core::video_mode::progressive)
\r
68 return display_mode::interlace;
\r
70 return display_mode::half;
\r
72 else if(std::abs(in_fps - out_fps/2.0) < epsilon)
\r
74 if(out_mode != core::video_mode::progressive)
\r
75 return display_mode::invalid;
\r
77 if(in_mode != core::video_mode::progressive)
\r
78 return display_mode::deinterlace;
\r
80 return display_mode::duplicate;
\r
83 return display_mode::invalid;
\r
86 struct frame_muxer::implementation
\r
88 std::queue<safe_ptr<write_frame>> video_frames_;
\r
89 std::queue<std::vector<int16_t>> audio_chunks_;
\r
90 std::queue<safe_ptr<basic_frame>> frame_buffer_;
\r
91 display_mode::type display_mode_;
\r
92 const double in_fps_;
\r
93 const double out_fps_;
\r
94 const video_mode::type out_mode_;
\r
96 implementation(double in_fps, const core::video_mode::type out_mode, double out_fps)
\r
97 : display_mode_(display_mode::invalid)
\r
100 , out_mode_(out_mode)
\r
104 void push(const safe_ptr<write_frame>& video_frame)
\r
106 video_frames_.push(video_frame);
\r
110 void push(const std::vector<int16_t>& audio_chunk)
\r
112 audio_chunks_.push(audio_chunk);
\r
116 safe_ptr<basic_frame> pop()
\r
118 auto frame = frame_buffer_.front();
\r
119 frame_buffer_.pop();
\r
123 size_t size() const
\r
125 return frame_buffer_.size();
\r
130 if(video_frames_.empty() || audio_chunks_.empty())
\r
133 if(display_mode_ == display_mode::invalid)
\r
134 display_mode_ = get_display_mode(video_frames_.front()->get_type(), in_fps_, out_mode_, out_fps_);
\r
136 switch(display_mode_)
\r
138 case display_mode::simple:
\r
140 case display_mode::duplicate:
\r
141 return duplicate();
\r
142 case display_mode::half:
\r
144 case display_mode::interlace:
\r
145 return interlace();
\r
146 case display_mode::deinterlace:
\r
147 return deinterlace();
\r
148 case display_mode::deinterlace_half:
\r
149 return deinterlace_half();
\r
151 BOOST_THROW_EXCEPTION(invalid_operation());
\r
157 if(video_frames_.empty() || audio_chunks_.empty())
\r
160 auto frame1 = video_frames_.front();
\r
161 video_frames_.pop();
\r
163 frame1->audio_data() = audio_chunks_.front();
\r
164 audio_chunks_.pop();
\r
166 frame_buffer_.push(frame1);
\r
171 if(video_frames_.empty() || audio_chunks_.size() < 2)
\r
174 auto frame = video_frames_.front();
\r
175 video_frames_.pop();
\r
177 auto frame1 = make_safe<core::write_frame>(*frame); // make a copy
\r
178 frame1->audio_data() = audio_chunks_.front();
\r
179 audio_chunks_.pop();
\r
181 auto frame2 = frame;
\r
182 frame2->audio_data() = audio_chunks_.front();
\r
183 audio_chunks_.pop();
\r
185 frame_buffer_.push(frame1);
\r
186 frame_buffer_.push(frame2);
\r
191 if(video_frames_.size() < 2 || audio_chunks_.empty())
\r
194 auto frame1 = video_frames_.front();
\r
195 video_frames_.pop();
\r
196 frame1->audio_data() = audio_chunks_.front();
\r
197 audio_chunks_.pop();
\r
199 video_frames_.pop(); // Throw away
\r
201 frame_buffer_.push(frame1);
\r
206 if(video_frames_.size() < 2 || audio_chunks_.empty())
\r
209 auto frame1 = video_frames_.front();
\r
210 video_frames_.pop();
\r
212 frame1->audio_data() = audio_chunks_.front();
\r
213 audio_chunks_.pop();
\r
215 auto frame2 = video_frames_.front();
\r
216 video_frames_.pop();
\r
218 frame_buffer_.push(core::basic_frame::interlace(frame1, frame2, out_mode_));
\r
223 BOOST_THROW_EXCEPTION(not_implemented() << msg_info("deinterlace"));
\r
226 void deinterlace_half()
\r
228 BOOST_THROW_EXCEPTION(not_implemented() << msg_info("deinterlace_half"));
\r
232 frame_muxer::frame_muxer(double in_fps, const core::video_mode::type out_mode, double out_fps)
\r
233 : impl_(implementation(in_fps, out_mode, out_fps)){}
\r
234 void frame_muxer::push(const safe_ptr<write_frame>& video_frame){impl_->push(video_frame);}
\r
235 void frame_muxer::push(const std::vector<int16_t>& audio_chunk){return impl_->push(audio_chunk);}
\r
236 safe_ptr<basic_frame> frame_muxer::pop(){return impl_->pop();}
\r
237 size_t frame_muxer::size() const {return impl_->size();}
\r
238 bool frame_muxer::empty() const {return impl_->size() == 0;}
\r
239 size_t frame_muxer::video_frames() const{return impl_->video_frames_.size();}
\r
240 size_t frame_muxer::audio_chunks() const{return impl_->audio_chunks_.size();}
\r