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