C++程序  |  496行  |  17.26 KB

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// #define LOG_NDEBUG 0
#define LOG_TAG "StaticProperties"

#include "static_properties.h"

#include <cutils/log.h>
#include <hardware/camera3.h>
#include <system/camera.h>

#include "metadata/metadata_reader.h"

namespace default_camera_hal {

// Build stream capabilities from configs + stall durations.
static bool ConstructStreamCapabilities(
    const std::vector<StreamConfiguration>& configs,
    const std::vector<StreamStallDuration>& stalls,
    StaticProperties::CapabilitiesMap* capabilities) {
  // Extract directional capabilities from the configs.
  for (const auto& config : configs) {
    switch (config.direction) {
      case ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT:
        (*capabilities)[config.spec].output_supported = true;
        break;
      case ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT:
        (*capabilities)[config.spec].input_supported = true;
        break;
      default:
        // Should never happen when using the MetadataReader;
        // it should validate directions.
        ALOGE("%s: Unrecognized stream config direction %d.",
              __func__,
              config.direction);
        return false;
    }
  }

  // Extract stall durations from the stalls.
  for (const auto& stall : stalls) {
    (*capabilities)[stall.spec].stall_duration = stall.duration;
  }

  return true;
}

// Check that each output config has a valid corresponding stall duration
// (extra durations not matching any output config are ignored).
static bool ValidateStreamCapabilities(
    StaticProperties::CapabilitiesMap capabilities) {
  for (const auto& spec_capabilities : capabilities) {
    // Only non-negative stall durations are valid. This should only happen
    // due to output streams without an associated stall duration, as
    // MetadataReader validates the metadata stall durations.
    if (spec_capabilities.second.output_supported &&
        spec_capabilities.second.stall_duration < 0) {
      ALOGE(
          "%s: Static metadata does not have a stall duration for "
          "each output configuration. ",
          __func__);
      return false;
    }
  }
  return true;
}

// Validate that the input/output formats map matches up with
// the capabilities listed for all formats.
bool ValidateReprocessFormats(
    const StaticProperties::CapabilitiesMap& capabilities,
    const ReprocessFormatMap& reprocess_map) {
  // Get input formats.
  std::set<int32_t> all_input_formats;
  std::set<int32_t> all_output_formats;
  for (const auto& spec_capabilities : capabilities) {
    if (spec_capabilities.second.input_supported) {
      all_input_formats.insert(spec_capabilities.first.format);
    }
    if (spec_capabilities.second.output_supported) {
      all_output_formats.insert(spec_capabilities.first.format);
    }
  }

  // Must be at least one input format.
  if (all_input_formats.size() < 1) {
    ALOGE("%s: No input formats, reprocessing can't be supported.", __func__);
    return false;
  }

  // Check that the reprocess map input formats are exactly all available
  // input formats (check size here, then checking for actual value
  // matches will happen as part of the loop below).
  if (all_input_formats.size() != reprocess_map.size()) {
    ALOGE(
        "%s: Stream configuration input formats do not match "
        "input/output format map input formats.",
        __func__);
    return false;
  }

  // Check that each input format has at least one matching output format.
  for (const auto& input_format : all_input_formats) {
    const auto input_outputs_iterator = reprocess_map.find(input_format);
    if (input_outputs_iterator == reprocess_map.end()) {
      ALOGE(
          "%s: No output formats for input format %d.", __func__, input_format);
      return false;
    }
    // No need to check that the output formats vector is non-empty;
    // MetadataReader validates this. Instead just check that
    // all outputs are actually output formats.
    for (const auto& output_format : input_outputs_iterator->second) {
      if (all_output_formats.count(output_format) < 1) {
        ALOGE(
            "%s: Output format %d for input format %d "
            "is not a supported output format.",
            __func__,
            input_format,
            output_format);
        return false;
      }
    }
  }

  return true;
}

StaticProperties* StaticProperties::NewStaticProperties(
    std::unique_ptr<const MetadataReader> metadata_reader) {
  int facing = 0;
  int orientation = 0;
  int32_t max_input_streams = 0;
  int32_t max_raw_output_streams = 0;
  int32_t max_non_stalling_output_streams = 0;
  int32_t max_stalling_output_streams = 0;
  std::set<uint8_t> request_capabilities;
  std::vector<StreamConfiguration> configs;
  std::vector<StreamStallDuration> stalls;
  CapabilitiesMap stream_capabilities;
  ReprocessFormatMap reprocess_map;

  // If reading any data returns an error, something is wrong.
  if (metadata_reader->Facing(&facing) ||
      metadata_reader->Orientation(&orientation) ||
      metadata_reader->MaxInputStreams(&max_input_streams) ||
      metadata_reader->MaxOutputStreams(&max_raw_output_streams,
                                        &max_non_stalling_output_streams,
                                        &max_stalling_output_streams) ||
      metadata_reader->RequestCapabilities(&request_capabilities) ||
      metadata_reader->StreamConfigurations(&configs) ||
      metadata_reader->StreamStallDurations(&stalls) ||
      !ConstructStreamCapabilities(configs, stalls, &stream_capabilities) ||
      // MetadataReader validates configs and stall seperately,
      // but not that they match.
      !ValidateStreamCapabilities(stream_capabilities) ||
      // Reprocessing metadata only necessary if input streams are allowed.
      (max_input_streams > 0 &&
       (metadata_reader->ReprocessFormats(&reprocess_map) ||
        // MetadataReader validates configs and the reprocess map seperately,
        // but not that they match.
        !ValidateReprocessFormats(stream_capabilities, reprocess_map)))) {
    return nullptr;
  }

  return new StaticProperties(std::move(metadata_reader),
                              facing,
                              orientation,
                              max_input_streams,
                              max_raw_output_streams,
                              max_non_stalling_output_streams,
                              max_stalling_output_streams,
                              std::move(request_capabilities),
                              std::move(stream_capabilities),
                              std::move(reprocess_map));
}

StaticProperties::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)
    : metadata_reader_(std::move(metadata_reader)),
      facing_(facing),
      orientation_(orientation),
      max_input_streams_(max_input_streams),
      max_raw_output_streams_(max_raw_output_streams),
      max_non_stalling_output_streams_(max_non_stalling_output_streams),
      max_stalling_output_streams_(max_stalling_output_streams),
      request_capabilities_(std::move(request_capabilities)),
      stream_capabilities_(std::move(stream_capabilities)),
      supported_reprocess_outputs_(std::move(supported_reprocess_outputs)) {}

