1bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen#include "CreateJavaOutputStreamAdaptor.h"
279ad7bedcfaec8ccce22589eb62b342fd0de05afMatt Sarett#include "SkJPEGWriteUtility.h"
3bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen#include "YuvToJpegEncoder.h"
48f2423e8f394ae0666f1b61f83df4c0c7a4782d9Mathias Agopian#include <ui/PixelFormat.h>
58f2423e8f394ae0666f1b61f83df4c0c7a4782d9Mathias Agopian#include <hardware/hardware.h>
6bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
7ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe#include "core_jni_helpers.h"
8ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe
9bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen#include <jni.h>
10bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
11bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta ChenYuvToJpegEncoder* YuvToJpegEncoder::create(int format, int* strides) {
12a696f5d667227365da732481770767dcb330dd23Mathias Agopian    // Only ImageFormat.NV21 and ImageFormat.YUY2 are supported
13bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    // for now.
14a696f5d667227365da732481770767dcb330dd23Mathias Agopian    if (format == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
15bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        return new Yuv420SpToJpegEncoder(strides);
168f2423e8f394ae0666f1b61f83df4c0c7a4782d9Mathias Agopian    } else if (format == HAL_PIXEL_FORMAT_YCbCr_422_I) {
17bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        return new Yuv422IToJpegEncoder(strides);
18bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    } else {
19bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen      return NULL;
20bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    }
21bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
22bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
23bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta ChenYuvToJpegEncoder::YuvToJpegEncoder(int* strides) : fStrides(strides) {
24bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
25bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
261c3ded39f2ebd57286577a648d5a906752046386Leon Scroggins IIIstruct ErrorMgr {
271c3ded39f2ebd57286577a648d5a906752046386Leon Scroggins III    struct jpeg_error_mgr pub;
281c3ded39f2ebd57286577a648d5a906752046386Leon Scroggins III    jmp_buf jmp;
291c3ded39f2ebd57286577a648d5a906752046386Leon Scroggins III};
301c3ded39f2ebd57286577a648d5a906752046386Leon Scroggins III
311c3ded39f2ebd57286577a648d5a906752046386Leon Scroggins IIIvoid error_exit(j_common_ptr cinfo) {
321c3ded39f2ebd57286577a648d5a906752046386Leon Scroggins III    ErrorMgr* err = (ErrorMgr*) cinfo->err;
331c3ded39f2ebd57286577a648d5a906752046386Leon Scroggins III    (*cinfo->err->output_message) (cinfo);
341c3ded39f2ebd57286577a648d5a906752046386Leon Scroggins III    longjmp(err->jmp, 1);
351c3ded39f2ebd57286577a648d5a906752046386Leon Scroggins III}
361c3ded39f2ebd57286577a648d5a906752046386Leon Scroggins III
37bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenbool YuvToJpegEncoder::encode(SkWStream* stream, void* inYuv, int width,
38bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        int height, int* offsets, int jpegQuality) {
39bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    jpeg_compress_struct    cinfo;
401c3ded39f2ebd57286577a648d5a906752046386Leon Scroggins III    ErrorMgr                err;
41bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    skjpeg_destination_mgr  sk_wstream(stream);
42bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
431c3ded39f2ebd57286577a648d5a906752046386Leon Scroggins III    cinfo.err = jpeg_std_error(&err.pub);
441c3ded39f2ebd57286577a648d5a906752046386Leon Scroggins III    err.pub.error_exit = error_exit;
451c3ded39f2ebd57286577a648d5a906752046386Leon Scroggins III
461c3ded39f2ebd57286577a648d5a906752046386Leon Scroggins III    if (setjmp(err.jmp)) {
471c3ded39f2ebd57286577a648d5a906752046386Leon Scroggins III        jpeg_destroy_compress(&cinfo);
48bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        return false;
49bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    }
50bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    jpeg_create_compress(&cinfo);
51bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
52bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo.dest = &sk_wstream;
53bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
54bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    setJpegCompressStruct(&cinfo, width, height, jpegQuality);
55bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
56bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    jpeg_start_compress(&cinfo, TRUE);
57bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
58bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    compress(&cinfo, (uint8_t*) inYuv, offsets);
59bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
60bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    jpeg_finish_compress(&cinfo);
61bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
621c3ded39f2ebd57286577a648d5a906752046386Leon Scroggins III    jpeg_destroy_compress(&cinfo);
631c3ded39f2ebd57286577a648d5a906752046386Leon Scroggins III
64bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    return true;
65bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
66bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
67bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenvoid YuvToJpegEncoder::setJpegCompressStruct(jpeg_compress_struct* cinfo,
68bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        int width, int height, int quality) {
69bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->image_width = width;
70bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->image_height = height;
71bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->input_components = 3;
72bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->in_color_space = JCS_YCbCr;
73bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    jpeg_set_defaults(cinfo);
74aa86859b1035f865147b4f76ad2a9eed7ee098a5Chia-chi Yeh
75aa86859b1035f865147b4f76ad2a9eed7ee098a5Chia-chi Yeh    jpeg_set_quality(cinfo, quality, TRUE);
76bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    jpeg_set_colorspace(cinfo, JCS_YCbCr);
77bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->raw_data_in = TRUE;
78bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->dct_method = JDCT_IFAST;
79bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    configSamplingFactors(cinfo);
80bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
81bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
82bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen///////////////////////////////////////////////////////////////////
83bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta ChenYuv420SpToJpegEncoder::Yuv420SpToJpegEncoder(int* strides) :
84bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        YuvToJpegEncoder(strides) {
85bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    fNumPlanes = 2;
86bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
87bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
88bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenvoid Yuv420SpToJpegEncoder::compress(jpeg_compress_struct* cinfo,
89bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        uint8_t* yuv, int* offsets) {
90bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    SkDebugf("onFlyCompress");
91bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    JSAMPROW y[16];
92bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    JSAMPROW cb[8];
93bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    JSAMPROW cr[8];
94bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    JSAMPARRAY planes[3];
95bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    planes[0] = y;
96bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    planes[1] = cb;
97bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    planes[2] = cr;
98bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
99bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    int width = cinfo->image_width;
100bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    int height = cinfo->image_height;
101bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    uint8_t* yPlanar = yuv + offsets[0];
102bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    uint8_t* vuPlanar = yuv + offsets[1]; //width * height;
103bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    uint8_t* uRows = new uint8_t [8 * (width >> 1)];
104bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    uint8_t* vRows = new uint8_t [8 * (width >> 1)];
105bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
106bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
107bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    // process 16 lines of Y and 8 lines of U/V each time.
108bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    while (cinfo->next_scanline < cinfo->image_height) {
109bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        //deitnerleave u and v
1104b63f14c96841d02b6bffce987f7705b6aa8e2a9Wu-cheng Li        deinterleave(vuPlanar, uRows, vRows, cinfo->next_scanline, width, height);
111bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
1124b63f14c96841d02b6bffce987f7705b6aa8e2a9Wu-cheng Li        // Jpeg library ignores the rows whose indices are greater than height.
113bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        for (int i = 0; i < 16; i++) {
114bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            // y row
115bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            y[i] = yPlanar + (cinfo->next_scanline + i) * fStrides[0];
116bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
117bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            // construct u row and v row
118bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            if ((i & 1) == 0) {
119bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen                // height and width are both halved because of downsampling
120bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen                int offset = (i >> 1) * (width >> 1);
121bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen                cb[i/2] = uRows + offset;
122bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen                cr[i/2] = vRows + offset;
123bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            }
124bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen          }
125bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        jpeg_write_raw_data(cinfo, planes, 16);
126bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    }
127bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    delete [] uRows;
128bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    delete [] vRows;
129bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
130bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
131bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
132bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenvoid Yuv420SpToJpegEncoder::deinterleave(uint8_t* vuPlanar, uint8_t* uRows,
1334b63f14c96841d02b6bffce987f7705b6aa8e2a9Wu-cheng Li        uint8_t* vRows, int rowIndex, int width, int height) {
1344b63f14c96841d02b6bffce987f7705b6aa8e2a9Wu-cheng Li    int numRows = (height - rowIndex) / 2;
1354b63f14c96841d02b6bffce987f7705b6aa8e2a9Wu-cheng Li    if (numRows > 8) numRows = 8;
1364b63f14c96841d02b6bffce987f7705b6aa8e2a9Wu-cheng Li    for (int row = 0; row < numRows; ++row) {
137bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        int offset = ((rowIndex >> 1) + row) * fStrides[1];
138bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        uint8_t* vu = vuPlanar + offset;
139bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        for (int i = 0; i < (width >> 1); ++i) {
140bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            int index = row * (width >> 1) + i;
141bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            uRows[index] = vu[1];
142bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            vRows[index] = vu[0];
143bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            vu += 2;
144bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        }
145bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    }
146bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
147bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
148bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenvoid Yuv420SpToJpegEncoder::configSamplingFactors(jpeg_compress_struct* cinfo) {
149bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    // cb and cr are horizontally downsampled and vertically downsampled as well.
150bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[0].h_samp_factor = 2;
151bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[0].v_samp_factor = 2;
152bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[1].h_samp_factor = 1;
153bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[1].v_samp_factor = 1;
154bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[2].h_samp_factor = 1;
155bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[2].v_samp_factor = 1;
156bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
157bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
158bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen///////////////////////////////////////////////////////////////////////////////
159bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta ChenYuv422IToJpegEncoder::Yuv422IToJpegEncoder(int* strides) :
160bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        YuvToJpegEncoder(strides) {
161bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    fNumPlanes = 1;
162bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
163bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
164bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenvoid Yuv422IToJpegEncoder::compress(jpeg_compress_struct* cinfo,
165bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        uint8_t* yuv, int* offsets) {
166bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    SkDebugf("onFlyCompress_422");
167bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    JSAMPROW y[16];
168bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    JSAMPROW cb[16];
169bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    JSAMPROW cr[16];
170bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    JSAMPARRAY planes[3];
171bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    planes[0] = y;
172bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    planes[1] = cb;
173bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    planes[2] = cr;
174bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
175bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    int width = cinfo->image_width;
176bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    int height = cinfo->image_height;
177bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    uint8_t* yRows = new uint8_t [16 * width];
178bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    uint8_t* uRows = new uint8_t [16 * (width >> 1)];
179bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    uint8_t* vRows = new uint8_t [16 * (width >> 1)];
180bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
181bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    uint8_t* yuvOffset = yuv + offsets[0];
182bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
183bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    // process 16 lines of Y and 16 lines of U/V each time.
184bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    while (cinfo->next_scanline < cinfo->image_height) {
185bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        deinterleave(yuvOffset, yRows, uRows, vRows, cinfo->next_scanline, width, height);
186bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
1874b63f14c96841d02b6bffce987f7705b6aa8e2a9Wu-cheng Li        // Jpeg library ignores the rows whose indices are greater than height.
188bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        for (int i = 0; i < 16; i++) {
189bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            // y row
190bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            y[i] = yRows + i * width;
191bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
192bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            // construct u row and v row
193bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            // width is halved because of downsampling
194bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            int offset = i * (width >> 1);
195bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            cb[i] = uRows + offset;
196bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            cr[i] = vRows + offset;
197bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        }
198bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
199bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        jpeg_write_raw_data(cinfo, planes, 16);
200bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    }
201bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    delete [] yRows;
202bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    delete [] uRows;
203bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    delete [] vRows;
204bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
205bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
206bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
207bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenvoid Yuv422IToJpegEncoder::deinterleave(uint8_t* yuv, uint8_t* yRows, uint8_t* uRows,
208bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        uint8_t* vRows, int rowIndex, int width, int height) {
2094b63f14c96841d02b6bffce987f7705b6aa8e2a9Wu-cheng Li    int numRows = height - rowIndex;
2104b63f14c96841d02b6bffce987f7705b6aa8e2a9Wu-cheng Li    if (numRows > 16) numRows = 16;
2114b63f14c96841d02b6bffce987f7705b6aa8e2a9Wu-cheng Li    for (int row = 0; row < numRows; ++row) {
212bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        uint8_t* yuvSeg = yuv + (rowIndex + row) * fStrides[0];
213bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        for (int i = 0; i < (width >> 1); ++i) {
214bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            int indexY = row * width + (i << 1);
215bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            int indexU = row * (width >> 1) + i;
216bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            yRows[indexY] = yuvSeg[0];
217bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            yRows[indexY + 1] = yuvSeg[2];
218bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            uRows[indexU] = yuvSeg[1];
219bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            vRows[indexU] = yuvSeg[3];
220bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            yuvSeg += 4;
221bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        }
222bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    }
223bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
224bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
225bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenvoid Yuv422IToJpegEncoder::configSamplingFactors(jpeg_compress_struct* cinfo) {
226bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    // cb and cr are horizontally downsampled and vertically downsampled as well.
227bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[0].h_samp_factor = 2;
228bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[0].v_samp_factor = 2;
229bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[1].h_samp_factor = 1;
230bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[1].v_samp_factor = 2;
231bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[2].h_samp_factor = 1;
232bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[2].v_samp_factor = 2;
233bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
234bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen///////////////////////////////////////////////////////////////////////////////
235bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
236bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenstatic jboolean YuvImage_compressToJpeg(JNIEnv* env, jobject, jbyteArray inYuv,
23739029b29906fb064fc1e408983809b9b7ad74095Ashok Bhat        jint format, jint width, jint height, jintArray offsets,
23839029b29906fb064fc1e408983809b9b7ad74095Ashok Bhat        jintArray strides, jint jpegQuality, jobject jstream,
239bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        jbyteArray jstorage) {
240bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    jbyte* yuv = env->GetByteArrayElements(inYuv, NULL);
241bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
242bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
243bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    jint* imgOffsets = env->GetIntArrayElements(offsets, NULL);
244bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    jint* imgStrides = env->GetIntArrayElements(strides, NULL);
245bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    YuvToJpegEncoder* encoder = YuvToJpegEncoder::create(format, imgStrides);
2467c68a4076e1ef141db5ac338d675646a278f0eb8Pawel Augustyn    jboolean result = JNI_FALSE;
2477c68a4076e1ef141db5ac338d675646a278f0eb8Pawel Augustyn    if (encoder != NULL) {
2487c68a4076e1ef141db5ac338d675646a278f0eb8Pawel Augustyn        encoder->encode(strm, yuv, width, height, imgOffsets, jpegQuality);
2497c68a4076e1ef141db5ac338d675646a278f0eb8Pawel Augustyn        delete encoder;
2507c68a4076e1ef141db5ac338d675646a278f0eb8Pawel Augustyn        result = JNI_TRUE;
251bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    }
252bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
253bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    env->ReleaseByteArrayElements(inYuv, yuv, 0);
254bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    env->ReleaseIntArrayElements(offsets, imgOffsets, 0);
255bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    env->ReleaseIntArrayElements(strides, imgStrides, 0);
256d865900425d9593974aac640bc4deb93865dcfbeMartin Wallgren    delete strm;
2577c68a4076e1ef141db5ac338d675646a278f0eb8Pawel Augustyn    return result;
258bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
259bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen///////////////////////////////////////////////////////////////////////////////
260bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
26176f6a86de25e1bf74717e047e55fd44b089673f3Daniel Micaystatic const JNINativeMethod gYuvImageMethods[] = {
262bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    {   "nativeCompressToJpeg",  "([BIII[I[IILjava/io/OutputStream;[B)Z",
263bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        (void*)YuvImage_compressToJpeg }
264bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen};
265bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
266bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenint register_android_graphics_YuvImage(JNIEnv* env)
267bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen{
268ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    return android::RegisterMethodsOrDie(env, "android/graphics/YuvImage", gYuvImageMethods,
269ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe                                         NELEM(gYuvImageMethods));
270bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
271