" -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;
* 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.
*
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;
}
}
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
}
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 _scale;
+ return _custom_ratio;
}
+
+ boost::optional<dcp::Size> custom_size () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ 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;
- 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
<< "\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 "
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);
}
}
--- /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;
+};
+
/*
- 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"
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"))
_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));
add_label_to_sizer (crop, _bottom_crop_label, true, wxGBPosition (cr, 2));
_bottom_crop->add (crop, wxGBPosition (cr, 3));
add_label_to_sizer (_grid, _crop_label, true, wxGBPosition(r, 0));
- _grid->Add (crop, wxGBPosition(r, 1), wxGBSpan(2, 3));
- r += 2;
+ _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;
+}
+
#include "content_sub_panel.h"
#include "content_widget.h"
#include "timecode.h"
-#include "lib/video_content_scale.h"
#include "lib/film.h"
class wxChoice;
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 setup_description ();
void setup_sensitivity ();
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'
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 9ec245b7f59b65ad6dd6d0f717686931ff66d748
/* 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));
+ }
}
+