blob: 40fcfe96b4b538d558238975eacedfa09ba3ea57 [file] [log] [blame]
Sascha Haeberling51163542014-08-14 19:27:34 -07001/*
2 * Copyright (C) 2014 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
17package com.android.camera.util;
18
19import android.hardware.camera2.CameraMetadata;
20import android.hardware.camera2.CaptureRequest;
21import android.hardware.camera2.CaptureResult;
22import android.hardware.camera2.params.ColorSpaceTransform;
23import android.hardware.camera2.params.RggbChannelVector;
24import android.hardware.camera2.params.TonemapCurve;
25import android.util.Rational;
26
27import com.android.camera.debug.Log;
28import com.android.camera.debug.Log.Tag;
29
30import java.io.BufferedWriter;
31import java.io.File;
32import java.io.FileWriter;
33import java.io.IOException;
34import java.io.StringWriter;
35import java.io.Writer;
36import java.lang.reflect.Array;
37import java.util.Arrays;
38import java.util.List;
39
40/**
41 * Can be used for debugging to output details about Camera2 capture request and
42 * responses.
43 */
44public class CaptureDataSerializer {
45 private static interface Writeable {
46 public void write(Writer writer) throws IOException;
47 }
48
49 private static final Tag TAG = new Tag("CaptureDataSerializer");
50
51 /**
52 * Generate a human-readable string of the given capture request and return
53 * it.
54 */
55 public static String toString(String title, CaptureRequest metadata) {
56 StringWriter writer = new StringWriter();
57 dumpMetadata(title, metadata, writer);
58 return writer.toString();
59 }
60
61 /**
62 * Generate a human-readable string of the given capture request and write
63 * it to the given file.
64 */
65 public static void toFile(String title, CameraMetadata<?> metadata, File file) {
66 try {
67 // Will append if the file already exists.
68 FileWriter writer = new FileWriter(file, true);
69 if (metadata instanceof CaptureRequest) {
70 dumpMetadata(title, (CaptureRequest) metadata, writer);
71 } else if (metadata instanceof CaptureResult) {
72 dumpMetadata(title, (CaptureResult) metadata, writer);
73 } else {
74 writer.close();
75 throw new IllegalArgumentException("Cannot generate debug data from type "
76 + metadata.getClass().getName());
77 }
78 writer.close();
79 } catch (IOException ex) {
80 Log.e(TAG, "Could not write capture data to file.", ex);
81 }
82 }
83
84 /**
85 * Writes the data about the marker and requests to the given folder for
86 * offline debugging.
87 */
88 private static void dumpMetadata(final String title, final CaptureRequest metadata,
89 Writer writer) {
90 Writeable writeable = new Writeable() {
91 @Override
92 public void write(Writer writer) throws IOException {
93 List<CaptureRequest.Key<?>> keys = metadata.getKeys();
94 writer.write(title + '\n');
95
96 // TODO: move to CameraMetadata#toString ?
97 for (CaptureRequest.Key<?> key : keys) {
98 writer.write(String.format(" %s\n", key.getName()));
99 writer.write(String.format(" %s\n",
100 metadataValueToString(metadata.get(key))));
101 }
102 }
103 };
104 dumpMetadata(writeable, new BufferedWriter(writer));
105 }
106
107 /**
108 * Writes the data about the marker and requests to the given folder for
109 * offline debugging.
110 */
111 private static void dumpMetadata(final String title, final CaptureResult metadata,
112 Writer writer) {
113 Writeable writeable = new Writeable() {
114 @Override
115 public void write(Writer writer) throws IOException {
116 List<CaptureResult.Key<?>> keys = metadata.getKeys();
117 writer.write(String.format(title));
118
119 // TODO: move to CameraMetadata#toString ?
120 for (CaptureResult.Key<?> key : keys) {
121 writer.write(String.format(" %s\n", key.getName()));
122 writer.write(String.format(" %s\n",
123 metadataValueToString(metadata.get(key))));
124 }
125 }
126 };
127 dumpMetadata(writeable, new BufferedWriter(writer));
128 }
129
130 private static String metadataValueToString(Object object) {
131 if (object == null) {
132 return "<null>";
133 }
134 if (object.getClass().isArray()) {
135 StringBuilder builder = new StringBuilder();
136 builder.append("[");
137
138 int length = Array.getLength(object);
139 for (int i = 0; i < length; ++i) {
140 Object item = Array.get(object, i);
141 builder.append(metadataValueToString(item));
142
143 if (i != length - 1) {
144 builder.append(", ");
145 }
146 }
147 builder.append(']');
148
149 return builder.toString();
150 } else {
151 // These classes don't have a toString() method yet
152 // See: http://b/16899576
153 if (object instanceof RggbChannelVector) {
154 return toString((RggbChannelVector) object);
155 } else if (object instanceof ColorSpaceTransform) {
156 return toString((ColorSpaceTransform) object);
157 } else if (object instanceof TonemapCurve) {
158 return toString((TonemapCurve) object);
159 }
160 return object.toString();
161 }
162 }
163
164 private static void dumpMetadata(Writeable metadata, Writer writer) {
165 /**
166 * Save metadata to file, appending if another metadata is already in
167 * that file.
168 */
169 try {
170 metadata.write(writer);
171 } catch (IOException e) {
172 Log.e(TAG, "dumpMetadata - Failed to dump metadata", e);
173 } finally {
174 try {
175 if (writer != null) {
176 writer.close();
177 }
178 } catch (IOException e) {
179 Log.e(TAG, "dumpMetadata - Failed to close writer.", e);
180 }
181 }
182 }
183
184 private static String toString(RggbChannelVector vector) {
185 StringBuilder str = new StringBuilder();
186 str.append("RggbChannelVector:");
187 str.append(" R:");
188 str.append(vector.getRed());
189 str.append(" G(even):");
190 str.append(vector.getGreenEven());
191 str.append(" G(odd):");
192 str.append(vector.getGreenOdd());
193 str.append(" B:");
194 str.append(vector.getBlue());
195
196 return str.toString();
197 }
198
199 private static String toString(ColorSpaceTransform transform) {
200 StringBuilder str = new StringBuilder();
201 Rational[] rationals = new Rational[9];
202 transform.copyElements(rationals, 0);
203 str.append("ColorSpaceTransform: ");
204 str.append(Arrays.toString(rationals));
205 return str.toString();
206 }
207
208 private static String toString(TonemapCurve curve) {
209 StringBuilder str = new StringBuilder();
210 str.append("TonemapCurve:");
211
212 float[] reds = new float[curve.getPointCount(TonemapCurve.CHANNEL_RED)
213 * TonemapCurve.POINT_SIZE];
214 curve.copyColorCurve(TonemapCurve.CHANNEL_RED, reds, 0);
215 float[] greens = new float[curve.getPointCount(TonemapCurve.CHANNEL_GREEN)
216 * TonemapCurve.POINT_SIZE];
217 curve.copyColorCurve(TonemapCurve.CHANNEL_GREEN, greens, 0);
218 float[] blues = new float[curve.getPointCount(TonemapCurve.CHANNEL_BLUE)
219 * TonemapCurve.POINT_SIZE];
220 curve.copyColorCurve(TonemapCurve.CHANNEL_BLUE, blues, 0);
221
222 str.append("\n\nReds: ");
223 str.append(Arrays.toString(reds));
224 str.append("\n\nGreens: ");
225 str.append(Arrays.toString(greens));
226 str.append("\n\nBlues: ");
227 str.append(Arrays.toString(blues));
228
229 return str.toString();
230 }
231}