X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Flib%2Fplayer.cc;h=7bf78c905248487e2e9d3723c38d267827e4a11b;hb=e7bc3bd16456c17bc6fe1d7981040b14e820505e;hp=ac046fcc0e6eaf9e59c912da2f6ad6a3a812a5e7;hpb=21ae33095a251da25b3c5a85bc52fad63e04db0b;p=dcpomatic.git diff --git a/src/lib/player.cc b/src/lib/player.cc index ac046fcc0..7bf78c905 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2013 Carl Hetherington + Copyright (C) 2013-2014 Carl Hetherington This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,16 +17,36 @@ */ +#include #include "player.h" #include "film.h" #include "ffmpeg_decoder.h" -#include "imagemagick_decoder.h" +#include "ffmpeg_content.h" +#include "image_decoder.h" +#include "image_content.h" #include "sndfile_decoder.h" +#include "sndfile_content.h" +#include "subtitle_content.h" #include "playlist.h" #include "job.h" +#include "image.h" +#include "image_proxy.h" +#include "ratio.h" +#include "resampler.h" +#include "log.h" +#include "scaler.h" +#include "player_video_frame.h" +#include "frame_rate_change.h" + +#define LOG_GENERAL(...) _film->log()->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL); using std::list; using std::cout; +using std::min; +using std::max; +using std::vector; +using std::pair; +using std::map; using boost::shared_ptr; using boost::weak_ptr; using boost::dynamic_pointer_cast; @@ -36,13 +56,16 @@ Player::Player (shared_ptr f, shared_ptr p) , _playlist (p) , _video (true) , _audio (true) - , _subtitles (true) - , _have_valid_decoders (false) - , _ffmpeg_decoder_done (false) - , _video_sync (true) + , _have_valid_pieces (false) + , _video_position (0) + , _audio_position (0) + , _audio_merger (f->audio_channels(), bind (&Film::time_to_audio_frames, f.get(), _1), bind (&Film::audio_frames_to_time, f.get(), _1)) + , _last_emit_was_black (false) { - _playlist->Changed.connect (bind (&Player::playlist_changed, this)); - _playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2)); + _playlist_changed_connection = _playlist->Changed.connect (bind (&Player::playlist_changed, this)); + _playlist_content_changed_connection = _playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2, _3)); + _film_changed_connection = _film->Changed.connect (bind (&Player::film_changed, this, _1)); + set_video_container_size (_film->frame_size ()); } void @@ -57,256 +80,562 @@ Player::disable_audio () _audio = false; } -void -Player::disable_subtitles () -{ - _subtitles = false; -} - bool Player::pass () { - if (!_have_valid_decoders) { - setup_decoders (); - _have_valid_decoders = true; + if (!_have_valid_pieces) { + setup_pieces (); } - - bool done = true; - - if (_playlist->video_from() == Playlist::VIDEO_FFMPEG || _playlist->audio_from() == Playlist::AUDIO_FFMPEG) { - if (!_ffmpeg_decoder_done) { - if (_ffmpeg_decoder->pass ()) { - _ffmpeg_decoder_done = true; - } else { - done = false; - } + + Time earliest_t = TIME_MAX; + shared_ptr earliest; + enum { + VIDEO, + AUDIO + } type = VIDEO; + + for (list >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) { + if ((*i)->decoder->done () || (*i)->content->length_after_trim() == 0) { + continue; } - } - if (_playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) { - if (_imagemagick_decoder != _imagemagick_decoders.end ()) { - if ((*_imagemagick_decoder)->pass ()) { - _imagemagick_decoder++; + shared_ptr vd = dynamic_pointer_cast ((*i)->decoder); + shared_ptr ad = dynamic_pointer_cast ((*i)->decoder); + + if (_video && vd) { + if ((*i)->video_position < earliest_t) { + earliest_t = (*i)->video_position; + earliest = *i; + type = VIDEO; } + } - if (_imagemagick_decoder != _imagemagick_decoders.end ()) { - done = false; + if (_audio && ad && ad->has_audio ()) { + if ((*i)->audio_position < earliest_t) { + earliest_t = (*i)->audio_position; + earliest = *i; + type = AUDIO; } } } - /* XXX: sndfile */ - - return done; -} + if (!earliest) { + flush (); + return true; + } -void -Player::set_progress (shared_ptr job) -{ - /* Assume progress can be divined from how far through the video we are */ - switch (_playlist->video_from ()) { - case Playlist::VIDEO_NONE: - break; - case Playlist::VIDEO_FFMPEG: - if (_playlist->video_length ()) { - job->set_progress (float(_ffmpeg_decoder->video_frame()) / _playlist->video_length ()); + switch (type) { + case VIDEO: + if (earliest_t > _video_position) { + emit_black (); + } else { + if (earliest->repeating ()) { + earliest->repeat (this); + } else { + earliest->decoder->pass (); + } } break; - case Playlist::VIDEO_IMAGEMAGICK: - { - int n = 0; - for (list >::iterator i = _imagemagick_decoders.begin(); i != _imagemagick_decoders.end(); ++i) { - if (_imagemagick_decoder == i) { - job->set_progress (float (n) / _imagemagick_decoders.size ()); + + case AUDIO: + if (earliest_t > _audio_position) { + emit_silence (_film->time_to_audio_frames (earliest_t - _audio_position)); + } else { + earliest->decoder->pass (); + + if (earliest->decoder->done()) { + shared_ptr ac = dynamic_pointer_cast (earliest->content); + assert (ac); + shared_ptr re = resampler (ac, false); + if (re) { + shared_ptr b = re->flush (); + if (b->frames ()) { + process_audio (earliest, b, ac->audio_length (), true); + } + } } - ++n; } break; } + + if (_audio) { + boost::optional