X-Git-Url: https://main.carlh.net/gitweb/?p=dcpomatic.git;a=blobdiff_plain;f=src%2Flib%2Fplayer.cc;h=0606a9340c9d1d6e51cd3f4e0d2ac906a090edf5;hp=8063d1212971afe2e9bf682a84d253361b902bac;hb=aeb835a18c8df347e0ed68fb24631b320abeb611;hpb=0b6c6de07f9a3aa28c2e8ca8ef30340e3fa1bfc6 diff --git a/src/lib/player.cc b/src/lib/player.cc index 8063d1212..0606a9340 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2014 Carl Hetherington + Copyright (C) 2013-2015 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,631 +17,752 @@ */ -#include #include "player.h" #include "film.h" #include "ffmpeg_decoder.h" +#include "audio_buffers.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 "subrip_decoder.h" +#include "subrip_content.h" +#include "dcp_content.h" #include "job.h" #include "image.h" -#include "image_proxy.h" +#include "raw_image_proxy.h" #include "ratio.h" -#include "resampler.h" #include "log.h" -#include "scaler.h" -#include "player_video_frame.h" +#include "render_subtitles.h" +#include "config.h" +#include "content_video.h" +#include "player_video.h" #include "frame_rate_change.h" +#include "dcp_content.h" +#include "dcp_decoder.h" +#include "dcp_subtitle_content.h" +#include "dcp_subtitle_decoder.h" +#include "audio_processor.h" +#include "playlist.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i18n.h" -#define LOG_GENERAL(...) _film->log()->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL); +#define LOG_GENERAL(...) _film->log()->log (String::compose (__VA_ARGS__), LogEntry::TYPE_GENERAL); using std::list; using std::cout; using std::min; using std::max; +using std::min; using std::vector; using std::pair; using std::map; +using std::make_pair; +using std::copy; using boost::shared_ptr; using boost::weak_ptr; using boost::dynamic_pointer_cast; +using boost::optional; -Player::Player (shared_ptr f, shared_ptr p) - : _film (f) - , _playlist (p) - , _video (true) - , _audio (true) +Player::Player (shared_ptr film, shared_ptr playlist) + : _film (film) + , _playlist (playlist) , _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) + , _ignore_video (false) + , _ignore_audio (false) + , _always_burn_subtitles (false) + , _fast (false) + , _play_referenced (false) { - _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)); + _playlist_changed_connection = _playlist->Changed.connect (bind (&Player::playlist_changed, this)); + _playlist_content_changed_connection = _playlist->ContentChanged.connect (bind (&Player::playlist_content_changed, this, _1, _2, _3)); set_video_container_size (_film->frame_size ()); -} -void -Player::disable_video () -{ - _video = false; + film_changed (Film::AUDIO_PROCESSOR); } void -Player::disable_audio () -{ - _audio = false; -} - -bool -Player::pass () +Player::setup_pieces () { - if (!_have_valid_pieces) { - setup_pieces (); - } + list > old_pieces = _pieces; + _pieces.clear (); - Time earliest_t = TIME_MAX; - shared_ptr earliest; - enum { - VIDEO, - AUDIO - } type = VIDEO; + BOOST_FOREACH (shared_ptr i, _playlist->content ()) { - for (list >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) { - if ((*i)->decoder->done () || (*i)->content->length_after_trim() == 0) { + if (!i->paths_valid ()) { continue; } - shared_ptr vd = dynamic_pointer_cast ((*i)->decoder); - shared_ptr ad = dynamic_pointer_cast ((*i)->decoder); + shared_ptr decoder; + optional frc; - if (_video && vd) { - if ((*i)->video_position < earliest_t) { - earliest_t = (*i)->video_position; - earliest = *i; - type = VIDEO; - } + /* FFmpeg */ + shared_ptr fc = dynamic_pointer_cast (i); + if (fc) { + decoder.reset (new FFmpegDecoder (fc, _film->log(), _fast)); + frc = FrameRateChange (fc->video_frame_rate(), _film->video_frame_rate()); } - if (_audio && ad && ad->has_audio ()) { - if ((*i)->audio_position < earliest_t) { - earliest_t = (*i)->audio_position; - earliest = *i; - type = AUDIO; - } + shared_ptr dc = dynamic_pointer_cast (i); + if (dc) { + decoder.reset (new DCPDecoder (dc, _fast)); + frc = FrameRateChange (dc->video_frame_rate(), _film->video_frame_rate()); } - } - if (!earliest) { - flush (); - return true; - } + /* ImageContent */ + shared_ptr ic = dynamic_pointer_cast (i); + if (ic) { + /* See if we can re-use an old ImageDecoder */ + for (list >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) { + shared_ptr imd = dynamic_pointer_cast ((*j)->decoder); + if (imd && imd->content() == ic) { + decoder = imd; + } + } - switch (type) { - case VIDEO: - if (earliest_t > _video_position) { - emit_black (); - } else { - if (earliest->repeating ()) { - earliest->repeat (this); - } else { - earliest->decoder->pass (); + if (!decoder) { + decoder.reset (new ImageDecoder (ic)); } + + frc = FrameRateChange (ic->video_frame_rate(), _film->video_frame_rate()); } - break; - - 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() * ac->output_audio_frame_rate() / ac->content_audio_frame_rate(), - true - ); - } + + /* SndfileContent */ + shared_ptr sc = dynamic_pointer_cast (i); + if (sc) { + decoder.reset (new SndfileDecoder (sc, _fast)); + + /* Work out a FrameRateChange for the best overlap video for this content */ + DCPTime best_overlap_t; + shared_ptr best_overlap; + BOOST_FOREACH (shared_ptr j, _playlist->content ()) { + shared_ptr vc = dynamic_pointer_cast (j); + if (!vc) { + continue; } - } - } - break; - } - if (_audio) { - boost::optional