YUVImage.java 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  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. package org.libjpegturbo.turbojpeg;
  30. /**
  31. * This class encapsulates a YUV planar image and the metadata
  32. * associated with it. The TurboJPEG API allows both the JPEG compression and
  33. * decompression pipelines to be split into stages: YUV encode, compress from
  34. * YUV, decompress to YUV, and YUV decode. A <code>YUVImage</code> instance
  35. * serves as the destination image for YUV encode and decompress-to-YUV
  36. * operations and as the source image for compress-from-YUV and YUV decode
  37. * operations.
  38. * <p>
  39. * Technically, the JPEG format uses the YCbCr colorspace (which technically is
  40. * not a "colorspace" but rather a "color transform"), but per the convention
  41. * of the digital video community, the TurboJPEG API uses "YUV" to refer to an
  42. * image format consisting of Y, Cb, and Cr image planes.
  43. * <p>
  44. * Each plane is simply a 2D array of bytes, each byte representing the value
  45. * of one of the components (Y, Cb, or Cr) at a particular location in the
  46. * image. The width and height of each plane are determined by the image
  47. * width, height, and level of chrominance subsampling. The luminance plane
  48. * width is the image width padded to the nearest multiple of the horizontal
  49. * subsampling factor (2 in the case of 4:2:0 and 4:2:2, 4 in the case of
  50. * 4:1:1, 1 in the case of 4:4:4 or grayscale.) Similarly, the luminance plane
  51. * height is the image height padded to the nearest multiple of the vertical
  52. * subsampling factor (2 in the case of 4:2:0 or 4:4:0, 1 in the case of 4:4:4
  53. * or grayscale.) The chrominance plane width is equal to the luminance plane
  54. * width divided by the horizontal subsampling factor, and the chrominance
  55. * plane height is equal to the luminance plane height divided by the vertical
  56. * subsampling factor.
  57. * <p>
  58. * For example, if the source image is 35 x 35 pixels and 4:2:2 subsampling is
  59. * used, then the luminance plane would be 36 x 35 bytes, and each of the
  60. * chrominance planes would be 18 x 35 bytes. If you specify a line padding of
  61. * 4 bytes on top of this, then the luminance plane would be 36 x 35 bytes, and
  62. * each of the chrominance planes would be 20 x 35 bytes.
  63. */
  64. public class YUVImage {
  65. private static final String NO_ASSOC_ERROR =
  66. "No image data is associated with this instance";
  67. /**
  68. * Create a new <code>YUVImage</code> instance backed by separate image
  69. * planes, and allocate memory for the image planes.
  70. *
  71. * @param width width (in pixels) of the YUV image
  72. *
  73. * @param strides an array of integers, each specifying the number of bytes
  74. * per line in the corresponding plane of the YUV image. Setting the stride
  75. * for any plane to 0 is the same as setting it to the plane width (see
  76. * {@link YUVImage above}.) If <code>strides</code> is null, then the
  77. * strides for all planes will be set to their respective plane widths. When
  78. * using this constructor, the stride for each plane must be equal to or
  79. * greater than the plane width.
  80. *
  81. * @param height height (in pixels) of the YUV image
  82. *
  83. * @param subsamp the level of chrominance subsampling to be used in the YUV
  84. * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
  85. */
  86. public YUVImage(int width, int[] strides, int height, int subsamp) {
  87. setBuf(null, null, width, strides, height, subsamp, true);
  88. }
  89. /**
  90. * Create a new <code>YUVImage</code> instance backed by a unified image
  91. * buffer, and allocate memory for the image buffer.
  92. *
  93. * @param width width (in pixels) of the YUV image
  94. *
  95. * @param pad Each line of each plane in the YUV image buffer will be padded
  96. * to this number of bytes (must be a power of 2.)
  97. *
  98. * @param height height (in pixels) of the YUV image
  99. *
  100. * @param subsamp the level of chrominance subsampling to be used in the YUV
  101. * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
  102. */
  103. public YUVImage(int width, int pad, int height, int subsamp) {
  104. setBuf(new byte[TJ.bufSizeYUV(width, pad, height, subsamp)], width, pad,
  105. height, subsamp);
  106. }
  107. /**
  108. * Create a new <code>YUVImage</code> instance from a set of existing image
  109. * planes.
  110. *
  111. * @param planes an array of buffers representing the Y, U (Cb), and V (Cr)
  112. * image planes (or just the Y plane, if the image is grayscale.) These
  113. * planes can be contiguous or non-contiguous in memory. Plane
  114. * <code>i</code> should be at least <code>offsets[i] +
  115. * {@link TJ#planeSizeYUV TJ.planeSizeYUV}(i, width, strides[i], height, subsamp)</code>
  116. * bytes in size.
  117. *
  118. * @param offsets If this <code>YUVImage</code> instance represents a
  119. * subregion of a larger image, then <code>offsets[i]</code> specifies the
  120. * offset (in bytes) of the subregion within plane <code>i</code> of the
  121. * larger image. Setting this to null is the same as setting the offsets for
  122. * all planes to 0.
  123. *
  124. * @param width width (in pixels) of the new YUV image (or subregion)
  125. *
  126. * @param strides an array of integers, each specifying the number of bytes
  127. * per line in the corresponding plane of the YUV image. Setting the stride
  128. * for any plane to 0 is the same as setting it to the plane width (see
  129. * {@link YUVImage above}.) If <code>strides</code> is null, then the
  130. * strides for all planes will be set to their respective plane widths. You
  131. * can adjust the strides in order to add an arbitrary amount of line padding
  132. * to each plane or to specify that this <code>YUVImage</code> instance is a
  133. * subregion of a larger image (in which case, <code>strides[i]</code> should
  134. * be set to the plane width of plane <code>i</code> in the larger image.)
  135. *
  136. * @param height height (in pixels) of the new YUV image (or subregion)
  137. *
  138. * @param subsamp the level of chrominance subsampling used in the YUV
  139. * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
  140. */
  141. public YUVImage(byte[][] planes, int[] offsets, int width, int[] strides,
  142. int height, int subsamp) {
  143. setBuf(planes, offsets, width, strides, height, subsamp, false);
  144. }
  145. /**
  146. * Create a new <code>YUVImage</code> instance from an existing unified image
  147. * buffer.
  148. *
  149. * @param yuvImage image buffer that contains or will contain YUV planar
  150. * image data. Use {@link TJ#bufSizeYUV} to determine the minimum size for
  151. * this buffer. The Y, U (Cb), and V (Cr) image planes are stored
  152. * sequentially in the buffer (see {@link YUVImage above} for a description
  153. * of the image format.)
  154. *
  155. * @param width width (in pixels) of the YUV image
  156. *
  157. * @param pad the line padding used in the YUV image buffer. For
  158. * instance, if each line in each plane of the buffer is padded to the
  159. * nearest multiple of 4 bytes, then <code>pad</code> should be set to 4.
  160. *
  161. * @param height height (in pixels) of the YUV image
  162. *
  163. * @param subsamp the level of chrominance subsampling used in the YUV
  164. * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
  165. */
  166. public YUVImage(byte[] yuvImage, int width, int pad, int height,
  167. int subsamp) {
  168. setBuf(yuvImage, width, pad, height, subsamp);
  169. }
  170. /**
  171. * Assign a set of image planes to this <code>YUVImage</code> instance.
  172. *
  173. * @param planes an array of buffers representing the Y, U (Cb), and V (Cr)
  174. * image planes (or just the Y plane, if the image is grayscale.) These
  175. * planes can be contiguous or non-contiguous in memory. Plane
  176. * <code>i</code> should be at least <code>offsets[i] +
  177. * {@link TJ#planeSizeYUV TJ.planeSizeYUV}(i, width, strides[i], height, subsamp)</code>
  178. * bytes in size.
  179. *
  180. * @param offsets If this <code>YUVImage</code> instance represents a
  181. * subregion of a larger image, then <code>offsets[i]</code> specifies the
  182. * offset (in bytes) of the subregion within plane <code>i</code> of the
  183. * larger image. Setting this to null is the same as setting the offsets for
  184. * all planes to 0.
  185. *
  186. * @param width width (in pixels) of the YUV image (or subregion)
  187. *
  188. * @param strides an array of integers, each specifying the number of bytes
  189. * per line in the corresponding plane of the YUV image. Setting the stride
  190. * for any plane to 0 is the same as setting it to the plane width (see
  191. * {@link YUVImage above}.) If <code>strides</code> is null, then the
  192. * strides for all planes will be set to their respective plane widths. You
  193. * can adjust the strides in order to add an arbitrary amount of line padding
  194. * to each plane or to specify that this <code>YUVImage</code> image is a
  195. * subregion of a larger image (in which case, <code>strides[i]</code> should
  196. * be set to the plane width of plane <code>i</code> in the larger image.)
  197. *
  198. * @param height height (in pixels) of the YUV image (or subregion)
  199. *
  200. * @param subsamp the level of chrominance subsampling used in the YUV
  201. * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
  202. */
  203. public void setBuf(byte[][] planes, int[] offsets, int width, int strides[],
  204. int height, int subsamp) {
  205. setBuf(planes, offsets, width, strides, height, subsamp, false);
  206. }
  207. private void setBuf(byte[][] planes, int[] offsets, int width, int strides[],
  208. int height, int subsamp, boolean alloc) {
  209. if ((planes == null && !alloc) || width < 1 || height < 1 || subsamp < 0 ||
  210. subsamp >= TJ.NUMSAMP)
  211. throw new IllegalArgumentException("Invalid argument in YUVImage::setBuf()");
  212. int nc = (subsamp == TJ.SAMP_GRAY ? 1 : 3);
  213. if (planes.length != nc || (offsets != null && offsets.length != nc) ||
  214. (strides != null && strides.length != nc))
  215. throw new IllegalArgumentException("YUVImage::setBuf(): planes, offsets, or strides array is the wrong size");
  216. if (offsets == null)
  217. offsets = new int[nc];
  218. if (strides == null)
  219. strides = new int[nc];
  220. for (int i = 0; i < nc; i++) {
  221. int pw = TJ.planeWidth(i, width, subsamp);
  222. int ph = TJ.planeHeight(i, height, subsamp);
  223. int planeSize = TJ.planeSizeYUV(i, width, strides[i], height, subsamp);
  224. if (strides[i] == 0)
  225. strides[i] = pw;
  226. if (alloc) {
  227. if (strides[i] < pw)
  228. throw new IllegalArgumentException("Stride must be >= plane width when allocating a new YUV image");
  229. planes[i] = new byte[strides[i] * ph];
  230. }
  231. if (planes[i] == null || offsets[i] < 0)
  232. throw new IllegalArgumentException("Invalid argument in YUVImage::setBuf()");
  233. if (strides[i] < 0 && offsets[i] - planeSize + pw < 0)
  234. throw new IllegalArgumentException("Stride for plane " + i + " would cause memory to be accessed below plane boundary");
  235. if (planes[i].length < offsets[i] + planeSize)
  236. throw new IllegalArgumentException("Image plane " + i + " is not large enough");
  237. }
  238. yuvPlanes = planes;
  239. yuvOffsets = offsets;
  240. yuvWidth = width;
  241. yuvStrides = strides;
  242. yuvHeight = height;
  243. yuvSubsamp = subsamp;
  244. }
  245. /**
  246. * Assign a unified image buffer to this <code>YUVImage</code> instance.
  247. *
  248. * @param yuvImage image buffer that contains or will contain YUV planar
  249. * image data. Use {@link TJ#bufSizeYUV} to determine the minimum size for
  250. * this buffer. The Y, U (Cb), and V (Cr) image planes are stored
  251. * sequentially in the buffer (see {@link YUVImage above} for a description
  252. * of the image format.)
  253. *
  254. * @param width width (in pixels) of the YUV image
  255. *
  256. * @param pad the line padding used in the YUV image buffer. For
  257. * instance, if each line in each plane of the buffer is padded to the
  258. * nearest multiple of 4 bytes, then <code>pad</code> should be set to 4.
  259. *
  260. * @param height height (in pixels) of the YUV image
  261. *
  262. * @param subsamp the level of chrominance subsampling used in the YUV
  263. * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
  264. */
  265. public void setBuf(byte[] yuvImage, int width, int pad, int height,
  266. int subsamp) {
  267. if (yuvImage == null || width < 1 || pad < 1 || ((pad & (pad - 1)) != 0) ||
  268. height < 1 || subsamp < 0 || subsamp >= TJ.NUMSAMP)
  269. throw new IllegalArgumentException("Invalid argument in YUVImage::setBuf()");
  270. if (yuvImage.length < TJ.bufSizeYUV(width, pad, height, subsamp))
  271. throw new IllegalArgumentException("YUV image buffer is not large enough");
  272. int nc = (subsamp == TJ.SAMP_GRAY ? 1 : 3);
  273. byte[][] planes = new byte[nc][];
  274. int[] strides = new int[nc];
  275. int[] offsets = new int[nc];
  276. planes[0] = yuvImage;
  277. strides[0] = PAD(TJ.planeWidth(0, width, subsamp), pad);
  278. if (subsamp != TJ.SAMP_GRAY) {
  279. strides[1] = strides[2] = PAD(TJ.planeWidth(1, width, subsamp), pad);
  280. planes[1] = planes[2] = yuvImage;
  281. offsets[1] = offsets[0] +
  282. strides[0] * TJ.planeHeight(0, height, subsamp);
  283. offsets[2] = offsets[1] +
  284. strides[1] * TJ.planeHeight(1, height, subsamp);
  285. }
  286. yuvPad = pad;
  287. setBuf(planes, offsets, width, strides, height, subsamp);
  288. }
  289. /**
  290. * Returns the width of the YUV image (or subregion.)
  291. *
  292. * @return the width of the YUV image (or subregion)
  293. */
  294. public int getWidth() {
  295. if (yuvWidth < 1)
  296. throw new IllegalStateException(NO_ASSOC_ERROR);
  297. return yuvWidth;
  298. }
  299. /**
  300. * Returns the height of the YUV image (or subregion.)
  301. *
  302. * @return the height of the YUV image (or subregion)
  303. */
  304. public int getHeight() {
  305. if (yuvHeight < 1)
  306. throw new IllegalStateException(NO_ASSOC_ERROR);
  307. return yuvHeight;
  308. }
  309. /**
  310. * Returns the line padding used in the YUV image buffer (if this image is
  311. * stored in a unified buffer rather than separate image planes.)
  312. *
  313. * @return the line padding used in the YUV image buffer
  314. */
  315. public int getPad() {
  316. if (yuvPlanes == null)
  317. throw new IllegalStateException(NO_ASSOC_ERROR);
  318. if (yuvPad < 1 || ((yuvPad & (yuvPad - 1)) != 0))
  319. throw new IllegalStateException("Image is not stored in a unified buffer");
  320. return yuvPad;
  321. }
  322. /**
  323. * Returns the number of bytes per line of each plane in the YUV image.
  324. *
  325. * @return the number of bytes per line of each plane in the YUV image
  326. */
  327. public int[] getStrides() {
  328. if (yuvStrides == null)
  329. throw new IllegalStateException(NO_ASSOC_ERROR);
  330. return yuvStrides;
  331. }
  332. /**
  333. * Returns the offsets (in bytes) of each plane within the planes of a larger
  334. * YUV image.
  335. *
  336. * @return the offsets (in bytes) of each plane within the planes of a larger
  337. * YUV image
  338. */
  339. public int[] getOffsets() {
  340. if (yuvOffsets == null)
  341. throw new IllegalStateException(NO_ASSOC_ERROR);
  342. return yuvOffsets;
  343. }
  344. /**
  345. * Returns the level of chrominance subsampling used in the YUV image. See
  346. * {@link TJ#SAMP_444 TJ.SAMP_*}.
  347. *
  348. * @return the level of chrominance subsampling used in the YUV image
  349. */
  350. public int getSubsamp() {
  351. if (yuvSubsamp < 0 || yuvSubsamp >= TJ.NUMSAMP)
  352. throw new IllegalStateException(NO_ASSOC_ERROR);
  353. return yuvSubsamp;
  354. }
  355. /**
  356. * Returns the YUV image planes. If the image is stored in a unified buffer,
  357. * then all image planes will point to that buffer.
  358. *
  359. * @return the YUV image planes
  360. */
  361. public byte[][] getPlanes() {
  362. if (yuvPlanes == null)
  363. throw new IllegalStateException(NO_ASSOC_ERROR);
  364. return yuvPlanes;
  365. }
  366. /**
  367. * Returns the YUV image buffer (if this image is stored in a unified
  368. * buffer rather than separate image planes.)
  369. *
  370. * @return the YUV image buffer
  371. */
  372. public byte[] getBuf() {
  373. if (yuvPlanes == null || yuvSubsamp < 0 || yuvSubsamp >= TJ.NUMSAMP)
  374. throw new IllegalStateException(NO_ASSOC_ERROR);
  375. int nc = (yuvSubsamp == TJ.SAMP_GRAY ? 1 : 3);
  376. for (int i = 1; i < nc; i++) {
  377. if (yuvPlanes[i] != yuvPlanes[0])
  378. throw new IllegalStateException("Image is not stored in a unified buffer");
  379. }
  380. return yuvPlanes[0];
  381. }
  382. /**
  383. * Returns the size (in bytes) of the YUV image buffer (if this image is
  384. * stored in a unified buffer rather than separate image planes.)
  385. *
  386. * @return the size (in bytes) of the YUV image buffer
  387. */
  388. public int getSize() {
  389. if (yuvPlanes == null || yuvSubsamp < 0 || yuvSubsamp >= TJ.NUMSAMP)
  390. throw new IllegalStateException(NO_ASSOC_ERROR);
  391. int nc = (yuvSubsamp == TJ.SAMP_GRAY ? 1 : 3);
  392. if (yuvPad < 1)
  393. throw new IllegalStateException("Image is not stored in a unified buffer");
  394. for (int i = 1; i < nc; i++) {
  395. if (yuvPlanes[i] != yuvPlanes[0])
  396. throw new IllegalStateException("Image is not stored in a unified buffer");
  397. }
  398. return TJ.bufSizeYUV(yuvWidth, yuvPad, yuvHeight, yuvSubsamp);
  399. }
  400. private static final int PAD(int v, int p) {
  401. return (v + p - 1) & (~(p - 1));
  402. }
  403. protected long handle = 0;
  404. protected byte[][] yuvPlanes = null;
  405. protected int[] yuvOffsets = null;
  406. protected int[] yuvStrides = null;
  407. protected int yuvPad = 0;
  408. protected int yuvWidth = 0;
  409. protected int yuvHeight = 0;
  410. protected int yuvSubsamp = -1;
  411. }