Support PNG subs in DCPSubtitleDecoder (#1479).
authorCarl Hetherington <cth@carlh.net>
Fri, 8 Mar 2019 23:23:49 +0000 (23:23 +0000)
committerCarl Hetherington <cth@carlh.net>
Fri, 8 Mar 2019 23:23:49 +0000 (23:23 +0000)
src/lib/dcp_decoder.cc
src/lib/dcp_subtitle_decoder.cc
src/lib/util.cc
src/lib/util.h

index 1098bb87a8c94a8df56cf2ca0f3a7d40cd24f72c..85dd280064ac02d8743420edee9cdf31e7a02552 100644 (file)
@@ -259,45 +259,20 @@ DCPDecoder::pass_texts (
                                strings.push_back (*is);
                        }
 
+                       /* XXX: perhaps these image subs should also be collected together like the string ones are;
+                          this would need to be done both here and in DCPSubtitleDecoder.
+                       */
+
                        shared_ptr<dcp::SubtitleImage> ii = dynamic_pointer_cast<dcp::SubtitleImage> (i);
                        if (ii) {
-                               FFmpegImageProxy proxy (ii->png_image());
-                               shared_ptr<Image> image = proxy.image().first;
-                               /* set up rect with height and width */
-                               dcpomatic::Rect<double> rect(0, 0, image->size().width / double(size.width), image->size().height / double(size.height));
-
-                               /* add in position */
-
-                               switch (ii->h_align()) {
-                               case dcp::HALIGN_LEFT:
-                                       rect.x += ii->h_position();
-                                       break;
-                               case dcp::HALIGN_CENTER:
-                                       rect.x += 0.5 + ii->h_position() - rect.width / 2;
-                                       break;
-                               case dcp::HALIGN_RIGHT:
-                                       rect.x += 1 - ii->h_position() - rect.width;
-                                       break;
-                               }
-
-                               switch (ii->v_align()) {
-                               case dcp::VALIGN_TOP:
-                                       rect.y += ii->v_position();
-                                       break;
-                               case dcp::VALIGN_CENTER:
-                                       rect.y += 0.5 + ii->v_position() - rect.height / 2;
-                                       break;
-                               case dcp::VALIGN_BOTTOM:
-                                       rect.y += 1 - ii->v_position() - rect.height;
-                                       break;
-                               }
-
-                               decoder->emit_bitmap (
+                               emit_subtitle_image (
                                        ContentTimePeriod (
                                                ContentTime::from_frames (_offset - entry_point, vfr) + ContentTime::from_seconds (i->in().as_seconds ()),
                                                ContentTime::from_frames (_offset - entry_point, vfr) + ContentTime::from_seconds (i->out().as_seconds ())
                                                ),
-                                       image, rect
+                                       *ii,
+                                       size,
+                                       decoder
                                        );
                        }
                }
index 6c95b8b1fa4aadcc99396e51d3e09102d7739104..5d5e1f6311019dc5269b3f7f29856629fa65d6ac 100644 (file)
@@ -64,12 +64,13 @@ DCPSubtitleDecoder::pass ()
 
        /* Gather all subtitles with the same time period that are next
           on the list.  We must emit all subtitles for the same time
-          period with the same plain_text() call otherwise the
+          period with the same emit*() call otherwise the
           TextDecoder will assume there is nothing else at the
-          time of emit the first.
+          time of emitting the first.
        */
 
        list<dcp::SubtitleString> s;
+       list<dcp::SubtitleImage> i;
        ContentTimePeriod const p = content_time_period (*_next);
 
        while (_next != _subtitles.end () && content_time_period (*_next) == p) {
@@ -79,7 +80,15 @@ DCPSubtitleDecoder::pass ()
                        ++_next;
                }
 
-               /* XXX: image subtitles */
+               /* XXX: perhaps these image subs should also be collected together like the string ones are;
+                  this would need to be done both here and in DCPDecoder.
+               */
+
+               shared_ptr<dcp::SubtitleImage> ni = dynamic_pointer_cast<dcp::SubtitleImage>(*_next);
+               if (ni) {
+                       emit_subtitle_image (p, *ni, film()->frame_size(), only_text());
+                       ++_next;
+               }
        }
 
        only_text()->emit_plain (p, s);
