1/*
2 * Copyright (C)2014 D. R. Commander.  All Rights Reserved.
3 * Copyright (C)2015 Viktor Szathmáry.  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
30package 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 */
66public 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.length != nc || (offsets != null && offsets.length != nc) ||
224        (strides != null && strides.length != nc))
225      throw new IllegalArgumentException("YUVImage::setBuf(): planes, offsets, or strides array is the wrong size");
226
227    if (offsets == null)
228      offsets = new int[nc];
229    if (strides == null)
230      strides = new int[nc];
231
232    for (int i = 0; i < nc; i++) {
233      int pw = TJ.planeWidth(i, width, subsamp);
234      int ph = TJ.planeHeight(i, height, subsamp);
235      int planeSize = TJ.planeSizeYUV(i, width, strides[i], height, subsamp);
236
237      if (strides[i] == 0)
238        strides[i] = pw;
239      if (alloc) {
240        if (strides[i] < pw)
241          throw new IllegalArgumentException("Stride must be >= plane width when allocating a new YUV image");
242        planes[i] = new byte[strides[i] * ph];
243      }
244      if (planes[i] == null || offsets[i] < 0)
245        throw new IllegalArgumentException("Invalid argument in YUVImage::setBuf()");
246      if (strides[i] < 0 && offsets[i] - planeSize + pw < 0)
247        throw new IllegalArgumentException("Stride for plane " + i + " would cause memory to be accessed below plane boundary");
248      if (planes[i].length < offsets[i] + planeSize)
249        throw new IllegalArgumentException("Image plane " + i + " is not large enough");
250    }
251
252    yuvPlanes = planes;
253    yuvOffsets = offsets;
254    yuvWidth = width;
255    yuvStrides = strides;
256    yuvHeight = height;
257    yuvSubsamp = subsamp;
258  }
259
260  /**
261   * Assign a unified image buffer to this <code>YUVImage</code> instance.
262   *
263   * @param yuvImage image buffer that contains or will contain YUV planar
264   * image data.  Use {@link TJ#bufSizeYUV} to determine the minimum size for
265   * this buffer.  The Y, U (Cb), and V (Cr) image planes are stored
266   * sequentially in the buffer (see {@link YUVImage above} for a description
267   * of the image format.)
268   *
269   * @param width width (in pixels) of the YUV image
270   *
271   * @param pad the line padding used in the YUV image buffer.  For
272   * instance, if each line in each plane of the buffer is padded to the
273   * nearest multiple of 4 bytes, then <code>pad</code> should be set to 4.
274   *
275   * @param height height (in pixels) of the YUV image
276   *
277   * @param subsamp the level of chrominance subsampling used in the YUV
278   * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
279   */
280  public void setBuf(byte[] yuvImage, int width, int pad, int height,
281                     int subsamp) {
282    if (yuvImage == null || width < 1 || pad < 1 || ((pad & (pad - 1)) != 0) ||
283        height < 1 || subsamp < 0 || subsamp >= TJ.NUMSAMP)
284      throw new IllegalArgumentException("Invalid argument in YUVImage::setBuf()");
285    if (yuvImage.length < TJ.bufSizeYUV(width, pad, height, subsamp))
286      throw new IllegalArgumentException("YUV image buffer is not large enough");
287
288    int nc = (subsamp == TJ.SAMP_GRAY ? 1 : 3);
289    byte[][] planes = new byte[nc][];
290    int[] strides = new int[nc];
291    int[] offsets = new int[nc];
292
293    planes[0] = yuvImage;
294    strides[0] = PAD(TJ.planeWidth(0, width, subsamp), pad);
295    if (subsamp != TJ.SAMP_GRAY) {
296      strides[1] = strides[2] = PAD(TJ.planeWidth(1, width, subsamp), pad);
297      planes[1] = planes[2] = yuvImage;
298      offsets[1] = offsets[0] +
299        strides[0] * TJ.planeHeight(0, height, subsamp);
300      offsets[2] = offsets[1] +
301        strides[1] * TJ.planeHeight(1, height, subsamp);
302    }
303
304    yuvPad = pad;
305    setBuf(planes, offsets, width, strides, height, subsamp);
306  }
307
308  /**
309   * Returns the width of the YUV image (or subregion.)
310   *
311   * @return the width of the YUV image (or subregion)
312   */
313  public int getWidth() {
314    if (yuvWidth < 1)
315      throw new IllegalStateException(NO_ASSOC_ERROR);
316    return yuvWidth;
317  }
318
319  /**
320   * Returns the height of the YUV image (or subregion.)
321   *
322   * @return the height of the YUV image (or subregion)
323   */
324  public int getHeight() {
325    if (yuvHeight < 1)
326      throw new IllegalStateException(NO_ASSOC_ERROR);
327    return yuvHeight;
328  }
329
330  /**
331   * Returns the line padding used in the YUV image buffer (if this image is
332   * stored in a unified buffer rather than separate image planes.)
333   *
334   * @return the line padding used in the YUV image buffer
335   */
336  public int getPad() {
337    if (yuvPlanes == null)
338      throw new IllegalStateException(NO_ASSOC_ERROR);
339    if (yuvPad < 1 || ((yuvPad & (yuvPad - 1)) != 0))
340      throw new IllegalStateException("Image is not stored in a unified buffer");
341    return yuvPad;
342  }
343
344  /**
345   * Returns the number of bytes per line of each plane in the YUV image.
346   *
347   * @return the number of bytes per line of each plane in the YUV image
348   */
349  public int[] getStrides() {
350    if (yuvStrides == null)
351      throw new IllegalStateException(NO_ASSOC_ERROR);
352    return yuvStrides;
353  }
354
355  /**
356   * Returns the offsets (in bytes) of each plane within the planes of a larger
357   * YUV image.
358   *
359   * @return the offsets (in bytes) of each plane within the planes of a larger
360   * YUV image
361   */
362  public int[] getOffsets() {
363    if (yuvOffsets == null)
364      throw new IllegalStateException(NO_ASSOC_ERROR);
365    return yuvOffsets;
366  }
367
368  /**
369   * Returns the level of chrominance subsampling used in the YUV image.  See
370   * {@link TJ#SAMP_444 TJ.SAMP_*}.
371   *
372   * @return the level of chrominance subsampling used in the YUV image
373   */
374  public int getSubsamp() {
375    if (yuvSubsamp < 0 || yuvSubsamp >= TJ.NUMSAMP)
376      throw new IllegalStateException(NO_ASSOC_ERROR);
377    return yuvSubsamp;
378  }
379
380  /**
381   * Returns the YUV image planes.  If the image is stored in a unified buffer,
382   * then all image planes will point to that buffer.
383   *
384   * @return the YUV image planes
385   */
386  public byte[][] getPlanes() {
387    if (yuvPlanes == null)
388      throw new IllegalStateException(NO_ASSOC_ERROR);
389    return yuvPlanes;
390  }
391
392  /**
393   * Returns the YUV image buffer (if this image is stored in a unified
394   * buffer rather than separate image planes.)
395   *
396   * @return the YUV image buffer
397   */
398  public byte[] getBuf() {
399    if (yuvPlanes == null || yuvSubsamp < 0 || yuvSubsamp >= TJ.NUMSAMP)
400      throw new IllegalStateException(NO_ASSOC_ERROR);
401    int nc = (yuvSubsamp == TJ.SAMP_GRAY ? 1 : 3);
402    for (int i = 1; i < nc; i++) {
403      if (yuvPlanes[i] != yuvPlanes[0])
404        throw new IllegalStateException("Image is not stored in a unified buffer");
405    }
406    return yuvPlanes[0];
407  }
408
409  /**
410   * Returns the size (in bytes) of the YUV image buffer (if this image is
411   * stored in a unified buffer rather than separate image planes.)
412   *
413   * @return the size (in bytes) of the YUV image buffer
414   */
415  public int getSize() {
416    if (yuvPlanes == null || yuvSubsamp < 0 || yuvSubsamp >= TJ.NUMSAMP)
417      throw new IllegalStateException(NO_ASSOC_ERROR);
418    int nc = (yuvSubsamp == TJ.SAMP_GRAY ? 1 : 3);
419    if (yuvPad < 1)
420      throw new IllegalStateException("Image is not stored in a unified buffer");
421    for (int i = 1; i < nc; i++) {
422      if (yuvPlanes[i] != yuvPlanes[0])
423        throw new IllegalStateException("Image is not stored in a unified buffer");
424    }
425    return TJ.bufSizeYUV(yuvWidth, yuvPad, yuvHeight, yuvSubsamp);
426  }
427
428  private static final int PAD(int v, int p) {
429    return (v + p - 1) & (~(p - 1));
430  }
431
432  protected long handle = 0;
433  protected byte[][] yuvPlanes = null;
434  protected int[] yuvOffsets = null;
435  protected int[] yuvStrides = null;
436  protected int yuvPad = 0;
437  protected int yuvWidth = 0;
438  protected int yuvHeight = 0;
439  protected int yuvSubsamp = -1;
440}
441