1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2023 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/codec/SkJpegSourceMgr.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStream.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/codec/SkCodecPriv.h"
15*c8dee2aaSAndroid Build Coastguard Worker
16*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_CODEC_DECODES_JPEG_GAINMAPS
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/codec/SkJpegConstants.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/codec/SkJpegSegmentScan.h"
19*c8dee2aaSAndroid Build Coastguard Worker #endif // SK_CODEC_DECODES_JPEG_GAINMAPS
20*c8dee2aaSAndroid Build Coastguard Worker
21*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////////////////////////
22*c8dee2aaSAndroid Build Coastguard Worker // SkStream helpers.
23*c8dee2aaSAndroid Build Coastguard Worker
24*c8dee2aaSAndroid Build Coastguard Worker /*
25*c8dee2aaSAndroid Build Coastguard Worker * Class that will will rewind an SkStream, and then restore it to its original position when it
26*c8dee2aaSAndroid Build Coastguard Worker * goes out of scope. If the SkStream is not seekable, then the stream will not be altered at all,
27*c8dee2aaSAndroid Build Coastguard Worker * and will return false from canRestore.
28*c8dee2aaSAndroid Build Coastguard Worker */
29*c8dee2aaSAndroid Build Coastguard Worker
30*c8dee2aaSAndroid Build Coastguard Worker class ScopedSkStreamRestorer {
31*c8dee2aaSAndroid Build Coastguard Worker public:
ScopedSkStreamRestorer(SkStream * stream)32*c8dee2aaSAndroid Build Coastguard Worker ScopedSkStreamRestorer(SkStream* stream) : fStream(stream), fPosition(stream->getPosition()) {
33*c8dee2aaSAndroid Build Coastguard Worker if (!fStream->rewind()) {
34*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Failed to rewind decoder stream.\n");
35*c8dee2aaSAndroid Build Coastguard Worker }
36*c8dee2aaSAndroid Build Coastguard Worker }
~ScopedSkStreamRestorer()37*c8dee2aaSAndroid Build Coastguard Worker ~ScopedSkStreamRestorer() {
38*c8dee2aaSAndroid Build Coastguard Worker if (!fStream->seek(fPosition)) {
39*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Failed to restore decoder stream.\n");
40*c8dee2aaSAndroid Build Coastguard Worker }
41*c8dee2aaSAndroid Build Coastguard Worker }
42*c8dee2aaSAndroid Build Coastguard Worker
43*c8dee2aaSAndroid Build Coastguard Worker private:
44*c8dee2aaSAndroid Build Coastguard Worker SkStream* const fStream;
45*c8dee2aaSAndroid Build Coastguard Worker const size_t fPosition;
46*c8dee2aaSAndroid Build Coastguard Worker };
47*c8dee2aaSAndroid Build Coastguard Worker
48*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////////////////////////
49*c8dee2aaSAndroid Build Coastguard Worker // SkJpegMemorySourceMgr
50*c8dee2aaSAndroid Build Coastguard Worker
51*c8dee2aaSAndroid Build Coastguard Worker class SkJpegMemorySourceMgr : public SkJpegSourceMgr {
52*c8dee2aaSAndroid Build Coastguard Worker public:
SkJpegMemorySourceMgr(SkStream * stream)53*c8dee2aaSAndroid Build Coastguard Worker SkJpegMemorySourceMgr(SkStream* stream) : SkJpegSourceMgr(stream) {}
~SkJpegMemorySourceMgr()54*c8dee2aaSAndroid Build Coastguard Worker ~SkJpegMemorySourceMgr() override {}
55*c8dee2aaSAndroid Build Coastguard Worker
initSource(const uint8_t * & nextInputByte,size_t & bytesInBuffer)56*c8dee2aaSAndroid Build Coastguard Worker void initSource(const uint8_t*& nextInputByte, size_t& bytesInBuffer) override {
57*c8dee2aaSAndroid Build Coastguard Worker nextInputByte = reinterpret_cast<const uint8_t*>(fStream->getMemoryBase());
58*c8dee2aaSAndroid Build Coastguard Worker bytesInBuffer = static_cast<size_t>(fStream->getLength());
59*c8dee2aaSAndroid Build Coastguard Worker }
fillInputBuffer(const uint8_t * & nextInputByte,size_t & bytesInBuffer)60*c8dee2aaSAndroid Build Coastguard Worker bool fillInputBuffer(const uint8_t*& nextInputByte, size_t& bytesInBuffer) override {
61*c8dee2aaSAndroid Build Coastguard Worker // The whole JPEG data is expected to reside in the supplied memory buffer, so any request
62*c8dee2aaSAndroid Build Coastguard Worker // for more data beyond the given buffer size is treated as an error.
63*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Asked to re-fill a memory-mapped stream.\n");
64*c8dee2aaSAndroid Build Coastguard Worker return false;
65*c8dee2aaSAndroid Build Coastguard Worker }
skipInputBytes(size_t bytesToSkip,const uint8_t * & nextInputByte,size_t & bytesInBuffer)66*c8dee2aaSAndroid Build Coastguard Worker bool skipInputBytes(size_t bytesToSkip,
67*c8dee2aaSAndroid Build Coastguard Worker const uint8_t*& nextInputByte,
68*c8dee2aaSAndroid Build Coastguard Worker size_t& bytesInBuffer) override {
69*c8dee2aaSAndroid Build Coastguard Worker if (bytesToSkip > bytesInBuffer) {
70*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Asked to read past end of a memory-mapped stream.\n");
71*c8dee2aaSAndroid Build Coastguard Worker return false;
72*c8dee2aaSAndroid Build Coastguard Worker }
73*c8dee2aaSAndroid Build Coastguard Worker nextInputByte += bytesToSkip;
74*c8dee2aaSAndroid Build Coastguard Worker bytesInBuffer -= bytesToSkip;
75*c8dee2aaSAndroid Build Coastguard Worker return true;
76*c8dee2aaSAndroid Build Coastguard Worker }
77*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_CODEC_DECODES_JPEG_GAINMAPS
getAllSegments()78*c8dee2aaSAndroid Build Coastguard Worker const std::vector<SkJpegSegment>& getAllSegments() override {
79*c8dee2aaSAndroid Build Coastguard Worker if (fScanner) {
80*c8dee2aaSAndroid Build Coastguard Worker return fScanner->getSegments();
81*c8dee2aaSAndroid Build Coastguard Worker }
82*c8dee2aaSAndroid Build Coastguard Worker fScanner = std::make_unique<SkJpegSegmentScanner>(kJpegMarkerEndOfImage);
83*c8dee2aaSAndroid Build Coastguard Worker fScanner->onBytes(fStream->getMemoryBase(), fStream->getLength());
84*c8dee2aaSAndroid Build Coastguard Worker return fScanner->getSegments();
85*c8dee2aaSAndroid Build Coastguard Worker }
getSubsetData(size_t offset,size_t size,bool * wasCopied)86*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> getSubsetData(size_t offset, size_t size, bool* wasCopied) override {
87*c8dee2aaSAndroid Build Coastguard Worker if (offset > fStream->getLength() || size > fStream->getLength() - offset) {
88*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
89*c8dee2aaSAndroid Build Coastguard Worker }
90*c8dee2aaSAndroid Build Coastguard Worker if (wasCopied) {
91*c8dee2aaSAndroid Build Coastguard Worker *wasCopied = false;
92*c8dee2aaSAndroid Build Coastguard Worker }
93*c8dee2aaSAndroid Build Coastguard Worker return SkData::MakeWithoutCopy(
94*c8dee2aaSAndroid Build Coastguard Worker reinterpret_cast<const uint8_t*>(fStream->getMemoryBase()) + offset, size);
95*c8dee2aaSAndroid Build Coastguard Worker }
getSegmentParameters(const SkJpegSegment & segment)96*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> getSegmentParameters(const SkJpegSegment& segment) override {
97*c8dee2aaSAndroid Build Coastguard Worker const uint8_t* base =
98*c8dee2aaSAndroid Build Coastguard Worker reinterpret_cast<const uint8_t*>(fStream->getMemoryBase()) + segment.offset;
99*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(segment.offset < fStream->getLength());
100*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(kJpegMarkerCodeSize + segment.parameterLength <=
101*c8dee2aaSAndroid Build Coastguard Worker fStream->getLength() - segment.offset);
102*c8dee2aaSAndroid Build Coastguard Worker
103*c8dee2aaSAndroid Build Coastguard Worker // Read the marker and verify it matches `segment`.
104*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(base[0] == 0xFF);
105*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(base[1] == segment.marker);
106*c8dee2aaSAndroid Build Coastguard Worker
107*c8dee2aaSAndroid Build Coastguard Worker // Read the parameter length and verify it matches `segment`.
108*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(256 * base[2] + base[3] == segment.parameterLength);
109*c8dee2aaSAndroid Build Coastguard Worker if (segment.parameterLength <= kJpegSegmentParameterLengthSize) {
110*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
111*c8dee2aaSAndroid Build Coastguard Worker }
112*c8dee2aaSAndroid Build Coastguard Worker
113*c8dee2aaSAndroid Build Coastguard Worker // Read the remainder of the segment.
114*c8dee2aaSAndroid Build Coastguard Worker return SkData::MakeWithoutCopy(base + kJpegMarkerCodeSize + kJpegSegmentParameterLengthSize,
115*c8dee2aaSAndroid Build Coastguard Worker segment.parameterLength - kJpegSegmentParameterLengthSize);
116*c8dee2aaSAndroid Build Coastguard Worker }
117*c8dee2aaSAndroid Build Coastguard Worker #endif // SK_CODEC_DECODES_JPEG_GAINMAPS
118*c8dee2aaSAndroid Build Coastguard Worker };
119*c8dee2aaSAndroid Build Coastguard Worker
120*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////////////////////////
121*c8dee2aaSAndroid Build Coastguard Worker // SkJpegBufferedSourceMgr
122*c8dee2aaSAndroid Build Coastguard Worker
123*c8dee2aaSAndroid Build Coastguard Worker class SkJpegBufferedSourceMgr : public SkJpegSourceMgr {
124*c8dee2aaSAndroid Build Coastguard Worker public:
SkJpegBufferedSourceMgr(SkStream * stream,size_t bufferSize)125*c8dee2aaSAndroid Build Coastguard Worker SkJpegBufferedSourceMgr(SkStream* stream, size_t bufferSize) : SkJpegSourceMgr(stream) {
126*c8dee2aaSAndroid Build Coastguard Worker fBuffer = SkData::MakeUninitialized(bufferSize);
127*c8dee2aaSAndroid Build Coastguard Worker }
~SkJpegBufferedSourceMgr()128*c8dee2aaSAndroid Build Coastguard Worker ~SkJpegBufferedSourceMgr() override {}
129*c8dee2aaSAndroid Build Coastguard Worker
initSource(const uint8_t * & nextInputByte,size_t & bytesInBuffer)130*c8dee2aaSAndroid Build Coastguard Worker void initSource(const uint8_t*& nextInputByte, size_t& bytesInBuffer) override {
131*c8dee2aaSAndroid Build Coastguard Worker nextInputByte = fBuffer->bytes();
132*c8dee2aaSAndroid Build Coastguard Worker bytesInBuffer = 0;
133*c8dee2aaSAndroid Build Coastguard Worker }
fillInputBuffer(const uint8_t * & nextInputByte,size_t & bytesInBuffer)134*c8dee2aaSAndroid Build Coastguard Worker bool fillInputBuffer(const uint8_t*& nextInputByte, size_t& bytesInBuffer) override {
135*c8dee2aaSAndroid Build Coastguard Worker size_t bytesRead = fStream->read(fBuffer->writable_data(), fBuffer->size());
136*c8dee2aaSAndroid Build Coastguard Worker if (bytesRead == 0) {
137*c8dee2aaSAndroid Build Coastguard Worker // Fail if we read zero bytes (libjpeg will accept any non-zero number of bytes).
138*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Hit end of file reading a buffered stream.\n");
139*c8dee2aaSAndroid Build Coastguard Worker return false;
140*c8dee2aaSAndroid Build Coastguard Worker }
141*c8dee2aaSAndroid Build Coastguard Worker nextInputByte = fBuffer->bytes();
142*c8dee2aaSAndroid Build Coastguard Worker bytesInBuffer = bytesRead;
143*c8dee2aaSAndroid Build Coastguard Worker return true;
144*c8dee2aaSAndroid Build Coastguard Worker }
skipInputBytes(size_t bytesToSkip,const uint8_t * & nextInputByte,size_t & bytesInBuffer)145*c8dee2aaSAndroid Build Coastguard Worker bool skipInputBytes(size_t bytesToSkip,
146*c8dee2aaSAndroid Build Coastguard Worker const uint8_t*& nextInputByte,
147*c8dee2aaSAndroid Build Coastguard Worker size_t& bytesInBuffer) override {
148*c8dee2aaSAndroid Build Coastguard Worker // Skip through the already-read (or already in memory) buffer.
149*c8dee2aaSAndroid Build Coastguard Worker if (bytesToSkip <= bytesInBuffer) {
150*c8dee2aaSAndroid Build Coastguard Worker nextInputByte += bytesToSkip;
151*c8dee2aaSAndroid Build Coastguard Worker bytesInBuffer -= bytesToSkip;
152*c8dee2aaSAndroid Build Coastguard Worker return true;
153*c8dee2aaSAndroid Build Coastguard Worker }
154*c8dee2aaSAndroid Build Coastguard Worker bytesToSkip -= bytesInBuffer;
155*c8dee2aaSAndroid Build Coastguard Worker
156*c8dee2aaSAndroid Build Coastguard Worker // Fail if we skip past the end of the stream.
157*c8dee2aaSAndroid Build Coastguard Worker if (fStream->skip(bytesToSkip) != bytesToSkip) {
158*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Failed to skip through buffered stream.\n");
159*c8dee2aaSAndroid Build Coastguard Worker return false;
160*c8dee2aaSAndroid Build Coastguard Worker }
161*c8dee2aaSAndroid Build Coastguard Worker
162*c8dee2aaSAndroid Build Coastguard Worker bytesInBuffer = 0;
163*c8dee2aaSAndroid Build Coastguard Worker nextInputByte = fBuffer->bytes();
164*c8dee2aaSAndroid Build Coastguard Worker return true;
165*c8dee2aaSAndroid Build Coastguard Worker }
166*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_CODEC_DECODES_JPEG_GAINMAPS
getAllSegments()167*c8dee2aaSAndroid Build Coastguard Worker const std::vector<SkJpegSegment>& getAllSegments() override {
168*c8dee2aaSAndroid Build Coastguard Worker if (fScanner) {
169*c8dee2aaSAndroid Build Coastguard Worker return fScanner->getSegments();
170*c8dee2aaSAndroid Build Coastguard Worker }
171*c8dee2aaSAndroid Build Coastguard Worker ScopedSkStreamRestorer streamRestorer(fStream);
172*c8dee2aaSAndroid Build Coastguard Worker fScanner = std::make_unique<SkJpegSegmentScanner>(kJpegMarkerEndOfImage);
173*c8dee2aaSAndroid Build Coastguard Worker while (!fScanner->isDone() && !fScanner->hadError()) {
174*c8dee2aaSAndroid Build Coastguard Worker constexpr size_t kBufferSize = 1024;
175*c8dee2aaSAndroid Build Coastguard Worker uint8_t buffer[kBufferSize];
176*c8dee2aaSAndroid Build Coastguard Worker size_t bytesRead = fStream->read(buffer, kBufferSize);
177*c8dee2aaSAndroid Build Coastguard Worker if (bytesRead == 0) {
178*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Unexpected EOF.\n");
179*c8dee2aaSAndroid Build Coastguard Worker break;
180*c8dee2aaSAndroid Build Coastguard Worker }
181*c8dee2aaSAndroid Build Coastguard Worker fScanner->onBytes(buffer, bytesRead);
182*c8dee2aaSAndroid Build Coastguard Worker }
183*c8dee2aaSAndroid Build Coastguard Worker return fScanner->getSegments();
184*c8dee2aaSAndroid Build Coastguard Worker }
getSubsetData(size_t offset,size_t size,bool * wasCopied)185*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> getSubsetData(size_t offset, size_t size, bool* wasCopied) override {
186*c8dee2aaSAndroid Build Coastguard Worker ScopedSkStreamRestorer streamRestorer(fStream);
187*c8dee2aaSAndroid Build Coastguard Worker if (!fStream->seek(offset)) {
188*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Failed to seek to subset stream position.\n");
189*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
190*c8dee2aaSAndroid Build Coastguard Worker }
191*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> data = SkData::MakeUninitialized(size);
192*c8dee2aaSAndroid Build Coastguard Worker if (fStream->read(data->writable_data(), size) != size) {
193*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Failed to read subset stream data.\n");
194*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
195*c8dee2aaSAndroid Build Coastguard Worker }
196*c8dee2aaSAndroid Build Coastguard Worker if (wasCopied) {
197*c8dee2aaSAndroid Build Coastguard Worker *wasCopied = true;
198*c8dee2aaSAndroid Build Coastguard Worker }
199*c8dee2aaSAndroid Build Coastguard Worker return data;
200*c8dee2aaSAndroid Build Coastguard Worker }
getSegmentParameters(const SkJpegSegment & segment)201*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> getSegmentParameters(const SkJpegSegment& segment) override {
202*c8dee2aaSAndroid Build Coastguard Worker // If the segment's parameter length isn't longer than the two bytes for the length,
203*c8dee2aaSAndroid Build Coastguard Worker // early-out early-out.
204*c8dee2aaSAndroid Build Coastguard Worker if (segment.parameterLength <= kJpegSegmentParameterLengthSize) {
205*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
206*c8dee2aaSAndroid Build Coastguard Worker }
207*c8dee2aaSAndroid Build Coastguard Worker
208*c8dee2aaSAndroid Build Coastguard Worker // Seek to the start of the segment.
209*c8dee2aaSAndroid Build Coastguard Worker ScopedSkStreamRestorer streamRestorer(fStream);
210*c8dee2aaSAndroid Build Coastguard Worker if (!fStream->seek(segment.offset)) {
211*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Failed to seek to segment\n");
212*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
213*c8dee2aaSAndroid Build Coastguard Worker }
214*c8dee2aaSAndroid Build Coastguard Worker
215*c8dee2aaSAndroid Build Coastguard Worker // Read the marker and verify it matches `segment`.
216*c8dee2aaSAndroid Build Coastguard Worker uint8_t markerCode[kJpegMarkerCodeSize] = {0};
217*c8dee2aaSAndroid Build Coastguard Worker if (fStream->read(markerCode, kJpegMarkerCodeSize) != kJpegMarkerCodeSize) {
218*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Failed to read segment marker code\n");
219*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
220*c8dee2aaSAndroid Build Coastguard Worker }
221*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(markerCode[0] == 0xFF);
222*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(markerCode[1] == segment.marker);
223*c8dee2aaSAndroid Build Coastguard Worker
224*c8dee2aaSAndroid Build Coastguard Worker // Read the parameter length and verify it matches `segment`.
225*c8dee2aaSAndroid Build Coastguard Worker uint8_t parameterLength[kJpegSegmentParameterLengthSize] = {0};
226*c8dee2aaSAndroid Build Coastguard Worker if (fStream->read(parameterLength, kJpegSegmentParameterLengthSize) !=
227*c8dee2aaSAndroid Build Coastguard Worker kJpegSegmentParameterLengthSize) {
228*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Failed to read parameter length\n");
229*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
230*c8dee2aaSAndroid Build Coastguard Worker }
231*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(256 * parameterLength[0] + parameterLength[1] == segment.parameterLength);
232*c8dee2aaSAndroid Build Coastguard Worker
233*c8dee2aaSAndroid Build Coastguard Worker // Read the remainder of the segment.
234*c8dee2aaSAndroid Build Coastguard Worker size_t sizeToRead = segment.parameterLength - kJpegSegmentParameterLengthSize;
235*c8dee2aaSAndroid Build Coastguard Worker auto result = SkData::MakeUninitialized(sizeToRead);
236*c8dee2aaSAndroid Build Coastguard Worker if (fStream->read(result->writable_data(), sizeToRead) != sizeToRead) {
237*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
238*c8dee2aaSAndroid Build Coastguard Worker }
239*c8dee2aaSAndroid Build Coastguard Worker
240*c8dee2aaSAndroid Build Coastguard Worker return result;
241*c8dee2aaSAndroid Build Coastguard Worker }
242*c8dee2aaSAndroid Build Coastguard Worker #endif // SK_CODEC_DECODES_JPEG_GAINMAPS
243*c8dee2aaSAndroid Build Coastguard Worker
244*c8dee2aaSAndroid Build Coastguard Worker private:
245*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> fBuffer;
246*c8dee2aaSAndroid Build Coastguard Worker };
247*c8dee2aaSAndroid Build Coastguard Worker
248*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////////////////////////
249*c8dee2aaSAndroid Build Coastguard Worker // SkJpegUnseekableSourceMgr
250*c8dee2aaSAndroid Build Coastguard Worker
251*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_CODEC_DECODES_JPEG_GAINMAPS
252*c8dee2aaSAndroid Build Coastguard Worker /*
253*c8dee2aaSAndroid Build Coastguard Worker * This class implements SkJpegSourceMgr for a stream that cannot seek or rewind. It scans the data
254*c8dee2aaSAndroid Build Coastguard Worker * as it is presented to the decoder. This allows it to track the position of segments, so that it
255*c8dee2aaSAndroid Build Coastguard Worker * can extract subsets at a specific offset (e.g, relative to the EndOfImage segment for JpegR or
256*c8dee2aaSAndroid Build Coastguard Worker * relative to an MPF segment for MPF).
257*c8dee2aaSAndroid Build Coastguard Worker */
258*c8dee2aaSAndroid Build Coastguard Worker class SkJpegUnseekableSourceMgr : public SkJpegSourceMgr {
259*c8dee2aaSAndroid Build Coastguard Worker public:
SkJpegUnseekableSourceMgr(SkStream * stream,size_t bufferSize)260*c8dee2aaSAndroid Build Coastguard Worker SkJpegUnseekableSourceMgr(SkStream* stream, size_t bufferSize) : SkJpegSourceMgr(stream) {
261*c8dee2aaSAndroid Build Coastguard Worker fBuffer = SkData::MakeUninitialized(bufferSize);
262*c8dee2aaSAndroid Build Coastguard Worker fScanner = std::make_unique<SkJpegSegmentScanner>(kJpegMarkerEndOfImage);
263*c8dee2aaSAndroid Build Coastguard Worker }
~SkJpegUnseekableSourceMgr()264*c8dee2aaSAndroid Build Coastguard Worker ~SkJpegUnseekableSourceMgr() override {}
265*c8dee2aaSAndroid Build Coastguard Worker
initSource(const uint8_t * & nextInputByte,size_t & bytesInBuffer)266*c8dee2aaSAndroid Build Coastguard Worker void initSource(const uint8_t*& nextInputByte, size_t& bytesInBuffer) override {
267*c8dee2aaSAndroid Build Coastguard Worker nextInputByte = fBuffer->bytes();
268*c8dee2aaSAndroid Build Coastguard Worker bytesInBuffer = 0;
269*c8dee2aaSAndroid Build Coastguard Worker }
fillInputBuffer(const uint8_t * & nextInputByte,size_t & bytesInBuffer)270*c8dee2aaSAndroid Build Coastguard Worker bool fillInputBuffer(const uint8_t*& nextInputByte, size_t& bytesInBuffer) override {
271*c8dee2aaSAndroid Build Coastguard Worker if (!readToBufferAndScan(fBuffer->size())) {
272*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Failure filling unseekable input buffer.\n");
273*c8dee2aaSAndroid Build Coastguard Worker return false;
274*c8dee2aaSAndroid Build Coastguard Worker }
275*c8dee2aaSAndroid Build Coastguard Worker nextInputByte = fBuffer->bytes();
276*c8dee2aaSAndroid Build Coastguard Worker bytesInBuffer = fLastReadSize;
277*c8dee2aaSAndroid Build Coastguard Worker return true;
278*c8dee2aaSAndroid Build Coastguard Worker }
skipInputBytes(size_t bytesToSkip,const uint8_t * & nextInputByte,size_t & bytesInBuffer)279*c8dee2aaSAndroid Build Coastguard Worker bool skipInputBytes(size_t bytesToSkip,
280*c8dee2aaSAndroid Build Coastguard Worker const uint8_t*& nextInputByte,
281*c8dee2aaSAndroid Build Coastguard Worker size_t& bytesInBuffer) override {
282*c8dee2aaSAndroid Build Coastguard Worker // Skip through the already-read (or already in memory) buffer.
283*c8dee2aaSAndroid Build Coastguard Worker if (bytesToSkip <= bytesInBuffer) {
284*c8dee2aaSAndroid Build Coastguard Worker nextInputByte += bytesToSkip;
285*c8dee2aaSAndroid Build Coastguard Worker bytesInBuffer -= bytesToSkip;
286*c8dee2aaSAndroid Build Coastguard Worker return true;
287*c8dee2aaSAndroid Build Coastguard Worker }
288*c8dee2aaSAndroid Build Coastguard Worker bytesToSkip -= bytesInBuffer;
289*c8dee2aaSAndroid Build Coastguard Worker
290*c8dee2aaSAndroid Build Coastguard Worker // Read the remaining bytes to skip into fBuffer and feed them into fScanner.
291*c8dee2aaSAndroid Build Coastguard Worker while (bytesToSkip > 0) {
292*c8dee2aaSAndroid Build Coastguard Worker if (!readToBufferAndScan(std::min(bytesToSkip, fBuffer->size()))) {
293*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Failure filling unseekable input buffer.\n");
294*c8dee2aaSAndroid Build Coastguard Worker return false;
295*c8dee2aaSAndroid Build Coastguard Worker }
296*c8dee2aaSAndroid Build Coastguard Worker bytesToSkip -= fLastReadSize;
297*c8dee2aaSAndroid Build Coastguard Worker }
298*c8dee2aaSAndroid Build Coastguard Worker
299*c8dee2aaSAndroid Build Coastguard Worker // Indicate to libjpeg that it it needs to call fillInputBuffer.
300*c8dee2aaSAndroid Build Coastguard Worker bytesInBuffer = 0;
301*c8dee2aaSAndroid Build Coastguard Worker nextInputByte = fBuffer->bytes();
302*c8dee2aaSAndroid Build Coastguard Worker return true;
303*c8dee2aaSAndroid Build Coastguard Worker }
getAllSegments()304*c8dee2aaSAndroid Build Coastguard Worker const std::vector<SkJpegSegment>& getAllSegments() override {
305*c8dee2aaSAndroid Build Coastguard Worker while (!fScanner->isDone() && !fScanner->hadError()) {
306*c8dee2aaSAndroid Build Coastguard Worker if (!readToBufferAndScan(fBuffer->size())) {
307*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Failure finishing unseekable input buffer.\n");
308*c8dee2aaSAndroid Build Coastguard Worker break;
309*c8dee2aaSAndroid Build Coastguard Worker }
310*c8dee2aaSAndroid Build Coastguard Worker }
311*c8dee2aaSAndroid Build Coastguard Worker return fScanner->getSegments();
312*c8dee2aaSAndroid Build Coastguard Worker }
getSubsetData(size_t offset,size_t size,bool * wasCopied)313*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> getSubsetData(size_t offset, size_t size, bool* wasCopied) override {
314*c8dee2aaSAndroid Build Coastguard Worker // If we haven't reached the EndOfImage, then we are throwing away the base image before
315*c8dee2aaSAndroid Build Coastguard Worker // decoding it. This is only reasonable for tests.
316*c8dee2aaSAndroid Build Coastguard Worker if (!fScanner->isDone()) {
317*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("getSubsetData is prematurely terminating scan.\n");
318*c8dee2aaSAndroid Build Coastguard Worker }
319*c8dee2aaSAndroid Build Coastguard Worker
320*c8dee2aaSAndroid Build Coastguard Worker // If we have read past offset, we can never get that data back again.
321*c8dee2aaSAndroid Build Coastguard Worker if (offset < fLastReadOffset) {
322*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Requested that is gone.\n");
323*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
324*c8dee2aaSAndroid Build Coastguard Worker }
325*c8dee2aaSAndroid Build Coastguard Worker
326*c8dee2aaSAndroid Build Coastguard Worker // Allocate the memory to return, and indicate that the result is a copy.
327*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> subsetData = SkData::MakeUninitialized(size);
328*c8dee2aaSAndroid Build Coastguard Worker uint8_t* subsetDataCurrent = reinterpret_cast<uint8_t*>(subsetData->writable_data());
329*c8dee2aaSAndroid Build Coastguard Worker
330*c8dee2aaSAndroid Build Coastguard Worker // Determine the relationship between the offset we're reading from and |fBuffer|.
331*c8dee2aaSAndroid Build Coastguard Worker size_t offsetIntoBuffer = offset - fLastReadOffset;
332*c8dee2aaSAndroid Build Coastguard Worker if (offsetIntoBuffer >= fLastReadSize) {
333*c8dee2aaSAndroid Build Coastguard Worker // We have to skip past |fBuffer| to get to |offset|.
334*c8dee2aaSAndroid Build Coastguard Worker fLastReadOffset += fLastReadSize;
335*c8dee2aaSAndroid Build Coastguard Worker fLastReadSize = 0;
336*c8dee2aaSAndroid Build Coastguard Worker
337*c8dee2aaSAndroid Build Coastguard Worker // Skip any additional bytes needed to get to |offset|.
338*c8dee2aaSAndroid Build Coastguard Worker size_t bytesToSkip = offset - fLastReadOffset;
339*c8dee2aaSAndroid Build Coastguard Worker while (bytesToSkip > 0) {
340*c8dee2aaSAndroid Build Coastguard Worker size_t bytesSkipped = fStream->skip(bytesToSkip);
341*c8dee2aaSAndroid Build Coastguard Worker if (bytesSkipped == 0) {
342*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Failed to skip bytes before subset.\n");
343*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
344*c8dee2aaSAndroid Build Coastguard Worker }
345*c8dee2aaSAndroid Build Coastguard Worker bytesToSkip -= bytesSkipped;
346*c8dee2aaSAndroid Build Coastguard Worker fLastReadOffset += bytesSkipped;
347*c8dee2aaSAndroid Build Coastguard Worker }
348*c8dee2aaSAndroid Build Coastguard Worker } else {
349*c8dee2aaSAndroid Build Coastguard Worker // This assert is to emphatically document the side of the branch we're on.
350*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(offsetIntoBuffer < fLastReadSize);
351*c8dee2aaSAndroid Build Coastguard Worker
352*c8dee2aaSAndroid Build Coastguard Worker // Some of the data we want to copy has already been read into |fBuffer|. Copy that data
353*c8dee2aaSAndroid Build Coastguard Worker // to |subsetData|
354*c8dee2aaSAndroid Build Coastguard Worker size_t bytesToReadFromBuffer = std::min(fLastReadSize - offsetIntoBuffer, size);
355*c8dee2aaSAndroid Build Coastguard Worker memcpy(subsetDataCurrent, fBuffer->bytes() + offsetIntoBuffer, bytesToReadFromBuffer);
356*c8dee2aaSAndroid Build Coastguard Worker size -= bytesToReadFromBuffer;
357*c8dee2aaSAndroid Build Coastguard Worker subsetDataCurrent += bytesToReadFromBuffer;
358*c8dee2aaSAndroid Build Coastguard Worker
359*c8dee2aaSAndroid Build Coastguard Worker // If all of the data that we needed was in |fBuffer|, then return early.
360*c8dee2aaSAndroid Build Coastguard Worker if (size == 0) {
361*c8dee2aaSAndroid Build Coastguard Worker if (wasCopied) {
362*c8dee2aaSAndroid Build Coastguard Worker *wasCopied = true;
363*c8dee2aaSAndroid Build Coastguard Worker }
364*c8dee2aaSAndroid Build Coastguard Worker return subsetData;
365*c8dee2aaSAndroid Build Coastguard Worker }
366*c8dee2aaSAndroid Build Coastguard Worker // We will now have to read beyond |fBuffer|, so reset it.
367*c8dee2aaSAndroid Build Coastguard Worker fLastReadOffset += fLastReadSize;
368*c8dee2aaSAndroid Build Coastguard Worker fLastReadSize = 0;
369*c8dee2aaSAndroid Build Coastguard Worker }
370*c8dee2aaSAndroid Build Coastguard Worker
371*c8dee2aaSAndroid Build Coastguard Worker // Read the remaining data from |fStream|.
372*c8dee2aaSAndroid Build Coastguard Worker while (size > 0) {
373*c8dee2aaSAndroid Build Coastguard Worker size_t bytesRead = fStream->read(subsetDataCurrent, size);
374*c8dee2aaSAndroid Build Coastguard Worker if (bytesRead == 0) {
375*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Failed to read subset stream data.\n");
376*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
377*c8dee2aaSAndroid Build Coastguard Worker }
378*c8dee2aaSAndroid Build Coastguard Worker size -= bytesRead;
379*c8dee2aaSAndroid Build Coastguard Worker subsetDataCurrent += bytesRead;
380*c8dee2aaSAndroid Build Coastguard Worker fLastReadOffset += bytesRead;
381*c8dee2aaSAndroid Build Coastguard Worker }
382*c8dee2aaSAndroid Build Coastguard Worker
383*c8dee2aaSAndroid Build Coastguard Worker if (wasCopied) {
384*c8dee2aaSAndroid Build Coastguard Worker *wasCopied = true;
385*c8dee2aaSAndroid Build Coastguard Worker }
386*c8dee2aaSAndroid Build Coastguard Worker return subsetData;
387*c8dee2aaSAndroid Build Coastguard Worker }
getSegmentParameters(const SkJpegSegment & segment)388*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> getSegmentParameters(const SkJpegSegment& segment) override {
389*c8dee2aaSAndroid Build Coastguard Worker // The only way to implement this for an unseekable stream is to record the parameters as
390*c8dee2aaSAndroid Build Coastguard Worker // they are scanned.
391*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
392*c8dee2aaSAndroid Build Coastguard Worker }
393*c8dee2aaSAndroid Build Coastguard Worker
394*c8dee2aaSAndroid Build Coastguard Worker private:
395*c8dee2aaSAndroid Build Coastguard Worker // Read the specified number of bytes into fBuffer and feed them to fScanner. The number of
396*c8dee2aaSAndroid Build Coastguard Worker // bytes must not be larger than fBuffer's size.
readToBufferAndScan(size_t bytesToRead)397*c8dee2aaSAndroid Build Coastguard Worker bool readToBufferAndScan(size_t bytesToRead) {
398*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(bytesToRead <= fBuffer->size());
399*c8dee2aaSAndroid Build Coastguard Worker fLastReadOffset += fLastReadSize;
400*c8dee2aaSAndroid Build Coastguard Worker fLastReadSize = fStream->read(fBuffer->writable_data(), bytesToRead);
401*c8dee2aaSAndroid Build Coastguard Worker if (fLastReadSize == 0) {
402*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Hit end of file reading an unseekable stream.\n");
403*c8dee2aaSAndroid Build Coastguard Worker return false;
404*c8dee2aaSAndroid Build Coastguard Worker }
405*c8dee2aaSAndroid Build Coastguard Worker fScanner->onBytes(fBuffer->bytes(), fLastReadSize);
406*c8dee2aaSAndroid Build Coastguard Worker return true;
407*c8dee2aaSAndroid Build Coastguard Worker }
408*c8dee2aaSAndroid Build Coastguard Worker
409*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> fBuffer;
410*c8dee2aaSAndroid Build Coastguard Worker
411*c8dee2aaSAndroid Build Coastguard Worker // The number of bytes that were most recently read into fBuffer (this can be less than the size
412*c8dee2aaSAndroid Build Coastguard Worker // of fBuffer).
413*c8dee2aaSAndroid Build Coastguard Worker size_t fLastReadSize = 0;
414*c8dee2aaSAndroid Build Coastguard Worker
415*c8dee2aaSAndroid Build Coastguard Worker // The offset into the stream (total number of bytes read) at the time of our most recent read
416*c8dee2aaSAndroid Build Coastguard Worker // into fBuffer.
417*c8dee2aaSAndroid Build Coastguard Worker size_t fLastReadOffset = 0;
418*c8dee2aaSAndroid Build Coastguard Worker };
419*c8dee2aaSAndroid Build Coastguard Worker #endif // SK_CODEC_DECODES_JPEG_GAINMAPS
420*c8dee2aaSAndroid Build Coastguard Worker
421*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////////////////////////
422*c8dee2aaSAndroid Build Coastguard Worker // SkJpegSourceMgr
423*c8dee2aaSAndroid Build Coastguard Worker
424*c8dee2aaSAndroid Build Coastguard Worker // static
Make(SkStream * stream,size_t bufferSize)425*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkJpegSourceMgr> SkJpegSourceMgr::Make(SkStream* stream, size_t bufferSize) {
426*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_CODEC_DECODES_JPEG_GAINMAPS
427*c8dee2aaSAndroid Build Coastguard Worker if (!stream->hasPosition()) {
428*c8dee2aaSAndroid Build Coastguard Worker return std::make_unique<SkJpegUnseekableSourceMgr>(stream, bufferSize);
429*c8dee2aaSAndroid Build Coastguard Worker }
430*c8dee2aaSAndroid Build Coastguard Worker #endif
431*c8dee2aaSAndroid Build Coastguard Worker if (stream->hasLength() && stream->getMemoryBase()) {
432*c8dee2aaSAndroid Build Coastguard Worker return std::make_unique<SkJpegMemorySourceMgr>(stream);
433*c8dee2aaSAndroid Build Coastguard Worker }
434*c8dee2aaSAndroid Build Coastguard Worker return std::make_unique<SkJpegBufferedSourceMgr>(stream, bufferSize);
435*c8dee2aaSAndroid Build Coastguard Worker }
436*c8dee2aaSAndroid Build Coastguard Worker
SkJpegSourceMgr(SkStream * stream)437*c8dee2aaSAndroid Build Coastguard Worker SkJpegSourceMgr::SkJpegSourceMgr(SkStream* stream) : fStream(stream) {}
438*c8dee2aaSAndroid Build Coastguard Worker
439*c8dee2aaSAndroid Build Coastguard Worker SkJpegSourceMgr::~SkJpegSourceMgr() = default;
440