Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(23)

Side by Side Diff: src/images/SkJPEGImageEncoder.cpp

Issue 1886183002: Use libjpeg-turbo for YUV->RGB conversion in jpeg encoder (Closed) Base URL: https://skia.googlesource.com/skia.git@encodebench
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2007 The Android Open Source Project 2 * Copyright 2016 Google Inc.
scroggo 2016/04/18 20:04:09 We generally leave copyright notices unchanged aft
msarett 2016/04/18 21:12:13 Done.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 8
9 #include "SkImageEncoder.h" 9 #include "SkImageEncoder.h"
10 #include "SkColorPriv.h" 10 #include "SkColorPriv.h"
11 #include "SkDither.h" 11 #include "SkDither.h"
12 #include "SkStream.h" 12 #include "SkStream.h"
13 #include "SkTemplates.h" 13 #include "SkTemplates.h"
14 #include "SkTime.h"
15 #include "SkUtils.h" 14 #include "SkUtils.h"
16 #include "SkRTConf.h" 15 #include "SkRTConf.h"
17 #include "SkRect.h" 16 #include "SkRect.h"
18 #include "SkCanvas.h" 17 #include "SkCanvas.h"
19 18
20
21 #include <stdio.h> 19 #include <stdio.h>
22 #include "SkJPEGWriteUtility.h" 20 #include "SkJPEGWriteUtility.h"
23 extern "C" { 21 extern "C" {
24 #include "jpeglib.h" 22 #include "jpeglib.h"
25 #include "jerror.h" 23 #include "jerror.h"
26 } 24 }
27 25
28 // These enable timing code that report milliseconds for an encoding
29 //#define TIME_ENCODE
30
31 // this enables our rgb->yuv code, which is faster than libjpeg on ARM
32 #define WE_CONVERT_TO_YUV
33
34 ///////////////////////////////////////////////////////////////////////////////
35
36 #include "SkColorPriv.h"
37
38 // taken from jcolor.c in libjpeg
39 #if 0 // 16bit - precise but slow
40 #define CYR 19595 // 0.299
41 #define CYG 38470 // 0.587
42 #define CYB 7471 // 0.114
43
44 #define CUR -11059 // -0.16874
45 #define CUG -21709 // -0.33126
46 #define CUB 32768 // 0.5
47
48 #define CVR 32768 // 0.5
49 #define CVG -27439 // -0.41869
50 #define CVB -5329 // -0.08131
51
52 #define CSHIFT 16
53 #else // 8bit - fast, slightly less precise
54 #define CYR 77 // 0.299
55 #define CYG 150 // 0.587
56 #define CYB 29 // 0.114
57
58 #define CUR -43 // -0.16874
59 #define CUG -85 // -0.33126
60 #define CUB 128 // 0.5
61
62 #define CVR 128 // 0.5
63 #define CVG -107 // -0.41869
64 #define CVB -21 // -0.08131
65
66 #define CSHIFT 8
67 #endif
68
69 static void rgb2yuv_32(uint8_t dst[], SkPMColor c) {
70 int r = SkGetPackedR32(c);
71 int g = SkGetPackedG32(c);
72 int b = SkGetPackedB32(c);
73
74 int y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT;
75 int u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT;
76 int v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT;
77
78 dst[0] = SkToU8(y);
79 dst[1] = SkToU8(u + 128);
80 dst[2] = SkToU8(v + 128);
81 }
82
83 static void rgb2yuv_4444(uint8_t dst[], U16CPU c) {
84 int r = SkGetPackedR4444(c);
85 int g = SkGetPackedG4444(c);
86 int b = SkGetPackedB4444(c);
87
88 int y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4);
89 int u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4);
90 int v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4);
91
92 dst[0] = SkToU8(y);
93 dst[1] = SkToU8(u + 128);
94 dst[2] = SkToU8(v + 128);
95 }
96
97 static void rgb2yuv_16(uint8_t dst[], U16CPU c) {
98 int r = SkGetPackedR16(c);
99 int g = SkGetPackedG16(c);
100 int b = SkGetPackedB16(c);
101
102 int y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2);
103 int u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2);
104 int v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2);
105
106 dst[0] = SkToU8(y);
107 dst[1] = SkToU8(u + 128);
108 dst[2] = SkToU8(v + 128);
109 }
110
111 ///////////////////////////////////////////////////////////////////////////////
112
113 typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst, 26 typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst,
114 const void* SK_RESTRICT src, int width, 27 const void* SK_RESTRICT src, int width,
115 const SkPMColor* SK_RESTRICT ctable); 28 const SkPMColor* SK_RESTRICT ctable);
116 29
117 static void Write_32_YUV(uint8_t* SK_RESTRICT dst, 30 static void Write_32_RGB(uint8_t* SK_RESTRICT dst,
118 const void* SK_RESTRICT srcRow, int width, 31 const void* SK_RESTRICT srcRow, int width,
119 const SkPMColor*) { 32 const SkPMColor*) {
120 const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow; 33 const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow;
121 while (--width >= 0) { 34 while (--width >= 0) {
122 #ifdef WE_CONVERT_TO_YUV
123 rgb2yuv_32(dst, *src++);
124 #else
125 uint32_t c = *src++; 35 uint32_t c = *src++;
126 dst[0] = SkGetPackedR32(c); 36 dst[0] = SkGetPackedR32(c);
127 dst[1] = SkGetPackedG32(c); 37 dst[1] = SkGetPackedG32(c);
128 dst[2] = SkGetPackedB32(c); 38 dst[2] = SkGetPackedB32(c);
129 #endif
130 dst += 3; 39 dst += 3;
131 } 40 }
132 } 41 }
133 42
134 static void Write_4444_YUV(uint8_t* SK_RESTRICT dst, 43 static void Write_4444_RGB(uint8_t* SK_RESTRICT dst,
135 const void* SK_RESTRICT srcRow, int width, 44 const void* SK_RESTRICT srcRow, int width,
136 const SkPMColor*) { 45 const SkPMColor*) {
137 const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow; 46 const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow;
138 while (--width >= 0) { 47 while (--width >= 0) {
139 #ifdef WE_CONVERT_TO_YUV
140 rgb2yuv_4444(dst, *src++);
141 #else
142 SkPMColor16 c = *src++; 48 SkPMColor16 c = *src++;
143 dst[0] = SkPacked4444ToR32(c); 49 dst[0] = SkPacked4444ToR32(c);
144 dst[1] = SkPacked4444ToG32(c); 50 dst[1] = SkPacked4444ToG32(c);
145 dst[2] = SkPacked4444ToB32(c); 51 dst[2] = SkPacked4444ToB32(c);
146 #endif
147 dst += 3; 52 dst += 3;
148 } 53 }
149 } 54 }
150 55
151 static void Write_16_YUV(uint8_t* SK_RESTRICT dst, 56 static void Write_16_RGB(uint8_t* SK_RESTRICT dst,
152 const void* SK_RESTRICT srcRow, int width, 57 const void* SK_RESTRICT srcRow, int width,
153 const SkPMColor*) { 58 const SkPMColor*) {
154 const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow; 59 const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow;
155 while (--width >= 0) { 60 while (--width >= 0) {
156 #ifdef WE_CONVERT_TO_YUV
157 rgb2yuv_16(dst, *src++);
158 #else
159 uint16_t c = *src++; 61 uint16_t c = *src++;
160 dst[0] = SkPacked16ToR32(c); 62 dst[0] = SkPacked16ToR32(c);
161 dst[1] = SkPacked16ToG32(c); 63 dst[1] = SkPacked16ToG32(c);
162 dst[2] = SkPacked16ToB32(c); 64 dst[2] = SkPacked16ToB32(c);
163 #endif
164 dst += 3; 65 dst += 3;
165 } 66 }
166 } 67 }
167 68
168 static void Write_Index_YUV(uint8_t* SK_RESTRICT dst, 69 static void Write_Index_RGB(uint8_t* SK_RESTRICT dst,
169 const void* SK_RESTRICT srcRow, int width, 70 const void* SK_RESTRICT srcRow, int width,
170 const SkPMColor* SK_RESTRICT ctable) { 71 const SkPMColor* SK_RESTRICT ctable) {
171 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow; 72 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow;
172 while (--width >= 0) { 73 while (--width >= 0) {
173 #ifdef WE_CONVERT_TO_YUV
174 rgb2yuv_32(dst, ctable[*src++]);
175 #else
176 uint32_t c = ctable[*src++]; 74 uint32_t c = ctable[*src++];
177 dst[0] = SkGetPackedR32(c); 75 dst[0] = SkGetPackedR32(c);
178 dst[1] = SkGetPackedG32(c); 76 dst[1] = SkGetPackedG32(c);
179 dst[2] = SkGetPackedB32(c); 77 dst[2] = SkGetPackedB32(c);
180 #endif
181 dst += 3; 78 dst += 3;
182 } 79 }
183 } 80 }
184 81
185 static WriteScanline ChooseWriter(const SkBitmap& bm) { 82 static WriteScanline ChooseWriter(const SkBitmap& bm) {
186 switch (bm.colorType()) { 83 switch (bm.colorType()) {
187 case kN32_SkColorType: 84 case kN32_SkColorType:
188 return Write_32_YUV; 85 return Write_32_RGB;
189 case kRGB_565_SkColorType: 86 case kRGB_565_SkColorType:
190 return Write_16_YUV; 87 return Write_16_RGB;
191 case kARGB_4444_SkColorType: 88 case kARGB_4444_SkColorType:
192 return Write_4444_YUV; 89 return Write_4444_RGB;
193 case kIndex_8_SkColorType: 90 case kIndex_8_SkColorType:
194 return Write_Index_YUV; 91 return Write_Index_RGB;
195 default: 92 default:
196 return nullptr; 93 return nullptr;
197 } 94 }
198 } 95 }
199 96
200 class SkJPEGImageEncoder : public SkImageEncoder { 97 class SkJPEGImageEncoder : public SkImageEncoder {
201 protected: 98 protected:
202 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) { 99 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) {
203 #ifdef TIME_ENCODE
204 SkAutoTime atm("JPEG Encode");
scroggo 2016/04/18 20:04:09 This seems like an unrelated change. That change s
msarett 2016/04/18 21:12:13 Reverting Time related aspects of this change.
205 #endif
206
207 SkAutoLockPixels alp(bm); 100 SkAutoLockPixels alp(bm);
208 if (nullptr == bm.getPixels()) { 101 if (nullptr == bm.getPixels()) {
209 return false; 102 return false;
210 } 103 }
211 104
212 jpeg_compress_struct cinfo; 105 jpeg_compress_struct cinfo;
213 skjpeg_error_mgr sk_err; 106 skjpeg_error_mgr sk_err;
214 skjpeg_destination_mgr sk_wstream(stream); 107 skjpeg_destination_mgr sk_wstream(stream);
215 108
216 // allocate these before set call setjmp 109 // allocate these before set call setjmp
217 SkAutoTMalloc<uint8_t> oneRow; 110 SkAutoTMalloc<uint8_t> oneRow;
218 111
219 cinfo.err = jpeg_std_error(&sk_err); 112 cinfo.err = jpeg_std_error(&sk_err);
220 sk_err.error_exit = skjpeg_error_exit; 113 sk_err.error_exit = skjpeg_error_exit;
221 if (setjmp(sk_err.fJmpBuf)) { 114 if (setjmp(sk_err.fJmpBuf)) {
222 return false; 115 return false;
223 } 116 }
224 117
225 // Keep after setjmp or mark volatile. 118 // Keep after setjmp or mark volatile.
226 const WriteScanline writer = ChooseWriter(bm); 119 const WriteScanline writer = ChooseWriter(bm);
227 if (nullptr == writer) { 120 if (nullptr == writer) {
228 return false; 121 return false;
229 } 122 }
230 123
231 jpeg_create_compress(&cinfo); 124 jpeg_create_compress(&cinfo);
232 cinfo.dest = &sk_wstream; 125 cinfo.dest = &sk_wstream;
233 cinfo.image_width = bm.width(); 126 cinfo.image_width = bm.width();
234 cinfo.image_height = bm.height(); 127 cinfo.image_height = bm.height();
235 cinfo.input_components = 3; 128 cinfo.input_components = 3;
236 #ifdef WE_CONVERT_TO_YUV 129
237 cinfo.in_color_space = JCS_YCbCr; 130 // FIXME: Can we take advantage of additional libjpeg-turbo in_color_spa ces
scroggo 2016/04/18 20:04:09 nit: This took me a few tries to parse. I think it
msarett 2016/04/18 21:12:13 Done.
238 #else 131 // (Ex: RGBA) and skip the "swizzle to RGB" step.
239 cinfo.in_color_space = JCS_RGB; 132 cinfo.in_color_space = JCS_RGB;
240 #endif 133
134 // The gamma value is ignored by libjpeg-turbo.
241 cinfo.input_gamma = 1; 135 cinfo.input_gamma = 1;
242 136
243 jpeg_set_defaults(&cinfo); 137 jpeg_set_defaults(&cinfo);
138
139 // Tells libjpeg-turbo to compute optimal Huffman coding tables
140 // for the image. This improves compression at the cost of
141 // slower encode performance.
244 cinfo.optimize_coding = TRUE; 142 cinfo.optimize_coding = TRUE;
245 jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); 143 jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
246 #ifdef DCT_IFAST_SUPPORTED
247 cinfo.dct_method = JDCT_IFAST;
248 #endif
249 144
250 jpeg_start_compress(&cinfo, TRUE); 145 jpeg_start_compress(&cinfo, TRUE);
251 146
252 const int width = bm.width(); 147 const int width = bm.width();
253 uint8_t* oneRowP = oneRow.reset(width * 3); 148 uint8_t* oneRowP = oneRow.reset(width * 3);
254 149
255 const SkPMColor* colors = bm.getColorTable() ? bm.getColorTable()->readC olors() : nullptr; 150 const SkPMColor* colors = bm.getColorTable() ? bm.getColorTable()->readC olors() : nullptr;
256 const void* srcRow = bm.getPixels(); 151 const void* srcRow = bm.getPixels();
257 152
258 while (cinfo.next_scanline < cinfo.image_height) { 153 while (cinfo.next_scanline < cinfo.image_height) {
(...skipping 14 matching lines...) Expand all
273 168
274 /////////////////////////////////////////////////////////////////////////////// 169 ///////////////////////////////////////////////////////////////////////////////
275 DEFINE_ENCODER_CREATOR(JPEGImageEncoder); 170 DEFINE_ENCODER_CREATOR(JPEGImageEncoder);
276 /////////////////////////////////////////////////////////////////////////////// 171 ///////////////////////////////////////////////////////////////////////////////
277 172
278 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { 173 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) {
279 return (SkImageEncoder::kJPEG_Type == t) ? new SkJPEGImageEncoder : nullptr; 174 return (SkImageEncoder::kJPEG_Type == t) ? new SkJPEGImageEncoder : nullptr;
280 } 175 }
281 176
282 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); 177 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory);
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698