2 Copyright (C) 2013-2014 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 "image_decoder.h"
26 #include "image_content.h"
27 #include "sndfile_decoder.h"
28 #include "sndfile_content.h"
29 #include "subtitle_content.h"
34 #include "resampler.h"
37 #include "player_video_frame.h"
46 using boost::shared_ptr;
47 using boost::weak_ptr;
48 using boost::dynamic_pointer_cast;
50 Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
55 , _have_valid_pieces (false)
58 , _audio_merger (f->audio_channels(), bind (&Film::time_to_audio_frames, f.get(), _1), bind (&Film::audio_frames_to_time, f.get(), _1))
59 , _last_emit_was_black (false)
61 _playlist_changed_connection = _playlist->Changed.connect (bind (&Player::playlist_changed, this));
62 _playlist_content_changed_connection = _playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2, _3));
63 _film_changed_connection = _film->Changed.connect (bind (&Player::film_changed, this, _1));
64 set_video_container_size (_film->frame_size ());
68 Player::disable_video ()
74 Player::disable_audio ()
82 if (!_have_valid_pieces) {
86 Time earliest_t = TIME_MAX;
87 shared_ptr<Piece> earliest;
93 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
94 if ((*i)->decoder->done ()) {
98 shared_ptr<VideoDecoder> vd = dynamic_pointer_cast<VideoDecoder> ((*i)->decoder);
99 shared_ptr<AudioDecoder> ad = dynamic_pointer_cast<AudioDecoder> ((*i)->decoder);
102 if ((*i)->video_position < earliest_t) {
103 earliest_t = (*i)->video_position;
109 if (_audio && ad && ad->has_audio ()) {
110 if ((*i)->audio_position < earliest_t) {
111 earliest_t = (*i)->audio_position;
125 if (earliest_t > _video_position) {
128 if (earliest->repeating ()) {
129 earliest->repeat (this);
131 earliest->decoder->pass ();
137 if (earliest_t > _audio_position) {
138 emit_silence (_film->time_to_audio_frames (earliest_t - _audio_position));
140 earliest->decoder->pass ();
142 if (earliest->decoder->done()) {
143 shared_ptr<AudioContent> ac = dynamic_pointer_cast<AudioContent> (earliest->content);
145 shared_ptr<Resampler> re = resampler (ac, false);
147 shared_ptr<const AudioBuffers> b = re->flush ();
149 process_audio (earliest, b, ac->audio_length ());
158 boost::optional<Time> audio_done_up_to;
159 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
160 if ((*i)->decoder->done ()) {
164 shared_ptr<AudioDecoder> ad = dynamic_pointer_cast<AudioDecoder> ((*i)->decoder);
165 if (ad && ad->has_audio ()) {
166 audio_done_up_to = min (audio_done_up_to.get_value_or (TIME_MAX), (*i)->audio_position);
170 if (audio_done_up_to) {
171 TimedAudioBuffers<Time> tb = _audio_merger.pull (audio_done_up_to.get ());
172 Audio (tb.audio, tb.time);
173 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
180 /** @param extra Amount of extra time to add to the content frame's time (for repeat) */
182 Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image, Eyes eyes, bool same, VideoContent::Frame frame, Time extra)
184 /* Keep a note of what came in so that we can repeat it if required */
185 _last_incoming_video.weak_piece = weak_piece;
186 _last_incoming_video.image = image;
187 _last_incoming_video.eyes = eyes;
188 _last_incoming_video.same = same;
189 _last_incoming_video.frame = frame;
190 _last_incoming_video.extra = extra;
192 shared_ptr<Piece> piece = weak_piece.lock ();
197 shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
200 FrameRateConversion frc (content->video_frame_rate(), _film->video_frame_rate());
201 if (frc.skip && (frame % 2) == 1) {
205 Time const relative_time = (frame * frc.factor() * TIME_HZ / _film->video_frame_rate());
206 if (content->trimmed (relative_time)) {
210 Time const time = content->position() + relative_time + extra - content->trim_start ();
211 libdcp::Size const image_size = content->scale().size (content, _video_container_size, _film->frame_size ());
213 shared_ptr<PlayerVideoFrame> pi (
214 new PlayerVideoFrame (
218 _video_container_size,
223 if (_film->with_subtitles ()) {
224 for (list<Subtitle>::const_iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) {
225 if (i->covers (time)) {
226 /* This may be true for more than one of _subtitles, but the last (latest-starting)
227 one is the one we want to use, so that's ok.
229 Position<int> const container_offset (
230 (_video_container_size.width - image_size.width) / 2,
231 (_video_container_size.height - image_size.width) / 2
234 pi->set_subtitle (i->out_image(), i->out_position() + container_offset);
239 /* Clear out old subtitles */
240 for (list<Subtitle>::iterator i = _subtitles.begin(); i != _subtitles.end(); ) {
241 list<Subtitle>::iterator j = i;
244 if (i->ends_before (time)) {
245 _subtitles.erase (i);
251 #ifdef DCPOMATIC_DEBUG
252 _last_video = piece->content;
255 Video (pi, eyes, content->colour_conversion(), same, time);
257 _last_emit_was_black = false;
258 _video_position = piece->video_position = (time + TIME_HZ / _film->video_frame_rate());
260 if (frc.repeat > 1 && !piece->repeating ()) {
261 piece->set_repeat (_last_incoming_video, frc.repeat - 1);
266 Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers> audio, AudioContent::Frame frame)
268 shared_ptr<Piece> piece = weak_piece.lock ();
273 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
277 if (content->audio_gain() != 0) {
278 shared_ptr<AudioBuffers> gain (new AudioBuffers (audio));
279 gain->apply_gain (content->audio_gain ());
284 if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) {
285 shared_ptr<Resampler> r = resampler (content, true);
286 pair<shared_ptr<const AudioBuffers>, AudioContent::Frame> ro = r->run (audio, frame);
291 Time const relative_time = _film->audio_frames_to_time (frame);
293 if (content->trimmed (relative_time)) {
297 Time time = content->position() + (content->audio_delay() * TIME_HZ / 1000) + relative_time - content->trim_start ();
300 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->frames()));
301 dcp_mapped->make_silent ();
303 AudioMapping map = content->audio_mapping ();
304 for (int i = 0; i < map.content_channels(); ++i) {
305 for (int j = 0; j < _film->audio_channels(); ++j) {
306 if (map.get (i, static_cast<libdcp::Channel> (j)) > 0) {
307 dcp_mapped->accumulate_channel (
310 static_cast<libdcp::Channel> (j),
311 map.get (i, static_cast<libdcp::Channel> (j))
319 /* We must cut off anything that comes before the start of all time */
321 int const frames = - time * _film->audio_frame_rate() / TIME_HZ;
322 if (frames >= audio->frames ()) {
326 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->channels(), audio->frames() - frames));
327 trimmed->copy_from (audio.get(), audio->frames() - frames, frames, 0);
333 _audio_merger.push (audio, time);
334 piece->audio_position += _film->audio_frames_to_time (audio->frames ());
340 TimedAudioBuffers<Time> tb = _audio_merger.flush ();
341 if (_audio && tb.audio) {
342 Audio (tb.audio, tb.time);
343 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
346 while (_video && _video_position < _audio_position) {
350 while (_audio && _audio_position < _video_position) {
351 emit_silence (_film->time_to_audio_frames (_video_position - _audio_position));
356 /** Seek so that the next pass() will yield (approximately) the requested frame.
357 * Pass accurate = true to try harder to get close to the request.
358 * @return true on error
361 Player::seek (Time t, bool accurate)
363 if (!_have_valid_pieces) {
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 /* s is the offset of t from the start position of this content */
378 Time s = t - vc->position ();
379 s = max (static_cast<Time> (0), s);
380 s = min (vc->length_after_trim(), s);
382 /* Hence set the piece positions to the `global' time */
383 (*i)->video_position = (*i)->audio_position = vc->position() + s;
385 /* And seek the decoder */
386 dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (
387 vc->time_to_content_video_frames (s + vc->trim_start ()), accurate
390 (*i)->reset_repeat ();
393 _video_position = _audio_position = t;
395 /* XXX: don't seek audio because we don't need to... */
399 Player::setup_pieces ()
401 list<shared_ptr<Piece> > old_pieces = _pieces;
405 ContentList content = _playlist->content ();
406 sort (content.begin(), content.end(), ContentSorter ());
408 for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
410 if (!(*i)->paths_valid ()) {
414 shared_ptr<Piece> piece (new Piece (*i));
416 /* XXX: into content? */
418 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
420 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
422 fd->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, 0));
423 fd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
424 fd->Subtitle.connect (bind (&Player::process_subtitle, this, weak_ptr<Piece> (piece), _1, _2, _3, _4));
426 fd->seek (fc->time_to_content_video_frames (fc->trim_start ()), true);
430 shared_ptr<const ImageContent> ic = dynamic_pointer_cast<const ImageContent> (*i);
432 bool reusing = false;
434 /* See if we can re-use an old ImageDecoder */
435 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
436 shared_ptr<ImageDecoder> imd = dynamic_pointer_cast<ImageDecoder> ((*j)->decoder);
437 if (imd && imd->content() == ic) {
444 shared_ptr<ImageDecoder> id (new ImageDecoder (_film, ic));
445 id->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, 0));
450 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
452 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
453 sd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
458 _pieces.push_back (piece);
461 _have_valid_pieces = true;
465 Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
467 shared_ptr<Content> c = w.lock ();
473 property == ContentProperty::POSITION || property == ContentProperty::LENGTH ||
474 property == ContentProperty::TRIM_START || property == ContentProperty::TRIM_END ||
475 property == VideoContentProperty::VIDEO_FRAME_TYPE
478 _have_valid_pieces = false;
482 property == SubtitleContentProperty::SUBTITLE_X_OFFSET ||
483 property == SubtitleContentProperty::SUBTITLE_Y_OFFSET ||
484 property == SubtitleContentProperty::SUBTITLE_SCALE
487 for (list<Subtitle>::iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) {
488 i->update (_film, _video_container_size);
494 property == VideoContentProperty::VIDEO_CROP || property == VideoContentProperty::VIDEO_SCALE ||
495 property == VideoContentProperty::VIDEO_FRAME_RATE
500 } else if (property == ContentProperty::PATH) {
502 _have_valid_pieces = false;
508 Player::playlist_changed ()
510 _have_valid_pieces = false;
515 Player::set_video_container_size (libdcp::Size s)
517 _video_container_size = s;
519 shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
523 new PlayerVideoFrame (
526 _video_container_size,
527 _video_container_size,
528 Scaler::from_id ("bicubic")
533 shared_ptr<Resampler>
534 Player::resampler (shared_ptr<AudioContent> c, bool create)
536 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
537 if (i != _resamplers.end ()) {
542 return shared_ptr<Resampler> ();
547 "Creating new resampler for %1 to %2 with %3 channels", c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()
551 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
557 Player::emit_black ()
559 #ifdef DCPOMATIC_DEBUG
560 _last_video.reset ();
563 Video (_black_frame, EYES_BOTH, ColourConversion(), _last_emit_was_black, _video_position);
564 _video_position += _film->video_frames_to_time (1);
565 _last_emit_was_black = true;
569 Player::emit_silence (OutputAudioFrame most)
575 OutputAudioFrame N = min (most, _film->audio_frame_rate() / 2);
576 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), N));
577 silence->make_silent ();
578 Audio (silence, _audio_position);
579 _audio_position += _film->audio_frames_to_time (N);
583 Player::film_changed (Film::Property p)
585 /* Here we should notice Film properties that affect our output, and
586 alert listeners that our output now would be different to how it was
587 last time we were run.
590 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER || p == Film::VIDEO_FRAME_RATE) {
596 Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
599 /* A null image means that we should stop any current subtitles at `from' */
600 for (list<Subtitle>::iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) {
604 _subtitles.push_back (Subtitle (_film, _video_container_size, weak_piece, image, rect, from, to));
608 /** Re-emit the last frame that was emitted, using current settings for crop, ratio, scaler and subtitles.
609 * @return false if this could not be done.
612 Player::repeat_last_video ()
614 if (!_last_incoming_video.image || !_have_valid_pieces) {
619 _last_incoming_video.weak_piece,
620 _last_incoming_video.image,
621 _last_incoming_video.eyes,
622 _last_incoming_video.same,
623 _last_incoming_video.frame,
624 _last_incoming_video.extra