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 "imagemagick_decoder.h"
26 #include "imagemagick_content.h"
27 #include "sndfile_decoder.h"
28 #include "sndfile_content.h"
33 #include "resampler.h"
42 using boost::shared_ptr;
43 using boost::weak_ptr;
44 using boost::dynamic_pointer_cast;
46 #define DEBUG_PLAYER 1
51 Piece (shared_ptr<Content> c)
53 , video_position (c->start ())
54 , audio_position (c->start ())
57 Piece (shared_ptr<Content> c, shared_ptr<Decoder> d)
60 , video_position (c->start ())
61 , audio_position (c->start ())
64 shared_ptr<Content> content;
65 shared_ptr<Decoder> decoder;
71 std::ostream& operator<<(std::ostream& s, Piece const & p)
73 if (dynamic_pointer_cast<FFmpegContent> (p.content)) {
75 } else if (dynamic_pointer_cast<ImageMagickContent> (p.content)) {
77 } else if (dynamic_pointer_cast<SndfileContent> (p.content)) {
81 s << " at " << p.content->start() << " until " << p.content->end();
87 Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
92 , _have_valid_pieces (false)
95 , _audio_buffers (f->dcp_audio_channels(), 0)
97 _playlist->Changed.connect (bind (&Player::playlist_changed, this));
98 _playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2));
99 _film->Changed.connect (bind (&Player::film_changed, this, _1));
100 set_video_container_size (_film->container()->size (_film->full_frame ()));
104 Player::disable_video ()
110 Player::disable_audio ()
118 if (!_have_valid_pieces) {
120 _have_valid_pieces = true;
124 cout << "= PASS " << this << "\n";
127 Time earliest_t = TIME_MAX;
128 shared_ptr<Piece> earliest;
134 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
135 if ((*i)->decoder->done ()) {
139 if (dynamic_pointer_cast<VideoDecoder> ((*i)->decoder)) {
140 if ((*i)->video_position < earliest_t) {
141 earliest_t = (*i)->video_position;
147 if (dynamic_pointer_cast<AudioDecoder> ((*i)->decoder)) {
148 if ((*i)->audio_position < earliest_t) {
149 earliest_t = (*i)->audio_position;
158 cout << "no earliest piece.\n";
167 if (earliest_t > _video_position) {
169 cout << "no video here; emitting black frame.\n";
174 cout << "Pass " << *earliest << "\n";
176 earliest->decoder->pass ();
181 if (earliest_t > _audio_position) {
183 cout << "no audio here; emitting silence.\n";
185 emit_silence (_film->time_to_audio_frames (earliest_t - _audio_position));
188 cout << "Pass " << *earliest << "\n";
190 earliest->decoder->pass ();
196 cout << "\tpost pass " << _video_position << " " << _audio_position << "\n";
203 Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image, bool same, VideoContent::Frame frame)
205 shared_ptr<Piece> piece = weak_piece.lock ();
210 shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
213 FrameRateConversion frc (content->video_frame_rate(), _film->dcp_video_frame_rate());
214 if (frc.skip && (frame % 2) == 1) {
218 image = image->crop (content->crop(), true);
220 libdcp::Size const image_size = content->ratio()->size (_video_container_size);
222 image = image->scale_and_convert_to_rgb (image_size, _film->scaler(), true);
225 if (film->with_subtitles ()) {
226 shared_ptr<Subtitle> sub;
227 if (_timed_subtitle && _timed_subtitle->displayed_at (t)) {
228 sub = _timed_subtitle->subtitle ();
232 dcpomatic::Rect const tx = subtitle_transformed_area (
233 float (image_size.width) / content->video_size().width,
234 float (image_size.height) / content->video_size().height,
235 sub->area(), film->subtitle_offset(), film->subtitle_scale()
238 shared_ptr<Image> im = sub->image()->scale (tx.size(), film->scaler(), true);
239 image->alpha_blend (im, tx.position());
244 if (image_size != _video_container_size) {
245 assert (image_size.width <= _video_container_size.width);
246 assert (image_size.height <= _video_container_size.height);
247 shared_ptr<Image> im (new SimpleImage (PIX_FMT_RGB24, _video_container_size, true));
249 im->copy (image, Position ((_video_container_size.width - image_size.width) / 2, (_video_container_size.height - image_size.height) / 2));
253 Time time = content->start() + (frame * frc.factor() * TIME_HZ / _film->dcp_video_frame_rate());
255 Video (image, same, time);
256 time += TIME_HZ / _film->dcp_video_frame_rate();
259 Video (image, true, time);
260 time += TIME_HZ / _film->dcp_video_frame_rate();
263 _video_position = piece->video_position = time;
267 Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers> audio, AudioContent::Frame frame)
269 shared_ptr<Piece> piece = weak_piece.lock ();
274 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
277 if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) {
278 audio = resampler(content)->run (audio);
282 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->dcp_audio_channels(), audio->frames()));
283 dcp_mapped->make_silent ();
284 list<pair<int, libdcp::Channel> > map = content->audio_mapping().content_to_dcp ();
285 for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) {
286 dcp_mapped->accumulate_channel (audio.get(), i->first, i->second);
289 /* The time of this audio may indicate that some of our buffered audio is not going to
290 be added to any more, so it can be emitted.
293 Time const time = content->start() + (frame * TIME_HZ / _film->dcp_audio_frame_rate());
295 if (time > _audio_position) {
296 /* We can emit some audio from our buffers */
297 OutputAudioFrame const N = _film->time_to_audio_frames (time - _audio_position);
298 assert (N <= _audio_buffers.frames());
299 shared_ptr<AudioBuffers> emit (new AudioBuffers (_audio_buffers.channels(), N));
300 emit->copy_from (&_audio_buffers, N, 0, 0);
301 Audio (emit, _audio_position);
302 _audio_position = piece->audio_position = time + _film->audio_frames_to_time (N);
304 /* And remove it from our buffers */
305 if (_audio_buffers.frames() > N) {
306 _audio_buffers.move (N, 0, _audio_buffers.frames() - N);
308 _audio_buffers.set_frames (_audio_buffers.frames() - N);
311 /* Now accumulate the new audio into our buffers */
312 _audio_buffers.ensure_size (_audio_buffers.frames() + audio->frames());
313 _audio_buffers.accumulate_frames (audio.get(), 0, 0, audio->frames ());
314 _audio_buffers.set_frames (_audio_buffers.frames() + audio->frames());
320 if (_audio_buffers.frames() > 0) {
321 shared_ptr<AudioBuffers> emit (new AudioBuffers (_audio_buffers.channels(), _audio_buffers.frames()));
322 emit->copy_from (&_audio_buffers, _audio_buffers.frames(), 0, 0);
323 Audio (emit, _audio_position);
324 _audio_position += _film->audio_frames_to_time (_audio_buffers.frames ());
325 _audio_buffers.set_frames (0);
328 while (_video_position < _audio_position) {
332 while (_audio_position < _video_position) {
333 emit_silence (_film->time_to_audio_frames (_video_position - _audio_position));
338 /** @return true on error */
340 Player::seek (Time t)
342 if (!_have_valid_pieces) {
344 _have_valid_pieces = true;
347 if (_pieces.empty ()) {
351 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
352 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content);
357 Time s = t - vc->start ();
358 s = max (static_cast<Time> (0), s);
359 s = min (vc->length(), s);
361 FrameRateConversion frc (vc->video_frame_rate(), _film->dcp_video_frame_rate());
362 VideoContent::Frame f = s * _film->dcp_video_frame_rate() / (frc.factor() * TIME_HZ);
363 dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (f);
366 /* XXX: don't seek audio because we don't need to... */
377 Player::setup_pieces ()
379 list<shared_ptr<Piece> > old_pieces = _pieces;
383 Playlist::ContentList content = _playlist->content ();
384 sort (content.begin(), content.end(), ContentSorter ());
386 for (Playlist::ContentList::iterator i = content.begin(); i != content.end(); ++i) {
388 shared_ptr<Piece> piece (new Piece (*i));
390 /* XXX: into content? */
392 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
394 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
396 fd->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3));
397 fd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
402 shared_ptr<const ImageMagickContent> ic = dynamic_pointer_cast<const ImageMagickContent> (*i);
404 shared_ptr<ImageMagickDecoder> id;
406 /* See if we can re-use an old ImageMagickDecoder */
407 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
408 shared_ptr<ImageMagickDecoder> imd = dynamic_pointer_cast<ImageMagickDecoder> ((*j)->decoder);
409 if (imd && imd->content() == ic) {
415 id.reset (new ImageMagickDecoder (_film, ic));
416 id->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3));
422 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
424 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
425 sd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
430 _pieces.push_back (piece);
434 cout << "=== Player setup:\n";
435 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
436 cout << *(i->get()) << "\n";
442 Player::content_changed (weak_ptr<Content> w, int p)
444 shared_ptr<Content> c = w.lock ();
450 p == ContentProperty::START || p == ContentProperty::LENGTH ||
451 p == VideoContentProperty::VIDEO_CROP || p == VideoContentProperty::VIDEO_RATIO
454 _have_valid_pieces = false;
460 Player::playlist_changed ()
462 _have_valid_pieces = false;
467 Player::set_video_container_size (libdcp::Size s)
469 _video_container_size = s;
470 _black_frame.reset (new SimpleImage (PIX_FMT_RGB24, _video_container_size, true));
471 _black_frame->make_black ();
474 shared_ptr<Resampler>
475 Player::resampler (shared_ptr<AudioContent> c)
477 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
478 if (i != _resamplers.end ()) {
482 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
488 Player::emit_black ()
490 /* XXX: use same here */
491 Video (_black_frame, false, _video_position);
492 _video_position += _film->video_frames_to_time (1);
496 Player::emit_silence (OutputAudioFrame most)
498 OutputAudioFrame N = min (most, _film->dcp_audio_frame_rate() / 2);
499 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->dcp_audio_channels(), N));
500 silence->make_silent ();
501 Audio (silence, _audio_position);
502 _audio_position += _film->audio_frames_to_time (N);
506 Player::film_changed (Film::Property p)
508 /* Here we should notice Film properties that affect our output, and
509 alert listeners that our output now would be different to how it was
510 last time we were run.
514 p == Film::SCALER || p == Film::WITH_SUBTITLES ||
515 p == Film::SUBTITLE_SCALE || p == Film::SUBTITLE_OFFSET ||