From 98060a4e6f02b418f30b4b736e5880a357454c40 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 4 Dec 2013 20:52:18 +0000 Subject: Do lots of the player processing with less copying. --- src/lib/image.cc | 51 +++++++++++++++++++++++++++++++++++++++++++++--- src/lib/image.h | 6 ++++-- src/lib/image_decoder.cc | 2 +- src/lib/player.cc | 31 ++++++++++------------------- src/lib/position.h | 7 +++++++ 5 files changed, 70 insertions(+), 27 deletions(-) (limited to 'src/lib') 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::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 scaled (new Image (result_format, out_size, result_aligned)); + shared_ptr 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 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::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 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 scale (libdcp::Size, Scaler const *, AVPixelFormat, bool aligned) const; boost::shared_ptr post_process (std::string, bool aligned) const; - void alpha_blend (boost::shared_ptr image, Position pos); - void copy (boost::shared_ptr image, Position pos); boost::shared_ptr crop (Crop c, bool aligned) const; + + boost::shared_ptr crop_scale_window (Crop c, libdcp::Size, libdcp::Size, Scaler const *, AVPixelFormat, bool aligned) const; void make_black (); + void alpha_blend (boost::shared_ptr image, Position pos); + void copy (boost::shared_ptr image, Position pos); void read_from_socket (boost::shared_ptr); void write_to_socket (boost::shared_ptr) 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 weak_piece, shared_ptr image return; } - /* Convert to RGB first, as FFmpeg doesn't seem to like handling YUV images with odd widths */ - shared_ptr 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 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 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 im (new Image (PIX_FMT_RGB24, _video_container_size, true)); - im->make_black (); - im->copy (work_image, Position ((_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 weak_piece, shared_ptr 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 +Position +operator+ (Position const & a, Position const & b) +{ + return Position (a.x + b.x, a.y + b.y); +} + #endif -- cgit v1.2.3