1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef TEST_CAMERA_JPEG_STUB_NV12_COMPRESSOR_H
18 #define TEST_CAMERA_JPEG_STUB_NV12_COMPRESSOR_H
19 
20 #include <setjmp.h>
21 #include <stdlib.h>
22 extern "C" {
23 #include <jpeglib.h>
24 #include <jerror.h>
25 }
26 
27 #include <utils/Errors.h>
28 #include <vector>
29 
30 #include "../utils/ExifUtils.h"
31 
32 struct _ExifData;
33 typedef _ExifData ExifData;
34 
35 class NV12Compressor {
36 public:
NV12Compressor()37     NV12Compressor() {}
38 
39     /* Compress |data| which represents raw NV21 encoded data of dimensions
40      * |width| * |height|.
41      */
42     bool compress(const unsigned char* data, int width, int height, int quality);
43     bool compressWithExifOrientation(const unsigned char* data, int width, int height, int quality,
44             android::camera3::ExifOrientation exifValue);
45 
46     /* Get a reference to the compressed data, this will return an empty vector
47      * if compress has not been called yet
48      */
49     const std::vector<unsigned char>& getCompressedData() const;
50 
51     // Utility methods
52     static android::status_t findJpegSize(uint8_t *jpegBuffer, size_t maxSize,
53             size_t *size /*out*/);
54 
55     static android::status_t getExifOrientation(uint8_t *jpegBuffer,
56             size_t jpegBufferSize, android::camera3::ExifOrientation *exifValue /*out*/);
57 
58     /* Get Jpeg image dimensions from the first Start Of Frame. Please note that due to the
59      * way the jpeg buffer is scanned if the image contains a thumbnail, then the size returned
60      * will be of the thumbnail and not the main image.
61      */
62     static android::status_t getJpegImageDimensions(uint8_t *jpegBuffer, size_t jpegBufferSize,
63             size_t *width /*out*/, size_t *height /*out*/);
64 
65 private:
66 
67     struct DestinationManager : jpeg_destination_mgr {
68         DestinationManager();
69 
70         static void initDestination(j_compress_ptr cinfo);
71         static boolean emptyOutputBuffer(j_compress_ptr cinfo);
72         static void termDestination(j_compress_ptr cinfo);
73 
74         std::vector<unsigned char> mBuffer;
75     };
76 
77     struct ErrorManager : jpeg_error_mgr {
78         ErrorManager();
79 
80         static void onJpegError(j_common_ptr cinfo);
81 
82         jmp_buf mJumpBuffer;
83     };
84 
85     static const size_t kMarkerLength = 2; // length of a marker
86     static const uint8_t kMarker = 0xFF; // First byte of marker
87     static const uint8_t kStartOfImage = 0xD8; // Start of Image
88     static const uint8_t kEndOfImage = 0xD9; // End of Image
89     static const uint8_t kStartOfFrame = 0xC0; // Start of Frame
90 
91     struct __attribute__((packed)) segment_t {
92         uint8_t marker[kMarkerLength];
93         uint16_t length;
94     };
95 
96     struct __attribute__((packed)) sof_t {
97         uint16_t length;
98         uint8_t precision;
99         uint16_t height;
100         uint16_t width;
101     };
102 
103     // check for start of image marker
checkStartOfFrame(uint8_t * buf)104     static bool checkStartOfFrame(uint8_t* buf) {
105         return buf[0] == kMarker && buf[1] == kStartOfFrame;
106     }
107 
108     // check for start of image marker
checkJpegStart(uint8_t * buf)109     static bool checkJpegStart(uint8_t* buf) {
110         return buf[0] == kMarker && buf[1] == kStartOfImage;
111     }
112 
113     // check for End of Image marker
checkJpegEnd(uint8_t * buf)114     static bool checkJpegEnd(uint8_t *buf) {
115         return buf[0] == kMarker && buf[1] == kEndOfImage;
116     }
117 
118     // check for arbitrary marker, returns marker type (second byte)
119     // returns 0 if no marker found. Note: 0x00 is not a valid marker type
checkJpegMarker(uint8_t * buf)120     static uint8_t checkJpegMarker(uint8_t *buf) {
121         return (buf[0] == kMarker) ? buf[1] : 0;
122     }
123 
124     jpeg_compress_struct mCompressInfo;
125     DestinationManager mDestManager;
126     ErrorManager mErrorManager;
127 
128     bool configureCompressor(int width, int height, int quality);
129     bool compressData(const unsigned char* data, ExifData* exifData);
130     bool attachExifData(ExifData* exifData);
131 };
132 
133 #endif  // TEST_CAMERA_JPEG_STUB_NV12_COMPRESSOR_H
134 
135