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 #include <stdio.h>
23 extern "C" {
24 #include <jpeglib.h>
25 #include <jerror.h>
26 }
27 
28 #include <utils/Errors.h>
29 #include <vector>
30 
31 #include "../utils/ExifUtils.h"
32 
33 struct _ExifData;
34 typedef _ExifData ExifData;
35 
36 class NV12Compressor {
37 public:
NV12Compressor()38     NV12Compressor() {}
39 
40     /* Compress |data| which represents raw NV21 encoded data of dimensions
41      * |width| * |height|.
42      */
43     bool compress(const unsigned char* data, int width, int height, int quality);
44     bool compressWithExifOrientation(const unsigned char* data, int width, int height, int quality,
45             android::camera3::ExifOrientation exifValue);
46 
47     /* Get a reference to the compressed data, this will return an empty vector
48      * if compress has not been called yet
49      */
50     const std::vector<unsigned char>& getCompressedData() const;
51 
52     // Utility methods
53     static android::status_t findJpegSize(uint8_t *jpegBuffer, size_t maxSize,
54             size_t *size /*out*/);
55 
56     static android::status_t getExifOrientation(uint8_t *jpegBuffer,
57             size_t jpegBufferSize, android::camera3::ExifOrientation *exifValue /*out*/);
58 
59     /* Get Jpeg image dimensions from the first Start Of Frame. Please note that due to the
60      * way the jpeg buffer is scanned if the image contains a thumbnail, then the size returned
61      * will be of the thumbnail and not the main image.
62      */
63     static android::status_t getJpegImageDimensions(uint8_t *jpegBuffer, size_t jpegBufferSize,
64             size_t *width /*out*/, size_t *height /*out*/);
65 
66 private:
67 
68     struct DestinationManager : jpeg_destination_mgr {
69         DestinationManager();
70 
71         static void initDestination(j_compress_ptr cinfo);
72         static boolean emptyOutputBuffer(j_compress_ptr cinfo);
73         static void termDestination(j_compress_ptr cinfo);
74 
75         std::vector<unsigned char> mBuffer;
76     };
77 
78     struct ErrorManager : jpeg_error_mgr {
79         ErrorManager();
80 
81         static void onJpegError(j_common_ptr cinfo);
82 
83         jmp_buf mJumpBuffer;
84     };
85 
86     static const size_t kMarkerLength = 2; // length of a marker
87     static const uint8_t kMarker = 0xFF; // First byte of marker
88     static const uint8_t kStartOfImage = 0xD8; // Start of Image
89     static const uint8_t kEndOfImage = 0xD9; // End of Image
90     static const uint8_t kStartOfFrame = 0xC0; // Start of Frame
91 
92     struct __attribute__((packed)) segment_t {
93         uint8_t marker[kMarkerLength];
94         uint16_t length;
95     };
96 
97     struct __attribute__((packed)) sof_t {
98         uint16_t length;
99         uint8_t precision;
100         uint16_t height;
101         uint16_t width;
102     };
103 
104     // check for start of image marker
checkStartOfFrame(uint8_t * buf)105     static bool checkStartOfFrame(uint8_t* buf) {
106         return buf[0] == kMarker && buf[1] == kStartOfFrame;
107     }
108 
109     // check for start of image marker
checkJpegStart(uint8_t * buf)110     static bool checkJpegStart(uint8_t* buf) {
111         return buf[0] == kMarker && buf[1] == kStartOfImage;
112     }
113 
114     // check for End of Image marker
checkJpegEnd(uint8_t * buf)115     static bool checkJpegEnd(uint8_t *buf) {
116         return buf[0] == kMarker && buf[1] == kEndOfImage;
117     }
118 
119     // check for arbitrary marker, returns marker type (second byte)
120     // returns 0 if no marker found. Note: 0x00 is not a valid marker type
checkJpegMarker(uint8_t * buf)121     static uint8_t checkJpegMarker(uint8_t *buf) {
122         return (buf[0] == kMarker) ? buf[1] : 0;
123     }
124 
125     jpeg_compress_struct mCompressInfo;
126     DestinationManager mDestManager;
127     ErrorManager mErrorManager;
128 
129     bool configureCompressor(int width, int height, int quality);
130     bool compressData(const unsigned char* data, ExifData* exifData);
131     bool attachExifData(ExifData* exifData);
132 };
133 
134 #endif  // TEST_CAMERA_JPEG_STUB_NV12_COMPRESSOR_H
135 
136