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
26bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenbool YuvToJpegEncoder::encode(SkWStream* stream, void* inYuv, int width,
27bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        int height, int* offsets, int jpegQuality) {
28bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    jpeg_compress_struct    cinfo;
29bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    skjpeg_error_mgr        sk_err;
30bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    skjpeg_destination_mgr  sk_wstream(stream);
31bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
32bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo.err = jpeg_std_error(&sk_err);
33bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    sk_err.error_exit = skjpeg_error_exit;
34bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    if (setjmp(sk_err.fJmpBuf)) {
35bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        return false;
36bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    }
37bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    jpeg_create_compress(&cinfo);
38bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
39bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo.dest = &sk_wstream;
40bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
41bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    setJpegCompressStruct(&cinfo, width, height, jpegQuality);
42bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
43bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    jpeg_start_compress(&cinfo, TRUE);
44bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
45bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    compress(&cinfo, (uint8_t*) inYuv, offsets);
46bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
47bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    jpeg_finish_compress(&cinfo);
48bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
49bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    return true;
50bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
51bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
52bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenvoid YuvToJpegEncoder::setJpegCompressStruct(jpeg_compress_struct* cinfo,
53bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        int width, int height, int quality) {
54bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->image_width = width;
55bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->image_height = height;
56bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->input_components = 3;
57bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->in_color_space = JCS_YCbCr;
58bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    jpeg_set_defaults(cinfo);
59aa86859b1035f865147b4f76ad2a9eed7ee098a5Chia-chi Yeh
60aa86859b1035f865147b4f76ad2a9eed7ee098a5Chia-chi Yeh    jpeg_set_quality(cinfo, quality, TRUE);
61bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    jpeg_set_colorspace(cinfo, JCS_YCbCr);
62bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->raw_data_in = TRUE;
63bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->dct_method = JDCT_IFAST;
64bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    configSamplingFactors(cinfo);
65bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
66bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
67bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen///////////////////////////////////////////////////////////////////
68bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta ChenYuv420SpToJpegEncoder::Yuv420SpToJpegEncoder(int* strides) :
69bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        YuvToJpegEncoder(strides) {
70bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    fNumPlanes = 2;
71bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
72bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
73bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenvoid Yuv420SpToJpegEncoder::compress(jpeg_compress_struct* cinfo,
74bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        uint8_t* yuv, int* offsets) {
75bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    SkDebugf("onFlyCompress");
76bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    JSAMPROW y[16];
77bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    JSAMPROW cb[8];
78bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    JSAMPROW cr[8];
79bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    JSAMPARRAY planes[3];
80bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    planes[0] = y;
81bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    planes[1] = cb;
82bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    planes[2] = cr;
83bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
84bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    int width = cinfo->image_width;
85bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    int height = cinfo->image_height;
86bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    uint8_t* yPlanar = yuv + offsets[0];
87bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    uint8_t* vuPlanar = yuv + offsets[1]; //width * height;
88bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    uint8_t* uRows = new uint8_t [8 * (width >> 1)];
89bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    uint8_t* vRows = new uint8_t [8 * (width >> 1)];
90bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
91bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
92bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    // process 16 lines of Y and 8 lines of U/V each time.
93bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    while (cinfo->next_scanline < cinfo->image_height) {
94bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        //deitnerleave u and v
954b63f14c96841d02b6bffce987f7705b6aa8e2a9Wu-cheng Li        deinterleave(vuPlanar, uRows, vRows, cinfo->next_scanline, width, height);
96bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
974b63f14c96841d02b6bffce987f7705b6aa8e2a9Wu-cheng Li        // Jpeg library ignores the rows whose indices are greater than height.
98bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        for (int i = 0; i < 16; i++) {
99bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            // y row
100bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            y[i] = yPlanar + (cinfo->next_scanline + i) * fStrides[0];
101bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
102bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            // construct u row and v row
103bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            if ((i & 1) == 0) {
104bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen                // height and width are both halved because of downsampling
105bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen                int offset = (i >> 1) * (width >> 1);
106bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen                cb[i/2] = uRows + offset;
107bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen                cr[i/2] = vRows + offset;
108bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            }
109bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen          }
110bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        jpeg_write_raw_data(cinfo, planes, 16);
111bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    }
112bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    delete [] uRows;
113bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    delete [] vRows;
114bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
115bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
116bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
117bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenvoid Yuv420SpToJpegEncoder::deinterleave(uint8_t* vuPlanar, uint8_t* uRows,
1184b63f14c96841d02b6bffce987f7705b6aa8e2a9Wu-cheng Li        uint8_t* vRows, int rowIndex, int width, int height) {
1194b63f14c96841d02b6bffce987f7705b6aa8e2a9Wu-cheng Li    int numRows = (height - rowIndex) / 2;
1204b63f14c96841d02b6bffce987f7705b6aa8e2a9Wu-cheng Li    if (numRows > 8) numRows = 8;
1214b63f14c96841d02b6bffce987f7705b6aa8e2a9Wu-cheng Li    for (int row = 0; row < numRows; ++row) {
122bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        int offset = ((rowIndex >> 1) + row) * fStrides[1];
123bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        uint8_t* vu = vuPlanar + offset;
124bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        for (int i = 0; i < (width >> 1); ++i) {
125bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            int index = row * (width >> 1) + i;
126bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            uRows[index] = vu[1];
127bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            vRows[index] = vu[0];
128bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            vu += 2;
129bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        }
130bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    }
131bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
132bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
133bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenvoid Yuv420SpToJpegEncoder::configSamplingFactors(jpeg_compress_struct* cinfo) {
134bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    // cb and cr are horizontally downsampled and vertically downsampled as well.
135bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[0].h_samp_factor = 2;
136bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[0].v_samp_factor = 2;
137bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[1].h_samp_factor = 1;
138bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[1].v_samp_factor = 1;
139bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[2].h_samp_factor = 1;
140bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[2].v_samp_factor = 1;
141bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
142bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
143bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen///////////////////////////////////////////////////////////////////////////////
144bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta ChenYuv422IToJpegEncoder::Yuv422IToJpegEncoder(int* strides) :
145bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        YuvToJpegEncoder(strides) {
146bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    fNumPlanes = 1;
147bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
148bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
149bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenvoid Yuv422IToJpegEncoder::compress(jpeg_compress_struct* cinfo,
150bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        uint8_t* yuv, int* offsets) {
151bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    SkDebugf("onFlyCompress_422");
152bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    JSAMPROW y[16];
153bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    JSAMPROW cb[16];
154bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    JSAMPROW cr[16];
155bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    JSAMPARRAY planes[3];
156bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    planes[0] = y;
157bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    planes[1] = cb;
158bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    planes[2] = cr;
159bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
160bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    int width = cinfo->image_width;
161bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    int height = cinfo->image_height;
162bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    uint8_t* yRows = new uint8_t [16 * width];
163bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    uint8_t* uRows = new uint8_t [16 * (width >> 1)];
164bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    uint8_t* vRows = new uint8_t [16 * (width >> 1)];
165bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
166bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    uint8_t* yuvOffset = yuv + offsets[0];
167bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
168bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    // process 16 lines of Y and 16 lines of U/V each time.
169bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    while (cinfo->next_scanline < cinfo->image_height) {
170bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        deinterleave(yuvOffset, yRows, uRows, vRows, cinfo->next_scanline, width, height);
171bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
1724b63f14c96841d02b6bffce987f7705b6aa8e2a9Wu-cheng Li        // Jpeg library ignores the rows whose indices are greater than height.
173bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        for (int i = 0; i < 16; i++) {
174bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            // y row
175bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            y[i] = yRows + i * width;
176bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
177bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            // construct u row and v row
178bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            // width is halved because of downsampling
179bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            int offset = i * (width >> 1);
180bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            cb[i] = uRows + offset;
181bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            cr[i] = vRows + offset;
182bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        }
183bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
184bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        jpeg_write_raw_data(cinfo, planes, 16);
185bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    }
186bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    delete [] yRows;
187bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    delete [] uRows;
188bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    delete [] vRows;
189bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
190bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
191bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
192bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenvoid Yuv422IToJpegEncoder::deinterleave(uint8_t* yuv, uint8_t* yRows, uint8_t* uRows,
193bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        uint8_t* vRows, int rowIndex, int width, int height) {
1944b63f14c96841d02b6bffce987f7705b6aa8e2a9Wu-cheng Li    int numRows = height - rowIndex;
1954b63f14c96841d02b6bffce987f7705b6aa8e2a9Wu-cheng Li    if (numRows > 16) numRows = 16;
1964b63f14c96841d02b6bffce987f7705b6aa8e2a9Wu-cheng Li    for (int row = 0; row < numRows; ++row) {
197bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        uint8_t* yuvSeg = yuv + (rowIndex + row) * fStrides[0];
198bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        for (int i = 0; i < (width >> 1); ++i) {
199bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            int indexY = row * width + (i << 1);
200bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            int indexU = row * (width >> 1) + i;
201bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            yRows[indexY] = yuvSeg[0];
202bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            yRows[indexY + 1] = yuvSeg[2];
203bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            uRows[indexU] = yuvSeg[1];
204bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            vRows[indexU] = yuvSeg[3];
205bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            yuvSeg += 4;
206bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        }
207bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    }
208bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
209bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
210bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenvoid Yuv422IToJpegEncoder::configSamplingFactors(jpeg_compress_struct* cinfo) {
211bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    // cb and cr are horizontally downsampled and vertically downsampled as well.
212bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[0].h_samp_factor = 2;
213bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[0].v_samp_factor = 2;
214bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[1].h_samp_factor = 1;
215bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[1].v_samp_factor = 2;
216bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[2].h_samp_factor = 1;
217bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    cinfo->comp_info[2].v_samp_factor = 2;
218bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
219bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen///////////////////////////////////////////////////////////////////////////////
220bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
221bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenstatic jboolean YuvImage_compressToJpeg(JNIEnv* env, jobject, jbyteArray inYuv,
22239029b29906fb064fc1e408983809b9b7ad74095Ashok Bhat        jint format, jint width, jint height, jintArray offsets,
22339029b29906fb064fc1e408983809b9b7ad74095Ashok Bhat        jintArray strides, jint jpegQuality, jobject jstream,
224bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        jbyteArray jstorage) {
225bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    jbyte* yuv = env->GetByteArrayElements(inYuv, NULL);
226bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
227bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
228bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    jint* imgOffsets = env->GetIntArrayElements(offsets, NULL);
229bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    jint* imgStrides = env->GetIntArrayElements(strides, NULL);
230bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    YuvToJpegEncoder* encoder = YuvToJpegEncoder::create(format, imgStrides);
2317c68a4076e1ef141db5ac338d675646a278f0eb8Pawel Augustyn    jboolean result = JNI_FALSE;
2327c68a4076e1ef141db5ac338d675646a278f0eb8Pawel Augustyn    if (encoder != NULL) {
2337c68a4076e1ef141db5ac338d675646a278f0eb8Pawel Augustyn        encoder->encode(strm, yuv, width, height, imgOffsets, jpegQuality);
2347c68a4076e1ef141db5ac338d675646a278f0eb8Pawel Augustyn        delete encoder;
2357c68a4076e1ef141db5ac338d675646a278f0eb8Pawel Augustyn        result = JNI_TRUE;
236bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    }
237bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
238bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    env->ReleaseByteArrayElements(inYuv, yuv, 0);
239bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    env->ReleaseIntArrayElements(offsets, imgOffsets, 0);
240bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    env->ReleaseIntArrayElements(strides, imgStrides, 0);
241d865900425d9593974aac640bc4deb93865dcfbeMartin Wallgren    delete strm;
2427c68a4076e1ef141db5ac338d675646a278f0eb8Pawel Augustyn    return result;
243bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
244bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen///////////////////////////////////////////////////////////////////////////////
245bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
24676f6a86de25e1bf74717e047e55fd44b089673f3Daniel Micaystatic const JNINativeMethod gYuvImageMethods[] = {
247bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    {   "nativeCompressToJpeg",  "([BIII[I[IILjava/io/OutputStream;[B)Z",
248bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        (void*)YuvImage_compressToJpeg }
249bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen};
250bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
251bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenint register_android_graphics_YuvImage(JNIEnv* env)
252bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen{
253ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    return android::RegisterMethodsOrDie(env, "android/graphics/YuvImage", gYuvImageMethods,
254ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe                                         NELEM(gYuvImageMethods));
255bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
256