Some attempts to block referencing of DCPs when it is not possible.
authorCarl Hetherington <cth@carlh.net>
Tue, 13 Oct 2015 10:30:30 +0000 (11:30 +0100)
committerCarl Hetherington <cth@carlh.net>
Tue, 13 Oct 2015 10:30:30 +0000 (11:30 +0100)
14 files changed:
hacks/fft.py [new file with mode: 0644]
src/lib/dcp_content.cc
src/lib/dcp_content.h
src/lib/dcpomatic_time.h
src/lib/overlaps.h [new file with mode: 0644]
src/lib/referenced_reel_asset.h [new file with mode: 0644]
src/wx/audio_panel.cc
src/wx/subtitle_panel.cc
src/wx/timeline.cc
src/wx/video_panel.cc
test/fft.py [new file with mode: 0644]
test/reels_test.cc [new file with mode: 0644]
test/vf_test.cc [new file with mode: 0644]
test/wscript

diff --git a/hacks/fft.py b/hacks/fft.py
new file mode 100644 (file)
index 0000000..ab700a5
--- /dev/null
@@ -0,0 +1,50 @@
+#!/usr/bin/python
+
+import wave
+import sys
+import struct
+from pylab import *
+import numpy
+
+f = wave.open(sys.argv[1], 'rb')
+width = f.getsampwidth()
+peak = pow(2, width * 8) / 2
+channels = f.getnchannels()
+frames = f.getnframes()
+print '%d bytes per sample' % width
+print '%d channels' % channels
+print '%d frames' % frames
+data = []
+for i in range(0, channels):
+    data.append([])
+
+for i in range(0, frames):
+    frame = f.readframes(1)
+    for j in range(0, channels):
+        v = 0
+        for k in range(0, width):
+            v |= ord(frame[j * width + k]) << (k * 8)
+        if v >= peak:
+            v = v - 2 * peak
+        data[j].append(v)
+
+f.close()
+
+names = ['L', 'R', 'C', 'Lfe', 'Ls', 'Rs']
+dyn_range = 20 * log10(pow(2, 23))
+
+for i in range(0, channels):
+    s = numpy.fft.fft(data[i])
+#    subplot(channels, 1, i + 1)
+    # 138.5 is a fudge factor:
+    semilogx(arange(0, frames / 2, 0.5), 20 * log10(abs(s) + 0.1) - dyn_range, label = names[i])
+    xlim(100, frames / 4)
+plt.gca().xaxis.grid(True, which='major')
+plt.gca().xaxis.grid(True, which='minor')
+plt.gca().yaxis.grid(True)
+legend(loc = 'lower right')
+show()
+
+#plot(abs(numpy.fft.fft(data[0])))
+#plot(data[0])
+#show()
index f39b2fb4a221c8070199d01aa3629972fc07a352..747216f3c666853a212bc3291d7262c0b744ed11 100644 (file)
@@ -22,6 +22,7 @@
 #include "job.h"
 #include "film.h"
 #include "config.h"
+#include "overlaps.h"
 #include "compose.hpp"
 #include "dcp_decoder.h"
 #include <dcp/dcp.h>
@@ -250,19 +251,75 @@ DCPContent::set_reference_subtitle (bool r)
        signal_changed (DCPContentProperty::REFERENCE_SUBTITLE);
 }
 
+list<DCPTimePeriod>
+DCPContent::reels () const
+{
+       list<DCPTimePeriod> p;
+       DCPDecoder decoder (shared_from_this(), false);
+
+       shared_ptr<const Film> film = _film.lock ();
+       DCPOMATIC_ASSERT (film);
+       DCPTime from = position ();
+       BOOST_FOREACH (shared_ptr<dcp::Reel> i, decoder.reels()) {
+               DCPTime const to = from + DCPTime::from_frames (i->main_picture()->duration(), film->video_frame_rate());
+               p.push_back (DCPTimePeriod (from, to));
+               from = to;
+       }
+
+       return p;
+}
+
 list<DCPTime>
 DCPContent::reel_split_points () const
 {
        list<DCPTime> s;
-       DCPDecoder decoder (shared_from_this(), false);
-       DCPTime t = position();
+       BOOST_FOREACH (DCPTimePeriod i, reels()) {
+               s.push_back (i.from);
+       }
+       return s;
+}
 
