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

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: Add missing override 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
« no previous file with comments | « resources/dng_with_preview.dng ('k') | tests/CodexTest.cpp » ('j') | 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 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 is_asset_stream(const SkStream& stream) {
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 an asset stream.
194 SkASSERT(!is_asset_stream(*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 19 matching lines...) Expand all
280 } 283 }
281 284
282 SkAutoTDelete<SkStream> fStream; 285 SkAutoTDelete<SkStream> fStream;
283 bool fWholeStreamRead; 286 bool fWholeStreamRead;
284 287
285 SkDynamicMemoryWStream fStreamBuffer; 288 SkDynamicMemoryWStream fStreamBuffer;
286 289
287 const size_t kReadToEnd = 0; 290 const size_t kReadToEnd = 0;
288 }; 291 };
289 292
293 class SkRawAssetStream : public SkRawStream {
294 public:
295 // Will take the ownership of the stream.
296 explicit SkRawAssetStream(SkStream* stream)
297 : fStream(stream)
298 {
299 // Only use SkRawAssetStream when the stream is an asset stream.
300 SkASSERT(is_asset_stream(*stream));
301 }
302
303 ~SkRawAssetStream() override {}
304
305 uint64 getLength() override {
306 return fStream->getLength();
307 }
308
309
310 bool read(void* data, size_t offset, size_t length) override {
311 if (length == 0) {
312 return true;
313 }
314
315 size_t sum;
316 if (!safe_add_to_size_t(offset, length, &sum)) {
317 return false;
318 }
319
320 return fStream->seek(offset) && (fStream->read(data, length) == length);
321 }
322
323 SkMemoryStream* transferBuffer(size_t offset, size_t size) override {
324 if (fStream->getLength() < offset) {
325 return nullptr;
326 }
327
328 size_t sum;
329 if (!safe_add_to_size_t(offset, size, &sum)) {
330 return nullptr;
331 }
332
333 // This will allow read less than the requested "size", because the JPEG codec wants to
334 // handle also a partial JPEG file.
335 const size_t bytesToRead = SkTMin(sum, fStream->getLength()) - offset;
336 if (bytesToRead == 0) {
337 return nullptr;
338 }
339
340 if (fStream->getMemoryBase()) { // directly copy if getMemoryBase() is available.
341 SkAutoTUnref<SkData> data(SkData::NewWithCopy(
342 static_cast<const uint8_t*>(fStream->getMemoryBase()) + offset, bytesToRead));
343 fStream.free();
344 return new SkMemoryStream(data);
345 } else {
346 SkAutoTUnref<SkData> data(SkData::NewUninitialized(bytesToRead));
347 if (!fStream->seek(offset)) {
348 return nullptr;
349 }
350 const size_t bytesRead = fStream->read(data->writable_data(), bytesT oRead);
351 if (bytesRead < bytesToRead) {
352 data.reset(SkData::NewSubset(data.get(), 0, bytesRead));
353 }
354 return new SkMemoryStream(data);
355 }
356 }
357 private:
358 SkAutoTDelete<SkStream> fStream;
359 };
360
361 class SkPiexStream : public ::piex::StreamInterface {
362 public:
363 // Will NOT take the ownership of the stream.
364 explicit SkPiexStream(SkRawStream* stream) : fStream(stream) {}
365
366 ~SkPiexStream() override {}
367
368 ::piex::Error GetData(const size_t offset, const size_t length,
369 uint8* data) override {
370 return fStream->read(static_cast<void*>(data), offset, length) ?
371 ::piex::Error::kOk : ::piex::Error::kFail;
372 }
373
374 private:
375 SkRawStream* fStream;
376 };
377
290 class SkDngStream : public dng_stream { 378 class SkDngStream : public dng_stream {
291 public: 379 public:
292 SkDngStream(SkRawStream* rawStream) : fRawStream(rawStream) {} 380 // Will NOT take the ownership of the stream.
381 SkDngStream(SkRawStream* stream) : fStream(stream) {}
293 382
294 uint64 DoGetLength() override { return fRawStream->getLength(); } 383 ~SkDngStream() override {}
384
385 uint64 DoGetLength() override { return fStream->getLength(); }
295 386
296 void DoRead(void* data, uint32 count, uint64 offset) override { 387 void DoRead(void* data, uint32 count, uint64 offset) override {
297 fRawStream->read(data, count, offset); 388 size_t sum;
389 if (!safe_add_to_size_t(static_cast<uint64>(count), offset, &sum) ||
390 !fStream->read(data, static_cast<size_t>(offset), static_cast<size_t >(count))) {
391 ThrowReadFile();
392 }
298 } 393 }
299 394
300 private: 395 private:
301 SkRawStream* fRawStream; 396 SkRawStream* fStream;
302 }; 397 };
303 398
304 class SkDngImage { 399 class SkDngImage {
305 public: 400 public:
401 // Will take the ownership of the stream.
306 static SkDngImage* NewFromStream(SkRawStream* stream) { 402 static SkDngImage* NewFromStream(SkRawStream* stream) {
307 SkAutoTDelete<SkDngImage> dngImage(new SkDngImage(stream)); 403 SkAutoTDelete<SkDngImage> dngImage(new SkDngImage(stream));
308 if (!dngImage->readDng()) { 404 if (!dngImage->readDng()) {
309 return nullptr; 405 return nullptr;
310 } 406 }
311 407
312 SkASSERT(dngImage->fNegative); 408 SkASSERT(dngImage->fNegative);
313 return dngImage.release(); 409 return dngImage.release();
314 } 410 }
315 411
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
432 bool fIsScalable; 528 bool fIsScalable;
433 bool fIsXtransImage; 529 bool fIsXtransImage;
434 }; 530 };
435 531
436 /* 532 /*
437 * Tries to handle the image with PIEX. If PIEX returns kOk and finds the previe w image, create a 533 * Tries to handle the image with PIEX. If PIEX returns kOk and finds the previe w image, create a
438 * SkJpegCodec. If PIEX returns kFail, then the file is invalid, return nullptr. In other cases, 534 * SkJpegCodec. If PIEX returns kFail, then the file is invalid, return nullptr. In other cases,
439 * fallback to create SkRawCodec for DNG images. 535 * fallback to create SkRawCodec for DNG images.
440 */ 536 */
441 SkCodec* SkRawCodec::NewFromStream(SkStream* stream) { 537 SkCodec* SkRawCodec::NewFromStream(SkStream* stream) {
442 SkAutoTDelete<SkRawStream> rawStream(new SkRawStream(stream)); 538 SkAutoTDelete<SkRawStream> rawStream;
539 if (is_asset_stream(*stream)) {
540 rawStream.reset(new SkRawAssetStream(stream));
541 } else {
542 rawStream.reset(new SkRawBufferedStream(stream));
543 }
544
545 // Does not take the ownership of rawStream.
546 SkPiexStream piexStream(rawStream.get());
443 ::piex::PreviewImageData imageData; 547 ::piex::PreviewImageData imageData;
444 if (::piex::IsRaw(rawStream.get())) { 548 if (::piex::IsRaw(&piexStream)) {
445 ::piex::Error error = ::piex::GetPreviewImageData(rawStream.get(), &imag eData); 549 ::piex::Error error = ::piex::GetPreviewImageData(&piexStream, &imageDat a);
446 550
447 if (error == ::piex::Error::kOk && imageData.preview_length > 0) { 551 if (error == ::piex::Error::kOk && imageData.preview_length > 0) {
448 #if !defined(GOOGLE3) 552 #if !defined(GOOGLE3)
449 // transferBuffer() is destructive to the rawStream. Abandon the raw Stream after this 553 // transferBuffer() is destructive to the rawStream. Abandon the raw Stream after this
450 // function call. 554 // function call.
451 // FIXME: one may avoid the copy of memoryStream and use the buffere d rawStream. 555 // FIXME: one may avoid the copy of memoryStream and use the buffere d rawStream.
452 SkMemoryStream* memoryStream = 556 SkMemoryStream* memoryStream =
453 rawStream->transferBuffer(imageData.preview_offset, imageDat a.preview_length); 557 rawStream->transferBuffer(imageData.preview_offset, imageData.pr eview_length);
454 return memoryStream ? SkJpegCodec::NewFromStream(memoryStream) : nul lptr; 558 return memoryStream ? SkJpegCodec::NewFromStream(memoryStream) : nul lptr;
455 #else 559 #else
456 return nullptr; 560 return nullptr;
457 #endif 561 #endif
458 } else if (error == ::piex::Error::kFail) { 562 } else if (error == ::piex::Error::kFail) {
459 return nullptr; 563 return nullptr;
460 } 564 }
461 } 565 }
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') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698