X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fplayer.cc;h=ebec19b2dc40f2d86da3c51865e05eb1d9105a6e;hb=73f52e94953848c696725defd3d7f5c4c30707e2;hp=bb1a4cdeb582298d8d22bd9cc1fcda08e4bf241c;hpb=4616b19fb5241a54c9d57f7a91bb975f41aed14b;p=dcpomatic.git diff --git a/src/lib/player.cc b/src/lib/player.cc index bb1a4cdeb..ebec19b2d 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -41,7 +41,7 @@ #include "render_subtitles.h" #include "config.h" #include "content_video.h" -#include "player_video_frame.h" +#include "player_video.h" #include "frame_rate_change.h" #define LOG_GENERAL(...) _film->log()->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL); @@ -223,24 +223,17 @@ Player::film_changed (Film::Property p) } list -Player::process_content_image_subtitles (shared_ptr content, list > subs) const +Player::transform_image_subtitles (list subs) const { list all; - for (list >::const_iterator i = subs.begin(); i != subs.end(); ++i) { - if (!(*i)->image) { + for (list::const_iterator i = subs.begin(); i != subs.end(); ++i) { + if (!i->image) { continue; } - dcpomatic::Rect in_rect = (*i)->rectangle; - dcp::Size scaled_size; - - in_rect.x += content->subtitle_x_offset (); - in_rect.y += content->subtitle_y_offset (); - - /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */ - scaled_size.width = in_rect.width * _video_container_size.width * content->subtitle_scale (); - scaled_size.height = in_rect.height * _video_container_size.height * content->subtitle_scale (); + /* We will scale the subtitle up to fit _video_container_size */ + dcp::Size scaled_size (i->rectangle.width * _video_container_size.width, i->rectangle.height * _video_container_size.height); /* Then we need a corrective translation, consisting of two parts: * @@ -256,15 +249,15 @@ Player::process_content_image_subtitles (shared_ptr content, li all.push_back ( PositionImage ( - (*i)->image->scale ( + i->image->scale ( scaled_size, Scaler::from_id ("bicubic"), - (*i)->image->pixel_format (), + i->image->pixel_format (), true ), Position ( - rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - content->subtitle_scale ()) / 2))), - rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - content->subtitle_scale ()) / 2))) + rint (_video_container_size.width * i->rectangle.x), + rint (_video_container_size.height * i->rectangle.y) ) ) ); @@ -273,31 +266,19 @@ Player::process_content_image_subtitles (shared_ptr content, li return all; } -list -Player::process_content_text_subtitles (list > sub) const -{ - list all; - for (list >::const_iterator i = sub.begin(); i != sub.end(); ++i) { - if (!(*i)->subs.empty ()) { - all.push_back (render_subtitles ((*i)->subs, _video_container_size)); - } - } - - return all; -} - void Player::set_approximate_size () { _approximate_size = true; } -shared_ptr -Player::black_player_video_frame () const +shared_ptr +Player::black_player_video_frame (DCPTime time) const { - return shared_ptr ( - new PlayerVideoFrame ( + return shared_ptr ( + new PlayerVideo ( shared_ptr (new RawImageProxy (_black_image, _film->log ())), + time, Crop (), _video_container_size, _video_container_size, @@ -309,8 +290,8 @@ Player::black_player_video_frame () const ); } -/** @return All PlayerVideoFrames at the given time (there may be two frames for 3D) */ -list > +/** @return All PlayerVideos at the given time (there may be two frames for 3D) */ +list > Player::get_video (DCPTime time, bool accurate) { if (!_have_valid_pieces) { @@ -322,13 +303,13 @@ Player::get_video (DCPTime time, bool accurate) time + DCPTime::from_frames (1, _film->video_frame_rate ()) ); - list > pvf; + list > pvf; if (ov.empty ()) { /* No video content at this time */ - pvf.push_back (black_player_video_frame ()); + pvf.push_back (black_player_video_frame (time)); } else { - /* Create a PlayerVideoFrame from the content's video at this time */ + /* Create a PlayerVideo from the content's video at this time */ shared_ptr piece = ov.back (); shared_ptr decoder = dynamic_pointer_cast (piece->decoder); @@ -338,7 +319,7 @@ Player::get_video (DCPTime time, bool accurate) list content_video = decoder->get_video (dcp_to_content_video (piece, time), accurate); if (content_video.empty ()) { - pvf.push_back (black_player_video_frame ()); + pvf.push_back (black_player_video_frame (time)); return pvf; } @@ -350,9 +331,10 @@ Player::get_video (DCPTime time, bool accurate) for (list::const_iterator i = content_video.begin(); i != content_video.end(); ++i) { pvf.push_back ( - shared_ptr ( - new PlayerVideoFrame ( + shared_ptr ( + new PlayerVideo ( i->image, + content_video_to_dcp (piece, i->frame), content->crop (), image_size, _video_container_size, @@ -366,45 +348,21 @@ Player::get_video (DCPTime time, bool accurate) } } - /* Add subtitles to whatever PlayerVideoFrames we got */ - - list > subs = overlaps ( - time, - time + DCPTime::from_frames (1, _film->video_frame_rate ()) - ); + /* Add subtitles (for possible burn-in) to whatever PlayerVideos we got */ + + PlayerSubtitles ps = get_subtitles (time, DCPTime::from_frames (1, _film->video_frame_rate ()), false); list sub_images; - - for (list >::const_iterator j = subs.begin(); j != subs.end(); ++j) { - shared_ptr subtitle_content = dynamic_pointer_cast ((*j)->content); - if (!subtitle_content->subtitle_use ()) { - continue; - } - shared_ptr subtitle_decoder = dynamic_pointer_cast ((*j)->decoder); - 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 ()); + /* Image subtitles */ + list c = transform_image_subtitles (ps.image); + copy (c.begin(), c.end(), back_inserter (sub_images)); - list > image_subtitles = subtitle_decoder->get_image_subtitles (ContentTimePeriod (from, to)); - if (!image_subtitles.empty ()) { - list im = process_content_image_subtitles ( - subtitle_content, - image_subtitles - ); - - copy (im.begin(), im.end(), back_inserter (sub_images)); - } - - list > text_subtitles = subtitle_decoder->get_text_subtitles (ContentTimePeriod (from, to)); - if (!text_subtitles.empty ()) { - list im = process_content_text_subtitles (text_subtitles); - copy (im.begin(), im.end(), back_inserter (sub_images)); - } - } + /* Text subtitles (rendered to images) */ + sub_images.push_back (render_subtitles (ps.text, _video_container_size)); if (!sub_images.empty ()) { - for (list >::const_iterator i = pvf.begin(); i != pvf.end(); ++i) { + for (list >::const_iterator i = pvf.begin(); i != pvf.end(); ++i) { (*i)->set_subtitle (merge (sub_images)); } } @@ -501,19 +459,30 @@ Player::dcp_to_content_video (shared_ptr piece, DCPTime t) const { /* s is the offset of t from the start position of this content */ DCPTime s = t - piece->content->position (); - s = DCPTime (max (int64_t (0), s.get ())); + s = DCPTime (max (DCPTime::Type (0), s.get ())); s = DCPTime (min (piece->content->length_after_trim().get(), s.get())); /* Convert this to the content frame */ return DCPTime (s + piece->content->trim_start()).frames (_film->video_frame_rate()) * piece->frc.factor (); } +DCPTime +Player::content_video_to_dcp (shared_ptr piece, VideoFrame f) const +{ + DCPTime t = DCPTime::from_frames (f / piece->frc.factor (), _film->video_frame_rate()) - piece->content->trim_start () + piece->content->position (); + if (t < DCPTime ()) { + t = DCPTime (); + } + + return t; +} + AudioFrame Player::dcp_to_content_audio (shared_ptr piece, DCPTime t) const { /* s is the offset of t from the start position of this content */ DCPTime s = t - piece->content->position (); - s = DCPTime (max (int64_t (0), s.get ())); + s = DCPTime (max (DCPTime::Type (0), s.get ())); s = DCPTime (min (piece->content->length_after_trim().get(), s.get())); /* Convert this to the content frame */ @@ -525,7 +494,7 @@ Player::dcp_to_content_subtitle (shared_ptr piece, DCPTime t) const { /* s is the offset of t from the start position of this content */ DCPTime s = t - piece->content->position (); - s = DCPTime (max (int64_t (0), s.get ())); + s = DCPTime (max (DCPTime::Type (0), s.get ())); s = DCPTime (min (piece->content->length_after_trim().get(), s.get())); return ContentTime (s + piece->content->trim_start(), piece->frc); @@ -543,3 +512,48 @@ Player::statistics () const { return _statistics; } + +PlayerSubtitles +Player::get_subtitles (DCPTime time, DCPTime length, bool starting) +{ + list > subs = overlaps (time, time + length); + + PlayerSubtitles ps (time, length); + + for (list >::const_iterator j = subs.begin(); j != subs.end(); ++j) { + shared_ptr subtitle_content = dynamic_pointer_cast ((*j)->content); + if (!subtitle_content->subtitle_use ()) { + continue; + } + + shared_ptr subtitle_decoder = dynamic_pointer_cast ((*j)->decoder); + 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); + for (list::iterator i = image.begin(); i != image.end(); ++i) { + + /* Apply content's subtitle offsets */ + i->sub.rectangle.x += subtitle_content->subtitle_x_offset (); + i->sub.rectangle.y += subtitle_content->subtitle_y_offset (); + + /* Apply content's subtitle scale */ + i->sub.rectangle.width *= subtitle_content->subtitle_scale (); + i->sub.rectangle.height *= subtitle_content->subtitle_scale (); + + /* Apply a corrective translation to keep the subtitle centred after that scale */ + i->sub.rectangle.x -= i->sub.rectangle.width * (subtitle_content->subtitle_scale() - 1); + i->sub.rectangle.y -= i->sub.rectangle.height * (subtitle_content->subtitle_scale() - 1); + + ps.image.push_back (i->sub); + } + + list text = subtitle_decoder->get_text_subtitles (ContentTimePeriod (from, to), starting); + for (list::const_iterator i = text.begin(); i != text.end(); ++i) { + copy (i->subs.begin(), i->subs.end(), back_inserter (ps.text)); + } + } + + return ps; +}