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.
23 #include "ffmpeg_decoder.h"
24 #include "ffmpeg_content.h"
25 #include "imagemagick_decoder.h"
26 #include "imagemagick_content.h"
27 #include "sndfile_decoder.h"
28 #include "sndfile_content.h"
33 #include "resampler.h"
42 using boost::shared_ptr;
43 using boost::weak_ptr;
44 using boost::dynamic_pointer_cast;
46 #define DEBUG_PLAYER 1
51 Piece (shared_ptr<Content> c)
53 , video_position (c->start ())
54 , audio_position (c->start ())
57 Piece (shared_ptr<Content> c, shared_ptr<Decoder> d)
60 , video_position (c->start ())
61 , audio_position (c->start ())
64 shared_ptr<Content> content;
65 shared_ptr<Decoder> decoder;
71 std::ostream& operator<<(std::ostream& s, Piece const & p)
73 if (dynamic_pointer_cast<FFmpegContent> (p.content)) {
75 } else if (dynamic_pointer_cast<ImageMagickContent> (p.content)) {
77 } else if (dynamic_pointer_cast<SndfileContent> (p.content)) {
81 s << " at " << p.content->start() << " until " << p.content->end();
87 Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
92 , _have_valid_pieces (false)
95 , _audio_buffers (f->dcp_audio_channels(), 0)
97 _playlist->Changed.connect (bind (&Player::playlist_changed, this));
98 _playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2));
99 _film->Changed.connect (bind (&Player::film_changed, this, _1));
100 set_video_container_size (_film->container()->size (_film->full_frame ()));
104 Player::disable_video ()
110 Player::disable_audio ()
118 if (!_have_valid_pieces) {
120 _have_valid_pieces = true;
127 Time earliest_t = TIME_MAX;
128 shared_ptr<Piece> earliest;
134 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
135 if ((*i)->decoder->done ()) {
139 if (dynamic_pointer_cast<VideoDecoder> ((*i)->decoder)) {
140 if ((*i)->video_position < earliest_t) {
141 earliest_t = (*i)->video_position;
147 if (dynamic_pointer_cast<AudioDecoder> ((*i)->decoder)) {
148 if ((*i)->audio_position < earliest_t) {
149 earliest_t = (*i)->audio_position;
158 cout << "no earliest piece.\n";
167 if (earliest_t > _video_position) {
169 cout << "no video here; emitting black frame.\n";
174 cout << "Pass " << *earliest << "\n";
176 earliest->decoder->pass ();
181 if (earliest_t > _audio_position) {
183 cout << "no audio here; emitting silence.\n";
185 emit_silence (_film->time_to_audio_frames (earliest_t - _audio_position));
188 cout << "Pass " << *earliest << "\n";
190 earliest->decoder->pass ();
196 cout << "\tpost pass " << _video_position << " " << _audio_position << "\n";
203 Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image, bool same, VideoContent::Frame frame)
205 shared_ptr<Piece> piece = weak_piece.lock ();
210 shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
213 FrameRateConversion frc (content->video_frame_rate(), _film->dcp_video_frame_rate());
214 if (frc.skip && (frame % 2) == 1) {
218 image = image->crop (content->crop(), true);
220 libdcp::Size const image_size = content->ratio()->size (_video_container_size);
222 image = image->scale_and_convert_to_rgb (image_size, _film->scaler(), true);
225 if (film->with_subtitles ()) {
226 shared_ptr<Subtitle> sub;
227 if (_timed_subtitle && _timed_subtitle->displayed_at (t)) {
228 sub = _timed_subtitle->subtitle ();
232 dcpomatic::Rect const tx = subtitle_transformed_area (
233 float (image_size.width) / content->video_size().width,
234 float (image_size.height) / content->video_size().height,
235 sub->area(), film->subtitle_offset(), film->subtitle_scale()
238 shared_ptr<Image> im = sub->image()->scale (tx.size(), film->scaler(), true);
239 image->alpha_blend (im, tx.position());
244 if (image_size != _video_container_size) {
245 assert (image_size.width <= _video_container_size.width);
246 assert (image_size.height <= _video_container_size.height);
247 shared_ptr<Image> im (new SimpleImage (PIX_FMT_RGB24, _video_container_size, true));
249 im->copy (image, Position ((_video_container_size.width - image_size.width) / 2, (_video_container_size.height - image_size.height) / 2));
253 Time time = content->start() + (frame * frc.factor() * TIME_HZ / _film->dcp_video_frame_rate());
255 Video (image, same, time);
256 time += TIME_HZ / _film->dcp_video_frame_rate();
259 Video (image, true, time);
260 time += TIME_HZ / _film->dcp_video_frame_rate();
263 _video_position = piece->video_position = time;
267 Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers> audio, AudioContent::Frame frame)
269 shared_ptr<Piece> piece = weak_piece.lock ();
274 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
277 if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) {
278 audio = resampler(content)->run (audio);
282 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->dcp_audio_channels(), audio->frames()));
283 dcp_mapped->make_silent ();
284 list<pair<int, libdcp::Channel> > map = content->audio_mapping().content_to_dcp ();
285 for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) {
286 dcp_mapped->accumulate_channel (audio.get(), i->first, i->second);
291 /* The time of this audio may indicate that some of our buffered audio is not going to
292 be added to any more, so it can be emitted.
295 Time const time = content->start() + (frame * TIME_HZ / _film->dcp_audio_frame_rate());
297 if (time > _audio_position) {
298 /* We can emit some audio from our buffers */
299 OutputAudioFrame const N = _film->time_to_audio_frames (time - _audio_position);
300 assert (N <= _audio_buffers.frames());
301 shared_ptr<AudioBuffers> emit (new AudioBuffers (_audio_buffers.channels(), N));
302 emit->copy_from (&_audio_buffers, N, 0, 0);
303 Audio (emit, _audio_position);
304 _audio_position = piece->audio_position = time + _film->audio_frames_to_time (N);
306 /* And remove it from our buffers */
307 if (_audio_buffers.frames() > N) {
308 _audio_buffers.move (N, 0, _audio_buffers.frames() - N);
310 _audio_buffers.set_frames (_audio_buffers.frames() - N);
313 /* Now accumulate the new audio into our buffers */
314 _audio_buffers.ensure_size (_audio_buffers.frames() + audio->frames());
315 _audio_buffers.accumulate_frames (audio.get(), 0, 0, audio->frames ());
316 _audio_buffers.set_frames (_audio_buffers.frames() + audio->frames());
322 if (_audio_buffers.frames() > 0) {
323 shared_ptr<AudioBuffers> emit (new AudioBuffers (_audio_buffers.channels(), _audio_buffers.frames()));
324 emit->copy_from (&_audio_buffers, _audio_buffers.frames(), 0, 0);
325 Audio (emit, _audio_position);
326 _audio_position += _film->audio_frames_to_time (_audio_buffers.frames ());
327 _audio_buffers.set_frames (0);
330 while (_video_position < _audio_position) {
334 while (_audio_position < _video_position) {
335 emit_silence (_film->time_to_audio_frames (_video_position - _audio_position));
340 /** @return true on error */
342 Player::seek (Time t, bool accurate)
344 if (!_have_valid_pieces) {
346 _have_valid_pieces = true;
349 if (_pieces.empty ()) {
353 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
354 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content);
359 Time s = t - vc->start ();
360 s = max (static_cast<Time> (0), s);
361 s = min (vc->length(), s);
363 FrameRateConversion frc (vc->video_frame_rate(), _film->dcp_video_frame_rate());
364 VideoContent::Frame f = s * vc->video_frame_rate() / (frc.factor() * TIME_HZ);
365 dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (f, accurate);
368 /* XXX: don't seek audio because we don't need to... */
372 Player::setup_pieces ()
374 list<shared_ptr<Piece> > old_pieces = _pieces;
378 Playlist::ContentList content = _playlist->content ();
379 sort (content.begin(), content.end(), ContentSorter ());
381 for (Playlist::ContentList::iterator i = content.begin(); i != content.end(); ++i) {
383 shared_ptr<Piece> piece (new Piece (*i));
385 /* XXX: into content? */
387 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
389 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
391 fd->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3));
392 fd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
397 shared_ptr<const ImageMagickContent> ic = dynamic_pointer_cast<const ImageMagickContent> (*i);
399 shared_ptr<ImageMagickDecoder> id;
401 /* See if we can re-use an old ImageMagickDecoder */
402 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
403 shared_ptr<ImageMagickDecoder> imd = dynamic_pointer_cast<ImageMagickDecoder> ((*j)->decoder);
404 if (imd && imd->content() == ic) {
410 id.reset (new ImageMagickDecoder (_film, ic));
411 id->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3));
417 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
419 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
420 sd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
425 _pieces.push_back (piece);
429 cout << "=== Player setup:\n";
430 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
431 cout << *(i->get()) << "\n";
437 Player::content_changed (weak_ptr<Content> w, int p)
439 shared_ptr<Content> c = w.lock ();
445 p == ContentProperty::START || p == ContentProperty::LENGTH ||
446 p == VideoContentProperty::VIDEO_CROP || p == VideoContentProperty::VIDEO_RATIO
449 _have_valid_pieces = false;
455 Player::playlist_changed ()
457 _have_valid_pieces = false;
462 Player::set_video_container_size (libdcp::Size s)
464 _video_container_size = s;
465 _black_frame.reset (new SimpleImage (PIX_FMT_RGB24, _video_container_size, true));
466 _black_frame->make_black ();
469 shared_ptr<Resampler>
470 Player::resampler (shared_ptr<AudioContent> c)
472 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
473 if (i != _resamplers.end ()) {
477 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
483 Player::emit_black ()
485 /* XXX: use same here */
486 Video (_black_frame, false, _video_position);
487 _video_position += _film->video_frames_to_time (1);
491 Player::emit_silence (OutputAudioFrame most)
493 OutputAudioFrame N = min (most, _film->dcp_audio_frame_rate() / 2);
494 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->dcp_audio_channels(), N));
495 silence->make_silent ();
496 Audio (silence, _audio_position);
497 _audio_position += _film->audio_frames_to_time (N);
501 Player::film_changed (Film::Property p)
503 /* Here we should notice Film properties that affect our output, and
504 alert listeners that our output now would be different to how it was
505 last time we were run.
509 p == Film::SCALER || p == Film::WITH_SUBTITLES ||
510 p == Film::SUBTITLE_SCALE || p == Film::SUBTITLE_OFFSET ||