+template <class T>
+bool
+DCPContent::can_reference (string overlapping, list<string>& why_not) const
+{
        shared_ptr<const Film> film = _film.lock ();
        DCPOMATIC_ASSERT (film);
-       BOOST_FOREACH (shared_ptr<dcp::Reel> k, decoder.reels()) {
-               s.push_back (t);
-               t += DCPTime::from_frames (k->main_picture()->duration(), film->video_frame_rate());
+
+       list<DCPTimePeriod> const fr = film->reels ();
+       /* fr must contain reels().  It can also contain other reels, but it must at
+          least contain reels().
+       */
+       BOOST_FOREACH (DCPTimePeriod i, reels()) {
+               if (find (fr.begin(), fr.end(), i) == fr.end ()) {
+                       why_not.push_back (_("Reel lengths in the project differ from those in the DCP; set the reel mode to `split by video content'."));
+                       return false;
+               }
        }
 
-       return s;
+       list<shared_ptr<T> > a = overlaps<T> (film->content(), position(), end());
+       if (a.size() != 1 || a.front().get() != this) {
+               why_not.push_back (overlapping);
+               return false;
+       }
+
+       return true;
+}
+
+bool
+DCPContent::can_reference_video (list<string>& why_not) const
+{
+       return can_reference<VideoContent> (_("There is other video content overlapping this DCP; remove it."), why_not);
+}
+
+bool
+DCPContent::can_reference_audio (list<string>& why_not) const
+{
+       return can_reference<AudioContent> (_("There is other audio content overlapping this DCP; remove it."), why_not);
+}
+
+bool
+DCPContent::can_reference_subtitle (list<string>& why_not) const
+{
+       return can_reference<SubtitleContent> (_("There is other subtitle content overlapping this DCP; remove it."), why_not);
 }
index be12ba5346eb7f81fa85dd75eec0df625818f8d3..78c97bec513026d3470640ea01b1c02075693a13 100644 (file)
@@ -104,6 +104,8 @@ public:
                return _reference_video;
        }
 
+       bool can_reference_video (std::list<std::string> &) const;
+
        void set_reference_audio (bool r);
 
        bool reference_audio () const {
@@ -111,6 +113,8 @@ public:
                return _reference_audio;
        }
 
+       bool can_reference_audio (std::list<std::string> &) const;
+
        void set_reference_subtitle (bool r);
 
        bool reference_subtitle () const {
@@ -118,11 +122,15 @@ public:
                return _reference_subtitle;
        }
 
+       bool can_reference_subtitle (std::list<std::string> &) const;
+
 protected:
        void add_properties (std::list<std::pair<std::string, std::string> >& p) const;
 
 private:
        void read_directory (boost::filesystem::path);
+       std::list<DCPTimePeriod> reels () const;
+       template <class T> bool can_reference (std::string overlapping, std::list<std::string>& why_not) const;
 
        std::string _name;
        bool _has_subtitles;
index 496f54d8efdb7fbf57a65a0fef0fc2ddc7505a9e..90e79de0a7b4cec45cee0a495d63554f2a6fa2c6 100644 (file)
@@ -258,7 +258,7 @@ public:
                return (from <= other && other < to);
        }
 
-       bool operator== (TimePeriod<T> const & other) {
+       bool operator== (TimePeriod<T> const & other) const {
                return from == other.from && to == other.to;
        }
 };
diff --git a/src/lib/overlaps.h b/src/lib/overlaps.h
new file mode 100644 (file)
index 0000000..6018af1
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+    Copyright (C) 2013-2015 Carl Hetherington <cth@carlh.net>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @return Pieces of content type C that overlap a specified time range in the given ContentList */
+template<class C>
+std::list<boost::shared_ptr<C> >
+overlaps (ContentList cl, DCPTime from, DCPTime to)
+{
+       std::list<boost::shared_ptr<C> > overlaps;
+       DCPTimePeriod period (from, to);
+       for (typename ContentList::const_iterator i = cl.begin(); i != cl.end(); ++i) {
+               boost::shared_ptr<C> c = boost::dynamic_pointer_cast<C> (*i);
+               if (!c) {
+                       continue;
+               }
+
+               if (DCPTimePeriod(c->position(), c->end()).overlaps (period)) {
+                       overlaps.push_back (c);
+               }
+       }
+
+       return overlaps;
+}
diff --git a/src/lib/referenced_reel_asset.h b/src/lib/referenced_reel_asset.h
new file mode 100644 (file)
index 0000000..5f54212
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+    Copyright (C) 2015 Carl Hetherington <cth@carlh.net>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+class ReferencedReelAsset
+{
+public:
+       ReferencedReelAsset (boost::shared_ptr<dcp::ReelAsset> asset_, DCPTimePeriod period_)
+               : asset (asset_)
+               , period (period_)
+       {}
+
+       /** The asset */
+       boost::shared_ptr<dcp::ReelAsset> asset;
+       /** Period that this asset covers in the DCP */
+       DCPTimePeriod period;
+};
index a4976b8c1bca172e888692f0aff3f78c71c3d429..9632b5235465a3c82b87e495fb40a900223e9fb0 100644 (file)
@@ -141,6 +141,8 @@ AudioPanel::film_changed (Film::Property property)
        case Film::VIDEO_FRAME_RATE:
                setup_description ();
                break;
