blob: 0584290fa274d0814ba0a80327dad794cbf3079e [file] [log] [blame]
Ari Hausman-Cohenf45f8d42016-09-07 15:35:53 -07001/*
2 * Copyright (C) 2016 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#include "static_properties.h"
18
19// #define LOG_NDEBUG 0
20#define LOG_TAG "StaticProperties"
21#include <cutils/log.h>
22#include <system/camera.h>
23
24#include "metadata/metadata_reader.h"
25
26namespace default_camera_hal {
27
Ari Hausman-Cohenffb9b722016-09-09 12:06:26 -070028// Build and capabilities from configs + stall durations.
29static bool ConstructCapabilities(
30 const std::vector<StreamConfiguration>& configs,
31 const std::vector<StreamStallDuration>& stalls,
32 StaticProperties::CapabilitiesMap* capabilities) {
33 // Extract directional capabilities from the configs.
34 for (const auto& config : configs) {
35 switch (config.direction) {
36 case ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT:
37 (*capabilities)[config.spec].output_supported = true;
38 break;
39 case ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT:
40 (*capabilities)[config.spec].input_supported = true;
41 break;
42 default:
43 // Should never happen when using the MetadataReader;
44 // it should validate directions.
45 ALOGE("%s: Unrecognized stream config direction %d.",
46 __func__,
47 config.direction);
48 return false;
49 }
50 }
51
52 // Extract stall durations from the stalls.
53 for (const auto& stall : stalls) {
54 (*capabilities)[stall.spec].stall_duration = stall.duration;
55 }
56
57 return true;
58}
59
60// Check that each output config has a valid corresponding stall duration
61// (extra durations not matching any output config are ignored).
62static bool ValidateCapabilities(
63 StaticProperties::CapabilitiesMap capabilities) {
64 for (const auto& spec_capabilities : capabilities) {
65 // Only non-negative stall durations are valid. This should only happen
66 // due to output streams without an associated stall duration, as
67 // MetadataReader validates the metadata stall durations.
68 if (spec_capabilities.second.output_supported &&
69 spec_capabilities.second.stall_duration < 0) {
70 ALOGE(
71 "%s: Static metadata does not have a stall duration for "
72 "each output configuration. ",
73 __func__);
74 return false;
75 }
76 }
77 return true;
78}
79
80// Validate that the input/output formats map matches up with
81// the capabilities listed for all formats.
82bool ValidateReprocessFormats(
83 const StaticProperties::CapabilitiesMap& capabilities,
84 const ReprocessFormatMap& reprocess_map) {
85 // Get input formats.
86 std::set<int32_t> all_input_formats;
87 std::set<int32_t> all_output_formats;
88 for (const auto& spec_capabilities : capabilities) {
89 if (spec_capabilities.second.input_supported) {
90 all_input_formats.insert(spec_capabilities.first.format);
91 }
92 if (spec_capabilities.second.output_supported) {
93 all_output_formats.insert(spec_capabilities.first.format);
94 }
95 }
96
97 // Must be at least one input format.
98 if (all_input_formats.size() < 1) {
99 ALOGE("%s: No input formats, reprocessing can't be supported.", __func__);
100 return false;
101 }
102
103 // Check that the reprocess map input formats are exactly all available
104 // input formats (check size here, then checking for actual value
105 // matches will happen as part of the loop below).
106 if (all_input_formats.size() != reprocess_map.size()) {
107 ALOGE(
108 "%s: Stream configuration input formats do not match "
109 "input/output format map input formats.",
110 __func__);
111 return false;
112 }
113
114 // Check that each input format has at least one matching output format.
115 for (const auto& input_format : all_input_formats) {
116 const auto input_outputs_iterator = reprocess_map.find(input_format);
117 if (input_outputs_iterator == reprocess_map.end()) {
118 ALOGE(
119 "%s: No output formats for input format %d.", __func__, input_format);
120 return false;
121 }
122 // No need to check that the output formats vector is non-empty;
123 // MetadataReader validates this. Instead just check that
124 // all outputs are actually output formats.
125 for (const auto& output_format : input_outputs_iterator->second) {
126 if (all_output_formats.count(output_format) < 1) {
127 ALOGE(
128 "%s: Output format %d for input format %d "
129 "is not a supported output format.",
130 __func__,
131 input_format,
132 output_format);
133 return false;
134 }
135 }
136 }
137
138 return true;
139}
140
Ari Hausman-Cohenf45f8d42016-09-07 15:35:53 -0700141StaticProperties* StaticProperties::NewStaticProperties(
142 std::unique_ptr<const MetadataReader> metadata_reader) {
143 int facing = 0;
144 int orientation = 0;
Ari Hausman-Cohenffb9b722016-09-09 12:06:26 -0700145 int32_t max_input_streams = 0;
146 int32_t max_raw_output_streams = 0;
147 int32_t max_non_stalling_output_streams = 0;
148 int32_t max_stalling_output_streams = 0;
149 std::vector<StreamConfiguration> configs;
150 std::vector<StreamStallDuration> stalls;
151 CapabilitiesMap capabilities;
152 ReprocessFormatMap reprocess_map;
153
Ari Hausman-Cohenf45f8d42016-09-07 15:35:53 -0700154 // If reading any data returns an error, something is wrong.
155 if (metadata_reader->Facing(&facing) ||
Ari Hausman-Cohenffb9b722016-09-09 12:06:26 -0700156 metadata_reader->Orientation(&orientation) ||
157 metadata_reader->MaxInputStreams(&max_input_streams) ||
158 metadata_reader->MaxOutputStreams(&max_raw_output_streams,
159 &max_non_stalling_output_streams,
160 &max_stalling_output_streams) ||
161 metadata_reader->StreamConfigurations(&configs) ||
162 metadata_reader->StreamStallDurations(&stalls) ||
163 !ConstructCapabilities(configs, stalls, &capabilities) ||
164 // MetadataReader validates configs and stall seperately,
165 // but not that they match.
166 !ValidateCapabilities(capabilities) ||
167 // Reprocessing metadata only necessary if input streams are allowed.
168 (max_input_streams > 0 &&
169 (metadata_reader->ReprocessFormats(&reprocess_map) ||
170 // MetadataReader validates configs and the reprocess map seperately,
171 // but not that they match.
172 !ValidateReprocessFormats(capabilities, reprocess_map)))) {
Ari Hausman-Cohenf45f8d42016-09-07 15:35:53 -0700173 return nullptr;
174 }
175
Ari Hausman-Cohenffb9b722016-09-09 12:06:26 -0700176 return new StaticProperties(std::move(metadata_reader),
177 facing,
178 orientation,
179 max_input_streams,
180 max_raw_output_streams,
181 max_non_stalling_output_streams,
182 max_stalling_output_streams,
183 std::move(capabilities),
184 std::move(reprocess_map));
Ari Hausman-Cohenf45f8d42016-09-07 15:35:53 -0700185}
186
187StaticProperties::StaticProperties(
188 std::unique_ptr<const MetadataReader> metadata_reader,
189 int facing,
Ari Hausman-Cohenffb9b722016-09-09 12:06:26 -0700190 int orientation,
191 int32_t max_input_streams,
192 int32_t max_raw_output_streams,
193 int32_t max_non_stalling_output_streams,
194 int32_t max_stalling_output_streams,
195 CapabilitiesMap stream_capabilities,
196 ReprocessFormatMap supported_reprocess_outputs)
Ari Hausman-Cohenf45f8d42016-09-07 15:35:53 -0700197 : metadata_reader_(std::move(metadata_reader)),
198 facing_(facing),
Ari Hausman-Cohenffb9b722016-09-09 12:06:26 -0700199 orientation_(orientation),
200 max_input_streams_(max_input_streams),
201 max_raw_output_streams_(max_raw_output_streams),
202 max_non_stalling_output_streams_(max_non_stalling_output_streams),
203 max_stalling_output_streams_(max_stalling_output_streams),
204 stream_capabilities_(std::move(stream_capabilities)),
205 supported_reprocess_outputs_(std::move(supported_reprocess_outputs)) {}
206
207// Helper functions for checking stream properties when verifying support.
208static bool IsInputType(int stream_type) {
209 return stream_type == CAMERA3_STREAM_INPUT ||
210 stream_type == CAMERA3_STREAM_BIDIRECTIONAL;
211}
212
213static bool IsOutputType(int stream_type) {
214 return stream_type == CAMERA3_STREAM_OUTPUT ||
215 stream_type == CAMERA3_STREAM_BIDIRECTIONAL;
216}
217
218static bool IsRawFormat(int format) {
219 return format == HAL_PIXEL_FORMAT_RAW10 || format == HAL_PIXEL_FORMAT_RAW12 ||
220 format == HAL_PIXEL_FORMAT_RAW16 ||
221 format == HAL_PIXEL_FORMAT_RAW_OPAQUE;
222}
223
224bool StaticProperties::StreamConfigurationSupported(
225 const camera3_stream_configuration_t* stream_config) {
226 return SanityCheckStreamConfiguration(stream_config) &&
227 InputStreamsSupported(stream_config) &&
228 OutputStreamsSupported(stream_config) &&
229 OperationModeSupported(stream_config);
230}
231
232bool StaticProperties::SanityCheckStreamConfiguration(
233 const camera3_stream_configuration_t* stream_config) {
234 // Check for null/empty values.
235 if (stream_config == nullptr) {
236 ALOGE("%s: NULL stream configuration array", __func__);
237 return false;
238 } else if (stream_config->num_streams == 0) {
239 ALOGE("%s: Empty stream configuration array", __func__);
240 return false;
241 } else if (stream_config->streams == nullptr) {
242 ALOGE("%s: NULL stream configuration streams", __func__);
243 return false;
244 }
245
246 // Check that all streams are either inputs or outputs (or both).
247 for (size_t i = 0; i < stream_config->num_streams; ++i) {
248 const camera3_stream_t* stream = stream_config->streams[i];
249 if (stream == nullptr) {
250 ALOGE("%s: Stream %d is null", __func__, i);
251 return false;
252 } else if (!IsInputType(stream->stream_type) &&
253 !IsOutputType(stream->stream_type)) {
254 ALOGE("%s: Stream %d type %d is neither an input nor an output type",
255 __func__,
256 i,
257 stream->stream_type);
258 return false;
259 }
260 }
261
262 return true;
263}
264
265bool StaticProperties::InputStreamsSupported(
266 const camera3_stream_configuration_t* stream_config) {
267 // Find the input stream(s).
268 size_t num_input_streams;
269 int input_format;
270 for (size_t i = 0; i < stream_config->num_streams; ++i) {
271 const camera3_stream_t* stream = stream_config->streams[i];
272 if (IsInputType(stream->stream_type)) {
273 // Check that this stream is valid as an input.
274 const auto capabilities_iterator = stream_capabilities_.find(stream);
275 if (capabilities_iterator == stream_capabilities_.end() ||
276 !capabilities_iterator->second.input_supported) {
277 ALOGE("%s: %d x %d stream of format %d is not a supported input setup.",
278 __func__,
279 stream->width,
280 stream->height,
281 stream->format);
282 return false;
283 }
284
285 // Valid input stream; count it.
286 ++num_input_streams;
287 input_format = stream->format;
288 }
289 }
290
291 // Check the count.
292 if (num_input_streams > max_input_streams_) {
293 ALOGE(
294 "%s: Requested number of input streams %d is greater than "
295 "the maximum number supported by the device (%d).",
296 __func__,
297 num_input_streams,
298 max_input_streams_);
299 return false;
300 }
301 if (num_input_streams > 1) {
302 ALOGE("%s: Camera HAL 3.4 only supports 1 input stream max.", __func__);
303 return false;
304 }
305
306 // If there's an input stream, the configuration must have at least one
307 // supported output format for reprocessing that input.
308 if (num_input_streams > 0) {
309 const auto input_output_formats_iterator =
310 supported_reprocess_outputs_.find(input_format);
311 if (input_output_formats_iterator == supported_reprocess_outputs_.end()) {
312 // Should never happen; factory should verify that all valid inputs
313 // have one or more valid outputs.
314 ALOGE("%s: No valid output formats for input format %d.",
315 __func__,
316 input_format);
317 return false;
318 }
319 bool match_found = false;
320 // Go through outputs looking for a supported one.
321 for (size_t i = 0; i < stream_config->num_streams; ++i) {
322 const camera3_stream_t* stream = stream_config->streams[i];
323 if (IsOutputType(stream->stream_type)) {
324 if (input_output_formats_iterator->second.count(stream->format) > 0) {
325 match_found = true;
326 break;
327 }
328 }
329 }
330 if (!match_found) {
331 ALOGE("%s: No supported output format provided for input format %d.",
332 __func__,
333 input_format);
334 return false;
335 }
336 }
337
338 return true;
339}
340
341bool StaticProperties::OutputStreamsSupported(
342 const camera3_stream_configuration_t* stream_config) {
343 // Find and count output streams.
344 size_t num_raw = 0;
345 size_t num_stalling = 0;
346 size_t num_non_stalling = 0;
347 for (int i = 0; i < stream_config->num_streams; ++i) {
348 const camera3_stream_t* stream = stream_config->streams[i];
349 if (IsOutputType(stream->stream_type)) {
350 // Check that this stream is valid as an output.
351 const auto capabilities_iterator = stream_capabilities_.find(stream);
352 if (capabilities_iterator == stream_capabilities_.end() ||
353 !capabilities_iterator->second.output_supported) {
354 ALOGE(
355 "%s: %d x %d stream of format %d "
356 "is not a supported output setup.",
357 __func__,
358 stream->width,
359 stream->height,
360 stream->format);
361 return false;
362 }
363
364 // Valid output; count it.
365 if (IsRawFormat(stream->format)) {
366 ++num_raw;
367 } else if (capabilities_iterator->second.stall_duration > 0) {
368 ++num_stalling;
369 } else {
370 ++num_non_stalling;
371 }
372 }
373 }
374
375 // Check that the counts are within bounds.
376 if (num_raw > max_raw_output_streams_) {
377 ALOGE(
378 "%s: Requested stream configuration exceeds maximum supported "
379 "raw output streams %d (requested %d).",
380 __func__,
381 max_raw_output_streams_,
382 num_raw);
383 return false;
384 } else if (num_stalling > max_stalling_output_streams_) {
385 ALOGE(
386 "%s: Requested stream configuration exceeds maximum supported "
387 "stalling output streams %d (requested %d).",
388 __func__,
389 max_stalling_output_streams_,
390 num_stalling);
391 return false;
392 } else if (num_non_stalling > max_non_stalling_output_streams_) {
393 ALOGE(
394 "%s: Requested stream configuration exceeds maximum supported "
395 "non-stalling output streams %d (requested %d).",
396 __func__,
397 max_non_stalling_output_streams_,
398 num_non_stalling);
399 return false;
400 }
401
402 return true;
403}
404
405bool StaticProperties::OperationModeSupported(
406 const camera3_stream_configuration_t* stream_config) {
407 switch (stream_config->operation_mode) {
408 case CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE:
409 return true;
410 case CAMERA3_STREAM_CONFIGURATION_CONSTRAINED_HIGH_SPEED_MODE:
411 // TODO(b/31370792): Check metadata for high speed support,
412 // check that requested streams have support for high speed.
413 ALOGE("%s: Support for CONSTRAINED_HIGH_SPEED not implemented", __func__);
414 return false;
415 default:
416 ALOGE("%s: Unrecognized stream configuration mode: %d",
417 __func__,
418 stream_config->operation_mode);
419 return false;
420 }
421}
422
423bool StaticProperties::ReprocessingSupported(
424 const camera3_stream_t* input_stream,
425 const std::set<const camera3_stream_t*>& output_streams) {
426 // There must be an input.
427 if (!input_stream) {
428 ALOGE("%s: No input stream.", __func__);
429 return false;
430 }
431 // There must be an output.
432 if (output_streams.size() < 1) {
433 ALOGE("%s: No output stream.", __func__);
434 return false;
435 }
436
437 const auto input_output_formats =
438 supported_reprocess_outputs_.find(input_stream->format);
439 if (input_output_formats == supported_reprocess_outputs_.end()) {
440 // Should never happen for a valid input stream.
441 ALOGE("%s: Input format %d does not support any output formats.",
442 __func__,
443 input_stream->format);
444 return false;
445 }
446
447 // Check that all output streams can be outputs for the input stream.
448 const std::set<int32_t>& supported_output_formats =
449 input_output_formats->second;
450 for (const auto output_stream : output_streams) {
451 if (supported_output_formats.count(output_stream->format) < 1) {
452 ALOGE(
453 "%s: Output format %d is not a supported output "
454 "for request input format %d.",
455 __func__,
456 output_stream->format,
457 input_stream->format);
458 return false;
459 }
460 }
461
462 return true;
463}
Ari Hausman-Cohenf45f8d42016-09-07 15:35:53 -0700464
465} // namespace default_camera_hal