bool StaticProperties::TemplateSupported(int type) {
  uint8_t required_capability = 0;
  switch (type) {
    case CAMERA3_TEMPLATE_PREVIEW:
      // Preview is always supported.
      return true;
    case CAMERA3_TEMPLATE_MANUAL:
      required_capability =
          ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR;
      break;
    case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:
      required_capability =
          ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING;
      break;
    default:
      required_capability =
          ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE;
      return true;
  }

  return request_capabilities_.count(required_capability) > 0;
}

// Helper functions for checking stream properties when verifying support.
static bool IsInputType(int stream_type) {
  return stream_type == CAMERA3_STREAM_INPUT ||
         stream_type == CAMERA3_STREAM_BIDIRECTIONAL;
}

static bool IsOutputType(int stream_type) {
  return stream_type == CAMERA3_STREAM_OUTPUT ||
         stream_type == CAMERA3_STREAM_BIDIRECTIONAL;
}

static bool IsRawFormat(int format) {
  return format == HAL_PIXEL_FORMAT_RAW10 || format == HAL_PIXEL_FORMAT_RAW12 ||
         format == HAL_PIXEL_FORMAT_RAW16 ||
         format == HAL_PIXEL_FORMAT_RAW_OPAQUE;
}

bool StaticProperties::StreamConfigurationSupported(
    const camera3_stream_configuration_t* stream_config) {
  return SanityCheckStreamConfiguration(stream_config) &&
         InputStreamsSupported(stream_config) &&
         OutputStreamsSupported(stream_config) &&
         OperationModeSupported(stream_config);
}

bool StaticProperties::SanityCheckStreamConfiguration(
    const camera3_stream_configuration_t* stream_config) {
  // Check for null/empty values.
  if (stream_config == nullptr) {
    ALOGE("%s: NULL stream configuration array", __func__);
    return false;
  } else if (stream_config->num_streams == 0) {
    ALOGE("%s: Empty stream configuration array", __func__);
    return false;
  } else if (stream_config->streams == nullptr) {
    ALOGE("%s: NULL stream configuration streams", __func__);
    return false;
  }

  // Check that all streams are either inputs or outputs (or both).
  for (size_t i = 0; i < stream_config->num_streams; ++i) {
    const camera3_stream_t* stream = stream_config->streams[i];
    if (stream == nullptr) {
      ALOGE("%s: Stream %zu is null", __func__, i);
      return false;
    } else if (!IsInputType(stream->stream_type) &&
               !IsOutputType(stream->stream_type)) {
      ALOGE("%s: Stream %zu type %d is neither an input nor an output type",
            __func__,
            i,
            stream->stream_type);
      return false;
    }
  }

  return true;
}

