• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
16 package com.android.camera.util;
17 
18 import android.graphics.ImageFormat;
19 import android.media.Image;
20 import android.media.Image.Plane;
21 
22 import java.nio.ByteBuffer;
23 
24 /**
25  * Provides direct access to libjpeg-turbo via the NDK.
26  */
27 public 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      */
compressJpegFromYUV420pNative( int width, int height, Object yBuf, int yPStride, int yRStride, Object cbBuf, int cbPStride, int cbRStride, Object crBuf, int crPStride, int crRStride, Object outBuf, int outBufCapacity, int quality)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      */
compressJpegFromYUV420p( int width, int height, ByteBuffer yBuf, int yPStride, int yRStride, ByteBuffer cbBuf, int cbPStride, int cbRStride, ByteBuffer crBuf, int crPStride, int crRStride, ByteBuffer outBuf, int quality)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      */
compressJpegFromYUV420Image(Image img, ByteBuffer outBuf, int quality)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