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 "sndfile_decoder.h"
28 #include "sndfile_content.h"
29 #include "subtitle_content.h"
34 #include "resampler.h"
45 using boost::shared_ptr;
46 using boost::weak_ptr;
47 using boost::dynamic_pointer_cast;
49 //#define DEBUG_PLAYER 1
54 Piece (shared_ptr<Content> c)
56 , video_position (c->start ())
57 , audio_position (c->start ())
60 Piece (shared_ptr<Content> c, shared_ptr<Decoder> d)
63 , video_position (c->start ())
64 , audio_position (c->start ())
67 shared_ptr<Content> content;
68 shared_ptr<Decoder> decoder;
74 std::ostream& operator<<(std::ostream& s, Piece const & p)
76 if (dynamic_pointer_cast<FFmpegContent> (p.content)) {
78 } else if (dynamic_pointer_cast<StillImageContent> (p.content)) {
80 } else if (dynamic_pointer_cast<SndfileContent> (p.content)) {
84 s << " at " << p.content->start() << " until " << p.content->end();
90 Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
95 , _have_valid_pieces (false)
98 , _audio_buffers (f->audio_channels(), 0)
100 _playlist->Changed.connect (bind (&Player::playlist_changed, this));
101 _playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2, _3));
102 _film->Changed.connect (bind (&Player::film_changed, this, _1));
103 set_video_container_size (_film->container()->size (_film->full_frame ()));
107 Player::disable_video ()
113 Player::disable_audio ()
121 if (!_have_valid_pieces) {
123 _have_valid_pieces = true;
130 Time earliest_t = TIME_MAX;
131 shared_ptr<Piece> earliest;
137 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
138 if ((*i)->decoder->done ()) {
142 if (_video && dynamic_pointer_cast<VideoDecoder> ((*i)->decoder)) {
143 if ((*i)->video_position < earliest_t) {
144 earliest_t = (*i)->video_position;
150 if (_audio && dynamic_pointer_cast<AudioDecoder> ((*i)->decoder)) {
151 if ((*i)->audio_position < earliest_t) {
152 earliest_t = (*i)->audio_position;
161 cout << "no earliest piece.\n";
170 if (earliest_t > _video_position) {
172 cout << "no video here; emitting black frame (earliest=" << earliest_t << ", video_position=" << _video_position << ").\n";
177 cout << "Pass " << *earliest << "\n";
179 earliest->decoder->pass ();
184 if (earliest_t > _audio_position) {
186 cout << "no audio here; emitting silence.\n";
188 emit_silence (_film->time_to_audio_frames (earliest_t - _audio_position));
191 cout << "Pass " << *earliest << "\n";
193 earliest->decoder->pass ();
195 if (earliest->decoder->done()) {
196 shared_ptr<AudioContent> ac = dynamic_pointer_cast<AudioContent> (earliest->content);
198 shared_ptr<Resampler> re = resampler (ac, false);
200 shared_ptr<const AudioBuffers> b = re->flush ();
202 process_audio (earliest, b, ac->audio_length ());
211 cout << "\tpost pass " << _video_position << " " << _audio_position << "\n";
218 Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image, Eyes eyes, bool same, VideoContent::Frame frame)
220 shared_ptr<Piece> piece = weak_piece.lock ();
225 shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
228 FrameRateConversion frc (content->video_frame_rate(), _film->video_frame_rate());
229 if (frc.skip && (frame % 2) == 1) {
233 shared_ptr<Image> work_image = image->crop (content->crop(), true);
235 libdcp::Size const image_size = content->ratio()->size (_video_container_size);
237 work_image = work_image->scale_and_convert_to_rgb (image_size, _film->scaler(), true);
239 Time time = content->start() + (frame * frc.factor() * TIME_HZ / _film->video_frame_rate());
241 if (_film->with_subtitles () && _out_subtitle.image && time >= _out_subtitle.from && time <= _out_subtitle.to) {
242 work_image->alpha_blend (_out_subtitle.image, _out_subtitle.position);
245 if (image_size != _video_container_size) {
246 assert (image_size.width <= _video_container_size.width);
247 assert (image_size.height <= _video_container_size.height);
248 shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
250 im->copy (work_image, Position<int> ((_video_container_size.width - image_size.width) / 2, (_video_container_size.height - image_size.height) / 2));
254 #ifdef DCPOMATIC_DEBUG
255 _last_video = piece->content;
258 Video (work_image, eyes, same, time);
259 time += TIME_HZ / _film->video_frame_rate();
262 Video (work_image, eyes, true, time);
263 time += TIME_HZ / _film->video_frame_rate();
266 _video_position = piece->video_position = time;
270 Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers> audio, AudioContent::Frame frame)
272 shared_ptr<Piece> piece = weak_piece.lock ();
277 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
281 if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) {
282 shared_ptr<Resampler> r = resampler (content, true);
283 audio = r->run (audio);
287 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->frames()));
288 dcp_mapped->make_silent ();
289 list<pair<int, libdcp::Channel> > map = content->audio_mapping().content_to_dcp ();
290 for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) {
291 if (i->first < audio->channels() && i->second < dcp_mapped->channels()) {
292 dcp_mapped->accumulate_channel (audio.get(), i->first, i->second);
298 Time time = content->start() + (frame * TIME_HZ / _film->audio_frame_rate()) + (content->audio_delay() * TIME_HZ / 1000);
300 /* We must cut off anything that comes before the start of all time */
302 int const frames = - time * _film->audio_frame_rate() / TIME_HZ;
303 if (frames >= audio->frames ()) {
307 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->channels(), audio->frames() - frames));
308 trimmed->copy_from (audio.get(), audio->frames() - frames, frames, 0);
314 /* The time of this audio may indicate that some of our buffered audio is not going to
315 be added to any more, so it can be emitted.
318 if (time > _audio_position) {
319 /* We can emit some audio from our buffers */
320 OutputAudioFrame const N = _film->time_to_audio_frames (time - _audio_position);
321 if (N > _audio_buffers.frames()) {
322 /* We need some extra silence before whatever is in the buffers */
323 _audio_buffers.ensure_size (N);
324 _audio_buffers.move (0, N - _audio_buffers.frames(), _audio_buffers.frames ());
325 _audio_buffers.make_silent (0, _audio_buffers.frames());
326 _audio_buffers.set_frames (N);
328 assert (N <= _audio_buffers.frames());
329 shared_ptr<AudioBuffers> emit (new AudioBuffers (_audio_buffers.channels(), N));
330 emit->copy_from (&_audio_buffers, N, 0, 0);
331 Audio (emit, _audio_position);
332 _audio_position = piece->audio_position = time + _film->audio_frames_to_time (N);
334 /* And remove it from our buffers */
335 if (_audio_buffers.frames() > N) {
336 _audio_buffers.move (N, 0, _audio_buffers.frames() - N);
338 _audio_buffers.set_frames (_audio_buffers.frames() - N);
341 /* Now accumulate the new audio into our buffers */
342 _audio_buffers.ensure_size (_audio_buffers.frames() + audio->frames());
343 _audio_buffers.accumulate_frames (audio.get(), 0, 0, audio->frames ());
344 _audio_buffers.set_frames (_audio_buffers.frames() + audio->frames());
350 if (_audio_buffers.frames() > 0) {
351 shared_ptr<AudioBuffers> emit (new AudioBuffers (_audio_buffers.channels(), _audio_buffers.frames()));
352 emit->copy_from (&_audio_buffers, _audio_buffers.frames(), 0, 0);
353 Audio (emit, _audio_position);
354 _audio_position += _film->audio_frames_to_time (_audio_buffers.frames ());
355 _audio_buffers.set_frames (0);
358 while (_video_position < _audio_position) {
362 while (_audio_position < _video_position) {
363 emit_silence (_film->time_to_audio_frames (_video_position - _audio_position));
368 /** Seek so that the next pass() will yield (approximately) the requested frame.
369 * Pass accurate = true to try harder to get close to the request.
370 * @return true on error
373 Player::seek (Time t, bool accurate)
375 if (!_have_valid_pieces) {
377 _have_valid_pieces = true;
380 if (_pieces.empty ()) {
384 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
385 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content);
390 Time s = t - vc->start ();
391 s = max (static_cast<Time> (0), s);
392 s = min (vc->length(), s);
394 (*i)->video_position = (*i)->audio_position = vc->start() + s;
396 FrameRateConversion frc (vc->video_frame_rate(), _film->video_frame_rate());
397 /* Here we are converting from time (in the DCP) to a frame number in the content.
398 Hence we need to use the DCP's frame rate and the double/skip correction, not
401 VideoContent::Frame f = s * _film->video_frame_rate() / (frc.factor() * TIME_HZ);
402 dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (f, accurate);
405 _video_position = _audio_position = t;
407 /* XXX: don't seek audio because we don't need to... */
411 Player::setup_pieces ()
413 list<shared_ptr<Piece> > old_pieces = _pieces;
417 ContentList content = _playlist->content ();
418 sort (content.begin(), content.end(), ContentSorter ());
420 for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
422 shared_ptr<Piece> piece (new Piece (*i));
424 /* XXX: into content? */
426 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
428 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
430 fd->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4));
431 fd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
432 fd->Subtitle.connect (bind (&Player::process_subtitle, this, piece, _1, _2, _3, _4));
437 shared_ptr<const StillImageContent> ic = dynamic_pointer_cast<const StillImageContent> (*i);
439 shared_ptr<StillImageDecoder> id;
441 /* See if we can re-use an old StillImageDecoder */
442 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
443 shared_ptr<StillImageDecoder> imd = dynamic_pointer_cast<StillImageDecoder> ((*j)->decoder);
444 if (imd && imd->content() == ic) {
450 id.reset (new StillImageDecoder (_film, ic));
451 id->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4));
457 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
459 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
460 sd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
465 _pieces.push_back (piece);
469 cout << "=== Player setup:\n";
470 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
471 cout << *(i->get()) << "\n";
477 Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
479 shared_ptr<Content> c = w.lock ();
485 property == ContentProperty::START || property == ContentProperty::LENGTH ||
486 property == VideoContentProperty::VIDEO_CROP || property == VideoContentProperty::VIDEO_RATIO
489 _have_valid_pieces = false;
492 } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET || property == SubtitleContentProperty::SUBTITLE_SCALE) {
495 } else if (property == VideoContentProperty::VIDEO_FRAME_TYPE) {
501 Player::playlist_changed ()
503 _have_valid_pieces = false;
508 Player::set_video_container_size (libdcp::Size s)
510 _video_container_size = s;
511 _black_frame.reset (new Image (PIX_FMT_RGB24, _video_container_size, true));
512 _black_frame->make_black ();
515 shared_ptr<Resampler>
516 Player::resampler (shared_ptr<AudioContent> c, bool create)
518 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
519 if (i != _resamplers.end ()) {
524 return shared_ptr<Resampler> ();
527 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
533 Player::emit_black ()
535 #ifdef DCPOMATIC_DEBUG
536 _last_video.reset ();
539 /* XXX: use same here */
540 Video (_black_frame, EYES_BOTH, false, _video_position);
541 _video_position += _film->video_frames_to_time (1);
545 Player::emit_silence (OutputAudioFrame most)
547 OutputAudioFrame N = min (most, _film->audio_frame_rate() / 2);
548 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), N));
549 silence->make_silent ();
550 Audio (silence, _audio_position);
551 _audio_position += _film->audio_frames_to_time (N);
555 Player::film_changed (Film::Property p)
557 /* Here we should notice Film properties that affect our output, and
558 alert listeners that our output now would be different to how it was
559 last time we were run.
562 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER) {
568 Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
570 _in_subtitle.piece = weak_piece;
571 _in_subtitle.image = image;
572 _in_subtitle.rect = rect;
573 _in_subtitle.from = from;
574 _in_subtitle.to = to;
580 Player::update_subtitle ()
582 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
587 if (!_in_subtitle.image) {
588 _out_subtitle.image.reset ();
592 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
595 dcpomatic::Rect<double> in_rect = _in_subtitle.rect;
596 libdcp::Size scaled_size;
598 in_rect.y += sc->subtitle_offset ();
600 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
601 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
602 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
604 /* Then we need a corrective translation, consisting of two parts:
606 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
607 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
609 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
610 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
611 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
613 * Combining these two translations gives these expressions.
616 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
617 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
619 _out_subtitle.image = _in_subtitle.image->scale (libdcp::Size (scaled_size.width, scaled_size.height), Scaler::from_id ("bicubic"), true);
620 _out_subtitle.from = _in_subtitle.from + piece->content->start ();
621 _out_subtitle.to = _in_subtitle.to + piece->content->start ();