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 //#define LOG_NDEBUG 0
18 #define LOG_TAG "JpegCompressor"
19 
20 #include "JpegCompressor.h"
21 
22 #include <camera_blob.h>
23 #include <cutils/properties.h>
24 #include <libyuv.h>
25 #include <ultrahdr/jpegr.h>
26 #include <utils/Log.h>
27 #include <utils/Trace.h>
28 
29 namespace android {
30 
31 using google_camera_hal::CameraBlob;
32 using google_camera_hal::CameraBlobId;
33 using google_camera_hal::ErrorCode;
34 using google_camera_hal::MessageType;
35 using google_camera_hal::NotifyMessage;
36 
37 // All ICC profile data sourced from https://github.com/saucecontrol/Compact-ICC-Profiles
38 static constexpr uint8_t kIccProfileDisplayP3[] = {
39     0x00, 0x00, 0x01, 0xe0, 0x6c, 0x63, 0x6d, 0x73, 0x04, 0x20, 0x00, 0x00,
40     0x6d, 0x6e, 0x74, 0x72, 0x52, 0x47, 0x42, 0x20, 0x58, 0x59, 0x5a, 0x20,
41     0x07, 0xe2, 0x00, 0x03, 0x00, 0x14, 0x00, 0x09, 0x00, 0x0e, 0x00, 0x1d,
42     0x61, 0x63, 0x73, 0x70, 0x4d, 0x53, 0x46, 0x54, 0x00, 0x00, 0x00, 0x00,
43     0x73, 0x61, 0x77, 0x73, 0x63, 0x74, 0x72, 0x6c, 0x00, 0x00, 0x00, 0x00,
44     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xd6,
45     0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d, 0x68, 0x61, 0x6e, 0x64,
46     0x51, 0xb1, 0x0e, 0x57, 0x9c, 0x0c, 0x00, 0x19, 0x38, 0xb9, 0x93, 0x88,
47     0x06, 0x61, 0xb8, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
50     0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x22,
51     0x63, 0x70, 0x72, 0x74, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x22,
52     0x77, 0x74, 0x70, 0x74, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00, 0x00, 0x14,
53     0x63, 0x68, 0x61, 0x64, 0x00, 0x00, 0x01, 0x58, 0x00, 0x00, 0x00, 0x2c,
54     0x72, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x01, 0x84, 0x00, 0x00, 0x00, 0x14,
55     0x67, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x01, 0x98, 0x00, 0x00, 0x00, 0x14,
56     0x62, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x01, 0xac, 0x00, 0x00, 0x00, 0x14,
57     0x72, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x20,
58     0x67, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x20,
59     0x62, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x20,
60     0x6d, 0x6c, 0x75, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
61     0x00, 0x00, 0x00, 0x0c, 0x65, 0x6e, 0x55, 0x53, 0x00, 0x00, 0x00, 0x06,
62     0x00, 0x00, 0x00, 0x1c, 0x00, 0x73, 0x00, 0x50, 0x00, 0x33, 0x00, 0x00,
63     0x6d, 0x6c, 0x75, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
64     0x00, 0x00, 0x00, 0x0c, 0x65, 0x6e, 0x55, 0x53, 0x00, 0x00, 0x00, 0x06,
65     0x00, 0x00, 0x00, 0x1c, 0x00, 0x43, 0x00, 0x43, 0x00, 0x30, 0x00, 0x21,
66     0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xd6,
67     0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d, 0x73, 0x66, 0x33, 0x32,
68     0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0c, 0x42, 0x00, 0x00, 0x05, 0xde,
69     0xff, 0xff, 0xf3, 0x25, 0x00, 0x00, 0x07, 0x93, 0x00, 0x00, 0xfd, 0x90,
70     0xff, 0xff, 0xfb, 0xa1, 0xff, 0xff, 0xfd, 0xa2, 0x00, 0x00, 0x03, 0xdc,
71     0x00, 0x00, 0xc0, 0x6e, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
72     0x00, 0x00, 0x83, 0xdf, 0x00, 0x00, 0x3d, 0xbf, 0xff, 0xff, 0xff, 0xbb,
73     0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0xbf,
74     0x00, 0x00, 0xb1, 0x37, 0x00, 0x00, 0x0a, 0xb9, 0x58, 0x59, 0x5a, 0x20,
75     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x38, 0x00, 0x00, 0x11, 0x0a,
76     0x00, 0x00, 0xc8, 0xb9, 0x70, 0x61, 0x72, 0x61, 0x00, 0x00, 0x00, 0x00,
77     0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x66, 0x69, 0x00, 0x00, 0xf2, 0xa7,
78     0x00, 0x00, 0x0d, 0x59, 0x00, 0x00, 0x13, 0xd0, 0x00, 0x00, 0x0a, 0x5b};
79 
80 static constexpr uint8_t kIccProfileDciP3[] = {
81     0x00, 0x00, 0x01, 0xd0, 0x6c, 0x63, 0x6d, 0x73, 0x04, 0x20, 0x00, 0x00,
82     0x6d, 0x6e, 0x74, 0x72, 0x52, 0x47, 0x42, 0x20, 0x58, 0x59, 0x5a, 0x20,
83     0x07, 0xe5, 0x00, 0x04, 0x00, 0x1b, 0x00, 0x0a, 0x00, 0x1b, 0x00, 0x00,
84     0x61, 0x63, 0x73, 0x70, 0x4d, 0x53, 0x46, 0x54, 0x00, 0x00, 0x00, 0x00,
85     0x73, 0x61, 0x77, 0x73, 0x63, 0x74, 0x72, 0x6c, 0x00, 0x00, 0x00, 0x00,
86     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xd6,
87     0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d, 0x68, 0x61, 0x6e, 0x64,
88     0x79, 0xb3, 0x51, 0x32, 0xc4, 0xd7, 0x5b, 0x84, 0xf1, 0xbb, 0xcb, 0x58,
89     0x53, 0xb0, 0xfa, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
90     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
91     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
92     0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x22,
93     0x63, 0x70, 0x72, 0x74, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x22,
94     0x77, 0x74, 0x70, 0x74, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00, 0x00, 0x14,
95     0x63, 0x68, 0x61, 0x64, 0x00, 0x00, 0x01, 0x58, 0x00, 0x00, 0x00, 0x2c,
96     0x72, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x01, 0x84, 0x00, 0x00, 0x00, 0x14,
97     0x67, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x01, 0x98, 0x00, 0x00, 0x00, 0x14,
98     0x62, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x01, 0xac, 0x00, 0x00, 0x00, 0x14,
99     0x72, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x10,
100     0x67, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x10,
101     0x62, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x10,
102     0x6d, 0x6c, 0x75, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
103     0x00, 0x00, 0x00, 0x0c, 0x65, 0x6e, 0x55, 0x53, 0x00, 0x00, 0x00, 0x06,
104     0x00, 0x00, 0x00, 0x1c, 0x00, 0x54, 0x00, 0x50, 0x00, 0x33, 0x00, 0x00,
105     0x6d, 0x6c, 0x75, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
106     0x00, 0x00, 0x00, 0x0c, 0x65, 0x6e, 0x55, 0x53, 0x00, 0x00, 0x00, 0x06,
107     0x00, 0x00, 0x00, 0x1c, 0x00, 0x43, 0x00, 0x43, 0x00, 0x30, 0x00, 0x21,
108     0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xd6,
109     0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d, 0x73, 0x66, 0x33, 0x32,
110     0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x12, 0xe6, 0x00, 0x00, 0x09, 0xef,
111     0xff, 0xff, 0xf6, 0x8d, 0x00, 0x00, 0x0e, 0x3a, 0x00, 0x00, 0xf6, 0xc8,
112     0xff, 0xff, 0xfc, 0x53, 0xff, 0xff, 0xfe, 0xe7, 0x00, 0x00, 0x01, 0x5b,
113     0x00, 0x00, 0xdc, 0xdf, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
114     0x00, 0x00, 0x7c, 0x75, 0x00, 0x00, 0x3a, 0x08, 0xff, 0xff, 0xff, 0xcc,
115     0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0xe8,
116     0x00, 0x00, 0xb5, 0xd8, 0x00, 0x00, 0x0b, 0x11, 0x58, 0x59, 0x5a, 0x20,
117     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x79, 0x00, 0x00, 0x10, 0x20,
118     0x00, 0x00, 0xc8, 0x50, 0x70, 0x61, 0x72, 0x61, 0x00, 0x00, 0x00, 0x00,
119     0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x99, 0x9a};
120 
121 static constexpr uint8_t kIccProfileSrgb[] = {
122     0x00, 0x00, 0x01, 0xe0, 0x6c, 0x63, 0x6d, 0x73, 0x04, 0x20, 0x00, 0x00,
123     0x6d, 0x6e, 0x74, 0x72, 0x52, 0x47, 0x42, 0x20, 0x58, 0x59, 0x5a, 0x20,
124     0x07, 0xe2, 0x00, 0x03, 0x00, 0x14, 0x00, 0x09, 0x00, 0x0e, 0x00, 0x1d,
125     0x61, 0x63, 0x73, 0x70, 0x4d, 0x53, 0x46, 0x54, 0x00, 0x00, 0x00, 0x00,
126     0x73, 0x61, 0x77, 0x73, 0x63, 0x74, 0x72, 0x6c, 0x00, 0x00, 0x00, 0x00,
127     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xd6,
128     0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d, 0x68, 0x61, 0x6e, 0x64,
129     0xa3, 0xb2, 0xab, 0xdf, 0x5c, 0xa7, 0x03, 0x12, 0xa8, 0x55, 0xa4, 0xec,
130     0x35, 0x7a, 0xd1, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
131     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
133     0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x24,
134     0x63, 0x70, 0x72, 0x74, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x22,
135     0x77, 0x74, 0x70, 0x74, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00, 0x00, 0x14,
136     0x63, 0x68, 0x61, 0x64, 0x00, 0x00, 0x01, 0x58, 0x00, 0x00, 0x00, 0x2c,
137     0x72, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x01, 0x84, 0x00, 0x00, 0x00, 0x14,
138     0x67, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x01, 0x98, 0x00, 0x00, 0x00, 0x14,
139     0x62, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x01, 0xac, 0x00, 0x00, 0x00, 0x14,
140     0x72, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x20,
141     0x67, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x20,
142     0x62, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x20,
143     0x6d, 0x6c, 0x75, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
144     0x00, 0x00, 0x00, 0x0c, 0x65, 0x6e, 0x55, 0x53, 0x00, 0x00, 0x00, 0x08,
145     0x00, 0x00, 0x00, 0x1c, 0x00, 0x73, 0x00, 0x52, 0x00, 0x47, 0x00, 0x42,
146     0x6d, 0x6c, 0x75, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
147     0x00, 0x00, 0x00, 0x0c, 0x65, 0x6e, 0x55, 0x53, 0x00, 0x00, 0x00, 0x06,
148     0x00, 0x00, 0x00, 0x1c, 0x00, 0x43, 0x00, 0x43, 0x00, 0x30, 0x00, 0x21,
149     0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xd6,
150     0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d, 0x73, 0x66, 0x33, 0x32,
151     0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0c, 0x3f, 0x00, 0x00, 0x05, 0xdd,
152     0xff, 0xff, 0xf3, 0x26, 0x00, 0x00, 0x07, 0x90, 0x00, 0x00, 0xfd, 0x92,
153     0xff, 0xff, 0xfb, 0xa1, 0xff, 0xff, 0xfd, 0xa2, 0x00, 0x00, 0x03, 0xdc,
154     0x00, 0x00, 0xc0, 0x71, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
155     0x00, 0x00, 0x6f, 0xa0, 0x00, 0x00, 0x38, 0xf2, 0x00, 0x00, 0x03, 0x8f,
156     0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x96,
157     0x00, 0x00, 0xb7, 0x89, 0x00, 0x00, 0x18, 0xda, 0x58, 0x59, 0x5a, 0x20,
158     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0xa0, 0x00, 0x00, 0x0f, 0x85,
159     0x00, 0x00, 0xb6, 0xc4, 0x70, 0x61, 0x72, 0x61, 0x00, 0x00, 0x00, 0x00,
160     0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x66, 0x69, 0x00, 0x00, 0xf2, 0xa7,
161     0x00, 0x00, 0x0d, 0x59, 0x00, 0x00, 0x13, 0xd0, 0x00, 0x00, 0x0a, 0x5b};
162 
JpegCompressor()163 JpegCompressor::JpegCompressor() {
164   ATRACE_CALL();
165   char value[PROPERTY_VALUE_MAX];
166   if (property_get("ro.product.manufacturer", value, "unknown") <= 0) {
167     ALOGW("%s: No Exif make data!", __FUNCTION__);
168   }
169   exif_make_ = std::string(value);
170 
171   if (property_get("ro.product.model", value, "unknown") <= 0) {
172     ALOGW("%s: No Exif model data!", __FUNCTION__);
173   }
174   exif_model_ = std::string(value);
175 
176   jpeg_processing_thread_ = std::thread([this] { this->ThreadLoop(); });
177 }
178 
~JpegCompressor()179 JpegCompressor::~JpegCompressor() {
180   ATRACE_CALL();
181 
182   // Abort the ongoing compression and flush any pending jobs
183   jpeg_done_ = true;
184   condition_.notify_one();
185   jpeg_processing_thread_.join();
186   while (!pending_yuv_jobs_.empty()) {
187     auto job = std::move(pending_yuv_jobs_.front());
188     job->output->stream_buffer.status = BufferStatus::kError;
189     pending_yuv_jobs_.pop();
190   }
191 }
192 
QueueYUV420(std::unique_ptr<JpegYUV420Job> job)193 status_t JpegCompressor::QueueYUV420(std::unique_ptr<JpegYUV420Job> job) {
194   ATRACE_CALL();
195 
196   if ((job->input.get() == nullptr) || (job->output.get() == nullptr) ||
197       (job->output->format != PixelFormat::BLOB) ||
198       ((job->output->dataSpace !=
199         static_cast<android_dataspace_t>(
200             ::aidl::android::hardware::graphics::common::Dataspace::JPEG_R)) &&
201        (job->output->dataSpace != HAL_DATASPACE_V0_JFIF))) {
202     ALOGE("%s: Unable to find buffers for JPEG source/destination",
203           __FUNCTION__);
204     return BAD_VALUE;
205   }
206 
207   std::unique_lock<std::mutex> lock(mutex_);
208   pending_yuv_jobs_.push(std::move(job));
209   condition_.notify_one();
210 
211   return OK;
212 }
213 
ThreadLoop()214 void JpegCompressor::ThreadLoop() {
215   ATRACE_CALL();
216 
217   while (!jpeg_done_) {
218     std::unique_ptr<JpegYUV420Job> current_yuv_job = nullptr;
219     {
220       std::lock_guard<std::mutex> lock(mutex_);
221       if (!pending_yuv_jobs_.empty()) {
222         current_yuv_job = std::move(pending_yuv_jobs_.front());
223         pending_yuv_jobs_.pop();
224       }
225     }
226 
227     if (current_yuv_job.get() != nullptr) {
228       CompressYUV420(std::move(current_yuv_job));
229     }
230 
231     std::unique_lock<std::mutex> lock(mutex_);
232     auto ret = condition_.wait_for(lock, std::chrono::milliseconds(10));
233     if (ret == std::cv_status::timeout) {
234       ALOGV("%s: Jpeg thread timeout", __FUNCTION__);
235     }
236   }
237 }
238 
CompressYUV420(std::unique_ptr<JpegYUV420Job> job)239 void JpegCompressor::CompressYUV420(std::unique_ptr<JpegYUV420Job> job) {
240   const uint8_t* app1_buffer = nullptr;
241   size_t app1_buffer_size = 0;
242   std::vector<uint8_t> thumbnail_jpeg_buffer;
243   size_t encoded_thumbnail_size = 0;
244   if ((job->exif_utils.get() != nullptr) &&
245       (job->result_metadata.get() != nullptr)) {
246     if (job->exif_utils->Initialize()) {
247       camera_metadata_ro_entry_t entry;
248       size_t thumbnail_width = 0;
249       size_t thumbnail_height = 0;
250       std::vector<uint8_t> thumb_yuv420_frame;
251       YCbCrPlanes thumb_planes;
252       auto ret = job->result_metadata->Get(ANDROID_JPEG_THUMBNAIL_SIZE, &entry);
253       if ((ret == OK) && (entry.count == 2)) {
254         thumbnail_width = entry.data.i32[0];
255         thumbnail_height = entry.data.i32[1];
256         if ((thumbnail_width > 0) && (thumbnail_height > 0)) {
257           thumb_yuv420_frame.resize((thumbnail_width * thumbnail_height * 3) /
258                                     2);
259           thumb_planes = {
260               .img_y = thumb_yuv420_frame.data(),
261               .img_cb = thumb_yuv420_frame.data() +
262                         thumbnail_width * thumbnail_height,
263               .img_cr = thumb_yuv420_frame.data() +
264                         (thumbnail_width * thumbnail_height * 5) / 4,
265               .y_stride = static_cast<uint32_t>(thumbnail_width),
266               .cbcr_stride = static_cast<uint32_t>(thumbnail_width) / 2};
267           // TODO: Crop thumbnail according to documentation
268           auto stat = I420Scale(
269               job->input->yuv_planes.img_y, job->input->yuv_planes.y_stride,
270               job->input->yuv_planes.img_cb, job->input->yuv_planes.cbcr_stride,
271               job->input->yuv_planes.img_cr, job->input->yuv_planes.cbcr_stride,
272               job->input->width, job->input->height, thumb_planes.img_y,
273               thumb_planes.y_stride, thumb_planes.img_cb,
274               thumb_planes.cbcr_stride, thumb_planes.img_cr,
275               thumb_planes.cbcr_stride, thumbnail_width, thumbnail_height,
276               libyuv::kFilterNone);
277           if (stat != 0) {
278             ALOGE("%s: Failed during thumbnail scaling: %d", __FUNCTION__, stat);
279             thumb_yuv420_frame.clear();
280           }
281         }
282       }
283 
284       if (job->exif_utils->SetFromMetadata(
285               *job->result_metadata, job->input->width, job->input->height)) {
286         if (!thumb_yuv420_frame.empty()) {
287           thumbnail_jpeg_buffer.resize(64 * 1024);  // APP1 is limited by 64k
288           encoded_thumbnail_size = CompressYUV420Frame(
289               {.output_buffer = thumbnail_jpeg_buffer.data(),
290                .output_buffer_size = thumbnail_jpeg_buffer.size(),
291                .yuv_planes = thumb_planes,
292                .width = thumbnail_width,
293                .height = thumbnail_height,
294                .app1_buffer = nullptr,
295                .app1_buffer_size = 0,
296                .color_space = job->input->color_space});
297           if (encoded_thumbnail_size > 0) {
298             job->output->stream_buffer.status = BufferStatus::kOk;
299           } else {
300             ALOGE("%s: Failed encoding thumbail!", __FUNCTION__);
301             thumbnail_jpeg_buffer.clear();
302           }
303         }
304 
305         job->exif_utils->SetMake(exif_make_);
306         job->exif_utils->SetModel(exif_model_);
307         job->exif_utils->SetColorSpace(COLOR_SPACE_ICC_PROFILE);
308         if (job->exif_utils->GenerateApp1(thumbnail_jpeg_buffer.empty()
309                                               ? nullptr
310                                               : thumbnail_jpeg_buffer.data(),
311                                           encoded_thumbnail_size)) {
312           app1_buffer = job->exif_utils->GetApp1Buffer();
313           app1_buffer_size = job->exif_utils->GetApp1Length();
314         } else {
315           ALOGE("%s: Unable to generate App1 buffer", __FUNCTION__);
316         }
317       } else {
318         ALOGE("%s: Unable to generate EXIF section!", __FUNCTION__);
319       }
320     } else {
321       ALOGE("%s: Unable to initialize Exif generator!", __FUNCTION__);
322     }
323   }
324 
325   size_t encoded_size = 0;
326   YUV420Frame frame = {.output_buffer = job->output->plane.img.img,
327                        .output_buffer_size = job->output->plane.img.buffer_size,
328                        .yuv_planes = job->input->yuv_planes,
329                        .width = job->input->width,
330                        .height = job->input->height,
331                        .app1_buffer = app1_buffer,
332                        .app1_buffer_size = app1_buffer_size,
333                        .color_space = job->input->color_space};
334   if (job->output->dataSpace ==
335       static_cast<android_dataspace_t>(
336           ::aidl::android::hardware::graphics::common::Dataspace::JPEG_R)) {
337     encoded_size = JpegRCompressYUV420Frame(frame);
338   } else {
339     encoded_size = CompressYUV420Frame(frame);
340   }
341   if (encoded_size > 0) {
342     job->output->stream_buffer.status = BufferStatus::kOk;
343   } else {
344     job->output->stream_buffer.status = BufferStatus::kError;
345     return;
346   }
347 
348   auto jpeg_header_offset =
349       job->output->plane.img.buffer_size - sizeof(struct CameraBlob);
350   if (jpeg_header_offset > encoded_size) {
351     struct CameraBlob* blob = reinterpret_cast<struct CameraBlob*>(
352         job->output->plane.img.img + jpeg_header_offset);
353     blob->blob_id = CameraBlobId::JPEG;
354     blob->blob_size = encoded_size;
355   } else {
356     ALOGW("%s: No space for jpeg header at offset: %u and jpeg size: %u",
357           __FUNCTION__, static_cast<unsigned>(jpeg_header_offset),
358           static_cast<unsigned>(encoded_size));
359   }
360 }
361 
JpegRCompressYUV420Frame(YUV420Frame p010_frame)362 size_t JpegCompressor::JpegRCompressYUV420Frame(YUV420Frame p010_frame) {
363   ATRACE_CALL();
364 
365   ultrahdr::jpegr_uncompressed_struct p010;
366   ultrahdr::jpegr_compressed_struct jpeg_r;
367   ultrahdr::JpegR jpeg_r_encoder;
368 
369   p010.height = p010_frame.height;
370   p010.width = p010_frame.width;
371   p010.colorGamut = ultrahdr::ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100;
372   p010.data = p010_frame.yuv_planes.img_y;
373   p010.chroma_data = p010_frame.yuv_planes.img_cb;
374   // Strides are expected to be in pixels not bytes
375   p010.luma_stride = p010_frame.yuv_planes.y_stride / 2;
376   p010.chroma_stride = p010_frame.yuv_planes.cbcr_stride / 2;
377 
378   jpeg_r.data = p010_frame.output_buffer;
379   jpeg_r.maxLength = p010_frame.output_buffer_size;
380 
381   ultrahdr::ultrahdr_transfer_function transferFunction =
382       ultrahdr::ultrahdr_transfer_function::ULTRAHDR_TF_HLG;
383 
384   ultrahdr::jpegr_exif_struct exif;
385   exif.data =
386       reinterpret_cast<void*>(const_cast<uint8_t*>(p010_frame.app1_buffer));
387   exif.length = p010_frame.app1_buffer_size;
388 
389   auto res = jpeg_r_encoder.encodeJPEGR(&p010, transferFunction, &jpeg_r,
390                                         /*jpegQuality*/ 100, &exif);
391   if (res != OK) {
392     ALOGE("%s: Error trying to encode JPEG/R: %s (%d)", __FUNCTION__,
393           strerror(-res), res);
394     return 0;
395   }
396 
397   return jpeg_r.length;
398 }
399 
CompressYUV420Frame(YUV420Frame frame)400 size_t JpegCompressor::CompressYUV420Frame(YUV420Frame frame) {
401   ATRACE_CALL();
402 
403   struct CustomJpegDestMgr : public jpeg_destination_mgr {
404     JOCTET* buffer;
405     size_t buffer_size;
406     size_t encoded_size;
407     bool success;
408   } dmgr;
409 
410   // Set up error management
411   jpeg_error_info_ = NULL;
412   jpeg_error_mgr jerr;
413 
414   auto cinfo = std::make_unique<jpeg_compress_struct>();
415   cinfo->err = jpeg_std_error(&jerr);
416   cinfo->err->error_exit = [](j_common_ptr cinfo) {
417     (*cinfo->err->output_message)(cinfo);
418     if (cinfo->client_data) {
419       auto& dmgr = *static_cast<CustomJpegDestMgr*>(cinfo->client_data);
420       dmgr.success = false;
421     }
422   };
423 
424   jpeg_create_compress(cinfo.get());
425   if (CheckError("Error initializing compression")) {
426     return 0;
427   }
428 
429   dmgr.buffer = static_cast<JOCTET*>(frame.output_buffer);
430   dmgr.buffer_size = frame.output_buffer_size;
431   dmgr.encoded_size = 0;
432   dmgr.success = true;
433   cinfo->client_data = static_cast<void*>(&dmgr);
434   dmgr.init_destination = [](j_compress_ptr cinfo) {
435     auto& dmgr = static_cast<CustomJpegDestMgr&>(*cinfo->dest);
436     dmgr.next_output_byte = dmgr.buffer;
437     dmgr.free_in_buffer = dmgr.buffer_size;
438     ALOGV("%s:%d jpeg start: %p [%zu]", __FUNCTION__, __LINE__, dmgr.buffer,
439           dmgr.buffer_size);
440   };
441 
442   dmgr.empty_output_buffer = [](j_compress_ptr) {
443     ALOGE("%s:%d Out of buffer", __FUNCTION__, __LINE__);
444     return 0;
445   };
446 
447   dmgr.term_destination = [](j_compress_ptr cinfo) {
448     auto& dmgr = static_cast<CustomJpegDestMgr&>(*cinfo->dest);
449     dmgr.encoded_size = dmgr.buffer_size - dmgr.free_in_buffer;
450     ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__,
451           dmgr.encoded_size);
452   };
453 
454   cinfo->dest = reinterpret_cast<struct jpeg_destination_mgr*>(&dmgr);
455 
456   // Set up compression parameters
457   cinfo->image_width = frame.width;
458   cinfo->image_height = frame.height;
459   cinfo->input_components = 3;
460   cinfo->in_color_space = JCS_YCbCr;
461 
462   jpeg_set_defaults(cinfo.get());
463   if (CheckError("Error configuring defaults")) {
464     return 0;
465   }
466 
467   jpeg_set_colorspace(cinfo.get(), JCS_YCbCr);
468   if (CheckError("Error configuring color space")) {
469     return 0;
470   }
471 
472   cinfo->raw_data_in = 1;
473   // YUV420 planar with chroma subsampling
474   cinfo->comp_info[0].h_samp_factor = 2;
475   cinfo->comp_info[0].v_samp_factor = 2;
476   cinfo->comp_info[1].h_samp_factor = 1;
477   cinfo->comp_info[1].v_samp_factor = 1;
478   cinfo->comp_info[2].h_samp_factor = 1;
479   cinfo->comp_info[2].v_samp_factor = 1;
480 
481   int max_vsamp_factor = std::max({cinfo->comp_info[0].v_samp_factor,
482                                    cinfo->comp_info[1].v_samp_factor,
483                                    cinfo->comp_info[2].v_samp_factor});
484   int c_vsub_sampling =
485       cinfo->comp_info[0].v_samp_factor / cinfo->comp_info[1].v_samp_factor;
486 
487   // Start compression
488   jpeg_start_compress(cinfo.get(), TRUE);
489   if (CheckError("Error starting compression")) {
490     return 0;
491   }
492 
493   if ((frame.app1_buffer != nullptr) && (frame.app1_buffer_size > 0)) {
494     jpeg_write_marker(cinfo.get(), JPEG_APP0 + 1,
495                       static_cast<const JOCTET*>(frame.app1_buffer),
496                       frame.app1_buffer_size);
497   }
498 
499   const uint8_t* icc_profile = nullptr;
500   size_t icc_profile_size = 0;
501   switch (frame.color_space) {
502     case 0:  // sRGB
503       icc_profile = kIccProfileSrgb;
504       icc_profile_size = std::size(kIccProfileSrgb);
505       break;
506     case 7:  // DISPLAY_P3
507       icc_profile = kIccProfileDisplayP3;
508       icc_profile_size = std::size(kIccProfileDisplayP3);
509       break;
510     case 6:  // DCI_P3
511       icc_profile = kIccProfileDciP3;
512       icc_profile_size = std::size(kIccProfileDciP3);
513       break;
514   }
515 
516   if (icc_profile != nullptr && icc_profile_size > 0) {
517     jpeg_write_icc_profile(cinfo.get(), static_cast<const JOCTET*>(icc_profile),
518                            icc_profile_size);
519   }
520 
521   // Compute our macroblock height, so we can pad our input to be vertically
522   // macroblock aligned.
523 
524   size_t mcu_v = DCTSIZE * max_vsamp_factor;
525   size_t padded_height = mcu_v * ((cinfo->image_height + mcu_v - 1) / mcu_v);
526 
527   std::vector<JSAMPROW> y_lines(padded_height);
528   std::vector<JSAMPROW> cb_lines(padded_height / c_vsub_sampling);
529   std::vector<JSAMPROW> cr_lines(padded_height / c_vsub_sampling);
530 
531   uint8_t* py = static_cast<uint8_t*>(frame.yuv_planes.img_y);
532   uint8_t* pcr = static_cast<uint8_t*>(frame.yuv_planes.img_cr);
533   uint8_t* pcb = static_cast<uint8_t*>(frame.yuv_planes.img_cb);
534 
535   for (uint32_t i = 0; i < padded_height; i++) {
536     /* Once we are in the padding territory we still point to the last line
537      * effectively replicating it several times ~ CLAMP_TO_EDGE */
538     int li = std::min(i, cinfo->image_height - 1);
539     y_lines[i] = static_cast<JSAMPROW>(py + li * frame.yuv_planes.y_stride);
540     if (i < padded_height / c_vsub_sampling) {
541       li = std::min(i, (cinfo->image_height - 1) / c_vsub_sampling);
542       cr_lines[i] =
543           static_cast<JSAMPROW>(pcr + li * frame.yuv_planes.cbcr_stride);
544       cb_lines[i] =
545           static_cast<JSAMPROW>(pcb + li * frame.yuv_planes.cbcr_stride);
546     }
547   }
548 
549   const uint32_t batch_size = DCTSIZE * max_vsamp_factor;
550   while (cinfo->next_scanline < cinfo->image_height) {
551     JSAMPARRAY planes[3]{&y_lines[cinfo->next_scanline],
552                          &cb_lines[cinfo->next_scanline / c_vsub_sampling],
553                          &cr_lines[cinfo->next_scanline / c_vsub_sampling]};
554 
555     jpeg_write_raw_data(cinfo.get(), planes, batch_size);
556     if (CheckError("Error while compressing")) {
557       return 0;
558     }
559 
560     if (jpeg_done_) {
561       ALOGV("%s: Cancel called, exiting early", __FUNCTION__);
562       jpeg_finish_compress(cinfo.get());
563       return 0;
564     }
565   }
566 
567   jpeg_finish_compress(cinfo.get());
568   if (CheckError("Error while finishing compression")) {
569     return 0;
570   }
571 
572   return dmgr.encoded_size;
573 }
574 
CheckError(const char * msg)575 bool JpegCompressor::CheckError(const char* msg) {
576   if (jpeg_error_info_) {
577     char err_buffer[JMSG_LENGTH_MAX];
578     jpeg_error_info_->err->format_message(jpeg_error_info_, err_buffer);
579     ALOGE("%s: %s: %s", __FUNCTION__, msg, err_buffer);
580     jpeg_error_info_ = NULL;
581     return true;
582   }
583 
584   return false;
585 }
586 
587 }  // namespace android
588