index 0b6f4be72b63c7ce1edbbc30fc06f5f33b19b5c0..b5265519413976328254749d63cb5236caa200cd 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
@@ -41,6 +41,9 @@
 #include "string_text.h"
 #include "font.h"
 #include "render_text.h"
+#include "ffmpeg_image_proxy.h"
+#include "image.h"
+#include "text_decoder.h"
 #include <dcp/locale_convert.h>
 #include <dcp/util.h>
 #include <dcp/raw_convert.h>
@@ -881,6 +884,45 @@ day_of_week_to_string (boost::gregorian::greg_weekday d)
        return d.as_long_string ();
 }
 
+/** @param size Size of picture that the subtitle will be overlaid onto */
+void
+emit_subtitle_image (ContentTimePeriod period, dcp::SubtitleImage sub, dcp::Size size, shared_ptr<TextDecoder> decoder)
+{
+       /* XXX: this is rather inefficient; decoding the image just to get its size */
+       FFmpegImageProxy proxy (sub.png_image());
+       shared_ptr<Image> image = proxy.image().first;
+       /* set up rect with height and width */
+       dcpomatic::Rect<double> rect(0, 0, image->size().width / double(size.width), image->size().height / double(size.height));
+
+       /* add in position */
+
+       switch (sub.h_align()) {
+       case dcp::HALIGN_LEFT:
+               rect.x += sub.h_position();
+               break;
+       case dcp::HALIGN_CENTER:
+               rect.x += 0.5 + sub.h_position() - rect.width / 2;
+               break;
+       case dcp::HALIGN_RIGHT:
+               rect.x += 1 - sub.h_position() - rect.width;
+               break;
+       }
+
+       switch (sub.v_align()) {
+       case dcp::VALIGN_TOP:
+               rect.y += sub.v_position();
+               break;
+       case dcp::VALIGN_CENTER:
+               rect.y += 0.5 + sub.v_position() - rect.height / 2;
+               break;
+       case dcp::VALIGN_BOTTOM:
+               rect.y += 1 - sub.v_position() - rect.height;
+               break;
+       }
+
+       decoder->emit_bitmap (period, image, rect);
+}
+
 #ifdef DCPOMATIC_VARIANT_SWAROOP
 
 /* Make up a key from the machine UUID */
index 86be996485e4706705816eab5d17ce280d3dc833..5ffdae450f711bc4eba5ea13796e92ebe9796b61 100644 (file)
@@ -29,6 +29,7 @@
 #include "dcpomatic_time.h"
 #include "audio_mapping.h"
 #include <dcp/util.h>
+#include <dcp/subtitle_image.h>
 #include <boost/shared_ptr.hpp>
 #include <boost/optional.hpp>
 #include <boost/filesystem.hpp>
@@ -68,6 +69,7 @@ extern bool is_batch_converter;
 
 struct AVSubtitle;
 class AudioBuffers;
+class TextDecoder;
 
 extern std::string seconds_to_hms (int);
 extern std::string time_to_hmsf (DCPTime time, Frame rate);
@@ -103,6 +105,7 @@ extern void checked_fread (void* ptr, size_t size, FILE* stream, boost::filesyst
 extern void checked_fwrite (void const * ptr, size_t size, FILE* stream, boost::filesystem::path path);
 extern size_t utf8_strlen (std::string s);
 extern std::string day_of_week_to_string (boost::gregorian::greg_weekday d);
+extern void emit_subtitle_image (ContentTimePeriod period, dcp::SubtitleImage sub, dcp::Size size, boost::shared_ptr<TextDecoder> decoder);
 #ifdef DCPOMATIC_VARIANT_SWAROOP
 extern boost::shared_ptr<dcp::CertificateChain> read_swaroop_chain (boost::filesystem::path path);
 extern void write_swaroop_chain (boost::shared_ptr<const dcp::CertificateChain> chain, boost::filesystem::path output);