summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2016-02-26 21:06:27 +0000
committerCarl Hetherington <cth@carlh.net>2016-02-26 21:06:27 +0000
commitcef07676fb15c9f1c3c3073d22f06ffe95d9c2ce (patch)
treead67d2991961429c52dda4d7adc1ded37ce71c0a /src/lib
parent2b54b284e2c2ffcaa082b1c201abecf25edc21c9 (diff)
Allow changes to colours of FFmpeg subtitles (#795).
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/ffmpeg_content.cc11
-rw-r--r--src/lib/ffmpeg_content.h3
-rw-r--r--src/lib/ffmpeg_decoder.cc17
-rw-r--r--src/lib/ffmpeg_examiner.cc17
-rw-r--r--src/lib/ffmpeg_examiner.h2
-rw-r--r--src/lib/ffmpeg_subtitle_stream.cc23
-rw-r--r--src/lib/ffmpeg_subtitle_stream.h4
-rw-r--r--src/lib/player.cc3
-rw-r--r--src/lib/rgba.cc60
-rw-r--r--src/lib/rgba.h59
-rw-r--r--src/lib/wscript1
11 files changed, 196 insertions, 4 deletions
diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc
index 9cd0395f2..789fd735f 100644
--- a/src/lib/ffmpeg_content.cc
+++ b/src/lib/ffmpeg_content.cc
@@ -505,3 +505,14 @@ FFmpegContent::add_properties (list<UserProperty>& p) const
p.push_back (UserProperty (_("Video"), _("Bits per pixel"), raw_convert<string> (_bits_per_pixel.get ())));
}
}
+
+/** Our subtitle streams have colour maps, which can be changed, but
+ * they have no way of signalling that change. As a hack, we have this
+ * method which callers can use when they've modified one of our subtitle
+ * streams.
+ */
+void
+FFmpegContent::signal_subtitle_stream_changed ()
+{
+ signal_changed (FFmpegContentProperty::SUBTITLE_STREAM);
+}
diff --git a/src/lib/ffmpeg_content.h b/src/lib/ffmpeg_content.h
index c7dc374fd..e9cb3dacf 100644
--- a/src/lib/ffmpeg_content.h
+++ b/src/lib/ffmpeg_content.h
@@ -37,6 +37,7 @@ class FFmpegContentProperty : public VideoContentProperty
{
public:
static int const SUBTITLE_STREAMS;
+ /** The chosen subtitle stream, or something about it */
static int const SUBTITLE_STREAM;
static int const FILTERS;
};
@@ -105,6 +106,8 @@ public:
std::list<ContentTimePeriod> image_subtitles_during (ContentTimePeriod, bool starting) const;
std::list<ContentTimePeriod> text_subtitles_during (ContentTimePeriod, bool starting) const;
+ void signal_subtitle_stream_changed ();
+
protected:
void add_properties (std::list<UserProperty> &) const;
diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc
index 294c0da8c..a7cfb44ac 100644
--- a/src/lib/ffmpeg_decoder.cc
+++ b/src/lib/ffmpeg_decoder.cc
@@ -65,6 +65,7 @@ using std::list;
using std::min;
using std::pair;
using std::max;
+using std::map;
using boost::shared_ptr;
using boost::is_any_of;
using boost::split;
@@ -489,6 +490,17 @@ FFmpegDecoder::decode_bitmap_subtitle (AVSubtitleRect const * rect, ContentTimeP
(i.e. first byte B, second G, third R, fourth A)
*/
uint32_t const * palette = (uint32_t *) rect->pict.data[1];
+ /* And the stream has a map of those palette colours to colours
+ chosen by the user; created a `mapped' palette from those settings.
+ */
+ map<RGBA, RGBA> colour_map = ffmpeg_content()->subtitle_stream()->colours ();
+ vector<RGBA> mapped_palette (rect->nb_colors);
+ for (int i = 0; i < rect->nb_colors; ++i) {
+ RGBA c ((palette[i] & 0xff0000) >> 16, (palette[i] & 0xff00) >> 8, palette[i] & 0xff, (palette[i] & 0xff000000) >> 24);
+ DCPOMATIC_ASSERT (colour_map.find(c) != colour_map.end());
+ mapped_palette[i] = colour_map[c];
+ }
+
/* Start of the output data */
uint32_t* out_p = (uint32_t *) image->data()[0];
@@ -496,8 +508,9 @@ FFmpegDecoder::decode_bitmap_subtitle (AVSubtitleRect const * rect, ContentTimeP
uint8_t* sub_line_p = sub_p;
uint32_t* out_line_p = out_p;
for (int x = 0; x < rect->w; ++x) {
- uint32_t const p = palette[*sub_line_p++];
- *out_line_p++ = ((p & 0xff) << 16) | (p & 0xff00) | ((p & 0xff0000) >> 16) | (p & 0xff000000);
+ RGBA const p = mapped_palette[*sub_line_p++];
+ /* XXX: this seems to be wrong to me (isn't the output image RGBA?) but it looks right on screen */
+ *out_line_p++ = (p.a << 24) | (p.r << 16) | (p.g << 8) | p.b;
}
sub_p += rect->pict.linesize[0];
out_p += image->stride()[0] / sizeof (uint32_t);
diff --git a/src/lib/ffmpeg_examiner.cc b/src/lib/ffmpeg_examiner.cc
index 29cc69063..850b8ba5f 100644
--- a/src/lib/ffmpeg_examiner.cc
+++ b/src/lib/ffmpeg_examiner.cc
@@ -246,6 +246,23 @@ FFmpegExaminer::subtitle_packet (AVCodecContext* context, shared_ptr<FFmpegSubti
_last_subtitle_start[stream] = SubtitleStart (id, image, period.from);
}
}
+
+ for (unsigned int i = 0; i < sub.num_rects; ++i) {
+ if (sub.rects[i]->type == SUBTITLE_BITMAP) {
+ uint32_t* palette = (uint32_t *) sub.rects[i]->pict.data[1];
+ for (int j = 0; j < sub.rects[i]->nb_colors; ++j) {
+ RGBA rgba (
+ (palette[j] & 0x00ff0000) >> 16,
+ (palette[j] & 0x0000ff00) >> 8,
+ (palette[j] & 0x000000ff) >> 0,
+ (palette[j] & 0xff000000) >> 24
+ );
+
+ stream->set_colour (rgba, rgba);
+ }
+ }
+ }
+
avsubtitle_free (&sub);
}
}
diff --git a/src/lib/ffmpeg_examiner.h b/src/lib/ffmpeg_examiner.h
index a2a80b254..f64ea8d79 100644
--- a/src/lib/ffmpeg_examiner.h
+++ b/src/lib/ffmpeg_examiner.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013-2015 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
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
diff --git a/src/lib/ffmpeg_subtitle_stream.cc b/src/lib/ffmpeg_subtitle_stream.cc
index 33759d86e..eca3fda6f 100644
--- a/src/lib/ffmpeg_subtitle_stream.cc
+++ b/src/lib/ffmpeg_subtitle_stream.cc
@@ -27,6 +27,7 @@ using std::string;
using std::map;
using std::list;
using std::cout;
+using std::make_pair;
/** Construct a SubtitleStream from a value returned from to_string().
* @param t String returned from to_string().
@@ -82,6 +83,10 @@ FFmpegSubtitleStream::FFmpegSubtitleStream (cxml::ConstNodePtr node, int version
)
);
}
+
+ BOOST_FOREACH (cxml::NodePtr i, node->node_children ("Colour")) {
+ _colours[RGBA(i->node_child("From"))] = RGBA (i->node_child("To"));
+ }
}
}
@@ -92,6 +97,12 @@ FFmpegSubtitleStream::as_xml (xmlpp::Node* root) const
as_xml (root, _image_subtitles, "ImageSubtitle");
as_xml (root, _text_subtitles, "TextSubtitle");
+
+ for (map<RGBA, RGBA>::const_iterator i = _colours.begin(); i != _colours.end(); ++i) {
+ xmlpp::Node* node = root->add_child("Colour");
+ i->first.as_xml (node->add_child("From"));
+ i->second.as_xml (node->add_child("To"));
+ }
}
void
@@ -173,3 +184,15 @@ FFmpegSubtitleStream::add_offset (ContentTime offset)
i->second.to += offset;
}
}
+
+map<RGBA, RGBA>
+FFmpegSubtitleStream::colours () const
+{
+ return _colours;
+}
+
+void
+FFmpegSubtitleStream::set_colour (RGBA from, RGBA to)
+{
+ _colours[from] = to;
+}
diff --git a/src/lib/ffmpeg_subtitle_stream.h b/src/lib/ffmpeg_subtitle_stream.h
index 688aaa993..175eeacef 100644
--- a/src/lib/ffmpeg_subtitle_stream.h
+++ b/src/lib/ffmpeg_subtitle_stream.h
@@ -18,6 +18,7 @@
*/
#include "dcpomatic_time.h"
+#include "rgba.h"
#include "ffmpeg_stream.h"
class FFmpegSubtitleStream : public FFmpegStream
@@ -37,6 +38,7 @@ public:
std::list<ContentTimePeriod> text_subtitles_during (ContentTimePeriod period, bool starting) const;
ContentTime find_subtitle_to (std::string id) const;
void add_offset (ContentTime offset);
+ void set_colour (RGBA from, RGBA to);
bool has_image_subtitles () const {
return !_image_subtitles.empty ();
@@ -44,6 +46,7 @@ public:
bool has_text_subtitles () const {
return !_text_subtitles.empty ();
}
+ std::map<RGBA, RGBA> colours () const;
private:
@@ -54,4 +57,5 @@ private:
PeriodMap _image_subtitles;
PeriodMap _text_subtitles;
+ std::map<RGBA, RGBA> _colours;
};
diff --git a/src/lib/player.cc b/src/lib/player.cc
index 3e92eb3d9..30f36107f 100644
--- a/src/lib/player.cc
+++ b/src/lib/player.cc
@@ -222,7 +222,8 @@ Player::playlist_content_changed (weak_ptr<Content> w, int property, bool freque
property == DCPContentProperty::CAN_BE_PLAYED ||
property == TextSubtitleContentProperty::TEXT_SUBTITLE_COLOUR ||
property == TextSubtitleContentProperty::TEXT_SUBTITLE_OUTLINE ||
- property == TextSubtitleContentProperty::TEXT_SUBTITLE_OUTLINE_COLOUR
+ property == TextSubtitleContentProperty::TEXT_SUBTITLE_OUTLINE_COLOUR ||
+ property == FFmpegContentProperty::SUBTITLE_STREAM
) {
_have_valid_pieces = false;
diff --git a/src/lib/rgba.cc b/src/lib/rgba.cc
new file mode 100644
index 000000000..dac58418d
--- /dev/null
+++ b/src/lib/rgba.cc
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) 2016 Carl Hetherington <cth@carlh.net>
+
+ 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
+ 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,
+ 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.
+
+*/
+
+#include "rgba.h"
+#include <libxml++/libxml++.h>
+#include <boost/lexical_cast.hpp>
+
+using std::string;
+using boost::lexical_cast;
+
+RGBA::RGBA (cxml::ConstNodePtr node)
+{
+ r = node->number_child<int> ("R");
+ g = node->number_child<int> ("G");
+ b = node->number_child<int> ("B");
+ a = node->number_child<int> ("A");
+}
+
+void
+RGBA::as_xml (xmlpp::Node* parent) const
+{
+ parent->add_child("R")->add_child_text (lexical_cast<string> (int (r)));
+ parent->add_child("G")->add_child_text (lexical_cast<string> (int (g)));
+ parent->add_child("B")->add_child_text (lexical_cast<string> (int (b)));
+ parent->add_child("A")->add_child_text (lexical_cast<string> (int (a)));
+}
+
+bool
+RGBA::operator< (RGBA const & other) const
+{
+ if (r != other.r) {
+ return r < other.r;
+ }
+
+ if (g != other.g) {
+ return g < other.g;
+ }
+
+ if (b != other.b) {
+ return b < other.b;
+ }
+
+ return a < other.a;
+}
diff --git a/src/lib/rgba.h b/src/lib/rgba.h
new file mode 100644
index 000000000..f950187b0
--- /dev/null
+++ b/src/lib/rgba.h
@@ -0,0 +1,59 @@
+/*
+ Copyright (C) 2016 Carl Hetherington <cth@carlh.net>
+
+ 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
+ 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,
+ 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.
+
+*/
+
+#ifndef DCPOMATIC_RGBA_H
+#define DCPOMATIC_RGBA_H
+
+#include <libcxml/cxml.h>
+#include <stdint.h>
+
+/** @class RGBA
+ * @brief A 32-bit RGBA colour.
+ */
+
+class RGBA
+{
+public:
+ RGBA ()
+ : r (0)
+ , g (0)
+ , b (0)
+ , a (0)
+ {}
+
+ RGBA (uint8_t r_, uint8_t g_, uint8_t b_, uint8_t a_)
+ : r (r_)
+ , g (g_)
+ , b (b_)
+ , a (a_)
+ {}
+
+ RGBA (cxml::ConstNodePtr node);
+
+ void as_xml (xmlpp::Node* parent) const;
+
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ uint8_t a;
+
+ bool operator< (RGBA const & other) const;
+};
+
+#endif
diff --git a/src/lib/wscript b/src/lib/wscript
index f6ca52fb7..8dd241a4d 100644
--- a/src/lib/wscript
+++ b/src/lib/wscript
@@ -104,6 +104,7 @@ sources = """
reel_writer.cc
render_subtitles.cc
resampler.cc
+ rgba.cc
safe_stringstream.cc
scoped_temporary.cc
scp_uploader.cc