Index: src/codec/SkRawCodec.cpp |
diff --git a/src/codec/SkRawCodec.cpp b/src/codec/SkRawCodec.cpp |
index da3c28c549ff617cc74df0effb9ff18177eca023..4e890fd953cd2ac92d16d66cde18873619bb79f6 100644 |
--- a/src/codec/SkRawCodec.cpp |
+++ b/src/codec/SkRawCodec.cpp |
@@ -157,23 +157,66 @@ public: |
} |
}; |
+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.
|
+ return stream.hasLength() && stream.hasPosition(); |
+} |
+ |
} // namespace |
-// Note: this class could throw exception if it is used as dng_stream. |
-class SkRawStream : public ::piex::StreamInterface { |
+class SkRawStream { |
public: |
- // Note that this call will take the ownership of stream. |
- explicit SkRawStream(SkStream* stream) |
- : fStream(stream), fWholeStreamRead(false) {} |
+ virtual ~SkRawStream() {} |
- ~SkRawStream() override {} |
+ /* |
+ * Gets the length of the stream. Depending on the type of stream, this may require reading to |
+ * the end of the stream. |
+ */ |
+ virtual uint64 getLength() = 0; |
+ |
+ virtual bool read(void* data, size_t offset, size_t length) = 0; |
/* |
* Creates an SkMemoryStream from the offset with size. |
* Note: for performance reason, this function is destructive to the SkRawStream. One should |
* abandon current object after the function call. |
*/ |
- SkMemoryStream* transferBuffer(size_t offset, size_t size) { |
+ virtual SkMemoryStream* transferBuffer(size_t offset, size_t size) = 0; |
+}; |
+ |
+class SkRawBufferedStream : public SkRawStream { |
+public: |
+ // Will take the ownership of the stream. |
+ explicit SkRawBufferedStream(SkStream* stream) |
+ : fStream(stream) |
+ , fWholeStreamRead(false) |
+ { |
+ // Only use SkRawBufferedStream when the stream is not seekable. |
+ SkASSERT(!IsStreamSeekable(*stream)); |
+ } |
+ |
+ ~SkRawBufferedStream() override {} |
+ |
+ uint64 getLength() override { |
+ if (!this->bufferMoreData(kReadToEnd)) { // read whole stream |
+ ThrowReadFile(); |
+ } |
+ return fStreamBuffer.bytesWritten(); |
+ } |
+ |
+ bool read(void* data, size_t offset, size_t length) override { |
+ if (length == 0) { |
+ return true; |
+ } |
+ |
+ size_t sum; |
+ if (!safe_add_to_size_t(offset, length, &sum)) { |
+ return false; |
+ } |
+ |
+ return this->bufferMoreData(sum) && fStreamBuffer.read(data, offset, length); |
+ } |
+ |
+ SkMemoryStream* transferBuffer(size_t offset, size_t size) override { |
SkAutoTUnref<SkData> data(SkData::NewUninitialized(size)); |
if (offset > fStreamBuffer.bytesWritten()) { |
// If the offset is not buffered, read from fStream directly and skip the buffering. |
@@ -208,46 +251,6 @@ public: |
return new SkMemoryStream(data); |
} |
- // For PIEX |
- ::piex::Error GetData(const size_t offset, const size_t length, |
- uint8* data) override { |
- if (offset == 0 && length == 0) { |
- return ::piex::Error::kOk; |
- } |
- size_t sum; |
- if (!safe_add_to_size_t(offset, length, &sum) || !this->bufferMoreData(sum)) { |
- return ::piex::Error::kFail; |
- } |
- if (!fStreamBuffer.read(data, offset, length)) { |
- return ::piex::Error::kFail; |
- } |
- return ::piex::Error::kOk; |
- } |
- |
- // For dng_stream |
- uint64 getLength() { |
- if (!this->bufferMoreData(kReadToEnd)) { // read whole stream |
- ThrowReadFile(); |
- } |
- return fStreamBuffer.bytesWritten(); |
- } |
- |
- // For dng_stream |
- void read(void* data, uint32 count, uint64 offset) { |
- if (count == 0 && offset == 0) { |
- return; |
- } |
- size_t sum; |
- if (!safe_add_to_size_t(static_cast<uint64>(count), offset, &sum) || |
- !this->bufferMoreData(sum)) { |
- ThrowReadFile(); |
- } |
- |
- if (!fStreamBuffer.read(data, static_cast<size_t>(offset), count)) { |
- ThrowReadFile(); |
- } |
- } |
- |
private: |
// Note: if the newSize == kReadToEnd (0), this function will read to the end of stream. |
bool bufferMoreData(size_t newSize) { |
@@ -284,22 +287,114 @@ private: |
const size_t kReadToEnd = 0; |
}; |
+class SkRawSeekableStream : public SkRawStream { |
+public: |
+ // Will take the ownership of the stream. |
+ explicit SkRawSeekableStream(SkStream* stream) |
+ : fStream(stream) |
+ { |
+ // Only use SkRawSeekableStream when the stream is seekable. |
+ SkASSERT(IsStreamSeekable(*stream)); |
+ } |
+ |
+ ~SkRawSeekableStream() override {} |
+ |
+ uint64 getLength() { |
+ return fStream->getLength(); |
+ } |
+ |
+ |
+ bool read(void* data, size_t offset, size_t length) override { |
+ if (length == 0) { |
+ return true; |
+ } |
+ |
+ size_t sum; |
+ if (!safe_add_to_size_t(offset, length, &sum)) { |
+ return false; |
+ } |
+ |
+ return fStream->seek(offset) && (fStream->read(data, length) == length); |
+ } |
+ |
+ SkMemoryStream* transferBuffer(size_t offset, size_t size) { |
+ if (fStream->getLength() < offset) { |
+ return nullptr; |
+ } |
+ |
+ size_t sum; |
+ if (!safe_add_to_size_t(offset, size, &sum)) { |
+ return nullptr; |
+ } |
+ |
+ // This will allow read less than the requested "size", because the JPEG codec wants to |
+ // handle also a partial JPEG file. |
+ const size_t bytesToRead = SkTMin(sum, fStream->getLength()) - offset; |
+ if (bytesToRead == 0) { |
+ return nullptr; |
+ } |
+ |
+ if (fStream->getMemoryBase()) { // directly copy if getMemoryBase() is available. |
+ SkAutoTUnref<SkData> data(SkData::NewWithCopy( |
+ static_cast<const uint8_t*>(fStream->getMemoryBase()) + offset, bytesToRead)); |
+ fStream.free(); |
+ return new SkMemoryStream(data); |
+ } else { |
+ SkAutoTUnref<SkData> data(SkData::NewUninitialized(bytesToRead)); |
+ if (!fStream->seek(offset)) { |
+ return nullptr; |
+ } |
+ 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.
|
+ return nullptr; |
+ } |
+ return new SkMemoryStream(data); |
+ } |
+ } |
+private: |
+ SkAutoTDelete<SkStream> fStream; |
+}; |
+ |
+class SkPiexStream : public ::piex::StreamInterface { |
+public: |
+ // Will NOT take the ownership of the stream. |
+ explicit SkPiexStream(SkRawStream* stream) : fStream(stream) {} |
+ |
+ ~SkPiexStream() override {} |
+ |
+ ::piex::Error GetData(const size_t offset, const size_t length, |
+ uint8* data) override { |
+ return fStream->read(static_cast<void*>(data), offset, length) ? |
+ ::piex::Error::kOk : ::piex::Error::kFail; |
+ } |
+ |
+private: |
+ SkRawStream* fStream; |
+}; |
+ |
class SkDngStream : public dng_stream { |
public: |
- SkDngStream(SkRawStream* rawStream) : fRawStream(rawStream) {} |
+ // Will NOT take the ownership of the stream. |
+ SkDngStream(SkRawStream* stream) : fStream(stream) {} |
+ |
+ ~SkDngStream() override {} |
- uint64 DoGetLength() override { return fRawStream->getLength(); } |
+ uint64 DoGetLength() override { return fStream->getLength(); } |
void DoRead(void* data, uint32 count, uint64 offset) override { |
- fRawStream->read(data, count, offset); |
+ size_t sum; |
+ if (!safe_add_to_size_t(static_cast<uint64>(count), offset, &sum) || |
+ !fStream->read(data, static_cast<size_t>(offset), static_cast<size_t>(count))) { |
+ ThrowReadFile(); |
+ } |
} |
private: |
- SkRawStream* fRawStream; |
+ SkRawStream* fStream; |
}; |
class SkDngImage { |
public: |
+ // Will take the ownership of the stream. |
static SkDngImage* NewFromStream(SkRawStream* stream) { |
SkAutoTDelete<SkDngImage> dngImage(new SkDngImage(stream)); |
if (!dngImage->readDng()) { |
@@ -436,13 +531,21 @@ private: |
* fallback to create SkRawCodec for DNG images. |
*/ |
SkCodec* SkRawCodec::NewFromStream(SkStream* stream) { |
- SkAutoTDelete<SkRawStream> rawStream(new SkRawStream(stream)); |
+ SkAutoTDelete<SkRawStream> rawStream; |
+ if (IsStreamSeekable(*stream)) { |
+ rawStream.reset(new SkRawSeekableStream(stream)); |
+ } else { |
+ rawStream.reset(new SkRawBufferedStream(stream)); |
+ } |
+ |
+ // Does not take the ownership of rawStream. |
+ 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.
|
::piex::PreviewImageData imageData; |
// FIXME: ::piex::GetPreviewImageData() calls GetData() frequently with small amounts, |
// resulting in many calls to bufferMoreData(). Could we make this more efficient by grouping |
// smaller requests together? |
- if (::piex::IsRaw(rawStream.get())) { |
- ::piex::Error error = ::piex::GetPreviewImageData(rawStream.get(), &imageData); |
+ if (::piex::IsRaw(piexStream.get())) { |
+ ::piex::Error error = ::piex::GetPreviewImageData(piexStream.get(), &imageData); |
if (error == ::piex::Error::kOk && imageData.preview_length > 0) { |
#if !defined(GOOGLE3) |
@@ -450,7 +553,7 @@ SkCodec* SkRawCodec::NewFromStream(SkStream* stream) { |
// function call. |
// FIXME: one may avoid the copy of memoryStream and use the buffered rawStream. |
SkMemoryStream* memoryStream = |
- rawStream->transferBuffer(imageData.preview_offset, imageData.preview_length); |
+ rawStream->transferBuffer(imageData.preview_offset, imageData.preview_length); |
return memoryStream ? SkJpegCodec::NewFromStream(memoryStream) : nullptr; |
#else |
return nullptr; |
@@ -459,7 +562,9 @@ SkCodec* SkRawCodec::NewFromStream(SkStream* stream) { |
return nullptr; |
} |
} |
+ piexStream.free(); |
+ // Takes the ownership of the rawStream. |
SkAutoTDelete<SkDngImage> dngImage(SkDngImage::NewFromStream(rawStream.release())); |
if (!dngImage) { |
return nullptr; |