summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2014-03-04 16:44:20 +0000
committerCarl Hetherington <cth@carlh.net>2014-03-04 16:44:20 +0000
commit3753cb8685e1755b067676345a5871db24149d0f (patch)
tree96dbcc8bd10583fcb1ee23823855b0e8ea7aa0fd /src/lib
parentf0738a22fc7555c306d49bcd1c356ce210e2c0e2 (diff)
Add support for no-scale of the input video.
Requested-by: Gérald Maruccia
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/ffmpeg_content.cc4
-rw-r--r--src/lib/film.cc4
-rw-r--r--src/lib/image.cc23
-rw-r--r--src/lib/image_content.cc6
-rw-r--r--src/lib/image_content.h2
-rw-r--r--src/lib/player.cc5
-rw-r--r--src/lib/util.cc2
-rw-r--r--src/lib/video_content.cc162
-rw-r--r--src/lib/video_content.h53
9 files changed, 213 insertions, 48 deletions
diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc
index 5524efc65..4ae5546c2 100644
--- a/src/lib/ffmpeg_content.cc
+++ b/src/lib/ffmpeg_content.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -60,7 +60,7 @@ FFmpegContent::FFmpegContent (shared_ptr<const Film> f, boost::filesystem::path
FFmpegContent::FFmpegContent (shared_ptr<const Film> f, shared_ptr<const cxml::Node> node, int version)
: Content (f, node)
- , VideoContent (f, node)
+ , VideoContent (f, node, version)
, AudioContent (f, node)
, SubtitleContent (f, node, version)
{
diff --git a/src/lib/film.cc b/src/lib/film.cc
index 134810452..00beb870f 100644
--- a/src/lib/film.cc
+++ b/src/lib/film.cc
@@ -85,8 +85,10 @@ using libdcp::Signer;
* AudioMapping XML changed.
* 6 -> 7
* Subtitle offset changed to subtitle y offset, and subtitle x offset added.
+ * 7 -> 8
+ * Use <Scale> tag in <VideoContent> rather than <Ratio>.
*/
-int const Film::current_state_version = 7;
+int const Film::current_state_version = 8;
/** Construct a Film object in a given directory.
*
diff --git a/src/lib/image.cc b/src/lib/image.cc
index 4722563c4..c7dfc91cb 100644
--- a/src/lib/image.cc
+++ b/src/lib/image.cc
@@ -32,9 +32,12 @@ extern "C" {
#include "exceptions.h"
#include "scaler.h"
+#include "i18n.h"
+
using std::string;
using std::min;
using std::cout;
+using std::cerr;
using boost::shared_ptr;
using libdcp::Size;
@@ -88,26 +91,38 @@ Image::crop_scale_window (Crop crop, libdcp::Size inter_size, libdcp::Size out_s
*/
assert (aligned ());
+ assert (out_size.width >= inter_size.width);
+ assert (out_size.height >= inter_size.height);
+
+ /* Here's an image of out_size */
shared_ptr<Image> out (new Image (out_format, out_size, out_aligned));
out->make_black ();
-
- libdcp::Size cropped_size = crop.apply (size ());
+ /* Size of the image after any crop */
+ libdcp::Size const cropped_size = crop.apply (size ());
+
+ /* Scale context for a scale from cropped_size to inter_size */
struct SwsContext* scale_context = sws_getContext (
cropped_size.width, cropped_size.height, pixel_format(),
inter_size.width, inter_size.height, out_format,
scaler->ffmpeg_id (), 0, 0, 0
);
+ if (!scale_context) {
+ throw StringError (N_("Could not allocate SwsContext"));
+ }
+
+ /* Prepare input data pointers with crop */
uint8_t* scale_in_data[components()];
for (int c = 0; c < components(); ++c) {
scale_in_data[c] = data()[c] + int (rint (bytes_per_pixel(c) * crop.left)) + stride()[c] * (crop.top / line_factor(c));
}
+ /* Corner of the image within out_size */
Position<int> const corner ((out_size.width - inter_size.width) / 2, (out_size.height - inter_size.height) / 2);
- uint8_t* scale_out_data[components()];
- for (int c = 0; c < components(); ++c) {
+ uint8_t* scale_out_data[out->components()];
+ for (int c = 0; c < out->components(); ++c) {
scale_out_data[c] = out->data()[c] + int (rint (out->bytes_per_pixel(c) * corner.x)) + out->stride()[c] * corner.y;
}
diff --git a/src/lib/image_content.cc b/src/lib/image_content.cc
index 2d29df0c4..fd0b57894 100644
--- a/src/lib/image_content.cc
+++ b/src/lib/image_content.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -50,9 +50,9 @@ ImageContent::ImageContent (shared_ptr<const Film> f, boost::filesystem::path p)
}
-ImageContent::ImageContent (shared_ptr<const Film> f, shared_ptr<const cxml::Node> node, int)
+ImageContent::ImageContent (shared_ptr<const Film> f, shared_ptr<const cxml::Node> node, int version)
: Content (f, node)
- , VideoContent (f, node)
+ , VideoContent (f, node, version)
{
}
diff --git a/src/lib/image_content.h b/src/lib/image_content.h
index e5a0311d9..e56abce4a 100644
--- a/src/lib/image_content.h
+++ b/src/lib/image_content.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/lib/player.cc b/src/lib/player.cc
index 59db923be..99aece8d6 100644
--- a/src/lib/player.cc
+++ b/src/lib/player.cc
@@ -273,8 +273,7 @@ Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image
}
Time const time = content->position() + relative_time + extra - content->trim_start ();
- float const ratio = content->ratio() ? content->ratio()->ratio() : content->video_size_after_crop().ratio();
- libdcp::Size const image_size = fit_ratio_within (ratio, _video_container_size);
+ libdcp::Size const image_size = content->scale().size (content, _video_container_size);
shared_ptr<PlayerImage> pi (
new PlayerImage (
@@ -537,7 +536,7 @@ Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
Changed (frequent);
} else if (
- property == VideoContentProperty::VIDEO_CROP || property == VideoContentProperty::VIDEO_RATIO ||
+ property == VideoContentProperty::VIDEO_CROP || property == VideoContentProperty::VIDEO_SCALE ||
property == VideoContentProperty::VIDEO_FRAME_RATE
) {
diff --git a/src/lib/util.cc b/src/lib/util.cc
index f604cd10a..48b418d37 100644
--- a/src/lib/util.cc
+++ b/src/lib/util.cc
@@ -70,6 +70,7 @@ extern "C" {
#include "ratio.h"
#include "job.h"
#include "cross.h"
+#include "video_content.h"
#ifdef DCPOMATIC_WINDOWS
#include "stack.hpp"
#endif
@@ -345,6 +346,7 @@ dcpomatic_setup ()
libdcp::init ();
Ratio::setup_ratios ();
+ VideoContentScale::setup_scales ();
DCPContentType::setup_dcp_content_types ();
Scaler::setup_scalers ();
Filter::setup_filters ();
diff --git a/src/lib/video_content.cc b/src/lib/video_content.cc
index cc075a34c..7bf2a6b62 100644
--- a/src/lib/video_content.cc
+++ b/src/lib/video_content.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,8 +22,8 @@
#include <libdcp/colour_matrix.h>
#include "video_content.h"
#include "video_examiner.h"
-#include "ratio.h"
#include "compose.hpp"
+#include "ratio.h"
#include "config.h"
#include "colour_conversion.h"
#include "util.h"
@@ -36,7 +36,7 @@ int const VideoContentProperty::VIDEO_SIZE = 0;
int const VideoContentProperty::VIDEO_FRAME_RATE = 1;
int const VideoContentProperty::VIDEO_FRAME_TYPE = 2;
int const VideoContentProperty::VIDEO_CROP = 3;
-int const VideoContentProperty::VIDEO_RATIO = 4;
+int const VideoContentProperty::VIDEO_SCALE = 4;
int const VideoContentProperty::COLOUR_CONVERSION = 5;
using std::string;
@@ -49,12 +49,14 @@ using boost::lexical_cast;
using boost::optional;
using boost::dynamic_pointer_cast;
+vector<VideoContentScale> VideoContentScale::_scales;
+
VideoContent::VideoContent (shared_ptr<const Film> f)
: Content (f)
, _video_length (0)
, _video_frame_rate (0)
, _video_frame_type (VIDEO_FRAME_TYPE_2D)
- , _ratio (Ratio::from_id ("185"))
+ , _scale (Ratio::from_id ("185"))
{
setup_default_colour_conversion ();
}
@@ -64,7 +66,7 @@ VideoContent::VideoContent (shared_ptr<const Film> f, Time s, VideoContent::Fram
, _video_length (len)
, _video_frame_rate (0)
, _video_frame_type (VIDEO_FRAME_TYPE_2D)
- , _ratio (Ratio::from_id ("185"))
+ , _scale (Ratio::from_id ("185"))
{
setup_default_colour_conversion ();
}
@@ -74,14 +76,13 @@ VideoContent::VideoContent (shared_ptr<const Film> f, boost::filesystem::path p)
, _video_length (0)
, _video_frame_rate (0)
, _video_frame_type (VIDEO_FRAME_TYPE_2D)
- , _ratio (Ratio::from_id ("185"))
+ , _scale (Ratio::from_id ("185"))
{
setup_default_colour_conversion ();
}
-VideoContent::VideoContent (shared_ptr<const Film> f, shared_ptr<const cxml::Node> node)
+VideoContent::VideoContent (shared_ptr<const Film> f, shared_ptr<const cxml::Node> node, int version)
: Content (f, node)
- , _ratio (0)
{
_video_length = node->number_child<VideoContent::Frame> ("VideoLength");
_video_size.width = node->number_child<int> ("VideoWidth");
@@ -92,10 +93,16 @@ VideoContent::VideoContent (shared_ptr<const Film> f, shared_ptr<const cxml::Nod
_crop.right = node->number_child<int> ("RightCrop");
_crop.top = node->number_child<int> ("TopCrop");
_crop.bottom = node->number_child<int> ("BottomCrop");
- optional<string> r = node->optional_string_child ("Ratio");
- if (r) {
- _ratio = Ratio::from_id (r.get ());
+
+ if (version <= 7) {
+ optional<string> r = node->optional_string_child ("Ratio");
+ if (r) {
+ _scale = VideoContentScale (Ratio::from_id (r.get ()));
+ }
+ } else {
+ _scale = VideoContentScale (node->node_child ("Scale"));
}
+
_colour_conversion = ColourConversion (node->node_child ("ColourConversion"));
}
@@ -125,8 +132,8 @@ VideoContent::VideoContent (shared_ptr<const Film> f, vector<shared_ptr<Content>
throw JoinError (_("Content to be joined must have the same crop."));
}
- if (vc->ratio() != ref->ratio()) {
- throw JoinError (_("Content to be joined must have the same ratio."));
+ if (vc->scale() != ref->scale()) {
+ throw JoinError (_("Content to be joined must have the same scale setting."));
}
if (vc->colour_conversion() != ref->colour_conversion()) {
@@ -140,7 +147,7 @@ VideoContent::VideoContent (shared_ptr<const Film> f, vector<shared_ptr<Content>
_video_frame_rate = ref->video_frame_rate ();
_video_frame_type = ref->video_frame_type ();
_crop = ref->crop ();
- _ratio = ref->ratio ();
+ _scale = ref->scale ();
_colour_conversion = ref->colour_conversion ();
}
@@ -157,9 +164,7 @@ VideoContent::as_xml (xmlpp::Node* node) const
node->add_child("RightCrop")->add_child_text (boost::lexical_cast<string> (_crop.right));
node->add_child("TopCrop")->add_child_text (boost::lexical_cast<string> (_crop.top));
node->add_child("BottomCrop")->add_child_text (boost::lexical_cast<string> (_crop.bottom));
- if (_ratio) {
- node->add_child("Ratio")->add_child_text (_ratio->id ());
- }
+ _scale.as_xml (node->add_child("Scale"));
_colour_conversion.as_xml (node->add_child("ColourConversion"));
}
@@ -268,18 +273,18 @@ VideoContent::set_bottom_crop (int c)
}
void
-VideoContent::set_ratio (Ratio const * r)
+VideoContent::set_scale (VideoContentScale s)
{
{
boost::mutex::scoped_lock lm (_mutex);
- if (_ratio == r) {
+ if (_scale == s) {
return;
}
- _ratio = r;
+ _scale = s;
}
- signal_changed (VideoContentProperty::VIDEO_RATIO);
+ signal_changed (VideoContentProperty::VIDEO_SCALE);
}
/** @return string which includes everything about how this content looks */
@@ -292,12 +297,9 @@ VideoContent::identifier () const
<< "_" << crop().right
<< "_" << crop().top
<< "_" << crop().bottom
+ << "_" << scale().id()
<< "_" << colour_conversion().identifier ();
- if (ratio()) {
- s << "_" << ratio()->id ();
- }
-
return s.str ();
}
@@ -369,3 +371,113 @@ VideoContent::time_to_content_video_frames (Time t) const
*/
return t * film->video_frame_rate() / (frc.factor() * TIME_HZ);
}
+
+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
+{
+ stringstream s;
+
+ if (_ratio) {
+ s << _ratio->id () << "_";
+ } else {
+ s << (_scale ? "S1" : "S0");
+ }
+
+ return s.str ();
+}
+
+string
+VideoContentScale::name () const
+{
+ if (_ratio) {
+ return _ratio->nickname ();
+ }
+
+ if (_scale) {
+ return _("No stretch");
+ }
+
+ return _("No scale");
+}
+
+libdcp::Size
+VideoContentScale::size (shared_ptr<const VideoContent> c, libdcp::Size container) const
+{
+ if (_ratio) {
+ return fit_ratio_within (_ratio->ratio (), container);
+ }
+
+ /* Force scale if the container is smaller than the content's image */
+ if (_scale || container.width < c->video_size().width || container.height < c->video_size().height) {
+ return fit_ratio_within (c->video_size().ratio (), container);
+ }
+
+ return c->video_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());
+}
diff --git a/src/lib/video_content.h b/src/lib/video_content.h
index 141525e01..c98a52d3a 100644
--- a/src/lib/video_content.h
+++ b/src/lib/video_content.h
@@ -33,10 +33,46 @@ public:
static int const VIDEO_FRAME_RATE;
static int const VIDEO_FRAME_TYPE;
static int const VIDEO_CROP;
- static int const VIDEO_RATIO;
+ static int const VIDEO_SCALE;
static int const COLOUR_CONVERSION;
};
+class VideoContentScale
+{
+public:
+ VideoContentScale ();
+ VideoContentScale (Ratio const *);
+ VideoContentScale (bool);
+ VideoContentScale (boost::shared_ptr<cxml::Node>);
+
+ libdcp::Size size (boost::shared_ptr<const VideoContent>, libdcp::Size) 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:
+ Ratio const * _ratio;
+ bool _scale;
+
+ static std::vector<VideoContentScale> _scales;
+};
+
+bool operator== (VideoContentScale const & a, VideoContentScale const & b);
+bool operator!= (VideoContentScale const & a, VideoContentScale const & b);
+
class VideoContent : public virtual Content
{
public:
@@ -45,7 +81,7 @@ public:
VideoContent (boost::shared_ptr<const Film>);
VideoContent (boost::shared_ptr<const Film>, Time, VideoContent::Frame);
VideoContent (boost::shared_ptr<const Film>, boost::filesystem::path);
- VideoContent (boost::shared_ptr<const Film>, boost::shared_ptr<const cxml::Node>);
+ VideoContent (boost::shared_ptr<const Film>, boost::shared_ptr<const cxml::Node>, int);
VideoContent (boost::shared_ptr<const Film>, std::vector<boost::shared_ptr<Content> >);
void as_xml (xmlpp::Node *) const;
@@ -75,8 +111,9 @@ public:
void set_top_crop (int);
void set_bottom_crop (int);
+ void set_scale (VideoContentScale);
void set_colour_conversion (ColourConversion);
-
+
VideoFrameType video_frame_type () const {
boost::mutex::scoped_lock lm (_mutex);
return _video_frame_type;
@@ -106,13 +143,11 @@ public:
boost::mutex::scoped_lock lm (_mutex);
return _crop.bottom;
}
-
- void set_ratio (Ratio const *);
- /** @return ratio to scale to, or 0 if the content's own ratio should be preserved. */
- Ratio const * ratio () const {
+ /** @return Description of how to scale this content (if indeed it should be scaled) */
+ VideoContentScale scale () const {
boost::mutex::scoped_lock lm (_mutex);
- return _ratio;
+ return _scale;
}
ColourConversion colour_conversion () const {
@@ -142,7 +177,7 @@ private:
libdcp::Size _video_size;
VideoFrameType _video_frame_type;
Crop _crop;
- Ratio const * _ratio;
+ VideoContentScale _scale;
ColourConversion _colour_conversion;
};