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

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: Response to comments 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 2007 The Android Open Source Project
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"
(...skipping 10 matching lines...) Expand all
21 #include <stdio.h> 21 #include <stdio.h>
22 #include "SkJPEGWriteUtility.h" 22 #include "SkJPEGWriteUtility.h"
23 extern "C" { 23 extern "C" {
24 #include "jpeglib.h" 24 #include "jpeglib.h"
25 #include "jerror.h" 25 #include "jerror.h"
26 } 26 }
27 27
28 // These enable timing code that report milliseconds for an encoding 28 // These enable timing code that report milliseconds for an encoding
29 //#define TIME_ENCODE 29 //#define TIME_ENCODE
30 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, 31 typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst,
114 const void* SK_RESTRICT src, int width, 32 const void* SK_RESTRICT src, int width,
115 const SkPMColor* SK_RESTRICT ctable); 33 const SkPMColor* SK_RESTRICT ctable);
116 34
117 static void Write_32_YUV(uint8_t* SK_RESTRICT dst, 35 static void Write_32_RGB(uint8_t* SK_RESTRICT dst,
118 const void* SK_RESTRICT srcRow, int width, 36 const void* SK_RESTRICT srcRow, int width,
119 const SkPMColor*) { 37 const SkPMColor*) {
120 const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow; 38 const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow;
121 while (--width >= 0) { 39 while (--width >= 0) {
122 #ifdef WE_CONVERT_TO_YUV
123 rgb2yuv_32(dst, *src++);
124 #else
125 uint32_t c = *src++; 40 uint32_t c = *src++;
126 dst[0] = SkGetPackedR32(c); 41 dst[0] = SkGetPackedR32(c);
127 dst[1] = SkGetPackedG32(c); 42 dst[1] = SkGetPackedG32(c);
128 dst[2] = SkGetPackedB32(c); 43 dst[2] = SkGetPackedB32(c);
129 #endif
130 dst += 3; 44 dst += 3;
131 } 45 }
132 } 46 }
133 47
134 static void Write_4444_YUV(uint8_t* SK_RESTRICT dst, 48 static void Write_4444_RGB(uint8_t* SK_RESTRICT dst,
135 const void* SK_RESTRICT srcRow, int width, 49 const void* SK_RESTRICT srcRow, int width,
136 const SkPMColor*) { 50 const SkPMColor*) {
137 const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow; 51 const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow;
138 while (--width >= 0) { 52 while (--width >= 0) {
139 #ifdef WE_CONVERT_TO_YUV
140 rgb2yuv_4444(dst, *src++);
141 #else
142 SkPMColor16 c = *src++; 53 SkPMColor16 c = *src++;
143 dst[0] = SkPacked4444ToR32(c); 54 dst[0] = SkPacked4444ToR32(c);
144 dst[1] = SkPacked4444ToG32(c); 55 dst[1] = SkPacked4444ToG32(c);
145 dst[2] = SkPacked4444ToB32(c); 56 dst[2] = SkPacked4444ToB32(c);
146 #endif
147 dst += 3; 57 dst += 3;
148 } 58 }
149 } 59 }
150 60
151 static void Write_16_YUV(uint8_t* SK_RESTRICT dst, 61 static void Write_16_RGB(uint8_t* SK_RESTRICT dst,
152 const void* SK_RESTRICT srcRow, int width, 62 const void* SK_RESTRICT srcRow, int width,
153 const SkPMColor*) { 63 const SkPMColor*) {
154 const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow; 64 const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow;
155 while (--width >= 0) { 65 while (--width >= 0) {
156 #ifdef WE_CONVERT_TO_YUV
157 rgb2yuv_16(dst, *src++);
158 #else
159 uint16_t c = *src++; 66 uint16_t c = *src++;
160 dst[0] = SkPacked16ToR32(c); 67 dst[0] = SkPacked16ToR32(c);
161 dst[1] = SkPacked16ToG32(c); 68 dst[1] = SkPacked16ToG32(c);
162 dst[2] = SkPacked16ToB32(c); 69 dst[2] = SkPacked16ToB32(c);
163 #endif
164 dst += 3; 70 dst += 3;
165 } 71 }
166 } 72 }
167 73
168 static void Write_Index_YUV(uint8_t* SK_RESTRICT dst, 74 static void Write_Index_RGB(uint8_t* SK_RESTRICT dst,
169 const void* SK_RESTRICT srcRow, int width, 75 const void* SK_RESTRICT srcRow, int width,
170 const SkPMColor* SK_RESTRICT ctable) { 76 const SkPMColor* SK_RESTRICT ctable) {
171 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow; 77 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow;
172 while (--width >= 0) { 78 while (--width >= 0) {
173 #ifdef WE_CONVERT_TO_YUV
174 rgb2yuv_32(dst, ctable[*src++]);
175 #else
176 uint32_t c = ctable[*src++]; 79 uint32_t c = ctable[*src++];
177 dst[0] = SkGetPackedR32(c); 80 dst[0] = SkGetPackedR32(c);
178 dst[1] = SkGetPackedG32(c); 81 dst[1] = SkGetPackedG32(c);
179 dst[2] = SkGetPackedB32(c); 82 dst[2] = SkGetPackedB32(c);
180 #endif
181 dst += 3; 83 dst += 3;
182 } 84 }
183 } 85 }
184 86
185 static WriteScanline ChooseWriter(const SkBitmap& bm) { 87 static WriteScanline ChooseWriter(const SkBitmap& bm) {
186 switch (bm.colorType()) { 88 switch (bm.colorType()) {
187 case kN32_SkColorType: 89 case kN32_SkColorType:
188 return Write_32_YUV; 90 return Write_32_RGB;
189 case kRGB_565_SkColorType: 91 case kRGB_565_SkColorType:
190 return Write_16_YUV; 92 return Write_16_RGB;
191 case kARGB_4444_SkColorType: 93 case kARGB_4444_SkColorType:
192 return Write_4444_YUV; 94 return Write_4444_RGB;
193 case kIndex_8_SkColorType: 95 case kIndex_8_SkColorType:
194 return Write_Index_YUV; 96 return Write_Index_RGB;
195 default: 97 default:
196 return nullptr; 98 return nullptr;
197 } 99 }
198 } 100 }
199 101
200 class SkJPEGImageEncoder : public SkImageEncoder { 102 class SkJPEGImageEncoder : public SkImageEncoder {
201 protected: 103 protected:
202 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) { 104 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) {
203 #ifdef TIME_ENCODE 105 #ifdef TIME_ENCODE
204 SkAutoTime atm("JPEG Encode"); 106 SkAutoTime atm("JPEG Encode");
(...skipping 21 matching lines...) Expand all
226 const WriteScanline writer = ChooseWriter(bm); 128 const WriteScanline writer = ChooseWriter(bm);
227 if (nullptr == writer) { 129 if (nullptr == writer) {
228 return false; 130 return false;
229 } 131 }
230 132
231 jpeg_create_compress(&cinfo); 133 jpeg_create_compress(&cinfo);
232 cinfo.dest = &sk_wstream; 134 cinfo.dest = &sk_wstream;
233 cinfo.image_width = bm.width(); 135 cinfo.image_width = bm.width();
234 cinfo.image_height = bm.height(); 136 cinfo.image_height = bm.height();
235 cinfo.input_components = 3; 137 cinfo.input_components = 3;
236 #ifdef WE_CONVERT_TO_YUV 138
237 cinfo.in_color_space = JCS_YCbCr; 139 // FIXME: Can we take advantage of other in_color_spaces in libjpeg-turb o?
238 #else
239 cinfo.in_color_space = JCS_RGB; 140 cinfo.in_color_space = JCS_RGB;
240 #endif 141
142 // The gamma value is ignored by libjpeg-turbo.
241 cinfo.input_gamma = 1; 143 cinfo.input_gamma = 1;
242 144
243 jpeg_set_defaults(&cinfo); 145 jpeg_set_defaults(&cinfo);
146
147 // Tells libjpeg-turbo to compute optimal Huffman coding tables
148 // for the image. This improves compression at the cost of
149 // slower encode performance.
244 cinfo.optimize_coding = TRUE; 150 cinfo.optimize_coding = TRUE;
245 jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); 151 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 152
250 jpeg_start_compress(&cinfo, TRUE); 153 jpeg_start_compress(&cinfo, TRUE);
251 154
252 const int width = bm.width(); 155 const int width = bm.width();
253 uint8_t* oneRowP = oneRow.reset(width * 3); 156 uint8_t* oneRowP = oneRow.reset(width * 3);
254 157
255 const SkPMColor* colors = bm.getColorTable() ? bm.getColorTable()->readC olors() : nullptr; 158 const SkPMColor* colors = bm.getColorTable() ? bm.getColorTable()->readC olors() : nullptr;
256 const void* srcRow = bm.getPixels(); 159 const void* srcRow = bm.getPixels();
257 160
258 while (cinfo.next_scanline < cinfo.image_height) { 161 while (cinfo.next_scanline < cinfo.image_height) {
(...skipping 14 matching lines...) Expand all
273 176
274 /////////////////////////////////////////////////////////////////////////////// 177 ///////////////////////////////////////////////////////////////////////////////
275 DEFINE_ENCODER_CREATOR(JPEGImageEncoder); 178 DEFINE_ENCODER_CREATOR(JPEGImageEncoder);
276 /////////////////////////////////////////////////////////////////////////////// 179 ///////////////////////////////////////////////////////////////////////////////
277 180
278 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { 181 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) {
279 return (SkImageEncoder::kJPEG_Type == t) ? new SkJPEGImageEncoder : nullptr; 182 return (SkImageEncoder::kJPEG_Type == t) ? new SkJPEGImageEncoder : nullptr;
280 } 183 }
281 184
282 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); 185 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