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 set_video_container_size (_film->container()->size (_film->full_frame ()));
103 Player::disable_video ()
109 Player::disable_audio ()
117 if (!_have_valid_pieces) {
119 _have_valid_pieces = true;
126 Time earliest_t = TIME_MAX;
127 shared_ptr<Piece> earliest;
133 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
134 if ((*i)->decoder->done ()) {
138 if (dynamic_pointer_cast<VideoDecoder> ((*i)->decoder)) {
139 if ((*i)->video_position < earliest_t) {
140 earliest_t = (*i)->video_position;
146 if (dynamic_pointer_cast<AudioDecoder> ((*i)->decoder)) {
147 if ((*i)->audio_position < earliest_t) {
148 earliest_t = (*i)->audio_position;
157 cout << "no earliest piece.\n";
166 if (earliest_t > _video_position) {
168 cout << "no video here; emitting black frame.\n";
173 cout << "Pass " << *earliest << "\n";
175 earliest->decoder->pass ();
180 if (earliest_t > _audio_position) {
182 cout << "no audio here; emitting silence.\n";
184 emit_silence (_film->time_to_audio_frames (earliest_t - _audio_position));
187 cout << "Pass " << *earliest << "\n";
189 earliest->decoder->pass ();
195 cout << "\tpost pass " << _video_position << " " << _audio_position << "\n";
202 Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image, bool same, VideoContent::Frame frame)
204 shared_ptr<Piece> piece = weak_piece.lock ();
209 shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
212 FrameRateConversion frc (content->video_frame_rate(), _film->dcp_video_frame_rate());
213 if (frc.skip && (frame % 2) == 1) {
217 image = image->crop (content->crop(), true);
219 libdcp::Size const image_size = content->ratio()->size (_video_container_size);
221 image = image->scale_and_convert_to_rgb (image_size, _film->scaler(), true);
224 if (film->with_subtitles ()) {
225 shared_ptr<Subtitle> sub;
226 if (_timed_subtitle && _timed_subtitle->displayed_at (t)) {
227 sub = _timed_subtitle->subtitle ();
231 dcpomatic::Rect const tx = subtitle_transformed_area (
232 float (image_size.width) / content->video_size().width,
233 float (image_size.height) / content->video_size().height,
234 sub->area(), film->subtitle_offset(), film->subtitle_scale()
237 shared_ptr<Image> im = sub->image()->scale (tx.size(), film->scaler(), true);
238 image->alpha_blend (im, tx.position());
243 if (image_size != _video_container_size) {
244 assert (image_size.width <= _video_container_size.width);
245 assert (image_size.height <= _video_container_size.height);
246 shared_ptr<Image> im (new SimpleImage (PIX_FMT_RGB24, _video_container_size, true));
248 im->copy (image, Position ((_video_container_size.width - image_size.width) / 2, (_video_container_size.height - image_size.height) / 2));
252 Time time = content->start() + (frame * frc.factor() * TIME_HZ / _film->dcp_video_frame_rate());
254 Video (image, same, time);
255 time += TIME_HZ / _film->dcp_video_frame_rate();
258 Video (image, true, time);
259 time += TIME_HZ / _film->dcp_video_frame_rate();
262 _video_position = piece->video_position = time;
266 Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers> audio, AudioContent::Frame frame)
268 shared_ptr<Piece> piece = weak_piece.lock ();
273 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
276 if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) {
277 audio = resampler(content)->run (audio);
281 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->dcp_audio_channels(), audio->frames()));
282 dcp_mapped->make_silent ();
283 list<pair<int, libdcp::Channel> > map = content->audio_mapping().content_to_dcp ();
284 for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) {
285 dcp_mapped->accumulate_channel (audio.get(), i->first, i->second);
288 /* The time of this audio may indicate that some of our buffered audio is not going to
289 be added to any more, so it can be emitted.
292 Time const time = content->start() + (frame * TIME_HZ / _film->dcp_audio_frame_rate());
294 cout << "Player gets " << dcp_mapped->frames() << " @ " << time << " cf " << _audio_position << "\n";
296 if (time > _audio_position) {
297 /* We can emit some audio from our buffers */
298 OutputAudioFrame const N = _film->time_to_audio_frames (time - _audio_position);
299 assert (N <= _audio_buffers.frames());
300 shared_ptr<AudioBuffers> emit (new AudioBuffers (_audio_buffers.channels(), N));
301 emit->copy_from (&_audio_buffers, N, 0, 0);
302 Audio (emit, _audio_position);
303 _audio_position = piece->audio_position = time + _film->audio_frames_to_time (N);
305 /* And remove it from our buffers */
306 if (_audio_buffers.frames() > N) {
307 _audio_buffers.move (N, 0, _audio_buffers.frames() - N);
309 _audio_buffers.set_frames (_audio_buffers.frames() - N);
312 /* Now accumulate the new audio into our buffers */
313 _audio_buffers.ensure_size (_audio_buffers.frames() + audio->frames());
314 _audio_buffers.accumulate_frames (audio.get(), 0, 0, audio->frames ());
315 _audio_buffers.set_frames (_audio_buffers.frames() + audio->frames());
321 if (_audio_buffers.frames() > 0) {
322 shared_ptr<AudioBuffers> emit (new AudioBuffers (_audio_buffers.channels(), _audio_buffers.frames()));
323 emit->copy_from (&_audio_buffers, _audio_buffers.frames(), 0, 0);
324 Audio (emit, _audio_position);
325 _audio_position += _film->audio_frames_to_time (_audio_buffers.frames ());
326 _audio_buffers.set_frames (0);
329 while (_video_position < _audio_position) {
333 while (_audio_position < _video_position) {
334 emit_silence (_film->time_to_audio_frames (_video_position - _audio_position));
339 /** @return true on error */
341 Player::seek (Time t)
343 if (!_have_valid_pieces) {
345 _have_valid_pieces = true;
348 if (_pieces.empty ()) {
352 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
353 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content);
358 Time s = t - vc->start ();
359 s = max (static_cast<Time> (0), s);
360 s = min (vc->length(), s);
362 FrameRateConversion frc (vc->video_frame_rate(), _film->dcp_video_frame_rate());
363 VideoContent::Frame f = s * _film->dcp_video_frame_rate() / (frc.factor() * TIME_HZ);
364 dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (f);
367 /* XXX: don't seek audio because we don't need to... */
378 Player::setup_pieces ()
380 list<shared_ptr<Piece> > old_pieces = _pieces;
384 Playlist::ContentList content = _playlist->content ();
385 sort (content.begin(), content.end(), ContentSorter ());
387 for (Playlist::ContentList::iterator i = content.begin(); i != content.end(); ++i) {
389 shared_ptr<Piece> piece (new Piece (*i));
391 /* XXX: into content? */
393 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
395 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
397 fd->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3));
398 fd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
403 shared_ptr<const ImageMagickContent> ic = dynamic_pointer_cast<const ImageMagickContent> (*i);
405 shared_ptr<ImageMagickDecoder> id;
407 /* See if we can re-use an old ImageMagickDecoder */
408 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
409 shared_ptr<ImageMagickDecoder> imd = dynamic_pointer_cast<ImageMagickDecoder> ((*j)->decoder);
410 if (imd && imd->content() == ic) {
416 id.reset (new ImageMagickDecoder (_film, ic));
417 id->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3));
423 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
425 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
426 sd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
431 _pieces.push_back (piece);
435 cout << "=== Player setup:\n";
436 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
437 cout << *(i->get()) << "\n";
443 Player::content_changed (weak_ptr<Content> w, int p)
445 shared_ptr<Content> c = w.lock ();
450 if (p == ContentProperty::START || p == ContentProperty::LENGTH) {
451 _have_valid_pieces = false;
456 Player::playlist_changed ()
458 _have_valid_pieces = false;
462 Player::set_video_container_size (libdcp::Size s)
464 _video_container_size = s;
465 _black_frame.reset (new SimpleImage (PIX_FMT_RGB24, _video_container_size, true));
466 _black_frame->make_black ();
469 shared_ptr<Resampler>
470 Player::resampler (shared_ptr<AudioContent> c)
472 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
473 if (i != _resamplers.end ()) {
477 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
483 Player::emit_black ()
485 /* XXX: use same here */
486 Video (_black_frame, false, _video_position);
487 _video_position += _film->video_frames_to_time (1);
491 Player::emit_silence (OutputAudioFrame most)
493 OutputAudioFrame N = min (most, _film->dcp_audio_frame_rate() / 2);
494 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->dcp_audio_channels(), N));
495 silence->make_silent ();
496 Audio (silence, _audio_position);
497 _audio_position += _film->audio_frames_to_time (N);