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