summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2013-12-04 20:52:18 +0000
committerCarl Hetherington <cth@carlh.net>2013-12-04 20:52:18 +0000
commit98060a4e6f02b418f30b4b736e5880a357454c40 (patch)
tree612a017ac6ab695a7dc5dffe49779a5a74fd1906 /src/lib
parent70ee6cc5cef66a4aed252dbfa2390cc9f0c8c286 (diff)
Do lots of the player processing with less copying.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/image.cc51
-rw-r--r--src/lib/image.h6
-rw-r--r--src/lib/image_decoder.cc2
-rw-r--r--src/lib/player.cc31
-rw-r--r--src/lib/position.h7
5 files changed, 70 insertions, 27 deletions
diff --git a/src/lib/image.cc b/src/lib/image.cc
index 048cc4ab6..9d3f675f0 100644
--- a/src/lib/image.cc
+++ b/src/lib/image.cc
@@ -78,8 +78,9 @@ Image::components () const
return d->nb_components;
}
+/** Crop this image, scale it to `inter_size' and then place it in a black frame of `out_size' */
shared_ptr<Image>
-Image::scale (libdcp::Size out_size, Scaler const * scaler, AVPixelFormat result_format, bool result_aligned) const
+Image::crop_scale_window (Crop crop, libdcp::Size inter_size, libdcp::Size out_size, Scaler const * scaler, AVPixelFormat out_format, bool out_aligned) const
{
assert (scaler);
/* Empirical testing suggests that sws_scale() will crash if
@@ -87,11 +88,55 @@ Image::scale (libdcp::Size out_size, Scaler const * scaler, AVPixelFormat result
*/
assert (aligned ());
- shared_ptr<Image> scaled (new Image (result_format, out_size, result_aligned));
+ shared_ptr<Image> out (new Image (out_format, out_size, out_aligned));
+ out->make_black ();
+
+ libdcp::Size cropped_size = crop.apply (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
+ );
+
+ 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));
+ }
+
+ 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) {
+ scale_out_data[c] = out->data()[c] + int (rint (out->bytes_per_pixel(c) * corner.x)) + out->stride()[c] * corner.y;
+ }
+
+ sws_scale (
+ scale_context,
+ scale_in_data, stride(),
+ 0, cropped_size.height,
+ scale_out_data, out->stride()
+ );
+
+ sws_freeContext (scale_context);
+
+ return out;
+}
+
+shared_ptr<Image>
+Image::scale (libdcp::Size out_size, Scaler const * scaler, AVPixelFormat out_format, bool out_aligned) const
+{
+ assert (scaler);
+ /* Empirical testing suggests that sws_scale() will crash if
+ the input image is not aligned.
+ */
+ assert (aligned ());
+
+ shared_ptr<Image> scaled (new Image (out_format, out_size, out_aligned));
struct SwsContext* scale_context = sws_getContext (
size().width, size().height, pixel_format(),
- out_size.width, out_size.height, result_format,
+ out_size.width, out_size.height, out_format,
scaler->ffmpeg_id (), 0, 0, 0
);
diff --git a/src/lib/image.h b/src/lib/image.h
index e455f22c6..b12db3a14 100644
--- a/src/lib/image.h
+++ b/src/lib/image.h
@@ -59,11 +59,13 @@ public:
boost::shared_ptr<Image> scale (libdcp::Size, Scaler const *, AVPixelFormat, bool aligned) const;
boost::shared_ptr<Image> post_process (std::string, bool aligned) const;
- void alpha_blend (boost::shared_ptr<const Image> image, Position<int> pos);
- void copy (boost::shared_ptr<const Image> image, Position<int> pos);
boost::shared_ptr<Image> crop (Crop c, bool aligned) const;
+
+ boost::shared_ptr<Image> crop_scale_window (Crop c, libdcp::Size, libdcp::Size, Scaler const *, AVPixelFormat, bool aligned) const;
void make_black ();
+ void alpha_blend (boost::shared_ptr<const Image> image, Position<int> pos);
+ void copy (boost::shared_ptr<const Image> image, Position<int> pos);
void read_from_socket (boost::shared_ptr<Socket>);
void write_to_socket (boost::shared_ptr<Socket>) const;
diff --git a/src/lib/image_decoder.cc b/src/lib/image_decoder.cc
index 498ff2e25..fb6053ae5 100644
--- a/src/lib/image_decoder.cc
+++ b/src/lib/image_decoder.cc
@@ -52,7 +52,7 @@ ImageDecoder::pass ()
return;
}
- Magick::Image* magick_image = new Magick::Image (_image_content->path(_video_position).string ());
+ Magick::Image* magick_image = new Magick::Image (_image_content->path (_image_content->still() ? 0 : _video_position).string ());
libdcp::Size size (magick_image->columns(), magick_image->rows());
_image.reset (new Image (PIX_FMT_RGB24, size, true));
diff --git a/src/lib/player.cc b/src/lib/player.cc
index 87b10a398..978db035f 100644
--- a/src/lib/player.cc
+++ b/src/lib/player.cc
@@ -270,29 +270,19 @@ Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image
return;
}
- /* Convert to RGB first, as FFmpeg doesn't seem to like handling YUV images with odd widths */
- shared_ptr<Image> work_image = image->scale (image->size (), _film->scaler(), PIX_FMT_RGB24, true);
-
- work_image = work_image->crop (content->crop(), true);
-
+ 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 image_size = fit_ratio_within (ratio, _video_container_size);
+ libdcp::Size const image_size = fit_ratio_within (ratio, _video_container_size);
- work_image = work_image->scale (image_size, _film->scaler(), PIX_FMT_RGB24, true);
+ shared_ptr<Image> work_image = image->crop_scale_window (content->crop(), image_size, _video_container_size, _film->scaler(), PIX_FMT_RGB24, false);
- Time time = content->position() + relative_time + extra - content->trim_start ();
-
- if (_film->with_subtitles () && _out_subtitle.image && time >= _out_subtitle.from && time <= _out_subtitle.to) {
- work_image->alpha_blend (_out_subtitle.image, _out_subtitle.position);
- }
+ Position<int> const container_offset (
+ (_video_container_size.width - image_size.width) / 2,
+ (_video_container_size.height - image_size.width) / 2
+ );
- if (image_size != _video_container_size) {
- assert (image_size.width <= _video_container_size.width);
- assert (image_size.height <= _video_container_size.height);
- shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
- im->make_black ();
- im->copy (work_image, Position<int> ((_video_container_size.width - image_size.width) / 2, (_video_container_size.height - image_size.height) / 2));
- work_image = im;
+ if (_film->with_subtitles () && _out_subtitle.image && time >= _out_subtitle.from && time <= _out_subtitle.to) {
+ work_image->alpha_blend (_out_subtitle.image, _out_subtitle.position + container_offset);
}
#ifdef DCPOMATIC_DEBUG
@@ -301,9 +291,8 @@ Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image
Video (work_image, eyes, content->colour_conversion(), same, time);
- time += TIME_HZ / _film->video_frame_rate();
_last_emit_was_black = false;
- _video_position = piece->video_position = time;
+ _video_position = piece->video_position = (time + TIME_HZ / _film->video_frame_rate());
if (frc.repeat > 1 && !piece->repeating ()) {
piece->set_repeat (_last_incoming_video, frc.repeat - 1);
diff --git a/src/lib/position.h b/src/lib/position.h
index 8768bf5a8..f9bd0987c 100644
--- a/src/lib/position.h
+++ b/src/lib/position.h
@@ -43,4 +43,11 @@ public:
T y;
};
+template<class T>
+Position<T>
+operator+ (Position<T> const & a, Position<T> const & b)
+{
+ return Position<T> (a.x + b.x, a.y + b.y);
+}
+
#endif