summaryrefslogtreecommitdiff
path: root/src/lib/player.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/player.cc')
-rw-r--r--src/lib/player.cc229
1 files changed, 122 insertions, 107 deletions
diff --git a/src/lib/player.cc b/src/lib/player.cc
index dd250d2e1..eb704f733 100644
--- a/src/lib/player.cc
+++ b/src/lib/player.cc
@@ -39,6 +39,17 @@ using boost::shared_ptr;
using boost::weak_ptr;
using boost::dynamic_pointer_cast;
+struct Piece
+{
+ Piece (shared_ptr<Content> c, shared_ptr<Decoder> d)
+ : content (c)
+ , decoder (d)
+ {}
+
+ shared_ptr<Content> content;
+ shared_ptr<Decoder> decoder;
+};
+
Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
: _film (f)
, _playlist (p)
@@ -50,7 +61,7 @@ Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
, _audio_buffers (MAX_AUDIO_CHANNELS, 0)
, _last_video (0)
, _last_was_black (false)
- , _last_audio (0)
+ , _next_audio (0)
{
_playlist->Changed.connect (bind (&Player::playlist_changed, this));
_playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2));
@@ -77,72 +88,63 @@ Player::disable_subtitles ()
bool
Player::pass ()
{
- if (!_have_valid_decoders) {
- setup_decoders ();
- _have_valid_decoders = true;
+ if (!_have_valid_pieces) {
+ setup_pieces ();
+ _have_valid_pieces = true;
}
/* Here we are just finding the active decoder with the earliest last emission time, then
- calling pass on it. If there is no decoder, we skip our position on until there is.
- Hence this method will cause video and audio to be emitted, and it is up to the
- process_{video,audio} methods to tidy it up.
+ calling pass on it.
*/
- Time earliest_pos = TIME_MAX;
- shared_ptr<DecoderRecord> earliest;
- Time next_wait = TIME_MAX;
-
- for (list<shared_ptr<DecoderRecord> >::iterator i = _decoders.begin(); i != _decoders.end(); ++i) {
- Time const ts = (*i)->content->time();
- Time const te = (*i)->content->time() + (*i)->content->length (_film);
- if (ts <= _position && te > _position) {
- Time const pos = ts + (*i)->last;
- if (pos < earliest_pos) {
- earliest_pos = pos;
- earliest = *i;
- }
- }
+ Time earliest_t = TIME_MAX;
+ shared_ptr<Piece> earliest;
- if (ts > _position) {
- next_wait = min (next_wait, ts - _position);
- }
- }
+ for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
+ if ((*i)->content->end(_film) < _position) {
+ continue;
+ }
+
+ Time const t = (*i)->content->start() + (*i)->decoder->next();
+ if (t < earliest_t) {
+ earliest_t = t;
+ earliest = *i;
+ }
+ }
- if (earliest) {
- cout << "pass on decoder...\n";
- earliest->decoder->pass ();
- _position = earliest->last;
- } else if (next_wait < TIME_MAX) {
- cout << "nw " << next_wait << " for " << _position << "\n";
- _position += next_wait;
- } else {
- return true;
- }
+ if (!earliest) {
+ return true;
+ }
+
+ earliest->decoder->pass ();
+
+ /* Move position to earliest active next emission */
+
+ for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
+ if ((*i)->content->end(_film) < _position) {
+ continue;
+ }
+
+ Time const t = (*i)->content->start() + (*i)->decoder->next();
+
+ if (t < _position) {
+ _position = t;
+ }
+ }
return false;
}
void
-Player::process_video (shared_ptr<DecoderRecord> dr, shared_ptr<const Image> image, bool same, shared_ptr<Subtitle> sub, Time time)
+Player::process_video (shared_ptr<Piece> piece, shared_ptr<const Image> image, bool same, shared_ptr<Subtitle> sub, Time time)
{
- shared_ptr<VideoDecoder> vd = dynamic_pointer_cast<VideoDecoder> (dr->decoder);
-
- Time const global_time = dr->content->time() + time;
- cout << "need to fill in " << global_time << " vs " << _last_video << "\n";
- while ((global_time - _last_video) > 1) {
- /* Fill in with black */
- cout << "(b)\n";
- emit_black_frame ();
- }
-
- Video (image, same, sub, global_time);
- dr->last = time;
- _last_video = global_time;
- _last_was_black = false;
+ time += piece->start ();
+
+ Video (image, same, sub, time);
}
void
-Player::process_audio (shared_ptr<DecoderRecord> dr, shared_ptr<const AudioBuffers> audio, Time time)
+Player::process_audio (shared_ptr<Piece> piece, shared_ptr<const AudioBuffers> audio, Time time)
{
/* XXX: mapping */
@@ -150,13 +152,15 @@ Player::process_audio (shared_ptr<DecoderRecord> dr, shared_ptr<const AudioBuffe
be added to any more, so it can be emitted.
*/
- if (time > _last_audio) {
+ time += piece->start ();
+
+ if (time > _next_audio) {
/* We can emit some audio from our buffers */
- OutputAudioFrame const N = min (_film->time_to_audio_frames (time - _last_audio), static_cast<OutputAudioFrame> (_audio_buffers.frames()));
+ OutputAudioFrame const N = min (_film->time_to_audio_frames (time - _next_audio), static_cast<OutputAudioFrame> (_audio_buffers.frames()));
shared_ptr<AudioBuffers> emit (new AudioBuffers (_audio_buffers.channels(), N));
emit->copy_from (&_audio_buffers, N, 0, 0);
- Audio (emit, _last_audio);
- _last_audio += _film->audio_frames_to_time (N);
+ Audio (emit, _next_audio);
+ _next_audio += _film->audio_frames_to_time (N);
/* And remove it from our buffers */
if (_audio_buffers.frames() > N) {
@@ -166,55 +170,23 @@ Player::process_audio (shared_ptr<DecoderRecord> dr, shared_ptr<const AudioBuffe
}
/* Now accumulate the new audio into our buffers */
-
- if (_audio_buffers.frames() == 0) {
- /* We have no remaining data. Emit silence up to the start of this new data */
- if ((time - _last_audio) > 0) {
- emit_silence (time - _last_audio);
- }
- }
-
- _audio_buffers.ensure_size (time - _last_audio + audio->frames());
- _audio_buffers.accumulate (audio.get(), 0, _film->time_to_audio_frames (time - _last_audio));
- dr->last = time + _film->audio_frames_to_time (audio->frames ());
+ _audio_buffers.ensure_size (time - _next_audio + audio->frames());
+ _audio_buffers.accumulate (audio.get(), 0, _film->time_to_audio_frames (time - _next_audio));
}
/** @return true on error */
bool
Player::seek (Time t)
{
- if (!_have_valid_decoders) {
- setup_decoders ();
- _have_valid_decoders = true;
+ if (!_have_valid_pieces) {
+ setup_pieces ();
+ _have_valid_pieces = true;
}
- if (_decoders.empty ()) {
+ if (_pieces.empty ()) {
return true;
}
- cout << "seek to " << t << "\n";
-
- Time current_time = 0;
- shared_ptr<VideoDecoder> current;
- for (list<shared_ptr<DecoderRecord> >::iterator i = _decoders.begin(); i != _decoders.end(); ++i) {
- shared_ptr<VideoDecoder> v = dynamic_pointer_cast<VideoDecoder> ((*i)->decoder);
- if (!v) {
- continue;
- }
-
- if ((*i)->content->time() < t && (*i)->content->time() >= current_time) {
- current_time = (*i)->content->time();
- current = v;
- }
- }
-
- if (current) {
- cout << "got a decoder to seek to " << (t - current_time) << ".\n";
- current->seek (t - current_time);
- _position = t;
- _last_video = t;
- }
-
/* XXX: don't seek audio because we don't need to... */
return false;
@@ -233,19 +205,27 @@ Player::seek_forward ()
/* XXX */
}
+struct ContentSorter
+{
+ bool operator() (shared_ptr<Content> a, shared_ptr<Content> b)
+ {
+ return a->time() < b->time();
+ }
+};
void
Player::setup_decoders ()
{
- list<shared_ptr<DecoderRecord> > old_decoders = _decoders;
+ list<shared_ptr<Piece> > old_pieces = _pieces;
- _decoders.clear ();
+ _pieces.clear ();
Playlist::ContentList content = _playlist->content ();
+ content.sort (ContentSorter ());
+
for (Playlist::ContentList::iterator i = content.begin(); i != content.end(); ++i) {
- shared_ptr<DecoderRecord> dr (new DecoderRecord);
- dr->content = *i;
+ shared_ptr<Decoder> decoder;
/* XXX: into content? */
@@ -256,7 +236,7 @@ Player::setup_decoders ()
fd->Video.connect (bind (&Player::process_video, this, dr, _1, _2, _3, _4));
fd->Audio.connect (bind (&Player::process_audio, this, dr, _1, _2));
- dr->decoder = fd;
+ decoder = fd;
}
shared_ptr<const ImageMagickContent> ic = dynamic_pointer_cast<const ImageMagickContent> (*i);
@@ -264,10 +244,13 @@ Player::setup_decoders ()
shared_ptr<ImageMagickDecoder> id;
/* See if we can re-use an old ImageMagickDecoder */
- for (list<shared_ptr<DecoderRecord> >::const_iterator i = old_decoders.begin(); i != old_decoders.end(); ++i) {
- shared_ptr<ImageMagickDecoder> imd = dynamic_pointer_cast<ImageMagickDecoder> ((*i)->decoder);
- if (imd && imd->content() == ic) {
- id = imd;
+ for (list<shared_ptr<Piece> >::const_iterator i = old_pieces.begin(); i != old_pieces.end(); ++i) {
+ shared_ptr<ContentPiece> cp = dynamic_pointer_cast<ContentPiece> (*i);
+ if (cp) {
+ shared_ptr<ImageMagickDecoder> imd = dynamic_pointer_cast<ImageMagickDecoder> (cp->decoder ());
+ if (imd && imd->content() == ic) {
+ id = imd;
+ }
}
}
@@ -276,7 +259,7 @@ Player::setup_decoders ()
id->Video.connect (bind (&Player::process_video, this, dr, _1, _2, _3, _4));
}
- dr->decoder = id;
+ decoder = id;
}
shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
@@ -284,10 +267,42 @@ Player::setup_decoders ()
shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
sd->Audio.connect (bind (&Player::process_audio, this, dr, _1, _2));
- dr->decoder = sd;
+ decoder = sd;
}
- _decoders.push_back (dr);
+ _pieces.push_back (shared_ptr<new ContentPiece> (*i, decoder));
+ }
+
+ /* Fill in visual gaps with black and audio gaps with silence */
+
+ Time video_pos = 0;
+ Time audio_pos = 0;
+ list<shared_ptr<Piece> > pieces_copy = _pieces;
+ for (list<shared_ptr<Piece> >::iterator i = pieces_copy.begin(); i != pieces_copy.end(); ++i) {
+ if (dynamic_pointer_cast<VideoContent> ((*i)->content)) {
+ Time const diff = video_pos - (*i)->content->time();
+ if (diff > 0) {
+ _pieces.push_back (
+ shared_ptr<Piece> (
+ shared_ptr<Content> (new NullContent (video_pos, diff)),
+ shared_ptr<Decoder> (new BlackDecoder (video_pos, diff))
+ )
+ );
+ }
+
+ video_pos = (*i)->content->time() + (*i)->content->length();
+ } else {
+ Time const diff = audio_pos - (*i)->content->time();
+ if (diff > 0) {
+ _pieces.push_back (
+ shared_ptr<Piece> (
+ shared_ptr<Content> (new NullContent (audio_pos, diff)),
+ shared_ptr<Decoder> (new SilenceDecoder (audio_pos, diff))
+ )
+ );
+ }
+ audio_pos = (*i)->content->time() + (*i)->content->length();
+ }
}
_position = 0;
@@ -302,14 +317,14 @@ Player::content_changed (weak_ptr<Content> w, int p)
}
if (p == VideoContentProperty::VIDEO_LENGTH) {
- _have_valid_decoders = false;
+ _have_valid_pieces = false;
}
}
void
Player::playlist_changed ()
{
- _have_valid_decoders = false;
+ _have_valid_pieces = false;
}
void