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

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: Handle the case when getBaseMemory() == nullptr 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 | « 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 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 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 } // namespace 160 } // namespace
161 161
162 // Note: this class could throw exception if it is used as dng_stream. 162 class SkRawStream {
163 class SkRawStream : public ::piex::StreamInterface {
164 public: 163 public:
165 // Note that this call will take the ownership of stream. 164 virtual ~SkRawStream() {}
166 explicit SkRawStream(SkStream* stream)
167 : fStream(stream), fWholeStreamRead(false) {}
168 165
169 ~SkRawStream() override {} 166 /*
167 * Gets the length of the stream. Denpending on the type of stream, this may require read to the
scroggo 2016/02/02 19:23:06 depending* reading*
yujieqin 2016/02/04 14:50:32 Done.
168 * end of stream.
scroggo 2016/02/02 19:23:06 the* stream
yujieqin 2016/02/04 14:50:31 Done.
169 */
170 virtual uint64 getLength() = 0;
171
172 virtual bool read(size_t offset, size_t length, void* data) = 0;
scroggo 2016/02/02 19:23:06 nit: We typically put our output parameters first.
yujieqin 2016/02/04 14:50:31 Done.
170 173
171 /* 174 /*
172 * Creates an SkMemoryStream from the offset with size. 175 * Creates an SkMemoryStream from the offset with size.
173 * Note: for performance reason, this function is destructive to the SkRawSt ream. One should 176 * Note: for performance reason, this function is destructive to the SkRawSt ream. One should
174 * abandon current object after the function call. 177 * abandon current object after the function call.
175 */ 178 */
176 SkMemoryStream* transferBuffer(size_t offset, size_t size) { 179 virtual SkMemoryStream* transferBuffer(size_t offset, size_t size) = 0;
180 };
181
182 class SkRawBufferedStream : public SkRawStream {
183 public:
184 static SkRawStream* NewFromStream(SkStream* stream) {
185 return new SkRawBufferedStream(stream);
186 }
187
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(!fStream->hasPosition());
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(size_t offset, size_t length, void* data) {
207 if (offset == 0 && length == 0) {
scroggo 2016/02/02 19:23:06 Why is there a special case here? I can see why a
yujieqin 2016/02/04 14:50:31 I think you are right. This should be a bug. :)
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 static SkRawStream* NewFromStream(SkStream* stream) {
293 return new SkRawSeekableStream(stream);
294 }
295
296 // Will take the ownership of the stream.
297 explicit SkRawSeekableStream(SkStream* stream)
298 : fStream(stream)
299 {
300 // Only use SkRawSeekableStream when the stream is seekable.
301 SkASSERT(fStream->hasPosition());
302 }
303
304 ~SkRawSeekableStream() override {}
305
306 uint64 getLength() {
307 return fStream->getLength();
scroggo 2016/02/02 19:23:06 Maybe we should also check hasLength() to determin
yujieqin 2016/02/04 14:50:31 Done.
308 }
309
310
311 bool read(size_t offset, size_t length, void* data) {
312 if (offset == 0 && length == 0) {
313 return true;
314 }
315
316 size_t sum;
317 if (!safe_add_to_size_t(offset, length, &sum)) {
318 return false;
319 }
320
321 if (sum > fStream->getLength()) {
scroggo 2016/02/02 19:23:06 I don't think this check is necessary - the below
yujieqin 2016/02/04 14:50:31 Done.
322 return false;
scroggo 2016/02/02 19:23:06 four space indent.
yujieqin 2016/02/04 14:50:31 Done.
323 }
324 return fStream->seek(offset) && (fStream->read(data, length) == length);
325 }
326
327 SkMemoryStream* transferBuffer(size_t offset, size_t size) {
328 size_t sum;
329 if (!safe_add_to_size_t(offset, size, &sum)) {
330 return nullptr;
331 }
332
333 if (fStream->getMemoryBase()) {
334 SkAutoTUnref<SkData> data(SkData::NewWithCopy(
335 static_cast<const uint8_t*>(fStream->getMemoryBase()) + offset, size));
scroggo 2016/02/02 19:23:06 This case should also support a partial jpeg file.
yujieqin 2016/02/04 14:50:31 Done.
336 fStream.free();
337 return new SkMemoryStream(data);
338 } else {
339 SkAutoTUnref<SkData> data(SkData::NewUninitialized(size));
340 if (!fStream->seek(offset)) {
341 return nullptr;
342 }
343 // Don't check the returned size, because the following JPEG codec m ay be able to
scroggo 2016/02/02 19:23:06 We do need to know the returned size, though, beca
yujieqin 2016/02/04 14:50:31 Done.
344 // process an incomplete file.
345 fStream->read(data->writable_data(), size);
346 return new SkMemoryStream(data);
347 }
348 }
349 private:
350 SkAutoTDelete<SkStream> fStream;
351 };
352
353 class SkPiexStream : public ::piex::StreamInterface {
354 public:
355 // Note that this call will take the ownership of stream.
356 explicit SkPiexStream(SkRawStream* stream) : fStream(stream) {}
357
358 ~SkPiexStream() override {}
359
360 ::piex::Error GetData(const size_t offset, const size_t length,
361 uint8* data) override {
362 return fStream->read(offset, length, static_cast<void*>(data)) ?
363 ::piex::Error::kOk : ::piex::Error::kFail;
364 }
365
366 // Release the fStream. One should abandon current object after this call.
367 SkRawStream* releaseRawStream() {
368 return fStream.release();
369 }
370
371 private:
372 SkAutoTDelete<SkRawStream> fStream;
373 };
374
287 class SkDngStream : public dng_stream { 375 class SkDngStream : public dng_stream {
288 public: 376 public:
289 SkDngStream(SkRawStream* rawStream) : fRawStream(rawStream) {} 377 // Will NOT take the ownership of the stream, because the stream needs to be able to reuse.
378 SkDngStream(SkRawStream* stream) : fStream(stream) {}
290 379
291 uint64 DoGetLength() override { return fRawStream->getLength(); } 380 ~SkDngStream() override {}
381
382 uint64 DoGetLength() override { return fStream->getLength(); }
292 383
293 void DoRead(void* data, uint32 count, uint64 offset) override { 384 void DoRead(void* data, uint32 count, uint64 offset) override {
294 fRawStream->read(data, count, offset); 385 size_t sum;
386 if (!safe_add_to_size_t(static_cast<uint64>(count), offset, &sum) ||
scroggo 2016/02/02 19:23:06 Won't the implementation of fStream->read also mak
yujieqin 2016/02/04 14:50:31 as explained for last patch set, this check is for
387 !fStream->read(static_cast<size_t>(offset), static_cast<size_t>(coun t), data)) {
388 ThrowReadFile();
389 }
295 } 390 }
296 391
297 private: 392 private:
298 SkRawStream* fRawStream; 393 SkRawStream* fStream;
299 }; 394 };
300 395
301 class SkDngImage { 396 class SkDngImage {
302 public: 397 public:
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
(...skipping 120 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<SkPiexStream> piexStream(new SkPiexStream(
535 stream->hasPosition() ?
536 SkRawSeekableStream::NewFromStream(stream) : SkRawBufferedStream::NewFro mStream(stream)));
scroggo 2016/02/02 19:23:06 I don't think these factory functions are necessar
yujieqin 2016/02/04 14:50:31 Done.
440 ::piex::PreviewImageData imageData; 537 ::piex::PreviewImageData imageData;
441 // FIXME: ::piex::GetPreviewImageData() calls GetData() frequently with smal l amounts, 538 // 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 539 // resulting in many calls to bufferMoreData(). Could we make this more effi cient by grouping
443 // smaller requests together? 540 // smaller requests together?
444 if (::piex::IsRaw(rawStream.get())) { 541 if (::piex::IsRaw(piexStream.get())) {
445 ::piex::Error error = ::piex::GetPreviewImageData(rawStream.get(), &imag eData); 542 ::piex::Error error = ::piex::GetPreviewImageData(piexStream.get(), &ima geData);
446 543
447 if (error == ::piex::Error::kOk && imageData.preview_length > 0) { 544 if (error == ::piex::Error::kOk && imageData.preview_length > 0) {
448 #if !defined(GOOGLE3) 545 #if !defined(GOOGLE3)
449 // transferBuffer() is destructive to the rawStream. Abandon the raw Stream after this 546 // transferBuffer() is destructive to the rawStream. Abandon the raw Stream after this
450 // function call. 547 // function call.
451 // FIXME: one may avoid the copy of memoryStream and use the buffere d rawStream. 548 // FIXME: one may avoid the copy of memoryStream and use the buffere d rawStream.
452 SkMemoryStream* memoryStream = 549 SkMemoryStream* memoryStream =
453 rawStream->transferBuffer(imageData.preview_offset, imageDat a.preview_length); 550 piexStream->releaseRawStream()->transferBuffer(imageData.preview _offset,
scroggo 2016/02/02 19:23:06 This is going to leak the raw stream. I think it m
yujieqin 2016/02/04 14:50:31 Done.
551 imageData.preview _length);
454 return memoryStream ? SkJpegCodec::NewFromStream(memoryStream) : nul lptr; 552 return memoryStream ? SkJpegCodec::NewFromStream(memoryStream) : nul lptr;
455 #else 553 #else
456 return nullptr; 554 return nullptr;
457 #endif 555 #endif
458 } else if (error == ::piex::Error::kFail) { 556 } else if (error == ::piex::Error::kFail) {
459 return nullptr; 557 return nullptr;
460 } 558 }
461 } 559 }
462 560
463 SkAutoTDelete<SkDngImage> dngImage(SkDngImage::NewFromStream(rawStream.relea se())); 561 SkAutoTDelete<SkDngImage> dngImage(SkDngImage::NewFromStream(piexStream->rel easeRawStream()));
464 if (!dngImage) { 562 if (!dngImage) {
465 return nullptr; 563 return nullptr;
466 } 564 }
467 565
468 return new SkRawCodec(dngImage.release()); 566 return new SkRawCodec(dngImage.release());
469 } 567 }
470 568
471 SkCodec::Result SkRawCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, 569 SkCodec::Result SkRawCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst,
472 size_t dstRowBytes, const Options& optio ns, 570 size_t dstRowBytes, const Options& optio ns,
473 SkPMColor ctable[], int* ctableCount, 571 SkPMColor ctable[], int* ctableCount,
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
559 SkISize sizeFloor = this->onGetScaledDimensions(1.f / std::floor(fullShortEd ge / shortEdge)); 657 SkISize sizeFloor = this->onGetScaledDimensions(1.f / std::floor(fullShortEd ge / shortEdge));
560 SkISize sizeCeil = this->onGetScaledDimensions(1.f / std::ceil(fullShortEdge / shortEdge)); 658 SkISize sizeCeil = this->onGetScaledDimensions(1.f / std::ceil(fullShortEdge / shortEdge));
561 return sizeFloor == dim || sizeCeil == dim; 659 return sizeFloor == dim || sizeCeil == dim;
562 } 660 }
563 661
564 SkRawCodec::~SkRawCodec() {} 662 SkRawCodec::~SkRawCodec() {}
565 663
566 SkRawCodec::SkRawCodec(SkDngImage* dngImage) 664 SkRawCodec::SkRawCodec(SkDngImage* dngImage)
567 : INHERITED(dngImage->getImageInfo(), nullptr) 665 : INHERITED(dngImage->getImageInfo(), nullptr)
568 , fDngImage(dngImage) {} 666 , fDngImage(dngImage) {}
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