#include <common/array.h>\r
#include <common/memshfl.h>\r
#include <common/utf.h>\r
+#include <common/prec_timer.h>\r
\r
#include <ffmpeg/producer/filter/filter.h>\r
\r
boost::timer perf_timer_;\r
boost::timer tick_timer_;\r
\r
+ caspar::prec_timer wait_timer_;\r
+\r
tbb::concurrent_bounded_queue<core::const_frame> frame_buffer_;\r
\r
boost::thread thread_;\r
, screen_height_(format_desc.height)\r
, square_width_(format_desc.square_width)\r
, square_height_(format_desc.square_height)\r
- , filter_(format_desc.field_mode == core::field_mode::progressive || !config.auto_deinterlace ? L"" : L"YADIF=0:-1", boost::assign::list_of(PIX_FMT_BGRA))\r
+ , filter_(format_desc.field_mode == core::field_mode::progressive || !config.auto_deinterlace ? L"" : L"YADIF=1:-1", boost::assign::list_of(PIX_FMT_BGRA))\r
{ \r
if(format_desc_.format == core::video_format::ntsc && config_.aspect == configuration::aspect_4_3)\r
{\r
\r
auto frame = core::const_frame::empty();\r
frame_buffer_.pop(frame);\r
+\r
+ render_and_draw_frame(frame);\r
\r
- perf_timer_.restart();\r
+ /*perf_timer_.restart();\r
render(frame);\r
graph_->set_value("frame-time", perf_timer_.elapsed()*format_desc_.fps*0.5); \r
\r
- window_.Display();\r
- \r
+ window_.Display();*/\r
+\r
graph_->set_value("tick-time", tick_timer_.elapsed()*format_desc_.fps*0.5); \r
tick_timer_.restart();\r
}\r
CASPAR_LOG_CURRENT_EXCEPTION();\r
}\r
}\r
- \r
+\r
+ void try_sleep_almost_until_vblank()\r
+ {\r
+ static const double THRESHOLD = 0.003;\r
+ double threshold = config_.vsync ? THRESHOLD : 0.0;\r
+\r
+ auto frame_time = 1.0 / (format_desc_.fps * format_desc_.field_count);\r
+\r
+ wait_timer_.tick(frame_time - threshold);\r
+ }\r
+\r
+ void wait_for_vblank_and_display()\r
+ {\r
+ try_sleep_almost_until_vblank();\r
+ window_.Display();\r
+ // Make sure that the next tick measures the duration from this point in time.\r
+ wait_timer_.tick(0.0);\r
+ }\r
+\r
spl::shared_ptr<AVFrame> get_av_frame()\r
{ \r
spl::shared_ptr<AVFrame> av_frame(avcodec_alloc_frame(), av_free); \r
return av_frame;\r
}\r
\r
- void render(core::const_frame frame)\r
- { \r
- if(static_cast<int>(frame.image_data().size()) != format_desc_.size)\r
+ void render_and_draw_frame(core::const_frame frame)\r
+ {\r
+ if(static_cast<size_t>(frame.image_data().size()) != format_desc_.size)\r
return;\r
\r
if(screen_width_ == 0 && screen_height_ == 0)\r
return;\r
\r
+ perf_timer_.restart();\r
auto av_frame = get_av_frame();\r
av_frame->data[0] = const_cast<uint8_t*>(frame.image_data().begin());\r
\r
filter_.push(av_frame);\r
auto frames = filter_.poll_all();\r
\r
- if(frames.empty())\r
+ if (frames.empty())\r
return;\r
\r
- av_frame = frames[0];\r
- \r
+ if (frames.size() == 1)\r
+ {\r
+ render(frames[0]);\r
+ graph_->set_value("frame-time", perf_timer_.elapsed() * format_desc_.fps * 0.5);\r
+\r
+ wait_for_vblank_and_display(); // progressive frame\r
+ }\r
+ else if (frames.size() == 2)\r
+ {\r
+ render(frames[0]);\r
+ double perf_elapsed = perf_timer_.elapsed();\r
+\r
+ wait_for_vblank_and_display(); // field1\r
+\r
+ perf_timer_.restart();\r
+ render(frames[1]);\r
+ perf_elapsed += perf_timer_.elapsed();\r
+ graph_->set_value("frame-time", perf_elapsed * format_desc_.fps * 0.5);\r
+\r
+ wait_for_vblank_and_display(); // field2\r
+ }\r
+ }\r
+\r
+ void render(spl::shared_ptr<AVFrame> av_frame)\r
+ {\r
GL(glBindTexture(GL_TEXTURE_2D, texture_));\r
\r
GL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbos_[0]));\r
std::rotate(pbos_.begin(), pbos_.begin() + 1, pbos_.end());\r
}\r
\r
+\r
bool send(core::const_frame frame)\r
{\r
if(!frame_buffer_.try_push(frame))\r
\r
int index() const override\r
{\r
- return 600 + (config_.key_only ? 1 : 0);\r
+ return 600 + (config_.key_only ? 10 : 0) + config_.screen_index;\r
}\r
\r
void subscribe(const monitor::observable::observer_ptr& o) override\r