+ _subtitle_asset->add (shared_ptr<dcp::Subtitle>(new dcp::SubtitleString(i)));
+ }
+
+ BOOST_FOREACH (BitmapText i, subs.image) {
+ _subtitle_asset->add (
+ shared_ptr<dcp::Subtitle>(
+ new dcp::SubtitleImage(
+ i.image->as_png(),
+ dcp::Time(period.from.seconds(), _film->video_frame_rate()),
+ dcp::Time(period.to.seconds(), _film->video_frame_rate()),
+ i.rectangle.x, dcp::HALIGN_LEFT, i.rectangle.y, dcp::VALIGN_TOP,
+ dcp::Time(), dcp::Time()
+ )
+ )
+ );
+ }
+}
+
+bool
+ReelWriter::existing_picture_frame_ok (FILE* asset_file, FILE* info_file, Frame frame) const
+{
+ LOG_GENERAL ("Checking existing picture frame %1", frame);
+
+ /* Read the data from the info file; for 3D we just check the left
+ frames until we find a good one.
+ */
+ dcp::FrameInfo const info = read_frame_info (info_file, frame, _film->three_d () ? EYES_LEFT : EYES_BOTH);
+
+ bool ok = true;
+
+ /* Read the data from the asset and hash it */
+ dcpomatic_fseek (asset_file, info.offset, SEEK_SET);
+ Data data (info.size);
+ size_t const read = fread (data.data().get(), 1, data.size(), asset_file);
+ LOG_GENERAL ("Read %1 bytes of asset data; wanted %2", read, info.size);
+ if (read != static_cast<size_t> (data.size ())) {
+ LOG_GENERAL ("Existing frame %1 is incomplete", frame);
+ ok = false;
+ } else {
+ Digester digester;
+ digester.add (data.data().get(), data.size());
+ LOG_GENERAL ("Hash %1 vs %2", digester.get(), info.hash);
+ if (digester.get() != info.hash) {
+ LOG_GENERAL ("Existing frame %1 failed hash check", frame);
+ ok = false;
+ }