2 * Copyright (C) 2014 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
32 void safeDelete(T& t) {
40 void safeDeleteArray(T& t) {
47 jpegutil::Plane::RowIterator::RowIterator(const Plane* plane) : plane_(plane) {
48 // We must be able to supply up to 8 * 2 lines at a time to libjpeg.
49 // 8 = vertical size of blocks transformed with DCT.
50 // 2 = scaling factor for Y vs UV planes.
53 // Rows must be padded to the next multiple of 16
54 // TODO OPTIMIZE Cb and Cr components only need to be padded to a multiple of
56 rowPadding_ = (16 - (plane_->planeWidth_ % 16)) % 16;
57 bufRowStride_ = plane_->planeWidth_ + rowPadding_;
59 // Round up to the nearest multiple of 64 for cache alignment
60 bufRowStride_ = (bufRowStride_ + 63) & ~63;
62 // Allocate an extra 64 bytes to allow for cache alignment
63 size_t bufSize = bufRowStride_ * bufRowCount_ + 64;
65 // TODO OPTIMIZE if the underlying data has a pixel-stride of 1, and an image
66 // width which is a multiple of 16, we can avoid this allocation and simply
67 // return pointers into the underlying data in operator()(int) instead of
69 buffer_ = unique_ptr<unsigned char[]>(new unsigned char[bufSize]);
71 // Find the start of the 64-byte aligned buffer we allocated.
72 size_t bufStart = reinterpret_cast<size_t>(&buffer_[0]);
73 size_t alignedBufStart = (bufStart + 63) & ~63;
74 alignedBuffer_ = reinterpret_cast<unsigned char*>(alignedBufStart);
79 unsigned char* jpegutil::Plane::RowIterator::operator()(int y) {
80 unsigned char* bufCurRowPtr = alignedBuffer_ + bufRowStride_ * bufCurRow_;
82 unsigned char* srcPtr = &plane_->data_[y * plane_->rowStride_];
83 unsigned char* dstPtr = bufCurRowPtr;
85 // Use memcpy when possible.
86 if (plane_->pixelStride_ == 1) {
87 memcpy(dstPtr, srcPtr, plane_->planeWidth_);
89 int pixelStride = plane_->pixelStride_;
91 for (int i = 0; i < plane_->planeWidth_; i++) {
94 srcPtr += pixelStride;
99 // Add padding to the right side by replicating the rightmost column of
100 // (actual) image values into the padding bytes.
101 memset(&bufCurRowPtr[plane_->planeWidth_],
102 bufCurRowPtr[plane_->planeWidth_ - 1], rowPadding_);
105 // Wrap within ring buffer.
106 bufCurRow_ %= bufRowCount_;
111 jpegutil::Plane::Plane(int imgWidth, int imgHeight, int planeWidth,
112 int planeHeight, unsigned char* data, int pixelStride,
114 : imgWidth_(imgWidth),
115 imgHeight_(imgHeight),
116 planeWidth_(planeWidth),
117 planeHeight_(planeHeight),
119 rowStride_(rowStride),
120 pixelStride_(pixelStride) {}
122 int jpegutil::compress(const Plane& yPlane, const Plane& cbPlane,
123 const Plane& crPlane, unsigned char* outBuf,
124 size_t outBufCapacity, std::function<void(size_t)> flush,
126 int imgWidth = yPlane.imgWidth();
127 int imgHeight = yPlane.imgHeight();
129 // libjpeg requires the use of setjmp/longjmp to recover from errors. Since
130 // this doesn't play well with RAII, we must use pointers and manually call
131 // delete. See POSIX documentation for longjmp() for details on why the
132 // volatile keyword is necessary.
133 volatile jpeg_compress_struct cinfov;
135 jpeg_compress_struct& cinfo =
136 *const_cast<struct jpeg_compress_struct*>(&cinfov);
138 JSAMPROW* volatile yArr = nullptr;
139 JSAMPROW* volatile cbArr = nullptr;
140 JSAMPROW* volatile crArr = nullptr;
142 Plane::RowIterator* volatile yRowGenerator = nullptr;
143 Plane::RowIterator* volatile cbRowGenerator = nullptr;
144 Plane::RowIterator* volatile crRowGenerator = nullptr;
146 JSAMPARRAY imgArr[3];
150 struct my_error_mgr {
151 struct jpeg_error_mgr pub;
152 jmp_buf setjmp_buffer;
155 cinfo.err = jpeg_std_error(&err.pub);
157 // Default error_exit will call exit(), so override
158 // to return control via setjmp/longjmp.
159 err.pub.error_exit = [](j_common_ptr cinfo) {
160 my_error_mgr* myerr = reinterpret_cast<my_error_mgr*>(cinfo->err);
162 (*cinfo->err->output_message)(cinfo);
164 // Return control to the setjmp point (see call to setjmp()).
165 longjmp(myerr->setjmp_buffer, 1);
168 cinfo.err = (struct jpeg_error_mgr*)&err;
170 // Set the setjmp point to return to in case of error.
171 if (setjmp(err.setjmp_buffer)) {
172 // If libjpeg hits an error, control will jump to this point (see call to
174 jpeg_destroy_compress(&cinfo);
176 safeDeleteArray(yArr);
177 safeDeleteArray(cbArr);
178 safeDeleteArray(crArr);
179 safeDelete(yRowGenerator);
180 safeDelete(cbRowGenerator);
181 safeDelete(crRowGenerator);
186 // Create jpeg compression context
187 jpeg_create_compress(&cinfo);
189 // Stores data needed by our c-style callbacks into libjpeg
191 unsigned char* outBuf;
192 size_t outBufCapacity;
193 std::function<void(size_t)> flush;
194 int totalOutputBytes;
195 } clientData{outBuf, outBufCapacity, flush, 0};
197 cinfo.client_data = &clientData;
199 // Initialize destination manager
200 jpeg_destination_mgr dest;
202 dest.init_destination = [](j_compress_ptr cinfo) {
203 ClientData& cdata = *reinterpret_cast<ClientData*>(cinfo->client_data);
205 cinfo->dest->next_output_byte = cdata.outBuf;
206 cinfo->dest->free_in_buffer = cdata.outBufCapacity;
209 dest.empty_output_buffer = [](j_compress_ptr cinfo) -> boolean {
210 ClientData& cdata = *reinterpret_cast<ClientData*>(cinfo->client_data);
212 size_t numBytesInBuffer = cdata.outBufCapacity;
213 cdata.flush(numBytesInBuffer);
214 cdata.totalOutputBytes += numBytesInBuffer;
217 cinfo->dest->next_output_byte = cdata.outBuf;
218 cinfo->dest->free_in_buffer = cdata.outBufCapacity;
223 dest.term_destination = [](j_compress_ptr cinfo) {
224 // do nothing to terminate the output buffer
229 // Set jpeg parameters
230 cinfo.image_width = imgWidth;
231 cinfo.image_height = imgHeight;
232 cinfo.input_components = 3;
234 // Set defaults based on the above values
235 jpeg_set_defaults(&cinfo);
237 jpeg_set_quality(&cinfo, quality, true);
239 cinfo.dct_method = JDCT_IFAST;
241 cinfo.raw_data_in = true;
243 jpeg_set_colorspace(&cinfo, JCS_YCbCr);
245 cinfo.comp_info[0].h_samp_factor = 2;
246 cinfo.comp_info[0].v_samp_factor = 2;
247 cinfo.comp_info[1].h_samp_factor = 1;
248 cinfo.comp_info[1].v_samp_factor = 1;
249 cinfo.comp_info[2].h_samp_factor = 1;
250 cinfo.comp_info[2].v_samp_factor = 1;
252 jpeg_start_compress(&cinfo, true);
254 yArr = new JSAMPROW[cinfo.comp_info[0].v_samp_factor * DCTSIZE];
255 cbArr = new JSAMPROW[cinfo.comp_info[1].v_samp_factor * DCTSIZE];
256 crArr = new JSAMPROW[cinfo.comp_info[2].v_samp_factor * DCTSIZE];
258 imgArr[0] = const_cast<JSAMPARRAY>(yArr);
259 imgArr[1] = const_cast<JSAMPARRAY>(cbArr);
260 imgArr[2] = const_cast<JSAMPARRAY>(crArr);
262 yRowGenerator = new Plane::RowIterator(&yPlane);
263 cbRowGenerator = new Plane::RowIterator(&cbPlane);
264 crRowGenerator = new Plane::RowIterator(&crPlane);
266 Plane::RowIterator& yRG = *const_cast<Plane::RowIterator*>(yRowGenerator);
267 Plane::RowIterator& cbRG = *const_cast<Plane::RowIterator*>(cbRowGenerator);
268 Plane::RowIterator& crRG = *const_cast<Plane::RowIterator*>(crRowGenerator);
270 for (int y = 0; y < imgHeight; y += DCTSIZE * 2) {
271 for (int row = 0; row < DCTSIZE * 2; row++) {
272 yArr[row] = yRG(y + row);
275 for (int row = 0; row < DCTSIZE; row++) {
276 // The y-index within the subsampled chroma planes to send to libjpeg.
277 const int chY = y / 2 + row;
279 if (chY < imgHeight / 2) {
280 cbArr[row] = cbRG(chY);
281 crArr[row] = crRG(chY);
283 // When we have run out of rows in the chroma planes to compress, send
284 // the last row as padding.
285 cbArr[row] = cbRG(imgHeight / 2 - 1);
286 crArr[row] = crRG(imgHeight / 2 - 1);
290 jpeg_write_raw_data(&cinfo, imgArr, DCTSIZE * 2);
293 jpeg_finish_compress(&cinfo);
295 int numBytesInBuffer = cinfo.dest->next_output_byte - outBuf;
297 flush(numBytesInBuffer);
299 clientData.totalOutputBytes += numBytesInBuffer;
301 safeDeleteArray(yArr);
302 safeDeleteArray(cbArr);
303 safeDeleteArray(crArr);
304 safeDelete(yRowGenerator);
305 safeDelete(cbRowGenerator);
306 safeDelete(crRowGenerator);
308 return clientData.totalOutputBytes;