+ // Some trial and error and undeterministic stuff here
+ static const int NUM_RETRIES = 32;
+
+ if (file_position > 0) // Assume frames are requested in sequential order,
+ // therefore no seeking should be necessary for the first frame.
+ {
+ input_.seek(file_position > 1 ? file_position - 2: file_position).get();
+ boost::this_thread::sleep(boost::posix_time::milliseconds(40));
+ }
+
+ for (int i = 0; i < NUM_RETRIES; ++i)
+ {
+ boost::this_thread::sleep(boost::posix_time::milliseconds(40));
+
+ auto frame = render_frame();
+
+ if (frame.second == std::numeric_limits<uint32_t>::max())
+ {
+ // Retry
+ continue;
+ }
+ else if (frame.second == file_position + 1 || frame.second == file_position)
+ return frame.first;
+ else if (frame.second > file_position + 1)
+ {
+ CASPAR_LOG(trace) << print() << L" " << frame.second << L" received, wanted " << file_position + 1;
+ int64_t adjusted_seek = file_position - (frame.second - file_position + 1);
+
+ if (adjusted_seek > 1 && file_position > 0)
+ {
+ CASPAR_LOG(trace) << print() << L" adjusting to " << adjusted_seek;
+ input_.seek(static_cast<uint32_t>(adjusted_seek) - 1).get();
+ boost::this_thread::sleep(boost::posix_time::milliseconds(40));
+ }
+ else
+ return frame.first;
+ }
+ }
+
+ CASPAR_LOG(trace) << print() << " Giving up finding frame at " << file_position;
+ return core::draw_frame::empty();
+ }
+
+ core::draw_frame create_thumbnail_frame()
+ {
+ auto total_frames = nb_frames();
+ auto grid = env::properties().get(L"configuration.thumbnails.video-grid", 2);
+
+ if (grid < 1)
+ {
+ CASPAR_LOG(error) << L"configuration/thumbnails/video-grid cannot be less than 1";
+ BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("configuration/thumbnails/video-grid cannot be less than 1"));
+ }
+
+ if (grid == 1)
+ {
+ return render_specific_frame(total_frames / 2);
+ }
+
+ auto num_snapshots = grid * grid;
+
+ std::vector<core::draw_frame> frames;
+
+ for (int i = 0; i < num_snapshots; ++i)
+ {
+ int x = i % grid;
+ int y = i / grid;
+ int desired_frame;
+
+ if (i == 0)
+ desired_frame = 0; // first
+ else if (i == num_snapshots - 1)
+ desired_frame = total_frames - 1; // last
+ else
+ // evenly distributed across the file.
+ desired_frame = total_frames * i / (num_snapshots - 1);
+
+ auto frame = render_specific_frame(desired_frame);
+ frame.transform().image_transform.fill_scale[0] = 1.0 / static_cast<double>(grid);
+ frame.transform().image_transform.fill_scale[1] = 1.0 / static_cast<double>(grid);
+ frame.transform().image_transform.fill_translation[0] = 1.0 / static_cast<double>(grid) * x;
+ frame.transform().image_transform.fill_translation[1] = 1.0 / static_cast<double>(grid) * y;
+
+ frames.push_back(frame);
+ }
+
+ return core::draw_frame(frames);
+ }
+
+ uint32_t file_frame_number() const
+ {
+ return video_decoder_ ? video_decoder_->file_frame_number() : 0;