--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="40.736046mm"
+ height="72.459007mm"
+ viewBox="0 0 40.736045 72.459008"
+ version="1.1"
+ id="svg8"
+ inkscape:version="0.92.3 (2405546, 2018-03-11)"
+ sodipodi:docname="link.svg">
+ <defs
+ id="defs2" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.979899"
+ inkscape:cx="30.0516"
+ inkscape:cy="107.36255"
+ inkscape:document-units="mm"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1680"
+ inkscape:window-height="995"
+ inkscape:window-x="0"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ fit-margin-top="1"
+ fit-margin-left="1"
+ fit-margin-right="1"
+ fit-margin-bottom="1" />
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-43.172802,-2.2134689)">
+ <g
+ id="g11"
+ transform="matrix(-3.0676153e-5,-1.0020549,1.0020464,-0.00413633,25.020746,102.13853)"
+ style="stroke-width:0.99795336">
+ <path
+ sodipodi:nodetypes="ccsccccccscscccccsssccc"
+ inkscape:connector-curvature="0"
+ id="rect819"
+ d="m 65.199219,27.601562 0.3125,0.01172 c 0,0 -1.921609,-0.08686 -3.953125,0.625 -2.031517,0.711861 -4.556382,2.227912 -6.824219,5.013672 l 6.205078,5.050781 c 1.370276,-1.683216 2.525799,-2.25443 3.265625,-2.513672 0.739826,-0.259241 0.679688,-0.199218 0.679688,-0.199218 l 0.15625,0.01172 h 19.550781 c 2.172037,0.06924 3.36417,0.821834 4.335937,2.03125 0.973224,1.211229 1.583731,3.040311 1.589844,4.931641 0.0061,1.89133 -0.59167,3.751118 -1.582031,5.015625 -0.986061,1.259016 -2.231578,2.067616 -4.441406,2.205078 h -15.51516 l -3.779762,8 h 19.626953 l 0.11914,-0.0078 c 4.347056,-0.25782 8.013718,-2.360449 10.289063,-5.26564 2.275345,-2.905192 3.294538,-6.465865 3.283203,-9.972657 C 98.506244,39.032271 97.46527,35.48507 95.164062,32.621094 92.862855,29.757118 89.15903,27.737178 84.832031,27.603516 l -0.0625,-0.002 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:7.98362684;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ sodipodi:nodetypes="ccscscccccccccccscscccc"
+ inkscape:connector-curvature="0"
+ id="rect819-7"
+ d="m 41.986328,19.101562 -0.117187,0.0059 c -4.347056,0.257804 -8.013718,2.360434 -10.289063,5.265625 -2.275345,2.905191 -3.296491,6.467818 -3.285156,9.974609 0.01133,3.506791 1.054262,7.05204 3.355469,9.916016 2.301207,2.863976 6.005032,4.885869 10.332031,5.019531 l 0.0625,0.002 h 19.570312 l -0.3125,-0.01172 c 0,0 1.921609,0.08491 3.953125,-0.626954 2.031517,-0.711861 4.556382,-2.227911 6.824219,-5.013672 L 65.875,38.582031 c -1.370276,1.683217 -2.525798,2.256384 -3.265625,2.515625 -0.739827,0.259242 -0.681641,0.199219 -0.681641,0.199219 l -0.15625,-0.01172 H 42.220703 c -2.172033,-0.06924 -3.362218,-0.821835 -4.333984,-2.03125 -0.973223,-1.211229 -1.585684,-3.04031 -1.591797,-4.93164 -0.0061,-1.891331 0.59167,-3.751118 1.582031,-5.015625 0.984624,-1.257182 2.229804,-2.06585 4.433594,-2.205079 h 14.957961 l 4.346726,-8 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:7.98362684;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ </g>
+</svg>
$INKSCAPE tick.png src/tick.svg -w 16 -h 16
$INKSCAPE no_tick.png src/no_tick.svg -w 16 -h 16
+ # Link icon
+ $INKSCAPE link.png src/link.svg -w 9 -h 16
+
# favicon
mkdir -p web
convert src/web.png -resize 256x256 -transparent white web/favicon-256x256.png
_language = optional<string> ();
_default_still_length = 10;
_default_container = Ratio::from_id ("185");
- _default_scale_to = 0;
_default_dcp_content_type = DCPContentType::from_isdcf_name ("FTR");
_default_dcp_audio_channels = 6;
_default_j2k_bandwidth = 150000000;
_default_container = Ratio::from_id ("185");
}
- c = f.optional_string_child ("DefaultScaleTo");
- if (c) {
- _default_scale_to = Ratio::from_id (c.get ());
- }
-
_default_dcp_content_type = DCPContentType::from_isdcf_name(f.optional_string_child("DefaultDCPContentType").get_value_or("FTR"));
_default_dcp_audio_channels = f.optional_number_child<int>("DefaultDCPAudioChannels").get_value_or (6);
*/
root->add_child("DefaultContainer")->add_child_text (_default_container->id ());
}
- if (_default_scale_to) {
- /* [XML:opt] DefaultScaleTo ID of default ratio to scale content to when creating new films
- (see <code>DefaultContainer</code> for IDs).
- */
- root->add_child("DefaultScaleTo")->add_child_text (_default_scale_to->id ());
- }
if (_default_dcp_content_type) {
/* [XML:opt] DefaultDCPContentType Default content type ot use when creating new films (<code>FTR</code>, <code>SHR</code>,
<code>TLR</code>, <code>TST</code>, <code>XSN</code>, <code>RTG</code>, <code>TSR</code>, <code>POL</code>,
return _default_container;
}
- Ratio const * default_scale_to () const {
- return _default_scale_to;
- }
-
DCPContentType const * default_dcp_content_type () const {
return _default_dcp_content_type;
}
maybe_set (_default_container, c);
}
- void set_default_scale_to (Ratio const * c) {
- maybe_set (_default_scale_to, c);
- }
-
void set_default_dcp_content_type (DCPContentType const * t) {
maybe_set (_default_dcp_content_type, t);
}
/** Default length of still image content (seconds) */
int _default_still_length;
Ratio const * _default_container;
- Ratio const * _default_scale_to;
DCPContentType const * _default_dcp_content_type;
int _default_dcp_audio_channels;
std::string _dcp_issuer;
" -c, --dcp-content-type <type> FTR, SHR, TLR, TST, XSN, RTG, TSR, POL, PSA or ADV\n"
" -f, --dcp-frame-rate <rate> set DCP video frame rate (otherwise guessed from content)\n"
" --container-ratio <ratio> 119, 133, 137, 138, 166, 178, 185 or 239\n"
- " --content-ratio <ratio> 119, 133, 137, 138, 166, 178, 185 or 239\n"
" -s, --still-length <n> number of seconds that still content should last\n"
" --standard <standard> SMPTE or interop (default SMPTE)\n"
" --no-use-isdcf-name do not use an ISDCF name; use the specified name unmodified\n"
, threed (false)
, dcp_content_type (0)
, container_ratio (0)
- , content_ratio (0)
, still_length (10)
, standard (dcp::SMPTE)
, no_use_isdcf_name (false)
, fourk (false)
{
string dcp_content_type_string = "TST";
- string content_ratio_string;
string container_ratio_string;
string standard_string = "SMPTE";
int dcp_frame_rate_int = 0;
argument_option(i, argc, argv, "-c", "--dcp-content-type", &claimed, &error, &dcp_content_type_string);
argument_option(i, argc, argv, "-f", "--dcp-frame-rate", &claimed, &error, &dcp_frame_rate_int);
argument_option(i, argc, argv, "", "--container-ratio", &claimed, &error, &container_ratio_string);
- argument_option(i, argc, argv, "", "--content-ratio", &claimed, &error, &content_ratio_string);
argument_option(i, argc, argv, "-s", "--still-length", &claimed, &error, &still_length);
argument_option(i, argc, argv, "", "--standard", &claimed, &error, &standard_string);
argument_option(i, argc, argv, "", "--config", &claimed, &error, &config_dir_string);
return;
}
- if (content_ratio_string.empty()) {
- error = String::compose("%1: missing required option --content-ratio", argv[0]);
- return;
- }
-
- content_ratio = Ratio::from_id (content_ratio_string);
- if (!content_ratio) {
- error = String::compose("%1: unrecognised content ratio %2", content_ratio_string);
- return;
- }
-
- if (container_ratio_string.empty()) {
- container_ratio_string = content_ratio_string;
- }
-
- container_ratio = Ratio::from_id (container_ratio_string);
- if (!container_ratio) {
- error = String::compose("%1: unrecognised container ratio %2", argv[0], container_ratio_string);
- return;
+ if (!container_ratio_string.empty()) {
+ container_ratio = Ratio::from_id (container_ratio_string);
+ if (!container_ratio) {
+ error = String::compose("%1: unrecognised container ratio %2", argv[0], container_ratio_string);
+ return;
+ }
}
if (standard_string != "SMPTE" && standard_string != "interop") {
DCPContentType const * dcp_content_type;
boost::optional<int> dcp_frame_rate;
Ratio const * container_ratio;
- Ratio const * content_ratio;
int still_length;
dcp::Standard standard;
bool no_use_isdcf_name;
list<dcp::VerificationNote> notes;
dcp->read (¬es, true);
if (!_tolerant) {
- /** We accept and ignore EmptyAssetPathError but everything else is bad */
+ /** We accept and ignore EMPTY_ASSET_PATH and EXTERNAL_ASSET but everything else is bad */
BOOST_FOREACH (dcp::VerificationNote j, notes) {
- if (j.code() == dcp::VerificationNote::EMPTY_ASSET_PATH) {
+ if (j.code() == dcp::VerificationNote::EMPTY_ASSET_PATH || j.code() == dcp::VerificationNote::EXTERNAL_ASSET) {
LOG_WARNING("Empty path in ASSETMAP of %1", i.string());
} else {
boost::throw_exception(dcp::ReadError(dcp::note_to_string(j)));
* 36 -> 37
* TextContent can be in a Caption tag, and some of the tag names
* have had Subtitle prefixes or suffixes removed.
+ * 37 -> 38
+ * VideoContent scale expressed just as "guess" or "custom"
*/
-int const Film::current_state_version = 37;
+int const Film::current_state_version = 38;
/** Construct a Film object in a given directory.
*
, _upload_after_make_dcp (Config::instance()->default_upload_after_make_dcp())
, _reencode_j2k (false)
, _user_explicit_video_frame_rate (false)
+ , _user_explicit_container (false)
+ , _user_explicit_resolution (false)
, _state_version (current_state_version)
, _dirty (false)
, _tolerant (false)
i.as_xml (root->add_child("Rating"));
}
root->add_child("ContentVersion")->add_child_text(_content_version);
+ root->add_child("UserExplicitContainer")->add_child_text(_user_explicit_container ? "1" : "0");
+ root->add_child("UserExplicitResolution")->add_child_text(_user_explicit_resolution ? "1" : "0");
_playlist->as_xml (root->add_child ("Playlist"), with_content_paths);
return doc;
_content_version = f.optional_string_child("ContentVersion").get_value_or("");
+ /* Disable guessing for files made in previous DCP-o-matic versions */
+ _user_explicit_container = f.optional_bool_child("UserExplicitContainer").get_value_or(true);
+ _user_explicit_resolution = f.optional_bool_child("UserExplicitResolution").get_value_or(true);
+
list<string> notes;
_playlist->set_from_xml (shared_from_this(), f.node_child ("Playlist"), _state_version, notes);
BOOST_FOREACH (shared_ptr<Content> i, content ()) {
if (i->video) {
/* Here's the first piece of video content */
- if (i->video->scale().ratio ()) {
- content_ratio = i->video->scale().ratio ();
- } else {
- content_ratio = Ratio::from_ratio (i->video->size().ratio ());
- }
+ content_ratio = Ratio::nearest_from_ratio(i->video->scaled_size(frame_size()).ratio());
break;
}
}
_dcp_content_type = t;
}
+
+/** @param explicit_user true if this is being set because of
+ * a direct user request, false if it is being done because
+ * DCP-o-matic is guessing the best container to use.
+ */
void
-Film::set_container (Ratio const * c)
+Film::set_container (Ratio const * c, bool explicit_user)
{
ChangeSignaller<Film> ch (this, CONTAINER);
_container = c;
+
+ if (explicit_user) {
+ _user_explicit_container = true;
+ }
}
+
+/** @param explicit_user true if this is being set because of
+ * a direct user request, false if it is being done because
+ * DCP-o-matic is guessing the best resolution to use.
+ */
void
-Film::set_resolution (Resolution r)
+Film::set_resolution (Resolution r, bool explicit_user)
{
ChangeSignaller<Film> ch (this, RESOLUTION);
_resolution = r;
+
+ if (explicit_user) {
+ _user_explicit_resolution = true;
+ }
}
+
void
Film::set_j2k_bandwidth (int b)
{
}
_playlist->add (shared_from_this(), c);
+
+ maybe_set_container_and_resolution ();
+}
+
+
+void
+Film::maybe_set_container_and_resolution ()
+{
+ /* Get the only piece of video content, if there is only one */
+ shared_ptr<VideoContent> video;
+ BOOST_FOREACH (shared_ptr<const Content> i, _playlist->content()) {
+ if (i->video) {
+ if (!video) {
+ video = i->video;
+ } else {
+ video.reset ();
+ }
+ }
+ }
+
+ if (video) {
+ /* This is the only piece of video content in this Film. Use it to make a guess for
+ * DCP container size and resolution, unless the user has already explicitly set these
+ * things.
+ */
+ if (!_user_explicit_container) {
+ if (video->size().ratio() > 2.3) {
+ set_container (Ratio::from_id("239"), false);
+ } else {
+ set_container (Ratio::from_id("185"), false);
+ }
+ }
+
+ if (!_user_explicit_resolution) {
+ if (video->size_after_crop().width > 2048 || video->size_after_crop().height > 1080) {
+ set_resolution (RESOLUTION_4K, false);
+ } else {
+ set_resolution (RESOLUTION_2K, false);
+ }
+ }
+ }
}
void
Film::remove_content (shared_ptr<Content> c)
{
_playlist->remove (c);
+ maybe_set_container_and_resolution ();
}
void
void move_content_earlier (boost::shared_ptr<Content>);
void move_content_later (boost::shared_ptr<Content>);
void set_dcp_content_type (DCPContentType const *);
- void set_container (Ratio const *);
- void set_resolution (Resolution);
+ void set_container (Ratio const *, bool user_explicit = true);
+ void set_resolution (Resolution, bool user_explicit = true);
void set_signed (bool);
void set_encrypted (bool);
void set_key (dcp::Key key);
void maybe_add_content (boost::weak_ptr<Job>, boost::weak_ptr<Content>, bool disable_audio_analysis);
void audio_analysis_finished ();
void check_settings_consistency ();
+ void maybe_set_container_and_resolution ();
static std::string const metadata_file;
bool _reencode_j2k;
/** true if the user has ever explicitly set the video frame rate of this film */
bool _user_explicit_video_frame_rate;
+ bool _user_explicit_container;
+ bool _user_explicit_resolution;
std::map<dcp::Marker, dcpomatic::DCPTime> _markers;
std::vector<dcp::Rating> _ratings;
std::string _content_version;
int scope = 0;
BOOST_FOREACH (shared_ptr<const Content> i, content) {
if (i->video) {
- Ratio const * r = i->video->scale().ratio ();
+ Ratio const * r = Ratio::nearest_from_ratio(i->video->scaled_size(film->frame_size()).ratio());
if (r && r->id() == "239") {
++scope;
} else if (r && r->id() != "239" && r->id() != "190") {
video.image,
piece->content->video->crop (),
piece->content->video->fade (_film, video.frame),
- piece->content->video->scale().size (
- piece->content->video, _video_container_size, _film->frame_size ()
- ),
+ scale_for_display(piece->content->video->scaled_size(_film->frame_size()), _video_container_size, _film->frame_size()),
_video_container_size,
video.eyes,
video.part,
boost::atomic<int> _suspended;
std::list<boost::shared_ptr<Piece> > _pieces;
- /** Size of the image in the DCP (e.g. 1990x1080 for flat) */
+ /** Size of the image we are rendering to; this may be the DCP frame size, or
+ * the size of preview in a window.
+ */
dcp::Size _video_container_size;
boost::shared_ptr<Image> _black_image;
_crop = content->video->crop();
_fade = content->video->fade(film, _video_frame.get());
- _inter_size = content->video->scale().size(content->video, video_container_size, film_frame_size);
+ _inter_size = scale_for_display(content->video->scaled_size(film_frame_size), video_container_size, film_frame_size);
_out_size = video_container_size;
_colour_conversion = content->video->colour_conversion();
_video_range = content->video->range();
Ratio::setup_ratios ();
PresetColourConversion::setup_colour_conversion_presets ();
- VideoContentScale::setup_scales ();
DCPContentType::setup_dcp_content_types ();
Filter::setup_filters ();
CinemaSoundProcessor::setup_cinema_sound_processors ();
return 20 * log10(linear);
}
+
+dcp::Size
+scale_for_display (dcp::Size s, dcp::Size display_container, dcp::Size film_container)
+{
+ /* Now scale it down if the display container is smaller than the film container */
+ if (display_container != film_container) {
+ float const scale = min (
+ float (display_container.width) / film_container.width,
+ float (display_container.height) / film_container.height
+ );
+
+ s.width = lrintf (s.width * scale);
+ s.height = lrintf (s.height * scale);
+ }
+
+ return s;
+}
+
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);
#endif
+extern dcp::Size scale_for_display (dcp::Size s, dcp::Size display_container, dcp::Size film_container);
template <class T>
std::list<T>
/*
- Copyright (C) 2013-2019 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2020 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
int const VideoContentProperty::FADE_IN = 6;
int const VideoContentProperty::FADE_OUT = 7;
int const VideoContentProperty::RANGE = 8;
+int const VideoContentProperty::CUSTOM_RATIO = 9;
+int const VideoContentProperty::CUSTOM_SIZE = 10;
using std::string;
using std::setprecision;
, _use (true)
, _length (0)
, _frame_type (VIDEO_FRAME_TYPE_2D)
- , _scale (VideoContentScale (Ratio::from_id ("178")))
, _yuv (true)
, _fade_in (0)
, _fade_out (0)
if (version <= 7) {
optional<string> r = node->optional_string_child ("Ratio");
if (r) {
- _scale = VideoContentScale (Ratio::from_id (r.get ()));
+ _legacy_ratio = Ratio::from_id(r.get())->ratio();
}
+ } else if (version <= 37) {
+ optional<string> ratio = node->node_child("Scale")->optional_string_child("Ratio");
+ if (ratio) {
+ _legacy_ratio = Ratio::from_id(ratio.get())->ratio();
+ }
+ optional<bool> scale = node->node_child("Scale")->optional_bool_child("Scale");
+ if (scale) {
+ if (*scale) {
+ /* This is what we used to call "no stretch" */
+ _legacy_ratio = _size.ratio();
+ } else {
+ /* This is what we used to call "no scale" */
+ _custom_size = _size;
+ }
+ }
+
} else {
- _scale = VideoContentScale (node->node_child ("Scale"));
+ _custom_ratio = node->optional_number_child<float>("CustomRatio");
+ if (node->optional_number_child<int>("CustomWidth")) {
+ _custom_size = dcp::Size (node->number_child<int>("CustomWidth"), node->number_child<int>("CustomHeight"));
+ }
}
if (node->optional_node_child ("ColourConversion")) {
throw JoinError (_("Content to be joined must have the same crop."));
}
- if (c[i]->video->scale() != ref->scale()) {
- throw JoinError (_("Content to be joined must have the same scale setting."));
+ if (c[i]->video->custom_ratio() != ref->custom_ratio()) {
+ throw JoinError (_("Content to be joined must have the same custom ratio setting."));
+ }
+
+ if (c[i]->video->custom_size() != ref->custom_size()) {
+ throw JoinError (_("Content to be joined must have the same custom size setting."));
}
if (c[i]->video->colour_conversion() != ref->colour_conversion()) {
_size = ref->size ();
_frame_type = ref->frame_type ();
_crop = ref->crop ();
- _scale = ref->scale ();
+ _custom_ratio = ref->custom_ratio ();
_colour_conversion = ref->colour_conversion ();
_fade_in = ref->fade_in ();
_fade_out = ref->fade_out ();
node->add_child("SampleAspectRatio")->add_child_text (raw_convert<string> (_sample_aspect_ratio.get ()));
}
_crop.as_xml (node);
- _scale.as_xml (node->add_child("Scale"));
+ if (_custom_ratio) {
+ node->add_child("CustomRatio")->add_child_text(raw_convert<string>(*_custom_ratio));
+ }
+ if (_custom_size) {
+ node->add_child("CustomWidth")->add_child_text(raw_convert<string>(_custom_size->width));
+ node->add_child("CustomHeight")->add_child_text(raw_convert<string>(_custom_size->height));
+ }
if (_colour_conversion) {
_colour_conversion.get().as_xml (node->add_child("ColourConversion"));
}
_sample_aspect_ratio = ar;
_yuv = yuv;
_range = range;
-
- if (Config::instance()->default_scale_to ()) {
- _scale = VideoContentScale (Config::instance()->default_scale_to ());
- } else {
- /* Guess correct scale from size and sample aspect ratio */
- _scale = VideoContentScale (
- Ratio::nearest_from_ratio (double (_size.width) * ar.get_value_or (1) / _size.height)
- );
- }
}
LOG_GENERAL ("Video length obtained from header as %1 frames", _length);
{
char buffer[256];
snprintf (
- buffer, sizeof(buffer), "%d_%d_%d_%d_%d_%s_%" PRId64 "_%" PRId64 "_%d",
+ buffer, sizeof(buffer), "%d_%d_%d_%d_%d_%f_%d_%d%" PRId64 "_%" PRId64 "_%d",
(_use ? 1 : 0),
crop().left,
crop().right,
crop().top,
crop().bottom,
- scale().id().c_str(),
+ _custom_ratio.get_value_or(0),
+ _custom_size ? _custom_size->width : 0,
+ _custom_size ? _custom_size->height : 0,
_fade_in,
_fade_out,
_range == VIDEO_RANGE_FULL ? 0 : 1
return crop().apply (size_after_3d_split ());
}
-void
-VideoContent::scale_and_crop_to_fit_width (shared_ptr<const Film> film)
-{
- set_scale (VideoContentScale(film->container()));
-
- int const crop = max (0, int (size().height - double (film->frame_size().height) * size().width / film->frame_size().width));
- set_left_crop (0);
- set_right_crop (0);
- set_top_crop (crop / 2);
- set_bottom_crop (crop / 2);
-}
-
-void
-VideoContent::scale_and_crop_to_fit_height (shared_ptr<const Film> film)
-{
- set_scale (VideoContentScale(film->container()));
-
- int const crop = max (0, int (size().width - double (film->frame_size().width) * size().height / film->frame_size().height));
- set_left_crop (crop / 2);
- set_right_crop (crop / 2);
- set_top_crop (0);
- set_bottom_crop (0);
-}
/** @param f Frame index within the whole (untrimmed) content.
* @return Fade factor (between 0 and 1) or unset if there is no fade.
}
string
-VideoContent::processing_description (shared_ptr<const Film> film) const
+VideoContent::processing_description (shared_ptr<const Film> film)
{
string d;
char buffer[256];
}
dcp::Size const container_size = film->frame_size ();
- dcp::Size const scaled = scale().size (shared_from_this(), container_size, container_size);
+ dcp::Size const scaled = scaled_size (container_size);
if (scaled != size_after_crop ()) {
d += String::compose (
maybe_set (_crop.bottom, c, VideoContentProperty::CROP);
}
-void
-VideoContent::set_scale (VideoContentScale s)
-{
- maybe_set (_scale, s, VideoContentProperty::SCALE);
-}
void
VideoContent::set_frame_type (VideoFrameType t)
set_right_crop (c->_crop.right);
set_top_crop (c->_crop.top);
set_bottom_crop (c->_crop.bottom);
- set_scale (c->_scale);
+ set_custom_ratio (c->_custom_ratio);
+ set_custom_size (c->_custom_size);
set_fade_in (c->_fade_in);
set_fade_out (c->_fade_out);
}
trim = trim.round (_parent->video_frame_rate().get());
}
}
+
+
+/** @param film_container The size of the container for the DCP that we are working on */
+dcp::Size
+VideoContent::scaled_size (dcp::Size film_container)
+{
+ if (_custom_ratio) {
+ return fit_ratio_within(*_custom_ratio, film_container);
+ }
+
+ if (_custom_size) {
+ return *_custom_size;
+ }
+
+ dcp::Size size = size_after_crop ();
+ 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 */
+ dcp::Size 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<float>();
+ return fit_ratio_within(*_custom_ratio, film_container);
+ }
+ _legacy_ratio = 0;
+ }
+
+ return auto_size;
+}
+
+
+void
+VideoContent::set_custom_ratio (optional<float> ratio)
+{
+ maybe_set (_custom_ratio, ratio, VideoContentProperty::CUSTOM_RATIO);
+}
+
+
+void
+VideoContent::set_custom_size (optional<dcp::Size> size)
+{
+ maybe_set (_custom_size, size, VideoContentProperty::CUSTOM_SIZE);
+}
/*
- Copyright (C) 2013-2019 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2020 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
#define DCPOMATIC_VIDEO_CONTENT_H
#include "colour_conversion.h"
-#include "video_content_scale.h"
#include "dcpomatic_time.h"
#include "user_property.h"
#include "types.h"
static int const FADE_IN;
static int const FADE_OUT;
static int const RANGE;
+ static int const CUSTOM_RATIO;
+ static int const CUSTOM_SIZE;
};
class VideoContent : public ContentPart, public boost::enable_shared_from_this<VideoContent>
void set_top_crop (int);
void set_bottom_crop (int);
- void set_scale (VideoContentScale);
+ void set_custom_ratio (boost::optional<float> ratio);
+ void set_custom_size (boost::optional<dcp::Size> size);
+
void unset_colour_conversion ();
void set_colour_conversion (ColourConversion);
return _crop.bottom;
}
- /** @return Description of how to scale this content (if indeed it should be scaled) */
- VideoContentScale scale () const {
+
+ boost::optional<float> custom_ratio () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _custom_ratio;
+ }
+
+
+ boost::optional<dcp::Size> custom_size () const {
boost::mutex::scoped_lock lm (_mutex);
- return _scale;
+ return _custom_size;
}
+
boost::optional<ColourConversion> colour_conversion () const {
boost::mutex::scoped_lock lm (_mutex);
return _colour_conversion;
return _use;
}
+ /* XXX: names for these? */
dcp::Size size_after_3d_split () const;
dcp::Size size_after_crop () const;
+ dcp::Size scaled_size (dcp::Size container_size);
boost::optional<double> fade (boost::shared_ptr<const Film> film, Frame) const;
- void scale_and_crop_to_fit_width (boost::shared_ptr<const Film> film);
- void scale_and_crop_to_fit_height (boost::shared_ptr<const Film> film);
-
- std::string processing_description (boost::shared_ptr<const Film> film) const;
+ std::string processing_description (boost::shared_ptr<const Film> film);
void set_length (Frame);
friend struct best_dcp_frame_rate_test_single;
friend struct best_dcp_frame_rate_test_double;
friend struct audio_sampling_rate_test;
+ friend struct scaled_size_test1;
+ friend struct scaled_size_test2;
+ friend struct scaled_size_legacy_test;
VideoContent (Content* parent, cxml::ConstNodePtr, int);
void setup_default_colour_conversion ();
dcp::Size _size;
VideoFrameType _frame_type;
Crop _crop;
- VideoContentScale _scale;
+ /** ratio to scale cropped image to (or none to guess); i.e. if set, scale to _custom_ratio:1 */
+ boost::optional<float> _custom_ratio;
+ /** size to scale cropped image to; only used if _custom_ratio is none */
+ boost::optional<dcp::Size> _custom_size;
+ /** ratio obtained from an older metadata file; will be used to set up
+ * _custom_{ratio,size} (or not, if not required) on the first call to
+ * scaled_size()
+ */
+ boost::optional<float> _legacy_ratio;
/** Sample aspect ratio obtained from the content file's header, if there is one */
boost::optional<double> _sample_aspect_ratio;
bool _yuv;
+++ /dev/null
-/*
- Copyright (C) 2013-2018 Carl Hetherington <cth@carlh.net>
-
- This file is part of DCP-o-matic.
-
- DCP-o-matic 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.
-
- DCP-o-matic 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 DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
-
-*/
-
-#include "video_content_scale.h"
-#include "video_content.h"
-#include "ratio.h"
-#include "util.h"
-#include <libcxml/cxml.h>
-#include <libxml++/libxml++.h>
-#include <boost/optional.hpp>
-#include <iostream>
-
-#include "i18n.h"
-
-using std::vector;
-using std::string;
-using std::min;
-using std::cout;
-using boost::shared_ptr;
-using boost::optional;
-
-vector<VideoContentScale> VideoContentScale::_scales;
-
-VideoContentScale::VideoContentScale (Ratio const * r)
- : _ratio (r)
- , _scale (true)
-{
-
-}
-
-VideoContentScale::VideoContentScale ()
- : _ratio (0)
- , _scale (false)
-{
-
-}
-
-VideoContentScale::VideoContentScale (bool scale)
- : _ratio (0)
- , _scale (scale)
-{
-
-}
-
-VideoContentScale::VideoContentScale (shared_ptr<cxml::Node> node)
- : _ratio (0)
- , _scale (true)
-{
- optional<string> r = node->optional_string_child ("Ratio");
- if (r) {
- _ratio = Ratio::from_id (r.get ());
- } else {
- _scale = node->bool_child ("Scale");
- }
-}
-
-void
-VideoContentScale::as_xml (xmlpp::Node* node) const
-{
- if (_ratio) {
- node->add_child("Ratio")->add_child_text (_ratio->id ());
- } else {
- node->add_child("Scale")->add_child_text (_scale ? "1" : "0");
- }
-}
-
-string
-VideoContentScale::id () const
-{
- if (_ratio) {
- return _ratio->id ();
- }
-
- return (_scale ? "S1" : "S0");
-}
-
-string
-VideoContentScale::name () const
-{
- if (_ratio) {
- return _ratio->image_nickname ();
- }
-
- if (_scale) {
- return _("No stretch");
- }
-
- return _("No scale");
-}
-
-/** @param display_container Size of the container that we are displaying this content in.
- * @param film_container The size of the film's image.
- * @return Size, in pixels that the VideoContent's image should be scaled to (taking into account its pixel aspect ratio)
- */
-dcp::Size
-VideoContentScale::size (shared_ptr<const VideoContent> c, dcp::Size display_container, dcp::Size film_container) const
-{
- /* Work out the size of the content if it were put inside film_container */
-
- dcp::Size video_size_after_crop = c->size_after_crop();
- video_size_after_crop.width *= c->sample_aspect_ratio().get_value_or(1);
-
- dcp::Size size;
-
- if (_ratio) {
- /* Stretch to fit the requested ratio */
- size = fit_ratio_within (_ratio->ratio (), film_container);
- } else if (_scale || video_size_after_crop.width > film_container.width || video_size_after_crop.height > film_container.height) {
- /* Scale, preserving aspect ratio; this is either if we have been asked to scale with no stretch
- or if the unscaled content is too big for film_container.
- */
- size = fit_ratio_within (video_size_after_crop.ratio(), film_container);
- } else {
- /* No stretch nor scale */
- size = video_size_after_crop;
- }
-
- /* Now scale it down if the display container is smaller than the film container */
- if (display_container != film_container) {
- float const scale = min (
- float (display_container.width) / film_container.width,
- float (display_container.height) / film_container.height
- );
-
- size.width = lrintf (size.width * scale);
- size.height = lrintf (size.height * scale);
- }
-
- return size;
-}
-
-void
-VideoContentScale::setup_scales ()
-{
- vector<Ratio const *> ratios = Ratio::all ();
- for (vector<Ratio const *>::const_iterator i = ratios.begin(); i != ratios.end(); ++i) {
- _scales.push_back (VideoContentScale (*i));
- }
-
- _scales.push_back (VideoContentScale (true));
- _scales.push_back (VideoContentScale (false));
-}
-
-bool
-operator== (VideoContentScale const & a, VideoContentScale const & b)
-{
- return (a.ratio() == b.ratio() && a.scale() == b.scale());
-}
-
-bool
-operator!= (VideoContentScale const & a, VideoContentScale const & b)
-{
- return (a.ratio() != b.ratio() || a.scale() != b.scale());
-}
+++ /dev/null
-/*
- Copyright (C) 2013-2018 Carl Hetherington <cth@carlh.net>
-
- This file is part of DCP-o-matic.
-
- DCP-o-matic 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.
-
- DCP-o-matic 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 DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
-
-*/
-
-#ifndef DCPOMATIC_VIDEO_CONTENT_SCALE_H
-#define DCPOMATIC_VIDEO_CONTENT_SCALE_H
-
-#include <dcp/util.h>
-#include <boost/shared_ptr.hpp>
-#include <vector>
-
-namespace cxml {
- class Node;
-}
-
-namespace xmlpp {
- class Node;
-}
-
-class Ratio;
-class VideoContent;
-
-class VideoContentScale
-{
-public:
- VideoContentScale ();
- explicit VideoContentScale (Ratio const *);
- explicit VideoContentScale (bool);
- explicit VideoContentScale (boost::shared_ptr<cxml::Node>);
-
- dcp::Size size (boost::shared_ptr<const VideoContent>, dcp::Size display_container, dcp::Size film_container) const;
- std::string id () const;
- std::string name () const;
- void as_xml (xmlpp::Node *) const;
-
- Ratio const * ratio () const {
- return _ratio;
- }
-
- bool scale () const {
- return _scale;
- }
-
- static void setup_scales ();
- static std::vector<VideoContentScale> all () {
- return _scales;
- }
-
-private:
- /** a ratio to stretch the content to, or 0 for no stretch */
- Ratio const * _ratio;
- /** true if we want to change the size of the content in any way */
- bool _scale;
-
- /* If _ratio is 0 and _scale is false there is no scale at all (i.e.
- the content is used at its original size)
- */
-
- static std::vector<VideoContentScale> _scales;
-};
-
-bool operator== (VideoContentScale const & a, VideoContentScale const & b);
-bool operator!= (VideoContentScale const & a, VideoContentScale const & b);
-
-#endif
util.cc
verify_dcp_job.cc
video_content.cc
- video_content_scale.cc
video_decoder.cc
video_filter_graph.cc
video_mxf_content.cc
ID_file_close = 100,
ID_edit_copy,
ID_edit_paste,
- ID_content_scale_to_fit_width,
- ID_content_scale_to_fit_height,
ID_jobs_make_dcp,
ID_jobs_make_dcp_batch,
ID_jobs_make_kdms,
Bind (wxEVT_MENU, boost::bind (&DOMFrame::edit_copy, this), ID_edit_copy);
Bind (wxEVT_MENU, boost::bind (&DOMFrame::edit_paste, this), ID_edit_paste);
Bind (wxEVT_MENU, boost::bind (&DOMFrame::edit_preferences, this), wxID_PREFERENCES);
- Bind (wxEVT_MENU, boost::bind (&DOMFrame::content_scale_to_fit_width, this), ID_content_scale_to_fit_width);
- Bind (wxEVT_MENU, boost::bind (&DOMFrame::content_scale_to_fit_height, this), ID_content_scale_to_fit_height);
Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_make_dcp, this), ID_jobs_make_dcp);
Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_make_kdms, this), ID_jobs_make_kdms);
Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_make_dkdms, this), ID_jobs_make_dkdms);
d->Destroy ();
}
- void content_scale_to_fit_width ()
- {
- ContentList vc = _film_editor->content_panel()->selected_video ();
- for (ContentList::iterator i = vc.begin(); i != vc.end(); ++i) {
- (*i)->video->scale_and_crop_to_fit_width (_film);
- }
- }
-
- void content_scale_to_fit_height ()
- {
- ContentList vc = _film_editor->content_panel()->selected_video ();
- for (ContentList::iterator i = vc.begin(); i != vc.end(); ++i) {
- (*i)->video->scale_and_crop_to_fit_height (_film);
- }
- }
-
void jobs_send_dcp_to_tms ()
{
_film->send_dcp_to_tms ();
add_item (edit, _("&Preferences...\tCtrl-P"), wxID_PREFERENCES, ALWAYS);
#endif
- wxMenu* content = new wxMenu;
- add_item (content, _("Scale to fit &width"), ID_content_scale_to_fit_width, NEEDS_FILM | NEEDS_SELECTED_VIDEO_CONTENT);
- add_item (content, _("Scale to fit &height"), ID_content_scale_to_fit_height, NEEDS_FILM | NEEDS_SELECTED_VIDEO_CONTENT);
-
wxMenu* jobs_menu = new wxMenu;
add_item (jobs_menu, _("&Make DCP\tCtrl-M"), ID_jobs_make_dcp, NEEDS_FILM | NOT_DURING_DCP_CREATION);
add_item (jobs_menu, _("Make DCP in &batch converter\tCtrl-B"), ID_jobs_make_dcp_batch, NEEDS_FILM | NOT_DURING_DCP_CREATION);
m->Append (_file_menu, _("&File"));
m->Append (edit, _("&Edit"));
- m->Append (content, _("&Content"));
m->Append (jobs_menu, _("&Jobs"));
m->Append (view, _("&View"));
m->Append (tools, _("&Tools"));
<< "\tcrop left " << c->video->left_crop()
<< " right " << c->video->right_crop()
<< " top " << c->video->top_crop()
- << " bottom " << c->video->bottom_crop() << "\n"
- << "\tscale " << c->video->scale().name() << "\n";
+ << " bottom " << c->video->bottom_crop() << "\n";
+ if (c->video->custom_ratio()) {
+ cout << "\tscale to custom ratio " << *c->video->custom_ratio() << ":1\n";
+ }
if (c->video->colour_conversion()) {
if (c->video->colour_conversion().get().preset()) {
cout << "\tcolour conversion "
}
film->set_name (cc.name);
- film->set_container (cc.container_ratio);
+ if (cc.container_ratio) {
+ film->set_container (cc.container_ratio);
+ }
film->set_dcp_content_type (cc.dcp_content_type);
film->set_interop (cc.standard == dcp::INTEROP);
film->set_use_isdcf_name (!cc.no_use_isdcf_name);
film->set_signed (!cc.no_sign);
film->set_encrypted (cc.encrypt);
film->set_three_d (cc.threed);
- film->set_resolution (cc.fourk ? RESOLUTION_4K : RESOLUTION_2K);
+ if (cc.fourk) {
+ film->set_resolution (RESOLUTION_4K);
+ }
if (cc.j2k_bandwidth) {
film->set_j2k_bandwidth (*cc.j2k_bandwidth);
}
BOOST_FOREACH (shared_ptr<Content> j, content) {
if (j->video) {
- j->video->set_scale (VideoContentScale(cc.content_ratio));
j->video->set_frame_type (i.frame_type);
}
}
* @param part Part of Content that the property is in (e.g. &Content::video)
* @param model_getter Function on the Content to get the value.
* @param model_setter Function on the Content to set the value.
+ * @param view_changed Function called when the view has changed; useful for linking controls.
* @param view_to_model Function to convert a view value to a model value.
* @param model_to_view Function to convert a model value to a view value.
*/
boost::function<boost::shared_ptr<S> (Content*)> part,
boost::function<U (S*)> model_getter,
boost::function<void (S*, U)> model_setter,
+ boost::function<void ()> view_changed,
boost::function<U (V)> view_to_model,
boost::function<V (U)> model_to_view
)
, _part (part)
, _model_getter (model_getter)
, _model_setter (model_setter)
+ , _view_changed (view_changed)
, _view_to_model (view_to_model)
, _model_to_view (model_to_view)
, _ignore_model_changes (false)
for (size_t i = 0; i < _content.size(); ++i) {
boost::bind (_model_setter, _part (_content[i].get()).get(), _view_to_model (wx_get (_wrapped))) ();
}
+ if (_view_changed) {
+ _view_changed ();
+ }
_ignore_model_changes = false;
}
boost::function<boost::shared_ptr<S> (Content *)> _part;
boost::function<U (S*)> _model_getter;
boost::function<void (S*, U)> _model_setter;
+ boost::function<void ()> _view_changed;
boost::function<U (V)> _view_to_model;
boost::function<V (U)> _model_to_view;
std::list<boost::signals2::connection> _connections;
int property,
boost::function<boost::shared_ptr<S> (Content *)> part,
boost::function<int (S*)> getter,
- boost::function<void (S*, int)> setter
+ boost::function<void (S*, int)> setter,
+ boost::function<void ()> view_changed = boost::function<void ()>()
)
: ContentWidget<S, wxSpinCtrl, int, int> (
parent,
property,
part,
getter, setter,
+ view_changed,
&caster<int, int>,
&caster<int, int>
)
int property,
boost::function<boost::shared_ptr<S> (Content *)> part,
boost::function<double (S*)> getter,
- boost::function<void (S*, double)> setter
+ boost::function<void (S*, double)> setter,
+ boost::function<void ()> view_changed = boost::function<void ()>()
)
: ContentWidget<S, wxSpinCtrlDouble, double, double> (
parent,
property,
part,
getter, setter,
+ view_changed,
&caster<double, double>,
&caster<double, double>
)
boost::function<U (S*)> getter,
boost::function<void (S*, U)> setter,
boost::function<U (int)> view_to_model,
- boost::function<int (U)> model_to_view
+ boost::function<int (U)> model_to_view,
+ boost::function<void ()> view_changed = boost::function<void()>()
)
: ContentWidget<S, wxChoice, U, int> (
parent,
part,
getter,
setter,
+ view_changed,
view_to_model,
model_to_view
)
--- /dev/null
+/*
+ Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
+
+ This file is part of DCP-o-matic.
+
+ DCP-o-matic 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.
+
+ DCP-o-matic 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 DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "custom_scale_dialog.h"
+#include "wx_util.h"
+#include "lib/util.h"
+#include <dcp/raw_convert.h>
+#include <wx/wx.h>
+#include <wx/propgrid/property.h>
+#include <wx/propgrid/props.h>
+
+
+using boost::optional;
+using namespace dcp;
+
+
+CustomScaleDialog::CustomScaleDialog (wxWindow* parent, dcp::Size initial, dcp::Size film_container, optional<float> custom_ratio, optional<dcp::Size> custom_size)
+ : TableDialog (parent, _("Custom scale"), 3, 1, true)
+ , _film_container (film_container)
+{
+ _ratio_to_fit = new wxRadioButton (this, wxID_ANY, _("Set ratio and fit to DCP container"));
+ add (_ratio_to_fit);
+ wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+ _ratio = new wxTextCtrl (this, wxID_ANY, _(""), wxDefaultPosition, wxDefaultSize, 0, wxNumericPropertyValidator(wxNumericPropertyValidator::Float));
+ s->Add (_ratio, 1, wxRIGHT, 4);
+ add_label_to_sizer (s, this, wxT(":1"), false);
+ add (s);
+ _size_from_ratio = new wxStaticText (this, wxID_ANY, wxT(""));
+ add (_size_from_ratio, 1, wxALIGN_CENTER_VERTICAL);
+
+ _size = new wxRadioButton (this, wxID_ANY, _("Set size"));
+ add (_size);
+ s = new wxBoxSizer (wxHORIZONTAL);
+ _width = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(64, -1), wxSP_ARROW_KEYS, 1, film_container.width);
+ s->Add (_width, 1, wxRIGHT, 4);
+ add_label_to_sizer (s, this, wxT("x"), false);
+ _height = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(64, -1), wxSP_ARROW_KEYS, 1, film_container.height);
+ s->Add (_height, 1, wxRIGHT, 4);
+ add (s);
+ _ratio_from_size = new wxStaticText (this, wxID_ANY, wxT(""));
+ add (_ratio_from_size, 1, wxALIGN_CENTER_VERTICAL);
+
+ if (custom_ratio) {
+ _ratio_to_fit->SetValue (true);
+ _size->SetValue (false);
+ _ratio->SetValue (wxString::Format("%.2f", *custom_ratio));
+ _width->SetValue (initial.width);
+ _height->SetValue (initial.height);
+ } else if (custom_size) {
+ _ratio_to_fit->SetValue (false);
+ _size->SetValue (true);
+ _ratio->SetValue (wxString::Format("%.2f", initial.ratio()));
+ _width->SetValue (custom_size->width);
+ _height->SetValue (custom_size->height);
+ } else {
+ _ratio_to_fit->SetValue (true);
+ _size->SetValue (false);
+ _ratio->SetValue (wxString::Format("%.2f", initial.ratio()));
+ _width->SetValue (initial.width);
+ _height->SetValue (initial.height);
+ }
+
+ setup_sensitivity ();
+ update_size_from_ratio ();
+ update_ratio_from_size ();
+
+ layout ();
+
+ _ratio_to_fit->Bind (wxEVT_RADIOBUTTON, boost::bind(&CustomScaleDialog::setup_sensitivity, this));
+ _ratio->Bind (wxEVT_TEXT, boost::bind(&CustomScaleDialog::update_size_from_ratio, this));
+ _size->Bind (wxEVT_RADIOBUTTON, boost::bind(&CustomScaleDialog::setup_sensitivity, this));
+ _width->Bind (wxEVT_TEXT, boost::bind(&CustomScaleDialog::update_ratio_from_size, this));
+ _height->Bind (wxEVT_TEXT, boost::bind(&CustomScaleDialog::update_ratio_from_size, this));
+}
+
+
+void
+CustomScaleDialog::update_size_from_ratio ()
+{
+ dcp::Size const s = fit_ratio_within (raw_convert<float>(wx_to_std(_ratio->GetValue())), _film_container);
+ _size_from_ratio->SetLabelMarkup (wxString::Format("<i>%dx%d</i>", s.width, s.height));
+}
+
+
+void
+CustomScaleDialog::update_ratio_from_size ()
+{
+ float const ratio = _height->GetValue() > 0 ? (float(_width->GetValue()) / _height->GetValue()) : 2;
+ _ratio_from_size->SetLabelMarkup (wxString::Format("<i>%.2f:1</i>", ratio));
+}
+
+
+void
+CustomScaleDialog::setup_sensitivity ()
+{
+ _ratio->Enable (_ratio_to_fit->GetValue());
+ _size_from_ratio->Enable (_ratio_to_fit->GetValue());
+ _width->Enable (_size->GetValue());
+ _height->Enable (_size->GetValue());
+ _ratio_from_size->Enable (_size->GetValue());
+}
+
+
+optional<float>
+CustomScaleDialog::custom_ratio () const
+{
+ if (!_ratio_to_fit->GetValue()) {
+ return optional<float>();
+ }
+
+ return raw_convert<float>(wx_to_std(_ratio->GetValue()));
+}
+
+
+optional<dcp::Size>
+CustomScaleDialog::custom_size () const
+{
+ if (!_size->GetValue()) {
+ return optional<dcp::Size>();
+ }
+
+ return dcp::Size (_width->GetValue(), _height->GetValue());
+}
+
--- /dev/null
+/*
+ Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
+
+ This file is part of DCP-o-matic.
+
+ DCP-o-matic 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.
+
+ DCP-o-matic 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 DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "table_dialog.h"
+#include <dcp/types.h>
+#include <wx/wx.h>
+#include <wx/spinctrl.h>
+
+
+class CustomScaleDialog : public TableDialog
+{
+public:
+ CustomScaleDialog (wxWindow* parent, dcp::Size initial, dcp::Size film_container, boost::optional<float> custom_ratio, boost::optional<dcp::Size> custom_size);
+
+ boost::optional<float> custom_ratio () const;
+ boost::optional<dcp::Size> custom_size () const;
+
+private:
+ void update_size_from_ratio ();
+ void update_ratio_from_size ();
+ void setup_sensitivity ();
+
+ wxRadioButton* _ratio_to_fit;
+ wxTextCtrl* _ratio;
+ wxStaticText* _size_from_ratio;
+ wxRadioButton* _size;
+ wxSpinCtrl* _width;
+ wxSpinCtrl* _height;
+ wxStaticText* _ratio_from_size;
+
+ dcp::Size _film_container;
+};
+
_container = new wxChoice (_panel, wxID_ANY);
table->Add (_container);
- add_label_to_sizer (table, _panel, _("Default scale-to"), true);
- _scale_to = new wxChoice (_panel, wxID_ANY);
- table->Add (_scale_to);
-
add_label_to_sizer (table, _panel, _("Default content type"), true);
_dcp_content_type = new wxChoice (_panel, wxID_ANY);
table->Add (_dcp_content_type);
_container->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::container_changed, this));
- _scale_to->Append (_("Guess from content"));
-
- BOOST_FOREACH (Ratio const * i, Ratio::all()) {
- _scale_to->Append (std_to_wx(i->image_nickname()));
- }
-
- _scale_to->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::scale_to_changed, this));
-
BOOST_FOREACH (DCPContentType const * i, DCPContentType::all()) {
_dcp_content_type->Append (std_to_wx (i->pretty_name ()));
}
}
}
- vector<Ratio const *> ratios = Ratio::all ();
- for (size_t i = 0; i < ratios.size(); ++i) {
- if (ratios[i] == config->default_scale_to ()) {
- _scale_to->SetSelection (i + 1);
- }
- }
-
- if (!config->default_scale_to()) {
- _scale_to->SetSelection (0);
- }
-
vector<DCPContentType const *> const ct = DCPContentType::all ();
for (size_t i = 0; i < ct.size(); ++i) {
if (ct[i] == config->default_dcp_content_type ()) {
Config::instance()->set_default_container (ratio[_container->GetSelection()]);
}
- void scale_to_changed ()
- {
- int const s = _scale_to->GetSelection ();
- if (s == 0) {
- Config::instance()->set_default_scale_to (0);
- } else {
- vector<Ratio const *> ratio = Ratio::all ();
- Config::instance()->set_default_scale_to (ratio[s - 1]);
- }
- }
-
void dcp_content_type_changed ()
{
vector<DCPContentType const *> ct = DCPContentType::all ();
wxDirPickerCtrl* _kdm_directory;
#endif
wxChoice* _container;
- wxChoice* _scale_to;
wxChoice* _dcp_content_type;
wxChoice* _dcp_audio_channels;
wxChoice* _standard;
_film_changed_connection = film->Change.connect (bind (&TimelineDialog::film_change, this, _1, _2));
}
-wxString
-TimelineDialog::bitmap_path (string name)
-{
- boost::filesystem::path base;
-
-#ifdef DCPOMATIC_DEBUG
- /* Hack to allow OS X to find icons when running from the source tree */
- char* path = getenv ("DCPOMATIC_GRAPHICS");
- if (path) {
- base = path;
- } else {
- base = shared_path();
- }
-#else
- base = shared_path();
-#endif
-
- boost::filesystem::path p = base / String::compose("%1.png", name);
- return std_to_wx (p.string());
-}
-
void
TimelineDialog::film_change (ChangeType type, Film::Property p)
{
private:
void film_change (ChangeType type, Film::Property);
void tool_clicked (wxCommandEvent& id);
- wxString bitmap_path (std::string name);
boost::weak_ptr<Film> _film;
Timeline _timeline;
/*
- Copyright (C) 2012-2018 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
#include "content_panel.h"
#include "static_text.h"
#include "check_box.h"
+#include "custom_scale_dialog.h"
#include "dcpomatic_button.h"
#include "lib/filter.h"
#include "lib/ffmpeg_content.h"
#include "lib/dcp_content.h"
#include "lib/video_content.h"
#include <wx/spinctrl.h>
+#include <wx/tglbtn.h>
#include <boost/foreach.hpp>
#include <boost/unordered_set.hpp>
#include <boost/functional/hash.hpp>
using boost::optional;
using namespace dcpomatic;
-static VideoContentScale
-index_to_scale (int n)
-{
- vector<VideoContentScale> scales = VideoContentScale::all ();
- DCPOMATIC_ASSERT (n >= 0);
- DCPOMATIC_ASSERT (n < int (scales.size ()));
- return scales[n];
-}
-
-static int
-scale_to_index (VideoContentScale scale)
-{
- vector<VideoContentScale> scales = VideoContentScale::all ();
- for (size_t i = 0; i < scales.size(); ++i) {
- if (scales[i] == scale) {
- return i;
- }
- }
-
- DCPOMATIC_ASSERT (false);
-}
VideoPanel::VideoPanel (ContentPanel* p)
: ContentSubPanel (p, _("Video"))
&caster<VideoFrameType, int>
);
- _left_crop_label = create_label (this, _("Left crop"), true);
+ _crop_label = create_label (this, _("Crop"), true);
+
+ int const crop_width = 56;
+ int const link_height = 28;
+
+ _left_crop_label = create_label (this, _("Left"), true);
_left_crop = new ContentSpinCtrl<VideoContent> (
this,
- new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)),
+ new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(crop_width, -1)),
VideoContentProperty::CROP,
&Content::video,
boost::mem_fn (&VideoContent::left_crop),
- boost::mem_fn (&VideoContent::set_left_crop)
+ boost::mem_fn (&VideoContent::set_left_crop),
+ boost::bind (&VideoPanel::left_crop_changed, this)
);
- _right_crop_label = create_label (this, _("Right crop"), true);
+ _left_right_link = new wxToggleButton (this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(22, link_height));
+ _left_right_link->SetBitmap (wxBitmap(bitmap_path("link"), wxBITMAP_TYPE_PNG));
+
+ _right_crop_label = create_label (this, _("Right"), true);
_right_crop = new ContentSpinCtrl<VideoContent> (
this,
- new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)),
+ new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(crop_width, -1)),
VideoContentProperty::CROP,
&Content::video,
boost::mem_fn (&VideoContent::right_crop),
- boost::mem_fn (&VideoContent::set_right_crop)
+ boost::mem_fn (&VideoContent::set_right_crop),
+ boost::bind (&VideoPanel::right_crop_changed, this)
);
- _top_crop_label = create_label (this, _("Top crop"), true);
+ _top_crop_label = create_label (this, _("Top"), true);
_top_crop = new ContentSpinCtrl<VideoContent> (
this,
- new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)),
+ new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(crop_width, -1)),
VideoContentProperty::CROP,
&Content::video,
boost::mem_fn (&VideoContent::top_crop),
- boost::mem_fn (&VideoContent::set_top_crop)
+ boost::mem_fn (&VideoContent::set_top_crop),
+ boost::bind (&VideoPanel::top_crop_changed, this)
);
- _bottom_crop_label = create_label (this, _("Bottom crop"), true);
+ _top_bottom_link = new wxToggleButton (this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(22, link_height));
+ _top_bottom_link->SetBitmap (wxBitmap(bitmap_path("link"), wxBITMAP_TYPE_PNG));
+
+ _bottom_crop_label = create_label (this, _("Bottom"), true);
_bottom_crop = new ContentSpinCtrl<VideoContent> (
this,
- new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)),
+ new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(crop_width, -1)),
VideoContentProperty::CROP,
&Content::video,
boost::mem_fn (&VideoContent::bottom_crop),
- boost::mem_fn (&VideoContent::set_bottom_crop)
+ boost::mem_fn (&VideoContent::set_bottom_crop),
+ boost::bind (&VideoPanel::bottom_crop_changed, this)
);
_fade_in_label = create_label (this, _("Fade in"), true);
_fade_out_label = create_label (this, _("Fade out"), true);
_fade_out = new Timecode<ContentTime> (this);
- _scale_to_label = create_label (this, _("Scale to"), true);
- _scale = new ContentChoice<VideoContent, VideoContentScale> (
- this,
- new wxChoice (this, wxID_ANY),
- VideoContentProperty::SCALE,
- &Content::video,
- boost::mem_fn (&VideoContent::scale),
- boost::mem_fn (&VideoContent::set_scale),
- &index_to_scale,
- &scale_to_index
- );
-
wxClientDC dc (this);
wxSize size = dc.GetTextExtent (wxT ("A quite long name"));
size.SetHeight (-1);
+ _scale_label = create_label (this, _("Scale"), true);
+ _scale_fit = new wxRadioButton (this, wxID_ANY, _("to fit DCP"));
+ _scale_custom = new wxRadioButton (this, wxID_ANY, _("custom"), wxDefaultPosition, size);
+ _scale_custom_edit = new Button (this, _("Edit..."));
+
_filters_label = create_label (this, _("Filters"), true);
_filters = new StaticText (this, _("None"), wxDefaultPosition, size);
_filters_button = new Button (this, _("Edit..."));
_right_crop->wrapped()->SetRange (0, 4096);
_bottom_crop->wrapped()->SetRange (0, 4096);
- _scale->wrapped()->Clear ();
- BOOST_FOREACH (VideoContentScale const & i, VideoContentScale::all ()) {
- _scale->wrapped()->Append (std_to_wx (i.name ()));
- }
-
_frame_type->wrapped()->Append (_("2D"));
_frame_type->wrapped()->Append (_("3D"));
_frame_type->wrapped()->Append (_("3D left/right"));
_use->Bind (wxEVT_CHECKBOX, boost::bind (&VideoPanel::use_clicked, this));
_reference->Bind (wxEVT_CHECKBOX, boost::bind (&VideoPanel::reference_clicked, this));
_filters_button->Bind (wxEVT_BUTTON, boost::bind (&VideoPanel::edit_filters_clicked, this));
+ _scale_fit->Bind (wxEVT_RADIOBUTTON, boost::bind (&VideoPanel::scale_fit_clicked, this));
+ _scale_custom->Bind (wxEVT_RADIOBUTTON, boost::bind (&VideoPanel::scale_custom_clicked, this));
+ _scale_custom_edit->Bind (wxEVT_BUTTON, boost::bind (&VideoPanel::scale_custom_edit_clicked, this));
_colour_conversion->Bind (wxEVT_CHOICE, boost::bind (&VideoPanel::colour_conversion_changed, this));
_range->Bind (wxEVT_CHOICE, boost::bind (&VideoPanel::range_changed, this));
_edit_colour_conversion_button->Bind (wxEVT_BUTTON, boost::bind (&VideoPanel::edit_colour_conversion_clicked, this));
+ _left_right_link->Bind (wxEVT_TOGGLEBUTTON, boost::bind(&VideoPanel::left_right_link_clicked, this));
+ _top_bottom_link->Bind (wxEVT_TOGGLEBUTTON, boost::bind(&VideoPanel::top_bottom_link_clicked, this));
add_to_grid ();
}
wxGridBagSizer* crop = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
add_label_to_sizer (crop, _left_crop_label, true, wxGBPosition (cr, 0));
_left_crop->add (crop, wxGBPosition (cr, 1));
- add_label_to_sizer (crop, _right_crop_label, true, wxGBPosition (cr, 2));
- _right_crop->add (crop, wxGBPosition (cr, 3));
+ crop->Add (_left_right_link, wxGBPosition(cr, 2));
+ add_label_to_sizer (crop, _right_crop_label, true, wxGBPosition (cr, 3));
+ _right_crop->add (crop, wxGBPosition (cr, 4));
++cr;
add_label_to_sizer (crop, _top_crop_label, true, wxGBPosition (cr, 0));
_top_crop->add (crop, wxGBPosition (cr, 1));
- add_label_to_sizer (crop, _bottom_crop_label, true, wxGBPosition (cr, 2));
- _bottom_crop->add (crop, wxGBPosition (cr, 3));
- _grid->Add (crop, wxGBPosition (r, 0), wxGBSpan (2, 4));
- r += 2;
+ crop->Add (_top_bottom_link, wxGBPosition(cr, 2));
+ add_label_to_sizer (crop, _bottom_crop_label, true, wxGBPosition (cr, 3));
+ _bottom_crop->add (crop, wxGBPosition (cr, 4));
+ add_label_to_sizer (_grid, _crop_label, true, wxGBPosition(r, 0));
+ _grid->Add (crop, wxGBPosition(r, 1));
+ ++r;
- _scale_to_label->Show (full);
- _scale->show (full);
+ _scale_label->Show (full);
+ _scale_fit->Show (full);
+ _scale_custom->Show (full);
+ _scale_custom_edit->Show (full);
_filters_label->Show (full);
_filters->Show (full);
_filters_button->Show (full);
++r;
if (full) {
- add_label_to_sizer (_grid, _scale_to_label, true, wxGBPosition (r, 0));
- _scale->add (_grid, wxGBPosition (r, 1), wxGBSpan (1, 2));
+ add_label_to_sizer (_grid, _scale_label, true, wxGBPosition (r, 0));
+ {
+ wxSizer* v = new wxBoxSizer (wxVERTICAL);
+ v->Add (_scale_fit, 0, wxBOTTOM, 4);
+ wxSizer* h = new wxBoxSizer (wxHORIZONTAL);
+ h->Add (_scale_custom, 1, wxRIGHT, 6);
+ h->Add (_scale_custom_edit, 0);
+ v->Add (h, 0);
+ _grid->Add (v, wxGBPosition(r, 1));
+ }
++r;
add_label_to_sizer (_grid, _filters_label, true, wxGBPosition (r, 0));
checked_set (_range, 0);
}
+ setup_sensitivity ();
+ } else if (property == VideoContentProperty::CUSTOM_RATIO || property == VideoContentProperty::CUSTOM_SIZE) {
+ set<Frame> check;
+ BOOST_FOREACH (shared_ptr<const Content> i, vc) {
+ check.insert (i->video->custom_ratio() || i->video->custom_size());
+ }
+
+ if (check.size() == 1) {
+ checked_set (_scale_fit, !vc.front()->video->custom_ratio() && !vc.front()->video->custom_size());
+ checked_set (_scale_custom, vc.front()->video->custom_ratio() || vc.front()->video->custom_size());
+ } else {
+ checked_set (_scale_fit, true);
+ checked_set (_scale_custom, false);
+ }
setup_sensitivity ();
}
}
_right_crop->set_content (video_sel);
_top_crop->set_content (video_sel);
_bottom_crop->set_content (video_sel);
- _scale->set_content (video_sel);
film_content_changed (ContentProperty::VIDEO_FRAME_RATE);
film_content_changed (VideoContentProperty::CROP);
film_content_changed (VideoContentProperty::FADE_OUT);
film_content_changed (VideoContentProperty::RANGE);
film_content_changed (VideoContentProperty::USE);
+ film_content_changed (VideoContentProperty::CUSTOM_RATIO);
+ film_content_changed (VideoContentProperty::CUSTOM_SIZE);
film_content_changed (FFmpegContentProperty::FILTERS);
film_content_changed (DCPContentProperty::REFERENCE_VIDEO);
_bottom_crop->wrapped()->Enable (false);
_fade_in->Enable (false);
_fade_out->Enable (false);
- _scale->wrapped()->Enable (false);
+ _scale_fit->Enable (false);
+ _scale_custom->Enable (false);
+ _scale_custom_edit->Enable (false);
_description->Enable (false);
_filters->Enable (false);
_filters_button->Enable (false);
_bottom_crop->wrapped()->Enable (true);
_fade_in->Enable (!video_sel.empty ());
_fade_out->Enable (!video_sel.empty ());
- _scale->wrapped()->Enable (true);
+ _scale_fit->Enable (true);
+ _scale_custom->Enable (true);
+ _scale_custom_edit->Enable (_scale_custom->GetValue());
_description->Enable (true);
_filters->Enable (true);
_filters_button->Enable (single && !ffmpeg_sel.empty ());
d->set_reference_video (_reference->GetValue ());
}
+
+
+void
+VideoPanel::scale_fit_clicked ()
+{
+ BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_video()) {
+ i->video->set_custom_ratio (optional<float>());
+ }
+}
+
+
+void
+VideoPanel::scale_custom_clicked ()
+{
+ if (!scale_custom_edit_clicked()) {
+ _scale_fit->SetValue (true);
+ }
+}
+
+
+bool
+VideoPanel::scale_custom_edit_clicked ()
+{
+ shared_ptr<const VideoContent> vc = _parent->selected_video().front()->video;
+ CustomScaleDialog* d = new CustomScaleDialog (this, vc->size(), _parent->film()->frame_size(), vc->custom_ratio(), vc->custom_size());
+ int const r = d->ShowModal ();
+ if (r == wxID_OK) {
+ BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_video()) {
+ i->video->set_custom_ratio (d->custom_ratio());
+ i->video->set_custom_size (d->custom_size());
+ }
+ }
+ d->Destroy ();
+ return r == wxID_OK;
+}
+
+
+void
+VideoPanel::left_right_link_clicked ()
+{
+ right_crop_changed ();
+}
+
+
+void
+VideoPanel::top_bottom_link_clicked ()
+{
+ bottom_crop_changed ();
+}
+
+
+void
+VideoPanel::left_crop_changed ()
+{
+ if (_left_right_link->GetValue()) {
+ BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_video()) {
+ i->video->set_right_crop (i->video->left_crop());
+ }
+ }
+}
+
+
+void
+VideoPanel::right_crop_changed ()
+{
+ if (_left_right_link->GetValue()) {
+ BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_video()) {
+ i->video->set_left_crop (i->video->right_crop());
+ }
+ }
+}
+
+
+void
+VideoPanel::top_crop_changed ()
+{
+ if (_top_bottom_link->GetValue()) {
+ BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_video()) {
+ i->video->set_bottom_crop (i->video->top_crop());
+ }
+ }
+}
+
+
+void
+VideoPanel::bottom_crop_changed ()
+{
+ if (_top_bottom_link->GetValue()) {
+ BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_video()) {
+ i->video->set_top_crop (i->video->bottom_crop());
+ }
+ }
+}
+
+
+
#include "content_sub_panel.h"
#include "content_widget.h"
#include "timecode.h"
-#include "lib/video_content_scale.h"
#include "lib/film.h"
class wxChoice;
class wxStaticText;
class wxSpinCtrl;
class wxButton;
+class wxToggleButton;
/** @class VideoPanel
* @brief The video tab of the film editor.
void fade_in_changed ();
void fade_out_changed ();
void add_to_grid ();
+ void scale_fit_clicked ();
+ void scale_custom_clicked ();
+ bool scale_custom_edit_clicked ();
+ void left_right_link_clicked ();
+ void top_bottom_link_clicked ();
+ void left_crop_changed ();
+ void right_crop_changed ();
+ void top_crop_changed ();
+ void bottom_crop_changed ();
void setup_description ();
void setup_sensitivity ();
wxCheckBox* _use;
wxStaticText* _type_label;
ContentChoice<VideoContent, VideoFrameType>* _frame_type;
+ wxStaticText* _crop_label;
wxStaticText* _left_crop_label;
ContentSpinCtrl<VideoContent>* _left_crop;
+ wxToggleButton* _left_right_link;
wxStaticText* _right_crop_label;
ContentSpinCtrl<VideoContent>* _right_crop;
wxStaticText* _top_crop_label;
ContentSpinCtrl<VideoContent>* _top_crop;
+ wxToggleButton* _top_bottom_link;
wxStaticText* _bottom_crop_label;
ContentSpinCtrl<VideoContent>* _bottom_crop;
wxStaticText* _fade_in_label;
Timecode<dcpomatic::ContentTime>* _fade_in;
wxStaticText* _fade_out_label;
Timecode<dcpomatic::ContentTime>* _fade_out;
- wxStaticText* _scale_to_label;
- ContentChoice<VideoContent, VideoContentScale>* _scale;
+ wxStaticText* _scale_label;
+ wxRadioButton* _scale_fit;
+ wxRadioButton* _scale_custom;
+ wxButton* _scale_custom_edit;
wxStaticText* _description;
wxStaticText* _filters_label;
wxStaticText* _filters;
controls.cc
closed_captions_dialog.cc
credentials_download_certificate_panel.cc
+ custom_scale_dialog.cc
dcp_panel.cc
dcpomatic_button.cc
disk_warning_dialog.cc
def configure(conf):
- wx_libs = 'core,richtext,adv,html,xml'
+ wx_libs = 'core,richtext,adv,html,xml,propgrid'
try:
wx_config = '/usr/lib64/wx/config/gtk2-unicode-3.0'
return utc;
}
+
+
+wxString
+bitmap_path (string name)
+{
+ boost::filesystem::path base;
+
+#ifdef DCPOMATIC_DEBUG
+ /* Hack to allow OS X to find icons when running from the source tree */
+ char* path = getenv ("DCPOMATIC_GRAPHICS");
+ if (path) {
+ base = path;
+ } else {
+ base = shared_path();
+ }
+#else
+ base = shared_path();
+#endif
+
+ boost::filesystem::path p = base / String::compose("%1.png", name);
+ return std_to_wx (p.string());
+}
+
extern double calculate_mark_interval (double start);
extern bool display_progress (wxString title, wxString task);
extern bool report_errors_from_last_job (wxWindow* parent);
-
+extern wxString bitmap_path (std::string name);
struct Offset
{
film->examine_and_add_content (c);
BOOST_REQUIRE (!wait_for_jobs());
- c->video->set_scale (VideoContentScale (Ratio::from_id ("185")));
-
film->make_dcp ();
BOOST_REQUIRE (!wait_for_jobs());
cc = run ("dcpomatic2_create -h");
BOOST_REQUIRE (cc.error);
- cc = run ("dcpomatic2_create x --content-ratio 185 --name frobozz --template bar");
+ cc = run ("dcpomatic2_create x --name frobozz --template bar");
BOOST_CHECK (!cc.error);
BOOST_CHECK_EQUAL (cc.name, "frobozz");
BOOST_REQUIRE (cc.template_name);
BOOST_CHECK_EQUAL (*cc.template_name, "bar");
- cc = run ("dcpomatic2_create x --content-ratio 185 --dcp-content-type FTR");
+ cc = run ("dcpomatic2_create x --dcp-content-type FTR");
BOOST_CHECK (!cc.error);
BOOST_CHECK_EQUAL (cc.dcp_content_type, DCPContentType::from_isdcf_name("FTR"));
- cc = run ("dcpomatic2_create x --content-ratio 185 --dcp-frame-rate 30");
+ cc = run ("dcpomatic2_create x --dcp-frame-rate 30");
BOOST_CHECK (!cc.error);
BOOST_REQUIRE (cc.dcp_frame_rate);
BOOST_CHECK_EQUAL (*cc.dcp_frame_rate, 30);
- cc = run ("dcpomatic2_create x --content-ratio 185 --container-ratio 185");
+ cc = run ("dcpomatic2_create x --container-ratio 185");
BOOST_CHECK (!cc.error);
BOOST_CHECK_EQUAL (cc.container_ratio, Ratio::from_id("185"));
- cc = run ("dcpomatic2_create x --content-ratio 185 --container-ratio XXX");
+ cc = run ("dcpomatic2_create x --container-ratio XXX");
BOOST_CHECK (cc.error);
- cc = run ("dcpomatic2_create x --content-ratio 185 --content-ratio 239");
- BOOST_CHECK (!cc.error);
- BOOST_CHECK_EQUAL (cc.content_ratio, Ratio::from_id("239"));
-
- cc = run ("dcpomatic2_create x --content-ratio 240");
- BOOST_CHECK (cc.error);
-
- cc = run ("dcpomatic2_create x --content-ratio 185 --still-length 42");
+ cc = run ("dcpomatic2_create x --still-length 42");
BOOST_CHECK (!cc.error);
BOOST_CHECK_EQUAL (cc.still_length, 42);
- cc = run ("dcpomatic2_create x --content-ratio 185 --standard SMPTE");
+ cc = run ("dcpomatic2_create x --standard SMPTE");
BOOST_CHECK (!cc.error);
BOOST_CHECK_EQUAL (cc.standard, dcp::SMPTE);
- cc = run ("dcpomatic2_create x --content-ratio 185 --standard SMPTEX");
+ cc = run ("dcpomatic2_create x --standard SMPTEX");
BOOST_CHECK (cc.error);
- cc = run ("dcpomatic2_create x --content-ratio 185 --config foo/bar");
+ cc = run ("dcpomatic2_create x --config foo/bar");
BOOST_CHECK (!cc.error);
BOOST_REQUIRE (cc.config_dir);
BOOST_CHECK_EQUAL (*cc.config_dir, "foo/bar");
- cc = run ("dcpomatic2_create x --content-ratio 185 --output fred/jim");
+ cc = run ("dcpomatic2_create x --output fred/jim");
BOOST_CHECK (!cc.error);
BOOST_REQUIRE (cc.output_dir);
BOOST_CHECK_EQUAL (*cc.output_dir, "fred/jim");
- cc = run ("dcpomatic2_create x --content-ratio 185 --outputX fred/jim");
+ cc = run ("dcpomatic2_create x --outputX fred/jim");
BOOST_CHECK (cc.error);
- cc = run ("dcpomatic2_create --content-ratio 185 --config foo/bar --still-length 42 --output flaps fred jim sheila");
+ cc = run ("dcpomatic2_create --config foo/bar --still-length 42 --output flaps fred jim sheila");
BOOST_CHECK (!cc.error);
BOOST_REQUIRE (cc.config_dir);
BOOST_CHECK_EQUAL (*cc.config_dir, "foo/bar");
BOOST_CHECK_EQUAL (cc.content[2].path, "sheila");
BOOST_CHECK_EQUAL (cc.content[2].frame_type, VIDEO_FRAME_TYPE_2D);
- cc = run ("dcpomatic2_create --content-ratio 185 --left-eye left.mp4 --right-eye right.mp4");
+ cc = run ("dcpomatic2_create --left-eye left.mp4 --right-eye right.mp4");
BOOST_REQUIRE_EQUAL (cc.content.size(), 2);
BOOST_CHECK_EQUAL (cc.content[0].path, "left.mp4");
BOOST_CHECK_EQUAL (cc.content[0].frame_type, VIDEO_FRAME_TYPE_3D_LEFT);
BOOST_CHECK_EQUAL (cc.content[1].frame_type, VIDEO_FRAME_TYPE_3D_RIGHT);
BOOST_CHECK_EQUAL (cc.fourk, false);
- cc = run ("dcpomatic2_create --fourk --content-ratio 185 foo.mp4");
+ cc = run ("dcpomatic2_create --fourk foo.mp4");
BOOST_REQUIRE_EQUAL (cc.content.size(), 1);
BOOST_CHECK_EQUAL (cc.content[0].path, "foo.mp4");
BOOST_CHECK_EQUAL (cc.fourk, true);
BOOST_CHECK (!cc.error);
- cc = run ("dcpomatic2_create --j2k-bandwidth 120 --content-ratio 185 foo.mp4");
+ cc = run ("dcpomatic2_create --j2k-bandwidth 120 foo.mp4");
BOOST_REQUIRE_EQUAL (cc.content.size(), 1);
BOOST_CHECK_EQUAL (cc.content[0].path, "foo.mp4");
BOOST_REQUIRE (cc.j2k_bandwidth);
-Subproject commit 6b694889479064979b52c1839a1919dc5fde6731
+Subproject commit 3b21196b894bfbc096a5e90ee11dcf5f50bd4bf9
/* 0 1 2 3 4 5 6 7
* A A A B
*/
- contentA->video->set_scale (VideoContentScale (Ratio::from_id ("185")));
contentA->video->set_length (3);
contentA->set_position (film, DCPTime::from_frames (2, vfr));
- contentB->video->set_scale (VideoContentScale (Ratio::from_id ("185")));
contentB->video->set_length (1);
contentB->set_position (film, DCPTime::from_frames (7, vfr));
/* 0 1 2 3 4 5 6 7
* A A A B
*/
- contentA->video->set_scale (VideoContentScale (Ratio::from_id ("185")));
contentA->video->set_length (3);
contentA->set_position (film, DCPTime(0));
- contentB->video->set_scale (VideoContentScale (Ratio::from_id ("185")));
contentB->video->set_length (1);
contentB->set_position (film, DCPTime::from_frames(7, vfr));
/* 0 1 2 3 4 5 6 7
* A A A B
*/
- contentA->video->set_scale (VideoContentScale (Ratio::from_id ("185")));
contentA->video->set_length (3);
contentA->set_position (film, DCPTime(0));
- contentB->video->set_scale (VideoContentScale (Ratio::from_id ("185")));
contentB->video->set_length (1);
contentB->set_position (film, DCPTime::from_frames(7, vfr));
BOOST_REQUIRE (!wait_for_jobs());
- c->video->set_scale (VideoContentScale (Ratio::from_id ("185")));
-
film->set_container (Ratio::from_id ("185"));
film->set_audio_channels (6);
film->set_dcp_content_type (DCPContentType::from_isdcf_name ("TST"));
BOOST_REQUIRE (!wait_for_jobs());
- c->video->set_scale (VideoContentScale (Ratio::from_id ("185")));
-
film->set_container (Ratio::from_id ("185"));
film->set_dcp_content_type (DCPContentType::from_isdcf_name ("TST"));
film->make_dcp ();
shared_ptr<ImageContent> content (new ImageContent ("test/data/simple_testcard_640x480.png"));
film->examine_and_add_content (content);
BOOST_REQUIRE (!wait_for_jobs());
- content->video->set_scale (VideoContentScale (Ratio::from_id ("133")));
+ content->video->set_custom_ratio (1.33);
film->set_container (Ratio::from_id ("185"));
BOOST_CHECK_EQUAL (film->isdcf_name(false), "MyNiceFilmWith_TLR-2_F_DE-fr_US-R_MOS_4K_DI_20140704_PP_SMPTE_OV");
/* And it should always be numeric */
- content->video->set_scale (VideoContentScale (Ratio::from_id ("239")));
+ content->video->set_custom_ratio (2.39);
BOOST_CHECK_EQUAL (film->isdcf_name(false), "MyNiceFilmWith_XSN-2_F-239_DE-fr_US-R_MOS_4K_DI_20140704_PP_SMPTE_OV");
- content->video->set_scale (VideoContentScale (Ratio::from_id ("190")));
+ content->video->set_custom_ratio (1.9);
BOOST_CHECK_EQUAL (film->isdcf_name(false), "MyNiceFilmWith_XSN-2_F-190_DE-fr_US-R_MOS_4K_DI_20140704_PP_SMPTE_OV");
- content->video->set_scale (VideoContentScale (Ratio::from_id ("133")));
+ content->video->set_custom_ratio (1.33);
/* Test 3D */
film->examine_and_add_content (contentB);
BOOST_REQUIRE (!wait_for_jobs());
- contentA->video->set_scale (VideoContentScale (Ratio::from_id ("185")));
contentA->video->set_length (3);
contentA->set_position (film, DCPTime::from_frames(2, film->video_frame_rate()));
- contentB->video->set_scale (VideoContentScale (Ratio::from_id ("185")));
+ contentA->video->set_custom_ratio (1.85);
contentB->video->set_length (1);
contentB->set_position (film, DCPTime::from_frames(7, film->video_frame_rate()));
+ contentB->video->set_custom_ratio (1.85);
film->make_dcp ();
film->make_dcp ();
BOOST_REQUIRE (!wait_for_jobs());
- boost::filesystem::path const video = "build/test/recover_test_2d/video/185_2K_d4343facdd66ca71f62a964fbade89f3_24_100000000_P_S_0_1200000.mxf";
+ boost::filesystem::path const video = "build/test/recover_test_2d/video/185_2K_02543352c540f4b083bff3f1e309d4a9_24_100000000_P_S_0_1200000.mxf";
boost::filesystem::copy_file (
video,
"build/test/recover_test_2d/original.mxf"
film->make_dcp ();
BOOST_REQUIRE (!wait_for_jobs());
- boost::filesystem::path const video = "build/test/recover_test_3d/video/185_2K_342fe9115d2b446914b31f7602e48cc6_24_100000000_P_S_3D_0_96000.mxf";
+ boost::filesystem::path const video = "build/test/recover_test_3d/video/185_2K_70e6661af92ae94458784c16a21a9748_24_100000000_P_S_3D_0_96000.mxf";
boost::filesystem::copy_file (
video,
BOOST_REQUIRE (!wait_for_jobs());
boost::filesystem::path const video =
- "build/test/recover_test_2d_encrypted/video/185_2K_d4343facdd66ca71f62a964fbade89f3_24_100000000_Eeafcb91c9f5472edf01f3a2404c57258_S_0_1200000.mxf";
+ "build/test/recover_test_2d_encrypted/video/185_2K_02543352c540f4b083bff3f1e309d4a9_24_100000000_Eeafcb91c9f5472edf01f3a2404c57258_S_0_1200000.mxf";
boost::filesystem::copy_file (
video,
film->set_interop (false);
shared_ptr<FFmpegContent> c (new FFmpegContent("test/data/red_24.mp4"));
film->examine_and_add_content (c);
-
BOOST_REQUIRE (!wait_for_jobs());
-
- c->video->set_scale (VideoContentScale (Ratio::from_id ("185")));
+ c->video->set_custom_ratio (1.85);
film->set_video_frame_rate (48);
film->make_dcp ();
using std::string;
using boost::shared_ptr;
-static void scaling_test_for (shared_ptr<Film> film, shared_ptr<Content> content, string image, string container)
+static void scaling_test_for (shared_ptr<Film> film, shared_ptr<Content> content, float ratio, std::string image, string container)
{
- content->video->set_scale (VideoContentScale (Ratio::from_id (image)));
+ content->video->set_custom_ratio (ratio);
film->set_container (Ratio::from_id (container));
film->set_interop (false);
film->make_dcp ();
imc->video->set_length (1);
/* F-133: 133 image in a flat container */
- scaling_test_for (film, imc, "133", "185");
+ scaling_test_for (film, imc, 4.0 / 3, "133", "185");
/* F: flat image in a flat container */
- scaling_test_for (film, imc, "185", "185");
+ scaling_test_for (film, imc, 1.85, "185", "185");
/* F-S: scope image in a flat container */
- scaling_test_for (film, imc, "239", "185");
+ scaling_test_for (film, imc, 2.38695, "239", "185");
/* S-133: 133 image in a scope container */
- scaling_test_for (film, imc, "133", "239");
+ scaling_test_for (film, imc, 4.0 / 3, "133", "239");
/* S-F: flat image in a scope container */
- scaling_test_for (film, imc, "185", "239");
+ scaling_test_for (film, imc, 1.85, "185", "239");
/* S: scope image in a scope container */
- scaling_test_for (film, imc, "239", "239");
+ scaling_test_for (film, imc, 2.38695, "239", "239");
}
BOOST_REQUIRE (!wait_for_jobs());
- c->video->set_scale (VideoContentScale (Ratio::from_id ("185")));
film->write_metadata ();
film->set_video_frame_rate (24);
BOOST_REQUIRE (!wait_for_jobs());
c->video->set_frame_type (VIDEO_FRAME_TYPE_3D_LEFT_RIGHT);
- c->video->set_scale (VideoContentScale (Ratio::from_id ("185")));
film->set_container (Ratio::from_id ("185"));
film->set_dcp_content_type (DCPContentType::from_isdcf_name ("TST"));
BOOST_REQUIRE (!wait_for_jobs());
c->video->set_frame_type (VIDEO_FRAME_TYPE_3D_ALTERNATE);
- c->video->set_scale (VideoContentScale (Ratio::from_id ("185")));
film->set_container (Ratio::from_id ("185"));
film->set_dcp_content_type (DCPContentType::from_isdcf_name ("TST"));
/*
- Copyright (C) 2015 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
-/** @file test/video_content_scale_test.cc
- * @brief Test VideoContentScale
- * @ingroup selfcontained
- */
-#include "lib/ffmpeg_content.h"
#include "lib/ratio.h"
#include "lib/video_content.h"
-#include <dcp/raw_convert.h>
#include <boost/test/unit_test.hpp>
-using std::list;
-using std::string;
-using std::cerr;
-using boost::shared_ptr;
-using boost::optional;
-using dcp::raw_convert;
-static
-void
-test (dcp::Size content_size, dcp::Size display_size, dcp::Size film_size, Crop crop, Ratio const * ratio, bool scale, dcp::Size correct)
-{
- shared_ptr<Film> film;
- string s = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
- "<Content>"
- "<Type>FFmpeg</Type>"
- "<Path>/home/c.hetherington/DCP/prophet_long_clip.mkv</Path>"
- "<Digest>f3f23663da5bef6d2cbaa0db066f3351314142710</Digest>"
- "<Position>0</Position>"
- "<TrimStart>0</TrimStart>"
- "<TrimEnd>0</TrimEnd>"
- "<VideoLength>2879</VideoLength>"
- "<VideoWidth>" + raw_convert<string>(content_size.width) + "</VideoWidth>"
- "<VideoHeight>" + raw_convert<string>(content_size.height) + "</VideoHeight>"
- "<VideoFrameRate>23.97602462768555</VideoFrameRate>"
- "<OriginalVideoFrameRate>23.97602462768555</OriginalVideoFrameRate>"
- "<VideoFrameType>0</VideoFrameType>"
- "<SampleAspectRatio>1</SampleAspectRatio>"
- "<BitsPerPixel>12</BitsPerPixel>"
- "<LeftCrop>" + raw_convert<string>(crop.left) + "</LeftCrop>"
- "<RightCrop>" + raw_convert<string>(crop.right) + "</RightCrop>"
- "<TopCrop>" + raw_convert<string>(crop.top) + "</TopCrop>"
- "<BottomCrop>" + raw_convert<string>(crop.bottom) + "</BottomCrop>"
- "<Scale>";
-
- if (ratio) {
- s += "<Ratio>" + ratio->id() + "</Ratio>";
- } else {
- s += "<Scale>" + string(scale ? "1" : "0") + "</Scale>";
- }
+static dcp::Size const FOUR_TO_THREE(1436, 1080);
+static dcp::Size const FLAT(1998, 1080);
+static dcp::Size const SCOPE(2048, 858);
- s += "</Scale>"
- "<ColourConversion>"
- "<InputGamma>2.4</InputGamma>"
- "<InputGammaLinearised>1</InputGammaLinearised>"
- "<Matrix i=\"0\" j=\"0\">0.4124564</Matrix>"
- "<Matrix i=\"0\" j=\"1\">0.3575761</Matrix>"
- "<Matrix i=\"0\" j=\"2\">0.1804375</Matrix>"
- "<Matrix i=\"1\" j=\"0\">0.2126729</Matrix>"
- "<Matrix i=\"1\" j=\"1\">0.7151522</Matrix>"
- "<Matrix i=\"1\" j=\"2\">0.072175</Matrix>"
- "<Matrix i=\"2\" j=\"0\">0.0193339</Matrix>"
- "<Matrix i=\"2\" j=\"1\">0.119192</Matrix>"
- "<Matrix i=\"2\" j=\"2\">0.9503041</Matrix>"
- "<OutputGamma>2.6</OutputGamma>"
- "</ColourConversion>"
- "<AudioGain>0</AudioGain>"
- "<AudioDelay>0</AudioDelay>"
- "<SubtitleXOffset>0</SubtitleXOffset>"
- "<SubtitleYOffset>0</SubtitleYOffset>"
- "<SubtitleXScale>0</SubtitleXScale>"
- "<SubtitleYScale>0</SubtitleYScale>"
- "</Content>";
-
- shared_ptr<cxml::Document> doc (new cxml::Document ());
- doc->read_string (s);
-
- list<string> notes;
- shared_ptr<FFmpegContent> vc (new FFmpegContent (doc, 10, notes));
-
- optional<VideoContentScale> sc;
- if (ratio) {
- sc = VideoContentScale (ratio);
- } else {
- sc = VideoContentScale (scale);
- }
- dcp::Size answer = sc.get().size (vc->video, display_size, film_size);
- if (answer != correct) {
- cerr << "Testing " << vc->video->size().width << "x" << vc->video->size().height << "\n";
- cerr << "Testing " << display_size.width << "x" << display_size.height << "\n";
- cerr << answer.width << "x" << answer.height << " instead of " << correct.width << "x" << correct.height << "\n";
- }
- BOOST_CHECK (answer == correct);
+/* Test VideoContent::scaled_size() without any legacy stuff */
+BOOST_AUTO_TEST_CASE (scaled_size_test1)
+{
+ VideoContent vc (0);
+
+ /* Images at full size and in DCP-approved sizes that will not be scaled */
+ // Flat/scope content into flat/scope container
+ vc._size = FLAT;
+ BOOST_CHECK_EQUAL (vc.scaled_size(FLAT), FLAT);
+ vc._size = SCOPE;
+ BOOST_CHECK_EQUAL (vc.scaled_size(SCOPE), SCOPE);
+ // 1.33:1 into flat container
+ vc._size = FOUR_TO_THREE;
+ BOOST_CHECK_EQUAL (vc.scaled_size(FLAT), dcp::Size(FOUR_TO_THREE));
+ // Scope into flat container
+ vc._size = SCOPE;
+ BOOST_CHECK_EQUAL (vc.scaled_size(FLAT), dcp::Size(1998, 837));
+
+ /* Smaller images but in the same ratios */
+ vc._size = dcp::Size(185, 100);
+ BOOST_CHECK_EQUAL (vc.scaled_size(FLAT), FLAT);
+ vc._size = dcp::Size(955, 400);
+ BOOST_CHECK_EQUAL (vc.scaled_size(SCOPE), SCOPE);
+ // 1.33:1 into flat container
+ vc._size = dcp::Size(133, 100);
+ BOOST_CHECK_EQUAL (vc.scaled_size(FLAT), dcp::Size(FOUR_TO_THREE));
+ // Scope into flat container
+ vc._size = dcp::Size(239, 100);
+ BOOST_CHECK_EQUAL (vc.scaled_size(FLAT), dcp::Size(1998, 836));
+
+ /* Images at full size that are not DCP-approved but will still remain unscaled */
+ vc._size = dcp::Size(600, 1080);
+ BOOST_CHECK_EQUAL (vc.scaled_size(FLAT), dcp::Size(600, 1080));
+ vc._size = dcp::Size(1700, 1080);
+ BOOST_CHECK_EQUAL (vc.scaled_size(FLAT), dcp::Size(1700, 1080));
+
+ /* Image at full size that is too big for the container and will be shrunk */
+ vc._size = dcp::Size(3000, 1080);
+ BOOST_CHECK_EQUAL (vc.scaled_size(FLAT), dcp::Size(1998, 719));
}
-/* Test scale and stretch to specified ratio */
-BOOST_AUTO_TEST_CASE (video_content_scale_test_to_ratio)
+
+/* Same as scaled_size_test1 but with a non-unity sample aspect ratio */
+BOOST_AUTO_TEST_CASE (scaled_size_test2)
{
- /* To DCP */
-
- // Flat in flat container
- test (
- dcp::Size (400, 200),
- dcp::Size (1998, 1080),
- dcp::Size (1998, 1080),
- Crop (0, 0, 0, 0),
- Ratio::from_id ("185"),
- true,
- dcp::Size (1998, 1080)
- );
-
- // Scope in flat container
- test (
- dcp::Size (400, 200),
- dcp::Size (1998, 1080),
- dcp::Size (1998, 1080),
- Crop (0, 0, 0, 0),
- Ratio::from_id ("239"),
- true,
- dcp::Size (1998, 837)
- );
-
- // Flat in scope container
- test (
- dcp::Size (400, 200),
- dcp::Size (2048, 858),
- dcp::Size (2048, 858),
- Crop (0, 0, 0, 0),
- Ratio::from_id ("185"),
- true,
- dcp::Size (1587, 858)
- );
-
-
- /* To player */
-
- // Flat in flat container
- test (
- dcp::Size (400, 200),
- dcp::Size (185, 100),
- dcp::Size (1998, 1080),
- Crop (0, 0, 0, 0),
- Ratio::from_id ("185"),
- true,
- dcp::Size (185, 100)
- );
-
- // Scope in flat container
- test (
- dcp::Size (400, 200),
- dcp::Size (185, 100),
- dcp::Size (1998, 1080),
- Crop (0, 0, 0, 0),
- Ratio::from_id ("239"),
- true,
- dcp::Size (185, 78)
- );
-
- // Flat in scope container
- test (
- dcp::Size (400, 200),
- dcp::Size (239, 100),
- dcp::Size (2048, 858),
- Crop (0, 0, 0, 0),
- Ratio::from_id ("185"),
- true,
- dcp::Size (185, 100)
- );
+ VideoContent vc (0);
+
+ vc._sample_aspect_ratio = 2;
+
+ /* Images at full size and in DCP-approved sizes that will not be scaled */
+ // Flat/scope content into flat/scope container
+ vc._size = dcp::Size (1998 / 2, 1080);
+ BOOST_CHECK_EQUAL (vc.scaled_size(FLAT), FLAT);
+ vc._size = dcp::Size (2048 / 2, 858);
+ BOOST_CHECK_EQUAL (vc.scaled_size(SCOPE), SCOPE);
+ // 1.33:1 into flat container
+ vc._size = dcp::Size (1436 / 2, 1080);
+ BOOST_CHECK_EQUAL (vc.scaled_size(FLAT), dcp::Size(FOUR_TO_THREE));
+ // Scope into flat container
+ vc._size = dcp::Size (2048 / 2, 858);
+ BOOST_CHECK_EQUAL (vc.scaled_size(FLAT), dcp::Size(1998, 837));
+
+ /* Smaller images but in the same ratios */
+ vc._size = dcp::Size(185, 200);
+ BOOST_CHECK_EQUAL (vc.scaled_size(FLAT), FLAT);
+ vc._size = dcp::Size(955, 800);
+ BOOST_CHECK_EQUAL (vc.scaled_size(SCOPE), SCOPE);
+ // 4:3 into flat container
+ vc._size = dcp::Size(133, 200);
+ BOOST_CHECK_EQUAL (vc.scaled_size(FLAT), dcp::Size(FOUR_TO_THREE));
+ // Scope into flat container
+ vc._size = dcp::Size(239, 200);
+ BOOST_CHECK_EQUAL (vc.scaled_size(FLAT), dcp::Size(1998, 836));
+
+ /* Images at full size that are not DCP-approved but will still remain unscaled */
+ vc._size = dcp::Size(600 / 2, 1080);
+ BOOST_CHECK_EQUAL (vc.scaled_size(FLAT), dcp::Size(600, 1080));
+ vc._size = dcp::Size(1700 / 2, 1080);
+ BOOST_CHECK_EQUAL (vc.scaled_size(FLAT), dcp::Size(1700, 1080));
+
+ /* Image at full size that is too big for the container and will be shrunk */
+ vc._size = dcp::Size(3000 / 2, 1080);
+ BOOST_CHECK_EQUAL (vc.scaled_size(FLAT), dcp::Size(1998, 719));
}
-/* Test no scale */
-BOOST_AUTO_TEST_CASE (video_content_scale_no_scale)
+
+/* Test VideoContent::scaled_size() with some legacy stuff */
+BOOST_AUTO_TEST_CASE (scaled_size_legacy_test)
{
- /* No scale where the content is bigger than even the film container */
- test (
- dcp::Size (1920, 1080),
- dcp::Size (887, 371),
- dcp::Size (2048, 858),
- Crop (),
- 0,
- false,
- dcp::Size (659, 371)
- );
+ {
+ /* 640x480 content that the user had asked to be stretched to 1.85:1 */
+ VideoContent vc (0);
+ vc._size = dcp::Size(640, 480);
+ vc._legacy_ratio = Ratio::from_id("185")->ratio();
+ BOOST_CHECK_EQUAL (vc.scaled_size(FLAT), FLAT);
+ }
+
+ {
+ /* 640x480 content that the user had asked to be scaled to fit the container, without stretch */
+ VideoContent vc (0);
+ vc._size = dcp::Size(640, 480);
+ vc._legacy_ratio = 1.33;
+ BOOST_CHECK_EQUAL (vc.scaled_size(FLAT), FOUR_TO_THREE);
+ }
+
+ {
+ /* 640x480 content that the user had asked to be kept the same size */
+ VideoContent vc (0);
+ vc._size = dcp::Size(640, 480);
+ vc._custom_size = dcp::Size(640, 480);
+ BOOST_CHECK_EQUAL (vc.scaled_size(FLAT), dcp::Size(640, 480));
+ }
}
+