• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C)2014, 2017 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 
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    */
YUVImage(int width, int[] strides, int height, int subsamp)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    */
YUVImage(int width, int pad, int height, int subsamp)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    */
YUVImage(byte[][] planes, int[] offsets, int width, int[] strides, int height, int subsamp)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    */
YUVImage(byte[] yuvImage, int width, int pad, int height, int subsamp)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    */
setBuf(byte[][] planes, int[] offsets, int width, int strides[], int height, int subsamp)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 
setBuf(byte[][] planes, int[] offsets, int width, int strides[], int height, int subsamp, boolean alloc)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    */
setBuf(byte[] yuvImage, int width, int pad, int height, int subsamp)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    */
getWidth()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    */
getHeight()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    */
getPad()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    */
getStrides()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    */
getOffsets()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    */
getSubsamp()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    */
getPlanes()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    */
getBuf()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    */
getSize()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 
PAD(int v, int p)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