Fix crop of some YUV content.
authorCarl Hetherington <cth@carlh.net>
Sun, 16 Aug 2015 23:37:39 +0000 (00:37 +0100)
committerCarl Hetherington <cth@carlh.net>
Sun, 16 Aug 2015 23:37:39 +0000 (00:37 +0100)
ChangeLog
src/lib/image.cc

index 7d4d3b96c00fde387b0b6d5bdf6d7a6b0fd441d6..d2be31f944ae0ea6cd691cc47bafcec40c0d08b8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2015-08-17  Carl Hetherington  <cth@carlh.net>
+
+       * Fix crop of some YUV content.
+
 2015-08-11  Carl Hetherington  <cth@carlh.net>
 
        * Prevent multiple creation of certificate chains
index c403b61abfe9cee0daea7d74cdccd49820275b60..30b997737698480336a5bfd19917172c64f0dd60 100644 (file)
@@ -54,7 +54,7 @@ Image::line_factor (int n) const
 
        AVPixFmtDescriptor const * d = av_pix_fmt_desc_get(_pixel_format);
        if (!d) {
-               throw PixelFormatError ("lines()", _pixel_format);
+               throw PixelFormatError ("line_factor()", _pixel_format);
        }
 
        return pow (2.0f, d->log2_chroma_h);
@@ -130,10 +130,21 @@ Image::crop_scale_window (
                0, 1 << 16, 1 << 16
                );
 
+       AVPixFmtDescriptor const * desc = av_pix_fmt_desc_get (_pixel_format);
+       if (!desc) {
+               throw PixelFormatError ("crop_scale_window()", _pixel_format);
+       }
+
        /* 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));
+               /* To work out the crop in bytes, start by multiplying
+                  the crop by the (average) bytes per pixel.  Then
+                  round down so that we don't crop a subsampled pixel until
+                  we've cropped all of its Y-channel pixels.
+               */
+               int const x = int (rint (bytes_per_pixel(c) * crop.left)) & ~ ((int) desc->log2_chroma_w);
+               scale_in_data[c] = data()[c] + x + stride()[c] * (crop.top / line_factor(c));
        }
 
        /* Corner of the image within out_size */
@@ -515,7 +526,7 @@ Image::bytes_per_pixel (int c) const
 {
        AVPixFmtDescriptor const * d = av_pix_fmt_desc_get(_pixel_format);
        if (!d) {
-               throw PixelFormatError ("lines()", _pixel_format);
+               throw PixelFormatError ("bytes_per_pixel()", _pixel_format);
        }
 
        if (c >= components()) {