X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fimage.cc;h=432cfbd54b9279e0b2631cc417b511066dc2ab2f;hb=ee77b3cf5f59f775e75e628aa28e8f2f9f941530;hp=e5f626c24762bbb2e57be8e1bd06a1cada3b9efc;hpb=ae9b0b509787d244366eb8f69bdf9d563b6c6bb6;p=dcpomatic.git diff --git a/src/lib/image.cc b/src/lib/image.cc index e5f626c24..432cfbd54 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012 Carl Hetherington + Copyright (C) 2012-2014 Carl Hetherington 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 @@ -26,18 +26,22 @@ extern "C" { #include #include #include -#include } #include "image.h" #include "exceptions.h" #include "scaler.h" #include "timer.h" +#include "rect.h" + +#include "i18n.h" using std::string; using std::min; using std::cout; +using std::cerr; +using std::list; using boost::shared_ptr; -using libdcp::Size; +using dcp::Size; int Image::line_factor (int n) const @@ -81,7 +85,7 @@ Image::components () const /** Crop this image, scale it to `inter_size' and then place it in a black frame of `out_size' */ shared_ptr -Image::crop_scale_window (Crop crop, libdcp::Size inter_size, libdcp::Size out_size, Scaler const * scaler, AVPixelFormat out_format, bool out_aligned) const +Image::crop_scale_window (Crop crop, dcp::Size inter_size, dcp::Size out_size, Scaler const * scaler, AVPixelFormat out_format, bool out_aligned) const { assert (scaler); /* Empirical testing suggests that sws_scale() will crash if @@ -89,26 +93,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 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 */ + dcp::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[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; } @@ -125,7 +141,7 @@ Image::crop_scale_window (Crop crop, libdcp::Size inter_size, libdcp::Size out_s } shared_ptr -Image::scale (libdcp::Size out_size, Scaler const * scaler, AVPixelFormat out_format, bool out_aligned) const +Image::scale (dcp::Size out_size, Scaler const * scaler, AVPixelFormat out_format, bool out_aligned) const { assert (scaler); /* Empirical testing suggests that sws_scale() will crash if @@ -153,55 +169,10 @@ Image::scale (libdcp::Size out_size, Scaler const * scaler, AVPixelFormat out_fo return scaled; } -/** Run a FFmpeg post-process on this image and return the processed version. - * @param pp Flags for the required set of post processes. - * @return Post-processed image. - */ -shared_ptr -Image::post_process (string pp, bool aligned) const -{ - shared_ptr out (new Image (pixel_format(), size (), aligned)); - - int pp_format = 0; - switch (pixel_format()) { - case PIX_FMT_YUV420P: - pp_format = PP_FORMAT_420; - break; - case PIX_FMT_YUV422P10LE: - case PIX_FMT_YUV422P: - case PIX_FMT_UYVY422: - pp_format = PP_FORMAT_422; - break; - case PIX_FMT_YUV444P: - case PIX_FMT_YUV444P9BE: - case PIX_FMT_YUV444P9LE: - case PIX_FMT_YUV444P10BE: - case PIX_FMT_YUV444P10LE: - pp_format = PP_FORMAT_444; - default: - throw PixelFormatError ("post_process", pixel_format()); - } - - pp_mode* mode = pp_get_mode_by_name_and_quality (pp.c_str (), PP_QUALITY_MAX); - pp_context* context = pp_get_context (size().width, size().height, pp_format | PP_CPU_CAPS_MMX2); - - pp_postprocess ( - (const uint8_t **) data(), stride(), - out->data(), out->stride(), - size().width, size().height, - 0, 0, mode, context, 0 - ); - - pp_free_mode (mode); - pp_free_context (context); - - return out; -} - shared_ptr Image::crop (Crop crop, bool aligned) const { - libdcp::Size cropped_size = crop.apply (size ()); + dcp::Size cropped_size = crop.apply (size ()); shared_ptr out (new Image (pixel_format(), cropped_size, aligned)); for (int c = 0; c < components(); ++c) { @@ -373,6 +344,16 @@ Image::make_black () } } +void +Image::make_transparent () +{ + if (_pixel_format != PIX_FMT_RGBA) { + throw PixelFormatError ("make_transparent()", _pixel_format); + } + + memset (data()[0], 0, lines(0) * stride()[0]); +} + void Image::alpha_blend (shared_ptr other, Position position) { @@ -498,8 +479,8 @@ Image::bytes_per_pixel (int c) const * @param p Pixel format. * @param s Size in pixels. */ -Image::Image (AVPixelFormat p, libdcp::Size s, bool aligned) - : libdcp::Image (s) +Image::Image (AVPixelFormat p, dcp::Size s, bool aligned) + : dcp::Image (s) , _pixel_format (p) , _aligned (aligned) { @@ -509,13 +490,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) { @@ -531,12 +512,12 @@ 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); } } Image::Image (Image const & other) - : libdcp::Image (other) + : dcp::Image (other) , _pixel_format (other._pixel_format) , _aligned (other._aligned) { @@ -554,7 +535,7 @@ Image::Image (Image const & other) } Image::Image (AVFrame* frame) - : libdcp::Image (libdcp::Size (frame->width, frame->height)) + : dcp::Image (dcp::Size (frame->width, frame->height)) , _pixel_format (static_cast (frame->format)) , _aligned (true) { @@ -573,7 +554,7 @@ Image::Image (AVFrame* frame) } Image::Image (shared_ptr other, bool aligned) - : libdcp::Image (other) + : dcp::Image (other) , _pixel_format (other->_pixel_format) , _aligned (aligned) { @@ -606,7 +587,7 @@ Image::operator= (Image const & other) void Image::swap (Image & other) { - libdcp::Image::swap (other); + dcp::Image::swap (other); std::swap (_pixel_format, other._pixel_format); @@ -649,7 +630,7 @@ Image::stride () const return _stride; } -libdcp::Size +dcp::Size Image::size () const { return _size; @@ -661,3 +642,23 @@ Image::aligned () const return _aligned; } +PositionImage +merge (list images) +{ + if (images.empty ()) { + return PositionImage (); + } + + dcpomatic::Rect all (images.front().position, images.front().image->size().width, images.front().image->size().height); + for (list::const_iterator i = images.begin(); i != images.end(); ++i) { + all.extend (dcpomatic::Rect (i->position, i->image->size().width, i->image->size().height)); + } + + shared_ptr merged (new Image (images.front().image->pixel_format (), dcp::Size (all.width, all.height), true)); + merged->make_transparent (); + for (list::const_iterator i = images.begin(); i != images.end(); ++i) { + merged->alpha_blend (i->image, i->position); + } + + return PositionImage (merged, all.position ()); +}