X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fvideo_content.cc;h=1d1d010a95662193bc52ab84e5dacb2b8746fb10;hb=HEAD;hp=853204575dacd1f6093cbc084fb80d32d38f447b;hpb=0e164ad80f0ceff9d643f3b466690d013c3be19d;p=dcpomatic.git diff --git a/src/lib/video_content.cc b/src/lib/video_content.cc index 853204575..6c027ff11 100644 --- a/src/lib/video_content.cc +++ b/src/lib/video_content.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Carl Hetherington + Copyright (C) 2013-2022 Carl Hetherington This file is part of DCP-o-matic. @@ -18,19 +18,20 @@ */ -#include "video_content.h" -#include "content.h" -#include "video_examiner.h" + +#include "colour_conversion.h" #include "compose.hpp" -#include "ratio.h" #include "config.h" -#include "colour_conversion.h" -#include "util.h" -#include "film.h" +#include "content.h" +#include "dcpomatic_log.h" #include "exceptions.h" +#include "film.h" #include "frame_rate_change.h" #include "log.h" -#include "dcpomatic_log.h" +#include "ratio.h" +#include "util.h" +#include "video_content.h" +#include "video_examiner.h" #include #include #include @@ -39,6 +40,7 @@ #include "i18n.h" + int const VideoContentProperty::USE = 0; int const VideoContentProperty::SIZE = 1; int const VideoContentProperty::FRAME_TYPE = 2; @@ -51,23 +53,25 @@ int const VideoContentProperty::CUSTOM_RATIO = 8; int const VideoContentProperty::CUSTOM_SIZE = 9; int const VideoContentProperty::BURNT_SUBTITLE_LANGUAGE = 10; -using std::string; -using std::setprecision; + using std::cout; -using std::vector; -using std::min; -using std::max; +using std::dynamic_pointer_cast; using std::fixed; -using std::setprecision; using std::list; +using std::make_shared; +using std::max; +using std::min; using std::pair; +using std::setprecision; +using std::setprecision; using std::shared_ptr; -using std::make_shared; +using std::string; +using std::vector; using boost::optional; -using std::dynamic_pointer_cast; using dcp::raw_convert; using namespace dcpomatic; + VideoContent::VideoContent (Content* parent) : ContentPart (parent) , _use (true) @@ -81,27 +85,24 @@ VideoContent::VideoContent (Content* parent) } + +/** @param video_range_hint Video range to use if none is given in the XML */ shared_ptr -VideoContent::from_xml (Content* parent, cxml::ConstNodePtr node, int version) +VideoContent::from_xml (Content* parent, cxml::ConstNodePtr node, int version, VideoRange video_range_hint) { if (!node->optional_number_child ("VideoWidth")) { return {}; } - return make_shared(parent, node, version); + return make_shared(parent, node, version, video_range_hint); } -VideoContent::VideoContent (Content* parent, cxml::ConstNodePtr node, int version) + +/** @param video_range_hint Video range to use if none is given in the XML */ +VideoContent::VideoContent (Content* parent, cxml::ConstNodePtr node, int version, VideoRange video_range_hint) : ContentPart (parent) { - _size.width = node->number_child ("VideoWidth"); - _size.height = node->number_child ("VideoHeight"); - - /* Backwards compatibility */ - auto r = node->optional_number_child("VideoFrameRate"); - if (r) { - _parent->set_video_frame_rate (r.get ()); - } + _size = dcp::Size(node->number_child("VideoWidth"), node->number_child("VideoHeight")); _use = node->optional_bool_child("Use").get_value_or(true); _length = node->number_child ("VideoLength"); @@ -152,10 +153,12 @@ VideoContent::VideoContent (Content* parent, cxml::ConstNodePtr node, int versio if (scale) { if (*scale) { /* This is what we used to call "no stretch" */ - _legacy_ratio = _size.ratio(); + DCPOMATIC_ASSERT(_size); + _legacy_ratio = _size->ratio(); } else { /* This is what we used to call "no scale" */ - _custom_size = _size; + DCPOMATIC_ASSERT(_size); + _custom_size = *_size; } } @@ -180,8 +183,12 @@ VideoContent::VideoContent (Content* parent, cxml::ConstNodePtr node, int versio _fade_in = _fade_out = 0; } - _range = VideoRange::FULL; - if (node->optional_string_child("Range").get_value_or("full") == "video") { + auto video_range = node->optional_string_child("Range"); + if (!video_range) { + _range = video_range_hint; + } else if (*video_range == "full") { + _range = VideoRange::FULL; + } else { _range = VideoRange::VIDEO; } @@ -271,8 +278,10 @@ VideoContent::as_xml (xmlpp::Node* node) const boost::mutex::scoped_lock lm (_mutex); node->add_child("Use")->add_child_text (_use ? "1" : "0"); node->add_child("VideoLength")->add_child_text (raw_convert (_length)); - node->add_child("VideoWidth")->add_child_text (raw_convert (_size.width)); - node->add_child("VideoHeight")->add_child_text (raw_convert (_size.height)); + if (_size) { + node->add_child("VideoWidth")->add_child_text(raw_convert(_size->width)); + node->add_child("VideoHeight")->add_child_text(raw_convert(_size->height)); + } node->add_child("VideoFrameType")->add_child_text (video_frame_type_to_string (_frame_type)); if (_sample_aspect_ratio) { node->add_child("SampleAspectRatio")->add_child_text (raw_convert (_sample_aspect_ratio.get ())); @@ -299,7 +308,7 @@ VideoContent::as_xml (xmlpp::Node* node) const } void -VideoContent::take_from_examiner (shared_ptr d) +VideoContent::take_from_examiner(shared_ptr film, shared_ptr d) { /* These examiner calls could call other content methods which take a lock on the mutex */ auto const vs = d->video_size (); @@ -326,7 +335,7 @@ VideoContent::take_from_examiner (shared_ptr d) LOG_GENERAL ("Video length obtained from header as %1 frames", _length); if (d->video_frame_rate()) { - _parent->set_video_frame_rate (d->video_frame_rate().get()); + _parent->set_video_frame_rate(film, d->video_frame_rate().get()); } } @@ -363,11 +372,12 @@ VideoContent::identifier () const string VideoContent::technical_summary () const { + string const size_string = size() ? String::compose("%1x%2", size()->width, size()->height) : _("unknown"); + string s = String::compose ( - N_("video: length %1 frames, size %2x%3"), + N_("video: length %1 frames, size %2"), length_after_3d_combine(), - size().width, - size().height + size_string ); if (sample_aspect_ratio ()) { @@ -377,31 +387,40 @@ VideoContent::technical_summary () const return s; } -dcp::Size +optional VideoContent::size_after_3d_split () const { auto const s = size (); + if (!s) { + return {}; + } + switch (frame_type ()) { case VideoFrameType::TWO_D: case VideoFrameType::THREE_D: case VideoFrameType::THREE_D_ALTERNATE: case VideoFrameType::THREE_D_LEFT: case VideoFrameType::THREE_D_RIGHT: - return s; + return *s; case VideoFrameType::THREE_D_LEFT_RIGHT: - return dcp::Size (s.width / 2, s.height); + return dcp::Size(s->width / 2, s->height); case VideoFrameType::THREE_D_TOP_BOTTOM: - return dcp::Size (s.width, s.height / 2); + return dcp::Size(s->width, s->height / 2); } DCPOMATIC_ASSERT (false); } /** @return Video size after 3D split and crop */ -dcp::Size +optional VideoContent::size_after_crop () const { - return actual_crop().apply(size_after_3d_split()); + auto const after_3d = size_after_3d_split(); + if (!after_3d) { + return {}; + } + + return actual_crop().apply(*after_3d); } @@ -434,15 +453,15 @@ VideoContent::processing_description (shared_ptr film) string d; char buffer[256]; - if (size().width && size().height) { + if (size() && size()->width && size()->height) { d += String::compose ( _("Content video is %1x%2"), - size_after_3d_split().width, - size_after_3d_split().height + size_after_3d_split()->width, + size_after_3d_split()->height ); - double ratio = size_after_3d_split().ratio (); + auto ratio = size_after_3d_split()->ratio(); if (sample_aspect_ratio ()) { snprintf (buffer, sizeof(buffer), _(", pixel aspect ratio %.2f:1"), sample_aspect_ratio().get()); @@ -458,29 +477,31 @@ VideoContent::processing_description (shared_ptr film) if ((crop.left || crop.right || crop.top || crop.bottom) && size() != dcp::Size(0, 0)) { auto const cropped = size_after_crop (); - d += String::compose ( - _("\nCropped to %1x%2"), - cropped.width, cropped.height - ); + if (cropped) { + d += String::compose ( + _("\nCropped to %1x%2"), + cropped->width, cropped->height + ); - snprintf (buffer, sizeof(buffer), " (%.2f:1)", cropped.ratio()); - d += buffer; + snprintf(buffer, sizeof(buffer), " (%.2f:1)", cropped->ratio()); + d += buffer; + } } auto const container_size = film->frame_size (); auto const scaled = scaled_size (container_size); - if (scaled != size_after_crop ()) { + if (scaled && *scaled != size_after_crop()) { d += String::compose ( _("\nScaled to %1x%2"), - scaled.width, scaled.height + scaled->width, scaled->height ); - snprintf (buffer, sizeof(buffer), _(" (%.2f:1)"), scaled.ratio()); + snprintf (buffer, sizeof(buffer), _(" (%.2f:1)"), scaled->ratio()); d += buffer; } - if (scaled != container_size) { + if (scaled && *scaled != container_size) { d += String::compose ( _("\nPadded with black to fit container %1 (%2x%3)"), film->container()->container_nickname (), @@ -508,7 +529,9 @@ void VideoContent::add_properties (list& p) const { p.push_back (UserProperty (UserProperty::VIDEO, _("Length"), length (), _("video frames"))); - p.push_back (UserProperty (UserProperty::VIDEO, _("Size"), String::compose ("%1x%2", size().width, size().height))); + if (auto s = size()) { + p.push_back(UserProperty(UserProperty::VIDEO, _("Size"), String::compose("%1x%2", s->width, s->height))); + } } void @@ -517,6 +540,12 @@ VideoContent::set_length (Frame len) maybe_set (_length, len, ContentProperty::LENGTH); } +void +VideoContent::set_crop (Crop c) +{ + maybe_set (_crop, c, VideoContentProperty::CROP); +} + void VideoContent::set_left_crop (int c) { @@ -611,6 +640,7 @@ VideoContent::take_settings_from (shared_ptr c) set_fade_in (c->_fade_in); set_fade_out (c->_fade_out); set_burnt_subtitle_language (c->_burnt_subtitle_language); + set_range(c->_range); } @@ -630,7 +660,7 @@ VideoContent::modify_trim_start (ContentTime& trim) const /** @param film_container The size of the container for the DCP that we are working on */ -dcp::Size +optional VideoContent::scaled_size (dcp::Size film_container) { if (_custom_ratio) { @@ -638,22 +668,29 @@ VideoContent::scaled_size (dcp::Size film_container) } if (_custom_size) { - return *_custom_size; + if (_custom_size->width <= film_container.width && _custom_size->height <= film_container.height) { + return *_custom_size; + } + return fit_ratio_within(_custom_size->ratio(), film_container); } auto size = size_after_crop (); - size.width *= _sample_aspect_ratio.get_value_or(1); + if (!size) { + return {}; + } + + size->width = std::lrint(size->width * _sample_aspect_ratio.get_value_or(1)); /* This is what we will return unless there is any legacy stuff to take into account */ - auto auto_size = fit_ratio_within (size.ratio(), film_container); + auto auto_size = fit_ratio_within(size->ratio(), film_container); if (_legacy_ratio) { if (fit_ratio_within(*_legacy_ratio, film_container) != auto_size) { _custom_ratio = *_legacy_ratio; - _legacy_ratio = optional(); + _legacy_ratio = {}; return fit_ratio_within(*_custom_ratio, film_container); } - _legacy_ratio = boost::optional(); + _legacy_ratio = {}; } return _pixel_quanta.round (auto_size); @@ -685,3 +722,12 @@ VideoContent::actual_crop () const ); } + +void +VideoContent::rotate_size() +{ + if (_size) { + std::swap(_size->width, _size->height); + } +} +