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

Side by Side Diff: src/codec/SkRawCodec.cpp

Issue 1645963002: Optimize the SkRawStream when the input is an asset stream (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Address comments and add test Created 4 years, 10 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
OLDNEW
1 /* 1 /*
2 * Copyright 2016 Google Inc. 2 * Copyright 2016 Google Inc.
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 #include "SkCodec.h" 8 #include "SkCodec.h"
9 #include "SkCodecPriv.h" 9 #include "SkCodecPriv.h"
10 #include "SkColorPriv.h" 10 #include "SkColorPriv.h"
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
150 // To avoid arbitary allocation requests which might lead to out-of-memo ry, limit the 150 // To avoid arbitary allocation requests which might lead to out-of-memo ry, limit the
151 // amount of memory that can be allocated at once. The memory limit is b ased on experiments 151 // amount of memory that can be allocated at once. The memory limit is b ased on experiments
152 // and supposed to be sufficient for all valid DNG images. 152 // and supposed to be sufficient for all valid DNG images.
153 if (size > 300 * 1024 * 1024) { // 300 MB 153 if (size > 300 * 1024 * 1024) { // 300 MB
154 ThrowMemoryFull(); 154 ThrowMemoryFull();
155 } 155 }
156 return dng_memory_allocator::Allocate(size); 156 return dng_memory_allocator::Allocate(size);
157 } 157 }
158 }; 158 };
159 159
160 bool IsStreamSeekable(const SkStream& stream) {
scroggo 2016/02/04 15:46:24 In SkStream.h, we consider a stream "seekable" if
yujieqin 2016/02/05 08:53:21 Done.
161 return stream.hasLength() && stream.hasPosition();
162 }
163
160 } // namespace 164 } // namespace
161 165
162 // Note: this class could throw exception if it is used as dng_stream. 166 class SkRawStream {
163 class SkRawStream : public ::piex::StreamInterface {
164 public: 167 public:
165 // Note that this call will take the ownership of stream. 168 virtual ~SkRawStream() {}
166 explicit SkRawStream(SkStream* stream)
167 : fStream(stream), fWholeStreamRead(false) {}
168 169
169 ~SkRawStream() override {} 170 /*
171 * Gets the length of the stream. Depending on the type of stream, this may r equire reading to
172 * the end of the stream.
173 */
174 virtual uint64 getLength() = 0;
175
176 virtual bool read(void* data, size_t offset, size_t length) = 0;
170 177
171 /* 178 /*
172 * Creates an SkMemoryStream from the offset with size. 179 * Creates an SkMemoryStream from the offset with size.
173 * Note: for performance reason, this function is destructive to the SkRawSt ream. One should 180 * Note: for performance reason, this function is destructive to the SkRawSt ream. One should
174 * abandon current object after the function call. 181 * abandon current object after the function call.
175 */ 182 */
176 SkMemoryStream* transferBuffer(size_t offset, size_t size) { 183 virtual SkMemoryStream* transferBuffer(size_t offset, size_t size) = 0;
184 };
185
186 class SkRawBufferedStream : public SkRawStream {
187 public:
188 // Will take the ownership of the stream.
189 explicit SkRawBufferedStream(SkStream* stream)
190 : fStream(stream)
191 , fWholeStreamRead(false)
192 {
193 // Only use SkRawBufferedStream when the stream is not seekable.
194 SkASSERT(!IsStreamSeekable(*stream));
195 }
196
197 ~SkRawBufferedStream() override {}
198
199 uint64 getLength() override {
200 if (!this->bufferMoreData(kReadToEnd)) { // read whole stream
201 ThrowReadFile();
202 }
203 return fStreamBuffer.bytesWritten();
204 }
205
206 bool read(void* data, size_t offset, size_t length) override {
207 if (length == 0) {
208 return true;
209 }
210
211 size_t sum;
212 if (!safe_add_to_size_t(offset, length, &sum)) {
213 return false;
214 }
215
216 return this->bufferMoreData(sum) && fStreamBuffer.read(data, offset, len gth);
217 }
218
219 SkMemoryStream* transferBuffer(size_t offset, size_t size) override {
177 SkAutoTUnref<SkData> data(SkData::NewUninitialized(size)); 220 SkAutoTUnref<SkData> data(SkData::NewUninitialized(size));
178 if (offset > fStreamBuffer.bytesWritten()) { 221 if (offset > fStreamBuffer.bytesWritten()) {
179 // If the offset is not buffered, read from fStream directly and ski p the buffering. 222 // If the offset is not buffered, read from fStream directly and ski p the buffering.
180 const size_t skipLength = offset - fStreamBuffer.bytesWritten(); 223 const size_t skipLength = offset - fStreamBuffer.bytesWritten();
181 if (fStream->skip(skipLength) != skipLength) { 224 if (fStream->skip(skipLength) != skipLength) {
182 return nullptr; 225 return nullptr;
183 } 226 }
184 const size_t bytesRead = fStream->read(data->writable_data(), size); 227 const size_t bytesRead = fStream->read(data->writable_data(), size);
185 if (bytesRead < size) { 228 if (bytesRead < size) {
186 data.reset(SkData::NewSubset(data.get(), 0, bytesRead)); 229 data.reset(SkData::NewSubset(data.get(), 0, bytesRead));
(...skipping 14 matching lines...) Expand all
201 if (!safe_add_to_size_t(alreadyBuffered, bytesRead, &newSize )) { 244 if (!safe_add_to_size_t(alreadyBuffered, bytesRead, &newSize )) {
202 return nullptr; 245 return nullptr;
203 } 246 }
204 data.reset(SkData::NewSubset(data.get(), 0, newSize)); 247 data.reset(SkData::NewSubset(data.get(), 0, newSize));
205 } 248 }
206 } 249 }
207 } 250 }
208 return new SkMemoryStream(data); 251 return new SkMemoryStream(data);
209 } 252 }
210 253
211 // For PIEX
212 ::piex::Error GetData(const size_t offset, const size_t length,
213 uint8* data) override {
214 if (offset == 0 && length == 0) {
215 return ::piex::Error::kOk;
216 }
217 size_t sum;
218 if (!safe_add_to_size_t(offset, length, &sum) || !this->bufferMoreData(s um)) {
219 return ::piex::Error::kFail;
220 }
221 if (!fStreamBuffer.read(data, offset, length)) {
222 return ::piex::Error::kFail;
223 }
224 return ::piex::Error::kOk;
225 }
226
227 // For dng_stream
228 uint64 getLength() {
229 if (!this->bufferMoreData(kReadToEnd)) { // read whole stream
230 ThrowReadFile();
231 }
232 return fStreamBuffer.bytesWritten();
233 }
234
235 // For dng_stream
236 void read(void* data, uint32 count, uint64 offset) {
237 if (count == 0 && offset == 0) {
238 return;
239 }
240 size_t sum;
241 if (!safe_add_to_size_t(static_cast<uint64>(count), offset, &sum) ||
242 !this->bufferMoreData(sum)) {
243 ThrowReadFile();
244 }
245
246 if (!fStreamBuffer.read(data, static_cast<size_t>(offset), count)) {
247 ThrowReadFile();
248 }
249 }
250
251 private: 254 private:
252 // Note: if the newSize == kReadToEnd (0), this function will read to the en d of stream. 255 // Note: if the newSize == kReadToEnd (0), this function will read to the en d of stream.
253 bool bufferMoreData(size_t newSize) { 256 bool bufferMoreData(size_t newSize) {
254 if (newSize == kReadToEnd) { 257 if (newSize == kReadToEnd) {
255 if (fWholeStreamRead) { // already read-to-end. 258 if (fWholeStreamRead) { // already read-to-end.
256 return true; 259 return true;
257 } 260 }
258 261
259 // TODO: optimize for the special case when the input is SkMemoryStr eam. 262 // TODO: optimize for the special case when the input is SkMemoryStr eam.
260 return SkStreamCopy(&fStreamBuffer, fStream.get()); 263 return SkStreamCopy(&fStreamBuffer, fStream.get());
(...skipping 16 matching lines...) Expand all
277 } 280 }
278 281
279 SkAutoTDelete<SkStream> fStream; 282 SkAutoTDelete<SkStream> fStream;
280 bool fWholeStreamRead; 283 bool fWholeStreamRead;
281 284
282 SkDynamicMemoryWStream fStreamBuffer; 285 SkDynamicMemoryWStream fStreamBuffer;
283 286
284 const size_t kReadToEnd = 0; 287 const size_t kReadToEnd = 0;
285 }; 288 };
286 289
290 class SkRawSeekableStream : public SkRawStream {
291 public:
292 // Will take the ownership of the stream.
293 explicit SkRawSeekableStream(SkStream* stream)
294 : fStream(stream)
295 {
296 // Only use SkRawSeekableStream when the stream is seekable.
297 SkASSERT(IsStreamSeekable(*stream));
298 }
299
300 ~SkRawSeekableStream() override {}
301
302 uint64 getLength() {
303 return fStream->getLength();
304 }
305
306
307 bool read(void* data, size_t offset, size_t length) override {
308 if (length == 0) {
309 return true;
310 }
311
312 size_t sum;
313 if (!safe_add_to_size_t(offset, length, &sum)) {
314 return false;
315 }
316
317 return fStream->seek(offset) && (fStream->read(data, length) == length);
318 }
319
320 SkMemoryStream* transferBuffer(size_t offset, size_t size) {
321 if (fStream->getLength() < offset) {
322 return nullptr;
323 }
324
325 size_t sum;
326 if (!safe_add_to_size_t(offset, size, &sum)) {
327 return nullptr;
328 }
329
330 // This will allow read less than the requested "size", because the JPEG codec wants to
331 // handle also a partial JPEG file.
332 const size_t bytesToRead = SkTMin(sum, fStream->getLength()) - offset;
333 if (bytesToRead == 0) {
334 return nullptr;
335 }
336
337 if (fStream->getMemoryBase()) { // directly copy if getMemoryBase() is available.
338 SkAutoTUnref<SkData> data(SkData::NewWithCopy(
339 static_cast<const uint8_t*>(fStream->getMemoryBase()) + offset, bytesToRead));
340 fStream.free();
341 return new SkMemoryStream(data);
342 } else {
343 SkAutoTUnref<SkData> data(SkData::NewUninitialized(bytesToRead));
344 if (!fStream->seek(offset)) {
345 return nullptr;
346 }
347 if (bytesToRead != fStream->read(data->writable_data(), bytesToRead) ) {
scroggo 2016/02/04 15:46:24 This isn't the fix I intended. You changed the fir
yujieqin 2016/02/05 08:53:21 Done.
348 return nullptr;
349 }
350 return new SkMemoryStream(data);
351 }
352 }
353 private:
354 SkAutoTDelete<SkStream> fStream;
355 };
356
357 class SkPiexStream : public ::piex::StreamInterface {
358 public:
359 // Will NOT take the ownership of the stream.
360 explicit SkPiexStream(SkRawStream* stream) : fStream(stream) {}
361
362 ~SkPiexStream() override {}
363
364 ::piex::Error GetData(const size_t offset, const size_t length,
365 uint8* data) override {
366 return fStream->read(static_cast<void*>(data), offset, length) ?
367 ::piex::Error::kOk : ::piex::Error::kFail;
368 }
369
370 private:
371 SkRawStream* fStream;
372 };
373
287 class SkDngStream : public dng_stream { 374 class SkDngStream : public dng_stream {
288 public: 375 public:
289 SkDngStream(SkRawStream* rawStream) : fRawStream(rawStream) {} 376 // Will NOT take the ownership of the stream.
377 SkDngStream(SkRawStream* stream) : fStream(stream) {}
290 378
291 uint64 DoGetLength() override { return fRawStream->getLength(); } 379 ~SkDngStream() override {}
380
381 uint64 DoGetLength() override { return fStream->getLength(); }
292 382
293 void DoRead(void* data, uint32 count, uint64 offset) override { 383 void DoRead(void* data, uint32 count, uint64 offset) override {
294 fRawStream->read(data, count, offset); 384 size_t sum;
385 if (!safe_add_to_size_t(static_cast<uint64>(count), offset, &sum) ||
386 !fStream->read(data, static_cast<size_t>(offset), static_cast<size_t >(count))) {
387 ThrowReadFile();
388 }
295 } 389 }
296 390
297 private: 391 private:
298 SkRawStream* fRawStream; 392 SkRawStream* fStream;
299 }; 393 };
300 394
301 class SkDngImage { 395 class SkDngImage {
302 public: 396 public:
397 // Will take the ownership of the stream.
303 static SkDngImage* NewFromStream(SkRawStream* stream) { 398 static SkDngImage* NewFromStream(SkRawStream* stream) {
304 SkAutoTDelete<SkDngImage> dngImage(new SkDngImage(stream)); 399 SkAutoTDelete<SkDngImage> dngImage(new SkDngImage(stream));
305 if (!dngImage->readDng()) { 400 if (!dngImage->readDng()) {
306 return nullptr; 401 return nullptr;
307 } 402 }
308 403
309 SkASSERT(dngImage->fNegative); 404 SkASSERT(dngImage->fNegative);
310 return dngImage.release(); 405 return dngImage.release();
311 } 406 }
312 407
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
429 bool fIsScalable; 524 bool fIsScalable;
430 bool fIsXtransImage; 525 bool fIsXtransImage;
431 }; 526 };
432 527
433 /* 528 /*
434 * Tries to handle the image with PIEX. If PIEX returns kOk and finds the previe w image, create a 529 * Tries to handle the image with PIEX. If PIEX returns kOk and finds the previe w image, create a
435 * SkJpegCodec. If PIEX returns kFail, then the file is invalid, return nullptr. In other cases, 530 * SkJpegCodec. If PIEX returns kFail, then the file is invalid, return nullptr. In other cases,
436 * fallback to create SkRawCodec for DNG images. 531 * fallback to create SkRawCodec for DNG images.
437 */ 532 */
438 SkCodec* SkRawCodec::NewFromStream(SkStream* stream) { 533 SkCodec* SkRawCodec::NewFromStream(SkStream* stream) {
439 SkAutoTDelete<SkRawStream> rawStream(new SkRawStream(stream)); 534 SkAutoTDelete<SkRawStream> rawStream;
535 if (IsStreamSeekable(*stream)) {
536 rawStream.reset(new SkRawSeekableStream(stream));
537 } else {
538 rawStream.reset(new SkRawBufferedStream(stream));
539 }
540
541 // Does not take the ownership of rawStream.
542 SkAutoTDelete<SkPiexStream> piexStream(new SkPiexStream(rawStream.get()));
scroggo 2016/02/04 15:46:24 No need to auto delete this. You can just put it o
yujieqin 2016/02/05 08:53:21 Done.
440 ::piex::PreviewImageData imageData; 543 ::piex::PreviewImageData imageData;
441 // FIXME: ::piex::GetPreviewImageData() calls GetData() frequently with smal l amounts, 544 // FIXME: ::piex::GetPreviewImageData() calls GetData() frequently with smal l amounts,
442 // resulting in many calls to bufferMoreData(). Could we make this more effi cient by grouping 545 // resulting in many calls to bufferMoreData(). Could we make this more effi cient by grouping
443 // smaller requests together? 546 // smaller requests together?
444 if (::piex::IsRaw(rawStream.get())) { 547 if (::piex::IsRaw(piexStream.get())) {
445 ::piex::Error error = ::piex::GetPreviewImageData(rawStream.get(), &imag eData); 548 ::piex::Error error = ::piex::GetPreviewImageData(piexStream.get(), &ima geData);
446 549
447 if (error == ::piex::Error::kOk && imageData.preview_length > 0) { 550 if (error == ::piex::Error::kOk && imageData.preview_length > 0) {
448 #if !defined(GOOGLE3) 551 #if !defined(GOOGLE3)
449 // transferBuffer() is destructive to the rawStream. Abandon the raw Stream after this 552 // transferBuffer() is destructive to the rawStream. Abandon the raw Stream after this
450 // function call. 553 // function call.
451 // FIXME: one may avoid the copy of memoryStream and use the buffere d rawStream. 554 // FIXME: one may avoid the copy of memoryStream and use the buffere d rawStream.
452 SkMemoryStream* memoryStream = 555 SkMemoryStream* memoryStream =
453 rawStream->transferBuffer(imageData.preview_offset, imageDat a.preview_length); 556 rawStream->transferBuffer(imageData.preview_offset, imageData.pr eview_length);
454 return memoryStream ? SkJpegCodec::NewFromStream(memoryStream) : nul lptr; 557 return memoryStream ? SkJpegCodec::NewFromStream(memoryStream) : nul lptr;
455 #else 558 #else
456 return nullptr; 559 return nullptr;
457 #endif 560 #endif
458 } else if (error == ::piex::Error::kFail) { 561 } else if (error == ::piex::Error::kFail) {
459 return nullptr; 562 return nullptr;
460 } 563 }
461 } 564 }
565 piexStream.free();
462 566
567 // Takes the ownership of the rawStream.
463 SkAutoTDelete<SkDngImage> dngImage(SkDngImage::NewFromStream(rawStream.relea se())); 568 SkAutoTDelete<SkDngImage> dngImage(SkDngImage::NewFromStream(rawStream.relea se()));
464 if (!dngImage) { 569 if (!dngImage) {
465 return nullptr; 570 return nullptr;
466 } 571 }
467 572
468 return new SkRawCodec(dngImage.release()); 573 return new SkRawCodec(dngImage.release());
469 } 574 }
470 575
471 SkCodec::Result SkRawCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, 576 SkCodec::Result SkRawCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst,
472 size_t dstRowBytes, const Options& optio ns, 577 size_t dstRowBytes, const Options& optio ns,
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
559 SkISize sizeFloor = this->onGetScaledDimensions(1.f / std::floor(fullShortEd ge / shortEdge)); 664 SkISize sizeFloor = this->onGetScaledDimensions(1.f / std::floor(fullShortEd ge / shortEdge));
560 SkISize sizeCeil = this->onGetScaledDimensions(1.f / std::ceil(fullShortEdge / shortEdge)); 665 SkISize sizeCeil = this->onGetScaledDimensions(1.f / std::ceil(fullShortEdge / shortEdge));
561 return sizeFloor == dim || sizeCeil == dim; 666 return sizeFloor == dim || sizeCeil == dim;
562 } 667 }
563 668
564 SkRawCodec::~SkRawCodec() {} 669 SkRawCodec::~SkRawCodec() {}
565 670
566 SkRawCodec::SkRawCodec(SkDngImage* dngImage) 671 SkRawCodec::SkRawCodec(SkDngImage* dngImage)
567 : INHERITED(dngImage->getImageInfo(), nullptr) 672 : INHERITED(dngImage->getImageInfo(), nullptr)
568 , fDngImage(dngImage) {} 673 , fDngImage(dngImage) {}
OLDNEW
« no previous file with comments | « resources/dng_with_preview.dng ('k') | tests/CodexTest.cpp » ('j') | tests/CodexTest.cpp » ('J')

Powered by Google App Engine
This is Rietveld 408576698