]> git.sesse.net Git - casparcg/blob - core/producer/frame_muxer.cpp
2.0.0.2: Refactoring. Working on re-enabling filter functionality.
[casparcg] / core / producer / frame_muxer.cpp
1 #include "../StdAfx.h"\r
2 \r
3 #include "frame_muxer.h"\r
4 \r
5 #include "frame/basic_frame.h"\r
6 #include "../mixer/write_frame.h"\r
7 \r
8 namespace caspar { namespace core {\r
9         \r
10 struct display_mode\r
11 {\r
12         enum type\r
13         {\r
14                 simple,\r
15                 duplicate,\r
16                 half,\r
17                 interlace,\r
18                 deinterlace,\r
19                 deinterlace_half,\r
20                 count,\r
21                 invalid\r
22         };\r
23 \r
24         static std::wstring print(display_mode::type value)\r
25         {\r
26                 switch(value)\r
27                 {\r
28                         case simple:\r
29                                 return L"simple";\r
30                         case duplicate:\r
31                                 return L"duplicate";\r
32                         case half:\r
33                                 return L"half";\r
34                         case interlace:\r
35                                 return L"interlace";\r
36                         case deinterlace:\r
37                                 return L"deinterlace";\r
38                         case deinterlace_half:\r
39                                 return L"deinterlace_half";\r
40                         default:\r
41                                 return L"invalid";\r
42                 }\r
43         }\r
44 };\r
45 \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
47 {               \r
48         if(in_mode == core::video_mode::invalid || out_mode == core::video_mode::invalid)\r
49                 return display_mode::invalid;\r
50 \r
51         static const auto epsilon = 2.0;\r
52 \r
53         if(std::abs(in_fps - out_fps) < epsilon)\r
54         {\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
59                 else\r
60                         return display_mode::simple;\r
61         }\r
62         else if(std::abs(in_fps/2.0 - out_fps) < epsilon)\r
63         {\r
64                 if(in_mode != core::video_mode::progressive)\r
65                         return display_mode::invalid;\r
66 \r
67                 if(out_mode != core::video_mode::progressive)\r
68                         return display_mode::interlace;\r
69                 else\r
70                         return display_mode::half;\r
71         }\r
72         else if(std::abs(in_fps - out_fps/2.0) < epsilon)\r
73         {\r
74                 if(out_mode != core::video_mode::progressive)\r
75                         return display_mode::invalid;\r
76 \r
77                 if(in_mode != core::video_mode::progressive)\r
78                         return display_mode::deinterlace;\r
79                 else\r
80                         return display_mode::duplicate;\r
81         }\r
82 \r
83         return display_mode::invalid;\r
84 }\r
85 \r
86 struct frame_muxer::implementation\r
87 {       \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
95 \r
96         implementation(double in_fps, const core::video_mode::type out_mode, double out_fps)\r
97                 : display_mode_(display_mode::invalid)\r
98                 , in_fps_(in_fps)\r
99                 , out_fps_(out_fps)\r
100                 , out_mode_(out_mode)\r
101         {\r
102         }\r
103 \r
104         void push(const safe_ptr<write_frame>& video_frame)\r
105         {\r
106                 video_frames_.push(video_frame);\r
107                 process();\r
108         }\r
109 \r
110         void push(const std::vector<int16_t>& audio_chunk)\r
111         {\r
112                 audio_chunks_.push(audio_chunk);\r
113                 process();\r
114         }\r
115 \r
116         safe_ptr<basic_frame> pop()\r
117         {               \r
118                 auto frame = frame_buffer_.front();\r
119                 frame_buffer_.pop();\r
120                 return frame;\r
121         }\r
122 \r
123         size_t size() const\r
124         {\r
125                 return frame_buffer_.size();\r
126         }\r
127 \r
128         void process()\r
129         {\r
130                 if(video_frames_.empty() || audio_chunks_.empty())\r
131                         return;\r
132 \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
135 \r
136                 switch(display_mode_)\r
137                 {\r
138                 case display_mode::simple:\r
139                         return simple();\r
140                 case display_mode::duplicate:\r
141                         return duplicate();\r
142                 case display_mode::half:\r
143                         return 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
150                 default:\r
151                         BOOST_THROW_EXCEPTION(invalid_operation());\r
152                 }\r
153         }\r
154 \r
155         void simple()\r
156         {\r
157                 if(video_frames_.empty() || audio_chunks_.empty())\r
158                         return;\r
159 \r
160                 auto frame1 = video_frames_.front();\r
161                 video_frames_.pop();\r
162 \r
163                 frame1->audio_data() = audio_chunks_.front();\r
164                 audio_chunks_.pop();\r
165 \r
166                 frame_buffer_.push(frame1);\r
167         }\r
168 \r
169         void duplicate()\r
170         {               \r
171                 if(video_frames_.empty() || audio_chunks_.size() < 2)\r
172                         return;\r
173 \r
174                 auto frame = video_frames_.front();\r
175                 video_frames_.pop();\r
176 \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
180 \r
181                 auto frame2 = frame;\r
182                 frame2->audio_data() = audio_chunks_.front();\r
183                 audio_chunks_.pop();\r
184 \r
185                 frame_buffer_.push(frame1);\r
186                 frame_buffer_.push(frame2);\r
187         }\r
188 \r
189         void half()\r
190         {       \r
191                 if(video_frames_.size() < 2 || audio_chunks_.empty())\r
192                         return;\r
193                                                 \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
198                                 \r
199                 video_frames_.pop(); // Throw away\r
200 \r
201                 frame_buffer_.push(frame1);\r
202         }\r
203         \r
204         void interlace()\r
205         {               \r
206                 if(video_frames_.size() < 2 || audio_chunks_.empty())\r
207                         return;\r
208                 \r
209                 auto frame1 = video_frames_.front();\r
210                 video_frames_.pop();\r
211 \r
212                 frame1->audio_data() = audio_chunks_.front();\r
213                 audio_chunks_.pop();\r
214                                 \r
215                 auto frame2 = video_frames_.front();\r
216                 video_frames_.pop();\r
217 \r
218                 frame_buffer_.push(core::basic_frame::interlace(frame1, frame2, out_mode_));            \r
219         }\r
220         \r
221         void deinterlace()\r
222         {\r
223                 BOOST_THROW_EXCEPTION(not_implemented() << msg_info("deinterlace"));\r
224         }\r
225 \r
226         void deinterlace_half()\r
227         {\r
228                 BOOST_THROW_EXCEPTION(not_implemented() << msg_info("deinterlace_half"));\r
229         }\r
230 };\r
231 \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
241 \r
242 }}