Try rounding length_after_trim.
[dcpomatic.git] / src / lib / content.cc
index 6f5d23fd5ab04be2007c9b9e3b298d4b9c809f5f..2593c01df2ca7a569cf48f101d55883840dd0bed 100644 (file)
@@ -52,6 +52,7 @@ using boost::shared_ptr;
 using boost::optional;
 using dcp::raw_convert;
 using dcp::locale_convert;
+using namespace dcpomatic;
 
 int const ContentProperty::PATH = 400;
 int const ContentProperty::POSITION = 401;
@@ -60,9 +61,8 @@ int const ContentProperty::TRIM_START = 403;
 int const ContentProperty::TRIM_END = 404;
 int const ContentProperty::VIDEO_FRAME_RATE = 405;
 
-Content::Content (shared_ptr<const Film> film)
-       : _film (film)
-       , _position (0)
+Content::Content ()
+       : _position (0)
        , _trim_start (0)
        , _trim_end (0)
        , _change_signals_frequent (false)
@@ -70,9 +70,8 @@ Content::Content (shared_ptr<const Film> film)
 
 }
 
-Content::Content (shared_ptr<const Film> film, DCPTime p)
-       : _film (film)
-       , _position (p)
+Content::Content (DCPTime p)
+       : _position (p)
        , _trim_start (0)
        , _trim_end (0)
        , _change_signals_frequent (false)
@@ -80,9 +79,8 @@ Content::Content (shared_ptr<const Film> film, DCPTime p)
 
 }
 
-Content::Content (shared_ptr<const Film> film, boost::filesystem::path p)
-       : _film (film)
-       , _position (0)
+Content::Content (boost::filesystem::path p)
+       : _position (0)
        , _trim_start (0)
        , _trim_end (0)
        , _change_signals_frequent (false)
@@ -90,9 +88,8 @@ Content::Content (shared_ptr<const Film> film, boost::filesystem::path p)
        add_path (p);
 }
 
-Content::Content (shared_ptr<const Film> film, cxml::ConstNodePtr node)
-       : _film (film)
-       , _change_signals_frequent (false)
+Content::Content (cxml::ConstNodePtr node)
+       : _change_signals_frequent (false)
 {
        list<cxml::NodePtr> path_children = node->node_children ("Path");
        BOOST_FOREACH (cxml::NodePtr i, path_children) {
@@ -113,9 +110,8 @@ Content::Content (shared_ptr<const Film> film, cxml::ConstNodePtr node)
        _video_frame_rate = node->optional_number_child<double> ("VideoFrameRate");
 }
 
-Content::Content (shared_ptr<const Film> film, vector<shared_ptr<Content> > c)
-       : _film (film)
-       , _position (c.front()->position ())
+Content::Content (vector<shared_ptr<Content> > c)
+       : _position (c.front()->position ())
        , _trim_start (c.front()->trim_start ())
        , _trim_end (c.back()->trim_end ())
        , _video_frame_rate (c.front()->video_frame_rate())
@@ -184,7 +180,7 @@ Content::calculate_digest () const
 }
 
 void
-Content::examine (shared_ptr<Job> job)
+Content::examine (shared_ptr<const Film>, shared_ptr<Job> job)
 {
        if (job) {
                job->sub (_("Computing digest"));
@@ -210,29 +206,35 @@ Content::signal_change (ChangeType c, int p)
                } else {
                        emit (boost::bind (boost::ref(Change), c, shared_from_this(), p, _change_signals_frequent));
                }
-       } catch (boost::bad_weak_ptr) {
+       } catch (boost::bad_weak_ptr &) {
                /* This must be during construction; never mind */
        }
 }
 
 void
