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
27namespace default_camera_hal {
28
29// Build stream capabilities from configs + stall durations.
30static 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).
63static 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.
83bool 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
142StaticProperties* 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
191StaticProperties::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
213bool 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.
237static bool IsInputType(int stream_type) {
238  return stream_type == CAMERA3_STREAM_INPUT ||
239         stream_type == CAMERA3_STREAM_BIDIRECTIONAL;
240}
241
242static bool IsOutputType(int stream_type) {
243  return stream_type == CAMERA3_STREAM_OUTPUT ||
244         stream_type == CAMERA3_STREAM_BIDIRECTIONAL;
245}
246
247static 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
253bool 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
261bool 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
294bool 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
370bool 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
434bool 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
452bool 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