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 ())
60 Piece (shared_ptr<Content> c, shared_ptr<Decoder> d)
63 , video_position (c->position ())
64 , audio_position (c->position ())
67 shared_ptr<Content> content;
68 shared_ptr<Decoder> decoder;
73 Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
78 , _have_valid_pieces (false)
81 , _audio_merger (f->audio_channels(), bind (&Film::time_to_audio_frames, f.get(), _1), bind (&Film::audio_frames_to_time, f.get(), _1))
82 , _last_emit_was_black (false)
84 _playlist_changed_connection = _playlist->Changed.connect (bind (&Player::playlist_changed, this));
85 _playlist_content_changed_connection = _playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2, _3));
86 _film_changed_connection = _film->Changed.connect (bind (&Player::film_changed, this, _1));
87 set_video_container_size (fit_ratio_within (_film->container()->ratio (), _film->full_frame ()));
91 Player::disable_video ()
97 Player::disable_audio ()
105 if (!_have_valid_pieces) {
107 _have_valid_pieces = true;
110 Time earliest_t = TIME_MAX;
111 shared_ptr<Piece> earliest;
117 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
118 if ((*i)->decoder->done ()) {
122 if (_video && dynamic_pointer_cast<VideoDecoder> ((*i)->decoder)) {
123 if ((*i)->video_position < earliest_t) {
124 earliest_t = (*i)->video_position;
130 if (_audio && dynamic_pointer_cast<AudioDecoder> ((*i)->decoder)) {
131 if ((*i)->audio_position < earliest_t) {
132 earliest_t = (*i)->audio_position;
146 if (earliest_t > _video_position) {
149 earliest->decoder->pass ();
154 if (earliest_t > _audio_position) {
155 emit_silence (_film->time_to_audio_frames (earliest_t - _audio_position));
157 earliest->decoder->pass ();
159 if (earliest->decoder->done()) {
160 shared_ptr<AudioContent> ac = dynamic_pointer_cast<AudioContent> (earliest->content);
162 shared_ptr<Resampler> re = resampler (ac, false);
164 shared_ptr<const AudioBuffers> b = re->flush ();
166 process_audio (earliest, b, ac->audio_length ());
175 Time audio_done_up_to = TIME_MAX;
176 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
177 if (dynamic_pointer_cast<AudioDecoder> ((*i)->decoder)) {
178 audio_done_up_to = min (audio_done_up_to, (*i)->audio_position);
182 TimedAudioBuffers<Time> tb = _audio_merger.pull (audio_done_up_to);
183 Audio (tb.audio, tb.time);
184 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
191 Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image, Eyes eyes, bool same, VideoContent::Frame frame)
193 shared_ptr<Piece> piece = weak_piece.lock ();
198 shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
201 FrameRateConversion frc (content->video_frame_rate(), _film->video_frame_rate());
202 if (frc.skip && (frame % 2) == 1) {
206 Time const relative_time = (frame * frc.factor() * TIME_HZ / _film->video_frame_rate());
207 if (content->trimmed (relative_time)) {
211 /* Convert to RGB first, as FFmpeg doesn't seem to like handling YUV images with odd widths */
212 shared_ptr<Image> work_image = image->scale (image->size (), _film->scaler(), PIX_FMT_RGB24, true);
214 work_image = work_image->crop (content->crop(), true);
216 float const ratio = content->ratio() ? content->ratio()->ratio() : content->video_size_after_crop().ratio();
217 libdcp::Size image_size = fit_ratio_within (ratio, _video_container_size);
219 work_image = work_image->scale (image_size, _film->scaler(), PIX_FMT_RGB24, true);
221 Time time = content->position() + relative_time - content->trim_start ();
223 if (_film->with_subtitles () && _out_subtitle.image && time >= _out_subtitle.from && time <= _out_subtitle.to) {
224 work_image->alpha_blend (_out_subtitle.image, _out_subtitle.position);
227 if (image_size != _video_container_size) {
228 assert (image_size.width <= _video_container_size.width);
229 assert (image_size.height <= _video_container_size.height);
230 shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
232 im->copy (work_image, Position<int> ((_video_container_size.width - image_size.width) / 2, (_video_container_size.height - image_size.height) / 2));
236 #ifdef DCPOMATIC_DEBUG
237 _last_video = piece->content;
240 Video (work_image, eyes, content->colour_conversion(), same, time);
241 time += TIME_HZ / _film->video_frame_rate();
244 Video (work_image, eyes, content->colour_conversion(), true, time);
245 time += TIME_HZ / _film->video_frame_rate();
248 _last_emit_was_black = false;
250 _video_position = piece->video_position = time;
254 Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers> audio, AudioContent::Frame frame)
256 shared_ptr<Piece> piece = weak_piece.lock ();
261 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
265 if (content->audio_gain() != 0) {
266 shared_ptr<AudioBuffers> gain (new AudioBuffers (audio));
267 gain->apply_gain (content->audio_gain ());
272 if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) {
273 shared_ptr<Resampler> r = resampler (content, true);
274 pair<shared_ptr<const AudioBuffers>, AudioContent::Frame> ro = r->run (audio, frame);
279 Time const relative_time = _film->audio_frames_to_time (frame);
281 if (content->trimmed (relative_time)) {
285 Time time = content->position() + (content->audio_delay() * TIME_HZ / 1000) + relative_time;
288 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->frames()));
289 dcp_mapped->make_silent ();
290 list<pair<int, libdcp::Channel> > map = content->audio_mapping().content_to_dcp ();
291 for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) {
292 if (i->first < audio->channels() && i->second < dcp_mapped->channels()) {
293 dcp_mapped->accumulate_channel (audio.get(), i->first, i->second);
299 /* We must cut off anything that comes before the start of all time */
301 int const frames = - time * _film->audio_frame_rate() / TIME_HZ;
302 if (frames >= audio->frames ()) {
306 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->channels(), audio->frames() - frames));
307 trimmed->copy_from (audio.get(), audio->frames() - frames, frames, 0);
313 _audio_merger.push (audio, time);
314 piece->audio_position += _film->audio_frames_to_time (audio->frames ());
320 TimedAudioBuffers<Time> tb = _audio_merger.flush ();
322 Audio (tb.audio, tb.time);
323 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
326 while (_video_position < _audio_position) {
330 while (_audio_position < _video_position) {
331 emit_silence (_film->time_to_audio_frames (_video_position - _audio_position));
336 /** Seek so that the next pass() will yield (approximately) the requested frame.
337 * Pass accurate = true to try harder to get close to the request.
338 * @return true on error
341 Player::seek (Time t, bool accurate)
343 if (!_have_valid_pieces) {
345 _have_valid_pieces = true;
348 if (_pieces.empty ()) {
352 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
353 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content);
358 Time s = t - vc->position ();
359 s = max (static_cast<Time> (0), s);
360 s = min (vc->length_after_trim(), s);
362 (*i)->video_position = (*i)->audio_position = vc->position() + s;
364 FrameRateConversion frc (vc->video_frame_rate(), _film->video_frame_rate());
365 /* Here we are converting from time (in the DCP) to a frame number in the content.
366 Hence we need to use the DCP's frame rate and the double/skip correction, not
369 VideoContent::Frame f = (s + vc->trim_start ()) * _film->video_frame_rate() / (frc.factor() * TIME_HZ);
370 dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (f, accurate);
373 _video_position = _audio_position = t;
375 /* XXX: don't seek audio because we don't need to... */
379 Player::setup_pieces ()
381 list<shared_ptr<Piece> > old_pieces = _pieces;
385 ContentList content = _playlist->content ();
386 sort (content.begin(), content.end(), ContentSorter ());
388 for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
390 shared_ptr<Piece> piece (new Piece (*i));
392 /* XXX: into content? */
394 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
396 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
398 fd->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4));
399 fd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
400 fd->Subtitle.connect (bind (&Player::process_subtitle, this, piece, _1, _2, _3, _4));
405 shared_ptr<const StillImageContent> ic = dynamic_pointer_cast<const StillImageContent> (*i);
407 shared_ptr<StillImageDecoder> id;
409 /* See if we can re-use an old StillImageDecoder */
410 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
411 shared_ptr<StillImageDecoder> imd = dynamic_pointer_cast<StillImageDecoder> ((*j)->decoder);
412 if (imd && imd->content() == ic) {
418 id.reset (new StillImageDecoder (_film, ic));
419 id->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4));
425 shared_ptr<const MovingImageContent> mc = dynamic_pointer_cast<const MovingImageContent> (*i);
427 shared_ptr<MovingImageDecoder> md;
430 md.reset (new MovingImageDecoder (_film, mc));
431 md->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4));
437 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
439 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
440 sd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
445 _pieces.push_back (piece);
450 Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
452 shared_ptr<Content> c = w.lock ();
458 property == ContentProperty::POSITION || property == ContentProperty::LENGTH ||
459 property == ContentProperty::TRIM_START || property == ContentProperty::TRIM_END
462 _have_valid_pieces = false;
465 } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET || property == SubtitleContentProperty::SUBTITLE_SCALE) {
471 property == VideoContentProperty::VIDEO_FRAME_TYPE || property == VideoContentProperty::VIDEO_CROP ||
472 property == VideoContentProperty::VIDEO_RATIO
480 Player::playlist_changed ()
482 _have_valid_pieces = false;
487 Player::set_video_container_size (libdcp::Size s)
489 _video_container_size = s;
490 _black_frame.reset (new Image (PIX_FMT_RGB24, _video_container_size, true));
491 _black_frame->make_black ();
494 shared_ptr<Resampler>
495 Player::resampler (shared_ptr<AudioContent> c, bool create)
497 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
498 if (i != _resamplers.end ()) {
503 return shared_ptr<Resampler> ();
506 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
512 Player::emit_black ()
514 #ifdef DCPOMATIC_DEBUG
515 _last_video.reset ();
518 Video (_black_frame, EYES_BOTH, ColourConversion(), _last_emit_was_black, _video_position);
519 _video_position += _film->video_frames_to_time (1);
520 _last_emit_was_black = true;
524 Player::emit_silence (OutputAudioFrame most)
530 OutputAudioFrame N = min (most, _film->audio_frame_rate() / 2);
531 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), N));
532 silence->make_silent ();
533 Audio (silence, _audio_position);
534 _audio_position += _film->audio_frames_to_time (N);
538 Player::film_changed (Film::Property p)
540 /* Here we should notice Film properties that affect our output, and
541 alert listeners that our output now would be different to how it was
542 last time we were run.
545 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER) {
551 Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
553 _in_subtitle.piece = weak_piece;
554 _in_subtitle.image = image;
555 _in_subtitle.rect = rect;
556 _in_subtitle.from = from;
557 _in_subtitle.to = to;
563 Player::update_subtitle ()
565 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
570 if (!_in_subtitle.image) {
571 _out_subtitle.image.reset ();
575 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
578 dcpomatic::Rect<double> in_rect = _in_subtitle.rect;
579 libdcp::Size scaled_size;
581 in_rect.y += sc->subtitle_offset ();
583 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
584 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
585 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
587 /* Then we need a corrective translation, consisting of two parts:
589 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
590 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
592 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
593 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
594 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
596 * Combining these two translations gives these expressions.
599 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
600 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
602 _out_subtitle.image = _in_subtitle.image->scale (
604 Scaler::from_id ("bicubic"),
605 _in_subtitle.image->pixel_format (),
608 _out_subtitle.from = _in_subtitle.from + piece->content->position ();
609 _out_subtitle.to = _in_subtitle.to + piece->content->position ();