1 #include "../StdAfx.h"
\r
4 #pragma warning (disable : 4244)
\r
7 #include "display_device.h"
\r
9 #include "../frame/frame_format.h"
\r
10 #include "../frame/gpu_frame.h"
\r
12 #include <tbb/concurrent_queue.h>
\r
13 #include <tbb/atomic.h>
\r
15 #include <boost/foreach.hpp>
\r
16 #include <boost/thread.hpp>
\r
18 #include <boost/date_time/posix_time/posix_time.hpp>
\r
20 #include <boost/range/algorithm_ext/erase.hpp>
\r
22 namespace caspar { namespace core { namespace renderer {
\r
24 class video_sync_clock
\r
27 video_sync_clock(const frame_format_desc& format_desc)
\r
29 period_ = static_cast<long>(get_frame_format_period(format_desc)*1000000.0);
\r
30 time_ = boost::posix_time::microsec_clock::local_time();
\r
35 auto remaining = boost::posix_time::microseconds(period_) -
\r
36 (boost::posix_time::microsec_clock::local_time() - time_);
\r
37 if(remaining > boost::posix_time::microseconds(5000))
\r
38 boost::this_thread::sleep(remaining -
\r
39 boost::posix_time::microseconds(5000));
\r
40 time_ = boost::posix_time::microsec_clock::local_time();
\r
43 boost::posix_time::ptime time_;
\r
47 struct display_device::implementation
\r
50 implementation(const frame_format_desc& format_desc,
\r
51 const std::vector<frame_consumer_ptr>& consumers)
\r
52 : consumers_(consumers), fmt_(format_desc)
\r
54 if(consumers.empty())
\r
55 BOOST_THROW_EXCEPTION(invalid_argument() << arg_name_info("consumer")
\r
56 << msg_info("display_device requires atleast one consumer"));
\r
58 if(std::any_of(consumers.begin(), consumers.end(),
\r
59 [&](const frame_consumer_ptr& pConsumer)
\r
60 { return pConsumer->get_frame_format_desc() != format_desc;}))
\r
62 BOOST_THROW_EXCEPTION(invalid_argument() << arg_name_info("consumer")
\r
63 << msg_info("All consumers must have same frameformat as display_device."));
\r
66 needs_clock_ = !std::any_of(consumers.begin(), consumers.end(),
\r
67 std::mem_fn(&frame_consumer::has_sync_clock));
\r
68 frame_buffer_.set_capacity(3);
\r
70 display_thread_ = boost::thread([=]{run();});
\r
75 is_running_ = false;
\r
76 frame_buffer_.clear();
\r
77 display_thread_.join();
\r
80 void display(const gpu_frame_ptr& frame)
\r
83 frame_buffer_.push(frame);
\r
88 CASPAR_LOG(info) << L"Started display_device thread";
\r
89 win32_exception::install_handler();
\r
91 video_sync_clock clock(fmt_);
\r
96 clock.synchronize();
\r
98 gpu_frame_ptr frame;
\r
99 if(!frame_buffer_.try_pop(frame))
\r
101 CASPAR_LOG(trace) << "Display Buffer Underrun";
\r
102 frame_buffer_.pop(frame);
\r
104 if(frame != nullptr)
\r
105 display_frame(frame);
\r
108 CASPAR_LOG(info) << L"Ended display_device thread";
\r
111 void display_frame(const gpu_frame_ptr& frame)
\r
113 BOOST_FOREACH(const frame_consumer_ptr& consumer, consumers_)
\r
117 consumer->prepare(frame);
\r
118 prepared_frames_.push_back(frame);
\r
120 if(prepared_frames_.size() > 2)
\r
122 consumer->display(prepared_frames_.front());
\r
123 prepared_frames_.pop_front();
\r
128 CASPAR_LOG_CURRENT_EXCEPTION();
\r
129 boost::range::remove_erase(consumers_, consumer);
\r
130 CASPAR_LOG(warning) << "Removed consumer from render-device.";
\r
131 if(consumers_.empty())
\r
133 CASPAR_LOG(warning)
\r
134 << "No consumers available. Shutting down display-device.";
\r
135 is_running_ = false;
\r
141 std::deque<gpu_frame_ptr> prepared_frames_;
\r
143 boost::thread display_thread_;
\r
145 tbb::atomic<bool> is_running_;
\r
146 tbb::concurrent_bounded_queue<gpu_frame_ptr> frame_buffer_;
\r
149 std::vector<frame_consumer_ptr> consumers_;
\r
151 frame_format_desc fmt_;
\r
154 display_device::display_device(const frame_format_desc& format_desc, const std::vector<frame_consumer_ptr>& consumers) : impl_(new implementation(format_desc, consumers)){}
\r
155 void display_device::display(const gpu_frame_ptr& frame){impl_->display(frame);}
\r