Fix referencing of trimmed multi-reel DCPs (#1495).
authorCarl Hetherington <cth@carlh.net>
Fri, 22 Mar 2019 21:31:37 +0000 (21:31 +0000)
committerCarl Hetherington <cth@carlh.net>
Fri, 22 Mar 2019 21:31:37 +0000 (21:31 +0000)
src/lib/player.cc
test/vf_test.cc

index 537a719..96c963e 100644 (file)
@@ -463,6 +463,19 @@ Player::set_play_referenced ()
        setup_pieces_unlocked ();
 }
 
+static void
+maybe_add_asset (list<ReferencedReelAsset>& a, shared_ptr<dcp::ReelAsset> r, Frame reel_trim_start, Frame reel_trim_end, DCPTime from, int const ffr)
+{
+       DCPOMATIC_ASSERT (r);
+       r->set_entry_point (r->entry_point() + reel_trim_start);
+       r->set_duration (r->duration() - reel_trim_start - reel_trim_end);
+       if (r->duration() > 0) {
+               a.push_back (
+                       ReferencedReelAsset(r, DCPTimePeriod(from, from + DCPTime::from_frames(r->duration(), ffr)))
+                       );
+       }
+}
+
 list<ReferencedReelAsset>
 Player::get_reel_assets ()
 {
@@ -483,59 +496,51 @@ Player::get_reel_assets ()
                        return a;
                }
 
-               int64_t offset = 0;
+               DCPOMATIC_ASSERT (j->video_frame_rate ());
+               double const cfr = j->video_frame_rate().get();
+               Frame const trim_start = j->trim_start().frames_round (cfr);
+               Frame const trim_end = j->trim_end().frames_round (cfr);
+               int const ffr = _film->video_frame_rate ();
+
+               /* position in the asset from the start */
+               int64_t offset_from_start = 0;
+               /* position in the asset from the end */
+               int64_t offset_from_end = 0;
+               BOOST_FOREACH (shared_ptr<dcp::Reel> k, decoder->reels()) {
+                       /* Assume that main picture duration is the length of the reel */
+                       offset_from_end += k->main_picture()->duration();
+               }
+
                BOOST_FOREACH (shared_ptr<dcp::Reel> k, decoder->reels()) {
 
-                       DCPOMATIC_ASSERT (j->video_frame_rate ());
-                       double const cfr = j->video_frame_rate().get();
-                       Frame const trim_start = j->trim_start().frames_round (cfr);
-                       Frame const trim_end = j->trim_end().frames_round (cfr);
-                       int const ffr = _film->video_frame_rate ();
+                       /* Assume that main picture duration is the length of the reel */
+                       int64_t const reel_duration = k->main_picture()->duration();
+
+                       /* See doc/design/trim_reels.svg */
+                       Frame const reel_trim_start = min(reel_duration, max(0L, trim_start - offset_from_start));
+                       Frame const reel_trim_end =   min(reel_duration, max(0L, reel_duration - (offset_from_end - trim_end)));
 
-                       DCPTime const from = i->position() + DCPTime::from_frames (offset, _film->video_frame_rate());
+                       DCPTime const from = i->position() + DCPTime::from_frames (offset_from_start, _film->video_frame_rate());
                        if (j->reference_video ()) {
-                               shared_ptr<dcp::ReelAsset> ra = k->main_picture ();
-                               DCPOMATIC_ASSERT (ra);
-                               ra->set_entry_point (ra->entry_point() + trim_start);
-                               ra->set_duration (ra->duration() - trim_start - trim_end);
-                               a.push_back (
-                                       ReferencedReelAsset (ra, DCPTimePeriod (from, from + DCPTime::from_frames (ra->duration(), ffr)))
-                                       );
+                               maybe_add_asset (a, k->main_picture(), reel_trim_start, reel_trim_end, from, ffr);
                        }
 
                        if (j->reference_audio ()) {
-                               shared_ptr<dcp::ReelAsset> ra = k->main_sound ();
-                               DCPOMATIC_ASSERT (ra);
-                               ra->set_entry_point (ra->entry_point() + trim_start);
-                               ra->set_duration (ra->duration() - trim_start - trim_end);
-                               a.push_back (
-                                       ReferencedReelAsset (ra, DCPTimePeriod (from, from + DCPTime::from_frames (ra->duration(), ffr)))
-                                       );
+                               maybe_add_asset (a, k->main_sound(), reel_trim_start, reel_trim_end, from, ffr);
                        }
 
                        if (j->reference_text (TEXT_OPEN_SUBTITLE)) {
-                               shared_ptr<dcp::ReelAsset> ra = k->main_subtitle ();
-                               DCPOMATIC_ASSERT (ra);
-                               ra->set_entry_point (ra->entry_point() + trim_start);
-                               ra->set_duration (ra->duration() - trim_start - trim_end);
-                               a.push_back (
-                                       ReferencedReelAsset (ra, DCPTimePeriod (from, from + DCPTime::from_frames (ra->duration(), ffr)))
-                                       );
+                               maybe_add_asset (a, k->main_subtitle(), reel_trim_start, reel_trim_end, from, ffr);
                        }
 
                        if (j->reference_text (TEXT_CLOSED_CAPTION)) {
                                BOOST_FOREACH (shared_ptr<dcp::ReelClosedCaptionAsset> l, k->closed_captions()) {
-                                       DCPOMATIC_ASSERT (l);
-                                       l->set_entry_point (l->entry_point() + trim_start);
-                                       l->set_duration (l->duration() - trim_start - trim_end);
-                                       a.push_back (
-                                               ReferencedReelAsset (l, DCPTimePeriod (from, from + DCPTime::from_frames (l->duration(), ffr)))
-                                               );
+                                       maybe_add_asset (a, l, reel_trim_start, reel_trim_end, from, ffr);
                                }
                        }
 
-                       /* Assume that main picture duration is the length of the reel */
-                       offset += k->main_picture()->duration ();
+                       offset_from_start += reel_duration;
+                       offset_from_end -= reel_duration;
                }
        }
 
