X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fffmpeg_content.cc;h=ddf4548b41959fe1c8eac9ea304a9d85da77c201;hb=cbd4450197a083bf58bda510e626f73ba583cb66;hp=76ee663ff14e3bdec4689c546eebaba12e566c84;hpb=f10ad31900f2aad8f6b906fee799186a6097cdf5;p=dcpomatic.git diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc index 76ee663ff..ddf4548b4 100644 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@ -32,9 +32,8 @@ #include "log.h" #include "exceptions.h" #include "frame_rate_change.h" -#include "safe_stringstream.h" -#include "raw_convert.h" -#include "subtitle_content.h" +#include "caption_content.h" +#include #include extern "C" { #include @@ -58,6 +57,7 @@ using std::max; using boost::shared_ptr; using boost::dynamic_pointer_cast; using boost::optional; +using dcp::raw_convert; int const FFmpegContentProperty::SUBTITLE_STREAMS = 100; int const FFmpegContentProperty::SUBTITLE_STREAM = 101; @@ -69,12 +69,23 @@ FFmpegContent::FFmpegContent (shared_ptr film, boost::filesystem::pa } +template +optional +get_optional_enum (cxml::ConstNodePtr node, string name) +{ + optional const v = node->optional_number_child(name); + if (!v) { + return optional(); + } + return static_cast(*v); +} + FFmpegContent::FFmpegContent (shared_ptr film, cxml::ConstNodePtr node, int version, list& 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); + caption = CaptionContent::from_xml (this, node, version); list c = node->node_children ("SubtitleStream"); for (list::const_iterator i = c.begin(); i != c.end(); ++i) { @@ -109,82 +120,19 @@ FFmpegContent::FFmpegContent (shared_ptr film, cxml::ConstNodePtr no _first_video = ContentTime (f.get ()); } - _color_range = static_cast (node->optional_number_child("ColorRange").get_value_or (AVCOL_RANGE_UNSPECIFIED)); - _color_primaries = static_cast (node->optional_number_child("ColorPrimaries").get_value_or (AVCOL_PRI_UNSPECIFIED)); - _color_trc = static_cast ( - node->optional_number_child("ColorTransferCharacteristic").get_value_or (AVCOL_TRC_UNSPECIFIED) - ); - _colorspace = static_cast (node->optional_number_child("Colorspace").get_value_or (AVCOL_SPC_UNSPECIFIED)); + _color_range = get_optional_enum(node, "ColorRange"); + _color_primaries = get_optional_enum(node, "ColorPrimaries"); + _color_trc = get_optional_enum(node, "ColorTransferCharacteristic"); + _colorspace = get_optional_enum(node, "Colorspace"); _bits_per_pixel = node->optional_number_child ("BitsPerPixel"); } -FFmpegContent::FFmpegContent (shared_ptr film, vector > c) - : Content (film, c) -{ - vector >::const_iterator i = c.begin (); - - bool need_video = false; - bool need_audio = false; - bool need_subtitle = false; - - if (i != c.end ()) { - need_video = static_cast ((*i)->video); - need_audio = static_cast ((*i)->audio); - need_subtitle = static_cast ((*i)->subtitle); - } - - while (i != c.end ()) { - if (need_video != static_cast ((*i)->video)) { - throw JoinError (_("Content to be joined must all have or not have video")); - } - if (need_audio != static_cast ((*i)->audio)) { - throw JoinError (_("Content to be joined must all have or not have audio")); - } - if (need_subtitle != static_cast ((*i)->subtitle)) { - throw JoinError (_("Content to be joined must all have or not have subtitles")); - } - ++i; - } - - if (need_video) { - video.reset (new VideoContent (this, c)); - } - if (need_audio) { - audio.reset (new AudioContent (this, c)); - } - if (need_subtitle) { - subtitle.reset (new SubtitleContent (this, c)); - } - - shared_ptr ref = dynamic_pointer_cast (c[0]); - DCPOMATIC_ASSERT (ref); - - for (size_t i = 0; i < c.size(); ++i) { - shared_ptr fc = dynamic_pointer_cast (c[i]); - if (fc->subtitle && fc->subtitle->use() && *(fc->_subtitle_stream.get()) != *(ref->_subtitle_stream.get())) { - throw JoinError (_("Content to be joined must use the same subtitle stream.")); - } - } - - /* XXX: should probably check that more of the stuff below is the same in *this and ref */ - - _subtitle_streams = ref->subtitle_streams (); - _subtitle_stream = ref->subtitle_stream (); - _first_video = ref->_first_video; - _filters = ref->_filters; - _color_range = ref->_color_range; - _color_primaries = ref->_color_primaries; - _color_trc = ref->_color_trc; - _colorspace = ref->_colorspace; - _bits_per_pixel = ref->_bits_per_pixel; -} - 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); @@ -200,8 +148,8 @@ FFmpegContent::as_xml (xmlpp::Node* node) const } } - if (subtitle) { - subtitle->as_xml (node); + if (only_caption()) { + only_caption()->as_xml (node); } boost::mutex::scoped_lock lm (_mutex); @@ -222,12 +170,20 @@ FFmpegContent::as_xml (xmlpp::Node* node) const node->add_child("FirstVideo")->add_child_text (raw_convert (_first_video.get().get())); } - node->add_child("ColorRange")->add_child_text (raw_convert (_color_range)); - node->add_child("ColorPrimaries")->add_child_text (raw_convert (_color_primaries)); - node->add_child("ColorTransferCharacteristic")->add_child_text (raw_convert (_color_trc)); - node->add_child("Colorspace")->add_child_text (raw_convert (_colorspace)); + if (_color_range) { + node->add_child("ColorRange")->add_child_text (raw_convert (static_cast (*_color_range))); + } + if (_color_primaries) { + node->add_child("ColorPrimaries")->add_child_text (raw_convert (static_cast (*_color_primaries))); + } + if (_color_trc) { + node->add_child("ColorTransferCharacteristic")->add_child_text (raw_convert (static_cast (*_color_trc))); + } + if (_colorspace) { + node->add_child("Colorspace")->add_child_text (raw_convert (static_cast (*_colorspace))); + } if (_bits_per_pixel) { - node->add_child("BitsPerPixel")->add_child_text (raw_convert (_bits_per_pixel.get ())); + node->add_child("BitsPerPixel")->add_child_text (raw_convert (*_bits_per_pixel)); } } @@ -243,7 +199,6 @@ FFmpegContent::examine (shared_ptr 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 +213,18 @@ FFmpegContent::examine (shared_ptr 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 +242,17 @@ FFmpegContent::examine (shared_ptr job) _subtitle_streams = examiner->subtitle_streams (); if (!_subtitle_streams.empty ()) { - subtitle.reset (new SubtitleContent (this)); + caption.clear (); + caption.push_back (shared_ptr (new CaptionContent (this))); _subtitle_stream = _subtitle_streams.front (); } } + if (examiner->has_video ()) { + set_default_colour_conversion (); + } + signal_changed (FFmpegContentProperty::SUBTITLE_STREAMS); signal_changed (FFmpegContentProperty::SUBTITLE_STREAM); } @@ -388,51 +360,27 @@ FFmpegContent::set_filters (vector const & filters) string FFmpegContent::identifier () const { - SafeStringStream s; - - s << Content::identifier(); + string s = Content::identifier(); if (video) { - s << "_" << video->identifier(); + s += "_" + video->identifier(); } - if (subtitle) { - s << "_" << subtitle->identifier(); + if (only_caption() && only_caption()->use() && only_caption()->burn()) { + s += "_" + only_caption()->identifier(); } boost::mutex::scoped_lock lm (_mutex); if (_subtitle_stream) { - s << "_" << _subtitle_stream->identifier (); + s += "_" + _subtitle_stream->identifier (); } for (vector::const_iterator i = _filters.begin(); i != _filters.end(); ++i) { - s << "_" << (*i)->id (); + s += "_" + (*i)->id (); } - return s.str (); -} - -list -FFmpegContent::image_subtitles_during (ContentTimePeriod period, bool starting) const -{ - shared_ptr stream = subtitle_stream (); - if (!stream) { - return list (); - } - - return stream->image_subtitles_during (period, starting); -} - -list -FFmpegContent::text_subtitles_during (ContentTimePeriod period, bool starting) const -{ - shared_ptr stream = subtitle_stream (); - if (!stream) { - return list (); - } - - return stream->text_subtitles_during (period, starting); + return s; } void @@ -444,10 +392,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; } } @@ -463,7 +430,7 @@ FFmpegContent::add_properties (list& 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). @@ -487,7 +454,7 @@ FFmpegContent::add_properties (list& 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). @@ -519,11 +486,23 @@ FFmpegContent::add_properties (list& 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"), @@ -548,7 +527,7 @@ FFmpegContent::add_properties (list& 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)"), @@ -562,13 +541,17 @@ FFmpegContent::add_properties (list& 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"), raw_convert (_bits_per_pixel.get ()))); + p.push_back (UserProperty (UserProperty::VIDEO, _("Bits per pixel"), *_bits_per_pixel)); } } @@ -601,3 +584,15 @@ FFmpegContent::ffmpeg_audio_streams () const return fa; } + +void +FFmpegContent::take_settings_from (shared_ptr c) +{ + shared_ptr fc = dynamic_pointer_cast (c); + if (!fc) { + return; + } + + Content::take_settings_from (c); + _filters = fc->_filters; +}