Home | History | Annotate | Download | only in turbojpeg
      1 /*
      2  * Copyright (C)2014, 2017 D. R. Commander.  All Rights Reserved.
      3  * Copyright (C)2015 Viktor Szathmry.  All Rights Reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  * - Redistributions of source code must retain the above copyright notice,
      9  *   this list of conditions and the following disclaimer.
     10  * - Redistributions in binary form must reproduce the above copyright notice,
     11  *   this list of conditions and the following disclaimer in the documentation
     12  *   and/or other materials provided with the distribution.
     13  * - Neither the name of the libjpeg-turbo Project nor the names of its
     14  *   contributors may be used to endorse or promote products derived from this
     15  *   software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
     18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
     21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     27  * POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 package org.libjpegturbo.turbojpeg;
     31 
     32 /**
     33  * This class encapsulates a YUV planar image and the metadata
     34  * associated with it.  The TurboJPEG API allows both the JPEG compression and
     35  * decompression pipelines to be split into stages:  YUV encode, compress from
     36  * YUV, decompress to YUV, and YUV decode.  A <code>YUVImage</code> instance
     37  * serves as the destination image for YUV encode and decompress-to-YUV
     38  * operations and as the source image for compress-from-YUV and YUV decode
     39  * operations.
     40  * <p>
     41  * Technically, the JPEG format uses the YCbCr colorspace (which technically is
     42  * not a "colorspace" but rather a "color transform"), but per the convention
     43  * of the digital video community, the TurboJPEG API uses "YUV" to refer to an
     44  * image format consisting of Y, Cb, and Cr image planes.
     45  * <p>
     46  * Each plane is simply a 2D array of bytes, each byte representing the value
     47  * of one of the components (Y, Cb, or Cr) at a particular location in the
     48  * image.  The width and height of each plane are determined by the image
     49  * width, height, and level of chrominance subsampling.  The luminance plane
     50  * width is the image width padded to the nearest multiple of the horizontal
     51  * subsampling factor (2 in the case of 4:2:0 and 4:2:2, 4 in the case of
     52  * 4:1:1, 1 in the case of 4:4:4 or grayscale.)  Similarly, the luminance plane
     53  * height is the image height padded to the nearest multiple of the vertical
     54  * subsampling factor (2 in the case of 4:2:0 or 4:4:0, 1 in the case of 4:4:4
     55  * or grayscale.)  The chrominance plane width is equal to the luminance plane
     56  * width divided by the horizontal subsampling factor, and the chrominance
     57  * plane height is equal to the luminance plane height divided by the vertical
     58  * subsampling factor.
     59  * <p>
     60  * For example, if the source image is 35 x 35 pixels and 4:2:2 subsampling is
     61  * used, then the luminance plane would be 36 x 35 bytes, and each of the
     62  * chrominance planes would be 18 x 35 bytes.  If you specify a line padding of
     63  * 4 bytes on top of this, then the luminance plane would be 36 x 35 bytes, and
     64  * each of the chrominance planes would be 20 x 35 bytes.
     65  */
     66 public class YUVImage {
     67 
     68   private static final String NO_ASSOC_ERROR =
     69     "No image data is associated with this instance";
     70 
     71   /**
     72    * Create a new <code>YUVImage</code> instance backed by separate image
     73    * planes, and allocate memory for the image planes.
     74    *
     75    * @param width width (in pixels) of the YUV image
     76    *
     77    * @param strides an array of integers, each specifying the number of bytes
     78    * per line in the corresponding plane of the YUV image.  Setting the stride
     79    * for any plane to 0 is the same as setting it to the plane width (see
     80    * {@link YUVImage above}.)  If <code>strides</code> is null, then the
     81    * strides for all planes will be set to their respective plane widths.  When
     82    * using this constructor, the stride for each plane must be equal to or
     83    * greater than the plane width.
     84    *
     85    * @param height height (in pixels) of the YUV image
     86    *
     87    * @param subsamp the level of chrominance subsampling to be used in the YUV
     88    * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
     89    */
     90   public YUVImage(int width, int[] strides, int height, int subsamp) {
     91     setBuf(null, null, width, strides, height, subsamp, true);
     92   }
     93 
     94   /**
     95    * Create a new <code>YUVImage</code> instance backed by a unified image
     96    * buffer, and allocate memory for the image buffer.
     97    *
     98    * @param width width (in pixels) of the YUV image
     99    *
    100    * @param pad Each line of each plane in the YUV image buffer will be padded
    101    * to this number of bytes (must be a power of 2.)
    102    *
    103    * @param height height (in pixels) of the YUV image
    104    *
    105    * @param subsamp the level of chrominance subsampling to be used in the YUV
    106    * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
    107    */
    108   public YUVImage(int width, int pad, int height, int subsamp) {
    109     setBuf(new byte[TJ.bufSizeYUV(width, pad, height, subsamp)], width, pad,
    110            height, subsamp);
    111   }
    112 
    113   /**
    114    * Create a new <code>YUVImage</code> instance from a set of existing image
    115    * planes.
    116    *
    117    * @param planes an array of buffers representing the Y, U (Cb), and V (Cr)
    118    * image planes (or just the Y plane, if the image is grayscale.)   These
    119    * planes can be contiguous or non-contiguous in memory.  Plane
    120    * <code>i</code> should be at least <code>offsets[i] +
    121    * {@link TJ#planeSizeYUV TJ.planeSizeYUV}(i, width, strides[i], height, subsamp)</code>
    122    * bytes in size.
    123    *
    124    * @param offsets If this <code>YUVImage</code> instance represents a
    125    * subregion of a larger image, then <code>offsets[i]</code> specifies the
    126    * offset (in bytes) of the subregion within plane <code>i</code> of the
    127    * larger image.  Setting this to null is the same as setting the offsets for
    128    * all planes to 0.
    129    *
    130    * @param width width (in pixels) of the new YUV image (or subregion)
    131    *
    132    * @param strides an array of integers, each specifying the number of bytes
    133    * per line in the corresponding plane of the YUV image.  Setting the stride
    134    * for any plane to 0 is the same as setting it to the plane width (see
    135    * {@link YUVImage above}.)  If <code>strides</code> is null, then the
    136    * strides for all planes will be set to their respective plane widths.  You
    137    * can adjust the strides in order to add an arbitrary amount of line padding
    138    * to each plane or to specify that this <code>YUVImage</code> instance is a
    139    * subregion of a larger image (in which case, <code>strides[i]</code> should
    140    * be set to the plane width of plane <code>i</code> in the larger image.)
    141    *
    142    * @param height height (in pixels) of the new YUV image (or subregion)
    143    *
    144    * @param subsamp the level of chrominance subsampling used in the YUV
    145    * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
    146    */
    147   public YUVImage(byte[][] planes, int[] offsets, int width, int[] strides,
    148                   int height, int subsamp) {
    149     setBuf(planes, offsets, width, strides, height, subsamp, false);
    150   }
    151 
    152   /**
    153    * Create a new <code>YUVImage</code> instance from an existing unified image
    154    * buffer.
    155    *
    156    * @param yuvImage image buffer that contains or will contain YUV planar
    157    * image data.  Use {@link TJ#bufSizeYUV} to determine the minimum size for
    158    * this buffer.  The Y, U (Cb), and V (Cr) image planes are stored
    159    * sequentially in the buffer (see {@link YUVImage above} for a description
    160    * of the image format.)
    161    *
    162    * @param width width (in pixels) of the YUV image
    163    *
    164    * @param pad the line padding used in the YUV image buffer.  For
    165    * instance, if each line in each plane of the buffer is padded to the
    166    * nearest multiple of 4 bytes, then <code>pad</code> should be set to 4.
    167    *
    168    * @param height height (in pixels) of the YUV image
    169    *
    170    * @param subsamp the level of chrominance subsampling used in the YUV
    171    * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
    172    */
    173   public YUVImage(byte[] yuvImage, int width, int pad, int height,
    174                   int subsamp) {
    175     setBuf(yuvImage, width, pad, height, subsamp);
    176   }
    177 
    178   /**
    179    * Assign a set of image planes to this <code>YUVImage</code> instance.
    180    *
    181    * @param planes an array of buffers representing the Y, U (Cb), and V (Cr)
    182    * image planes (or just the Y plane, if the image is grayscale.)  These
    183    * planes can be contiguous or non-contiguous in memory.  Plane
    184    * <code>i</code> should be at least <code>offsets[i] +
    185    * {@link TJ#planeSizeYUV TJ.planeSizeYUV}(i, width, strides[i], height, subsamp)</code>
    186    * bytes in size.
    187    *
    188    * @param offsets If this <code>YUVImage</code> instance represents a
    189    * subregion of a larger image, then <code>offsets[i]</code> specifies the
    190    * offset (in bytes) of the subregion within plane <code>i</code> of the
    191    * larger image.  Setting this to null is the same as setting the offsets for
    192    * all planes to 0.
    193    *
    194    * @param width width (in pixels) of the YUV image (or subregion)
    195    *
    196    * @param strides an array of integers, each specifying the number of bytes
    197    * per line in the corresponding plane of the YUV image.  Setting the stride
    198    * for any plane to 0 is the same as setting it to the plane width (see
    199    * {@link YUVImage above}.)  If <code>strides</code> is null, then the
    200    * strides for all planes will be set to their respective plane widths.  You
    201    * can adjust the strides in order to add an arbitrary amount of line padding
    202    * to each plane or to specify that this <code>YUVImage</code> image is a
    203    * subregion of a larger image (in which case, <code>strides[i]</code> should
    204    * be set to the plane width of plane <code>i</code> in the larger image.)
    205    *
    206    * @param height height (in pixels) of the YUV image (or subregion)
    207    *
    208    * @param subsamp the level of chrominance subsampling used in the YUV
    209    * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
    210    */
    211   public void setBuf(byte[][] planes, int[] offsets, int width, int strides[],
    212                      int height, int subsamp) {
    213     setBuf(planes, offsets, width, strides, height, subsamp, false);
    214   }
    215 
    216   private void setBuf(byte[][] planes, int[] offsets, int width, int strides[],
    217                      int height, int subsamp, boolean alloc) {
    218     if ((planes == null && !alloc) || width < 1 || height < 1 || subsamp < 0 ||
    219         subsamp >= TJ.NUMSAMP)
    220       throw new IllegalArgumentException("Invalid argument in YUVImage::setBuf()");
    221 
    222     int nc = (subsamp == TJ.SAMP_GRAY ? 1 : 3);
    223     if ((planes != null && planes.length != nc) ||
    224         (offsets != null && offsets.length != nc) ||
    225         (strides != null && strides.length != nc))
    226       throw new IllegalArgumentException("YUVImage::setBuf(): planes, offsets, or strides array is the wrong size");
    227 
    228     if (planes == null)
    229       planes = new byte[nc][];
    230     if (offsets == null)
    231       offsets = new int[nc];
    232     if (strides == null)
    233       strides = new int[nc];
    234 
    235     for (int i = 0; i < nc; i++) {
    236       int pw = TJ.planeWidth(i, width, subsamp);
    237       int ph = TJ.planeHeight(i, height, subsamp);
    238       int planeSize = TJ.planeSizeYUV(i, width, strides[i], height, subsamp);
    239 
    240       if (strides[i] == 0)
    241         strides[i] = pw;
    242       if (alloc) {
    243         if (strides[i] < pw)
    244           throw new IllegalArgumentException("Stride must be >= plane width when allocating a new YUV image");
    245         planes[i] = new byte[strides[i] * ph];
    246       }
    247       if (planes[i] == null || offsets[i] < 0)
    248         throw new IllegalArgumentException("Invalid argument in YUVImage::setBuf()");
    249       if (strides[i] < 0 && offsets[i] - planeSize + pw < 0)
    250         throw new IllegalArgumentException("Stride for plane " + i + " would cause memory to be accessed below plane boundary");
    251       if (planes[i].length < offsets[i] + planeSize)
    252         throw new IllegalArgumentException("Image plane " + i + " is not large enough");
    253     }
    254 
    255     yuvPlanes = planes;
    256     yuvOffsets = offsets;
    257     yuvWidth = width;
    258     yuvStrides = strides;
    259     yuvHeight = height;
    260     yuvSubsamp = subsamp;
    261   }
    262 
    263   /**
    264    * Assign a unified image buffer to this <code>YUVImage</code> instance.
    265    *
    266    * @param yuvImage image buffer that contains or will contain YUV planar
    267    * image data.  Use {@link TJ#bufSizeYUV} to determine the minimum size for
    268    * this buffer.  The Y, U (Cb), and V (Cr) image planes are stored
    269    * sequentially in the buffer (see {@link YUVImage above} for a description
    270    * of the image format.)
    271    *
    272    * @param width width (in pixels) of the YUV image
    273    *
    274    * @param pad the line padding used in the YUV image buffer.  For
    275    * instance, if each line in each plane of the buffer is padded to the
    276    * nearest multiple of 4 bytes, then <code>pad</code> should be set to 4.
    277    *
    278    * @param height height (in pixels) of the YUV image
    279    *
    280    * @param subsamp the level of chrominance subsampling used in the YUV
    281    * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
    282    */
    283   public void setBuf(byte[] yuvImage, int width, int pad, int height,
    284                      int subsamp) {
    285     if (yuvImage == null || width < 1 || pad < 1 || ((pad & (pad - 1)) != 0) ||
    286         height < 1 || subsamp < 0 || subsamp >= TJ.NUMSAMP)
    287       throw new IllegalArgumentException("Invalid argument in YUVImage::setBuf()");
    288     if (yuvImage.length < TJ.bufSizeYUV(width, pad, height, subsamp))
    289       throw new IllegalArgumentException("YUV image buffer is not large enough");
    290 
    291     int nc = (subsamp == TJ.SAMP_GRAY ? 1 : 3);
    292     byte[][] planes = new byte[nc][];
    293     int[] strides = new int[nc];
    294     int[] offsets = new int[nc];
    295 
    296     planes[0] = yuvImage;
    297     strides[0] = PAD(TJ.planeWidth(0, width, subsamp), pad);
    298     if (subsamp != TJ.SAMP_GRAY) {
    299       strides[1] = strides[2] = PAD(TJ.planeWidth(1, width, subsamp), pad);
    300       planes[1] = planes[2] = yuvImage;
    301       offsets[1] = offsets[0] +
    302         strides[0] * TJ.planeHeight(0, height, subsamp);
    303       offsets[2] = offsets[1] +
    304         strides[1] * TJ.planeHeight(1, height, subsamp);
    305     }
    306 
    307     yuvPad = pad;
    308     setBuf(planes, offsets, width, strides, height, subsamp);
    309   }
    310 
    311   /**
    312    * Returns the width of the YUV image (or subregion.)
    313    *
    314    * @return the width of the YUV image (or subregion)
    315    */
    316   public int getWidth() {
    317     if (yuvWidth < 1)
    318       throw new IllegalStateException(NO_ASSOC_ERROR);
    319     return yuvWidth;
    320   }
    321 
    322   /**
    323    * Returns the height of the YUV image (or subregion.)
    324    *
    325    * @return the height of the YUV image (or subregion)
    326    */
    327   public int getHeight() {
    328     if (yuvHeight < 1)
    329       throw new IllegalStateException(NO_ASSOC_ERROR);
    330     return yuvHeight;
    331   }
    332 
    333   /**
    334    * Returns the line padding used in the YUV image buffer (if this image is
    335    * stored in a unified buffer rather than separate image planes.)
    336    *
    337    * @return the line padding used in the YUV image buffer
    338    */
    339   public int getPad() {
    340     if (yuvPlanes == null)
    341       throw new IllegalStateException(NO_ASSOC_ERROR);
    342     if (yuvPad < 1 || ((yuvPad & (yuvPad - 1)) != 0))
    343       throw new IllegalStateException("Image is not stored in a unified buffer");
    344     return yuvPad;
    345   }
    346 
    347   /**
    348    * Returns the number of bytes per line of each plane in the YUV image.
    349    *
    350    * @return the number of bytes per line of each plane in the YUV image
    351    */
    352   public int[] getStrides() {
    353     if (yuvStrides == null)
    354       throw new IllegalStateException(NO_ASSOC_ERROR);
    355     return yuvStrides;
    356   }
    357 
    358   /**
    359    * Returns the offsets (in bytes) of each plane within the planes of a larger
    360    * YUV image.
    361    *
    362    * @return the offsets (in bytes) of each plane within the planes of a larger
    363    * YUV image
    364    */
    365   public int[] getOffsets() {
    366     if (yuvOffsets == null)
    367       throw new IllegalStateException(NO_ASSOC_ERROR);
    368     return yuvOffsets;
    369   }
    370 
    371   /**
    372    * Returns the level of chrominance subsampling used in the YUV image.  See
    373    * {@link TJ#SAMP_444 TJ.SAMP_*}.
    374    *
    375    * @return the level of chrominance subsampling used in the YUV image
    376    */
    377   public int getSubsamp() {
    378     if (yuvSubsamp < 0 || yuvSubsamp >= TJ.NUMSAMP)
    379       throw new IllegalStateException(NO_ASSOC_ERROR);
    380     return yuvSubsamp;
    381   }
    382 
    383   /**
    384    * Returns the YUV image planes.  If the image is stored in a unified buffer,
    385    * then all image planes will point to that buffer.
    386    *
    387    * @return the YUV image planes
    388    */
    389   public byte[][] getPlanes() {
    390     if (yuvPlanes == null)
    391       throw new IllegalStateException(NO_ASSOC_ERROR);
    392     return yuvPlanes;
    393   }
    394 
    395   /**
    396    * Returns the YUV image buffer (if this image is stored in a unified
    397    * buffer rather than separate image planes.)
    398    *
    399    * @return the YUV image buffer
    400    */
    401   public byte[] getBuf() {
    402     if (yuvPlanes == null || yuvSubsamp < 0 || yuvSubsamp >= TJ.NUMSAMP)
    403       throw new IllegalStateException(NO_ASSOC_ERROR);
    404     int nc = (yuvSubsamp == TJ.SAMP_GRAY ? 1 : 3);
    405     for (int i = 1; i < nc; i++) {
    406       if (yuvPlanes[i] != yuvPlanes[0])
    407         throw new IllegalStateException("Image is not stored in a unified buffer");
    408     }
    409     return yuvPlanes[0];
    410   }
    411 
    412   /**
    413    * Returns the size (in bytes) of the YUV image buffer (if this image is
    414    * stored in a unified buffer rather than separate image planes.)
    415    *
    416    * @return the size (in bytes) of the YUV image buffer
    417    */
    418   public int getSize() {
    419     if (yuvPlanes == null || yuvSubsamp < 0 || yuvSubsamp >= TJ.NUMSAMP)
    420       throw new IllegalStateException(NO_ASSOC_ERROR);
    421     int nc = (yuvSubsamp == TJ.SAMP_GRAY ? 1 : 3);
    422     if (yuvPad < 1)
    423       throw new IllegalStateException("Image is not stored in a unified buffer");
    424     for (int i = 1; i < nc; i++) {
    425       if (yuvPlanes[i] != yuvPlanes[0])
    426         throw new IllegalStateException("Image is not stored in a unified buffer");
    427     }
    428     return TJ.bufSizeYUV(yuvWidth, yuvPad, yuvHeight, yuvSubsamp);
    429   }
    430 
    431   private static final int PAD(int v, int p) {
    432     return (v + p - 1) & (~(p - 1));
    433   }
    434 
    435   protected long handle = 0;
    436   protected byte[][] yuvPlanes = null;
    437   protected int[] yuvOffsets = null;
    438   protected int[] yuvStrides = null;
    439   protected int yuvPad = 0;
    440   protected int yuvWidth = 0;
    441   protected int yuvHeight = 0;
    442   protected int yuvSubsamp = -1;
    443 }
    444