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 "moving_image_decoder.h"
28 #include "moving_image_content.h"
29 #include "sndfile_decoder.h"
30 #include "sndfile_content.h"
31 #include "subtitle_content.h"
36 #include "resampler.h"
47 using boost::shared_ptr;
48 using boost::weak_ptr;
49 using boost::dynamic_pointer_cast;
51 //#define DEBUG_PLAYER 1
56 Piece (shared_ptr<Content> c)
58 , video_position (c->position ())
59 , audio_position (c->position ())
62 Piece (shared_ptr<Content> c, shared_ptr<Decoder> d)
65 , video_position (c->position ())
66 , audio_position (c->position ())
69 shared_ptr<Content> content;
70 shared_ptr<Decoder> decoder;
76 std::ostream& operator<<(std::ostream& s, Piece const & p)
78 if (dynamic_pointer_cast<FFmpegContent> (p.content)) {
80 } else if (dynamic_pointer_cast<StillImageContent> (p.content)) {
82 } else if (dynamic_pointer_cast<SndfileContent> (p.content)) {
86 s << " at " << p.content->position() << " until " << p.content->end();
92 Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
97 , _have_valid_pieces (false)
100 , _audio_merger (f->audio_channels(), bind (&Film::time_to_audio_frames, f.get(), _1), bind (&Film::audio_frames_to_time, f.get(), _1))
101 , _last_emit_was_black (false)
103 _playlist_changed_connection = _playlist->Changed.connect (bind (&Player::playlist_changed, this));
104 _playlist_content_changed_connection = _playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2, _3));
105 _film_changed_connection = _film->Changed.connect (bind (&Player::film_changed, this, _1));
106 set_video_container_size (_film->container()->size (_film->full_frame ()));
110 Player::disable_video ()
116 Player::disable_audio ()
124 if (!_have_valid_pieces) {
126 _have_valid_pieces = true;
133 Time earliest_t = TIME_MAX;
134 shared_ptr<Piece> earliest;
140 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
141 if ((*i)->decoder->done ()) {
145 if (_video && dynamic_pointer_cast<VideoDecoder> ((*i)->decoder)) {
146 if ((*i)->video_position < earliest_t) {
147 earliest_t = (*i)->video_position;
153 if (_audio && dynamic_pointer_cast<AudioDecoder> ((*i)->decoder)) {
154 if ((*i)->audio_position < earliest_t) {
155 earliest_t = (*i)->audio_position;
164 cout << "no earliest piece.\n";
173 if (earliest_t > _video_position) {
175 cout << "no video here; emitting black frame (earliest=" << earliest_t << ", video_position=" << _video_position << ").\n";
180 cout << "Pass " << *earliest << "\n";
182 earliest->decoder->pass ();
187 if (earliest_t > _audio_position) {
189 cout << "no audio here; emitting silence.\n";
191 emit_silence (_film->time_to_audio_frames (earliest_t - _audio_position));
194 cout << "Pass " << *earliest << "\n";
196 earliest->decoder->pass ();
198 if (earliest->decoder->done()) {
199 shared_ptr<AudioContent> ac = dynamic_pointer_cast<AudioContent> (earliest->content);
201 shared_ptr<Resampler> re = resampler (ac, false);
203 shared_ptr<const AudioBuffers> b = re->flush ();
205 process_audio (earliest, b, ac->audio_length ());
213 Time done_up_to = TIME_MAX;
214 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
215 if (dynamic_pointer_cast<AudioContent> ((*i)->content)) {
216 done_up_to = min (done_up_to, (*i)->audio_position);
220 TimedAudioBuffers<Time> tb = _audio_merger.pull (done_up_to);
221 Audio (tb.audio, tb.time);
222 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
229 cout << "\tpost pass " << _video_position << " " << _audio_position << "\n";
236 Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image, Eyes eyes, bool same, VideoContent::Frame frame)
238 shared_ptr<Piece> piece = weak_piece.lock ();
243 shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
246 FrameRateConversion frc (content->video_frame_rate(), _film->video_frame_rate());
247 if (frc.skip && (frame % 2) == 1) {
251 Time const relative_time = (frame * frc.factor() * TIME_HZ / _film->video_frame_rate());
252 if (content->trimmed (relative_time)) {
256 shared_ptr<Image> work_image = image->crop (content->crop(), true);
258 libdcp::Size const image_size = content->ratio()->size (_video_container_size);
260 work_image = work_image->scale_and_convert_to_rgb (image_size, _film->scaler(), true);
262 Time time = content->position() + relative_time - content->trim_start ();
264 if (_film->with_subtitles () && _out_subtitle.image && time >= _out_subtitle.from && time <= _out_subtitle.to) {
265 work_image->alpha_blend (_out_subtitle.image, _out_subtitle.position);
268 if (image_size != _video_container_size) {
269 assert (image_size.width <= _video_container_size.width);
270 assert (image_size.height <= _video_container_size.height);
271 shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
273 im->copy (work_image, Position<int> ((_video_container_size.width - image_size.width) / 2, (_video_container_size.height - image_size.height) / 2));
277 #ifdef DCPOMATIC_DEBUG
278 _last_video = piece->content;
281 Video (work_image, eyes, same, time);
282 time += TIME_HZ / _film->video_frame_rate();
285 Video (work_image, eyes, true, time);
286 time += TIME_HZ / _film->video_frame_rate();
289 _last_emit_was_black = false;
291 _video_position = piece->video_position = time;
295 Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers> audio, AudioContent::Frame frame)
297 shared_ptr<Piece> piece = weak_piece.lock ();
302 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
305 Time const relative_time = _film->audio_frames_to_time (frame)
306 + (content->audio_delay() * TIME_HZ / 1000);
308 if (content->trimmed (relative_time)) {
312 Time time = content->position() + relative_time;
315 if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) {
316 shared_ptr<Resampler> r = resampler (content, true);
317 pair<shared_ptr<const AudioBuffers>, AudioContent::Frame> ro = r->run (audio, frame);
323 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->frames()));
324 dcp_mapped->make_silent ();
325 list<pair<int, libdcp::Channel> > map = content->audio_mapping().content_to_dcp ();
326 for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) {
327 if (i->first < audio->channels() && i->second < dcp_mapped->channels()) {
328 dcp_mapped->accumulate_channel (audio.get(), i->first, i->second);
334 /* We must cut off anything that comes before the start of all time */
336 int const frames = - time * _film->audio_frame_rate() / TIME_HZ;
337 if (frames >= audio->frames ()) {
341 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->channels(), audio->frames() - frames));
342 trimmed->copy_from (audio.get(), audio->frames() - frames, frames, 0);
348 _audio_merger.push (audio, time);
349 piece->audio_position += _film->audio_frames_to_time (audio->frames ());
355 TimedAudioBuffers<Time> tb = _audio_merger.flush ();
357 Audio (tb.audio, tb.time);
358 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
361 while (_video_position < _audio_position) {
365 while (_audio_position < _video_position) {
366 emit_silence (_film->time_to_audio_frames (_video_position - _audio_position));
371 /** Seek so that the next pass() will yield (approximately) the requested frame.
372 * Pass accurate = true to try harder to get close to the request.
373 * @return true on error
376 Player::seek (Time t, bool accurate)
378 if (!_have_valid_pieces) {
380 _have_valid_pieces = true;
383 if (_pieces.empty ()) {
387 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
388 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content);
393 Time s = t - vc->position ();
394 s = max (static_cast<Time> (0), s);
395 s = min (vc->length_after_trim(), s);
397 (*i)->video_position = (*i)->audio_position = vc->position() + s;
399 FrameRateConversion frc (vc->video_frame_rate(), _film->video_frame_rate());
400 /* Here we are converting from time (in the DCP) to a frame number in the content.
401 Hence we need to use the DCP's frame rate and the double/skip correction, not
404 VideoContent::Frame f = (s + vc->trim_start ()) * _film->video_frame_rate() / (frc.factor() * TIME_HZ);
405 dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (f, accurate);
408 _video_position = _audio_position = t;
410 /* XXX: don't seek audio because we don't need to... */
414 Player::setup_pieces ()
416 list<shared_ptr<Piece> > old_pieces = _pieces;
420 ContentList content = _playlist->content ();
421 sort (content.begin(), content.end(), ContentSorter ());
423 for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
425 shared_ptr<Piece> piece (new Piece (*i));
427 /* XXX: into content? */
429 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
431 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
433 fd->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4));
434 fd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
435 fd->Subtitle.connect (bind (&Player::process_subtitle, this, piece, _1, _2, _3, _4));
440 shared_ptr<const StillImageContent> ic = dynamic_pointer_cast<const StillImageContent> (*i);
442 shared_ptr<StillImageDecoder> id;
444 /* See if we can re-use an old StillImageDecoder */
445 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
446 shared_ptr<StillImageDecoder> imd = dynamic_pointer_cast<StillImageDecoder> ((*j)->decoder);
447 if (imd && imd->content() == ic) {
453 id.reset (new StillImageDecoder (_film, ic));
454 id->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4));
460 shared_ptr<const MovingImageContent> mc = dynamic_pointer_cast<const MovingImageContent> (*i);
462 shared_ptr<MovingImageDecoder> md;
465 md.reset (new MovingImageDecoder (_film, mc));
466 md->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4));
472 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
474 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
475 sd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
480 _pieces.push_back (piece);
484 cout << "=== Player setup:\n";
485 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
486 cout << *(i->get()) << "\n";
492 Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
494 shared_ptr<Content> c = w.lock ();
500 property == ContentProperty::POSITION || property == ContentProperty::LENGTH ||
501 property == ContentProperty::TRIM_START || property == ContentProperty::TRIM_END ||
502 property == VideoContentProperty::VIDEO_CROP || property == VideoContentProperty::VIDEO_RATIO
505 _have_valid_pieces = false;
508 } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET || property == SubtitleContentProperty::SUBTITLE_SCALE) {
511 } else if (property == VideoContentProperty::VIDEO_FRAME_TYPE) {
517 Player::playlist_changed ()
519 _have_valid_pieces = false;
524 Player::set_video_container_size (libdcp::Size s)
526 _video_container_size = s;
527 _black_frame.reset (new Image (PIX_FMT_RGB24, _video_container_size, true));
528 _black_frame->make_black ();
531 shared_ptr<Resampler>
532 Player::resampler (shared_ptr<AudioContent> c, bool create)
534 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
535 if (i != _resamplers.end ()) {
540 return shared_ptr<Resampler> ();
543 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
549 Player::emit_black ()
551 #ifdef DCPOMATIC_DEBUG
552 _last_video.reset ();
555 Video (_black_frame, EYES_BOTH, _last_emit_was_black, _video_position);
556 _video_position += _film->video_frames_to_time (1);
557 _last_emit_was_black = true;
561 Player::emit_silence (OutputAudioFrame most)
563 OutputAudioFrame N = min (most, _film->audio_frame_rate() / 2);
564 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), N));
565 silence->make_silent ();
566 Audio (silence, _audio_position);
567 _audio_position += _film->audio_frames_to_time (N);
571 Player::film_changed (Film::Property p)
573 /* Here we should notice Film properties that affect our output, and
574 alert listeners that our output now would be different to how it was
575 last time we were run.
578 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER) {
584 Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
586 _in_subtitle.piece = weak_piece;
587 _in_subtitle.image = image;
588 _in_subtitle.rect = rect;
589 _in_subtitle.from = from;
590 _in_subtitle.to = to;
596 Player::update_subtitle ()
598 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
603 if (!_in_subtitle.image) {
604 _out_subtitle.image.reset ();
608 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
611 dcpomatic::Rect<double> in_rect = _in_subtitle.rect;
612 libdcp::Size scaled_size;
614 in_rect.y += sc->subtitle_offset ();
616 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
617 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
618 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
620 /* Then we need a corrective translation, consisting of two parts:
622 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
623 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
625 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
626 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
627 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
629 * Combining these two translations gives these expressions.
632 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
633 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
635 _out_subtitle.image = _in_subtitle.image->scale (libdcp::Size (scaled_size.width, scaled_size.height), Scaler::from_id ("bicubic"), true);
636 _out_subtitle.from = _in_subtitle.from + piece->content->position ();
637 _out_subtitle.to = _in_subtitle.to + piece->content->position ();