R_A &= \frac{C_V F_A}{F_V}
\end{align*}
+Once this is done, consider 1 second's worth of content samples ($C_A$
+samples). We have turned them into $R_A$ samples which should still
+last 1 second. These samples are then played back at $F_A$ samples
+per second, so they last $R_A / F_A$ seconds. Hence there is a
+scaling between some content time and some DCP time of $R_A / F_A$
+i.e. $C_V / F_V$.
+
\end{document}
AudioContent::technical_summary () const
{
return String::compose (
- "audio: channels %1, length %2, content rate %3, resampled rate %4",
+ "audio: channels %1, length %2 frames, content rate %3, resampled rate %4",
audio_channels(),
- audio_length().seconds(),
+ audio_length(),
audio_frame_rate(),
resampled_audio_frame_rate()
);
/** @return number of audio channels in the content */
virtual int audio_channels () const = 0;
/** @return the length of the audio in the content */
- virtual ContentTime audio_length () const = 0;
+ virtual Frame audio_length () const = 0;
/** @return the frame rate of the content */
virtual int audio_frame_rate () const = 0;
virtual AudioMapping audio_mapping () const = 0;
virtual ~AudioExaminer () {}
virtual int audio_channels () const = 0;
- virtual ContentTime audio_length () const = 0;
+ virtual Frame audio_length () const = 0;
virtual int audio_frame_rate () const = 0;
};
/** Default ISDCF metadata for newly-created Films */
ISDCFMetadata _default_isdcf_metadata;
boost::optional<std::string> _language;
+ /** Default length of still image content (seconds) */
int _default_still_length;
Ratio const * _default_container;
DCPContentType const * _default_dcp_content_type;
{
shared_ptr<const Film> film = _film.lock ();
DCPOMATIC_ASSERT (film);
- return DCPTime (video_length (), FrameRateChange (video_frame_rate (), film->video_frame_rate ()));
+ FrameRateChange const frc (video_frame_rate (), film->video_frame_rate ());
+ return DCPTime::from_frames (rint (video_length () * frc.factor ()), film->video_frame_rate ());
}
string
throw DCPError (_("Mismatched video sizes in DCP"));
}
- _video_length += ContentTime::from_frames ((*i)->main_picture()->duration(), _video_frame_rate.get ());
+ _video_length += (*i)->main_picture()->duration();
}
if ((*i)->main_sound ()) {
throw DCPError (_("Mismatched audio frame rates in DCP"));
}
- _audio_length += ContentTime::from_frames ((*i)->main_sound()->duration(), _video_frame_rate.get ());
+ _audio_length += (*i)->main_sound()->duration();
}
if ((*i)->main_subtitle ()) {
return _video_size.get_value_or (dcp::Size (1998, 1080));
}
- ContentTime video_length () const {
+ Frame video_length () const {
return _video_length;
}
return _audio_channels.get_value_or (0);
}
- ContentTime audio_length () const {
+ Frame audio_length () const {
return _audio_length;
}
private:
boost::optional<float> _video_frame_rate;
boost::optional<dcp::Size> _video_size;
- ContentTime _video_length;
+ Frame _video_length;
boost::optional<int> _audio_channels;
boost::optional<int> _audio_frame_rate;
- ContentTime _audio_length;
+ Frame _audio_length;
std::string _name;
bool _has_subtitles;
bool _encrypted;
signal_changed (FFmpegContentProperty::AUDIO_STREAM);
}
-ContentTime
+Frame
FFmpegContent::audio_length () const
{
if (!audio_stream ()) {
- return ContentTime ();
+ return 0;
}
- return video_length ();
+ /* We're talking about the content's audio length here, at the content's frame
+ rate. We assume it's the same as the video's length, and we can just convert
+ using the content's rates.
+ */
+ return (video_length () / video_frame_rate ()) * audio_frame_rate ();
}
int
{
shared_ptr<const Film> film = _film.lock ();
DCPOMATIC_ASSERT (film);
- return DCPTime (video_length_after_3d_combine(), FrameRateChange (video_frame_rate (), film->video_frame_rate ()));
+ FrameRateChange const frc (video_frame_rate (), film->video_frame_rate ());
+ return DCPTime::from_frames (rint (video_length_after_3d_combine() * frc.factor()), film->video_frame_rate());
}
AudioMapping
/* AudioContent */
int audio_channels () const;
- ContentTime audio_length () const;
+ Frame audio_length () const;
int audio_frame_rate () const;
AudioMapping audio_mapping () const;
void set_audio_mapping (AudioMapping);
/* See if the header has duration information in it */
_need_video_length = _format_context->duration == AV_NOPTS_VALUE;
if (!_need_video_length) {
- _video_length = ContentTime::from_seconds (double (_format_context->duration) / AV_TIME_BASE);
+ _video_length = (double (_format_context->duration) / AV_TIME_BASE) * video_frame_rate().get ();
} else if (job) {
job->sub (_("Finding length"));
job->set_progress_unknown ();
_first_video = frame_time (_format_context->streams[_video_stream]);
}
if (_need_video_length) {
- _video_length = frame_time (_format_context->streams[_video_stream]).get_value_or (ContentTime ());
+ _video_length = frame_time (
+ _format_context->streams[_video_stream]
+ ).get_value_or (ContentTime ()).frames (video_frame_rate().get ());
}
}
}
}
/** @return Length according to our content's header */
-ContentTime
+Frame
FFmpegExaminer::video_length () const
{
- ContentTime const length = ContentTime::from_seconds (double (_format_context->duration) / AV_TIME_BASE);
- return ContentTime (max (ContentTime (1), _video_length));
+ return max (Frame (1), _video_length);
}
optional<float>
boost::optional<float> video_frame_rate () const;
dcp::Size video_size () const;
- ContentTime video_length () const;
+ Frame video_length () const;
boost::optional<float> sample_aspect_ratio () const;
std::vector<boost::shared_ptr<FFmpegSubtitleStream> > subtitle_streams () const {
/** Video length, either obtained from the header or derived by running
* through the whole file.
*/
- ContentTime _video_length;
+ Frame _video_length;
bool _need_video_length;
boost::optional<ContentTime> _last_subtitle_start;
/*
- Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
+ 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
}
void
-ImageContent::set_video_length (ContentTime len)
+ImageContent::set_video_length (Frame len)
{
{
boost::mutex::scoped_lock lm (_mutex);
{
shared_ptr<const Film> film = _film.lock ();
DCPOMATIC_ASSERT (film);
- return DCPTime (video_length_after_3d_combine(), FrameRateChange (video_frame_rate(), film->video_frame_rate()));
+ FrameRateChange const frc (video_frame_rate(), film->video_frame_rate());
+ return DCPTime::from_frames (rint (video_length_after_3d_combine() * frc.factor ()), film->video_frame_rate ());
}
string
{
SafeStringStream s;
s << VideoContent::identifier ();
- s << "_" << video_length().get();
+ s << "_" << video_length();
return s.str ();
}
/*
- Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
+ 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
/* VideoContent */
void set_default_colour_conversion ();
- void set_video_length (ContentTime);
+ void set_video_length (Frame);
bool still () const;
void set_video_frame_rate (float);
};
bool
ImageDecoder::pass (PassReason)
{
- if (_video_position >= _image_content->video_length().frames (_image_content->video_frame_rate ())) {
+ if (_video_position >= _image_content->video_length()) {
return true;
}
}
if (content->still ()) {
- _video_length = ContentTime::from_seconds (Config::instance()->default_still_length());
+ _video_length = Config::instance()->default_still_length() * video_frame_rate().get_value_or (24);
} else {
- _video_length = ContentTime::from_frames (
- _image_content->number_of_paths (), video_frame_rate().get_value_or (24)
- );
+ _video_length = _image_content->number_of_paths ();
}
}
boost::optional<float> video_frame_rate () const;
dcp::Size video_size () const;
- ContentTime video_length () const {
+ Frame video_length () const {
return _video_length;
}
boost::weak_ptr<const Film> _film;
boost::shared_ptr<const ImageContent> _image_content;
boost::optional<dcp::Size> _video_size;
- ContentTime _video_length;
+ Frame _video_length;
};
, _audio_mapping (node->node_child ("AudioMapping"), version)
{
_audio_channels = node->number_child<int> ("AudioChannels");
- _audio_length = ContentTime (node->number_child<ContentTime::Type> ("AudioLength"));
+ _audio_length = node->number_child<Frame> ("AudioLength");
_audio_frame_rate = node->number_child<int> ("AudioFrameRate");
}
{
AudioContent::as_xml (node);
node->add_child("AudioChannels")->add_child_text (raw_convert<string> (audio_channels ()));
- node->add_child("AudioLength")->add_child_text (raw_convert<string> (audio_length().get ()));
+ node->add_child("AudioLength")->add_child_text (raw_convert<string> (audio_length ()));
node->add_child("AudioFrameRate")->add_child_text (raw_convert<string> (audio_frame_rate ()));
_audio_mapping.as_xml (node->add_child("AudioMapping"));
}
/*
- Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014-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
return _audio_channels;
}
- ContentTime audio_length () const {
+ Frame audio_length () const {
boost::mutex::scoped_lock lm (_mutex);
return _audio_length;
}
protected:
int _audio_channels;
- ContentTime _audio_length;
+ Frame _audio_length;
int _audio_frame_rate;
AudioMapping _audio_mapping;
};
{
shared_ptr<const Film> film = _film.lock ();
DCPOMATIC_ASSERT (film);
- return DCPTime (audio_length(), film->active_frame_rate_change (position ()));
+ FrameRateChange const frc = film->active_frame_rate_change (position ());
+ return DCPTime::from_frames (audio_length() / frc.speed_up, film->audio_frame_rate ());
}
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-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
return _info.channels;
}
-ContentTime
+Frame
SndfileDecoder::audio_length () const
{
- return ContentTime::from_frames (_info.frames, audio_frame_rate ());
+ return _info.frames;
}
int
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-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
~SndfileDecoder ();
int audio_channels () const;
- ContentTime audio_length () const;
+ Frame audio_length () const;
int audio_frame_rate () const;
private:
set_default_colour_conversion ();
}
-VideoContent::VideoContent (shared_ptr<const Film> f, DCPTime s, ContentTime len)
+VideoContent::VideoContent (shared_ptr<const Film> f, DCPTime s, Frame len)
: Content (f, s)
, _video_length (len)
, _video_frame_rate (0)
_video_size.width = node->number_child<int> ("VideoWidth");
_video_size.height = node->number_child<int> ("VideoHeight");
_video_frame_rate = node->number_child<float> ("VideoFrameRate");
-
- if (version < 32) {
- /* DCP-o-matic 1.0 branch */
- _video_length = ContentTime::from_frames (node->number_child<int64_t> ("VideoLength"), _video_frame_rate);
- } else {
- _video_length = ContentTime (node->number_child<ContentTime::Type> ("VideoLength"));
- }
-
+ _video_length = node->number_child<Frame> ("VideoLength");
_video_frame_type = static_cast<VideoFrameType> (node->number_child<int> ("VideoFrameType"));
_sample_aspect_ratio = node->optional_number_child<float> ("SampleAspectRatio");
_crop.left = node->number_child<int> ("LeftCrop");
_colour_conversion = ColourConversion (node->node_child ("ColourConversion"), version);
}
if (version >= 32) {
- _fade_in = ContentTime (node->number_child<int64_t> ("FadeIn"));
- _fade_out = ContentTime (node->number_child<int64_t> ("FadeOut"));
+ _fade_in = node->number_child<Frame> ("FadeIn");
+ _fade_out = node->number_child<Frame> ("FadeOut");
}
}
VideoContent::as_xml (xmlpp::Node* node) const
{
boost::mutex::scoped_lock lm (_mutex);
- node->add_child("VideoLength")->add_child_text (raw_convert<string> (_video_length.get ()));
+ node->add_child("VideoLength")->add_child_text (raw_convert<string> (_video_length));
node->add_child("VideoWidth")->add_child_text (raw_convert<string> (_video_size.width));
node->add_child("VideoHeight")->add_child_text (raw_convert<string> (_video_size.height));
node->add_child("VideoFrameRate")->add_child_text (raw_convert<string> (_video_frame_rate));
if (_colour_conversion) {
_colour_conversion.get().as_xml (node->add_child("ColourConversion"));
}
- node->add_child("FadeIn")->add_child_text (raw_convert<string> (_fade_in.get ()));
- node->add_child("FadeOut")->add_child_text (raw_convert<string> (_fade_out.get ()));
+ node->add_child("FadeIn")->add_child_text (raw_convert<string> (_fade_in));
+ node->add_child("FadeOut")->add_child_text (raw_convert<string> (_fade_out));
}
void
/* These examiner calls could call other content methods which take a lock on the mutex */
dcp::Size const vs = d->video_size ();
optional<float> const vfr = d->video_frame_rate ();
- ContentTime vl = d->video_length ();
+ Frame vl = d->video_length ();
optional<float> const ar = d->sample_aspect_ratio ();
{
shared_ptr<const Film> film = _film.lock ();
DCPOMATIC_ASSERT (film);
- LOG_GENERAL ("Video length obtained from header as %1 frames", _video_length.frames (_video_frame_rate));
+ LOG_GENERAL ("Video length obtained from header as %1 frames", _video_length);
set_default_colour_conversion ();
VideoContent::technical_summary () const
{
string s = String::compose (
- N_("video: length %1, size %2x%3, rate %4"),
- video_length_after_3d_combine().seconds(),
+ N_("video: length %1 frames, size %2x%3, rate %4"),
+ video_length_after_3d_combine(),
video_size().width,
video_size().height,
video_frame_rate()
}
void
-VideoContent::set_fade_in (ContentTime t)
+VideoContent::set_fade_in (Frame t)
{
{
boost::mutex::scoped_lock lm (_mutex);
}
void
-VideoContent::set_fade_out (ContentTime t)
+VideoContent::set_fade_out (Frame t)
{
{
boost::mutex::scoped_lock lm (_mutex);
{
DCPOMATIC_ASSERT (f >= 0);
- if (f < fade_in().frames (video_frame_rate ())) {
- return float (f) / _fade_in.frames (video_frame_rate ());
+ if (f < fade_in()) {
+ return float (f) / fade_in();
}
- Frame fade_out_start = ContentTime (video_length() - fade_out()).frames (video_frame_rate ());
+ Frame fade_out_start = video_length() - fade_out();
if (f >= fade_out_start) {
- return 1 - float (f - fade_out_start) / fade_out().frames (video_frame_rate ());
+ return 1 - float (f - fade_out_start) / fade_out();
}
return optional<float> ();
{
public:
VideoContent (boost::shared_ptr<const Film>);
- VideoContent (boost::shared_ptr<const Film>, DCPTime, ContentTime);
+ VideoContent (boost::shared_ptr<const Film>, DCPTime, Frame);
VideoContent (boost::shared_ptr<const Film>, boost::filesystem::path);
VideoContent (boost::shared_ptr<const Film>, cxml::ConstNodePtr, int);
VideoContent (boost::shared_ptr<const Film>, std::vector<boost::shared_ptr<Content> >);
virtual void set_default_colour_conversion ();
- ContentTime video_length () const {
+ Frame video_length () const {
boost::mutex::scoped_lock lm (_mutex);
return _video_length;
}
- ContentTime video_length_after_3d_combine () const {
+ Frame video_length_after_3d_combine () const {
boost::mutex::scoped_lock lm (_mutex);
if (_video_frame_type == VIDEO_FRAME_TYPE_3D_ALTERNATE) {
- return ContentTime (_video_length.get() / 2);
+ return _video_length / 2;
}
return _video_length;
void unset_colour_conversion (bool signal = true);
void set_colour_conversion (ColourConversion);
- void set_fade_in (ContentTime);
- void set_fade_out (ContentTime);
+ void set_fade_in (Frame);
+ void set_fade_out (Frame);
VideoFrameType video_frame_type () const {
boost::mutex::scoped_lock lm (_mutex);
return _sample_aspect_ratio;
}
- ContentTime fade_in () const {
+ Frame fade_in () const {
boost::mutex::scoped_lock lm (_mutex);
return _fade_in;
}
- ContentTime fade_out () const {
+ Frame fade_out () const {
boost::mutex::scoped_lock lm (_mutex);
return _fade_out;
}
protected:
void take_from_video_examiner (boost::shared_ptr<VideoExaminer>);
- ContentTime _video_length;
+ Frame _video_length;
float _video_frame_rate;
boost::optional<ColourConversion> _colour_conversion;
if there is one.
*/
boost::optional<float> _sample_aspect_ratio;
- ContentTime _fade_in;
- ContentTime _fade_out;
+ Frame _fade_in;
+ Frame _fade_out;
};
#endif
/*
- Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
+ 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
virtual ~VideoExaminer () {}
virtual boost::optional<float> video_frame_rate () const = 0;
virtual dcp::Size video_size () const = 0;
- virtual ContentTime video_length () const = 0;
+ virtual Frame video_length () const = 0;
virtual boost::optional<float> sample_aspect_ratio () const {
return boost::optional<float> ();
}
for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
shared_ptr<ImageContent> ic = dynamic_pointer_cast<ImageContent> (*i);
if (ic) {
- ic->set_video_length (ContentTime::from_seconds (still_length));
+ ic->set_video_length (still_length * 24);
}
}
if (video) {
add_property (
_("Video length"),
- std_to_wx (raw_convert<string> (video->video_length ().frames (video->video_frame_rate ()))) + " " + _("video frames")
+ std_to_wx (raw_convert<string> (video->video_length ())) + " " + _("video frames")
);
add_property (
_("Video size"),
);
add_property (
_("Audio length"),
- std_to_wx (raw_convert<string> (audio->audio_length().frames (audio->audio_frame_rate ()))) + " " + _("audio frames")
+ std_to_wx (raw_convert<string> (audio->audio_length())) + " " + _("audio frames")
);
}
for (ContentList::iterator i = c.begin(); i != c.end(); ++i) {
shared_ptr<ImageContent> ic = dynamic_pointer_cast<ImageContent> (*i);
if (ic && ic->still ()) {
- /* XXX: No effective FRC here... is this right? */
- ic->set_video_length (ContentTime (_full_length->get (_parent->film()->video_frame_rate()), FrameRateChange (1, 1)));
+ int const vfr = _parent->film()->video_frame_rate ();
+ ic->set_video_length (_full_length->get (vfr).frames (vfr));
}
}
}
}
}
} else if (property == VideoContentProperty::VIDEO_FADE_IN) {
- set<ContentTime> check;
+ set<Frame> check;
for (VideoContentList::const_iterator i = vc.begin (); i != vc.end(); ++i) {
check.insert ((*i)->fade_in ());
}
if (check.size() == 1) {
- _fade_in->set (vc.front()->fade_in (), vc.front()->video_frame_rate ());
+ _fade_in->set (ContentTime::from_frames (vc.front()->fade_in (), vc.front()->video_frame_rate ()), vc.front()->video_frame_rate ());
} else {
_fade_in->clear ();
}
} else if (property == VideoContentProperty::VIDEO_FADE_OUT) {
- set<ContentTime> check;
+ set<Frame> check;
for (VideoContentList::const_iterator i = vc.begin (); i != vc.end(); ++i) {
check.insert ((*i)->fade_out ());
}
if (check.size() == 1) {
- _fade_out->set (vc.front()->fade_out (), vc.front()->video_frame_rate ());
+ _fade_out->set (ContentTime::from_frames (vc.front()->fade_out (), vc.front()->video_frame_rate ()), vc.front()->video_frame_rate ());
} else {
_fade_out->clear ();
}
{
VideoContentList vc = _parent->selected_video ();
for (VideoContentList::const_iterator i = vc.begin(); i != vc.end(); ++i) {
- (*i)->set_fade_in (_fade_in->get (_parent->film()->video_frame_rate ()));
+ int const vfr = _parent->film()->video_frame_rate ();
+ (*i)->set_fade_in (_fade_in->get (vfr).frames (vfr));
}
}
{
VideoContentList vc = _parent->selected_video ();
for (VideoContentList::const_iterator i = vc.begin(); i != vc.end(); ++i) {
- (*i)->set_fade_out (_fade_out->get (_parent->film()->video_frame_rate ()));
+ int const vfr = _parent->film()->video_frame_rate ();
+ (*i)->set_fade_out (_fade_out->get (vfr).frames (vfr));
}
}
/*
- Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-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
{
Frame const N = min (
Frame (2000),
- _audio_content->audio_length().frames (_audio_content->resampled_audio_frame_rate ()) - _position
+ _audio_content->audio_length() - _position
);
shared_ptr<AudioBuffers> buffers (new AudioBuffers (_audio_content->audio_channels(), N));
}
DCPTime full_length () const {
- return DCPTime (audio_length().get ());
+ return DCPTime::from_seconds (float (audio_length()) / audio_frame_rate ());
}
int audio_channels () const {
return 2;
}
- ContentTime audio_length () const {
- return ContentTime::from_seconds (61.2942);
+ Frame audio_length () const {
+ return rint (61.2942 * audio_frame_rate ());
}
int audio_frame_rate () const {
wait_for_jobs ();
contentA->set_scale (VideoContentScale (Ratio::from_id ("185")));
- contentA->set_video_length (ContentTime::from_frames (3, 24));
+ contentA->set_video_length (3);
contentA->set_position (DCPTime::from_frames (2, film->video_frame_rate ()));
contentB->set_scale (VideoContentScale (Ratio::from_id ("185")));
- contentB->set_video_length (ContentTime::from_frames (1, 24));
+ contentB->set_video_length (1);
contentB->set_position (DCPTime::from_frames (7, film->video_frame_rate ()));
film->make_dcp ();
BOOST_CHECK_CLOSE (decoder.video_content()->video_frame_rate(), fps, 0.01);
- Frame const N = decoder.video_content()->video_length().frames (decoder.video_content()->video_frame_rate ());
+ Frame const N = decoder.video_content()->video_length();
#ifdef DCPOMATIC_DEBUG
decoder.test_gaps = 0;
#endif
wait_for_jobs ();
- imc->set_video_length (ContentTime::from_frames (1, 24));
+ imc->set_video_length (1);
scaling_test_for (film, imc, "133", "185");
scaling_test_for (film, imc, "185", "185");
stream_test.cc
test.cc
threed_test.cc
+ time_calculation_test.cc
update_checker_test.cc
upmixer_a_test.cc
util_test.cc