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;
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, bool accurate)
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 * vc->video_frame_rate() / (frc.factor() * TIME_HZ);
363 dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (f, accurate);
366 /* XXX: don't seek audio because we don't need to... */
370 Player::setup_pieces ()
372 list<shared_ptr<Piece> > old_pieces = _pieces;
376 Playlist::ContentList content = _playlist->content ();
377 sort (content.begin(), content.end(), ContentSorter ());
379 for (Playlist::ContentList::iterator i = content.begin(); i != content.end(); ++i) {
381 shared_ptr<Piece> piece (new Piece (*i));
383 /* XXX: into content? */
385 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
387 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
389 fd->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3));
390 fd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
395 shared_ptr<const ImageMagickContent> ic = dynamic_pointer_cast<const ImageMagickContent> (*i);
397 shared_ptr<ImageMagickDecoder> id;
399 /* See if we can re-use an old ImageMagickDecoder */
400 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
401 shared_ptr<ImageMagickDecoder> imd = dynamic_pointer_cast<ImageMagickDecoder> ((*j)->decoder);
402 if (imd && imd->content() == ic) {
408 id.reset (new ImageMagickDecoder (_film, ic));
409 id->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3));
415 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
417 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
418 sd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
423 _pieces.push_back (piece);
427 cout << "=== Player setup:\n";
428 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
429 cout << *(i->get()) << "\n";
435 Player::content_changed (weak_ptr<Content> w, int p)
437 shared_ptr<Content> c = w.lock ();
443 p == ContentProperty::START || p == ContentProperty::LENGTH ||
444 p == VideoContentProperty::VIDEO_CROP || p == VideoContentProperty::VIDEO_RATIO
447 _have_valid_pieces = false;
453 Player::playlist_changed ()
455 _have_valid_pieces = false;
460 Player::set_video_container_size (libdcp::Size s)
462 _video_container_size = s;
463 _black_frame.reset (new SimpleImage (PIX_FMT_RGB24, _video_container_size, true));
464 _black_frame->make_black ();
467 shared_ptr<Resampler>
468 Player::resampler (shared_ptr<AudioContent> c)
470 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
471 if (i != _resamplers.end ()) {
475 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
481 Player::emit_black ()
483 /* XXX: use same here */
484 Video (_black_frame, false, _video_position);
485 _video_position += _film->video_frames_to_time (1);
489 Player::emit_silence (OutputAudioFrame most)
491 OutputAudioFrame N = min (most, _film->dcp_audio_frame_rate() / 2);
492 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->dcp_audio_channels(), N));
493 silence->make_silent ();
494 Audio (silence, _audio_position);
495 _audio_position += _film->audio_frames_to_time (N);
499 Player::film_changed (Film::Property p)
501 /* Here we should notice Film properties that affect our output, and
502 alert listeners that our output now would be different to how it was
503 last time we were run.
507 p == Film::SCALER || p == Film::WITH_SUBTITLES ||
508 p == Film::SUBTITLE_SCALE || p == Film::SUBTITLE_OFFSET ||