xref: /aosp_15_r20/cts/tests/camera/libctscamera2jni/dng-validate-jni.cpp (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
1*b7c941bbSAndroid Build Coastguard Worker /*
2*b7c941bbSAndroid Build Coastguard Worker  * Copyright (C) 2016 The Android Open Source Project
3*b7c941bbSAndroid Build Coastguard Worker  *
4*b7c941bbSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*b7c941bbSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*b7c941bbSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*b7c941bbSAndroid Build Coastguard Worker  *
8*b7c941bbSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*b7c941bbSAndroid Build Coastguard Worker  *
10*b7c941bbSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*b7c941bbSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*b7c941bbSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*b7c941bbSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*b7c941bbSAndroid Build Coastguard Worker  * limitations under the License.
15*b7c941bbSAndroid Build Coastguard Worker  */
16*b7c941bbSAndroid Build Coastguard Worker 
17*b7c941bbSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
18*b7c941bbSAndroid Build Coastguard Worker #define LOG_TAG "DngValidateCamera"
19*b7c941bbSAndroid Build Coastguard Worker #include <log/log.h>
20*b7c941bbSAndroid Build Coastguard Worker #include <jni.h>
21*b7c941bbSAndroid Build Coastguard Worker 
22*b7c941bbSAndroid Build Coastguard Worker #include <string>
23*b7c941bbSAndroid Build Coastguard Worker #include <sstream>
24*b7c941bbSAndroid Build Coastguard Worker #include <iostream>
25*b7c941bbSAndroid Build Coastguard Worker 
26*b7c941bbSAndroid Build Coastguard Worker /**
27*b7c941bbSAndroid Build Coastguard Worker  * Use DNG SDK to validate captured DNG file.
28*b7c941bbSAndroid Build Coastguard Worker  *
29*b7c941bbSAndroid Build Coastguard Worker  * This code is largely based on the dng_validate.cpp implementation included
30*b7c941bbSAndroid Build Coastguard Worker  * with the DNG SDK. The portions of this file that are from the DNG SDK are
31*b7c941bbSAndroid Build Coastguard Worker  * covered by the the DNG SDK license in /external/dng_sdk/LICENSE
32*b7c941bbSAndroid Build Coastguard Worker  */
33*b7c941bbSAndroid Build Coastguard Worker 
34*b7c941bbSAndroid Build Coastguard Worker #include "dng_color_space.h"
35*b7c941bbSAndroid Build Coastguard Worker #include "dng_date_time.h"
36*b7c941bbSAndroid Build Coastguard Worker #include "dng_exceptions.h"
37*b7c941bbSAndroid Build Coastguard Worker #include "dng_file_stream.h"
38*b7c941bbSAndroid Build Coastguard Worker #include "dng_globals.h"
39*b7c941bbSAndroid Build Coastguard Worker #include "dng_host.h"
40*b7c941bbSAndroid Build Coastguard Worker #include "dng_ifd.h"
41*b7c941bbSAndroid Build Coastguard Worker #include "dng_image_writer.h"
42*b7c941bbSAndroid Build Coastguard Worker #include "dng_info.h"
43*b7c941bbSAndroid Build Coastguard Worker #include "dng_linearization_info.h"
44*b7c941bbSAndroid Build Coastguard Worker #include "dng_mosaic_info.h"
45*b7c941bbSAndroid Build Coastguard Worker #include "dng_negative.h"
46*b7c941bbSAndroid Build Coastguard Worker #include "dng_preview.h"
47*b7c941bbSAndroid Build Coastguard Worker #include "dng_render.h"
48*b7c941bbSAndroid Build Coastguard Worker #include "dng_simple_image.h"
49*b7c941bbSAndroid Build Coastguard Worker #include "dng_tag_codes.h"
50*b7c941bbSAndroid Build Coastguard Worker #include "dng_tag_types.h"
51*b7c941bbSAndroid Build Coastguard Worker #include "dng_tag_values.h"
52*b7c941bbSAndroid Build Coastguard Worker 
53*b7c941bbSAndroid Build Coastguard Worker // Version of DNG validate referenced for this implementation
54*b7c941bbSAndroid Build Coastguard Worker #define kDNGValidateVersion "1.4"
55*b7c941bbSAndroid Build Coastguard Worker 
56*b7c941bbSAndroid Build Coastguard Worker static bool gFourColorBayer = false;
57*b7c941bbSAndroid Build Coastguard Worker 
58*b7c941bbSAndroid Build Coastguard Worker static int32 gMosaicPlane = -1;
59*b7c941bbSAndroid Build Coastguard Worker 
60*b7c941bbSAndroid Build Coastguard Worker static uint32 gPreferredSize = 0;
61*b7c941bbSAndroid Build Coastguard Worker static uint32 gMinimumSize   = 0;
62*b7c941bbSAndroid Build Coastguard Worker static uint32 gMaximumSize   = 0;
63*b7c941bbSAndroid Build Coastguard Worker 
64*b7c941bbSAndroid Build Coastguard Worker static uint32 gProxyDNGSize = 0;
65*b7c941bbSAndroid Build Coastguard Worker 
66*b7c941bbSAndroid Build Coastguard Worker static const dng_color_space *gFinalSpace = &dng_space_sRGB::Get();
67*b7c941bbSAndroid Build Coastguard Worker 
68*b7c941bbSAndroid Build Coastguard Worker static uint32 gFinalPixelType = ttByte;
69*b7c941bbSAndroid Build Coastguard Worker 
70*b7c941bbSAndroid Build Coastguard Worker static dng_string gDumpStage1;
71*b7c941bbSAndroid Build Coastguard Worker static dng_string gDumpStage2;
72*b7c941bbSAndroid Build Coastguard Worker static dng_string gDumpStage3;
73*b7c941bbSAndroid Build Coastguard Worker static dng_string gDumpTIF;
74*b7c941bbSAndroid Build Coastguard Worker static dng_string gDumpDNG;
75*b7c941bbSAndroid Build Coastguard Worker 
76*b7c941bbSAndroid Build Coastguard Worker /**
77*b7c941bbSAndroid Build Coastguard Worker  * Validate DNG file in provided buffer.
78*b7c941bbSAndroid Build Coastguard Worker  *
79*b7c941bbSAndroid Build Coastguard Worker  * Returns dng_error_none (0) on success, otherwise one of the
80*b7c941bbSAndroid Build Coastguard Worker  * dng_error_code enum values is returned.
81*b7c941bbSAndroid Build Coastguard Worker  *
82*b7c941bbSAndroid Build Coastguard Worker  * Warnings and errors found during validation are printed to stderr
83*b7c941bbSAndroid Build Coastguard Worker  */
dng_validate(const void * data,uint32_t count)84*b7c941bbSAndroid Build Coastguard Worker static dng_error_code dng_validate(const void* data, uint32_t count) {
85*b7c941bbSAndroid Build Coastguard Worker 
86*b7c941bbSAndroid Build Coastguard Worker     ALOGI("Validating DNG buffer");
87*b7c941bbSAndroid Build Coastguard Worker 
88*b7c941bbSAndroid Build Coastguard Worker     try {
89*b7c941bbSAndroid Build Coastguard Worker         dng_stream stream(data, count);
90*b7c941bbSAndroid Build Coastguard Worker 
91*b7c941bbSAndroid Build Coastguard Worker         dng_host host;
92*b7c941bbSAndroid Build Coastguard Worker 
93*b7c941bbSAndroid Build Coastguard Worker         host.SetPreferredSize(gPreferredSize);
94*b7c941bbSAndroid Build Coastguard Worker         host.SetMinimumSize(gMinimumSize);
95*b7c941bbSAndroid Build Coastguard Worker         host.SetMaximumSize(gMaximumSize);
96*b7c941bbSAndroid Build Coastguard Worker 
97*b7c941bbSAndroid Build Coastguard Worker         host.ValidateSizes();
98*b7c941bbSAndroid Build Coastguard Worker 
99*b7c941bbSAndroid Build Coastguard Worker         if (host.MinimumSize()) {
100*b7c941bbSAndroid Build Coastguard Worker             host.SetForPreview(true);
101*b7c941bbSAndroid Build Coastguard Worker             gDumpDNG.Clear();
102*b7c941bbSAndroid Build Coastguard Worker         }
103*b7c941bbSAndroid Build Coastguard Worker 
104*b7c941bbSAndroid Build Coastguard Worker         if (gDumpDNG.NotEmpty()) {
105*b7c941bbSAndroid Build Coastguard Worker             host.SetSaveDNGVersion(dngVersion_SaveDefault);
106*b7c941bbSAndroid Build Coastguard Worker             host.SetSaveLinearDNG(false);
107*b7c941bbSAndroid Build Coastguard Worker             host.SetKeepOriginalFile(false);
108*b7c941bbSAndroid Build Coastguard Worker         }
109*b7c941bbSAndroid Build Coastguard Worker 
110*b7c941bbSAndroid Build Coastguard Worker         // Read into the negative.
111*b7c941bbSAndroid Build Coastguard Worker 
112*b7c941bbSAndroid Build Coastguard Worker         AutoPtr<dng_negative> negative;
113*b7c941bbSAndroid Build Coastguard Worker         {
114*b7c941bbSAndroid Build Coastguard Worker             dng_info info;
115*b7c941bbSAndroid Build Coastguard Worker             info.Parse(host, stream);
116*b7c941bbSAndroid Build Coastguard Worker             info.PostParse(host);
117*b7c941bbSAndroid Build Coastguard Worker             if (!info.IsValidDNG()) {
118*b7c941bbSAndroid Build Coastguard Worker                 return dng_error_bad_format;
119*b7c941bbSAndroid Build Coastguard Worker             }
120*b7c941bbSAndroid Build Coastguard Worker 
121*b7c941bbSAndroid Build Coastguard Worker             negative.Reset(host.Make_dng_negative());
122*b7c941bbSAndroid Build Coastguard Worker             negative->Parse(host, stream, info);
123*b7c941bbSAndroid Build Coastguard Worker             negative->PostParse(host, stream, info);
124*b7c941bbSAndroid Build Coastguard Worker 
125*b7c941bbSAndroid Build Coastguard Worker             {
126*b7c941bbSAndroid Build Coastguard Worker                 dng_timer timer("Raw image read time");
127*b7c941bbSAndroid Build Coastguard Worker                 negative->ReadStage1Image(host, stream, info);
128*b7c941bbSAndroid Build Coastguard Worker             }
129*b7c941bbSAndroid Build Coastguard Worker 
130*b7c941bbSAndroid Build Coastguard Worker             if (info.fMaskIndex != -1) {
131*b7c941bbSAndroid Build Coastguard Worker                 dng_timer timer("Transparency mask read time");
132*b7c941bbSAndroid Build Coastguard Worker                 negative->ReadTransparencyMask(host, stream, info);
133*b7c941bbSAndroid Build Coastguard Worker             }
134*b7c941bbSAndroid Build Coastguard Worker 
135*b7c941bbSAndroid Build Coastguard Worker             negative->ValidateRawImageDigest(host);
136*b7c941bbSAndroid Build Coastguard Worker         }
137*b7c941bbSAndroid Build Coastguard Worker 
138*b7c941bbSAndroid Build Coastguard Worker         // Option to write stage 1 image.
139*b7c941bbSAndroid Build Coastguard Worker 
140*b7c941bbSAndroid Build Coastguard Worker         if (gDumpStage1.NotEmpty()) {
141*b7c941bbSAndroid Build Coastguard Worker             dng_file_stream stream2 (gDumpStage1.Get(), true);
142*b7c941bbSAndroid Build Coastguard Worker             const dng_image &stage1 = *negative->Stage1Image();
143*b7c941bbSAndroid Build Coastguard Worker             dng_image_writer writer;
144*b7c941bbSAndroid Build Coastguard Worker 
145*b7c941bbSAndroid Build Coastguard Worker             writer.WriteTIFF(host,
146*b7c941bbSAndroid Build Coastguard Worker                     stream2,
147*b7c941bbSAndroid Build Coastguard Worker                     stage1,
148*b7c941bbSAndroid Build Coastguard Worker                     stage1.Planes() >= 3 ? piRGB
149*b7c941bbSAndroid Build Coastguard Worker                     : piBlackIsZero);
150*b7c941bbSAndroid Build Coastguard Worker 
151*b7c941bbSAndroid Build Coastguard Worker             gDumpStage1.Clear();
152*b7c941bbSAndroid Build Coastguard Worker         }
153*b7c941bbSAndroid Build Coastguard Worker 
154*b7c941bbSAndroid Build Coastguard Worker         // Metadata.
155*b7c941bbSAndroid Build Coastguard Worker 
156*b7c941bbSAndroid Build Coastguard Worker         negative->SynchronizeMetadata();
157*b7c941bbSAndroid Build Coastguard Worker 
158*b7c941bbSAndroid Build Coastguard Worker         // Four color Bayer option.
159*b7c941bbSAndroid Build Coastguard Worker 
160*b7c941bbSAndroid Build Coastguard Worker         if (gFourColorBayer) {
161*b7c941bbSAndroid Build Coastguard Worker             negative->SetFourColorBayer();
162*b7c941bbSAndroid Build Coastguard Worker         }
163*b7c941bbSAndroid Build Coastguard Worker 
164*b7c941bbSAndroid Build Coastguard Worker         // Build stage 2 image.
165*b7c941bbSAndroid Build Coastguard Worker 
166*b7c941bbSAndroid Build Coastguard Worker         {
167*b7c941bbSAndroid Build Coastguard Worker             dng_timer timer("Linearization time");
168*b7c941bbSAndroid Build Coastguard Worker             negative->BuildStage2Image(host);
169*b7c941bbSAndroid Build Coastguard Worker         }
170*b7c941bbSAndroid Build Coastguard Worker 
171*b7c941bbSAndroid Build Coastguard Worker         if (gDumpStage2.NotEmpty()) {
172*b7c941bbSAndroid Build Coastguard Worker             dng_file_stream stream2(gDumpStage2.Get(), true);
173*b7c941bbSAndroid Build Coastguard Worker             const dng_image &stage2 = *negative->Stage2Image();
174*b7c941bbSAndroid Build Coastguard Worker             dng_image_writer writer;
175*b7c941bbSAndroid Build Coastguard Worker 
176*b7c941bbSAndroid Build Coastguard Worker             writer.WriteTIFF (host,
177*b7c941bbSAndroid Build Coastguard Worker                     stream2,
178*b7c941bbSAndroid Build Coastguard Worker                     stage2,
179*b7c941bbSAndroid Build Coastguard Worker                     stage2.Planes() >= 3 ? piRGB
180*b7c941bbSAndroid Build Coastguard Worker                     : piBlackIsZero);
181*b7c941bbSAndroid Build Coastguard Worker 
182*b7c941bbSAndroid Build Coastguard Worker             gDumpStage2.Clear();
183*b7c941bbSAndroid Build Coastguard Worker         }
184*b7c941bbSAndroid Build Coastguard Worker 
185*b7c941bbSAndroid Build Coastguard Worker         // Build stage 3 image.
186*b7c941bbSAndroid Build Coastguard Worker 
187*b7c941bbSAndroid Build Coastguard Worker         {
188*b7c941bbSAndroid Build Coastguard Worker             dng_timer timer("Interpolate time");
189*b7c941bbSAndroid Build Coastguard Worker             negative->BuildStage3Image(host,
190*b7c941bbSAndroid Build Coastguard Worker                     gMosaicPlane);
191*b7c941bbSAndroid Build Coastguard Worker         }
192*b7c941bbSAndroid Build Coastguard Worker 
193*b7c941bbSAndroid Build Coastguard Worker         // Convert to proxy, if requested.
194*b7c941bbSAndroid Build Coastguard Worker 
195*b7c941bbSAndroid Build Coastguard Worker         if (gProxyDNGSize) {
196*b7c941bbSAndroid Build Coastguard Worker             dng_timer timer("ConvertToProxy time");
197*b7c941bbSAndroid Build Coastguard Worker             dng_image_writer writer;
198*b7c941bbSAndroid Build Coastguard Worker 
199*b7c941bbSAndroid Build Coastguard Worker             negative->ConvertToProxy(host,
200*b7c941bbSAndroid Build Coastguard Worker                     writer,
201*b7c941bbSAndroid Build Coastguard Worker                     gProxyDNGSize);
202*b7c941bbSAndroid Build Coastguard Worker         }
203*b7c941bbSAndroid Build Coastguard Worker 
204*b7c941bbSAndroid Build Coastguard Worker         // Flatten transparency, if required.
205*b7c941bbSAndroid Build Coastguard Worker 
206*b7c941bbSAndroid Build Coastguard Worker         if (negative->NeedFlattenTransparency(host)) {
207*b7c941bbSAndroid Build Coastguard Worker             dng_timer timer("FlattenTransparency time");
208*b7c941bbSAndroid Build Coastguard Worker             negative->FlattenTransparency(host);
209*b7c941bbSAndroid Build Coastguard Worker         }
210*b7c941bbSAndroid Build Coastguard Worker 
211*b7c941bbSAndroid Build Coastguard Worker         if (gDumpStage3.NotEmpty()) {
212*b7c941bbSAndroid Build Coastguard Worker             dng_file_stream stream2(gDumpStage3.Get(), true);
213*b7c941bbSAndroid Build Coastguard Worker             const dng_image &stage3 = *negative->Stage3Image();
214*b7c941bbSAndroid Build Coastguard Worker             dng_image_writer writer;
215*b7c941bbSAndroid Build Coastguard Worker 
216*b7c941bbSAndroid Build Coastguard Worker             writer.WriteTIFF (host,
217*b7c941bbSAndroid Build Coastguard Worker                     stream2,
218*b7c941bbSAndroid Build Coastguard Worker                     stage3,
219*b7c941bbSAndroid Build Coastguard Worker                     stage3.Planes () >= 3 ? piRGB
220*b7c941bbSAndroid Build Coastguard Worker                     : piBlackIsZero);
221*b7c941bbSAndroid Build Coastguard Worker 
222*b7c941bbSAndroid Build Coastguard Worker             gDumpStage3.Clear();
223*b7c941bbSAndroid Build Coastguard Worker         }
224*b7c941bbSAndroid Build Coastguard Worker 
225*b7c941bbSAndroid Build Coastguard Worker         // Output DNG file if requested.
226*b7c941bbSAndroid Build Coastguard Worker 
227*b7c941bbSAndroid Build Coastguard Worker         if (gDumpDNG.NotEmpty()) {
228*b7c941bbSAndroid Build Coastguard Worker             // Build the preview list.
229*b7c941bbSAndroid Build Coastguard Worker             dng_preview_list previewList;
230*b7c941bbSAndroid Build Coastguard Worker             dng_date_time_info dateTimeInfo;
231*b7c941bbSAndroid Build Coastguard Worker             CurrentDateTimeAndZone(dateTimeInfo);
232*b7c941bbSAndroid Build Coastguard Worker 
233*b7c941bbSAndroid Build Coastguard Worker             for (uint32 previewIndex = 0; previewIndex < 2; previewIndex++) {
234*b7c941bbSAndroid Build Coastguard Worker 
235*b7c941bbSAndroid Build Coastguard Worker                 // Skip preview if writing a compresssed main image to save space
236*b7c941bbSAndroid Build Coastguard Worker                 // in this example code.
237*b7c941bbSAndroid Build Coastguard Worker                 if (negative->RawJPEGImage() != NULL && previewIndex > 0) {
238*b7c941bbSAndroid Build Coastguard Worker                     break;
239*b7c941bbSAndroid Build Coastguard Worker                 }
240*b7c941bbSAndroid Build Coastguard Worker 
241*b7c941bbSAndroid Build Coastguard Worker                 // Report timing.
242*b7c941bbSAndroid Build Coastguard Worker                 dng_timer timer(previewIndex == 0 ? "Build thumbnail time"
243*b7c941bbSAndroid Build Coastguard Worker                         : "Build preview time");
244*b7c941bbSAndroid Build Coastguard Worker 
245*b7c941bbSAndroid Build Coastguard Worker                 // Render a preview sized image.
246*b7c941bbSAndroid Build Coastguard Worker                 AutoPtr<dng_image> previewImage;
247*b7c941bbSAndroid Build Coastguard Worker 
248*b7c941bbSAndroid Build Coastguard Worker                 {
249*b7c941bbSAndroid Build Coastguard Worker                     dng_render render (host, *negative);
250*b7c941bbSAndroid Build Coastguard Worker                     render.SetFinalSpace (negative->IsMonochrome() ?
251*b7c941bbSAndroid Build Coastguard Worker                             dng_space_GrayGamma22::Get() : dng_space_sRGB::Get());
252*b7c941bbSAndroid Build Coastguard Worker                     render.SetFinalPixelType (ttByte);
253*b7c941bbSAndroid Build Coastguard Worker                     render.SetMaximumSize (previewIndex == 0 ? 256 : 1024);
254*b7c941bbSAndroid Build Coastguard Worker 
255*b7c941bbSAndroid Build Coastguard Worker                     previewImage.Reset (render.Render());
256*b7c941bbSAndroid Build Coastguard Worker                 }
257*b7c941bbSAndroid Build Coastguard Worker 
258*b7c941bbSAndroid Build Coastguard Worker                 // Don't write the preview if it is same size as thumbnail.
259*b7c941bbSAndroid Build Coastguard Worker 
260*b7c941bbSAndroid Build Coastguard Worker                 if (previewIndex > 0 &&
261*b7c941bbSAndroid Build Coastguard Worker                         Max_uint32(previewImage->Bounds().W(),
262*b7c941bbSAndroid Build Coastguard Worker                                 previewImage->Bounds().H()) <= 256) {
263*b7c941bbSAndroid Build Coastguard Worker                     break;
264*b7c941bbSAndroid Build Coastguard Worker                 }
265*b7c941bbSAndroid Build Coastguard Worker 
266*b7c941bbSAndroid Build Coastguard Worker                 // If we have compressed JPEG data, create a compressed thumbnail.  Otherwise
267*b7c941bbSAndroid Build Coastguard Worker                 // save a uncompressed thumbnail.
268*b7c941bbSAndroid Build Coastguard Worker                 bool useCompressedPreview = (negative->RawJPEGImage() != NULL) ||
269*b7c941bbSAndroid Build Coastguard Worker                         (previewIndex > 0);
270*b7c941bbSAndroid Build Coastguard Worker 
271*b7c941bbSAndroid Build Coastguard Worker                 AutoPtr<dng_preview> preview (useCompressedPreview ?
272*b7c941bbSAndroid Build Coastguard Worker                         (dng_preview *) new dng_jpeg_preview :
273*b7c941bbSAndroid Build Coastguard Worker                         (dng_preview *) new dng_image_preview);
274*b7c941bbSAndroid Build Coastguard Worker 
275*b7c941bbSAndroid Build Coastguard Worker                 // Setup up preview info.
276*b7c941bbSAndroid Build Coastguard Worker 
277*b7c941bbSAndroid Build Coastguard Worker                 preview->fInfo.fApplicationName.Set("dng_validate");
278*b7c941bbSAndroid Build Coastguard Worker                 preview->fInfo.fApplicationVersion.Set(kDNGValidateVersion);
279*b7c941bbSAndroid Build Coastguard Worker 
280*b7c941bbSAndroid Build Coastguard Worker                 preview->fInfo.fSettingsName.Set("Default");
281*b7c941bbSAndroid Build Coastguard Worker 
282*b7c941bbSAndroid Build Coastguard Worker                 preview->fInfo.fColorSpace = previewImage->Planes() == 1 ?
283*b7c941bbSAndroid Build Coastguard Worker                         previewColorSpace_GrayGamma22 :
284*b7c941bbSAndroid Build Coastguard Worker                         previewColorSpace_sRGB;
285*b7c941bbSAndroid Build Coastguard Worker 
286*b7c941bbSAndroid Build Coastguard Worker                 preview->fInfo.fDateTime = dateTimeInfo.Encode_ISO_8601();
287*b7c941bbSAndroid Build Coastguard Worker 
288*b7c941bbSAndroid Build Coastguard Worker                 if (!useCompressedPreview) {
289*b7c941bbSAndroid Build Coastguard Worker                     dng_image_preview *imagePreview = static_cast<dng_image_preview *>(preview.Get());
290*b7c941bbSAndroid Build Coastguard Worker                     imagePreview->fImage.Reset(previewImage.Release());
291*b7c941bbSAndroid Build Coastguard Worker                 } else {
292*b7c941bbSAndroid Build Coastguard Worker                     dng_jpeg_preview *jpegPreview = static_cast<dng_jpeg_preview *>(preview.Get());
293*b7c941bbSAndroid Build Coastguard Worker                     int32 quality = (previewIndex == 0 ? 8 : 5);
294*b7c941bbSAndroid Build Coastguard Worker                     dng_image_writer writer;
295*b7c941bbSAndroid Build Coastguard Worker                     writer.EncodeJPEGPreview (host,
296*b7c941bbSAndroid Build Coastguard Worker                             *previewImage,
297*b7c941bbSAndroid Build Coastguard Worker                             *jpegPreview,
298*b7c941bbSAndroid Build Coastguard Worker                             quality);
299*b7c941bbSAndroid Build Coastguard Worker                 }
300*b7c941bbSAndroid Build Coastguard Worker                 previewList.Append (preview);
301*b7c941bbSAndroid Build Coastguard Worker             }
302*b7c941bbSAndroid Build Coastguard Worker 
303*b7c941bbSAndroid Build Coastguard Worker             // Write DNG file.
304*b7c941bbSAndroid Build Coastguard Worker 
305*b7c941bbSAndroid Build Coastguard Worker             dng_file_stream stream2(gDumpDNG.Get(), true);
306*b7c941bbSAndroid Build Coastguard Worker 
307*b7c941bbSAndroid Build Coastguard Worker             {
308*b7c941bbSAndroid Build Coastguard Worker                 dng_timer timer("Write DNG time");
309*b7c941bbSAndroid Build Coastguard Worker                 dng_image_writer writer;
310*b7c941bbSAndroid Build Coastguard Worker 
311*b7c941bbSAndroid Build Coastguard Worker                 writer.WriteDNG(host,
312*b7c941bbSAndroid Build Coastguard Worker                         stream2,
313*b7c941bbSAndroid Build Coastguard Worker                         *negative.Get(),
314*b7c941bbSAndroid Build Coastguard Worker                         &previewList,
315*b7c941bbSAndroid Build Coastguard Worker                         dngVersion_Current,
316*b7c941bbSAndroid Build Coastguard Worker                         false);
317*b7c941bbSAndroid Build Coastguard Worker             }
318*b7c941bbSAndroid Build Coastguard Worker 
319*b7c941bbSAndroid Build Coastguard Worker             gDumpDNG.Clear();
320*b7c941bbSAndroid Build Coastguard Worker         }
321*b7c941bbSAndroid Build Coastguard Worker 
322*b7c941bbSAndroid Build Coastguard Worker         // Output TIF file if requested.
323*b7c941bbSAndroid Build Coastguard Worker         if (gDumpTIF.NotEmpty()) {
324*b7c941bbSAndroid Build Coastguard Worker 
325*b7c941bbSAndroid Build Coastguard Worker             // Render final image.
326*b7c941bbSAndroid Build Coastguard Worker 
327*b7c941bbSAndroid Build Coastguard Worker             dng_render render(host, *negative);
328*b7c941bbSAndroid Build Coastguard Worker 
329*b7c941bbSAndroid Build Coastguard Worker             render.SetFinalSpace(*gFinalSpace   );
330*b7c941bbSAndroid Build Coastguard Worker             render.SetFinalPixelType(gFinalPixelType);
331*b7c941bbSAndroid Build Coastguard Worker 
332*b7c941bbSAndroid Build Coastguard Worker             if (host.MinimumSize()) {
333*b7c941bbSAndroid Build Coastguard Worker                 dng_point stage3Size = negative->Stage3Image()->Size();
334*b7c941bbSAndroid Build Coastguard Worker                 render.SetMaximumSize (Max_uint32(stage3Size.v,
335*b7c941bbSAndroid Build Coastguard Worker                                 stage3Size.h));
336*b7c941bbSAndroid Build Coastguard Worker             }
337*b7c941bbSAndroid Build Coastguard Worker 
338*b7c941bbSAndroid Build Coastguard Worker             AutoPtr<dng_image> finalImage;
339*b7c941bbSAndroid Build Coastguard Worker 
340*b7c941bbSAndroid Build Coastguard Worker             {
341*b7c941bbSAndroid Build Coastguard Worker                 dng_timer timer("Render time");
342*b7c941bbSAndroid Build Coastguard Worker                 finalImage.Reset(render.Render());
343*b7c941bbSAndroid Build Coastguard Worker             }
344*b7c941bbSAndroid Build Coastguard Worker 
345*b7c941bbSAndroid Build Coastguard Worker             finalImage->Rotate(negative->Orientation());
346*b7c941bbSAndroid Build Coastguard Worker 
347*b7c941bbSAndroid Build Coastguard Worker             // Now that Camera Raw supports non-raw formats, we should
348*b7c941bbSAndroid Build Coastguard Worker             // not keep any Camera Raw settings in the XMP around when
349*b7c941bbSAndroid Build Coastguard Worker             // writing rendered files.
350*b7c941bbSAndroid Build Coastguard Worker #if qDNGUseXMP
351*b7c941bbSAndroid Build Coastguard Worker             if (negative->GetXMP()) {
352*b7c941bbSAndroid Build Coastguard Worker                 negative->GetXMP()->RemoveProperties(XMP_NS_CRS);
353*b7c941bbSAndroid Build Coastguard Worker                 negative->GetXMP()->RemoveProperties(XMP_NS_CRSS);
354*b7c941bbSAndroid Build Coastguard Worker             }
355*b7c941bbSAndroid Build Coastguard Worker #endif
356*b7c941bbSAndroid Build Coastguard Worker 
357*b7c941bbSAndroid Build Coastguard Worker             // Write TIF file.
358*b7c941bbSAndroid Build Coastguard Worker             dng_file_stream stream2(gDumpTIF.Get(), true);
359*b7c941bbSAndroid Build Coastguard Worker 
360*b7c941bbSAndroid Build Coastguard Worker             {
361*b7c941bbSAndroid Build Coastguard Worker                 dng_timer timer("Write TIFF time");
362*b7c941bbSAndroid Build Coastguard Worker                 dng_image_writer writer;
363*b7c941bbSAndroid Build Coastguard Worker 
364*b7c941bbSAndroid Build Coastguard Worker                 writer.WriteTIFF(host,
365*b7c941bbSAndroid Build Coastguard Worker                         stream2,
366*b7c941bbSAndroid Build Coastguard Worker                         *finalImage.Get(),
367*b7c941bbSAndroid Build Coastguard Worker                         finalImage->Planes() >= 3 ? piRGB
368*b7c941bbSAndroid Build Coastguard Worker                         : piBlackIsZero,
369*b7c941bbSAndroid Build Coastguard Worker                         ccUncompressed,
370*b7c941bbSAndroid Build Coastguard Worker                         negative.Get(),
371*b7c941bbSAndroid Build Coastguard Worker                         &render.FinalSpace());
372*b7c941bbSAndroid Build Coastguard Worker             }
373*b7c941bbSAndroid Build Coastguard Worker             gDumpTIF.Clear();
374*b7c941bbSAndroid Build Coastguard Worker         }
375*b7c941bbSAndroid Build Coastguard Worker     } catch (const dng_exception &except) {
376*b7c941bbSAndroid Build Coastguard Worker         return except.ErrorCode();
377*b7c941bbSAndroid Build Coastguard Worker     } catch (...) {
378*b7c941bbSAndroid Build Coastguard Worker         return dng_error_unknown;
379*b7c941bbSAndroid Build Coastguard Worker     }
380*b7c941bbSAndroid Build Coastguard Worker 
381*b7c941bbSAndroid Build Coastguard Worker     ALOGI("DNG validation complete");
382*b7c941bbSAndroid Build Coastguard Worker 
383*b7c941bbSAndroid Build Coastguard Worker     return dng_error_none;
384*b7c941bbSAndroid Build Coastguard Worker }
385*b7c941bbSAndroid Build Coastguard Worker 
386*b7c941bbSAndroid Build Coastguard Worker extern "C" jboolean
Java_android_hardware_camera2_cts_DngCreatorTest_validateDngNative(JNIEnv * env,jclass,jbyteArray dngBuffer)387*b7c941bbSAndroid Build Coastguard Worker Java_android_hardware_camera2_cts_DngCreatorTest_validateDngNative(
388*b7c941bbSAndroid Build Coastguard Worker     JNIEnv* env, jclass /*clazz*/, jbyteArray dngBuffer) {
389*b7c941bbSAndroid Build Coastguard Worker 
390*b7c941bbSAndroid Build Coastguard Worker     jbyte* buffer = env->GetByteArrayElements(dngBuffer, NULL);
391*b7c941bbSAndroid Build Coastguard Worker     jsize bufferCount = env->GetArrayLength(dngBuffer);
392*b7c941bbSAndroid Build Coastguard Worker     if (buffer == nullptr) {
393*b7c941bbSAndroid Build Coastguard Worker         ALOGE("Unable to map DNG buffer to native");
394*b7c941bbSAndroid Build Coastguard Worker         return JNI_FALSE;
395*b7c941bbSAndroid Build Coastguard Worker     }
396*b7c941bbSAndroid Build Coastguard Worker 
397*b7c941bbSAndroid Build Coastguard Worker     // DNG parsing warnings/errors fprintfs are spread throughout the DNG SDK,
398*b7c941bbSAndroid Build Coastguard Worker     // guarded by the qDNGValidate define flag. To avoid modifying the SDK,
399*b7c941bbSAndroid Build Coastguard Worker     // redirect stderr to a pipe to capture output locally.
400*b7c941bbSAndroid Build Coastguard Worker 
401*b7c941bbSAndroid Build Coastguard Worker     int pipeFds[2];
402*b7c941bbSAndroid Build Coastguard Worker     int err;
403*b7c941bbSAndroid Build Coastguard Worker 
404*b7c941bbSAndroid Build Coastguard Worker     err = pipe(pipeFds);
405*b7c941bbSAndroid Build Coastguard Worker     if (err != 0) {
406*b7c941bbSAndroid Build Coastguard Worker         ALOGE("Error redirecting dng_validate output: %d", errno);
407*b7c941bbSAndroid Build Coastguard Worker         env->ReleaseByteArrayElements(dngBuffer, buffer, 0);
408*b7c941bbSAndroid Build Coastguard Worker         return JNI_FALSE;
409*b7c941bbSAndroid Build Coastguard Worker     }
410*b7c941bbSAndroid Build Coastguard Worker 
411*b7c941bbSAndroid Build Coastguard Worker     int stderrFd = dup(fileno(stderr));
412*b7c941bbSAndroid Build Coastguard Worker     dup2(pipeFds[1], fileno(stderr));
413*b7c941bbSAndroid Build Coastguard Worker     close(pipeFds[1]);
414*b7c941bbSAndroid Build Coastguard Worker 
415*b7c941bbSAndroid Build Coastguard Worker     // Actually run the validation
416*b7c941bbSAndroid Build Coastguard Worker     dng_error_code dng_err = dng_validate(buffer, bufferCount);
417*b7c941bbSAndroid Build Coastguard Worker 
418*b7c941bbSAndroid Build Coastguard Worker     env->ReleaseByteArrayElements(dngBuffer, buffer, 0);
419*b7c941bbSAndroid Build Coastguard Worker 
420*b7c941bbSAndroid Build Coastguard Worker     // Restore stderr and read out pipe
421*b7c941bbSAndroid Build Coastguard Worker     dup2(stderrFd, fileno(stderr));
422*b7c941bbSAndroid Build Coastguard Worker 
423*b7c941bbSAndroid Build Coastguard Worker     std::stringstream errorStream;
424*b7c941bbSAndroid Build Coastguard Worker     const size_t BUF_SIZE = 256;
425*b7c941bbSAndroid Build Coastguard Worker     char readBuf[BUF_SIZE];
426*b7c941bbSAndroid Build Coastguard Worker 
427*b7c941bbSAndroid Build Coastguard Worker     ssize_t count = 0;
428*b7c941bbSAndroid Build Coastguard Worker     while((count = read(pipeFds[0], readBuf, BUF_SIZE)) > 0) {
429*b7c941bbSAndroid Build Coastguard Worker         errorStream.write(readBuf, count);
430*b7c941bbSAndroid Build Coastguard Worker     }
431*b7c941bbSAndroid Build Coastguard Worker     if (count < 0) {
432*b7c941bbSAndroid Build Coastguard Worker         ALOGE("Error reading from dng_validate output pipe: %d", errno);
433*b7c941bbSAndroid Build Coastguard Worker         return JNI_FALSE;
434*b7c941bbSAndroid Build Coastguard Worker     }
435*b7c941bbSAndroid Build Coastguard Worker     close(pipeFds[1]);
436*b7c941bbSAndroid Build Coastguard Worker 
437*b7c941bbSAndroid Build Coastguard Worker     std::string line;
438*b7c941bbSAndroid Build Coastguard Worker     int lineCount = 0;
439*b7c941bbSAndroid Build Coastguard Worker     ALOGI("Output from DNG validation:");
440*b7c941bbSAndroid Build Coastguard Worker     // dng_validate doesn't actually propagate all errors/warnings to the
441*b7c941bbSAndroid Build Coastguard Worker     // return error code, so look for an error pattern in output to detect
442*b7c941bbSAndroid Build Coastguard Worker     // problems. Also make sure the output is long enough since some non-error
443*b7c941bbSAndroid Build Coastguard Worker     // content should always be printed.
444*b7c941bbSAndroid Build Coastguard Worker     while(std::getline(errorStream, line, '\n')) {
445*b7c941bbSAndroid Build Coastguard Worker         lineCount++;
446*b7c941bbSAndroid Build Coastguard Worker         if ( (line.size() > 3) &&
447*b7c941bbSAndroid Build Coastguard Worker                 (line[0] == line[1]) &&
448*b7c941bbSAndroid Build Coastguard Worker                 (line[1] == line[2]) &&
449*b7c941bbSAndroid Build Coastguard Worker                 (line[2] == '*') ) {
450*b7c941bbSAndroid Build Coastguard Worker             // Found a warning or error, so need to fail the test
451*b7c941bbSAndroid Build Coastguard Worker             if (dng_err == dng_error_none) {
452*b7c941bbSAndroid Build Coastguard Worker                 dng_err = dng_error_bad_format;
453*b7c941bbSAndroid Build Coastguard Worker             }
454*b7c941bbSAndroid Build Coastguard Worker             ALOGE("**|%s", line.c_str());
455*b7c941bbSAndroid Build Coastguard Worker         } else {
456*b7c941bbSAndroid Build Coastguard Worker             ALOGI("  |%s", line.c_str());
457*b7c941bbSAndroid Build Coastguard Worker         }
458*b7c941bbSAndroid Build Coastguard Worker     }
459*b7c941bbSAndroid Build Coastguard Worker     // If no output is produced, assume something went wrong
460*b7c941bbSAndroid Build Coastguard Worker     if (lineCount < 3) {
461*b7c941bbSAndroid Build Coastguard Worker         ALOGE("Validation output less than expected!");
462*b7c941bbSAndroid Build Coastguard Worker         dng_err = dng_error_unknown;
463*b7c941bbSAndroid Build Coastguard Worker     }
464*b7c941bbSAndroid Build Coastguard Worker     if (dng_err != dng_error_none) {
465*b7c941bbSAndroid Build Coastguard Worker         ALOGE("DNG validation failed!");
466*b7c941bbSAndroid Build Coastguard Worker     }
467*b7c941bbSAndroid Build Coastguard Worker 
468*b7c941bbSAndroid Build Coastguard Worker     return (dng_err == dng_error_none) ? JNI_TRUE : JNI_FALSE;
469*b7c941bbSAndroid Build Coastguard Worker }
470