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"
29 #include "subtitle_content.h"
34 #include "resampler.h"
44 using boost::shared_ptr;
45 using boost::weak_ptr;
46 using boost::dynamic_pointer_cast;
48 //#define DEBUG_PLAYER 1
53 Piece (shared_ptr<Content> c)
55 , video_position (c->start ())
56 , audio_position (c->start ())
59 Piece (shared_ptr<Content> c, shared_ptr<Decoder> d)
62 , video_position (c->start ())
63 , audio_position (c->start ())
66 shared_ptr<Content> content;
67 shared_ptr<Decoder> decoder;
73 std::ostream& operator<<(std::ostream& s, Piece const & p)
75 if (dynamic_pointer_cast<FFmpegContent> (p.content)) {
77 } else if (dynamic_pointer_cast<ImageMagickContent> (p.content)) {
79 } else if (dynamic_pointer_cast<SndfileContent> (p.content)) {
83 s << " at " << p.content->start() << " until " << p.content->end();
89 Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
94 , _have_valid_pieces (false)
97 , _audio_buffers (f->dcp_audio_channels(), 0)
99 _playlist->Changed.connect (bind (&Player::playlist_changed, this));
100 _playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2, _3));
101 _film->Changed.connect (bind (&Player::film_changed, this, _1));
102 set_video_container_size (_film->container()->size (_film->full_frame ()));
106 Player::disable_video ()
112 Player::disable_audio ()
120 if (!_have_valid_pieces) {
122 _have_valid_pieces = true;
129 Time earliest_t = TIME_MAX;
130 shared_ptr<Piece> earliest;
136 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
137 if ((*i)->decoder->done ()) {
141 if (_video && dynamic_pointer_cast<VideoDecoder> ((*i)->decoder)) {
142 if ((*i)->video_position < earliest_t) {
143 earliest_t = (*i)->video_position;
149 if (_audio && dynamic_pointer_cast<AudioDecoder> ((*i)->decoder)) {
150 if ((*i)->audio_position < earliest_t) {
151 earliest_t = (*i)->audio_position;
160 cout << "no earliest piece.\n";
169 if (earliest_t > _video_position) {
171 cout << "no video here; emitting black frame (earliest=" << earliest_t << ", video_position=" << _video_position << ").\n";
176 cout << "Pass " << *earliest << "\n";
178 earliest->decoder->pass ();
183 if (earliest_t > _audio_position) {
185 cout << "no audio here; emitting silence.\n";
187 emit_silence (_film->time_to_audio_frames (earliest_t - _audio_position));
190 cout << "Pass " << *earliest << "\n";
192 earliest->decoder->pass ();
198 cout << "\tpost pass " << _video_position << " " << _audio_position << "\n";
205 Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image, bool same, VideoContent::Frame frame)
207 shared_ptr<Piece> piece = weak_piece.lock ();
212 shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
215 FrameRateConversion frc (content->video_frame_rate(), _film->dcp_video_frame_rate());
216 if (frc.skip && (frame % 2) == 1) {
220 shared_ptr<Image> work_image = image->crop (content->crop(), true);
222 libdcp::Size const image_size = content->ratio()->size (_video_container_size);
224 work_image = work_image->scale_and_convert_to_rgb (image_size, _film->scaler(), true);
226 Time time = content->start() + (frame * frc.factor() * TIME_HZ / _film->dcp_video_frame_rate());
228 if (_film->with_subtitles () && _out_subtitle.image && time >= _out_subtitle.from && time <= _out_subtitle.to) {
229 work_image->alpha_blend (_out_subtitle.image, _out_subtitle.position);
232 if (image_size != _video_container_size) {
233 assert (image_size.width <= _video_container_size.width);
234 assert (image_size.height <= _video_container_size.height);
235 shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
237 im->copy (work_image, Position<int> ((_video_container_size.width - image_size.width) / 2, (_video_container_size.height - image_size.height) / 2));
241 #ifdef DCPOMATIC_DEBUG
242 _last_video = piece->content;
245 Video (work_image, same, time);
246 time += TIME_HZ / _film->dcp_video_frame_rate();
249 Video (work_image, true, time);
250 time += TIME_HZ / _film->dcp_video_frame_rate();
253 _video_position = piece->video_position = time;
257 Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers> audio, AudioContent::Frame frame)
259 shared_ptr<Piece> piece = weak_piece.lock ();
264 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
268 if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) {
269 shared_ptr<Resampler> r = resampler (content);
270 audio = r->run (audio);
274 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->dcp_audio_channels(), audio->frames()));
275 dcp_mapped->make_silent ();
276 list<pair<int, libdcp::Channel> > map = content->audio_mapping().content_to_dcp ();
277 for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) {
278 if (i->first < audio->channels() && i->second < dcp_mapped->channels()) {
279 dcp_mapped->accumulate_channel (audio.get(), i->first, i->second);
285 Time time = content->start() + (frame * TIME_HZ / _film->dcp_audio_frame_rate()) + (content->audio_delay() * TIME_HZ / 1000);
287 /* We must cut off anything that comes before the start of all time */
289 int const frames = - time * _film->dcp_audio_frame_rate() / TIME_HZ;
290 if (frames >= audio->frames ()) {
294 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->channels(), audio->frames() - frames));
295 trimmed->copy_from (audio.get(), audio->frames() - frames, frames, 0);
301 /* The time of this audio may indicate that some of our buffered audio is not going to
302 be added to any more, so it can be emitted.
305 if (time > _audio_position) {
306 /* We can emit some audio from our buffers */
307 OutputAudioFrame const N = _film->time_to_audio_frames (time - _audio_position);
308 if (N > _audio_buffers.frames()) {
309 /* We need some extra silence before whatever is in the buffers */
310 _audio_buffers.ensure_size (N);
311 _audio_buffers.move (0, N - _audio_buffers.frames(), _audio_buffers.frames ());
312 _audio_buffers.make_silent (0, _audio_buffers.frames());
313 _audio_buffers.set_frames (N);
315 assert (N <= _audio_buffers.frames());
316 shared_ptr<AudioBuffers> emit (new AudioBuffers (_audio_buffers.channels(), N));
317 emit->copy_from (&_audio_buffers, N, 0, 0);
318 Audio (emit, _audio_position);
319 _audio_position = piece->audio_position = time + _film->audio_frames_to_time (N);
321 /* And remove it from our buffers */
322 if (_audio_buffers.frames() > N) {
323 _audio_buffers.move (N, 0, _audio_buffers.frames() - N);
325 _audio_buffers.set_frames (_audio_buffers.frames() - N);
328 /* Now accumulate the new audio into our buffers */
329 _audio_buffers.ensure_size (_audio_buffers.frames() + audio->frames());
330 _audio_buffers.accumulate_frames (audio.get(), 0, 0, audio->frames ());
331 _audio_buffers.set_frames (_audio_buffers.frames() + audio->frames());
337 if (_audio_buffers.frames() > 0) {
338 shared_ptr<AudioBuffers> emit (new AudioBuffers (_audio_buffers.channels(), _audio_buffers.frames()));
339 emit->copy_from (&_audio_buffers, _audio_buffers.frames(), 0, 0);
340 Audio (emit, _audio_position);
341 _audio_position += _film->audio_frames_to_time (_audio_buffers.frames ());
342 _audio_buffers.set_frames (0);
345 while (_video_position < _audio_position) {
349 while (_audio_position < _video_position) {
350 emit_silence (_film->time_to_audio_frames (_video_position - _audio_position));
355 /** Seek so that the next pass() will yield (approximately) the requested frame.
356 * Pass accurate = true to try harder to get close to the request.
357 * @return true on error
360 Player::seek (Time t, bool accurate)
362 if (!_have_valid_pieces) {
364 _have_valid_pieces = true;
367 if (_pieces.empty ()) {
371 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
372 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content);
377 Time s = t - vc->start ();
378 s = max (static_cast<Time> (0), s);
379 s = min (vc->length(), s);
381 (*i)->video_position = (*i)->audio_position = vc->start() + s;
383 FrameRateConversion frc (vc->video_frame_rate(), _film->dcp_video_frame_rate());
384 /* Here we are converting from time (in the DCP) to a frame number in the content.
385 Hence we need to use the DCP's frame rate and the double/skip correction, not
388 VideoContent::Frame f = s * _film->dcp_video_frame_rate() / (frc.factor() * TIME_HZ);
389 dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (f, accurate);
392 _video_position = _audio_position = t;
394 /* XXX: don't seek audio because we don't need to... */
398 Player::setup_pieces ()
400 list<shared_ptr<Piece> > old_pieces = _pieces;
404 Playlist::ContentList content = _playlist->content ();
405 sort (content.begin(), content.end(), ContentSorter ());
407 for (Playlist::ContentList::iterator i = content.begin(); i != content.end(); ++i) {
409 shared_ptr<Piece> piece (new Piece (*i));
411 /* XXX: into content? */
413 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
415 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
417 fd->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3));
418 fd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
419 fd->Subtitle.connect (bind (&Player::process_subtitle, this, piece, _1, _2, _3, _4));
424 shared_ptr<const ImageMagickContent> ic = dynamic_pointer_cast<const ImageMagickContent> (*i);
426 shared_ptr<ImageMagickDecoder> id;
428 /* See if we can re-use an old ImageMagickDecoder */
429 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
430 shared_ptr<ImageMagickDecoder> imd = dynamic_pointer_cast<ImageMagickDecoder> ((*j)->decoder);
431 if (imd && imd->content() == ic) {
437 id.reset (new ImageMagickDecoder (_film, ic));
438 id->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3));
444 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
446 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
447 sd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
452 _pieces.push_back (piece);
456 cout << "=== Player setup:\n";
457 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
458 cout << *(i->get()) << "\n";
464 Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
466 shared_ptr<Content> c = w.lock ();
472 property == ContentProperty::START || property == ContentProperty::LENGTH ||
473 property == VideoContentProperty::VIDEO_CROP || property == VideoContentProperty::VIDEO_RATIO
476 _have_valid_pieces = false;
479 } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET || property == SubtitleContentProperty::SUBTITLE_SCALE) {
486 Player::playlist_changed ()
488 _have_valid_pieces = false;
493 Player::set_video_container_size (libdcp::Size s)
495 _video_container_size = s;
496 _black_frame.reset (new Image (PIX_FMT_RGB24, _video_container_size, true));
497 _black_frame->make_black ();
500 shared_ptr<Resampler>
501 Player::resampler (shared_ptr<AudioContent> c)
503 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
504 if (i != _resamplers.end ()) {
508 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
514 Player::emit_black ()
516 #ifdef DCPOMATIC_DEBUG
517 _last_video.reset ();
520 /* XXX: use same here */
521 Video (_black_frame, false, _video_position);
522 _video_position += _film->video_frames_to_time (1);
526 Player::emit_silence (OutputAudioFrame most)
528 OutputAudioFrame N = min (most, _film->dcp_audio_frame_rate() / 2);
529 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->dcp_audio_channels(), N));
530 silence->make_silent ();
531 Audio (silence, _audio_position);
532 _audio_position += _film->audio_frames_to_time (N);
536 Player::film_changed (Film::Property p)
538 /* Here we should notice Film properties that affect our output, and
539 alert listeners that our output now would be different to how it was
540 last time we were run.
543 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER) {
549 Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
551 _in_subtitle.piece = weak_piece;
552 _in_subtitle.image = image;
553 _in_subtitle.rect = rect;
554 _in_subtitle.from = from;
555 _in_subtitle.to = to;
561 Player::update_subtitle ()
563 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
568 if (!_in_subtitle.image) {
569 _out_subtitle.image.reset ();
573 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
576 dcpomatic::Rect<double> in_rect = _in_subtitle.rect;
577 libdcp::Size scaled_size;
579 in_rect.y += sc->subtitle_offset ();
581 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
582 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
583 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
585 /* Then we need a corrective translation, consisting of two parts:
587 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
588 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
590 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
591 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
592 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
594 * Combining these two translations gives these expressions.
597 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
598 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
600 _out_subtitle.image = _in_subtitle.image->scale (libdcp::Size (scaled_size.width, scaled_size.height), Scaler::from_id ("bicubic"), true);
601 _out_subtitle.from = _in_subtitle.from + piece->content->start ();
602 _out_subtitle.to = _in_subtitle.to + piece->content->start ();