index 540e8da..b36cc65 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2015-2017 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2015-2019 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
@@ -29,6 +29,8 @@
 #include "lib/content_factory.h"
 #include "lib/dcp_content_type.h"
 #include "lib/video_content.h"
+#include "lib/referenced_reel_asset.h"
+#include "lib/player.h"
 #include "test.h"
 #include <dcp/cpl.h>
 #include <dcp/reel.h>
@@ -36,6 +38,7 @@
 #include <dcp/reel_sound_asset.h>
 #include <boost/test/unit_test.hpp>
 #include <boost/foreach.hpp>
+#include <iostream>
 
 using std::list;
 using std::string;
@@ -283,4 +286,18 @@ BOOST_AUTO_TEST_CASE (vf_test5)
        dcp->set_trim_end (ContentTime::from_seconds(15));
        vf->make_dcp ();
        BOOST_REQUIRE (!wait_for_jobs());
+
+       /* Check that the selected reel assets are right */
+       shared_ptr<Player> player (new Player(vf, vf->playlist()));
+       list<ReferencedReelAsset> a = player->get_reel_assets();
+       BOOST_REQUIRE_EQUAL (a.size(), 4);
+       list<ReferencedReelAsset>::const_iterator i = a.begin();
+       BOOST_CHECK (i->period == DCPTimePeriod(DCPTime(0), DCPTime(960000)));
+       ++i;
+       BOOST_CHECK (i->period == DCPTimePeriod(DCPTime(0), DCPTime(960000)));
+       ++i;
+       BOOST_CHECK (i->period == DCPTimePeriod(DCPTime(960000), DCPTime(1440000)));
+       ++i;
+       BOOST_CHECK (i->period == DCPTimePeriod(DCPTime(960000), DCPTime(1440000)));
+       ++i;
 }