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->dcp_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 ();
199 cout << "\tpost pass " << _video_position << " " << _audio_position << "\n";
206 Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image, Eyes eyes, bool same, VideoContent::Frame frame)
208 shared_ptr<Piece> piece = weak_piece.lock ();
213 shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
216 FrameRateConversion frc (content->video_frame_rate(), _film->dcp_video_frame_rate());
217 if (frc.skip && (frame % 2) == 1) {
221 shared_ptr<Image> work_image = image->crop (content->crop(), true);
223 libdcp::Size const image_size = content->ratio()->size (_video_container_size);
225 work_image = work_image->scale_and_convert_to_rgb (image_size, _film->scaler(), true);
227 Time time = content->start() + (frame * frc.factor() * TIME_HZ / _film->dcp_video_frame_rate());
229 if (_film->with_subtitles () && _out_subtitle.image && time >= _out_subtitle.from && time <= _out_subtitle.to) {
230 work_image->alpha_blend (_out_subtitle.image, _out_subtitle.position);
233 if (image_size != _video_container_size) {
234 assert (image_size.width <= _video_container_size.width);
235 assert (image_size.height <= _video_container_size.height);
236 shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
238 im->copy (work_image, Position<int> ((_video_container_size.width - image_size.width) / 2, (_video_container_size.height - image_size.height) / 2));
242 #ifdef DCPOMATIC_DEBUG
243 _last_video = piece->content;
246 Video (work_image, eyes, same, time);
247 time += TIME_HZ / _film->dcp_video_frame_rate();
250 Video (work_image, eyes, true, time);
251 time += TIME_HZ / _film->dcp_video_frame_rate();
254 _video_position = piece->video_position = time;
258 Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers> audio, AudioContent::Frame frame)
260 shared_ptr<Piece> piece = weak_piece.lock ();
265 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
269 if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) {
270 shared_ptr<Resampler> r = resampler (content);
271 audio = r->run (audio);
275 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->dcp_audio_channels(), audio->frames()));
276 dcp_mapped->make_silent ();
277 list<pair<int, libdcp::Channel> > map = content->audio_mapping().content_to_dcp ();
278 for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) {
279 if (i->first < audio->channels() && i->second < dcp_mapped->channels()) {
280 dcp_mapped->accumulate_channel (audio.get(), i->first, i->second);
286 Time time = content->start() + (frame * TIME_HZ / _film->dcp_audio_frame_rate()) + (content->audio_delay() * TIME_HZ / 1000);
288 /* We must cut off anything that comes before the start of all time */
290 int const frames = - time * _film->dcp_audio_frame_rate() / TIME_HZ;
291 if (frames >= audio->frames ()) {
295 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->channels(), audio->frames() - frames));
296 trimmed->copy_from (audio.get(), audio->frames() - frames, frames, 0);
302 /* The time of this audio may indicate that some of our buffered audio is not going to
303 be added to any more, so it can be emitted.
306 if (time > _audio_position) {
307 /* We can emit some audio from our buffers */
308 OutputAudioFrame const N = _film->time_to_audio_frames (time - _audio_position);
309 if (N > _audio_buffers.frames()) {
310 /* We need some extra silence before whatever is in the buffers */
311 _audio_buffers.ensure_size (N);
312 _audio_buffers.move (0, N - _audio_buffers.frames(), _audio_buffers.frames ());
313 _audio_buffers.make_silent (0, _audio_buffers.frames());
314 _audio_buffers.set_frames (N);
316 assert (N <= _audio_buffers.frames());
317 shared_ptr<AudioBuffers> emit (new AudioBuffers (_audio_buffers.channels(), N));
318 emit->copy_from (&_audio_buffers, N, 0, 0);
319 Audio (emit, _audio_position);
320 _audio_position = piece->audio_position = time + _film->audio_frames_to_time (N);
322 /* And remove it from our buffers */
323 if (_audio_buffers.frames() > N) {
324 _audio_buffers.move (N, 0, _audio_buffers.frames() - N);
326 _audio_buffers.set_frames (_audio_buffers.frames() - N);
329 /* Now accumulate the new audio into our buffers */
330 _audio_buffers.ensure_size (_audio_buffers.frames() + audio->frames());
331 _audio_buffers.accumulate_frames (audio.get(), 0, 0, audio->frames ());
332 _audio_buffers.set_frames (_audio_buffers.frames() + audio->frames());
338 if (_audio_buffers.frames() > 0) {
339 shared_ptr<AudioBuffers> emit (new AudioBuffers (_audio_buffers.channels(), _audio_buffers.frames()));
340 emit->copy_from (&_audio_buffers, _audio_buffers.frames(), 0, 0);
341 Audio (emit, _audio_position);
342 _audio_position += _film->audio_frames_to_time (_audio_buffers.frames ());
343 _audio_buffers.set_frames (0);
346 while (_video_position < _audio_position) {
350 while (_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) {
365 _have_valid_pieces = true;
368 if (_pieces.empty ()) {
372 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
373 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content);
378 Time s = t - vc->start ();
379 s = max (static_cast<Time> (0), s);
380 s = min (vc->length(), s);
382 (*i)->video_position = (*i)->audio_position = vc->start() + s;
384 FrameRateConversion frc (vc->video_frame_rate(), _film->dcp_video_frame_rate());
385 /* Here we are converting from time (in the DCP) to a frame number in the content.
386 Hence we need to use the DCP's frame rate and the double/skip correction, not
389 VideoContent::Frame f = s * _film->dcp_video_frame_rate() / (frc.factor() * TIME_HZ);
390 dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (f, accurate);
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 shared_ptr<Piece> piece (new Piece (*i));
412 /* XXX: into content? */
414 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
416 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
418 fd->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4));
419 fd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
420 fd->Subtitle.connect (bind (&Player::process_subtitle, this, piece, _1, _2, _3, _4));
425 shared_ptr<const StillImageContent> ic = dynamic_pointer_cast<const StillImageContent> (*i);
427 shared_ptr<StillImageDecoder> id;
429 /* See if we can re-use an old StillImageDecoder */
430 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
431 shared_ptr<StillImageDecoder> imd = dynamic_pointer_cast<StillImageDecoder> ((*j)->decoder);
432 if (imd && imd->content() == ic) {
438 id.reset (new StillImageDecoder (_film, ic));
439 id->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4));
445 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
447 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
448 sd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
453 _pieces.push_back (piece);
457 cout << "=== Player setup:\n";
458 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
459 cout << *(i->get()) << "\n";
465 Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
467 shared_ptr<Content> c = w.lock ();
473 property == ContentProperty::START || property == ContentProperty::LENGTH ||
474 property == VideoContentProperty::VIDEO_CROP || property == VideoContentProperty::VIDEO_RATIO
477 _have_valid_pieces = false;
480 } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET || property == SubtitleContentProperty::SUBTITLE_SCALE) {
483 } else if (property == VideoContentProperty::VIDEO_FRAME_TYPE) {
484 cout << "vft change.\n";
490 Player::playlist_changed ()
492 _have_valid_pieces = false;
497 Player::set_video_container_size (libdcp::Size s)
499 _video_container_size = s;
500 _black_frame.reset (new Image (PIX_FMT_RGB24, _video_container_size, true));
501 _black_frame->make_black ();
504 shared_ptr<Resampler>
505 Player::resampler (shared_ptr<AudioContent> c)
507 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
508 if (i != _resamplers.end ()) {
512 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
518 Player::emit_black ()
520 #ifdef DCPOMATIC_DEBUG
521 _last_video.reset ();
524 /* XXX: use same here */
525 Video (_black_frame, EYES_BOTH, false, _video_position);
526 _video_position += _film->video_frames_to_time (1);
530 Player::emit_silence (OutputAudioFrame most)
532 OutputAudioFrame N = min (most, _film->dcp_audio_frame_rate() / 2);
533 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->dcp_audio_channels(), N));
534 silence->make_silent ();
535 Audio (silence, _audio_position);
536 _audio_position += _film->audio_frames_to_time (N);
540 Player::film_changed (Film::Property p)
542 /* Here we should notice Film properties that affect our output, and
543 alert listeners that our output now would be different to how it was
544 last time we were run.
547 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER) {
553 Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
555 _in_subtitle.piece = weak_piece;
556 _in_subtitle.image = image;
557 _in_subtitle.rect = rect;
558 _in_subtitle.from = from;
559 _in_subtitle.to = to;
565 Player::update_subtitle ()
567 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
572 if (!_in_subtitle.image) {
573 _out_subtitle.image.reset ();
577 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
580 dcpomatic::Rect<double> in_rect = _in_subtitle.rect;
581 libdcp::Size scaled_size;
583 in_rect.y += sc->subtitle_offset ();
585 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
586 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
587 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
589 /* Then we need a corrective translation, consisting of two parts:
591 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
592 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
594 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
595 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
596 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
598 * Combining these two translations gives these expressions.
601 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
602 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
604 _out_subtitle.image = _in_subtitle.image->scale (libdcp::Size (scaled_size.width, scaled_size.height), Scaler::from_id ("bicubic"), true);
605 _out_subtitle.from = _in_subtitle.from + piece->content->start ();
606 _out_subtitle.to = _in_subtitle.to + piece->content->start ();