X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fimage.cc;h=c7dfc91cb374eb9c765b0009e22a00a407f1aff2;hb=3753cb8685e1755b067676345a5871db24149d0f;hp=9a3aa8d45b036557fcb6f0297cc92afbf519aeb1;hpb=089b90439e745a218494e76b45e7df6215af01df;p=dcpomatic.git diff --git a/src/lib/image.cc b/src/lib/image.cc index 9a3aa8d45..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; @@ -78,8 +81,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 +91,67 @@ Image::scale (libdcp::Size out_size, Scaler const * scaler, AVPixelFormat result */ assert (aligned ()); - shared_ptr scaled (new Image (result_format, out_size, result_aligned)); + assert (out_size.width >= inter_size.width); + assert (out_size.height >= inter_size.height); + + /* Here's an image of out_size */ + shared_ptr out (new Image (out_format, out_size, out_aligned)); + out->make_black (); + + /* 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 const corner ((out_size.width - inter_size.width) / 2, (out_size.height - inter_size.height) / 2); + + 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; + } + + 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 ); @@ -155,10 +215,7 @@ Image::post_process (string pp, bool aligned) const shared_ptr Image::crop (Crop crop, bool aligned) const { - libdcp::Size cropped_size = size (); - cropped_size.width -= crop.left + crop.right; - cropped_size.height -= crop.top + crop.bottom; - + libdcp::Size cropped_size = crop.apply (size ()); shared_ptr out (new Image (pixel_format(), cropped_size, aligned)); for (int c = 0; c < components(); ++c) { @@ -226,6 +283,7 @@ Image::make_black () case PIX_FMT_YUV420P: case PIX_FMT_YUV422P: case PIX_FMT_YUV444P: + case PIX_FMT_YUV411P: memset (data()[0], 0, lines(0) * stride()[0]); memset (data()[1], eight_bit_uv, lines(1) * stride()[1]); memset (data()[2], eight_bit_uv, lines(2) * stride()[2]); @@ -300,7 +358,11 @@ Image::make_black () yuv_16_black (sixteen_bit_uv, true); break; - case PIX_FMT_RGB24: + case PIX_FMT_RGB24: + case PIX_FMT_ARGB: + case PIX_FMT_RGBA: + case PIX_FMT_ABGR: + case PIX_FMT_BGRA: memset (data()[0], 0, lines(0) * stride()[0]); break; @@ -451,13 +513,13 @@ Image::Image (AVPixelFormat p, libdcp::Size s, bool aligned) void Image::allocate () { - _data = (uint8_t **) av_malloc (4 * sizeof (uint8_t *)); + _data = (uint8_t **) wrapped_av_malloc (4 * sizeof (uint8_t *)); _data[0] = _data[1] = _data[2] = _data[3] = 0; - _line_size = (int *) av_malloc (4 * sizeof (int)); + _line_size = (int *) wrapped_av_malloc (4 * sizeof (int)); _line_size[0] = _line_size[1] = _line_size[2] = _line_size[3] = 0; - _stride = (int *) av_malloc (4 * sizeof (int)); + _stride = (int *) wrapped_av_malloc (4 * sizeof (int)); _stride[0] = _stride[1] = _stride[2] = _stride[3] = 0; for (int i = 0; i < components(); ++i) { @@ -473,7 +535,7 @@ Image::allocate () seem to mind. The nasty + 1 in this malloc makes sure there is always a byte for that instruction to read safely. */ - _data[i] = (uint8_t *) av_malloc (_stride[i] * lines (i) + 1); + _data[i] = (uint8_t *) wrapped_av_malloc (_stride[i] * lines (i) + 1); } }