Rename Subtitle -> Text
[dcpomatic.git] / src / lib / ffmpeg_content.cc
index b5c5ce0a8a45e64da5d52aae6a4aa3aaf482fb91..e18977944648fc1faff37e83987d8018a63fe473 100644 (file)
@@ -32,7 +32,7 @@
 #include "log.h"
 #include "exceptions.h"
 #include "frame_rate_change.h"
-#include "subtitle_content.h"
+#include "text_content.h"
 #include <dcp/raw_convert.h>
 #include <libcxml/cxml.h>
 extern "C" {
@@ -69,12 +69,23 @@ FFmpegContent::FFmpegContent (shared_ptr<const Film> film, boost::filesystem::pa
 
 }
 
+template <class T>
+optional<T>
+get_optional_enum (cxml::ConstNodePtr node, string name)
+{
+       optional<int> const v = node->optional_number_child<int>(name);
+       if (!v) {
+               return optional<T>();
+       }
+       return static_cast<T>(*v);
+}
+
 FFmpegContent::FFmpegContent (shared_ptr<const Film> film, cxml::ConstNodePtr node, int version, list<string>& notes)
        : Content (film, node)
 {
        video = VideoContent::from_xml (this, node, version);
        audio = AudioContent::from_xml (this, node, version);
-       subtitle = SubtitleContent::from_xml (this, node, version);
+       subtitle = TextContent::from_xml (this, node, version);
 
        list<cxml::NodePtr> c = node->node_children ("SubtitleStream");
        for (list<cxml::NodePtr>::const_iterator i = c.begin(); i != c.end(); ++i) {
@@ -109,12 +120,10 @@ FFmpegContent::FFmpegContent (shared_ptr<const Film> film, cxml::ConstNodePtr no
                _first_video = ContentTime (f.get ());
        }
 
-       _color_range = static_cast<AVColorRange> (node->optional_number_child<int>("ColorRange").get_value_or (AVCOL_RANGE_UNSPECIFIED));
-       _color_primaries = static_cast<AVColorPrimaries> (node->optional_number_child<int>("ColorPrimaries").get_value_or (AVCOL_PRI_UNSPECIFIED));
-       _color_trc = static_cast<AVColorTransferCharacteristic> (
-               node->optional_number_child<int>("ColorTransferCharacteristic").get_value_or (AVCOL_TRC_UNSPECIFIED)
-               );
-       _colorspace = static_cast<AVColorSpace> (node->optional_number_child<int>("Colorspace").get_value_or (AVCOL_SPC_UNSPECIFIED));
+       _color_range = get_optional_enum<AVColorRange>(node, "ColorRange");
+       _color_primaries = get_optional_enum<AVColorPrimaries>(node, "ColorPrimaries");
+       _color_trc = get_optional_enum<AVColorTransferCharacteristic>(node, "ColorTransferCharacteristic");
+       _colorspace = get_optional_enum<AVColorSpace>(node, "Colorspace");
        _bits_per_pixel = node->optional_number_child<int> ("BitsPerPixel");
 
 }
@@ -154,7 +163,7 @@ FFmpegContent::FFmpegContent (shared_ptr<const Film> film, vector<shared_ptr<Con
                audio.reset (new AudioContent (this, c));
        }
        if (need_subtitle) {
-               subtitle.reset (new SubtitleContent (this, c));
+               subtitle.reset (new TextContent (this, c));
        }
 
        shared_ptr<FFmpegContent> ref = dynamic_pointer_cast<FFmpegContent> (c[0]);
@@ -181,10 +190,10 @@ FFmpegContent::FFmpegContent (shared_ptr<const Film> film, vector<shared_ptr<Con
 }
 
 void
-FFmpegContent::as_xml (xmlpp::Node* node) const
+FFmpegContent::as_xml (xmlpp::Node* node, bool with_paths) const
 {
        node->add_child("Type")->add_child_text ("FFmpeg");
-       Content::as_xml (node);
+       Content::as_xml (node, with_paths);
 
        if (video) {
                video->as_xml (node);
@@ -222,12 +231,20 @@ FFmpegContent::as_xml (xmlpp::Node* node) const
                node->add_child("FirstVideo")->add_child_text (raw_convert<string> (_first_video.get().get()));
        }
 
-       node->add_child("ColorRange")->add_child_text (raw_convert<string> (static_cast<int> (_color_range)));
-       node->add_child("ColorPrimaries")->add_child_text (raw_convert<string> (static_cast<int> (_color_primaries)));
-       node->add_child("ColorTransferCharacteristic")->add_child_text (raw_convert<string> (static_cast<int> (_color_trc)));
-       node->add_child("Colorspace")->add_child_text (raw_convert<string> (static_cast<int> (_colorspace)));
+       if (_color_range) {
+               node->add_child("ColorRange")->add_child_text (raw_convert<string> (static_cast<int> (*_color_range)));
+       }
+       if (_color_primaries) {
+               node->add_child("ColorPrimaries")->add_child_text (raw_convert<string> (static_cast<int> (*_color_primaries)));
+       }
+       if (_color_trc) {
+               node->add_child("ColorTransferCharacteristic")->add_child_text (raw_convert<string> (static_cast<int> (*_color_trc)));
+       }
+       if (_colorspace) {
+               node->add_child("Colorspace")->add_child_text (raw_convert<string> (static_cast<int> (*_colorspace)));
+       }
        if (_bits_per_pixel) {
-               node->add_child("BitsPerPixel")->add_child_text (raw_convert<string> (_bits_per_pixel.get ()));
+               node->add_child("BitsPerPixel")->add_child_text (raw_convert<string> (*_bits_per_pixel));
        }
 }
 
@@ -243,7 +260,6 @@ FFmpegContent::examine (shared_ptr<Job> job)
        if (examiner->has_video ()) {
                video.reset (new VideoContent (this));
                video->take_from_examiner (examiner);
-               set_default_colour_conversion ();
        }
 
        boost::filesystem::path first_path = path (0);
@@ -258,6 +274,18 @@ FFmpegContent::examine (shared_ptr<Job> job)
                        _color_trc = examiner->color_trc ();
                        _colorspace = examiner->colorspace ();
                        _bits_per_pixel = examiner->bits_per_pixel ();
+
+                       if (examiner->rotation()) {
+                               double rot = *examiner->rotation ();
+                               if (fabs (rot - 180) < 1.0) {
+                                       _filters.push_back (Filter::from_id ("vflip"));
+                                       _filters.push_back (Filter::from_id ("hflip"));
+                               } else if (fabs (rot - 90) < 1.0) {
+                                       _filters.push_back (Filter::from_id ("90clock"));
+                               } else if (fabs (rot - 270) < 1.0) {
+                                       _filters.push_back (Filter::from_id ("90anticlock"));
+                               }
+                       }
                }
 
                if (!examiner->audio_streams().empty ()) {
@@ -275,12 +303,16 @@ FFmpegContent::examine (shared_ptr<Job> job)
 
                _subtitle_streams = examiner->subtitle_streams ();
                if (!_subtitle_streams.empty ()) {
-                       subtitle.reset (new SubtitleContent (this));
+                       subtitle.reset (new TextContent (this));
                        _subtitle_stream = _subtitle_streams.front ();
                }
 
        }
 
+       if (examiner->has_video ()) {
+               set_default_colour_conversion ();
+       }
+
        signal_changed (FFmpegContentProperty::SUBTITLE_STREAMS);
        signal_changed (FFmpegContentProperty::SUBTITLE_STREAM);
 }
