+
+void
+VideoContent::set_left_crop (int c)
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+
+ if (_crop.left == c) {
+ return;
+ }
+
+ _crop.left = c;
+ }
+
+ signal_changed (VideoContentProperty::VIDEO_CROP);
+}
+
+void
+VideoContent::set_right_crop (int c)
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ if (_crop.right == c) {
+ return;
+ }
+
+ _crop.right = c;
+ }
+
+ signal_changed (VideoContentProperty::VIDEO_CROP);
+}
+
+void
+VideoContent::set_top_crop (int c)
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ if (_crop.top == c) {
+ return;
+ }
+
+ _crop.top = c;
+ }
+
+ signal_changed (VideoContentProperty::VIDEO_CROP);
+}
+
+void
+VideoContent::set_bottom_crop (int c)
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ if (_crop.bottom == c) {
+ return;
+ }
+
+ _crop.bottom = c;
+ }
+
+ signal_changed (VideoContentProperty::VIDEO_CROP);
+}
+
+void
+VideoContent::set_ratio (Ratio const * r)
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ if (_ratio == r) {
+ return;
+ }
+
+ _ratio = r;
+ }
+
+ signal_changed (VideoContentProperty::VIDEO_RATIO);
+}
+
+/** @return string which includes everything about how this content looks */
+string
+VideoContent::identifier () const
+{
+ stringstream s;
+ s << Content::identifier()
+ << "_" << crop().left
+ << "_" << crop().right
+ << "_" << crop().top
+ << "_" << crop().bottom
+ << "_" << colour_conversion().identifier ();
+
+ if (ratio()) {
+ s << "_" << ratio()->id ();
+ }
+
+ return s.str ();
+}
+
+void
+VideoContent::set_video_frame_type (VideoFrameType t)
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _video_frame_type = t;
+ }
+
+ signal_changed (VideoContentProperty::VIDEO_FRAME_TYPE);
+}
+
+string
+VideoContent::technical_summary () const
+{
+ return String::compose ("video: length %1, size %2x%3, rate %4", video_length(), video_size().width, video_size().height, video_frame_rate());
+}
+
+libdcp::Size
+VideoContent::video_size_after_3d_split () const
+{
+ libdcp::Size const s = video_size ();
+ switch (video_frame_type ()) {
+ case VIDEO_FRAME_TYPE_2D:
+ return s;
+ case VIDEO_FRAME_TYPE_3D_LEFT_RIGHT:
+ return libdcp::Size (s.width / 2, s.height);
+ }
+
+ assert (false);
+}
+
+void
+VideoContent::set_colour_conversion (ColourConversion c)
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _colour_conversion = c;
+ }
+
+ signal_changed (VideoContentProperty::COLOUR_CONVERSION);
+}
+
+/** @return Video size after 3D split and crop */
+libdcp::Size
+VideoContent::video_size_after_crop () const
+{
+ return crop().apply (video_size_after_3d_split ());
+}
+
+/** @param t A time offset from the start of this piece of content.
+ * @return Corresponding frame index.
+ */
+VideoContent::Frame
+VideoContent::time_to_content_video_frames (Time t) const
+{
+ shared_ptr<const Film> film = _film.lock ();
+ assert (film);
+
+ FrameRateConversion frc (video_frame_rate(), film->video_frame_rate());
+
+ /* Here we are converting from time (in the DCP) to a frame number in the content.
+ Hence we need to use the DCP's frame rate and the double/skip correction, not
+ the source's rate.
+ */
+ return t * film->video_frame_rate() / (frc.factor() * TIME_HZ);
+}