#include "compose.hpp"
#include "film.h"
#include "player.h"
+#include "playlist.h"
#include <boost/foreach.hpp>
#include "i18n.h"
int const AnalyseAudioJob::_num_points = 1024;
-AnalyseAudioJob::AnalyseAudioJob (shared_ptr<const Film> film)
+AnalyseAudioJob::AnalyseAudioJob (shared_ptr<const Film> film, shared_ptr<const Playlist> playlist)
: Job (film)
+ , _playlist (playlist)
, _done (0)
, _samples_per_point (1)
, _overall_peak (0)
void
AnalyseAudioJob::run ()
{
- shared_ptr<Player> player (new Player (_film));
+ shared_ptr<Player> player (new Player (_film, _playlist));
player->set_ignore_video ();
- int64_t const len = _film->length().frames (_film->audio_frame_rate());
+ int64_t const len = _playlist->length().frames (_film->audio_frame_rate());
_samples_per_point = max (int64_t (1), len / _num_points);
_current.resize (_film->audio_channels ());
_analysis.reset (new AudioAnalysis (_film->audio_channels ()));
bool has_any_audio = false;
- BOOST_FOREACH (shared_ptr<Content> c, _film->content ()) {
+ BOOST_FOREACH (shared_ptr<Content> c, _playlist->content ()) {
if (dynamic_pointer_cast<AudioContent> (c)) {
has_any_audio = true;
}
++_done;
}
}
-
#include "types.h"
class AudioBuffers;
+class Playlist;
/** @class AnalyseAudioJob
* @brief A job to analyse the audio of a film and make a note of its
class AnalyseAudioJob : public Job
{
public:
- AnalyseAudioJob (boost::shared_ptr<const Film>);
+ AnalyseAudioJob (boost::shared_ptr<const Film>, boost::shared_ptr<const Playlist>);
std::string name () const;
std::string json_name () const;
private:
void analyse (boost::shared_ptr<const AudioBuffers>);
+ boost::shared_ptr<const Playlist> _playlist;
+
int64_t _done;
int64_t _samples_per_point;
std::vector<AudioPoint> _current;
static const int _num_points;
};
-
void repeat_content (ContentList, int);
+ boost::shared_ptr<const Playlist> playlist () const {
+ return _playlist;
+ }
+
/** Identifiers for the parts of our state;
used for signalling changes.
*/
#include "dcp_subtitle_content.h"
#include "dcp_subtitle_decoder.h"
#include "audio_processor.h"
+#include "playlist.h"
#include <boost/foreach.hpp>
#include <stdint.h>
#include <algorithm>
using boost::dynamic_pointer_cast;
using boost::optional;
-Player::Player (shared_ptr<const Film> film)
+Player::Player (shared_ptr<const Film> film, shared_ptr<const Playlist> playlist)
: _film (film)
+ , _playlist (playlist)
, _have_valid_pieces (false)
, _ignore_video (false)
, _always_burn_subtitles (false)
{
- _film_content_changed_connection = _film->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2, _3));
_film_changed_connection = _film->Changed.connect (bind (&Player::film_changed, this, _1));
+ _playlist_changed_connection = _playlist->ContentChanged.connect (bind (&Player::playlist_changed, this));
+ _playlist_content_changed_connection = _playlist->ContentChanged.connect (bind (&Player::playlist_content_changed, this, _1, _2, _3));
set_video_container_size (_film->frame_size ());
film_changed (Film::AUDIO_PROCESSOR);
list<shared_ptr<Piece> > old_pieces = _pieces;
_pieces.clear ();
- ContentList content = _film->content ();
+ BOOST_FOREACH (shared_ptr<Content> i, _playlist->content ()) {
- for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
-
- if (!(*i)->paths_valid ()) {
+ if (!i->paths_valid ()) {
continue;
}
/* Work out a FrameRateChange for the best overlap video for this content, in case we need it below */
DCPTime best_overlap_t;
shared_ptr<VideoContent> best_overlap;
- for (ContentList::iterator j = content.begin(); j != content.end(); ++j) {
- shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (*j);
+ BOOST_FOREACH (shared_ptr<Content> j, _playlist->content ()) {
+ shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (j);
if (!vc) {
continue;
}
- DCPTime const overlap = max (vc->position(), (*i)->position()) - min (vc->end(), (*i)->end());
+ DCPTime const overlap = max (vc->position(), i->position()) - min (vc->end(), i->end());
if (overlap > best_overlap_t) {
best_overlap = vc;
best_overlap_t = overlap;
}
/* FFmpeg */
- shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
+ shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (i);
if (fc) {
decoder.reset (new FFmpegDecoder (fc, _film->log()));
frc = FrameRateChange (fc->video_frame_rate(), _film->video_frame_rate());
}
- shared_ptr<const DCPContent> dc = dynamic_pointer_cast<const DCPContent> (*i);
+ shared_ptr<const DCPContent> dc = dynamic_pointer_cast<const DCPContent> (i);
if (dc) {
decoder.reset (new DCPDecoder (dc));
frc = FrameRateChange (dc->video_frame_rate(), _film->video_frame_rate());
}
/* ImageContent */
- shared_ptr<const ImageContent> ic = dynamic_pointer_cast<const ImageContent> (*i);
+ shared_ptr<const ImageContent> ic = dynamic_pointer_cast<const ImageContent> (i);
if (ic) {
/* See if we can re-use an old ImageDecoder */
for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
}
/* SndfileContent */
- shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
+ shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (i);
if (sc) {
decoder.reset (new SndfileDecoder (sc));
frc = best_overlap_frc;
}
/* SubRipContent */
- shared_ptr<const SubRipContent> rc = dynamic_pointer_cast<const SubRipContent> (*i);
+ shared_ptr<const SubRipContent> rc = dynamic_pointer_cast<const SubRipContent> (i);
if (rc) {
decoder.reset (new SubRipDecoder (rc));
frc = best_overlap_frc;
}
/* DCPSubtitleContent */
- shared_ptr<const DCPSubtitleContent> dsc = dynamic_pointer_cast<const DCPSubtitleContent> (*i);
+ shared_ptr<const DCPSubtitleContent> dsc = dynamic_pointer_cast<const DCPSubtitleContent> (i);
if (dsc) {
decoder.reset (new DCPSubtitleDecoder (dsc));
frc = best_overlap_frc;
vd->set_ignore_video ();
}
- _pieces.push_back (shared_ptr<Piece> (new Piece (*i, decoder, frc.get ())));
+ _pieces.push_back (shared_ptr<Piece> (new Piece (i, decoder, frc.get ())));
}
_have_valid_pieces = true;
}
void
-Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
+Player::playlist_content_changed (weak_ptr<Content> w, int property, bool frequent)
{
shared_ptr<Content> c = w.lock ();
if (!c) {
_black_image->make_black ();
}
+void
+Player::playlist_changed ()
+{
+ _have_valid_pieces = false;
+ Changed (false);
+}
+
void
Player::film_changed (Film::Property p)
{
last time we were run.
*/
- if (p == Film::CONTENT) {
- _have_valid_pieces = false;
- Changed (false);
- } else if (p == Film::CONTAINER || p == Film::VIDEO_FRAME_RATE) {
+ if (p == Film::CONTAINER || p == Film::VIDEO_FRAME_RATE) {
Changed (false);
} else if (p == Film::AUDIO_PROCESSOR) {
if (_film->audio_processor ()) {
};
/** @class Player
- * @brief A class which can `play' a Film.
+ * @brief A class which can `play' a Playlist.
*/
class Player : public boost::enable_shared_from_this<Player>, public boost::noncopyable
{
public:
- Player (boost::shared_ptr<const Film>);
+ Player (boost::shared_ptr<const Film>, boost::shared_ptr<const Playlist> playlist);
std::list<boost::shared_ptr<PlayerVideo> > get_video (DCPTime time, bool accurate);
boost::shared_ptr<AudioBuffers> get_audio (DCPTime time, DCPTime length, bool accurate);
friend struct player_overlaps_test;
void setup_pieces ();
- void content_changed (boost::weak_ptr<Content>, int, bool);
void flush ();
void film_changed (Film::Property);
+ void playlist_changed ();
+ void playlist_content_changed (boost::weak_ptr<Content>, int, bool);
std::list<PositionImage> transform_image_subtitles (std::list<ImageSubtitle>) const;
void update_subtitle_from_text ();
Frame dcp_to_content_video (boost::shared_ptr<const Piece> piece, DCPTime t) const;
}
boost::shared_ptr<const Film> _film;
+ boost::shared_ptr<const Playlist> _playlist;
/** Our pieces are ready to go; if this is false the pieces must be (re-)created before they are used */
bool _have_valid_pieces;
PlayerStatistics _statistics;
- boost::signals2::scoped_connection _film_content_changed_connection;
boost::signals2::scoped_connection _film_changed_connection;
+ boost::signals2::scoped_connection _playlist_changed_connection;
+ boost::signals2::scoped_connection _playlist_content_changed_connection;
};
#endif
*/
Transcoder::Transcoder (shared_ptr<const Film> film, shared_ptr<Job> j)
: _film (film)
- , _player (new Player (film))
+ , _player (new Player (film, film->playlist ()))
, _writer (new Writer (film, j))
, _encoder (new Encoder (film, j, _writer))
, _finishing (false)
{
return _encoder->video_frames_out ();
}
-
film.reset (new Film (film_dir));
film->read_metadata ();
- shared_ptr<Player> player (new Player (film));
+ shared_ptr<Player> player (new Player (film, film->playlist ()));
DCPTime const frame = DCPTime::from_frames (1, film->video_frame_rate ());
for (DCPTime t; t < film->length(); t += frame) {
if (!boost::filesystem::exists (path)) {
_plot->set_analysis (shared_ptr<AudioAnalysis> ());
_analysis.reset ();
- shared_ptr<AnalyseAudioJob> job (new AnalyseAudioJob (film));
+ shared_ptr<AnalyseAudioJob> job (new AnalyseAudioJob (film, film->playlist ()));
_analysis_finished_connection = job->Finished.connect (bind (&AudioDialog::analysis_finished, this));
JobManager::instance()->add (job);
return;
_analysis.reset (new AudioAnalysis (path));
} catch (xmlpp::exception& e) {
/* Probably an old-style analysis file: recreate it */
- shared_ptr<AnalyseAudioJob> job (new AnalyseAudioJob (film));
+ shared_ptr<AnalyseAudioJob> job (new AnalyseAudioJob (film, film->playlist ()));
_analysis_finished_connection = job->Finished.connect (bind (&AudioDialog::analysis_finished, this));
JobManager::instance()->add (job);
return;
try_to_load_analysis ();
return r;
}
-
-
}
try {
- _player.reset (new Player (_film));
+ _player.reset (new Player (_film, _film->playlist ()));
} catch (bad_alloc) {
error_dialog (this, _("There is not enough free memory to do that."));
_film.reset ();
film->examine_and_add_content (c);
wait_for_jobs ();
- shared_ptr<AnalyseAudioJob> job (new AnalyseAudioJob (film));
+ shared_ptr<AnalyseAudioJob> job (new AnalyseAudioJob (film, film->playlist ()));
job->Finished.connect (boost::bind (&finished));
JobManager::instance()->add (job);
wait_for_jobs ();
film->examine_and_add_content (c);
wait_for_jobs ();
- shared_ptr<AnalyseAudioJob> job (new AnalyseAudioJob (film));
+ shared_ptr<AnalyseAudioJob> job (new AnalyseAudioJob (film, film->playlist ()));
job->Finished.connect (boost::bind (&finished));
JobManager::instance()->add (job);
wait_for_jobs ();
film->examine_and_add_content (c);
wait_for_jobs ();
- shared_ptr<AnalyseAudioJob> job (new AnalyseAudioJob (film));
+ shared_ptr<AnalyseAudioJob> job (new AnalyseAudioJob (film, film->playlist ()));
job->Finished.connect (boost::bind (&finished));
JobManager::instance()->add (job);
wait_for_jobs ();
B->set_position (DCPTime::from_seconds (10));
C->set_position (DCPTime::from_seconds (20));
- shared_ptr<Player> player (new Player (film));
+ shared_ptr<Player> player (new Player (film, film->playlist ()));
list<shared_ptr<Piece> > o = player->overlaps<FFmpegContent> (DCPTime::from_seconds (0), DCPTime::from_seconds (5));
BOOST_CHECK_EQUAL (o.size(), 1U);
film->examine_and_add_content (c);
wait_for_jobs ();
- shared_ptr<Player> player (new Player (film));
+ shared_ptr<Player> player (new Player (film, film->playlist ()));
shared_ptr<AudioBuffers> test = player->get_audio (DCPTime (0), DCPTime::from_seconds (1), true);
BOOST_CHECK_EQUAL (test->frames(), 48000);
BOOST_CHECK_EQUAL (test->channels(), film->audio_channels ());
}
}
}
-
SNDFILE* Ls = sf_open ("build/test/upmixer_a_test/Ls.wav", SFM_WRITE, &info);
SNDFILE* Rs = sf_open ("build/test/upmixer_a_test/Rs.wav", SFM_WRITE, &info);
- shared_ptr<Player> player (new Player (film));
+ shared_ptr<Player> player (new Player (film, film->playlist ()));
for (DCPTime t; t < film->length(); t += DCPTime::from_seconds (1)) {
shared_ptr<AudioBuffers> b = player->get_audio (t, DCPTime::from_seconds (1), true);
sf_write_float (L, b->data(0), b->frames());