diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/bitmap_text.h | 2 | ||||
| -rw-r--r-- | src/lib/player.cc | 67 | ||||
| -rw-r--r-- | src/lib/player.h | 1 | ||||
| -rw-r--r-- | src/lib/player_text.cc | 28 | ||||
| -rw-r--r-- | src/lib/player_text.h | 11 | ||||
| -rw-r--r-- | src/lib/player_video.cc | 102 | ||||
| -rw-r--r-- | src/lib/player_video.h | 14 | ||||
| -rw-r--r-- | src/lib/rect.h | 3 | ||||
| -rw-r--r-- | src/lib/render_text.cc | 45 | ||||
| -rw-r--r-- | src/lib/render_text.h | 8 | ||||
| -rw-r--r-- | src/lib/string_text.h | 2 | ||||
| -rw-r--r-- | src/lib/wscript | 3 | ||||
| -rw-r--r-- | src/wx/film_viewer.cc | 5 |
13 files changed, 186 insertions, 105 deletions
diff --git a/src/lib/bitmap_text.h b/src/lib/bitmap_text.h index 2314c2db0..9324e1d34 100644 --- a/src/lib/bitmap_text.h +++ b/src/lib/bitmap_text.h @@ -45,4 +45,6 @@ public: dcpomatic::Rect<double> rectangle; }; +extern bool operator== (BitmapText const & a, BitmapText const & b); + #endif diff --git a/src/lib/player.cc b/src/lib/player.cc index c88be5826..51c89b362 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -345,7 +345,8 @@ Player::black_player_video_frame (Eyes eyes) const PresetColourConversion::all().front().conversion, VIDEO_RANGE_FULL, boost::weak_ptr<Content>(), - boost::optional<Frame>() + boost::optional<DCPTime>(), + _film->video_frame_rate() ) ); } @@ -713,52 +714,6 @@ Player::pass () return done; } -/** @return Open subtitles for the frame at the given time, converted to images */ -optional<PositionImage> -Player::open_subtitles_for_frame (DCPTime time) const -{ - list<PositionImage> captions; - int const vfr = _film->video_frame_rate(); - - BOOST_FOREACH ( - PlayerText j, - _active_texts[TEXT_OPEN_SUBTITLE].get_burnt(DCPTimePeriod(time, time + DCPTime::from_frames(1, vfr)), _always_burn_open_subtitles) - ) { - - /* Bitmap subtitles */ - BOOST_FOREACH (BitmapText i, j.bitmap) { - if (!i.image) { - continue; - } - - /* i.image will already have been scaled to fit _video_container_size */ - dcp::Size scaled_size (i.rectangle.width * _video_container_size.width, i.rectangle.height * _video_container_size.height); - - captions.push_back ( - PositionImage ( - i.image, - Position<int> ( - lrint (_video_container_size.width * i.rectangle.x), - lrint (_video_container_size.height * i.rectangle.y) - ) - ) - ); - } - - /* String subtitles (rendered to an image) */ - if (!j.string.empty ()) { - list<PositionImage> s = render_text (j.string, j.fonts, _video_container_size, time, vfr); - copy (s.begin(), s.end(), back_inserter (captions)); - } - } - - if (captions.empty ()) { - return optional<PositionImage> (); - } - - return merge (captions); -} - void Player::video (weak_ptr<Piece> wp, ContentVideo video) { @@ -847,7 +802,8 @@ Player::video (weak_ptr<Piece> wp, ContentVideo video) piece->content->video->colour_conversion(), piece->content->video->range(), piece->content, - video.frame + time, + _film->video_frame_rate() ) ); @@ -950,10 +906,11 @@ Player::bitmap_text_start (weak_ptr<Piece> wp, weak_ptr<const TextContent> wc, C subtitle.sub.rectangle.width *= text->x_scale (); subtitle.sub.rectangle.height *= text->y_scale (); - PlayerText ps; shared_ptr<Image> image = subtitle.sub.image; /* We will scale the subtitle up to fit _video_container_size */ dcp::Size scaled_size (subtitle.sub.rectangle.width * _video_container_size.width, subtitle.sub.rectangle.height * _video_container_size.height); + PlayerText ps; + ps.content = text; ps.bitmap.push_back (BitmapText(image->scale(scaled_size, dcp::YUV_TO_RGB_REC601, image->pixel_format(), true, _fast), subtitle.sub.rectangle)); DCPTime from (content_time_to_dcp (piece, subtitle.from())); @@ -970,6 +927,7 @@ Player::plain_text_start (weak_ptr<Piece> wp, weak_ptr<const TextContent> wc, Co } PlayerText ps; + ps.content = text; DCPTime const from (content_time_to_dcp (piece, subtitle.from())); if (from > piece->content->end(_film)) { @@ -977,8 +935,8 @@ Player::plain_text_start (weak_ptr<Piece> wp, weak_ptr<const TextContent> wc, Co } BOOST_FOREACH (dcp::SubtitleString s, subtitle.subs) { - s.set_h_position (s.h_position() + text->x_offset ()); - s.set_v_position (s.v_position() + text->y_offset ()); +// s.set_h_position (s.h_position() + text->x_offset ()); +// s.set_v_position (s.v_position() + text->y_offset ()); float const xs = text->x_scale(); float const ys = text->y_scale(); float size = s.size(); @@ -1126,10 +1084,9 @@ Player::do_emit_video (shared_ptr<PlayerVideo> pv, DCPTime time) } } - optional<PositionImage> subtitles = open_subtitles_for_frame (time); - if (subtitles) { - pv->set_text (subtitles.get ()); - } + int const vfr = _film->video_frame_rate(); + list<PlayerText> subtitles = _active_texts[TEXT_OPEN_SUBTITLE].get_burnt(DCPTimePeriod(time, time + DCPTime::from_frames(1, vfr)), _always_burn_open_subtitles); + pv->set_text (subtitles); Video (pv, time); } diff --git a/src/lib/player.h b/src/lib/player.h index e99c345bb..37b3f6c1b 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -135,7 +135,6 @@ private: std::pair<boost::shared_ptr<AudioBuffers>, dcpomatic::DCPTime> discard_audio ( boost::shared_ptr<const AudioBuffers> audio, dcpomatic::DCPTime time, dcpomatic::DCPTime discard_to ) const; - boost::optional<PositionImage> open_subtitles_for_frame (dcpomatic::DCPTime time) const; void emit_video (boost::shared_ptr<PlayerVideo> pv, dcpomatic::DCPTime time); void do_emit_video (boost::shared_ptr<PlayerVideo> pv, dcpomatic::DCPTime time); void emit_audio (boost::shared_ptr<AudioBuffers> data, dcpomatic::DCPTime time); diff --git a/src/lib/player_text.cc b/src/lib/player_text.cc index d31c7d024..ab28f9221 100644 --- a/src/lib/player_text.cc +++ b/src/lib/player_text.cc @@ -41,3 +41,31 @@ PlayerText::add_fonts (list<shared_ptr<Font> > fonts_) } } } + +bool +operator== (PlayerText const & a, PlayerText const & b) +{ + if (a.fonts.size() != b.fonts.size()) { + return false; + } + + { + list<shared_ptr<Font> >::const_iterator i = a.fonts.begin(); + list<shared_ptr<Font> >::const_iterator j = b.fonts.begin(); + while (i != a.fonts.end()) { + if (**i != **j) { + return false; + } + ++i; + ++j; + } + } + + return a.bitmap == b.bitmap && a.string == b.string; +} + +bool +operator!= (PlayerText const & a, PlayerText const & b) +{ + return !(a == b); +} diff --git a/src/lib/player_text.h b/src/lib/player_text.h index fb1d846d8..37c55db4a 100644 --- a/src/lib/player_text.h +++ b/src/lib/player_text.h @@ -18,17 +18,20 @@ */ -#ifndef DCPOMATIC_PLAYER_CAPTION_H -#define DCPOMATIC_PLAYER_CAPTION_H +#ifndef DCPOMATIC_PLAYER_TEXT_H +#define DCPOMATIC_PLAYER_TEXT_H #include "bitmap_text.h" #include "dcpomatic_time.h" #include "string_text.h" +#include <boost/weak_ptr.hpp> namespace dcpomatic { class Font; } +class TextContent; + /** A set of text (subtitle/CCAP) which span the same time period */ class PlayerText { @@ -36,9 +39,13 @@ public: void add_fonts (std::list<boost::shared_ptr<dcpomatic::Font> > fonts_); std::list<boost::shared_ptr<dcpomatic::Font> > fonts; + boost::weak_ptr<const TextContent> content; /** BitmapTexts, with their rectangles transformed as specified by their content */ std::list<BitmapText> bitmap; std::list<StringText> string; }; +extern bool operator== (PlayerText const & a, PlayerText const & b); +extern bool operator!= (PlayerText const & a, PlayerText const & b); + #endif diff --git a/src/lib/player_video.cc b/src/lib/player_video.cc index 75479136f..fa550f346 100644 --- a/src/lib/player_video.cc +++ b/src/lib/player_video.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2018 Carl Hetherington <cth@carlh.net> + Copyright (C) 2013-2019 Carl Hetherington <cth@carlh.net> This file is part of DCP-o-matic. @@ -25,6 +25,8 @@ #include "image_proxy.h" #include "j2k_image_proxy.h" #include "film.h" +#include "render_text.h" +#include "text_content.h" #include <dcp/raw_convert.h> extern "C" { #include <libavutil/pixfmt.h> @@ -35,6 +37,7 @@ extern "C" { using std::string; using std::cout; using std::pair; +using std::list; using boost::shared_ptr; using boost::weak_ptr; using boost::dynamic_pointer_cast; @@ -54,7 +57,8 @@ PlayerVideo::PlayerVideo ( optional<ColourConversion> colour_conversion, VideoRange video_range, weak_ptr<Content> content, - optional<Frame> video_frame + optional<dcpomatic::DCPTime> time, + int video_frame_rate ) : _in (in) , _crop (crop) @@ -66,12 +70,15 @@ PlayerVideo::PlayerVideo ( , _colour_conversion (colour_conversion) , _video_range (video_range) , _content (content) - , _video_frame (video_frame) + , _time (time) + , _video_frame_rate (video_frame_rate) + , _image_dirty (false) { } PlayerVideo::PlayerVideo (shared_ptr<cxml::Node> node, shared_ptr<Socket> socket) + : _image_dirty (false) { _crop = Crop (node); _fade = node->optional_number_child<double> ("Fade"); @@ -95,14 +102,16 @@ PlayerVideo::PlayerVideo (shared_ptr<cxml::Node> node, shared_ptr<Socket> socket image->read_from_socket (socket); + /* XXX_b _text = PositionImage (image, Position<int> (node->number_child<int> ("SubtitleX"), node->number_child<int> ("SubtitleY"))); + */ } } void -PlayerVideo::set_text (PositionImage image) +PlayerVideo::set_text (list<PlayerText> text) { - _text = image; + _text = text; } shared_ptr<Image> @@ -111,7 +120,7 @@ PlayerVideo::image (function<AVPixelFormat (AVPixelFormat)> pixel_format, bool a /* XXX: this assumes that image() and prepare() are only ever called with the same parameters (except crop, inter size, out size, fade) */ boost::mutex::scoped_lock lm (_mutex); - if (!_image || _crop != _image_crop || _inter_size != _image_inter_size || _out_size != _image_out_size || _fade != _image_fade) { + if (!_image || _image_dirty) { make_image (pixel_format, aligned, fast); } return _image; @@ -172,13 +181,52 @@ PlayerVideo::make_image (function<AVPixelFormat (AVPixelFormat)> pixel_format, b total_crop, _inter_size, _out_size, yuv_to_rgb, _video_range, pixel_format (im->pixel_format()), aligned, fast ); - if (_text) { - _image->alpha_blend (Image::ensure_aligned (_text->image), _text->position); + list<PositionImage> subtitles; + + BOOST_FOREACH (PlayerText i, _text) { + + /* Bitmap subtitles */ + BOOST_FOREACH (BitmapText j, i.bitmap) { + if (!j.image) { + continue; + } + + /* j.image will already have been scaled to fit _out_size */ + dcp::Size scaled_size (j.rectangle.width * _out_size.width, j.rectangle.height * _out_size.height); + + subtitles.push_back ( + PositionImage ( + j.image, + Position<int> ( + lrint (_out_size.width * j.rectangle.x), + lrint (_out_size.height * j.rectangle.y) + ) + ) + ); + } + + /* String subtitles (rendered to an image) */ + if (!i.string.empty ()) { + DCPOMATIC_ASSERT (_time); + shared_ptr<const TextContent> content = i.content.lock (); + DCPOMATIC_ASSERT (content); + list<PositionImage> s = render_text ( + i.string, i.fonts, _out_size, *_time, _video_frame_rate, content->x_offset(), content->y_offset() + ); + copy (s.begin(), s.end(), back_inserter (subtitles)); + } + } + + if (!subtitles.empty()) { + PositionImage pi = merge (subtitles); + _image->alpha_blend (Image::ensure_aligned(pi.image), pi.position); } if (_fade) { _image->fade (_fade.get ()); } + + _image_dirty = false; } void @@ -199,21 +247,25 @@ PlayerVideo::add_metadata (xmlpp::Node* node) const if (_colour_conversion) { _colour_conversion.get().as_xml (node); } + /* XXX_b if (_text) { node->add_child ("SubtitleWidth")->add_child_text (raw_convert<string> (_text->image->size().width)); node->add_child ("SubtitleHeight")->add_child_text (raw_convert<string> (_text->image->size().height)); node->add_child ("SubtitleX")->add_child_text (raw_convert<string> (_text->position.x)); node->add_child ("SubtitleY")->add_child_text (raw_convert<string> (_text->position.y)); } + */ } void PlayerVideo::send_binary (shared_ptr<Socket> socket) const { _in->send_binary (socket); + /* XXX_b if (_text) { _text->image->write_to_socket (socket); } + */ } bool @@ -226,7 +278,7 @@ PlayerVideo::has_j2k () const return false; } - return _crop == Crop () && _out_size == j2k->size() && !_text && !_fade && !_colour_conversion; + return _crop == Crop() && _out_size == j2k->size() && _text.empty() && !_fade && !_colour_conversion; } Data @@ -258,18 +310,22 @@ PlayerVideo::same (shared_ptr<const PlayerVideo> other) const return false; } - if ((!_text && other->_text) || (_text && !other->_text)) { - /* One has a text and the other doesn't */ + if (_text.size() != other->_text.size()) { + /* Different text counts */ return false; } - if (_text && other->_text && !_text->same (other->_text.get ())) { - /* They both have texts but they are different */ - return false; + list<PlayerText>::const_iterator i = _text.begin(); + list<PlayerText>::const_iterator j = other->_text.begin(); + while (i != _text.end()) { + if (*i != *j) { + /* Same number of texts but one differs */ + return false; + } + ++i; + ++j; } - /* Now neither has subtitles */ - return _in->same (other->_in); } @@ -317,7 +373,8 @@ PlayerVideo::shallow_copy () const _colour_conversion, _video_range, _content, - _video_frame + _time, + _video_frame_rate ) ); } @@ -329,16 +386,23 @@ bool PlayerVideo::reset_metadata (shared_ptr<const Film> film, dcp::Size video_container_size, dcp::Size film_frame_size) { shared_ptr<Content> content = _content.lock(); - if (!content || !_video_frame) { + if (!content || !_time) { return false; } _crop = content->video->crop(); - _fade = content->video->fade(film, _video_frame.get()); + _fade = content->video->fade(film, _time->frames_round(_video_frame_rate)); _inter_size = content->video->scale().size(content->video, video_container_size, film_frame_size); _out_size = video_container_size; _colour_conversion = content->video->colour_conversion(); _video_range = content->video->range(); + /* XXX_b _text looks into content directly itself, as maybe the other parameters should; we could just + have a pointer to the content and get stuff from there. + */ + + /* XXX_b thread safety of _image_dirty? */ + _image_dirty = true; + return true; } diff --git a/src/lib/player_video.h b/src/lib/player_video.h index 3cd559409..f62287a64 100644 --- a/src/lib/player_video.h +++ b/src/lib/player_video.h @@ -26,6 +26,7 @@ #include "dcpomatic_time.h" #include "colour_conversion.h" #include "position_image.h" +#include "player_text.h" extern "C" { #include <libavutil/pixfmt.h> } @@ -56,14 +57,15 @@ public: boost::optional<ColourConversion>, VideoRange video_range, boost::weak_ptr<Content>, - boost::optional<Frame> + boost::optional<dcpomatic::DCPTime>, + int video_frame_rate ); PlayerVideo (boost::shared_ptr<cxml::Node>, boost::shared_ptr<Socket>); boost::shared_ptr<PlayerVideo> shallow_copy () const; - void set_text (PositionImage); + void set_text (std::list<PlayerText>); void prepare (boost::function<AVPixelFormat (AVPixelFormat)> pixel_format, bool aligned, bool fast); boost::shared_ptr<Image> image (boost::function<AVPixelFormat (AVPixelFormat)> pixel_format, bool aligned, bool fast) const; @@ -119,13 +121,14 @@ private: Part _part; boost::optional<ColourConversion> _colour_conversion; VideoRange _video_range; - boost::optional<PositionImage> _text; + std::list<PlayerText> _text; /** Content that we came from. This is so that reset_metadata() can work, and also * for variant:swaroop's non-skippable ads. */ boost::weak_ptr<Content> _content; - /** Video frame that we came from. Again, this is for reset_metadata() */ - boost::optional<Frame> _video_frame; + /** Time that we came from. Again, this is for reset_metadata() */ + boost::optional<dcpomatic::DCPTime> _time; + int _video_frame_rate; mutable boost::mutex _mutex; mutable boost::shared_ptr<Image> _image; @@ -137,6 +140,7 @@ private: mutable dcp::Size _image_out_size; /** _fade that was used to make _image */ mutable boost::optional<double> _image_fade; + mutable bool _image_dirty; }; #endif diff --git a/src/lib/rect.h b/src/lib/rect.h index 4851ad007..07fb22dc9 100644 --- a/src/lib/rect.h +++ b/src/lib/rect.h @@ -24,6 +24,7 @@ #include "position.h" #include <boost/optional.hpp> #include <algorithm> +#include <cmath> /* Put this inside a namespace as Apple put a Rect in the global namespace */ @@ -114,6 +115,8 @@ public: } }; +extern bool operator== (Rect<double> const & a, Rect<double> const & b); + } #endif diff --git a/src/lib/render_text.cc b/src/lib/render_text.cc index 8b9d93423..dff702b78 100644 --- a/src/lib/render_text.cc +++ b/src/lib/render_text.cc @@ -92,7 +92,7 @@ set_source_rgba (Cairo::RefPtr<Cairo::Context> context, dcp::Colour colour, floa * at the same time and with the same fade in/out. */ static PositionImage -render_line (list<StringText> subtitles, list<shared_ptr<Font> > fonts, dcp::Size target, DCPTime time, int frame_rate) +render_line (list<StringText> subtitles, list<shared_ptr<Font> > fonts, dcp::Size target, DCPTime time, int frame_rate, double x_offset, double y_offset) { /* XXX: this method can only handle italic / bold changes mid-line, nothing else yet. @@ -263,14 +263,14 @@ render_line (list<StringText> subtitles, list<shared_ptr<Font> > fonts, dcp::Siz /* Shuffle the subtitle over very slightly if it has a border so that the left-hand side of the first character's border is not cut off. */ - int const x_offset = subtitles.front().effect() == dcp::BORDER ? (target.width / 600.0) : 0; + int const xoff = subtitles.front().effect() == dcp::BORDER ? (target.width / 600.0) : 0; /* Move down a bit so that accents on capital letters can be seen */ - int const y_offset = target.height / 100.0; + int const yoff = target.height / 100.0; if (subtitles.front().effect() == dcp::SHADOW) { /* Drop-shadow effect */ set_source_rgba (context, subtitles.front().effect_colour(), fade_factor); - context->move_to (x_offset + 4, y_offset + 4); + context->move_to (xoff + 4, yoff + 4); layout->add_to_cairo_context (context); context->fill (); } @@ -280,7 +280,7 @@ render_line (list<StringText> subtitles, list<shared_ptr<Font> > fonts, dcp::Siz set_source_rgba (context, subtitles.front().effect_colour(), fade_factor); context->set_line_width (subtitles.front().outline_width * target.width / 2048.0); context->set_line_join (Cairo::LINE_JOIN_ROUND); - context->move_to (x_offset, y_offset); + context->move_to (xoff, yoff); layout->add_to_cairo_context (context); context->stroke (); } @@ -301,65 +301,68 @@ render_line (list<StringText> subtitles, list<shared_ptr<Font> > fonts, dcp::Siz layout_width *= xscale; layout_height *= yscale; + double const h_pos = subtitles.front().h_position() + x_offset; + double const v_pos = subtitles.front().v_position() + y_offset; + int x = 0; - switch (subtitles.front().h_align ()) { + switch (subtitles.front().h_align()) { case dcp::HALIGN_LEFT: - /* h_position is distance between left of frame and left of subtitle */ - x = subtitles.front().h_position() * target.width; + /* h_pos is distance between left of frame and left of subtitle */ + x = h_pos * target.width; break; case dcp::HALIGN_CENTER: - /* h_position is distance between centre of frame and centre of subtitle */ - x = (0.5 + subtitles.front().h_position()) * target.width - layout_width / 2; + /* h_pos is distance between centre of frame and centre of subtitle */ + x = (0.5 + h_pos) * target.width - layout_width / 2; break; case dcp::HALIGN_RIGHT: - /* h_position is distance between right of frame and right of subtitle */ - x = (1.0 - subtitles.front().h_position()) * target.width - layout_width; + /* h_pos is distance between right of frame and right of subtitle */ + x = (1.0 - h_pos) * target.width - layout_width; break; } int y = 0; - switch (subtitles.front().v_align ()) { + switch (subtitles.front().v_align()) { case dcp::VALIGN_TOP: - /* SMPTE says that v_position is the distance between top + /* SMPTE says that v_pos is the distance between top of frame and top of subtitle, but this doesn't always seem to be the case in practice; Gunnar Ásgeirsson's Dolby server appears to put VALIGN_TOP subs with v_position as the distance between top of frame and bottom of subtitle. */ - y = subtitles.front().v_position() * target.height - layout_height; + y = v_pos * target.height - layout_height; break; case dcp::VALIGN_CENTER: /* v_position is distance between centre of frame and centre of subtitle */ - y = (0.5 + subtitles.front().v_position()) * target.height - layout_height / 2; + y = (0.5 + v_pos) * target.height - layout_height / 2; break; case dcp::VALIGN_BOTTOM: /* v_position is distance between bottom of frame and bottom of subtitle */ - y = (1.0 - subtitles.front().v_position()) * target.height - layout_height; + y = (1.0 - v_pos) * target.height - layout_height; break; } - return PositionImage (image, Position<int> (max (0, x), max (0, y))); + return PositionImage (image, Position<int>(max (0, x), max(0, y))); } /** @param time Time of the frame that these subtitles are going on. * @param frame_rate DCP frame rate. */ list<PositionImage> -render_text (list<StringText> subtitles, list<shared_ptr<Font> > fonts, dcp::Size target, DCPTime time, int frame_rate) +render_text (list<StringText> subtitles, list<shared_ptr<Font> > fonts, dcp::Size target, DCPTime time, int frame_rate, double x_offset, double y_offset) { list<StringText> pending; list<PositionImage> images; BOOST_FOREACH (StringText const & i, subtitles) { if (!pending.empty() && (i.v_align() != pending.back().v_align() || fabs(i.v_position() - pending.back().v_position()) > 1e-4)) { - images.push_back (render_line (pending, fonts, target, time, frame_rate)); + images.push_back (render_line(pending, fonts, target, time, frame_rate, x_offset, y_offset)); pending.clear (); } pending.push_back (i); } if (!pending.empty ()) { - images.push_back (render_line (pending, fonts, target, time, frame_rate)); + images.push_back (render_line(pending, fonts, target, time, frame_rate, x_offset, y_offset)); } return images; diff --git a/src/lib/render_text.h b/src/lib/render_text.h index 7187ca30b..38009403a 100644 --- a/src/lib/render_text.h +++ b/src/lib/render_text.h @@ -29,5 +29,11 @@ namespace dcpomatic { std::string marked_up (std::list<StringText> subtitles, int target_height, float fade_factor); std::list<PositionImage> render_text ( - std::list<StringText>, std::list<boost::shared_ptr<dcpomatic::Font> > fonts, dcp::Size, dcpomatic::DCPTime, int + std::list<StringText> subtitles, + std::list<boost::shared_ptr<dcpomatic::Font> > fonts, + dcp::Size target, + dcpomatic::DCPTime time, + int frame_rate, + double x_offset, + double y_offset ); diff --git a/src/lib/string_text.h b/src/lib/string_text.h index 4f4958163..4063a688d 100644 --- a/src/lib/string_text.h +++ b/src/lib/string_text.h @@ -38,4 +38,6 @@ public: int outline_width; }; +extern bool operator== (StringText const & a, StringText const & b); + #endif diff --git a/src/lib/wscript b/src/lib/wscript index b78586843..19c8cc7ef 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -39,6 +39,7 @@ sources = """ audio_processor.cc audio_ring_buffers.cc audio_stream.cc + bitmap_text.cc butler.cc text_content.cc text_decoder.cc @@ -135,6 +136,7 @@ sources = """ position_image.cc ratio.cc raw_image_proxy.cc + rect.cc reel_writer.cc render_text.cc resampler.cc @@ -152,6 +154,7 @@ sources = """ spl.cc spl_entry.cc string_log_entry.cc + string_text.cc string_text_file.cc string_text_file_content.cc string_text_file_decoder.cc diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 893e1bf0f..c4c1429dc 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -47,6 +47,7 @@ #include "lib/config.h" #include "lib/compose.hpp" #include "lib/dcpomatic_log.h" +#include "lib/text_content.h" extern "C" { #include <libavutil/pixfmt.h> } @@ -519,7 +520,9 @@ FilmViewer::player_change (ChangeType type, int property, bool frequent) property == VideoContentProperty::FADE_OUT || property == VideoContentProperty::COLOUR_CONVERSION || property == PlayerProperty::VIDEO_CONTAINER_SIZE || - property == PlayerProperty::FILM_CONTAINER + property == PlayerProperty::FILM_CONTAINER || + property == TextContentProperty::X_OFFSET || + property == TextContentProperty::Y_OFFSET ) { refreshed = quick_refresh (); } |
