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.
22 #include "ffmpeg_decoder.h"
23 #include "ffmpeg_content.h"
24 #include "imagemagick_decoder.h"
25 #include "imagemagick_content.h"
26 #include "sndfile_decoder.h"
27 #include "sndfile_content.h"
34 using boost::shared_ptr;
35 using boost::weak_ptr;
36 using boost::dynamic_pointer_cast;
38 Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
44 , _have_valid_decoders (false)
46 _playlist->Changed.connect (bind (&Player::playlist_changed, this));
47 _playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2));
51 Player::disable_video ()
57 Player::disable_audio ()
63 Player::disable_subtitles ()
71 if (!_have_valid_decoders) {
73 _have_valid_decoders = true;
78 if (_video && _video_decoder < _video_decoders.size ()) {
80 /* Run video decoder; this may also produce audio */
82 if (_video_decoders[_video_decoder]->pass ()) {
86 if (_video_decoder < _video_decoders.size ()) {
92 if (!_video && _audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG && _sequential_audio_decoder < _audio_decoders.size ()) {
94 /* We're not producing video, so we may need to run FFmpeg content to get the audio */
96 if (_audio_decoders[_sequential_audio_decoder]->pass ()) {
97 _sequential_audio_decoder++;
100 if (_sequential_audio_decoder < _audio_decoders.size ()) {
106 if (_audio && _playlist->audio_from() == Playlist::AUDIO_SNDFILE) {
108 /* We're getting audio from SndfileContent */
110 for (vector<shared_ptr<AudioDecoder> >::iterator i = _audio_decoders.begin(); i != _audio_decoders.end(); ++i) {
111 if (!(*i)->pass ()) {
116 Audio (_audio_buffers, _audio_time.get());
117 _audio_buffers.reset ();
118 _audio_time = boost::none;
125 Player::set_progress (shared_ptr<Job> job)
127 /* Assume progress can be divined from how far through the video we are */
129 if (_video_decoder >= _video_decoders.size() || !_playlist->video_length()) {
133 job->set_progress ((_video_start[_video_decoder] + _video_decoders[_video_decoder]->video_frame()) / _playlist->video_length ());
137 Player::process_video (shared_ptr<const Image> i, bool same, shared_ptr<Subtitle> s, double t)
139 Video (i, same, s, _video_start[_video_decoder] + t);
143 Player::process_audio (weak_ptr<const AudioContent> c, shared_ptr<const AudioBuffers> b, double t)
145 AudioMapping mapping = _film->audio_mapping ();
146 if (!_audio_buffers) {
147 _audio_buffers.reset (new AudioBuffers (mapping.dcp_channels(), b->frames ()));
148 _audio_buffers->make_silent ();
150 if (_playlist->audio_from() == Playlist::AUDIO_FFMPEG) {
151 _audio_time = _audio_time.get() + _audio_start[_sequential_audio_decoder];
155 for (int i = 0; i < b->channels(); ++i) {
156 list<libdcp::Channel> dcp = mapping.content_to_dcp (AudioMapping::Channel (c, i));
157 for (list<libdcp::Channel>::iterator j = dcp.begin(); j != dcp.end(); ++j) {
158 _audio_buffers->accumulate (b, i, static_cast<int> (*j));
162 if (_playlist->audio_from() == Playlist::AUDIO_FFMPEG) {
163 /* We can just emit this audio now as it will all be here */
164 Audio (_audio_buffers, t);
165 _audio_buffers.reset ();
166 _audio_time = boost::none;
170 /** @return true on error */
172 Player::seek (double t)
174 if (!_have_valid_decoders) {
176 _have_valid_decoders = true;
179 if (_video_decoders.empty ()) {
183 /* Find the decoder that contains this position */
187 if (_video_decoder >= _video_decoders.size () || t < _video_start[_video_decoder]) {
189 t -= _video_start[_video_decoder];
194 if (_video_decoder < _video_decoders.size()) {
195 _video_decoders[_video_decoder]->seek (t);
200 /* XXX: don't seek audio because we don't need to... */
213 Player::seek_forward ()
220 Player::setup_decoders ()
222 _video_decoders.clear ();
224 _audio_decoders.clear ();
225 _sequential_audio_decoder = 0;
227 _video_start.clear();
228 _audio_start.clear();
230 double video_so_far = 0;
231 double audio_so_far = 0;
233 list<shared_ptr<const VideoContent> > vc = _playlist->video ();
234 for (list<shared_ptr<const VideoContent> >::iterator i = vc.begin(); i != vc.end(); ++i) {
236 shared_ptr<const VideoContent> video_content;
237 shared_ptr<const AudioContent> audio_content;
238 shared_ptr<VideoDecoder> video_decoder;
239 shared_ptr<AudioDecoder> audio_decoder;
241 /* XXX: into content? */
243 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
245 shared_ptr<FFmpegDecoder> fd (
248 _audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG,
259 shared_ptr<const ImageMagickContent> ic = dynamic_pointer_cast<const ImageMagickContent> (*i);
262 video_decoder.reset (new ImageMagickDecoder (_film, ic));
265 video_decoder->connect_video (shared_from_this ());
266 _video_decoders.push_back (video_decoder);
267 _video_start.push_back (video_so_far);
268 video_so_far += video_content->video_length() / video_content->video_frame_rate();
270 if (audio_decoder && _playlist->audio_from() == Playlist::AUDIO_FFMPEG) {
271 audio_decoder->Audio.connect (bind (&Player::process_audio, this, audio_content, _1, _2));
272 _audio_decoders.push_back (audio_decoder);
273 _audio_start.push_back (audio_so_far);
274 audio_so_far += double(audio_content->audio_length()) / audio_content->audio_frame_rate();
279 _sequential_audio_decoder = 0;
281 if (_playlist->audio_from() == Playlist::AUDIO_SNDFILE) {
283 list<shared_ptr<const AudioContent> > ac = _playlist->audio ();
284 for (list<shared_ptr<const AudioContent> >::iterator i = ac.begin(); i != ac.end(); ++i) {
286 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
289 shared_ptr<AudioDecoder> d (new SndfileDecoder (_film, sc));
290 d->Audio.connect (bind (&Player::process_audio, this, sc, _1, _2));
291 _audio_decoders.push_back (d);
292 _audio_start.push_back (audio_so_far);
298 Player::last_video_time () const
300 return _video_start[_video_decoder] + _video_decoders[_video_decoder]->last_content_time ();
304 Player::content_changed (weak_ptr<Content> w, int p)
306 shared_ptr<Content> c = w.lock ();
311 if (p == VideoContentProperty::VIDEO_LENGTH) {
312 _have_valid_decoders = false;
317 Player::playlist_changed ()
319 _have_valid_decoders = false;