-Content::set_position (DCPTime p)
+Content::set_position (shared_ptr<const Film> film, DCPTime p, bool force_emit)
 {
        /* video and audio content can modify its position */
 
        if (video) {
-               video->modify_position (p);
+               video->modify_position (film, p);
        }
 
-       if (audio) {
-               audio->modify_position (p);
+       /* Only allow the audio to modify if we have no video;
+          sometimes p can't be on an integer video AND audio frame,
+          and in these cases we want the video constraint to be
+          satisfied since (I think) the audio code is better able to
+          cope.
+       */
+       if (!video && audio) {
+               audio->modify_position (film, p);
        }
 
        ChangeSignaller<Content> cc (this, ContentProperty::POSITION);
 
        {
                boost::mutex::scoped_lock lm (_mutex);
-               if (p == _position) {
+               if (p == _position && !force_emit) {
                        cc.abort ();
                        return;
                }
@@ -250,7 +252,8 @@ Content::set_trim_start (ContentTime t)
                video->modify_trim_start (t);
        }
 
-       if (audio) {
+       /* See note in ::set_position */
+       if (!video && audio) {
                audio->modify_trim_start (t);
        }
 
@@ -277,11 +280,6 @@ Content::set_trim_end (ContentTime t)
 shared_ptr<Content>
 Content::clone () const
 {
-       shared_ptr<const Film> film = _film.lock ();
-       if (!film) {
-               return shared_ptr<Content> ();
-       }
-
        /* This is a bit naughty, but I can't think of a compelling reason not to do it ... */
        xmlpp::Document doc;
        xmlpp::Node* node = doc.create_root_node ("Content");
@@ -289,7 +287,7 @@ Content::clone () const
 
        /* notes is unused here (we assume) */
        list<string> notes;
-       return content_factory (film, cxml::NodePtr (new cxml::Node (node)), Film::current_state_version, notes);
+       return content_factory (cxml::NodePtr(new cxml::Node(node)), Film::current_state_version, notes);
 }
 
 string
@@ -303,9 +301,9 @@ Content::technical_summary () const
 }
 
 DCPTime
-Content::length_after_trim () const
+Content::length_after_trim (shared_ptr<const Film> film) const
 {
-       return max (DCPTime (), full_length() - DCPTime (trim_start() + trim_end(), film()->active_frame_rate_change (position ())));
+       return max(DCPTime(), full_length(film) - DCPTime(trim_start() + trim_end(), film->active_frame_rate_change(position()))).round(film->video_frame_rate());
 }
 
 /** @return string which changes when something about this content changes which affects
@@ -366,24 +364,16 @@ Content::path_summary () const
 
 /** @return a list of properties that might be interesting to the user */
 list<UserProperty>
-Content::user_properties () const
+Content::user_properties (shared_ptr<const Film> film) const
 {
        list<UserProperty> p;
-       add_properties (p);
+       add_properties (film, p);
        return p;
 }
 
-shared_ptr<const Film>
-Content::film () const
-{
-       shared_ptr<const Film> film = _film.lock ();
-       DCPOMATIC_ASSERT (film);
-       return film;
-}
-
 /** @return DCP times of points within this content where a reel split could occur */
 list<DCPTime>
-Content::reel_split_points () const
+Content::reel_split_points (shared_ptr<const Film>) const
 {
        list<DCPTime> t;
        /* This is only called for video content and such content has its position forced
@@ -424,7 +414,7 @@ Content::unset_video_frame_rate ()
 }
 
 double
-Content::active_video_frame_rate () const
+Content::active_video_frame_rate (shared_ptr<const Film> film) const
 {
        {
                boost::mutex::scoped_lock lm (_mutex);
@@ -437,13 +427,11 @@ Content::active_video_frame_rate () const
           prepared for any concurrent video content or perhaps
           just the DCP rate.
        */
-       shared_ptr<const Film> film = _film.lock ();
-       DCPOMATIC_ASSERT (film);
        return film->active_frame_rate_change(position()).source;
 }
 
 void
-Content::add_properties (list<UserProperty>& p) const
+Content::add_properties (shared_ptr<const Film>, list<UserProperty>& p) const
 {
        p.push_back (UserProperty (UserProperty::GENERAL, _("Filename"), path(0).string ()));