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