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->start ())
59 , audio_position (c->start ())
62 Piece (shared_ptr<Content> c, shared_ptr<Decoder> d)
65 , video_position (c->start ())
66 , audio_position (c->start ())
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->start() << " 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.connect (bind (&Player::playlist_changed, this));
104 _playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2, _3));
105 _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 shared_ptr<Image> work_image = image->crop (content->crop(), true);
253 libdcp::Size const image_size = content->ratio()->size (_video_container_size);
255 work_image = work_image->scale_and_convert_to_rgb (image_size, _film->scaler(), true);
257 Time time = content->start() + (frame * frc.factor() * TIME_HZ / _film->video_frame_rate());
259 if (_film->with_subtitles () && _out_subtitle.image && time >= _out_subtitle.from && time <= _out_subtitle.to) {
260 work_image->alpha_blend (_out_subtitle.image, _out_subtitle.position);
263 if (image_size != _video_container_size) {
264 assert (image_size.width <= _video_container_size.width);
265 assert (image_size.height <= _video_container_size.height);
266 shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
268 im->copy (work_image, Position<int> ((_video_container_size.width - image_size.width) / 2, (_video_container_size.height - image_size.height) / 2));
272 #ifdef DCPOMATIC_DEBUG
273 _last_video = piece->content;
276 Video (work_image, eyes, same, time);
277 time += TIME_HZ / _film->video_frame_rate();
280 Video (work_image, eyes, true, time);
281 time += TIME_HZ / _film->video_frame_rate();
284 _last_emit_was_black = false;
286 _video_position = piece->video_position = time;
290 Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers> audio, AudioContent::Frame frame)
292 shared_ptr<Piece> piece = weak_piece.lock ();
297 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
301 if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) {
302 shared_ptr<Resampler> r = resampler (content, true);
303 pair<shared_ptr<const AudioBuffers>, AudioContent::Frame> ro = r->run (audio, frame);
309 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->frames()));
310 dcp_mapped->make_silent ();
311 list<pair<int, libdcp::Channel> > map = content->audio_mapping().content_to_dcp ();
312 for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) {
313 if (i->first < audio->channels() && i->second < dcp_mapped->channels()) {
314 dcp_mapped->accumulate_channel (audio.get(), i->first, i->second);
320 Time time = content->start()
321 + _film->audio_frames_to_time (frame)
322 + (content->audio_delay() * TIME_HZ / 1000);
324 /* We must cut off anything that comes before the start of all time */
326 int const frames = - time * _film->audio_frame_rate() / TIME_HZ;
327 if (frames >= audio->frames ()) {
331 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->channels(), audio->frames() - frames));
332 trimmed->copy_from (audio.get(), audio->frames() - frames, frames, 0);
338 _audio_merger.push (audio, time);
339 piece->audio_position += _film->audio_frames_to_time (audio->frames ());
345 TimedAudioBuffers<Time> tb = _audio_merger.flush ();
347 Audio (tb.audio, tb.time);
348 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
351 while (_video_position < _audio_position) {
355 while (_audio_position < _video_position) {
356 emit_silence (_film->time_to_audio_frames (_video_position - _audio_position));
361 /** Seek so that the next pass() will yield (approximately) the requested frame.
362 * Pass accurate = true to try harder to get close to the request.
363 * @return true on error
366 Player::seek (Time t, bool accurate)
368 if (!_have_valid_pieces) {
370 _have_valid_pieces = true;
373 if (_pieces.empty ()) {
377 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
378 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content);
383 Time s = t - vc->start ();
384 s = max (static_cast<Time> (0), s);
385 s = min (vc->length(), s);
387 (*i)->video_position = (*i)->audio_position = vc->start() + s;
389 FrameRateConversion frc (vc->video_frame_rate(), _film->video_frame_rate());
390 /* Here we are converting from time (in the DCP) to a frame number in the content.
391 Hence we need to use the DCP's frame rate and the double/skip correction, not
394 VideoContent::Frame f = s * _film->video_frame_rate() / (frc.factor() * TIME_HZ);
395 dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (f, accurate);
398 _video_position = _audio_position = t;
400 /* XXX: don't seek audio because we don't need to... */
404 Player::setup_pieces ()
406 list<shared_ptr<Piece> > old_pieces = _pieces;
410 ContentList content = _playlist->content ();
411 sort (content.begin(), content.end(), ContentSorter ());
413 for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
415 shared_ptr<Piece> piece (new Piece (*i));
417 /* XXX: into content? */
419 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
421 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
423 fd->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4));
424 fd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
425 fd->Subtitle.connect (bind (&Player::process_subtitle, this, piece, _1, _2, _3, _4));
430 shared_ptr<const StillImageContent> ic = dynamic_pointer_cast<const StillImageContent> (*i);
432 shared_ptr<StillImageDecoder> id;
434 /* See if we can re-use an old StillImageDecoder */
435 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
436 shared_ptr<StillImageDecoder> imd = dynamic_pointer_cast<StillImageDecoder> ((*j)->decoder);
437 if (imd && imd->content() == ic) {
443 id.reset (new StillImageDecoder (_film, ic));
444 id->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4));
450 shared_ptr<const MovingImageContent> mc = dynamic_pointer_cast<const MovingImageContent> (*i);
452 shared_ptr<MovingImageDecoder> md;
455 md.reset (new MovingImageDecoder (_film, mc));
456 md->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4));
462 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
464 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
465 sd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
470 _pieces.push_back (piece);
474 cout << "=== Player setup:\n";
475 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
476 cout << *(i->get()) << "\n";
482 Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
484 shared_ptr<Content> c = w.lock ();
490 property == ContentProperty::START || property == ContentProperty::LENGTH ||
491 property == VideoContentProperty::VIDEO_CROP || property == VideoContentProperty::VIDEO_RATIO
494 _have_valid_pieces = false;
497 } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET || property == SubtitleContentProperty::SUBTITLE_SCALE) {
500 } else if (property == VideoContentProperty::VIDEO_FRAME_TYPE) {
506 Player::playlist_changed ()
508 _have_valid_pieces = false;
513 Player::set_video_container_size (libdcp::Size s)
515 _video_container_size = s;
516 _black_frame.reset (new Image (PIX_FMT_RGB24, _video_container_size, true));
517 _black_frame->make_black ();
520 shared_ptr<Resampler>
521 Player::resampler (shared_ptr<AudioContent> c, bool create)
523 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
524 if (i != _resamplers.end ()) {
529 return shared_ptr<Resampler> ();
532 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
538 Player::emit_black ()
540 #ifdef DCPOMATIC_DEBUG
541 _last_video.reset ();
544 Video (_black_frame, EYES_BOTH, _last_emit_was_black, _video_position);
545 _video_position += _film->video_frames_to_time (1);
546 _last_emit_was_black = true;
550 Player::emit_silence (OutputAudioFrame most)
552 OutputAudioFrame N = min (most, _film->audio_frame_rate() / 2);
553 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), N));
554 silence->make_silent ();
555 Audio (silence, _audio_position);
556 _audio_position += _film->audio_frames_to_time (N);
560 Player::film_changed (Film::Property p)
562 /* Here we should notice Film properties that affect our output, and
563 alert listeners that our output now would be different to how it was
564 last time we were run.
567 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER) {
573 Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
575 _in_subtitle.piece = weak_piece;
576 _in_subtitle.image = image;
577 _in_subtitle.rect = rect;
578 _in_subtitle.from = from;
579 _in_subtitle.to = to;
585 Player::update_subtitle ()
587 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
592 if (!_in_subtitle.image) {
593 _out_subtitle.image.reset ();
597 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
600 dcpomatic::Rect<double> in_rect = _in_subtitle.rect;
601 libdcp::Size scaled_size;
603 in_rect.y += sc->subtitle_offset ();
605 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
606 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
607 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
609 /* Then we need a corrective translation, consisting of two parts:
611 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
612 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
614 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
615 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
616 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
618 * Combining these two translations gives these expressions.
621 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
622 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
624 _out_subtitle.image = _in_subtitle.image->scale (libdcp::Size (scaled_size.width, scaled_size.height), Scaler::from_id ("bicubic"), true);
625 _out_subtitle.from = _in_subtitle.from + piece->content->start ();
626 _out_subtitle.to = _in_subtitle.to + piece->content->start ();