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