5 #include "producer/layer.h"
\r
7 #include "consumer/frame_consumer_device.h"
\r
9 #include "processor/draw_frame.h"
\r
10 #include "processor/frame_processor_device.h"
\r
12 #include <common/concurrency/executor.h>
\r
14 #include <boost/range/algorithm_ext/erase.hpp>
\r
16 #include <tbb/parallel_for.h>
\r
20 namespace caspar { namespace core {
\r
25 clock(int fps = 25) : fps_(fps)
\r
27 QueryPerformanceFrequency(&freq_);
\r
31 // Author: Ryan M. Geiss
\r
32 // http://www.geisswerks.com/ryan/FAQS/timing.html
\r
36 QueryPerformanceCounter(&t);
\r
38 if (time_.QuadPart != 0)
\r
40 int ticks_to_wait = static_cast<int>(freq_.QuadPart / fps_);
\r
44 QueryPerformanceCounter(&t);
\r
46 int ticks_passed = static_cast<int>(static_cast<__int64>(t.QuadPart) - static_cast<__int64>(time_.QuadPart));
\r
47 int ticks_left = ticks_to_wait - ticks_passed;
\r
49 if (t.QuadPart < time_.QuadPart) // time wrap
\r
51 if (ticks_passed >= ticks_to_wait)
\r
56 // if > 0.002s left, do Sleep(1), which will actually sleep some
\r
57 // steady amount, probably 1-2 ms,
\r
58 // and do so in a nice way (cpu meter drops; laptop battery spared).
\r
59 // otherwise, do a few Sleep(0)'s, which just give up the timeslice,
\r
60 // but don't really save cpu or battery, but do pass a tiny
\r
62 if (ticks_left > static_cast<int>((freq_.QuadPart*2)/1000))
\r
65 for (int i = 0; i < 10; ++i)
\r
66 Sleep(0); // causes thread to give up its timeslice
\r
75 LARGE_INTEGER freq_;
\r
76 LARGE_INTEGER time_;
\r
80 struct channel::implementation : boost::noncopyable
\r
82 implementation(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers)
\r
83 : format_desc_(format_desc), processor_device_(frame_processor_device(format_desc)), consumer_device_(format_desc, consumers)
\r
86 executor_.begin_invoke([=]{tick();});
\r
91 auto drawed_frame = draw();
\r
92 auto processed_frame = processor_device_->process(std::move(drawed_frame));
\r
93 consumer_device_.consume(std::move(processed_frame));
\r
95 executor_.begin_invoke([=]{tick();});
\r
100 safe_ptr<draw_frame> draw()
\r
102 std::vector<safe_ptr<draw_frame>> frames(layers_.size(), draw_frame::empty());
\r
103 tbb::parallel_for(tbb::blocked_range<size_t>(0, frames.size()),
\r
104 [&](const tbb::blocked_range<size_t>& r)
\r
106 auto it = layers_.begin();
\r
107 std::advance(it, r.begin());
\r
108 for(size_t i = r.begin(); i != r.end(); ++i, ++it)
\r
109 frames[i] = it->second.receive();
\r
111 boost::range::remove_erase(frames, draw_frame::eof());
\r
112 boost::range::remove_erase(frames, draw_frame::empty());
\r
113 return draw_frame(frames);
\r
116 void load(int index, const safe_ptr<frame_producer>& producer, bool autoplay)
\r
118 producer->initialize(processor_device_);
\r
119 executor_.begin_invoke([=]
\r
121 auto it = layers_.insert(std::make_pair(index, layer(index))).first;
\r
122 it->second.load(producer, autoplay);
\r
126 void preview(int index, const safe_ptr<frame_producer>& producer)
\r
128 producer->initialize(processor_device_);
\r
129 executor_.begin_invoke([=]
\r
131 auto it = layers_.insert(std::make_pair(index, layer(index))).first;
\r
132 it->second.preview(producer);
\r
136 void pause(int index)
\r
138 executor_.begin_invoke([=]
\r
140 auto it = layers_.find(index);
\r
141 if(it != layers_.end())
\r
142 it->second.pause();
\r
146 void play(int index)
\r
148 executor_.begin_invoke([=]
\r
150 auto it = layers_.find(index);
\r
151 if(it != layers_.end())
\r
152 it->second.play();
\r
156 void stop(int index)
\r
158 executor_.begin_invoke([=]
\r
160 auto it = layers_.find(index);
\r
161 if(it != layers_.end())
\r
163 it->second.stop();
\r
164 if(it->second.empty())
\r
170 void clear(int index)
\r
172 executor_.begin_invoke([=]
\r
174 auto it = layers_.find(index);
\r
175 if(it != layers_.end())
\r
177 it->second.clear();
\r
185 executor_.begin_invoke([=]
\r
191 boost::unique_future<safe_ptr<frame_producer>> foreground(int index) const
\r
193 return executor_.begin_invoke([=]() -> safe_ptr<frame_producer>
\r
195 auto it = layers_.find(index);
\r
196 return it != layers_.end() ? it->second.foreground() : frame_producer::empty();
\r
200 boost::unique_future<safe_ptr<frame_producer>> background(int index) const
\r
202 return executor_.begin_invoke([=]() -> safe_ptr<frame_producer>
\r
204 auto it = layers_.find(index);
\r
205 return it != layers_.end() ? it->second.background() : frame_producer::empty();
\r
211 mutable executor executor_;
\r
213 safe_ptr<frame_processor_device> processor_device_;
\r
214 frame_consumer_device consumer_device_;
\r
216 std::map<int, layer> layers_;
\r
218 const video_format_desc format_desc_;
\r
221 channel::channel(channel&& other) : impl_(std::move(other.impl_)){}
\r
222 channel::channel(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers)
\r
223 : impl_(new implementation(format_desc, consumers)){}
\r
224 void channel::load(int index, const safe_ptr<frame_producer>& producer, bool autoplay){impl_->load(index, producer, autoplay);}
\r
225 void channel::preview(int index, const safe_ptr<frame_producer>& producer){impl_->preview(index, producer);}
\r
226 void channel::pause(int index){impl_->pause(index);}
\r
227 void channel::play(int index){impl_->play(index);}
\r
228 void channel::stop(int index){impl_->stop(index);}
\r
229 void channel::clear(int index){impl_->clear(index);}
\r
230 void channel::clear(){impl_->clear();}
\r
231 boost::unique_future<safe_ptr<frame_producer>> channel::foreground(int index) const{ return impl_->foreground(index);}
\r
232 boost::unique_future<safe_ptr<frame_producer>> channel::background(int index) const{return impl_->background(index);}
\r
233 const video_format_desc& channel::get_video_format_desc() const{ return impl_->format_desc_;}
\r