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;
54 Piece (shared_ptr<Content> c)
56 , video_position (c->position ())
57 , 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 void set_repeat (IncomingVideo video, int num)
71 cout << "Set repeat " << num << "\n";
79 repeat_video.image.reset ();
84 bool repeating () const
86 return repeat_done != repeat_to_do;
89 void repeat (Player* player)
91 cout << "repeating; " << repeat_done << "\n";
92 player->process_video (
93 repeat_video.weak_piece,
98 (repeat_done + 1) * (TIME_HZ / player->_film->video_frame_rate ())
104 shared_ptr<Content> content;
105 shared_ptr<Decoder> decoder;
109 IncomingVideo repeat_video;
114 Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
119 , _have_valid_pieces (false)
120 , _video_position (0)
121 , _audio_position (0)
122 , _audio_merger (f->audio_channels(), bind (&Film::time_to_audio_frames, f.get(), _1), bind (&Film::audio_frames_to_time, f.get(), _1))
123 , _last_emit_was_black (false)
125 _playlist_changed_connection = _playlist->Changed.connect (bind (&Player::playlist_changed, this));
126 _playlist_content_changed_connection = _playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2, _3));
127 _film_changed_connection = _film->Changed.connect (bind (&Player::film_changed, this, _1));
128 set_video_container_size (fit_ratio_within (_film->container()->ratio (), _film->full_frame ()));
132 Player::disable_video ()
138 Player::disable_audio ()
146 if (!_have_valid_pieces) {
148 _have_valid_pieces = true;
151 Time earliest_t = TIME_MAX;
152 shared_ptr<Piece> earliest;
158 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
159 if ((*i)->decoder->done ()) {
160 cout << "Scan: done.\n";
164 if (_video && dynamic_pointer_cast<VideoDecoder> ((*i)->decoder)) {
165 if ((*i)->video_position < earliest_t) {
166 earliest_t = (*i)->video_position;
172 if (_audio && dynamic_pointer_cast<AudioDecoder> ((*i)->decoder)) {
173 if ((*i)->audio_position < earliest_t) {
174 earliest_t = (*i)->audio_position;
182 cout << "No earliest: out.\n";
187 cout << "Earliest: " << earliest_t << "\n";
192 if (earliest_t > _video_position) {
195 if (earliest->repeating ()) {
196 cout << "-repeating.\n";
197 earliest->repeat (this);
199 cout << "-passing.\n";
200 earliest->decoder->pass ();
207 if (earliest_t > _audio_position) {
208 emit_silence (_film->time_to_audio_frames (earliest_t - _audio_position));
210 earliest->decoder->pass ();
212 if (earliest->decoder->done()) {
213 shared_ptr<AudioContent> ac = dynamic_pointer_cast<AudioContent> (earliest->content);
215 shared_ptr<Resampler> re = resampler (ac, false);
217 shared_ptr<const AudioBuffers> b = re->flush ();
219 process_audio (earliest, b, ac->audio_length ());
228 Time audio_done_up_to = TIME_MAX;
229 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
230 if (dynamic_pointer_cast<AudioDecoder> ((*i)->decoder)) {
231 audio_done_up_to = min (audio_done_up_to, (*i)->audio_position);
235 TimedAudioBuffers<Time> tb = _audio_merger.pull (audio_done_up_to);
236 Audio (tb.audio, tb.time);
237 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
244 Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image, Eyes eyes, bool same, VideoContent::Frame frame, Time extra)
246 cout << "PLAYER RECEIVES A VIDEO FRAME, extra " << extra << "\n";
248 /* Keep a note of what came in so that we can repeat it if required */
249 _last_incoming_video.weak_piece = weak_piece;
250 _last_incoming_video.image = image;
251 _last_incoming_video.eyes = eyes;
252 _last_incoming_video.same = same;
253 _last_incoming_video.frame = frame;
255 shared_ptr<Piece> piece = weak_piece.lock ();
260 shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
263 FrameRateConversion frc (content->video_frame_rate(), _film->video_frame_rate());
264 if (frc.skip && (frame % 2) == 1) {
268 Time const relative_time = (frame * frc.factor() * TIME_HZ / _film->video_frame_rate());
269 if (content->trimmed (relative_time)) {
273 /* Convert to RGB first, as FFmpeg doesn't seem to like handling YUV images with odd widths */
274 shared_ptr<Image> work_image = image->scale (image->size (), _film->scaler(), PIX_FMT_RGB24, true);
276 work_image = work_image->crop (content->crop(), true);
278 float const ratio = content->ratio() ? content->ratio()->ratio() : content->video_size_after_crop().ratio();
279 libdcp::Size image_size = fit_ratio_within (ratio, _video_container_size);
281 work_image = work_image->scale (image_size, _film->scaler(), PIX_FMT_RGB24, true);
283 Time time = content->position() + relative_time + extra - content->trim_start ();
285 if (_film->with_subtitles () && _out_subtitle.image && time >= _out_subtitle.from && time <= _out_subtitle.to) {
286 work_image->alpha_blend (_out_subtitle.image, _out_subtitle.position);
289 if (image_size != _video_container_size) {
290 assert (image_size.width <= _video_container_size.width);
291 assert (image_size.height <= _video_container_size.height);
292 shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
294 im->copy (work_image, Position<int> ((_video_container_size.width - image_size.width) / 2, (_video_container_size.height - image_size.height) / 2));
298 #ifdef DCPOMATIC_DEBUG
299 _last_video = piece->content;
302 Video (work_image, eyes, content->colour_conversion(), same, time);
304 time += TIME_HZ / _film->video_frame_rate();
305 _last_emit_was_black = false;
306 _video_position = piece->video_position = time;
308 cout << "frc.repeat=" << frc.repeat << "; vp now " << _video_position << "\n";
310 if (frc.repeat > 1 && !piece->repeating ()) {
311 piece->set_repeat (_last_incoming_video, frc.repeat - 1);
316 Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers> audio, AudioContent::Frame frame)
318 shared_ptr<Piece> piece = weak_piece.lock ();
323 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
327 if (content->audio_gain() != 0) {
328 shared_ptr<AudioBuffers> gain (new AudioBuffers (audio));
329 gain->apply_gain (content->audio_gain ());
334 if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) {
335 shared_ptr<Resampler> r = resampler (content, true);
336 pair<shared_ptr<const AudioBuffers>, AudioContent::Frame> ro = r->run (audio, frame);
341 Time const relative_time = _film->audio_frames_to_time (frame);
343 if (content->trimmed (relative_time)) {
347 Time time = content->position() + (content->audio_delay() * TIME_HZ / 1000) + relative_time;
350 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->frames()));
351 dcp_mapped->make_silent ();
352 list<pair<int, libdcp::Channel> > map = content->audio_mapping().content_to_dcp ();
353 for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) {
354 if (i->first < audio->channels() && i->second < dcp_mapped->channels()) {
355 dcp_mapped->accumulate_channel (audio.get(), i->first, i->second);
361 /* We must cut off anything that comes before the start of all time */
363 int const frames = - time * _film->audio_frame_rate() / TIME_HZ;
364 if (frames >= audio->frames ()) {
368 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->channels(), audio->frames() - frames));
369 trimmed->copy_from (audio.get(), audio->frames() - frames, frames, 0);
375 _audio_merger.push (audio, time);
376 piece->audio_position += _film->audio_frames_to_time (audio->frames ());
382 TimedAudioBuffers<Time> tb = _audio_merger.flush ();
384 Audio (tb.audio, tb.time);
385 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
388 while (_video_position < _audio_position) {
392 while (_audio_position < _video_position) {
393 emit_silence (_film->time_to_audio_frames (_video_position - _audio_position));
398 /** Seek so that the next pass() will yield (approximately) the requested frame.
399 * Pass accurate = true to try harder to get close to the request.
400 * @return true on error
403 Player::seek (Time t, bool accurate)
405 if (!_have_valid_pieces) {
407 _have_valid_pieces = true;
410 if (_pieces.empty ()) {
414 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
415 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content);
420 Time s = t - vc->position ();
421 s = max (static_cast<Time> (0), s);
422 s = min (vc->length_after_trim(), s);
424 (*i)->video_position = (*i)->audio_position = vc->position() + s;
426 FrameRateConversion frc (vc->video_frame_rate(), _film->video_frame_rate());
427 /* Here we are converting from time (in the DCP) to a frame number in the content.
428 Hence we need to use the DCP's frame rate and the double/skip correction, not
431 VideoContent::Frame f = (s + vc->trim_start ()) * _film->video_frame_rate() / (frc.factor() * TIME_HZ);
432 dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (f, accurate);
434 (*i)->reset_repeat ();
437 _video_position = _audio_position = t;
439 /* XXX: don't seek audio because we don't need to... */
443 Player::setup_pieces ()
445 list<shared_ptr<Piece> > old_pieces = _pieces;
449 ContentList content = _playlist->content ();
450 sort (content.begin(), content.end(), ContentSorter ());
452 for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
454 shared_ptr<Piece> piece (new Piece (*i));
456 /* XXX: into content? */
458 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
460 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
462 fd->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4, 0));
463 fd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
464 fd->Subtitle.connect (bind (&Player::process_subtitle, this, piece, _1, _2, _3, _4));
469 shared_ptr<const StillImageContent> ic = dynamic_pointer_cast<const StillImageContent> (*i);
471 shared_ptr<StillImageDecoder> id;
473 /* See if we can re-use an old StillImageDecoder */
474 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
475 shared_ptr<StillImageDecoder> imd = dynamic_pointer_cast<StillImageDecoder> ((*j)->decoder);
476 if (imd && imd->content() == ic) {
482 id.reset (new StillImageDecoder (_film, ic));
483 id->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4, 0));
489 shared_ptr<const MovingImageContent> mc = dynamic_pointer_cast<const MovingImageContent> (*i);
491 shared_ptr<MovingImageDecoder> md;
494 md.reset (new MovingImageDecoder (_film, mc));
495 md->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4, 0));
501 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
503 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
504 sd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
509 _pieces.push_back (piece);
514 Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
516 shared_ptr<Content> c = w.lock ();
522 property == ContentProperty::POSITION || property == ContentProperty::LENGTH ||
523 property == ContentProperty::TRIM_START || property == ContentProperty::TRIM_END
526 _have_valid_pieces = false;
529 } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET || property == SubtitleContentProperty::SUBTITLE_SCALE) {
535 property == VideoContentProperty::VIDEO_FRAME_TYPE || property == VideoContentProperty::VIDEO_CROP ||
536 property == VideoContentProperty::VIDEO_RATIO
544 Player::playlist_changed ()
546 _have_valid_pieces = false;
551 Player::set_video_container_size (libdcp::Size s)
553 _video_container_size = s;
554 _black_frame.reset (new Image (PIX_FMT_RGB24, _video_container_size, true));
555 _black_frame->make_black ();
558 shared_ptr<Resampler>
559 Player::resampler (shared_ptr<AudioContent> c, bool create)
561 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
562 if (i != _resamplers.end ()) {
567 return shared_ptr<Resampler> ();
570 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
576 Player::emit_black ()
578 #ifdef DCPOMATIC_DEBUG
579 _last_video.reset ();
582 Video (_black_frame, EYES_BOTH, ColourConversion(), _last_emit_was_black, _video_position);
583 _video_position += _film->video_frames_to_time (1);
584 _last_emit_was_black = true;
588 Player::emit_silence (OutputAudioFrame most)
594 OutputAudioFrame N = min (most, _film->audio_frame_rate() / 2);
595 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), N));
596 silence->make_silent ();
597 Audio (silence, _audio_position);
598 _audio_position += _film->audio_frames_to_time (N);
602 Player::film_changed (Film::Property p)
604 /* Here we should notice Film properties that affect our output, and
605 alert listeners that our output now would be different to how it was
606 last time we were run.
609 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER) {
615 Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
617 _in_subtitle.piece = weak_piece;
618 _in_subtitle.image = image;
619 _in_subtitle.rect = rect;
620 _in_subtitle.from = from;
621 _in_subtitle.to = to;
627 Player::update_subtitle ()
629 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
634 if (!_in_subtitle.image) {
635 _out_subtitle.image.reset ();
639 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
642 dcpomatic::Rect<double> in_rect = _in_subtitle.rect;
643 libdcp::Size scaled_size;
645 in_rect.y += sc->subtitle_offset ();
647 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
648 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
649 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
651 /* Then we need a corrective translation, consisting of two parts:
653 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
654 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
656 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
657 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
658 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
660 * Combining these two translations gives these expressions.
663 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
664 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
666 _out_subtitle.image = _in_subtitle.image->scale (
668 Scaler::from_id ("bicubic"),
669 _in_subtitle.image->pixel_format (),
672 _out_subtitle.from = _in_subtitle.from + piece->content->position ();
673 _out_subtitle.to = _in_subtitle.to + piece->content->position ();
676 /** Re-emit the last frame that was emitted, using current settings for crop, ratio, scaler and subtitles.
677 * @return false if this could not be done.
680 Player::repeat_last_video ()
682 if (!_last_incoming_video.image) {
687 _last_incoming_video.weak_piece,
688 _last_incoming_video.image,
689 _last_incoming_video.eyes,
690 _last_incoming_video.same,
691 _last_incoming_video.frame,