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 #ifndef SkJpegSegmentScan_codec_DEFINED 9*c8dee2aaSAndroid Build Coastguard Worker #define SkJpegSegmentScan_codec_DEFINED 10*c8dee2aaSAndroid Build Coastguard Worker 11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h" 12*c8dee2aaSAndroid Build Coastguard Worker #include "src/codec/SkJpegConstants.h" 13*c8dee2aaSAndroid Build Coastguard Worker 14*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef> 15*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint> 16*c8dee2aaSAndroid Build Coastguard Worker #include <memory> 17*c8dee2aaSAndroid Build Coastguard Worker #include <vector> 18*c8dee2aaSAndroid Build Coastguard Worker 19*c8dee2aaSAndroid Build Coastguard Worker class SkData; 20*c8dee2aaSAndroid Build Coastguard Worker class SkStream; 21*c8dee2aaSAndroid Build Coastguard Worker 22*c8dee2aaSAndroid Build Coastguard Worker /* 23*c8dee2aaSAndroid Build Coastguard Worker * A JPEG segment. 24*c8dee2aaSAndroid Build Coastguard Worker */ 25*c8dee2aaSAndroid Build Coastguard Worker struct SkJpegSegment { 26*c8dee2aaSAndroid Build Coastguard Worker // The offset in bytes from the initial position to where this segment starts. 27*c8dee2aaSAndroid Build Coastguard Worker size_t offset = 0; 28*c8dee2aaSAndroid Build Coastguard Worker // The second byte of the marker code, which determines the segment type. 29*c8dee2aaSAndroid Build Coastguard Worker uint8_t marker = 0; 30*c8dee2aaSAndroid Build Coastguard Worker // The length of the parameters for this segment (including the two bytes used to specify 31*c8dee2aaSAndroid Build Coastguard Worker // the length). 32*c8dee2aaSAndroid Build Coastguard Worker uint16_t parameterLength = 0; 33*c8dee2aaSAndroid Build Coastguard Worker }; 34*c8dee2aaSAndroid Build Coastguard Worker 35*c8dee2aaSAndroid Build Coastguard Worker /* 36*c8dee2aaSAndroid Build Coastguard Worker * Class for scanning JPEG data. The JPEG format consists of a sequence of segments that begin with 37*c8dee2aaSAndroid Build Coastguard Worker * a marker, with entropy-coded data in between. 38*c8dee2aaSAndroid Build Coastguard Worker */ 39*c8dee2aaSAndroid Build Coastguard Worker class SkJpegSegmentScanner { 40*c8dee2aaSAndroid Build Coastguard Worker public: 41*c8dee2aaSAndroid Build Coastguard Worker SkJpegSegmentScanner(uint8_t stopMarker = kJpegMarkerEndOfImage); 42*c8dee2aaSAndroid Build Coastguard Worker isDone()43*c8dee2aaSAndroid Build Coastguard Worker bool isDone() const { return fState == State::kDone; } hadError()44*c8dee2aaSAndroid Build Coastguard Worker bool hadError() const { return fState == State::kError; } 45*c8dee2aaSAndroid Build Coastguard Worker 46*c8dee2aaSAndroid Build Coastguard Worker // Provide more bytes of data to the state machine. 47*c8dee2aaSAndroid Build Coastguard Worker void onBytes(const void* data, size_t size); 48*c8dee2aaSAndroid Build Coastguard Worker 49*c8dee2aaSAndroid Build Coastguard Worker // Return the segments that have been retrieved so far. If an error was encountered, this will 50*c8dee2aaSAndroid Build Coastguard Worker // include all segments up to the error. 51*c8dee2aaSAndroid Build Coastguard Worker const std::vector<SkJpegSegment>& getSegments() const; 52*c8dee2aaSAndroid Build Coastguard Worker 53*c8dee2aaSAndroid Build Coastguard Worker // Helper function to retrieve the parameters for a segment. ScannedData must be the data that 54*c8dee2aaSAndroid Build Coastguard Worker // was scanned to produce segment, starting at StartOfImage. 55*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkData> GetParameters(const SkData* scannedData, const SkJpegSegment& segment); 56*c8dee2aaSAndroid Build Coastguard Worker 57*c8dee2aaSAndroid Build Coastguard Worker private: 58*c8dee2aaSAndroid Build Coastguard Worker // The scanner is a state machine. State transitions happen when a byte is read. 59*c8dee2aaSAndroid Build Coastguard Worker enum class State { 60*c8dee2aaSAndroid Build Coastguard Worker // The initial state, before we read the 0xFF,0xD8,0xFF JPEG signature. 61*c8dee2aaSAndroid Build Coastguard Worker kStartOfImageByte0, 62*c8dee2aaSAndroid Build Coastguard Worker // We have read the 0xFF of the JPEG signature. 63*c8dee2aaSAndroid Build Coastguard Worker kStartOfImageByte1, 64*c8dee2aaSAndroid Build Coastguard Worker // We have read the 0xFF,0xD8 of the JPEG signature. The next byte should be the 0xFF that 65*c8dee2aaSAndroid Build Coastguard Worker // completes the JPEG signature and starts the second marker (the one after StartOfImage). 66*c8dee2aaSAndroid Build Coastguard Worker kSecondMarkerByte0, 67*c8dee2aaSAndroid Build Coastguard Worker // We have read the full JPEG signature. The next byte should be the the second byte of the 68*c8dee2aaSAndroid Build Coastguard Worker // second marker. 69*c8dee2aaSAndroid Build Coastguard Worker kSecondMarkerByte1, 70*c8dee2aaSAndroid Build Coastguard Worker // We have read a marker that does not stand alone. The next byte is the first byte of the 71*c8dee2aaSAndroid Build Coastguard Worker // length of the parameters, 72*c8dee2aaSAndroid Build Coastguard Worker kSegmentParamLengthByte0, 73*c8dee2aaSAndroid Build Coastguard Worker // We have read the first byte of the length of the parameters (and it is stored in 74*c8dee2aaSAndroid Build Coastguard Worker // |fSegmentParamLengthByte0|). The next byte we read is the second byte of the length of 75*c8dee2aaSAndroid Build Coastguard Worker // the parameters. 76*c8dee2aaSAndroid Build Coastguard Worker kSegmentParamLengthByte1, 77*c8dee2aaSAndroid Build Coastguard Worker // We have read the full length of the parameters. The next |fSegmentParamBytesRemaining| 78*c8dee2aaSAndroid Build Coastguard Worker // bytes are the parameters. 79*c8dee2aaSAndroid Build Coastguard Worker kSegmentParam, 80*c8dee2aaSAndroid Build Coastguard Worker // We have read a marker and (optionally) its parameters, and we are now reading entropy- 81*c8dee2aaSAndroid Build Coastguard Worker // coded data. All subsequent bytes until we reach 0xFF are entropy-coded data. 82*c8dee2aaSAndroid Build Coastguard Worker kEntropyCodedData, 83*c8dee2aaSAndroid Build Coastguard Worker // We reached an 0xFF in entropy-coded data. If the next byte is 0x00 then we continue 84*c8dee2aaSAndroid Build Coastguard Worker // reading entropy-coded data. If the next byte is 0xFF then we are reading fill data. 85*c8dee2aaSAndroid Build Coastguard Worker // If the next byte is anything else then it is the second byte of a marker. 86*c8dee2aaSAndroid Build Coastguard Worker kEntropyCodedDataSentinel, 87*c8dee2aaSAndroid Build Coastguard Worker // We are reading fill data. If the next byte is 0xFF then we are still reading fill data, 88*c8dee2aaSAndroid Build Coastguard Worker // otherwise the next byte is the second byte of a marker. 89*c8dee2aaSAndroid Build Coastguard Worker kPostEntropyCodedDataFill, 90*c8dee2aaSAndroid Build Coastguard Worker // We reached |fStopMarker| and have stopped tracking our state. 91*c8dee2aaSAndroid Build Coastguard Worker kDone, 92*c8dee2aaSAndroid Build Coastguard Worker // We hit an error somewhere and have given up. 93*c8dee2aaSAndroid Build Coastguard Worker kError, 94*c8dee2aaSAndroid Build Coastguard Worker }; 95*c8dee2aaSAndroid Build Coastguard Worker State fState = State::kStartOfImageByte0; 96*c8dee2aaSAndroid Build Coastguard Worker 97*c8dee2aaSAndroid Build Coastguard Worker // Update state transition when a single byte is read. 98*c8dee2aaSAndroid Build Coastguard Worker void onByte(uint8_t byte); 99*c8dee2aaSAndroid Build Coastguard Worker 100*c8dee2aaSAndroid Build Coastguard Worker // Perform the appropriate state transition for when a marker is read. This will set 101*c8dee2aaSAndroid Build Coastguard Worker // |fCurrentSegmentMarker| and |fCurrentSegmentOffset|, and potentially call saveCurrentSegment. 102*c8dee2aaSAndroid Build Coastguard Worker void onMarkerSecondByte(uint8_t byte); 103*c8dee2aaSAndroid Build Coastguard Worker 104*c8dee2aaSAndroid Build Coastguard Worker // Add a new entry in |segments| for |fCurrentSegmentMarker| and offset |fCurrentSegmentOffset| 105*c8dee2aaSAndroid Build Coastguard Worker // and the specified length. 106*c8dee2aaSAndroid Build Coastguard Worker void saveCurrentSegment(uint16_t length); 107*c8dee2aaSAndroid Build Coastguard Worker MarkerStandsAlone(uint8_t marker)108*c8dee2aaSAndroid Build Coastguard Worker static bool MarkerStandsAlone(uint8_t marker) { 109*c8dee2aaSAndroid Build Coastguard Worker // These markers are TEM (0x01), RSTm (0xD0 through 0xD7), SOI (0xD8), and 110*c8dee2aaSAndroid Build Coastguard Worker // EOI (0xD9). See section B.1.1.3, Marker assignments. 111*c8dee2aaSAndroid Build Coastguard Worker return marker == 0x01 || (marker >= 0xD0 && marker <= 0xD9); 112*c8dee2aaSAndroid Build Coastguard Worker } 113*c8dee2aaSAndroid Build Coastguard Worker 114*c8dee2aaSAndroid Build Coastguard Worker // Stop tracking state when we hit this marker. If this is 0x00, then never stop. 115*c8dee2aaSAndroid Build Coastguard Worker const uint8_t fStopMarker; 116*c8dee2aaSAndroid Build Coastguard Worker 117*c8dee2aaSAndroid Build Coastguard Worker // The number of bytes that have been processed so far. 118*c8dee2aaSAndroid Build Coastguard Worker size_t fOffset = 0; 119*c8dee2aaSAndroid Build Coastguard Worker 120*c8dee2aaSAndroid Build Coastguard Worker // If |fState| is kSegmentParamLengthByte1, then this is the value of the the previous byte. 121*c8dee2aaSAndroid Build Coastguard Worker uint8_t fSegmentParamLengthByte0 = 0; 122*c8dee2aaSAndroid Build Coastguard Worker 123*c8dee2aaSAndroid Build Coastguard Worker // If |fState| is kSegmentParam, then this is the number of bytes reamining in the current 124*c8dee2aaSAndroid Build Coastguard Worker // segment. 125*c8dee2aaSAndroid Build Coastguard Worker size_t fSegmentParamBytesRemaining = 0; 126*c8dee2aaSAndroid Build Coastguard Worker 127*c8dee2aaSAndroid Build Coastguard Worker // The offset and marker for the segment started by the previous call to OnMarkerSecondByte. 128*c8dee2aaSAndroid Build Coastguard Worker // These are re-set when SaveCurrentSegment is called. 129*c8dee2aaSAndroid Build Coastguard Worker size_t fCurrentSegmentOffset = 0; 130*c8dee2aaSAndroid Build Coastguard Worker uint8_t fCurrentSegmentMarker = 0; 131*c8dee2aaSAndroid Build Coastguard Worker 132*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkJpegSegment> fSegments; 133*c8dee2aaSAndroid Build Coastguard Worker }; 134*c8dee2aaSAndroid Build Coastguard Worker 135*c8dee2aaSAndroid Build Coastguard Worker #endif 136