@@ -394,7 +426,7 @@ FFmpegContent::identifier () const
                s += "_" + video->identifier();
        }
 
-       if (subtitle) {
+       if (subtitle && subtitle->use() && subtitle->burn()) {
                s += "_" + subtitle->identifier();
        }
 
@@ -411,28 +443,6 @@ FFmpegContent::identifier () const
        return s;
 }
 
-list<ContentTimePeriod>
-FFmpegContent::image_subtitles_during (ContentTimePeriod period, bool starting) const
-{
-       shared_ptr<FFmpegSubtitleStream> stream = subtitle_stream ();
-       if (!stream) {
-               return list<ContentTimePeriod> ();
-       }
-
-       return stream->image_subtitles_during (period, starting);
-}
-
-list<ContentTimePeriod>
-FFmpegContent::text_subtitles_during (ContentTimePeriod period, bool starting) const
-{
-       shared_ptr<FFmpegSubtitleStream> stream = subtitle_stream ();
-       if (!stream) {
-               return list<ContentTimePeriod> ();
-       }
-
-       return stream->text_subtitles_during (period, starting);
-}
-
 void
 FFmpegContent::set_default_colour_conversion ()
 {
@@ -442,10 +452,29 @@ FFmpegContent::set_default_colour_conversion ()
 
        boost::mutex::scoped_lock lm (_mutex);
 
-       if (s.width < 1080) {
-               video->set_colour_conversion (PresetColourConversion::from_id ("rec601").conversion);
-       } else {
+       switch (_colorspace.get_value_or(AVCOL_SPC_UNSPECIFIED)) {
+       case AVCOL_SPC_RGB:
+               video->set_colour_conversion (PresetColourConversion::from_id ("srgb").conversion);
+               break;
+       case AVCOL_SPC_BT709:
                video->set_colour_conversion (PresetColourConversion::from_id ("rec709").conversion);
+               break;
+       case AVCOL_SPC_BT470BG:
+       case AVCOL_SPC_SMPTE170M:
+       case AVCOL_SPC_SMPTE240M:
+               video->set_colour_conversion (PresetColourConversion::from_id ("rec601").conversion);
+               break;
+       case AVCOL_SPC_BT2020_CL:
+       case AVCOL_SPC_BT2020_NCL:
+               video->set_colour_conversion (PresetColourConversion::from_id ("rec2020").conversion);
+               break;
+       default:
+               if (s.width < 1080) {
+                       video->set_colour_conversion (PresetColourConversion::from_id ("rec601").conversion);
+               } else {
+                       video->set_colour_conversion (PresetColourConversion::from_id ("rec709").conversion);
+               }
+               break;
        }
 }
 
@@ -461,7 +490,7 @@ FFmpegContent::add_properties (list<UserProperty>& p) const
                        int const sub = 219 * pow (2, _bits_per_pixel.get() - 8);
                        int const total = pow (2, _bits_per_pixel.get());
 
-                       switch (_color_range) {
+                       switch (_color_range.get_value_or(AVCOL_RANGE_UNSPECIFIED)) {
                        case AVCOL_RANGE_UNSPECIFIED:
                                /// TRANSLATORS: this means that the range of pixel values used in this
                                /// file is unknown (not specified in the file).
@@ -485,7 +514,7 @@ FFmpegContent::add_properties (list<UserProperty>& p) const
                                DCPOMATIC_ASSERT (false);
                        }
                } else {
-                       switch (_color_range) {
+                       switch (_color_range.get_value_or(AVCOL_RANGE_UNSPECIFIED)) {
                        case AVCOL_RANGE_UNSPECIFIED:
                                /// TRANSLATORS: this means that the range of pixel values used in this
                                /// file is unknown (not specified in the file).
@@ -517,11 +546,23 @@ FFmpegContent::add_properties (list<UserProperty>& p) const
                        _("SMPTE 240M"),
                        _("Film"),
                        _("BT2020"),
-                       _("SMPTE ST 428-1 (CIE 1931 XYZ)")
+                       _("SMPTE ST 428-1 (CIE 1931 XYZ)"),
+                       _("SMPTE ST 431-2 (2011)"),
+                       _("SMPTE ST 432-1 D65 (2010)"), // 12
+                       "", // 13
+                       "", // 14
+                       "", // 15
+                       "", // 16
+                       "", // 17
+                       "", // 18
+                       "", // 19
+                       "", // 20
+                       "", // 21
+                       _("JEDEC P22")
                };
 
-               DCPOMATIC_ASSERT (AVCOL_PRI_NB <= 11);
-               p.push_back (UserProperty (UserProperty::VIDEO, _("Colour primaries"), primaries[_color_primaries]));
+               DCPOMATIC_ASSERT (AVCOL_PRI_NB <= 23);
+               p.push_back (UserProperty (UserProperty::VIDEO, _("Colour primaries"), primaries[_color_primaries.get_value_or(AVCOL_PRI_UNSPECIFIED)]));
 
                char const * transfers[] = {
                        _("Unspecified"),
@@ -546,7 +587,7 @@ FFmpegContent::add_properties (list<UserProperty>& p) const
                };
 
                DCPOMATIC_ASSERT (AVCOL_TRC_NB <= 19);
-               p.push_back (UserProperty (UserProperty::VIDEO, _("Colour transfer characteristic"), transfers[_color_trc]));
+               p.push_back (UserProperty (UserProperty::VIDEO, _("Colour transfer characteristic"), transfers[_color_trc.get_value_or(AVCOL_TRC_UNSPECIFIED)]));
 
                char const * spaces[] = {
                        _("RGB / sRGB (IEC61966-2-1)"),
@@ -560,13 +601,17 @@ FFmpegContent::add_properties (list<UserProperty>& p) const
                        _("YCOCG"),
                        _("BT2020 non-constant luminance"),
                        _("BT2020 constant luminance"),
+                       _("SMPTE 2085, Y'D'zD'x"),
+                       _("Chroma-derived non-constant luminance"),
+                       _("Chroma-derived constant luminance"),
+                       _("BT2100")
                };
 
-               DCPOMATIC_ASSERT (AVCOL_SPC_NB == 11);
-               p.push_back (UserProperty (UserProperty::VIDEO, _("Colourspace"), spaces[_colorspace]));
+               DCPOMATIC_ASSERT (AVCOL_SPC_NB == 15);
+               p.push_back (UserProperty (UserProperty::VIDEO, _("Colourspace"), spaces[_colorspace.get_value_or(AVCOL_SPC_UNSPECIFIED)]));
 
                if (_bits_per_pixel) {
-                       p.push_back (UserProperty (UserProperty::VIDEO, _("Bits per pixel"), _bits_per_pixel.get ()));
+                       p.push_back (UserProperty (UserProperty::VIDEO, _("Bits per pixel"), *_bits_per_pixel));
                }
        }
 
@@ -599,3 +644,15 @@ FFmpegContent::ffmpeg_audio_streams () const
 
        return fa;
 }
+
+void
+FFmpegContent::take_settings_from (shared_ptr<const Content> c)
+{
+       shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (c);
+       if (!fc) {
+               return;
+               }
+
+       Content::take_settings_from (c);
+       _filters = fc->_filters;
+}