+/** @return a list of properties that might be interesting to the user */
+list<UserProperty>
+Content::user_properties (shared_ptr<const Film> film) const
+{
+ list<UserProperty> p;
+ add_properties (film, p);
+ return p;
+}
+
+/** @return DCP times of points within this content where a reel split could occur */
+list<DCPTime>
+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
+ to start on a frame boundary.
+ */
+ t.push_back (position());
+ return t;
+}
+
+void
+Content::set_video_frame_rate (double r)
+{
+ ChangeSignaller<Content> cc (this, ContentProperty::VIDEO_FRAME_RATE);
+
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ if (_video_frame_rate && fabs(r - *_video_frame_rate) < VIDEO_FRAME_RATE_EPSILON) {
+ cc.abort();
+ }
+ _video_frame_rate = r;
+ }
+
+ /* Make sure trim is still on a frame boundary */
+ if (video) {
+ set_trim_start (trim_start());
+ }
+}
+
+void
+Content::unset_video_frame_rate ()
+{
+ ChangeSignaller<Content> cc (this, ContentProperty::VIDEO_FRAME_RATE);
+
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _video_frame_rate = optional<double>();
+ }
+}
+
+double
+Content::active_video_frame_rate (shared_ptr<const Film> film) const