/*
- Copyright (C) 2013-2018 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
#include "playlist.h"
#include "video_content.h"
#include "text_content.h"
#include "i18n.h"
+
using std::list;
using std::cout;
using std::vector;
using namespace boost::placeholders;
#endif
+
Playlist::Playlist ()
- : _sequence (true)
- , _sequencing (false)
{
}
+
Playlist::~Playlist ()
{
boost::mutex::scoped_lock lm (_mutex);
disconnect ();
}
+
void
Playlist::content_change (weak_ptr<const Film> weak_film, ChangeType type, weak_ptr<Content> content, int property, bool frequent)
{
- shared_ptr<const Film> film = weak_film.lock ();
+ auto film = weak_film.lock ();
DCPOMATIC_ASSERT (film);
- if (type == CHANGE_TYPE_DONE) {
+ if (type == ChangeType::DONE) {
if (
property == ContentProperty::TRIM_START ||
property == ContentProperty::TRIM_END ||
ContentChange (type, content, property, frequent);
}
+
void
Playlist::maybe_sequence (shared_ptr<const Film> film)
{
_sequencing = true;
- ContentList cont = content ();
+ auto cont = content ();
/* Keep track of the content that we've set the position of so that we don't
do it twice.
continue;
}
- if (i->video->frame_type() == VIDEO_FRAME_TYPE_3D_RIGHT) {
+ if (i->video->frame_type() == VideoFrameType::THREE_D_RIGHT) {
i->set_position (film, next_right);
next_right = i->end(film);
} else {
_sequencing = false;
}
+
string
Playlist::video_identifier () const
{
return digester.get ();
}
+
/** @param film Film that this Playlist is for.
* @param node <Playlist> node.
* @param version Metadata version number.
boost::mutex::scoped_lock lm (_mutex);
for (auto i: node->node_children ("Content")) {
- shared_ptr<Content> content = content_factory (i, version, notes);
+ auto content = content_factory (i, version, notes);
/* See if this content should be nudged to start on a video frame */
- DCPTime const old_pos = content->position();
+ auto const old_pos = content->position();
content->set_position(film, old_pos);
if (old_pos != content->position()) {
string note = _("Your project contains video content that was not aligned to a frame boundary.");
}
/* ...or have a start trim which is an integer number of frames */
- ContentTime const old_trim = content->trim_start();
+ auto const old_trim = content->trim_start();
content->set_trim_start(old_trim);
if (old_trim != content->trim_start()) {
string note = _("Your project contains video content whose trim was not aligned to a frame boundary.");
reconnect (film);
}
+
/** @param node <Playlist> node.
* @param with_content_paths true to include <Path> nodes in <Content> nodes, false to omit them.
*/
}
}
+
void
Playlist::add (shared_ptr<const Film> film, shared_ptr<Content> c)
{
- Change (CHANGE_TYPE_PENDING);
+ Change (ChangeType::PENDING);
{
boost::mutex::scoped_lock lm (_mutex);
reconnect (film);
}
- Change (CHANGE_TYPE_DONE);
+ Change (ChangeType::DONE);
LengthChange ();
}
+
void
Playlist::remove (shared_ptr<Content> c)
{
- Change (CHANGE_TYPE_PENDING);
+ Change (ChangeType::PENDING);
bool cancelled = false;
{
boost::mutex::scoped_lock lm (_mutex);
- ContentList::iterator i = _content.begin ();
+ auto i = _content.begin ();
while (i != _content.end() && *i != c) {
++i;
}
}
if (cancelled) {
- Change (CHANGE_TYPE_CANCELLED);
+ Change (ChangeType::CANCELLED);
} else {
- Change (CHANGE_TYPE_DONE);
+ Change (ChangeType::DONE);
}
/* This won't change order, so it does not need a sort */
LengthChange ();
}
+
void
Playlist::remove (ContentList c)
{
- Change (CHANGE_TYPE_PENDING);
+ Change (ChangeType::PENDING);
{
boost::mutex::scoped_lock lm (_mutex);
for (auto i: c) {
- ContentList::iterator j = _content.begin ();
+ auto j = _content.begin ();
while (j != _content.end() && *j != i) {
++j;
}
}
}
- Change (CHANGE_TYPE_DONE);
+ Change (ChangeType::DONE);
/* This won't change order, so it does not need a sort */
LengthChange ();
}
+
class FrameRateCandidate
{
public:
int dcp;
};
+
/** @return the best frame rate from Config::_allowed_dcp_frame_rates for the content in this list */
int
Playlist::best_video_frame_rate () const
{
- list<int> const allowed_dcp_frame_rates = Config::instance()->allowed_dcp_frame_rates ();
+ auto const allowed_dcp_frame_rates = Config::instance()->allowed_dcp_frame_rates ();
/* Work out what rates we could manage, including those achieved by using skip / repeat */
list<FrameRateCandidate> candidates;
/* Pick the best one */
float error = std::numeric_limits<float>::max ();
optional<FrameRateCandidate> best;
- list<FrameRateCandidate>::iterator i = candidates.begin();
+ auto i = candidates.begin();
while (i != candidates.end()) {
float this_error = 0;
return best->dcp;
}
+
/** @return length of the playlist from time 0 to the last thing on the playlist */
DCPTime
Playlist::length (shared_ptr<const Film> film) const
return len;
}
+
/** @return position of the first thing on the playlist, if it's not empty */
optional<DCPTime>
Playlist::start () const
{
- ContentList cont = content ();
+ auto cont = content ();
if (cont.empty()) {
- return optional<DCPTime> ();
+ return {};
}
- DCPTime start = DCPTime::max ();
+ auto start = DCPTime::max ();
for (auto i: cont) {
start = min (start, i->position ());
}
return start;
}
+
/** Must be called with a lock held on _mutex */
void
Playlist::disconnect ()
_content_connections.clear ();
}
+
/** Must be called with a lock held on _mutex */
void
Playlist::reconnect (shared_ptr<const Film> film)
}
}
+
DCPTime
Playlist::video_end (shared_ptr<const Film> film) const
{
return end;
}
+
DCPTime
Playlist::text_end (shared_ptr<const Film> film) const
{
return end;
}
+
FrameRateChange
Playlist::active_frame_rate_change (DCPTime t, int dcp_video_frame_rate) const
{
- ContentList cont = content ();
+ auto cont = content ();
for (ContentList::const_reverse_iterator i = cont.rbegin(); i != cont.rend(); ++i) {
if (!(*i)->video) {
continue;
return FrameRateChange (dcp_video_frame_rate, dcp_video_frame_rate);
}
+
void
Playlist::set_sequence (bool s)
{
_sequence = s;
}
+
bool
ContentSorter::operator() (shared_ptr<Content> a, shared_ptr<Content> b)
{
return a->digest() < b->digest();
}
+
/** @return content in ascending order of position */
ContentList
Playlist::content () const
return _content;
}
+
void
Playlist::repeat (shared_ptr<const Film> film, ContentList c, int n)
{
- pair<DCPTime, DCPTime> range (DCPTime::max (), DCPTime ());
+ pair<DCPTime, DCPTime> range (DCPTime::max(), DCPTime());
for (auto i: c) {
range.first = min (range.first, i->position ());
range.second = max (range.second, i->position ());
range.second = max (range.second, i->end(film));
}
- Change (CHANGE_TYPE_PENDING);
+ Change (ChangeType::PENDING);
{
boost::mutex::scoped_lock lm (_mutex);
DCPTime pos = range.second;
for (int i = 0; i < n; ++i) {
for (auto j: c) {
- shared_ptr<Content> copy = j->clone ();
+ auto copy = j->clone ();
copy->set_position (film, pos + copy->position() - range.first);
_content.push_back (copy);
}
reconnect (film);
}
- Change (CHANGE_TYPE_DONE);
+ Change (ChangeType::DONE);
}
+
void
Playlist::move_earlier (shared_ptr<const Film> film, shared_ptr<Content> c)
{
- ContentList cont = content ();
- ContentList::iterator previous = cont.end();
- ContentList::iterator i = cont.begin();
+ auto cont = content ();
+ auto previous = cont.end();
+ auto i = cont.begin();
while (i != cont.end() && *i != c) {
previous = i;
++i;
return;
}
- shared_ptr<Content> previous_c = *previous;
+ auto previous_c = *previous;
- DCPTime const p = previous_c->position ();
+ auto const p = previous_c->position ();
previous_c->set_position (film, p + c->length_after_trim(film));
c->set_position (film, p);
}
+
void
Playlist::move_later (shared_ptr<const Film> film, shared_ptr<Content> c)
{
- ContentList cont = content ();
- ContentList::iterator i = cont.begin();
+ auto cont = content ();
+ auto i = cont.begin();
while (i != cont.end() && *i != c) {
++i;
}
return;
}
- shared_ptr<Content> next_c = *next;
+ auto next_c = *next;
next_c->set_position (film, c->position());
c->set_position (film, c->position() + next_c->length_after_trim(film));
}
+
int64_t
Playlist::required_disk_space (shared_ptr<const Film> film, int j2k_bandwidth, int audio_channels, int audio_frame_rate) const
{
int64_t audio = uint64_t (audio_channels * audio_frame_rate * 3) * length(film).seconds();
for (auto i: content()) {
- shared_ptr<DCPContent> d = dynamic_pointer_cast<DCPContent> (i);
+ auto d = dynamic_pointer_cast<DCPContent> (i);
if (d) {
if (d->reference_video()) {
video -= uint64_t (j2k_bandwidth / 8) * d->length_after_trim(film).seconds();
return video + audio + 65536;
}
+
string
Playlist::content_summary (shared_ptr<const Film> film, DCPTimePeriod period) const
{
int best_score = -1;
for (auto i: content()) {
int score = 0;
- optional<DCPTimePeriod> const o = DCPTimePeriod(i->position(), i->end(film)).overlap (period);
+ auto const o = DCPTimePeriod(i->position(), i->end(film)).overlap (period);
if (o) {
score += 100 * o.get().duration().get() / period.duration().get();
}
return best_summary;
}
+
pair<double, double>
Playlist::speed_up_range (int dcp_video_frame_rate) const
{