/*
Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
- 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 <http://www.gnu.org/licenses/>.
*/
#include "player.h"
#include "film.h"
-#include "ffmpeg_decoder.h"
-#include "video_decoder.h"
-#include "audio_decoder.h"
#include "audio_buffers.h"
-#include "audio_content.h"
-#include "ffmpeg_content.h"
-#include "image_decoder.h"
#include "content_audio.h"
-#include "image_content.h"
-#include "subtitle_content.h"
-#include "text_subtitle_decoder.h"
-#include "text_subtitle_content.h"
-#include "video_mxf_decoder.h"
-#include "video_mxf_content.h"
#include "dcp_content.h"
#include "job.h"
#include "image.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 "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 <dcp/reel.h>
#include <dcp/reel_sound_asset.h>
#include <dcp/reel_subtitle_asset.h>
void
Player::setup_pieces ()
{
- list<shared_ptr<Piece> > old_pieces = _pieces;
_pieces.clear ();
BOOST_FOREACH (shared_ptr<Content> i, _playlist->content ()) {
continue;
}
- shared_ptr<Decoder> decoder;
- optional<FrameRateChange> frc;
-
- /* FFmpeg */
- shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (i);
- if (fc) {
- decoder.reset (new FFmpegDecoder (fc, _film->log(), _fast));
- frc = FrameRateChange (fc->active_video_frame_rate(), _film->video_frame_rate());
- }
-
- shared_ptr<const DCPContent> dc = dynamic_pointer_cast<const DCPContent> (i);
- if (dc) {
- decoder.reset (new DCPDecoder (dc, _film->log(), _fast));
- frc = FrameRateChange (dc->active_video_frame_rate(), _film->video_frame_rate());
- }
-
- /* ImageContent */
- shared_ptr<const ImageContent> ic = dynamic_pointer_cast<const ImageContent> (i);
- if (ic) {
- /* See if we can re-use an old ImageDecoder */
- for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
- shared_ptr<ImageDecoder> imd = dynamic_pointer_cast<ImageDecoder> ((*j)->decoder);
- if (imd && imd->content() == ic) {
- decoder = imd;
- }
- }
-
- if (!decoder) {
- decoder.reset (new ImageDecoder (ic, _film->log()));
- }
-
- frc = FrameRateChange (ic->active_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<const TextSubtitleContent> rc = dynamic_pointer_cast<const TextSubtitleContent> (i);
- if (rc) {
- decoder.reset (new TextSubtitleDecoder (rc));
- frc = FrameRateChange (rc->active_video_frame_rate(), _film->video_frame_rate());
- }
-
- /* DCPSubtitleContent */
- shared_ptr<const DCPSubtitleContent> dsc = dynamic_pointer_cast<const DCPSubtitleContent> (i);
- if (dsc) {
- decoder.reset (new DCPSubtitleDecoder (dsc));
- frc = FrameRateChange (dsc->active_video_frame_rate(), _film->video_frame_rate());
- }
-
- /* VideoMXFContent */
- shared_ptr<const VideoMXFContent> vmc = dynamic_pointer_cast<const VideoMXFContent> (i);
- if (vmc) {
- decoder.reset (new VideoMXFDecoder (vmc, _film->log()));
- frc = FrameRateChange (vmc->active_video_frame_rate(), _film->video_frame_rate());
- }
+ shared_ptr<Decoder> decoder = decoder_factory (i, _film->log());
+ FrameRateChange frc (i->active_video_frame_rate(), _film->video_frame_rate());
if (!decoder) {
/* Not something that we can decode; e.g. Atmos content */
decoder->audio->set_ignore ();
}
- _pieces.push_back (shared_ptr<Piece> (new Piece (i, decoder, frc.get ())));
+ if (decoder->audio && _fast) {
+ decoder->audio->set_fast ();
+ }
+
+ shared_ptr<DCPDecoder> dcp = dynamic_pointer_cast<DCPDecoder> (decoder);
+ if (dcp && _play_referenced) {
+ dcp->set_decode_referenced ();
+ }
+
+ _pieces.push_back (shared_ptr<Piece> (new Piece (i, decoder, frc)));
}
_have_valid_pieces = true;
property == ContentProperty::TRIM_END ||
property == ContentProperty::PATH ||
property == VideoContentProperty::FRAME_TYPE ||
- property == DCPContentProperty::CAN_BE_PLAYED ||
+ property == DCPContentProperty::NEEDS_ASSETS ||
+ property == DCPContentProperty::NEEDS_KDM ||
property == SubtitleContentProperty::COLOUR ||
property == SubtitleContentProperty::OUTLINE ||
- property == SubtitleContentProperty::OUTLINE_COLOUR ||
- property == FFmpegContentProperty::SUBTITLE_STREAM
+ property == SubtitleContentProperty::SHADOW ||
+ property == SubtitleContentProperty::EFFECT_COLOUR ||
+ property == FFmpegContentProperty::SUBTITLE_STREAM ||
+ property == VideoContentProperty::COLOUR_CONVERSION
) {
_have_valid_pieces = false;
Changed (frequent);
+ } else if (
+ property == SubtitleContentProperty::LINE_SPACING ||
+ property == SubtitleContentProperty::OUTLINE_WIDTH ||
+ property == SubtitleContentProperty::Y_SCALE ||
+ property == SubtitleContentProperty::FADE_IN ||
+ property == SubtitleContentProperty::FADE_OUT
+ ) {
+
+ /* These changes just need the pieces' decoders to be reset.
+ It's quite possible that other changes could be handled by
+ this branch rather than the _have_valid_pieces = false branch
+ above. This would make things a lot faster.
+ */
+
+ reset_pieces ();
+ Changed (frequent);
+
} else if (
property == ContentProperty::VIDEO_FRAME_RATE ||
property == SubtitleContentProperty::USE ||
property == SubtitleContentProperty::X_OFFSET ||
property == SubtitleContentProperty::Y_OFFSET ||
property == SubtitleContentProperty::X_SCALE ||
- property == SubtitleContentProperty::Y_SCALE ||
property == SubtitleContentProperty::FONTS ||
property == VideoContentProperty::CROP ||
property == VideoContentProperty::SCALE ||
property == VideoContentProperty::FADE_IN ||
- property == VideoContentProperty::FADE_OUT ||
- property == VideoContentProperty::COLOUR_CONVERSION
+ property == VideoContentProperty::FADE_OUT
) {
Changed (frequent);
/* Text subtitles (rendered to an image) */
if (!ps.text.empty ()) {
- list<PositionImage> s = render_subtitles (ps.text, ps.fonts, _video_container_size);
+ list<PositionImage> s = render_subtitles (ps.text, ps.fonts, _video_container_size, time);
copy (s.begin (), s.end (), back_inserter (sub_images));
}
shared_ptr<PlayerVideo> (
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 ()
)
{
list<shared_ptr<Piece> > subs = overlaps (time, time + length, has_subtitle);
- PlayerSubtitles ps (time, length);
+ PlayerSubtitles ps (time);
for (list<shared_ptr<Piece> >::const_iterator j = subs.begin(); j != subs.end(); ++j) {
if (!(*j)->content->subtitle->use () || (!_always_burn_subtitles && (burnt != (*j)->content->subtitle->burn ()))) {
}
s.set_in (dcp::Time(content_subtitle_to_dcp (*j, ts.period().from).seconds(), 1000));
s.set_out (dcp::Time(content_subtitle_to_dcp (*j, ts.period().to).seconds(), 1000));
- ps.text.push_back (s);
+ ps.text.push_back (SubtitleString (s, (*j)->content->subtitle->outline_width()));
ps.add_fonts ((*j)->content->subtitle->fonts ());
}
}
scoped_ptr<DCPDecoder> decoder;
try {
- decoder.reset (new DCPDecoder (j, _film->log(), false));
+ decoder.reset (new DCPDecoder (j, _film->log()));
} catch (...) {
return a;
}
int64_t offset = 0;
BOOST_FOREACH (shared_ptr<dcp::Reel> k, decoder->reels()) {
+
+ DCPOMATIC_ASSERT (j->video_frame_rate ());
+ double const cfr = j->video_frame_rate().get();
+ Frame const trim_start = j->trim_start().frames_round (cfr);
+ Frame const trim_end = j->trim_end().frames_round (cfr);
+
DCPTime const from = i->position() + DCPTime::from_frames (offset, _film->video_frame_rate());
if (j->reference_video ()) {
+ DCPOMATIC_ASSERT (k->main_picture ());
+ k->main_picture()->set_entry_point (trim_start);
+ k->main_picture()->set_duration (k->main_picture()->intrinsic_duration() - trim_start - trim_end);
a.push_back (
ReferencedReelAsset (
k->main_picture (),
}
if (j->reference_audio ()) {
+ DCPOMATIC_ASSERT (k->main_sound ());
+ k->main_sound()->set_entry_point (trim_start);
+ k->main_sound()->set_duration (k->main_sound()->intrinsic_duration() - trim_start - trim_end);
a.push_back (
ReferencedReelAsset (
k->main_sound (),
if (j->reference_subtitle ()) {
DCPOMATIC_ASSERT (k->main_subtitle ());
+ k->main_subtitle()->set_entry_point (trim_start);
+ k->main_subtitle()->set_duration (k->main_subtitle()->intrinsic_duration() - trim_start - trim_end);
a.push_back (
ReferencedReelAsset (
k->main_subtitle (),
return overlaps;
}
+
+void
+Player::reset_pieces ()
+{
+ BOOST_FOREACH (shared_ptr<Piece> i, _pieces) {
+ i->decoder->reset ();
+ }
+}