X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Flib%2Fimage.cc;h=95bf2b04d171085615e786418600d23d858f2909;hb=3ace8d6c8400939a6b66743fe395a0c16a90ecf2;hp=dbea62d26b3b7363d7c33ce7df19dff170430a5f;hpb=7b96999f95cd715ad49b1715602287fa4cae0950;p=dcpomatic.git diff --git a/src/lib/image.cc b/src/lib/image.cc index dbea62d26..95bf2b04d 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 ); @@ -155,10 +200,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) { @@ -185,18 +227,23 @@ Image::crop (Crop crop, bool aligned) const /** Blacken a YUV image whose bits per pixel is rounded up to 16 */ void -Image::yuv_16_black (uint16_t v) +Image::yuv_16_black (uint16_t v, bool alpha) { memset (data()[0], 0, lines(0) * stride()[0]); for (int i = 1; i < 3; ++i) { int16_t* p = reinterpret_cast (data()[i]); - for (int y = 0; y < size().height; ++y) { + for (int y = 0; y < lines(i); ++y) { + /* We divide by 2 here because we are writing 2 bytes at a time */ for (int x = 0; x < line_size()[i] / 2; ++x) { p[x] = v; } p += stride()[i] / 2; } } + + if (alpha) { + memset (data()[3], 0, lines(3) * stride()[3]); + } } uint16_t @@ -221,6 +268,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]); @@ -236,30 +284,70 @@ Image::make_black () case PIX_FMT_YUV422P9LE: case PIX_FMT_YUV444P9LE: - yuv_16_black (nine_bit_uv); + yuv_16_black (nine_bit_uv, false); break; case PIX_FMT_YUV422P9BE: case PIX_FMT_YUV444P9BE: - yuv_16_black (swap_16 (nine_bit_uv)); + yuv_16_black (swap_16 (nine_bit_uv), false); break; case PIX_FMT_YUV422P10LE: case PIX_FMT_YUV444P10LE: - yuv_16_black (ten_bit_uv); + yuv_16_black (ten_bit_uv, false); break; case PIX_FMT_YUV422P16LE: case PIX_FMT_YUV444P16LE: - yuv_16_black (sixteen_bit_uv); + yuv_16_black (sixteen_bit_uv, false); break; case PIX_FMT_YUV444P10BE: case PIX_FMT_YUV422P10BE: - yuv_16_black (swap_16 (ten_bit_uv)); + yuv_16_black (swap_16 (ten_bit_uv), false); + break; + + case AV_PIX_FMT_YUVA420P9BE: + case AV_PIX_FMT_YUVA422P9BE: + case AV_PIX_FMT_YUVA444P9BE: + yuv_16_black (swap_16 (nine_bit_uv), true); + break; + + case AV_PIX_FMT_YUVA420P9LE: + case AV_PIX_FMT_YUVA422P9LE: + case AV_PIX_FMT_YUVA444P9LE: + yuv_16_black (nine_bit_uv, true); + break; + + case AV_PIX_FMT_YUVA420P10BE: + case AV_PIX_FMT_YUVA422P10BE: + case AV_PIX_FMT_YUVA444P10BE: + yuv_16_black (swap_16 (ten_bit_uv), true); + break; + + case AV_PIX_FMT_YUVA420P10LE: + case AV_PIX_FMT_YUVA422P10LE: + case AV_PIX_FMT_YUVA444P10LE: + yuv_16_black (ten_bit_uv, true); + break; + + case AV_PIX_FMT_YUVA420P16BE: + case AV_PIX_FMT_YUVA422P16BE: + case AV_PIX_FMT_YUVA444P16BE: + yuv_16_black (swap_16 (sixteen_bit_uv), true); + break; + + case AV_PIX_FMT_YUVA420P16LE: + case AV_PIX_FMT_YUVA422P16LE: + case AV_PIX_FMT_YUVA444P16LE: + 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;