1 /* -*- c-basic-offset: 8; default-tab-width: 8; -*- */
4 Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "ffmpeg_decoder.h"
25 #include "ffmpeg_content.h"
26 #include "imagemagick_decoder.h"
27 #include "imagemagick_content.h"
28 #include "sndfile_decoder.h"
29 #include "sndfile_content.h"
38 using boost::shared_ptr;
39 using boost::weak_ptr;
40 using boost::dynamic_pointer_cast;
44 Piece (shared_ptr<Content> c, shared_ptr<Decoder> d)
49 shared_ptr<Content> content;
50 shared_ptr<Decoder> decoder;
53 Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
59 , _have_valid_decoders (false)
61 , _audio_buffers (MAX_AUDIO_CHANNELS, 0)
63 , _last_was_black (false)
66 _playlist->Changed.connect (bind (&Player::playlist_changed, this));
67 _playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2));
71 Player::disable_video ()
77 Player::disable_audio ()
83 Player::disable_subtitles ()
91 if (!_have_valid_pieces) {
93 _have_valid_pieces = true;
96 /* Here we are just finding the active decoder with the earliest last emission time, then
100 Time earliest_t = TIME_MAX;
101 shared_ptr<Piece> earliest;
103 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
104 if ((*i)->content->end(_film) < _position) {
108 Time const t = (*i)->content->start() + (*i)->decoder->next();
109 if (t < earliest_t) {
119 earliest->decoder->pass ();
121 /* Move position to earliest active next emission */
123 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
124 if ((*i)->content->end(_film) < _position) {
128 Time const t = (*i)->content->start() + (*i)->decoder->next();
139 Player::process_video (shared_ptr<Piece> piece, shared_ptr<const Image> image, bool same, shared_ptr<Subtitle> sub, Time time)
141 time += piece->start ();
143 Video (image, same, sub, time);
147 Player::process_audio (shared_ptr<Piece> piece, shared_ptr<const AudioBuffers> audio, Time time)
151 /* The time of this audio may indicate that some of our buffered audio is not going to
152 be added to any more, so it can be emitted.
155 time += piece->start ();
157 if (time > _next_audio) {
158 /* We can emit some audio from our buffers */
159 OutputAudioFrame const N = min (_film->time_to_audio_frames (time - _next_audio), static_cast<OutputAudioFrame> (_audio_buffers.frames()));
160 shared_ptr<AudioBuffers> emit (new AudioBuffers (_audio_buffers.channels(), N));
161 emit->copy_from (&_audio_buffers, N, 0, 0);
162 Audio (emit, _next_audio);
163 _next_audio += _film->audio_frames_to_time (N);
165 /* And remove it from our buffers */
166 if (_audio_buffers.frames() > N) {
167 _audio_buffers.move (N, 0, _audio_buffers.frames() - N);
169 _audio_buffers.set_frames (_audio_buffers.frames() - N);
172 /* Now accumulate the new audio into our buffers */
173 _audio_buffers.ensure_size (time - _next_audio + audio->frames());
174 _audio_buffers.accumulate (audio.get(), 0, _film->time_to_audio_frames (time - _next_audio));
177 /** @return true on error */
179 Player::seek (Time t)
181 if (!_have_valid_pieces) {
183 _have_valid_pieces = true;
186 if (_pieces.empty ()) {
190 /* XXX: don't seek audio because we don't need to... */
203 Player::seek_forward ()
210 bool operator() (shared_ptr<Content> a, shared_ptr<Content> b)
212 return a->time() < b->time();
217 Player::setup_decoders ()
219 list<shared_ptr<Piece> > old_pieces = _pieces;
223 Playlist::ContentList content = _playlist->content ();
224 content.sort (ContentSorter ());
226 for (Playlist::ContentList::iterator i = content.begin(); i != content.end(); ++i) {
228 shared_ptr<Decoder> decoder;
230 /* XXX: into content? */
232 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
234 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio, _subtitles));
236 fd->Video.connect (bind (&Player::process_video, this, dr, _1, _2, _3, _4));
237 fd->Audio.connect (bind (&Player::process_audio, this, dr, _1, _2));
242 shared_ptr<const ImageMagickContent> ic = dynamic_pointer_cast<const ImageMagickContent> (*i);
244 shared_ptr<ImageMagickDecoder> id;
246 /* See if we can re-use an old ImageMagickDecoder */
247 for (list<shared_ptr<Piece> >::const_iterator i = old_pieces.begin(); i != old_pieces.end(); ++i) {
248 shared_ptr<ContentPiece> cp = dynamic_pointer_cast<ContentPiece> (*i);
250 shared_ptr<ImageMagickDecoder> imd = dynamic_pointer_cast<ImageMagickDecoder> (cp->decoder ());
251 if (imd && imd->content() == ic) {
258 id.reset (new ImageMagickDecoder (_film, ic));
259 id->Video.connect (bind (&Player::process_video, this, dr, _1, _2, _3, _4));
265 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
267 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
268 sd->Audio.connect (bind (&Player::process_audio, this, dr, _1, _2));
273 _pieces.push_back (shared_ptr<new ContentPiece> (*i, decoder));
276 /* Fill in visual gaps with black and audio gaps with silence */
280 list<shared_ptr<Piece> > pieces_copy = _pieces;
281 for (list<shared_ptr<Piece> >::iterator i = pieces_copy.begin(); i != pieces_copy.end(); ++i) {
282 if (dynamic_pointer_cast<VideoContent> ((*i)->content)) {
283 Time const diff = video_pos - (*i)->content->time();
287 shared_ptr<Content> (new NullContent (video_pos, diff)),
288 shared_ptr<Decoder> (new BlackDecoder (video_pos, diff))
293 video_pos = (*i)->content->time() + (*i)->content->length();
295 Time const diff = audio_pos - (*i)->content->time();
299 shared_ptr<Content> (new NullContent (audio_pos, diff)),
300 shared_ptr<Decoder> (new SilenceDecoder (audio_pos, diff))
304 audio_pos = (*i)->content->time() + (*i)->content->length();
312 Player::content_changed (weak_ptr<Content> w, int p)
314 shared_ptr<Content> c = w.lock ();
319 if (p == VideoContentProperty::VIDEO_LENGTH) {
320 _have_valid_pieces = false;
325 Player::playlist_changed ()
327 _have_valid_pieces = false;
331 Player::emit_black_frame ()
333 shared_ptr<SimpleImage> image (new SimpleImage (AV_PIX_FMT_RGB24, libdcp::Size (128, 128), true));
334 Video (image, _last_was_black, shared_ptr<Subtitle> (), _last_video);
335 _last_video += _film->video_frames_to_time (1);
339 Player::emit_silence (Time t)
341 OutputAudioFrame frames = _film->time_to_audio_frames (t);
343 /* Do this in half-second chunks so we don't overwhelm anybody */
344 OutputAudioFrame this_time = min (_film->dcp_audio_frame_rate() / 2, frames);
345 shared_ptr<AudioBuffers> silence (new AudioBuffers (MAX_AUDIO_CHANNELS, this_time));
346 silence->make_silent ();
347 Audio (silence, _last_audio);
348 _last_audio += _film->audio_frames_to_time (this_time);