safe_ptr<diagnostics::graph> graph_;\r
boost::timer perf_timer_;\r
boost::timer tick_timer_;\r
+ boost::timer vblank_timer_;\r
+\r
+ caspar::high_prec_timer wait_timer_;\r
\r
tbb::concurrent_bounded_queue<safe_ptr<core::read_frame>> frame_buffer_;\r
\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
\r
safe_ptr<core::read_frame> frame;\r
+\r
frame_buffer_.pop(frame);\r
- \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
+ render_and_draw_frame(frame);\r
\r
graph_->set_value("tick-time", tick_timer_.elapsed()*format_desc_.fps*0.5); \r
tick_timer_.restart();\r
CASPAR_LOG_CURRENT_EXCEPTION();\r
}\r
}\r
+\r
+ void try_sleep_almost_until_vblank()\r
+ {\r
+ static const double THRESHOLD = 0.005;\r
+ double threshold = config_.vsync ? THRESHOLD : 0.0;\r
+\r
+ auto elapsed = vblank_timer_.elapsed();\r
+ auto frame_time = 1.0 / (format_desc_.fps * format_desc_.field_count);\r
+\r
+ if (elapsed + threshold < frame_time)\r
+ {\r
+ wait_timer_.tick(frame_time - elapsed - threshold);\r
+ }\r
+ }\r
\r
safe_ptr<AVFrame> get_av_frame()\r
{ \r
return av_frame;\r
}\r
\r
- void render(const safe_ptr<core::read_frame>& frame)\r
- { \r
+ void render_and_draw_frame(const safe_ptr<core::read_frame>& frame)\r
+ {\r
if(static_cast<size_t>(frame->image_data().size()) != format_desc_.size)\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
+ if (frames.size() == 1)\r
+ {\r
+ render(frames[0], frame->image_data().size());\r
+ graph_->set_value("frame-time", perf_timer_.elapsed() * format_desc_.fps * 0.5);\r
+\r
+ try_sleep_almost_until_vblank();\r
+ window_.Display();\r
+ vblank_timer_.restart();\r
+ }\r
+ else if (frames.size() == 2)\r
+ {\r
+ render(frames[0], frame->image_data().size());\r
+ double perf_elapsed = perf_timer_.elapsed();\r
+\r
+ try_sleep_almost_until_vblank();\r
+ window_.Display();\r
+ vblank_timer_.restart();\r
+\r
+ perf_timer_.restart();\r
+ render(frames[1], frame->image_data().size());\r
+ perf_elapsed += perf_timer_.elapsed();\r
+ graph_->set_value("frame-time", perf_elapsed * format_desc_.fps * 0.5);\r
\r
+ try_sleep_almost_until_vblank();\r
+ window_.Display();\r
+ vblank_timer_.restart();\r
+ }\r
+ }\r
+\r
+ void render(safe_ptr<AVFrame> av_frame, int image_data_size)\r
+ {\r
if(av_frame->linesize[0] != static_cast<int>(format_desc_.width*4))\r
{\r
const uint8_t *src_data[4] = {0};\r
if(ptr)\r
{\r
if(config_.key_only)\r
- fast_memshfl(reinterpret_cast<char*>(ptr), av_frame->data[0], frame->image_data().size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303);\r
+ fast_memshfl(reinterpret_cast<char*>(ptr), av_frame->data[0], image_data_size, 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303);\r
else\r
- fast_memcpy(reinterpret_cast<char*>(ptr), av_frame->data[0], frame->image_data().size());\r
+ fast_memcpy(reinterpret_cast<char*>(ptr), av_frame->data[0], image_data_size);\r
\r
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); // release the mapped buffer\r
}\r
\r
bool send(const safe_ptr<core::read_frame>& frame)\r
{\r
- if(!frame_buffer_.try_push(frame))\r
- graph_->set_tag("dropped-frame");\r
+ if (!frame_buffer_.try_push(frame))\r
+ graph_->set_tag("dropped-frame"); \r
+\r
return is_running_;\r
}\r
\r