1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package com.android.camera.util; 17 18import android.graphics.ImageFormat; 19import android.media.Image; 20import android.media.Image.Plane; 21 22import java.nio.ByteBuffer; 23 24/** 25 * Provides direct access to libjpeg-turbo via the NDK. 26 */ 27public class JpegUtilNative { 28 static { 29 System.loadLibrary("jni_jpegutil"); 30 } 31 32 public static final int ERROR_OUT_BUF_TOO_SMALL = -1; 33 34 /** 35 * Compresses an image from YUV422 format to jpeg. 36 * 37 * @param yBuf the buffer containing the Y component of the image 38 * @param yPStride the stride between adjacent pixels in the same row in yBuf 39 * @param yRStride the stride between adjacent rows in yBuf 40 * @param cbBuf the buffer containing the Cb component of the image 41 * @param cbPStride the stride between adjacent pixels in the same row in cbBuf 42 * @param cbRStride the stride between adjacent rows in cbBuf 43 * @param crBuf the buffer containing the Cr component of the image 44 * @param crPStride the stride between adjacent pixels in the same row in crBuf 45 * @param crRStride the stride between adjacent rows in crBuf 46 * @param quality the quality level (0 to 100) to use 47 * @return The number of bytes written, or a negative value indicating an error 48 */ 49 private static native int compressJpegFromYUV420pNative( 50 int width, int height, 51 Object yBuf, int yPStride, int yRStride, 52 Object cbBuf, int cbPStride, int cbRStride, 53 Object crBuf, int crPStride, int crRStride, 54 Object outBuf, int outBufCapacity, int quality); 55 56 /** 57 * @see JpegUtilNative#compressJpegFromYUV420pNative(int, int, java.lang.Object, int, int, 58 * java.lang.Object, int, int, java.lang.Object, int, int, java.lang.Object, int, int) 59 */ 60 public static int compressJpegFromYUV420p( 61 int width, int height, 62 ByteBuffer yBuf, int yPStride, int yRStride, 63 ByteBuffer cbBuf, int cbPStride, int cbRStride, 64 ByteBuffer crBuf, int crPStride, int crRStride, 65 ByteBuffer outBuf, int quality) { 66 return compressJpegFromYUV420pNative(width, height, yBuf, yPStride, yRStride, cbBuf, 67 cbPStride, cbRStride, crBuf, crPStride, crRStride, outBuf, outBuf.capacity(), quality); 68 } 69 70 /** 71 * Compresses the given image to jpeg. Note that only ImageFormat.YUV_420_888 is currently 72 * supported. Furthermore, all planes must use direct byte buffers. 73 * 74 * @param img the image to compress 75 * @param outBuf a direct byte buffer to hold the output jpeg. 76 * @return The number of bytes written to outBuf 77 */ 78 public static int compressJpegFromYUV420Image(Image img, ByteBuffer outBuf, int quality) { 79 if (img.getFormat() != ImageFormat.YUV_420_888) { 80 throw new RuntimeException("Unsupported Image Format."); 81 } 82 83 final int NUM_PLANES = 3; 84 85 if (img.getPlanes().length != NUM_PLANES) { 86 throw new RuntimeException("Output buffer must be direct."); 87 } 88 89 if (!outBuf.isDirect()) { 90 throw new RuntimeException("Output buffer must be direct."); 91 } 92 93 ByteBuffer[] planeBuf = new ByteBuffer[NUM_PLANES]; 94 int[] pixelStride = new int[NUM_PLANES]; 95 int[] rowStride = new int[NUM_PLANES]; 96 97 for (int i = 0; i < NUM_PLANES; i++) { 98 Plane plane = img.getPlanes()[i]; 99 100 if (!plane.getBuffer().isDirect()) { 101 return -1; 102 } 103 104 planeBuf[i] = plane.getBuffer(); 105 pixelStride[i] = plane.getPixelStride(); 106 rowStride[i] = plane.getRowStride(); 107 } 108 109 outBuf.clear(); 110 111 int numBytesWritten = compressJpegFromYUV420p( 112 img.getWidth(), img.getHeight(), 113 planeBuf[0], pixelStride[0], rowStride[0], 114 planeBuf[1], pixelStride[1], rowStride[1], 115 planeBuf[2], pixelStride[2], rowStride[2], 116 outBuf, quality); 117 118 outBuf.limit(numBytesWritten); 119 120 return numBytesWritten; 121 } 122} 123