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 "still_image_decoder.h"
26 #include "still_image_content.h"
27 #include "sndfile_decoder.h"
28 #include "sndfile_content.h"
29 #include "subtitle_content.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<StillImageContent> (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->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, Eyes eyes, 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->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->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, eyes, same, time);
246 time += TIME_HZ / _film->video_frame_rate();
249 Video (work_image, eyes, true, time);
250 time += TIME_HZ / _film->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 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->frames()));
269 dcp_mapped->make_silent ();
270 list<pair<int, libdcp::Channel> > map = content->audio_mapping().content_to_dcp ();
271 for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) {
272 if (i->first < audio->channels() && i->second < dcp_mapped->channels()) {
273 dcp_mapped->accumulate_channel (audio.get(), i->first, i->second);
279 Time time = content->start()
280 + _film->audio_frames_to_time (frame)
281 + (content->audio_delay() * TIME_HZ / 1000);
283 /* We must cut off anything that comes before the start of all time */
285 int const frames = - time * _film->audio_frame_rate() / TIME_HZ;
286 if (frames >= audio->frames ()) {
290 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->channels(), audio->frames() - frames));
291 trimmed->copy_from (audio.get(), audio->frames() - frames, frames, 0);
297 /* The time of this audio may indicate that some of our buffered audio is not going to
298 be added to any more, so it can be emitted.
301 if (time > _audio_position) {
302 /* We can emit some audio from our buffers; this is how many frames */
303 OutputAudioFrame const N = _film->time_to_audio_frames (time - _audio_position);
304 if (N > _audio_buffers.frames()) {
305 /* We need some extra silence before whatever is in the buffers */
306 _audio_buffers.ensure_size (N);
307 _audio_buffers.move (0, N - _audio_buffers.frames(), _audio_buffers.frames ());
308 _audio_buffers.make_silent (0, _audio_buffers.frames());
309 _audio_buffers.set_frames (N);
311 assert (N <= _audio_buffers.frames());
313 /* XXX: not convinced that a copy is necessary here */
314 shared_ptr<AudioBuffers> emit (new AudioBuffers (_audio_buffers.channels(), N));
315 emit->copy_from (&_audio_buffers, N, 0, 0);
316 Audio (emit, _audio_position);
317 _audio_position = piece->audio_position = _audio_position + _film->audio_frames_to_time (N);
319 /* And remove it from our buffers */
320 if (_audio_buffers.frames() > N) {
321 _audio_buffers.move (N, 0, _audio_buffers.frames() - N);
323 _audio_buffers.set_frames (_audio_buffers.frames() - N);
326 /* Now accumulate the new audio into our buffers */
327 _audio_buffers.ensure_size (_audio_buffers.frames() + audio->frames());
328 _audio_buffers.accumulate_frames (audio.get(), 0, 0, audio->frames ());
329 _audio_buffers.set_frames (_audio_buffers.frames() + audio->frames());
335 if (_audio_buffers.frames() > 0) {
336 shared_ptr<AudioBuffers> emit (new AudioBuffers (_audio_buffers.channels(), _audio_buffers.frames()));
337 emit->copy_from (&_audio_buffers, _audio_buffers.frames(), 0, 0);
338 Audio (emit, _audio_position);
339 _audio_position += _film->audio_frames_to_time (_audio_buffers.frames ());
340 _audio_buffers.set_frames (0);
343 while (_video_position < _audio_position) {
347 while (_audio_position < _video_position) {
348 emit_silence (_film->time_to_audio_frames (_video_position - _audio_position));
353 /** Seek so that the next pass() will yield (approximately) the requested frame.
354 * Pass accurate = true to try harder to get close to the request.
355 * @return true on error
358 Player::seek (Time t, bool accurate)
360 if (!_have_valid_pieces) {
362 _have_valid_pieces = true;
365 if (_pieces.empty ()) {
369 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
370 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content);
375 Time s = t - vc->start ();
376 s = max (static_cast<Time> (0), s);
377 s = min (vc->length(), s);
379 (*i)->video_position = (*i)->audio_position = vc->start() + s;
381 FrameRateConversion frc (vc->video_frame_rate(), _film->video_frame_rate());
382 /* Here we are converting from time (in the DCP) to a frame number in the content.
383 Hence we need to use the DCP's frame rate and the double/skip correction, not
386 VideoContent::Frame f = s * _film->video_frame_rate() / (frc.factor() * TIME_HZ);
387 dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (f, accurate);
390 _video_position = _audio_position = t;
392 /* XXX: don't seek audio because we don't need to... */
396 Player::setup_pieces ()
398 list<shared_ptr<Piece> > old_pieces = _pieces;
402 ContentList content = _playlist->content ();
403 sort (content.begin(), content.end(), ContentSorter ());
405 for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
407 shared_ptr<Piece> piece (new Piece (*i));
409 /* XXX: into content? */
411 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
413 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
415 fd->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4));
416 fd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
417 fd->Subtitle.connect (bind (&Player::process_subtitle, this, piece, _1, _2, _3, _4));
422 shared_ptr<const StillImageContent> ic = dynamic_pointer_cast<const StillImageContent> (*i);
424 shared_ptr<StillImageDecoder> id;
426 /* See if we can re-use an old StillImageDecoder */
427 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
428 shared_ptr<StillImageDecoder> imd = dynamic_pointer_cast<StillImageDecoder> ((*j)->decoder);
429 if (imd && imd->content() == ic) {
435 id.reset (new StillImageDecoder (_film, ic));
436 id->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4));
442 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
444 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
445 sd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
450 _pieces.push_back (piece);
454 cout << "=== Player setup:\n";
455 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
456 cout << *(i->get()) << "\n";
462 Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
464 shared_ptr<Content> c = w.lock ();
470 property == ContentProperty::START || property == ContentProperty::LENGTH ||
471 property == VideoContentProperty::VIDEO_CROP || property == VideoContentProperty::VIDEO_RATIO
474 _have_valid_pieces = false;
477 } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET || property == SubtitleContentProperty::SUBTITLE_SCALE) {
480 } else if (property == VideoContentProperty::VIDEO_FRAME_TYPE) {
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 ();
501 Player::emit_black ()
503 #ifdef DCPOMATIC_DEBUG
504 _last_video.reset ();
507 /* XXX: use same here */
508 Video (_black_frame, EYES_BOTH, false, _video_position);
509 _video_position += _film->video_frames_to_time (1);
513 Player::emit_silence (OutputAudioFrame most)
515 OutputAudioFrame N = min (most, _film->audio_frame_rate() / 2);
516 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), N));
517 silence->make_silent ();
518 Audio (silence, _audio_position);
519 _audio_position += _film->audio_frames_to_time (N);
523 Player::film_changed (Film::Property p)
525 /* Here we should notice Film properties that affect our output, and
526 alert listeners that our output now would be different to how it was
527 last time we were run.
530 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER) {
536 Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
538 _in_subtitle.piece = weak_piece;
539 _in_subtitle.image = image;
540 _in_subtitle.rect = rect;
541 _in_subtitle.from = from;
542 _in_subtitle.to = to;
548 Player::update_subtitle ()
550 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
555 if (!_in_subtitle.image) {
556 _out_subtitle.image.reset ();
560 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
563 dcpomatic::Rect<double> in_rect = _in_subtitle.rect;
564 libdcp::Size scaled_size;
566 in_rect.y += sc->subtitle_offset ();
568 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
569 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
570 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
572 /* Then we need a corrective translation, consisting of two parts:
574 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
575 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
577 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
578 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
579 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
581 * Combining these two translations gives these expressions.
584 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
585 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
587 _out_subtitle.image = _in_subtitle.image->scale (libdcp::Size (scaled_size.width, scaled_size.height), Scaler::from_id ("bicubic"), true);
588 _out_subtitle.from = _in_subtitle.from + piece->content->start ();
589 _out_subtitle.to = _in_subtitle.to + piece->content->start ();