+       case Film::REEL_TYPE:
+               setup_sensitivity ();
        default:
                break;
        }
@@ -238,7 +240,24 @@ void
 AudioPanel::setup_sensitivity ()
 {
        AudioContentList sel = _parent->selected_audio ();
-       _reference->Enable (sel.size() == 1 && dynamic_pointer_cast<DCPContent> (sel.front ()));
+
+       shared_ptr<DCPContent> dcp;
+       if (sel.size() == 1) {
+               dcp = dynamic_pointer_cast<DCPContent> (sel.front ());
+       }
+
+       list<string> why_not;
+       bool const can_reference = dcp && dcp->can_reference_audio (why_not);
+       _reference->Enable (can_reference);
+
+       wxString s;
+       if (!can_reference) {
+               s = _("Cannot reference this DCP.  ");
+               BOOST_FOREACH (string i, why_not) {
+                       s += std_to_wx(i) + wxT("  ");
+               }
+       }
+       _reference->SetToolTip (s);
 
        if (_reference->GetValue ()) {
                _gain->wrapped()->Enable (false);
index f3083b194bb4a38c57c32b44f68ce588164f0441..757a302a124ab8db3678a297ecf61da10aa908b6 100644 (file)
@@ -36,6 +36,7 @@
 
 using std::vector;
 using std::string;
+using std::list;
 using boost::shared_ptr;
 using boost::lexical_cast;
 using boost::dynamic_pointer_cast;
@@ -133,7 +134,7 @@ SubtitlePanel::SubtitlePanel (ContentPanel* p)
 void
 SubtitlePanel::film_changed (Film::Property property)
 {
-       if (property == Film::CONTENT) {
+       if (property == Film::CONTENT || property == Film::REEL_TYPE) {
                setup_sensitivity ();
        }
 }
@@ -219,7 +220,8 @@ SubtitlePanel::setup_sensitivity ()
        int ffmpeg_subs = 0;
        int subrip_or_dcp_subs = 0;
        int image_subs = 0;
-       BOOST_FOREACH (shared_ptr<SubtitleContent> i, _parent->selected_subtitle ()) {
+       SubtitleContentList sel = _parent->selected_subtitle ();
+       BOOST_FOREACH (shared_ptr<SubtitleContent> i, sel) {
                shared_ptr<const FFmpegContent> fc = boost::dynamic_pointer_cast<const FFmpegContent> (i);
                shared_ptr<const SubRipContent> sc = boost::dynamic_pointer_cast<const SubRipContent> (i);
                shared_ptr<const DCPSubtitleContent> dsc = boost::dynamic_pointer_cast<const DCPSubtitleContent> (i);
@@ -242,6 +244,24 @@ SubtitlePanel::setup_sensitivity ()
                }
        }
 
+       shared_ptr<DCPContent> dcp;
+       if (sel.size() == 1) {
+               dcp = dynamic_pointer_cast<DCPContent> (sel.front ());
+       }
+
+       list<string> why_not;
+       bool const can_reference = dcp && dcp->can_reference_subtitle (why_not);
+       _reference->Enable (can_reference);
+
+       wxString s;
+       if (!can_reference) {
+               s = _("Cannot reference this DCP.  ");
+               BOOST_FOREACH (string i, why_not) {
+                       s += std_to_wx(i) + wxT("  ");
+               }
+       }
+       _reference->SetToolTip (s);
+
        bool const reference = _reference->GetValue ();
 
        _use->Enable (!reference && any_subs > 0);
@@ -255,9 +275,6 @@ SubtitlePanel::setup_sensitivity ()
        _stream->Enable (!reference && ffmpeg_subs == 1);
        _subtitle_view_button->Enable (!reference && subrip_or_dcp_subs == 1);
        _fonts_dialog_button->Enable (!reference && subrip_or_dcp_subs == 1);
-
-       ContentList sel = _parent->selected ();
-       _reference->Enable (sel.size() == 1 && dynamic_pointer_cast<DCPContent> (sel.front ()));
 }
 
 void
index c1afdd369cfbb8d231c93304289e2843c01de7a5..f91d2937f44ed51ac23aa94cff8a0bbe5674914f 100644 (file)
@@ -168,6 +168,7 @@ Timeline::assign_tracks ()
                }
 
                shared_ptr<Content> content = cv->content();
+               DCPTimePeriod content_period (content->position(), content->end());
 
                int t = 0;
                while (true) {
@@ -182,11 +183,7 @@ Timeline::assign_tracks ()
                                shared_ptr<Content> test_content = test->content();
 
                                if (test && test->track() && test->track().get() == t) {
-                                       bool const no_overlap =
-                                               (content->position() < test_content->position() && content->end() < test_content->position()) ||
-                                               (content->position() > test_content->end()      && content->end() > test_content->end());
-
-                                       if (!no_overlap) {
+                                       if (content_period.overlaps (DCPTimePeriod(test_content->position(), test_content->end()))) {
                                                /* we have an overlap on track `t' */
                                                ++t;
                                                break;
@@ -367,7 +364,7 @@ Timeline::set_position_from_event (wxMouseEvent& ev)
 
        if (_snap) {
 
-               DCPTime const new_end = new_position + _down_view->content()->length_after_trim () - DCPTime (1);
+               DCPTime const new_end = new_position + _down_view->content()->length_after_trim();
                /* Signed `distance' to nearest thing (i.e. negative is left on the timeline,
                   positive is right).
                */
@@ -381,9 +378,9 @@ Timeline::set_position_from_event (wxMouseEvent& ev)
                        }
 
                        maybe_snap (cv->content()->position(), new_position, nearest_distance);
-                       maybe_snap (cv->content()->position(), new_end + DCPTime (1), nearest_distance);
-                       maybe_snap (cv->content()->end() + DCPTime (1), new_position, nearest_distance);
-                       maybe_snap (cv->content()->end() + DCPTime (1), new_end, nearest_distance);
+                       maybe_snap (cv->content()->position(), new_end, nearest_distance);
+                       maybe_snap (cv->content()->end(), new_position, nearest_distance);
+                       maybe_snap (cv->content()->end(), new_end, nearest_distance);
                }
 
                if (nearest_distance) {
index dd9bb58489dfadac1a6f93ac610c3c416db36fa2..79ea9dbfa3e99e4b05200ac0972c4867d654d0d2 100644 (file)
@@ -246,6 +246,8 @@ VideoPanel::film_changed (Film::Property property)
        case Film::RESOLUTION:
                setup_description ();
                break;
+       case Film::REEL_TYPE:
+               setup_sensitivity ();
        default:
                break;
        }
@@ -434,7 +436,24 @@ void
 VideoPanel::setup_sensitivity ()
 {
        ContentList sel = _parent->selected ();
-       _reference->Enable (sel.size() == 1 && dynamic_pointer_cast<DCPContent> (sel.front ()));
+
+       shared_ptr<DCPContent> dcp;
+       if (sel.size() == 1) {
+               dcp = dynamic_pointer_cast<DCPContent> (sel.front ());
+       }
+
+       list<string> why_not;
+       bool const can_reference = dcp && dcp->can_reference_video(why_not);
+       _reference->Enable (can_reference);
+
+       wxString s;
+       if (!can_reference) {
+               s = _("Cannot reference this DCP.  ");
+               BOOST_FOREACH (string i, why_not) {
+                       s += std_to_wx(i) + wxT("  ");
+               }
+       }
+       _reference->SetToolTip (s);
 
        if (_reference->GetValue ()) {
                _frame_type->wrapped()->Enable (false);
diff --git a/test/fft.py b/test/fft.py
new file mode 100644 (file)
index 0000000..bc6509f
--- /dev/null
@@ -0,0 +1,17 @@
+#!/usr/bin/python
+
+from pylab import *
+import numpy
+
+f = open('build/test/lpf_ir')
+ir = []
+while True:
+    l = f.readline()
+    if l == "":
+        break
+
+    ir.append(float(l.strip()))
+
+#plot(abs(numpy.fft.fft(ir)))
+plot(ir)
+show()
diff --git a/test/reels_test.cc b/test/reels_test.cc
new file mode 100644 (file)
index 0000000..85a9d07
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+    Copyright (C) 2015 Carl Hetherington <cth@carlh.net>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "lib/film.h"
+#include "lib/ratio.h"
+#include "lib/ffmpeg_content.h"
+#include "lib/image_content.h"
+#include "lib/dcp_content_type.h"
+#include "lib/dcp_content.h"
+#include "test.h"
+#include <boost/test/unit_test.hpp>
+
+using std::list;
+using boost::shared_ptr;
+
+/** Test Film::reels() */
+BOOST_AUTO_TEST_CASE (reels_test1)
+{
+       shared_ptr<Film> film = new_test_film ("reels_test1");
+       film->set_container (Ratio::from_id ("185"));
+       shared_ptr<FFmpegContent> A (new FFmpegContent (film, "test/data/test.mp4"));
+       film->examine_and_add_content (A);
+       shared_ptr<FFmpegContent> B (new FFmpegContent (film, "test/data/test.mp4"));
+       film->examine_and_add_content (B);
+       wait_for_jobs ();
+       BOOST_CHECK_EQUAL (A->full_length(), DCPTime (288000));
+
+       film->set_reel_type (REELTYPE_SINGLE);
+       list<DCPTimePeriod> r = film->reels ();
+       BOOST_CHECK_EQUAL (r.size(), 1);
+       BOOST_CHECK_EQUAL (r.front().from, DCPTime (0));
+       BOOST_CHECK_EQUAL (r.front().to, DCPTime (288000 * 2));
+
+       film->set_reel_type (REELTYPE_BY_VIDEO_CONTENT);
+       r = film->reels ();
+       BOOST_CHECK_EQUAL (r.size(), 2);
+       BOOST_CHECK_EQUAL (r.front().from, DCPTime (0));
+       BOOST_CHECK_EQUAL (r.front().to, DCPTime (288000));
+       BOOST_CHECK_EQUAL (r.back().from, DCPTime (288000));
+       BOOST_CHECK_EQUAL (r.back().to, DCPTime (288000 * 2));
+
+       film->set_j2k_bandwidth (100000000);
+       film->set_reel_type (REELTYPE_BY_LENGTH);
+       /* This is just over 2.5s at 100Mbit/s; should correspond to 60 frames */
+       film->set_reel_length (31253154);
+       r = film->reels ();
+       BOOST_CHECK_EQUAL (r.size(), 3);
+       list<DCPTimePeriod>::const_iterator i = r.begin ();
+       BOOST_CHECK_EQUAL (i->from, DCPTime (0));
+       BOOST_CHECK_EQUAL (i->to, DCPTime::from_frames (60, 24));
+       ++i;
+       BOOST_CHECK_EQUAL (i->from, DCPTime::from_frames (60, 24));
+       BOOST_CHECK_EQUAL (i->to, DCPTime::from_frames (120, 24));
+       ++i;
+       BOOST_CHECK_EQUAL (i->from, DCPTime::from_frames (120, 24));
+       BOOST_CHECK_EQUAL (i->to, DCPTime::from_frames (144, 24));
+}
+
+/** Make a short DCP with multi reels split by video content, then import
+ *  this into a new project and make a new DCP referencing it.
+ */
+BOOST_AUTO_TEST_CASE (reels_test2)
+{
+       shared_ptr<Film> film = new_test_film ("reels_test2");
+       film->set_name ("reels_test2");
+       film->set_container (Ratio::from_id ("185"));
+       film->set_dcp_content_type (DCPContentType::from_pretty_name ("Test"));
+
+       {
+               shared_ptr<ImageContent> c (new ImageContent (film, "test/data/flat_red.png"));
+               film->examine_and_add_content (c);
+               wait_for_jobs ();
+               c->set_video_length (24);
+       }
+
+       {
+               shared_ptr<ImageContent> c (new ImageContent (film, "test/data/flat_green.png"));
+               film->examine_and_add_content (c);
+               wait_for_jobs ();
+               c->set_video_length (24);
+       }
+
+       {
+               shared_ptr<ImageContent> c (new ImageContent (film, "test/data/flat_blue.png"));
+               film->examine_and_add_content (c);
+               wait_for_jobs ();
+               c->set_video_length (24);
+       }
+
+       film->set_reel_type (REELTYPE_BY_VIDEO_CONTENT);
+       wait_for_jobs ();
+
+       film->make_dcp ();
+       wait_for_jobs ();
+
+       check_dcp ("test/data/reels_test2", film->dir (film->dcp_name()));
+
+       shared_ptr<Film> film2 = new_test_film ("reels_test3");
+       film2->set_name ("reels_test3");
+       film2->set_container (Ratio::from_id ("185"));
+       film2->set_dcp_content_type (DCPContentType::from_pretty_name ("Test"));
+       film2->set_reel_type (REELTYPE_BY_VIDEO_CONTENT);
+
+       shared_ptr<DCPContent> c (new DCPContent (film2, film->dir (film->dcp_name ())));
+       film2->examine_and_add_content (c);
+       wait_for_jobs ();
+
+       list<DCPTimePeriod> r = film2->reels ();
+       BOOST_CHECK_EQUAL (r.size(), 3);
+       list<DCPTimePeriod>::const_iterator i = r.begin ();
+       BOOST_CHECK_EQUAL (i->from, DCPTime (0));
+       BOOST_CHECK_EQUAL (i->to, DCPTime (96000));
+       ++i;
+       BOOST_CHECK_EQUAL (i->from, DCPTime (96000));
+       BOOST_CHECK_EQUAL (i->to, DCPTime (96000 * 2));
+       ++i;
+       BOOST_CHECK_EQUAL (i->from, DCPTime (96000 * 2));
+       BOOST_CHECK_EQUAL (i->to, DCPTime (96000 * 3));
+
+       c->set_reference_video (true);
+       c->set_reference_audio (true);
+
+       film2->make_dcp ();
+       wait_for_jobs ();
+}
diff --git a/test/vf_test.cc b/test/vf_test.cc
new file mode 100644 (file)
index 0000000..904f1d5
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+    Copyright (C) 2015 Carl Hetherington <cth@carlh.net>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "lib/film.h"
+#include "lib/dcp_content.h"
+#include "lib/ffmpeg_content.h"
+#include "test.h"
+#include <boost/test/unit_test.hpp>
+
+using std::list;
+using std::string;
+using boost::shared_ptr;
+
+/** Test the logic which decides whether a DCP can be referenced or not */
+BOOST_AUTO_TEST_CASE (vf_test1)
+{
+       shared_ptr<Film> film = new_test_film ("vf_test1");
+       shared_ptr<DCPContent> dcp (new DCPContent (film, "test/data/reels_test2"));
+       film->examine_and_add_content (dcp);
+       wait_for_jobs ();
+
+       /* Multi-reel DCP can't be referenced if we are using a single reel for the project */
+       film->set_reel_type (REELTYPE_SINGLE);
+       list<string> why_not;
+       BOOST_CHECK (!dcp->can_reference_video(why_not));
+       BOOST_CHECK (!dcp->can_reference_audio(why_not));
+       BOOST_CHECK (!dcp->can_reference_subtitle(why_not));
+
+       /* Multi-reel DCP can be referenced if we are using by-video-content */
+       film->set_reel_type (REELTYPE_BY_VIDEO_CONTENT);
+       BOOST_CHECK (dcp->can_reference_video(why_not));
+       BOOST_CHECK (dcp->can_reference_audio(why_not));
+       BOOST_CHECK (dcp->can_reference_subtitle(why_not));
+
+       shared_ptr<FFmpegContent> other (new FFmpegContent (film, "test/data/test.mp4"));
+       film->examine_and_add_content (other);
+       wait_for_jobs ();
+
+       /* Not possible if there is overlap */
+       other->set_position (DCPTime (0));
+       BOOST_CHECK (!dcp->can_reference_video(why_not));
+       BOOST_CHECK (!dcp->can_reference_audio(why_not));
+       BOOST_CHECK (!dcp->can_reference_subtitle(why_not));
+
+       /* This should not be considered an overlap */
+       other->set_position (dcp->end ());
+       BOOST_CHECK (dcp->can_reference_video(why_not));
+       BOOST_CHECK (dcp->can_reference_audio(why_not));
+       BOOST_CHECK (dcp->can_reference_subtitle(why_not));
+}
index 89f84e836e87bf6d01f952751089dd9d648817f5..5cbc327e1c61c9f46e67a04f74525072684ffc6d 100644 (file)
@@ -85,6 +85,7 @@ def build(bld):
                  update_checker_test.cc
                  upmixer_a_test.cc
                  util_test.cc
+                 vf_test.cc
                  video_content_scale_test.cc
                  video_decoder_fill_test.cc
                  xml_subtitle_test.cc