diff options
| author | Carl Hetherington <cth@carlh.net> | 2016-08-16 08:41:25 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2016-08-16 16:56:32 +0100 |
| commit | 94b3924ed3cbf4fbfa2445ca1007f25c53dc8b60 (patch) | |
| tree | 40abbdf14043edf4d6592b82acf3eccb960ea71f | |
| parent | 03c5a8155043613c01e0e151735a7fcf8ab84415 (diff) | |
Basic support for fading subtitles in and out (#923).
| -rw-r--r-- | ChangeLog | 2 | ||||
| -rw-r--r-- | src/lib/player.cc | 2 | ||||
| -rw-r--r-- | src/lib/render_subtitles.cc | 28 | ||||
| -rw-r--r-- | src/lib/render_subtitles.h | 5 | ||||
| -rw-r--r-- | src/lib/subtitle_content.cc | 28 | ||||
| -rw-r--r-- | src/lib/subtitle_content.h | 34 | ||||
| -rw-r--r-- | src/lib/subtitle_decoder.cc | 4 | ||||
| -rw-r--r-- | src/wx/subtitle_panel.cc | 2 | ||||
| -rw-r--r-- | src/wx/text_subtitle_appearance_dialog.cc | 30 | ||||
| -rw-r--r-- | src/wx/text_subtitle_appearance_dialog.h | 9 |
10 files changed, 108 insertions, 36 deletions
@@ -1,5 +1,7 @@ 2016-08-16 c.hetherington <cth@carlh.net> + * Basic support for fading subtitles in and out (#923). + * Fix error on seeking through imported mulit-reel DCPs. * Simple information on mouse position in the video waveform (part of #932). diff --git a/src/lib/player.cc b/src/lib/player.cc index 7dcaf68b7..07bb097c2 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -337,7 +337,7 @@ Player::get_video (DCPTime time, bool accurate) /* 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)); } diff --git a/src/lib/render_subtitles.cc b/src/lib/render_subtitles.cc index 5c8cf13ee..6e4dcf46a 100644 --- a/src/lib/render_subtitles.cc +++ b/src/lib/render_subtitles.cc @@ -92,9 +92,11 @@ marked_up (list<dcp::SubtitleString> subtitles) return out; } -/** @param subtitles A list of subtitles that are all on the same line */ +/** @param subtitles A list of subtitles that are all on the same line, + * at the same time and with the same fade in/out. + */ static PositionImage -render_line (list<dcp::SubtitleString> subtitles, list<shared_ptr<Font> > fonts, dcp::Size target) +render_line (list<dcp::SubtitleString> subtitles, list<shared_ptr<Font> > fonts, dcp::Size target, DCPTime time) { /* XXX: this method can only handle italic / bold changes mid-line, nothing else yet. @@ -205,7 +207,9 @@ render_line (list<dcp::SubtitleString> subtitles, list<shared_ptr<Font> > fonts, } } - FcPattern* pattern = FcPatternBuild (0, FC_FILE, FcTypeString, font_files.get(FontFiles::NORMAL).get().string().c_str(), static_cast<char *> (0)); + FcPattern* pattern = FcPatternBuild ( + 0, FC_FILE, FcTypeString, font_files.get(FontFiles::NORMAL).get().string().c_str(), static_cast<char *> (0) + ); FcObjectSet* object_set = FcObjectSetBuild (FC_FAMILY, FC_STYLE, FC_LANG, FC_FILE, static_cast<char *> (0)); FcFontSet* font_set = FcFontList (fc_config, pattern, object_set); if (font_set) { @@ -248,9 +252,18 @@ render_line (list<dcp::SubtitleString> subtitles, list<shared_ptr<Font> > fonts, layout->set_markup (marked_up (subtitles)); /* Compute fade factor */ - /* XXX */ float fade_factor = 1; + DCPTime const fade_in_start = DCPTime::from_seconds (subtitles.front().in().as_seconds ()); + DCPTime const fade_in_end = fade_in_start + DCPTime::from_seconds (subtitles.front().fade_up_time().as_seconds ()); + DCPTime const fade_out_end = DCPTime::from_seconds (subtitles.front().out().as_seconds ()); + DCPTime const fade_out_start = fade_out_end - DCPTime::from_seconds (subtitles.front().fade_down_time().as_seconds ()); + if (fade_in_start <= time && time <= fade_in_end && fade_in_start != fade_in_end) { + fade_factor = DCPTime(time - fade_in_start).seconds() / DCPTime(fade_in_end - fade_in_start).seconds(); + } else if (fade_out_start <= time && time <= fade_out_end && fade_out_start != fade_out_end) { + fade_factor = 1 - DCPTime(time - fade_out_start).seconds() / DCPTime(fade_out_end - fade_out_start).seconds(); + } + context->scale (xscale, yscale); layout->update_from_cairo_context (context); @@ -335,22 +348,23 @@ render_line (list<dcp::SubtitleString> subtitles, list<shared_ptr<Font> > fonts, return PositionImage (image, Position<int> (max (0, x), max (0, y))); } +/** @param time Time of the frame that these subtitles are going on */ list<PositionImage> -render_subtitles (list<dcp::SubtitleString> subtitles, list<shared_ptr<Font> > fonts, dcp::Size target) +render_subtitles (list<dcp::SubtitleString> subtitles, list<shared_ptr<Font> > fonts, dcp::Size target, DCPTime time) { list<dcp::SubtitleString> pending; list<PositionImage> images; BOOST_FOREACH (dcp::SubtitleString const & i, subtitles) { if (!pending.empty() && fabs (i.v_position() - pending.back().v_position()) > 1e-4) { - images.push_back (render_line (pending, fonts, target)); + images.push_back (render_line (pending, fonts, target, time)); pending.clear (); } pending.push_back (i); } if (!pending.empty ()) { - images.push_back (render_line (pending, fonts, target)); + images.push_back (render_line (pending, fonts, target, time)); } return images; diff --git a/src/lib/render_subtitles.h b/src/lib/render_subtitles.h index 281efe97a..79194568a 100644 --- a/src/lib/render_subtitles.h +++ b/src/lib/render_subtitles.h @@ -19,10 +19,13 @@ */ #include "position_image.h" +#include "dcpomatic_time.h" #include <dcp/subtitle_string.h> #include <dcp/util.h> class Font; std::string marked_up (std::list<dcp::SubtitleString> subtitles); -std::list<PositionImage> render_subtitles (std::list<dcp::SubtitleString>, std::list<boost::shared_ptr<Font> > fonts, dcp::Size); +std::list<PositionImage> render_subtitles ( + std::list<dcp::SubtitleString>, std::list<boost::shared_ptr<Font> > fonts, dcp::Size, DCPTime + ); diff --git a/src/lib/subtitle_content.cc b/src/lib/subtitle_content.cc index 21bfd8a2d..c57c72fb1 100644 --- a/src/lib/subtitle_content.cc +++ b/src/lib/subtitle_content.cc @@ -52,6 +52,8 @@ int const SubtitleContentProperty::OUTLINE = 509; int const SubtitleContentProperty::SHADOW = 510; int const SubtitleContentProperty::EFFECT_COLOUR = 511; int const SubtitleContentProperty::LINE_SPACING = 512; +int const SubtitleContentProperty::FADE_IN = 513; +int const SubtitleContentProperty::FADE_OUT = 514; SubtitleContent::SubtitleContent (Content* parent) : ContentPart (parent) @@ -107,6 +109,8 @@ SubtitleContent::SubtitleContent (Content* parent, cxml::ConstNodePtr node, int , _outline (node->optional_bool_child("Outline").get_value_or(false)) , _shadow (node->optional_bool_child("Shadow").get_value_or(false)) , _line_spacing (node->optional_number_child<double>("LineSpacing").get_value_or (1)) + , _fade_in (node->optional_number_child<Frame>("SubtitleFadeIn").get_value_or (0)) + , _fade_out (node->optional_number_child<Frame>("SubtitleFadeOut").get_value_or (0)) { if (version >= 32) { _use = node->bool_child ("UseSubtitles"); @@ -188,6 +192,10 @@ SubtitleContent::SubtitleContent (Content* parent, vector<shared_ptr<Content> > throw JoinError (_("Content to be joined must have the same subtitle line spacing.")); } + if ((c[i]->subtitle->fade_in() != ref->fade_in()) || (c[i]->subtitle->fade_out() != ref->fade_out())) { + throw JoinError (_("Content to be joined must have the same subtitle fades.")); + } + list<shared_ptr<Font> > fonts = c[i]->subtitle->fonts (); if (fonts.size() != ref_fonts.size()) { throw JoinError (_("Content to be joined must use the same fonts.")); @@ -214,6 +222,8 @@ SubtitleContent::SubtitleContent (Content* parent, vector<shared_ptr<Content> > _language = ref->language (); _fonts = ref_fonts; _line_spacing = ref->line_spacing (); + _fade_in = ref->fade_in (); + _fade_out = ref->fade_out (); connect_to_fonts (); } @@ -240,6 +250,8 @@ SubtitleContent::as_xml (xmlpp::Node* root) const root->add_child("EffectGreen")->add_child_text (raw_convert<string> (_effect_colour.g)); root->add_child("EffectBlue")->add_child_text (raw_convert<string> (_effect_colour.b)); root->add_child("LineSpacing")->add_child_text (raw_convert<string> (_line_spacing)); + root->add_child("SubtitleFadeIn")->add_child_text (raw_convert<string> (_fade_in.get())); + root->add_child("SubtitleFadeOut")->add_child_text (raw_convert<string> (_fade_out.get())); for (list<shared_ptr<Font> >::const_iterator i = _fonts.begin(); i != _fonts.end(); ++i) { (*i)->as_xml (root->add_child("Font")); @@ -253,7 +265,9 @@ SubtitleContent::identifier () const + "_" + raw_convert<string> (y_scale()) + "_" + raw_convert<string> (x_offset()) + "_" + raw_convert<string> (y_offset()) - + "_" + raw_convert<string> (line_spacing()); + + "_" + raw_convert<string> (line_spacing()) + + "_" + raw_convert<string> (fade_in().get()) + + "_" + raw_convert<string> (fade_out().get()); /* XXX: I suppose really _fonts shouldn't be in here, since not all types of subtitle content involve fonts. @@ -369,3 +383,15 @@ SubtitleContent::set_line_spacing (double s) { maybe_set (_line_spacing, s, SubtitleContentProperty::LINE_SPACING); } + +void +SubtitleContent::set_fade_in (ContentTime t) +{ + maybe_set (_fade_in, t, SubtitleContentProperty::FADE_IN); +} + +void +SubtitleContent::set_fade_out (ContentTime t) +{ + maybe_set (_fade_out, t, SubtitleContentProperty::FADE_OUT); +} diff --git a/src/lib/subtitle_content.h b/src/lib/subtitle_content.h index c8492b91a..fd02d032a 100644 --- a/src/lib/subtitle_content.h +++ b/src/lib/subtitle_content.h @@ -44,6 +44,8 @@ public: static int const SHADOW; static int const EFFECT_COLOUR; static int const LINE_SPACING; + static int const FADE_IN; + static int const FADE_OUT; }; /** @class SubtitleContent @@ -70,6 +72,13 @@ public: void set_x_scale (double); void set_y_scale (double); void set_language (std::string language); + void set_colour (dcp::Colour); + void set_outline (bool); + void set_shadow (bool); + void set_effect_colour (dcp::Colour); + void set_line_spacing (double s); + void set_fade_in (ContentTime); + void set_fade_out (ContentTime); bool use () const { boost::mutex::scoped_lock lm (_mutex); @@ -111,41 +120,41 @@ public: return _language; } - void set_colour (dcp::Colour); - dcp::Colour colour () const { boost::mutex::scoped_lock lm (_mutex); return _colour; } - void set_outline (bool); - bool outline () const { boost::mutex::scoped_lock lm (_mutex); return _outline; } - void set_shadow (bool); - bool shadow () const { boost::mutex::scoped_lock lm (_mutex); return _shadow; } - void set_effect_colour (dcp::Colour); - dcp::Colour effect_colour () const { boost::mutex::scoped_lock lm (_mutex); return _effect_colour; } - void set_line_spacing (double s); - double line_spacing () const { boost::mutex::scoped_lock lm (_mutex); return _line_spacing; } + ContentTime fade_in () const { + boost::mutex::scoped_lock lm (_mutex); + return _fade_in; + } + + ContentTime fade_out () const { + boost::mutex::scoped_lock lm (_mutex); + return _fade_out; + } + static boost::shared_ptr<SubtitleContent> from_xml (Content* parent, cxml::ConstNodePtr, int version); protected: @@ -159,6 +168,8 @@ private: void font_changed (); void connect_to_fonts (); + std::list<boost::signals2::connection> _font_connections; + bool _use; bool _burn; /** x offset for placing subtitles, as a proportion of the container width; @@ -178,9 +189,10 @@ private: bool _outline; bool _shadow; dcp::Colour _effect_colour; - std::list<boost::signals2::connection> _font_connections; /** scaling factor for line spacing; 1 is "standard", < 1 is closer together, > 1 is further apart */ double _line_spacing; + ContentTime _fade_in; + ContentTime _fade_out; }; #endif diff --git a/src/lib/subtitle_decoder.cc b/src/lib/subtitle_decoder.cc index 5ae1a703e..ba6fe4600 100644 --- a/src/lib/subtitle_decoder.cc +++ b/src/lib/subtitle_decoder.cc @@ -245,8 +245,8 @@ SubtitleDecoder::give_text (ContentTimePeriod period, sub::Subtitle const & subt j.text, effect, content()->effect_colour(), - dcp::Time (0, 1000), - dcp::Time (0, 1000) + dcp::Time (content()->fade_in().seconds(), 1000), + dcp::Time (content()->fade_out().seconds(), 1000) ) ); } diff --git a/src/wx/subtitle_panel.cc b/src/wx/subtitle_panel.cc index 3db50104f..e4db3560e 100644 --- a/src/wx/subtitle_panel.cc +++ b/src/wx/subtitle_panel.cc @@ -477,7 +477,7 @@ SubtitlePanel::appearance_dialog_clicked () } if (text) { - TextSubtitleAppearanceDialog* d = new TextSubtitleAppearanceDialog (this, c.front()->subtitle); + TextSubtitleAppearanceDialog* d = new TextSubtitleAppearanceDialog (this, c.front()); if (d->ShowModal () == wxID_OK) { d->apply (); } diff --git a/src/wx/text_subtitle_appearance_dialog.cc b/src/wx/text_subtitle_appearance_dialog.cc index a826cbc66..49c8920f6 100644 --- a/src/wx/text_subtitle_appearance_dialog.cc +++ b/src/wx/text_subtitle_appearance_dialog.cc @@ -26,7 +26,7 @@ using boost::shared_ptr; -TextSubtitleAppearanceDialog::TextSubtitleAppearanceDialog (wxWindow* parent, shared_ptr<SubtitleContent> content) +TextSubtitleAppearanceDialog::TextSubtitleAppearanceDialog (wxWindow* parent, shared_ptr<Content> content) : TableDialog (parent, _("Subtitle appearance"), 2, 1, true) , _content (content) { @@ -50,23 +50,35 @@ TextSubtitleAppearanceDialog::TextSubtitleAppearanceDialog (wxWindow* parent, sh _effect_colour = new wxColourPickerCtrl (this, wxID_ANY); add (_effect_colour); + add (_("Fade in time"), true); + _fade_in = new Timecode<ContentTime> (this); + add (_fade_in); + + add (_("Fade out time"), true); + _fade_out = new Timecode<ContentTime> (this); + add (_fade_out); + layout (); - _colour->SetColour (wxColour (_content->colour().r, _content->colour().g, _content->colour().b)); - _outline->SetValue (_content->outline ()); - _shadow->SetValue (_content->shadow ()); + _colour->SetColour (wxColour (_content->subtitle->colour().r, _content->subtitle->colour().g, _content->subtitle->colour().b)); + _outline->SetValue (_content->subtitle->outline ()); + _shadow->SetValue (_content->subtitle->shadow ()); _effect_colour->SetColour ( - wxColour (_content->effect_colour().r, _content->effect_colour().g, _content->effect_colour().b) + wxColour (_content->subtitle->effect_colour().r, _content->subtitle->effect_colour().g, _content->subtitle->effect_colour().b) ); + _fade_in->set (_content->subtitle->fade_in(), _content->active_video_frame_rate ()); + _fade_out->set (_content->subtitle->fade_out(), _content->active_video_frame_rate ()); } void TextSubtitleAppearanceDialog::apply () { wxColour const c = _colour->GetColour (); - _content->set_colour (dcp::Colour (c.Red(), c.Green(), c.Blue())); - _content->set_outline (_outline->GetValue ()); - _content->set_shadow (_shadow->GetValue ()); + _content->subtitle->set_colour (dcp::Colour (c.Red(), c.Green(), c.Blue())); + _content->subtitle->set_outline (_outline->GetValue ()); + _content->subtitle->set_shadow (_shadow->GetValue ()); wxColour const ec = _effect_colour->GetColour (); - _content->set_effect_colour (dcp::Colour (ec.Red(), ec.Green(), ec.Blue())); + _content->subtitle->set_effect_colour (dcp::Colour (ec.Red(), ec.Green(), ec.Blue())); + _content->subtitle->set_fade_in (_fade_in->get (_content->active_video_frame_rate ())); + _content->subtitle->set_fade_out (_fade_out->get (_content->active_video_frame_rate ())); } diff --git a/src/wx/text_subtitle_appearance_dialog.h b/src/wx/text_subtitle_appearance_dialog.h index c67ec8756..55fe51066 100644 --- a/src/wx/text_subtitle_appearance_dialog.h +++ b/src/wx/text_subtitle_appearance_dialog.h @@ -19,16 +19,17 @@ */ #include "table_dialog.h" +#include "timecode.h" #include <boost/shared_ptr.hpp> class wxRadioButton; class wxColourPickerCtrl; -class SubtitleContent; +class Content; class TextSubtitleAppearanceDialog : public TableDialog { public: - TextSubtitleAppearanceDialog (wxWindow* parent, boost::shared_ptr<SubtitleContent> content); + TextSubtitleAppearanceDialog (wxWindow* parent, boost::shared_ptr<Content> content); void apply (); @@ -37,6 +38,8 @@ private: wxRadioButton* _outline; wxRadioButton* _shadow; wxColourPickerCtrl* _effect_colour; + Timecode<ContentTime>* _fade_in; + Timecode<ContentTime>* _fade_out; - boost::shared_ptr<SubtitleContent> _content; + boost::shared_ptr<Content> _content; }; |
