X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fsubtitle.cc;h=0d18861c455f69f2d2649730f93d898d0ed66463;hb=e01961397fbf87c69da4c8a8e79cef3c16480d3a;hp=f851d5643a34792ddbfe7bf12694d70407db22f7;hpb=d7d1a6b8d97390e57ce8d2442d90d25f97d8b562;p=dcpomatic.git diff --git a/src/lib/subtitle.cc b/src/lib/subtitle.cc index f851d5643..0d18861c4 100644 --- a/src/lib/subtitle.cc +++ b/src/lib/subtitle.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012 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,113 +17,57 @@ */ -/** @file src/subtitle.cc - * @brief Representations of subtitles. - */ - #include "subtitle.h" +#include "subtitle_content.h" +#include "piece.h" #include "image.h" -#include "exceptions.h" -#include "film_state.h" - -using namespace std; -using namespace boost; - -/** Construct a TimedSubtitle. This is a subtitle image, position, - * and a range of time over which it should be shown. - * @param sub AVSubtitle to read. - */ -TimedSubtitle::TimedSubtitle (AVSubtitle const & sub) +#include "scaler.h" +#include "film.h" + +using boost::shared_ptr; +using boost::dynamic_pointer_cast; +using boost::weak_ptr; + +Subtitle::Subtitle (shared_ptr film, libdcp::Size video_container_size, weak_ptr weak_piece, shared_ptr image, dcpomatic::Rect rect, Time from, Time to) + : _piece (weak_piece) + , _in_image (image) + , _in_rect (rect) + , _in_from (from) + , _in_to (to) { - assert (sub.rects > 0); - - /* subtitle PTS in seconds */ - float const packet_time = (sub.pts / AV_TIME_BASE) + float (sub.pts % AV_TIME_BASE) / 1e6; - - /* hence start time for this sub */ - _from = packet_time + (double (sub.start_display_time) / 1e3); - _to = packet_time + (double (sub.end_display_time) / 1e3); + update (film, video_container_size); +} - if (sub.num_rects > 1) { - throw DecodeError ("multi-part subtitles not yet supported"); +void +Subtitle::update (shared_ptr film, libdcp::Size video_container_size) +{ + shared_ptr piece = _piece.lock (); + if (!piece) { + return; } - AVSubtitleRect const * rect = sub.rects[0]; - - if (rect->type != SUBTITLE_BITMAP) { - throw DecodeError ("non-bitmap subtitles not yet supported"); - } - - shared_ptr image (new AlignedImage (PIX_FMT_RGBA, Size (rect->w, rect->h))); - - /* Start of the first line in the subtitle */ - uint8_t* sub_p = rect->pict.data[0]; - /* sub_p looks up into a RGB palette which is here */ - uint32_t const * palette = (uint32_t *) rect->pict.data[1]; - /* Start of the output data */ - uint32_t* out_p = (uint32_t *) image->data()[0]; - - for (int y = 0; y < rect->h; ++y) { - uint8_t* sub_line_p = sub_p; - uint32_t* out_line_p = out_p; - for (int x = 0; x < rect->w; ++x) { - *out_line_p++ = palette[*sub_line_p++]; - } - sub_p += rect->pict.linesize[0]; - out_p += image->stride()[0] / sizeof (uint32_t); + if (!_in_image) { + _out_image.reset (); + return; } - _subtitle.reset (new Subtitle (Position (rect->x, rect->y), image)); -} - -/** @param t Time in seconds from the start of the film */ -bool -TimedSubtitle::displayed_at (double t) const -{ - return t >= _from && t <= _to; -} - -/** Construct a subtitle, which is an image and a position. - * @param p Position within the (uncropped) source frame. - * @param i Image of the subtitle (should be RGBA). - */ -Subtitle::Subtitle (Position p, shared_ptr i) - : _position (p) - , _image (i) -{ + shared_ptr sc = dynamic_pointer_cast (piece->content); + assert (sc); -} + dcpomatic::Rect in_rect = _in_rect; + libdcp::Size scaled_size; -/** Given the area of a subtitle, work out the area it should - * take up when its video frame is scaled up, and it is optionally - * itself scaled and offset. - * @param target_x_scale the x scaling of the video frame that the subtitle is in. - * @param target_y_scale the y scaling of the video frame that the subtitle is in. - * @param sub_area The area of the subtitle within the original source. - * @param subtitle_offset y offset to apply to the subtitle position (+ve is down) - * in the coordinate space of the source. - * @param subtitle_scale scaling factor to apply to the subtitle image. - */ -Rect -subtitle_transformed_area ( - float target_x_scale, float target_y_scale, - Rect sub_area, int subtitle_offset, float subtitle_scale - ) -{ - Rect tx; - - sub_area.y += subtitle_offset; + in_rect.x += sc->subtitle_x_offset (); + in_rect.y += sc->subtitle_y_offset (); - /* We will scale the subtitle by the same amount as the video frame, and also by the additional - subtitle_scale - */ - tx.width = sub_area.width * target_x_scale * subtitle_scale; - tx.height = sub_area.height * target_y_scale * subtitle_scale; + /* 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 * sc->subtitle_scale (); + scaled_size.height = in_rect.height * video_container_size.height * sc->subtitle_scale (); /* Then we need a corrective translation, consisting of two parts: * - * 1. that which is the result of the scaling of the subtitle by target_x_scale and target_y_scale; this will be - * sub_area.x * target_x_scale and sub_area.y * target_y_scale. + * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be + * rect.x * _video_container_size.width and rect.y * _video_container_size.height. * * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and @@ -132,15 +76,41 @@ subtitle_transformed_area ( * Combining these two translations gives these expressions. */ - tx.x = target_x_scale * (sub_area.x + (sub_area.width * (1 - subtitle_scale) / 2)); - tx.y = target_y_scale * (sub_area.y + (sub_area.height * (1 - subtitle_scale) / 2)); + _out_position.x = rint (video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2))); + _out_position.y = rint (video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2))); + + _out_image = _in_image->scale ( + scaled_size, + Scaler::from_id ("bicubic"), + _in_image->pixel_format (), + true + ); + + /* XXX: hack */ + Time from = _in_from; + Time to = _in_to; + shared_ptr vc = dynamic_pointer_cast (piece->content); + if (vc) { + from = rint (from * vc->video_frame_rate() / film->video_frame_rate()); + to = rint (to * vc->video_frame_rate() / film->video_frame_rate()); + } + + _out_from = from + piece->content->position (); + _out_to = to + piece->content->position (); - return tx; + check_out_to (); } -/** @return area that this subtitle take up, in the original uncropped source's coordinate space */ -Rect -Subtitle::area () const +bool +Subtitle::covers (Time t) const { - return Rect (_position.x, _position.y, _image->size().width, _image->size().height); + return _out_from <= t && t <= _out_to; +} + +void +Subtitle::check_out_to () +{ + if (_stop && _out_to > _stop.get ()) { + _out_to = _stop.get (); + } }