X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fplayer.cc;h=30313d39dd23bb57445cf43ff8a45f7b9c2d8b00;hb=a8a0dfd1b21de6c0facf965ab119833ff6f790bf;hp=d37910ad8fdcd3dd816cb165e9ccef72a7c91f84;hpb=2d5beb0d6794df13ad1df47e84fd7a57d1d1c64d;p=dcpomatic.git diff --git a/src/lib/player.cc b/src/lib/player.cc index d37910ad8..30313d39d 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -1,35 +1,27 @@ /* Copyright (C) 2013-2016 Carl Hetherington - This program is free software; you can redistribute it and/or modify + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - This program is distributed in the hope that it will be useful, + DCP-o-matic is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + along with DCP-o-matic. If not, see . */ #include "player.h" #include "film.h" -#include "ffmpeg_decoder.h" #include "audio_buffers.h" -#include "audio_content.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 "text_subtitle_decoder.h" -#include "text_subtitle_content.h" +#include "content_audio.h" #include "dcp_content.h" #include "job.h" #include "image.h" @@ -41,13 +33,20 @@ #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 "referenced_reel_asset.h" +#include "decoder_factory.h" +#include "decoder.h" +#include "video_decoder.h" +#include "audio_decoder.h" +#include "subtitle_content.h" +#include "subtitle_decoder.h" +#include "ffmpeg_content.h" +#include "audio_content.h" +#include "content_subtitle.h" +#include "dcp_decoder.h" +#include "image_decoder.h" #include #include #include @@ -77,6 +76,24 @@ using boost::dynamic_pointer_cast; using boost::optional; using boost::scoped_ptr; +static bool +has_video (Content* c) +{ + return static_cast(c->video); +} + +static bool +has_audio (Content* c) +{ + return static_cast(c->audio); +} + +static bool +has_subtitle (Content* c) +{ + return static_cast(c->subtitle); +} + Player::Player (shared_ptr film, shared_ptr playlist) : _film (film) , _playlist (playlist) @@ -98,7 +115,6 @@ Player::Player (shared_ptr film, shared_ptr playlist void Player::setup_pieces () { - list > old_pieces = _pieces; _pieces.clear (); BOOST_FOREACH (shared_ptr i, _playlist->content ()) { @@ -107,98 +123,23 @@ Player::setup_pieces () continue; } - shared_ptr decoder; - optional frc; - - /* 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()); - } - - shared_ptr dc = dynamic_pointer_cast (i); - if (dc) { - decoder.reset (new DCPDecoder (dc, _film->log(), _fast)); - frc = FrameRateChange (dc->video->frame_rate(), _film->video_frame_rate()); - } - - /* 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; - } - } - - if (!decoder) { - decoder.reset (new ImageDecoder (ic, _film->log())); - } - - frc = FrameRateChange (ic->video->frame_rate(), _film->video_frame_rate()); - } - - /* SndfileContent */ - shared_ptr sc = dynamic_pointer_cast (i); - if (sc) { - decoder.reset (new SndfileDecoder (sc, _fast, _film->log())); - - /* 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 ()) { - if (!j->video) { - continue; - } - - DCPTime const overlap = min (j->end(), i->end()) - max (j->position(), i->position()); - if (overlap > best_overlap_t) { - best_overlap = j; - best_overlap_t = overlap; - } - } - - if (best_overlap) { - frc = FrameRateChange (best_overlap->video->frame_rate(), _film->video_frame_rate ()); - } else { - /* No video overlap; e.g. if the DCP is just audio */ - frc = FrameRateChange (_film->video_frame_rate(), _film->video_frame_rate ()); - } - } - - /* It's questionable whether subtitle content should have a video frame rate; perhaps - it should be assumed that any subtitle content has been prepared at the same rate - as simultaneous video content (like we do with audio). - */ - - /* TextSubtitleContent */ - shared_ptr rc = dynamic_pointer_cast (i); - if (rc) { - decoder.reset (new TextSubtitleDecoder (rc)); - frc = FrameRateChange (rc->subtitle->video_frame_rate(), _film->video_frame_rate()); - } + shared_ptr decoder = decoder_factory (i, _film->log(), _fast); + FrameRateChange frc (i->active_video_frame_rate(), _film->video_frame_rate()); - /* DCPSubtitleContent */ - shared_ptr dsc = dynamic_pointer_cast (i); - if (dsc) { - decoder.reset (new DCPSubtitleDecoder (dsc)); - frc = FrameRateChange (dsc->subtitle->video_frame_rate(), _film->video_frame_rate()); + if (!decoder) { + /* Not something that we can decode; e.g. Atmos content */ + continue; } - shared_ptr vd = dynamic_pointer_cast (decoder); - if (vd && _ignore_video) { - vd->set_ignore_video (); + if (decoder->video && _ignore_video) { + decoder->video->set_ignore (); } - shared_ptr ad = dynamic_pointer_cast (decoder); - if (ad && _ignore_audio) { - ad->set_ignore_audio (); + if (decoder->audio && _ignore_audio) { + decoder->audio->set_ignore (); } - _pieces.push_back (shared_ptr (new Piece (i, decoder, frc.get ()))); + _pieces.push_back (shared_ptr (new Piece (i, decoder, frc))); } _have_valid_pieces = true; @@ -230,6 +171,7 @@ Player::playlist_content_changed (weak_ptr w, int property, bool freque Changed (frequent); } else if ( + property == ContentProperty::VIDEO_FRAME_RATE || property == SubtitleContentProperty::USE || property == SubtitleContentProperty::X_OFFSET || property == SubtitleContentProperty::Y_OFFSET || @@ -238,7 +180,6 @@ Player::playlist_content_changed (weak_ptr w, int property, bool freque property == SubtitleContentProperty::FONTS || property == VideoContentProperty::CROP || property == VideoContentProperty::SCALE || - property == VideoContentProperty::FRAME_RATE || property == VideoContentProperty::FADE_IN || property == VideoContentProperty::FADE_OUT || property == VideoContentProperty::COLOUR_CONVERSION @@ -384,9 +325,10 @@ Player::get_video (DCPTime time, bool accurate) /* Find pieces containing video which is happening now */ - list > ov = overlaps ( + list > ov = overlaps ( time, - time + DCPTime::from_frames (1, _film->video_frame_rate ()) + time + DCPTime::from_frames (1, _film->video_frame_rate ()), + &has_video ); list > pvf; @@ -402,7 +344,7 @@ Player::get_video (DCPTime time, bool accurate) /* Get video from appropriate piece(s) */ BOOST_FOREACH (shared_ptr piece, ov) { - shared_ptr decoder = dynamic_pointer_cast (piece->decoder); + shared_ptr decoder = piece->decoder->video; DCPOMATIC_ASSERT (decoder); shared_ptr dcp_content = dynamic_pointer_cast (piece->content); @@ -419,7 +361,7 @@ Player::get_video (DCPTime time, bool accurate) if (use) { /* We want to use this piece */ - list content_video = decoder->get_video (dcp_to_content_video (piece, time), accurate); + list content_video = decoder->get (dcp_to_content_video (piece, time), accurate); if (content_video.empty ()) { pvf.push_back (black_player_video_frame (time)); } else { @@ -432,12 +374,12 @@ Player::get_video (DCPTime time, bool accurate) shared_ptr ( new PlayerVideo ( i->image, - content_video_to_dcp (piece, i->frame), + time, piece->content->video->crop (), - piece->content->video->fade (i->frame), + piece->content->video->fade (i->frame.index()), image_size, _video_container_size, - i->eyes, + i->frame.eyes(), i->part, piece->content->video->colour_conversion () ) @@ -447,7 +389,7 @@ Player::get_video (DCPTime time, bool accurate) } } else { /* Discard unused video */ - decoder->get_video (dcp_to_content_video (piece, time), accurate); + decoder->get (dcp_to_content_video (piece, time), accurate); } } } @@ -474,7 +416,7 @@ Player::get_audio (DCPTime time, DCPTime length, bool accurate) shared_ptr audio (new AudioBuffers (_film->audio_channels(), length_frames)); audio->make_silent (); - list > ov = overlaps (time, time + length); + list > ov = overlaps (time, time + length, has_audio); if (ov.empty ()) { return audio; } @@ -495,7 +437,7 @@ Player::get_audio (DCPTime time, DCPTime length, bool accurate) BOOST_FOREACH (shared_ptr i, ov) { DCPOMATIC_ASSERT (i->content->audio); - shared_ptr decoder = dynamic_pointer_cast (i->decoder); + shared_ptr decoder = i->decoder->audio; DCPOMATIC_ASSERT (decoder); /* The time that we should request from the content */ @@ -524,7 +466,7 @@ Player::get_audio (DCPTime time, DCPTime length, bool accurate) } /* Audio from this piece's decoder stream (which might be more or less than what we asked for) */ - ContentAudio all = decoder->get_audio (j, content_frame, request_frames, accurate); + ContentAudio all = decoder->get (j, content_frame, request_frames, accurate); /* Gain */ if (i->content->audio->gain() != 0) { @@ -623,7 +565,7 @@ Player::content_subtitle_to_dcp (shared_ptr piece, ContentTime t) c PlayerSubtitles Player::get_subtitles (DCPTime time, DCPTime length, bool starting, bool burnt, bool accurate) { - list > subs = overlaps (time, time + length); + list > subs = overlaps (time, time + length, has_subtitle); PlayerSubtitles ps (time, length); @@ -637,12 +579,12 @@ Player::get_subtitles (DCPTime time, DCPTime length, bool starting, bool burnt, continue; } - shared_ptr subtitle_decoder = dynamic_pointer_cast ((*j)->decoder); + shared_ptr subtitle_decoder = (*j)->decoder->subtitle; ContentTime const from = dcp_to_content_subtitle (*j, time); /* XXX: this video_frame_rate() should be the rate that the subtitle content has been prepared for */ ContentTime const to = from + ContentTime::from_frames (1, _film->video_frame_rate ()); - list image = subtitle_decoder->get_image_subtitles (ContentTimePeriod (from, to), starting, accurate); + list image = subtitle_decoder->get_image (ContentTimePeriod (from, to), starting, accurate); for (list::iterator i = image.begin(); i != image.end(); ++i) { /* Apply content's subtitle offsets */ @@ -660,7 +602,7 @@ Player::get_subtitles (DCPTime time, DCPTime length, bool starting, bool burnt, ps.image.push_back (i->sub); } - list text = subtitle_decoder->get_text_subtitles (ContentTimePeriod (from, to), starting, accurate); + list text = subtitle_decoder->get_text (ContentTimePeriod (from, to), starting, accurate); BOOST_FOREACH (ContentTextSubtitle& ts, text) { BOOST_FOREACH (dcp::SubtitleString s, ts.subs) { s.set_h_position (s.h_position() + (*j)->content->subtitle->x_offset ()); @@ -807,3 +749,20 @@ Player::get_reel_assets () return a; } + +list > +Player::overlaps (DCPTime from, DCPTime to, boost::function valid) +{ + if (!_have_valid_pieces) { + setup_pieces (); + } + + list > overlaps; + BOOST_FOREACH (shared_ptr i, _pieces) { + if (valid (i->content.get ()) && i->content->position() < to && i->content->end() > from) { + overlaps.push_back (i); + } + } + + return overlaps; +}