bool StaticProperties::InputStreamsSupported(
    const camera3_stream_configuration_t* stream_config) {
  // Find the input stream(s).
  int32_t num_input_streams = 0;
  int input_format = -1;
  for (size_t i = 0; i < stream_config->num_streams; ++i) {
    const camera3_stream_t* stream = stream_config->streams[i];
    if (IsInputType(stream->stream_type)) {
      // Check that this stream is valid as an input.
      const auto capabilities_iterator = stream_capabilities_.find(stream);
      if (capabilities_iterator == stream_capabilities_.end() ||
          !capabilities_iterator->second.input_supported) {
        ALOGE("%s: %d x %d stream of format %d is not a supported input setup.",
              __func__,
              stream->width,
              stream->height,
              stream->format);
        return false;
      }

      // Valid input stream; count it.
      ++num_input_streams;
      input_format = stream->format;
    }
  }

  // Check the count.
  if (num_input_streams > max_input_streams_) {
    ALOGE(
        "%s: Requested number of input streams %d is greater than "
        "the maximum number supported by the device (%d).",
        __func__,
        num_input_streams,
        max_input_streams_);
    return false;
  }
  if (num_input_streams > 1) {
    ALOGE("%s: Camera HAL 3.4 only supports 1 input stream max.", __func__);
    return false;
  }

  // If there's an input stream, the configuration must have at least one
  // supported output format for reprocessing that input.
  if (num_input_streams > 0) {
    const auto input_output_formats_iterator =
        supported_reprocess_outputs_.find(input_format);
    if (input_output_formats_iterator == supported_reprocess_outputs_.end()) {
      // Should never happen; factory should verify that all valid inputs
      // have one or more valid outputs.
      ALOGE("%s: No valid output formats for input format %d.",
            __func__,
            input_format);
      return false;
    }
    bool match_found = false;
    // Go through outputs looking for a supported one.
    for (size_t i = 0; i < stream_config->num_streams; ++i) {
      const camera3_stream_t* stream = stream_config->streams[i];
      if (IsOutputType(stream->stream_type)) {
        if (input_output_formats_iterator->second.count(stream->format) > 0) {
          match_found = true;
          break;
        }
      }
    }
    if (!match_found) {
      ALOGE("%s: No supported output format provided for input format %d.",
            __func__,
            input_format);
      return false;
    }
  }

  return true;
}

bool StaticProperties::OutputStreamsSupported(
    const camera3_stream_configuration_t* stream_config) {
  // Find and count output streams.
  int32_t num_raw = 0;
  int32_t num_stalling = 0;
  int32_t num_non_stalling = 0;
  for (size_t i = 0; i < stream_config->num_streams; ++i) {
    const camera3_stream_t* stream = stream_config->streams[i];
    if (IsOutputType(stream->stream_type)) {
      // Check that this stream is valid as an output.
      const auto capabilities_iterator = stream_capabilities_.find(stream);
      if (capabilities_iterator == stream_capabilities_.end() ||
          !capabilities_iterator->second.output_supported) {
        ALOGE(
            "%s: %d x %d stream of format %d "
            "is not a supported output setup.",
            __func__,
            stream->width,
            stream->height,
            stream->format);
        return false;
      }

      // Valid output; count it.
      if (IsRawFormat(stream->format)) {
        ++num_raw;
      } else if (capabilities_iterator->second.stall_duration > 0) {
        ++num_stalling;
      } else {
        ++num_non_stalling;
      }
    }
  }

  // Check that the counts are within bounds.
  if (num_raw > max_raw_output_streams_) {
    ALOGE(
        "%s: Requested stream configuration exceeds maximum supported "
        "raw output streams %d (requested %d).",
        __func__,
        max_raw_output_streams_,
        num_raw);
    return false;
  } else if (num_stalling > max_stalling_output_streams_) {
    ALOGE(
        "%s: Requested stream configuration exceeds maximum supported "
        "stalling output streams %d (requested %u).",
        __func__,
        max_stalling_output_streams_,
        num_stalling);
    return false;
  } else if (num_non_stalling > max_non_stalling_output_streams_) {
    ALOGE(
        "%s: Requested stream configuration exceeds maximum supported "
        "non-stalling output streams %d (requested %d).",
        __func__,
        max_non_stalling_output_streams_,
        num_non_stalling);
    return false;
  }

  return true;
}

bool StaticProperties::OperationModeSupported(
    const camera3_stream_configuration_t* stream_config) {
  switch (stream_config->operation_mode) {
    case CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE:
      return true;
    case CAMERA3_STREAM_CONFIGURATION_CONSTRAINED_HIGH_SPEED_MODE:
      // TODO(b/31370792): Check metadata for high speed support,
      // check that requested streams have support for high speed.
      ALOGE("%s: Support for CONSTRAINED_HIGH_SPEED not implemented", __func__);
      return false;
    default:
      ALOGE("%s: Unrecognized stream configuration mode: %d",
            __func__,
            stream_config->operation_mode);
      return false;
  }
}

bool StaticProperties::ReprocessingSupported(
    const camera3_stream_t* input_stream,
    const std::set<const camera3_stream_t*>& output_streams) {
  // There must be an input.
  if (!input_stream) {
    ALOGE("%s: No input stream.", __func__);
    return false;
  }
  // There must be an output.
  if (output_streams.size() < 1) {
    ALOGE("%s: No output stream.", __func__);
    return false;
  }

  const auto input_output_formats =
      supported_reprocess_outputs_.find(input_stream->format);
  if (input_output_formats == supported_reprocess_outputs_.end()) {
    // Should never happen for a valid input stream.
    ALOGE("%s: Input format %d does not support any output formats.",
          __func__,
          input_stream->format);
    return false;
  }

  // Check that all output streams can be outputs for the input stream.
  const std::set<int32_t>& supported_output_formats =
      input_output_formats->second;
  for (const auto output_stream : output_streams) {
    if (supported_output_formats.count(output_stream->format) < 1) {
      ALOGE(
          "%s: Output format %d is not a supported output "
          "for request input format %d.",
          __func__,
          output_stream->format,
          input_stream->format);
      return false;
    }
  }

  return true;
}

}  // namespace default_camera_hal