1967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall/* 2967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * Copyright (C) 2014 The Android Open Source Project 3967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * 4967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * Licensed under the Apache License, Version 2.0 (the "License"); 5967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * you may not use this file except in compliance with the License. 6967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * You may obtain a copy of the License at 7967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * 8967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * http://www.apache.org/licenses/LICENSE-2.0 9967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * 10967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * Unless required by applicable law or agreed to in writing, software 11967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * distributed under the License is distributed on an "AS IS" BASIS, 12967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * See the License for the specific language governing permissions and 14967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * limitations under the License. 15967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall */ 16967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lallpackage com.android.camera.util; 17967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 18967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lallimport android.graphics.ImageFormat; 19967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lallimport android.media.Image; 20967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lallimport android.media.Image.Plane; 21967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 22967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lallimport java.nio.ByteBuffer; 23967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 24967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall/** 25967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * Provides direct access to libjpeg-turbo via the NDK. 26967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall */ 27967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lallpublic class JpegUtilNative { 28967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall static { 29967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall System.loadLibrary("jni_jpegutil"); 30967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall } 31967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 32967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall public static final int ERROR_OUT_BUF_TOO_SMALL = -1; 33967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 34967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall /** 35967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * Compresses an image from YUV422 format to jpeg. 36967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * 37967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * @param yBuf the buffer containing the Y component of the image 38967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * @param yPStride the stride between adjacent pixels in the same row in yBuf 39967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * @param yRStride the stride between adjacent rows in yBuf 40967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * @param cbBuf the buffer containing the Cb component of the image 41967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * @param cbPStride the stride between adjacent pixels in the same row in cbBuf 42967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * @param cbRStride the stride between adjacent rows in cbBuf 43967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * @param crBuf the buffer containing the Cr component of the image 44967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * @param crPStride the stride between adjacent pixels in the same row in crBuf 45967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * @param crRStride the stride between adjacent rows in crBuf 46967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * @param quality the quality level (0 to 100) to use 47967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * @return The number of bytes written, or a negative value indicating an error 48967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall */ 49967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall private static native int compressJpegFromYUV420pNative( 50967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall int width, int height, 51967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall Object yBuf, int yPStride, int yRStride, 52967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall Object cbBuf, int cbPStride, int cbRStride, 53967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall Object crBuf, int crPStride, int crRStride, 54967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall Object outBuf, int outBufCapacity, int quality); 55967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 56967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall /** 57967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * @see JpegUtilNative#compressJpegFromYUV420pNative(int, int, java.lang.Object, int, int, 58967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * java.lang.Object, int, int, java.lang.Object, int, int, java.lang.Object, int, int) 59967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall */ 60967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall public static int compressJpegFromYUV420p( 61967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall int width, int height, 62967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall ByteBuffer yBuf, int yPStride, int yRStride, 63967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall ByteBuffer cbBuf, int cbPStride, int cbRStride, 64967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall ByteBuffer crBuf, int crPStride, int crRStride, 65967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall ByteBuffer outBuf, int quality) { 66967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall return compressJpegFromYUV420pNative(width, height, yBuf, yPStride, yRStride, cbBuf, 67967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall cbPStride, cbRStride, crBuf, crPStride, crRStride, outBuf, outBuf.capacity(), quality); 68967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall } 69967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 70967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall /** 71967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * Compresses the given image to jpeg. Note that only ImageFormat.YUV_420_888 is currently 72967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * supported. Furthermore, all planes must use direct byte buffers. 73967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * 74967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * @param img the image to compress 75967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * @param outBuf a direct byte buffer to hold the output jpeg. 76967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * @return The number of bytes written to outBuf 77967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall */ 78967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall public static int compressJpegFromYUV420Image(Image img, ByteBuffer outBuf, int quality) { 79967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall if (img.getFormat() != ImageFormat.YUV_420_888) { 80967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall throw new RuntimeException("Unsupported Image Format."); 81967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall } 82967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 83967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall final int NUM_PLANES = 3; 84967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 85967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall if (img.getPlanes().length != NUM_PLANES) { 86967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall throw new RuntimeException("Output buffer must be direct."); 87967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall } 88967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 89967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall if (!outBuf.isDirect()) { 90967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall throw new RuntimeException("Output buffer must be direct."); 91967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall } 92967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 93967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall ByteBuffer[] planeBuf = new ByteBuffer[NUM_PLANES]; 94967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall int[] pixelStride = new int[NUM_PLANES]; 95967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall int[] rowStride = new int[NUM_PLANES]; 96967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 97967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall for (int i = 0; i < NUM_PLANES; i++) { 98967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall Plane plane = img.getPlanes()[i]; 99967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 100967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall if (!plane.getBuffer().isDirect()) { 101967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall return -1; 102967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall } 103967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 104967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall planeBuf[i] = plane.getBuffer(); 105967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall pixelStride[i] = plane.getPixelStride(); 106967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall rowStride[i] = plane.getRowStride(); 107967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall } 108967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 109967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall outBuf.clear(); 110967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 111967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall int numBytesWritten = compressJpegFromYUV420p( 112967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall img.getWidth(), img.getHeight(), 113967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall planeBuf[0], pixelStride[0], rowStride[0], 114967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall planeBuf[1], pixelStride[1], rowStride[1], 115967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall planeBuf[2], pixelStride[2], rowStride[2], 116967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall outBuf, quality); 117967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 118967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall outBuf.limit(numBytesWritten); 119967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 120967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall return numBytesWritten; 121967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall } 122967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall} 123