using boost::optional;
using dcp::raw_convert;
using dcp::locale_convert;
+using namespace dcpomatic;
int const ContentProperty::PATH = 400;
int const ContentProperty::POSITION = 401;
int const ContentProperty::LENGTH = 402;
int const ContentProperty::TRIM_START = 403;
int const ContentProperty::TRIM_END = 404;
-int const ContentProperty::VIDEO_FRAME_RATE = 405;
+int const ContentProperty::TRIM_BEHAVIOUR = 405;
+int const ContentProperty::VIDEO_FRAME_RATE = 406;
Content::Content ()
: _position (0)
, _trim_start (0)
, _trim_end (0)
+ , _trim_behaviour (TRIM_CONTENT)
, _change_signals_frequent (false)
{
: _position (p)
, _trim_start (0)
, _trim_end (0)
+ , _trim_behaviour (TRIM_CONTENT)
, _change_signals_frequent (false)
{
: _position (0)
, _trim_start (0)
, _trim_end (0)
+ , _trim_behaviour (TRIM_CONTENT)
, _change_signals_frequent (false)
{
add_path (p);
_position = DCPTime (node->number_child<DCPTime::Type> ("Position"));
_trim_start = ContentTime (node->number_child<ContentTime::Type> ("TrimStart"));
_trim_end = ContentTime (node->number_child<ContentTime::Type> ("TrimEnd"));
+ _trim_behaviour = node->optional_string_child("TrimBehaviour").get_value_or("content") == "content" ? TRIM_CONTENT : TRIM_PLAYLIST;
_video_frame_rate = node->optional_number_child<double> ("VideoFrameRate");
}
throw JoinError (_("Only the last piece of content to be joined can have an end trim."));
}
+ if (_trim_behaviour != c[i]->_trim_behaviour) {
+ throw JoinError (_("Content to be joined must ahve the same trim behaviour setting"));
+ }
+
if (
(_video_frame_rate && !c[i]->_video_frame_rate) ||
(!_video_frame_rate && c[i]->_video_frame_rate)
node->add_child("Position")->add_child_text (raw_convert<string> (_position.get ()));
node->add_child("TrimStart")->add_child_text (raw_convert<string> (_trim_start.get ()));
node->add_child("TrimEnd")->add_child_text (raw_convert<string> (_trim_end.get ()));
+ node->add_child("TrimBehaviour")->add_child_text (_trim_behaviour == TRIM_CONTENT ? N_("content") : N_("playlist"));
if (_video_frame_rate) {
node->add_child("VideoFrameRate")->add_child_text (raw_convert<string> (_video_frame_rate.get()));
}
}
void
-Content::set_position (shared_ptr<const Film> film, DCPTime p)
+Content::set_position (shared_ptr<const Film> film, DCPTime p, bool force_emit)
{
/* video and audio content can modify its position */
video->modify_position (film, p);
}
- if (audio) {
+ /* 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);
}
{
boost::mutex::scoped_lock lm (_mutex);
- if (p == _position) {
+ if (p == _position && !force_emit) {
cc.abort ();
return;
}
video->modify_trim_start (t);
}
- if (audio) {
+ /* See note in ::set_position */
+ if (!video && audio) {
audio->modify_trim_start (t);
}
}
+void
+Content::set_trim_behaviour (TrimBehaviour t)
+{
+ ChangeSignaller<Content> cc (this, ContentProperty::TRIM_BEHAVIOUR);
+
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _trim_behaviour = t;
+ }
+}
+
+
shared_ptr<Content>
Content::clone () const
{
DCPTime
Content::length_after_trim (shared_ptr<const Film> film) const
{
- return max (DCPTime(), full_length(film) - DCPTime(trim_start() + trim_end(), film->active_frame_rate_change(position())));
+ DCPTime length = max(DCPTime(), full_length(film) - DCPTime(trim_start() + trim_end(), film->active_frame_rate_change(position())));
+ if (video) {
+ length = length.round(film->video_frame_rate());
+ }
+ return length;
}
/** @return string which changes when something about this content changes which affects