2 Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <boost/shared_ptr.hpp>
22 #include "sndfile_content.h"
23 #include "sndfile_decoder.h"
24 #include "ffmpeg_content.h"
25 #include "ffmpeg_decoder.h"
26 #include "imagemagick_content.h"
27 #include "imagemagick_decoder.h"
31 using boost::shared_ptr;
32 using boost::dynamic_pointer_cast;
35 : _video_from (VIDEO_NONE)
36 , _audio_from (AUDIO_NONE)
42 Playlist::setup (ContentList content)
44 _video_from = VIDEO_NONE;
45 _audio_from = AUDIO_NONE;
47 for (ContentList::const_iterator i = content.begin(); i != content.end(); ++i) {
48 shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (*i);
52 _video_from = VIDEO_FFMPEG;
53 if (_audio_from == AUDIO_NONE) {
54 _audio_from = AUDIO_FFMPEG;
58 shared_ptr<ImageMagickContent> ic = dynamic_pointer_cast<ImageMagickContent> (*i);
60 _imagemagick.push_back (ic);
61 if (_video_from == VIDEO_NONE) {
62 _video_from = VIDEO_IMAGEMAGICK;
66 shared_ptr<SndfileContent> sc = dynamic_pointer_cast<SndfileContent> (*i);
68 _sndfile.push_back (sc);
69 _audio_from = AUDIO_SNDFILE;
75 Playlist::audio_length () const
77 switch (_audio_from) {
81 return _ffmpeg->audio_length ();
84 ContentAudioFrame l = 0;
85 for (list<shared_ptr<const SndfileContent> >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) {
86 l += (*i)->audio_length ();
96 Playlist::audio_channels () const
98 switch (_audio_from) {
102 return _ffmpeg->audio_channels ();
106 for (list<shared_ptr<const SndfileContent> >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) {
107 c += (*i)->audio_channels ();
117 Playlist::audio_frame_rate () const
119 switch (_audio_from) {
123 return _ffmpeg->audio_frame_rate ();
125 return _sndfile.front()->audio_frame_rate ();
132 Playlist::audio_channel_layout () const
134 switch (_audio_from) {
138 return _ffmpeg->audio_channel_layout ();
148 Playlist::video_frame_rate () const
150 switch (_video_from) {
154 return _ffmpeg->video_frame_rate ();
155 case VIDEO_IMAGEMAGICK:
163 Playlist::video_size () const
165 switch (_video_from) {
167 return libdcp::Size ();
169 return _ffmpeg->video_size ();
170 case VIDEO_IMAGEMAGICK:
172 return _imagemagick.front()->video_size ();
175 return libdcp::Size ();
179 Playlist::video_length () const
181 switch (_video_from) {
185 return _ffmpeg->video_length ();
186 case VIDEO_IMAGEMAGICK:
188 ContentVideoFrame l = 0;
189 for (list<shared_ptr<const ImageMagickContent> >::const_iterator i = _imagemagick.begin(); i != _imagemagick.end(); ++i) {
190 l += (*i)->video_length ();
200 Playlist::has_audio () const
202 return _audio_from != AUDIO_NONE;
205 Player::Player (boost::shared_ptr<const Film> f, boost::shared_ptr<const Playlist> p)
211 , _have_setup_decoders (false)
212 , _ffmpeg_decoder_done (false)
219 Player::disable_video ()
225 Player::disable_audio ()
231 Player::disable_subtitles ()
239 if (!_have_setup_decoders) {
241 _have_setup_decoders = true;
246 if (_playlist->video_from() == Playlist::VIDEO_FFMPEG || _playlist->audio_from() == Playlist::AUDIO_FFMPEG) {
247 if (!_ffmpeg_decoder_done) {
248 if (_ffmpeg_decoder->pass ()) {
249 _ffmpeg_decoder_done = true;
256 if (_playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) {
257 if (_imagemagick_decoder != _imagemagick_decoders.end ()) {
258 if ((*_imagemagick_decoder)->pass ()) {
259 _imagemagick_decoder++;
262 if (_imagemagick_decoder != _imagemagick_decoders.end ()) {
274 Player::set_progress (shared_ptr<Job> job)
280 Player::process_video (shared_ptr<Image> i, bool same, shared_ptr<Subtitle> s)
286 Player::process_audio (shared_ptr<AudioBuffers> b)
291 /** @return true on error */
293 Player::seek (double t)
297 switch (_playlist->video_from()) {
298 case Playlist::VIDEO_NONE:
300 case Playlist::VIDEO_FFMPEG:
301 if (_ffmpeg_decoder->seek (t)) {
305 case Playlist::VIDEO_IMAGEMAGICK:
306 /* Find the decoder that contains this position */
307 _imagemagick_decoder = _imagemagick_decoders.begin ();
308 while (_imagemagick_decoder != _imagemagick_decoders.end ()) {
309 double const this_length = (*_imagemagick_decoder)->video_length() / _film->video_frame_rate ();
310 if (this_length < t) {
314 ++_imagemagick_decoder;
317 if (_imagemagick_decoder != _imagemagick_decoders.end()) {
318 (*_imagemagick_decoder)->seek (t);
325 /* XXX: don't seek audio because we don't need to... */
331 Player::seek_to_last ()
335 switch (_playlist->video_from ()) {
336 case Playlist::VIDEO_NONE:
338 case Playlist::VIDEO_FFMPEG:
339 if (_ffmpeg_decoder->seek_to_last ()) {
343 case Playlist::VIDEO_IMAGEMAGICK:
344 if ((*_imagemagick_decoder)->seek_to_last ()) {
350 /* XXX: don't seek audio because we don't need to... */
356 Player::setup_decoders ()
358 if ((_video && _playlist->video_from() == Playlist::VIDEO_FFMPEG) || (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG)) {
359 _ffmpeg_decoder.reset (
363 _video && _playlist->video_from() == Playlist::VIDEO_FFMPEG,
364 _audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG,
365 _subtitles && _film->with_subtitles(),
371 if (_video && _playlist->video_from() == Playlist::VIDEO_FFMPEG) {
372 _ffmpeg_decoder->connect_video (shared_from_this ());
375 if (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG) {
376 _ffmpeg_decoder->connect_audio (shared_from_this ());
379 if (_video && _playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) {
380 list<shared_ptr<const ImageMagickContent> > ic = _playlist->imagemagick ();
381 for (list<shared_ptr<const ImageMagickContent> >::iterator i = ic.begin(); i != ic.end(); ++i) {
382 shared_ptr<ImageMagickDecoder> d (new ImageMagickDecoder (_film, *i));
383 _imagemagick_decoders.push_back (d);
384 d->connect_video (shared_from_this ());
387 _imagemagick_decoder = _imagemagick_decoders.begin ();
390 if (_audio && _playlist->audio_from() == Playlist::AUDIO_SNDFILE) {
391 list<shared_ptr<const SndfileContent> > sc = _playlist->sndfile ();
392 for (list<shared_ptr<const SndfileContent> >::iterator i = sc.begin(); i != sc.end(); ++i) {
393 shared_ptr<SndfileDecoder> d (new SndfileDecoder (_film, *i));
394 _sndfile_decoders.push_back (d);
395 d->connect_audio (shared_from_this ());
401 Player::disable_video_sync ()
407 Player::last_video_time () const
409 switch (_playlist->video_from ()) {
410 case Playlist::VIDEO_NONE:
412 case Playlist::VIDEO_FFMPEG:
413 return _ffmpeg_decoder->last_source_time ();
414 case Playlist::VIDEO_IMAGEMAGICK:
415 return (*_imagemagick_decoder)->last_source_time ();