summaryrefslogtreecommitdiff
path: root/modules/camera/3_4/metadata/map_converter.h
blob: 2324d7446efe82a781a98351e5ce93e77a976552 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
 * 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.
 */

#ifndef V4L2_CAMERA_HAL_METADATA_MAP_CONVERTER_H_
#define V4L2_CAMERA_HAL_METADATA_MAP_CONVERTER_H_

#include <errno.h>

#include <map>
#include <memory>

#include <android-base/macros.h>

#include "converter_interface.h"

namespace v4l2_camera_hal {

// A MapConverter fits values converted by a wrapped converter
// to a map entry corresponding to the key with the nearest value.
template <typename TMetadata, typename TV4L2, typename TMapKey>
class MapConverter : public ConverterInterface<TMetadata, TV4L2> {
 public:
  MapConverter(
      std::shared_ptr<ConverterInterface<TMetadata, TMapKey>> wrapped_converter,
      std::map<TMapKey, TV4L2> conversion_map);

  virtual int MetadataToV4L2(TMetadata value, TV4L2* conversion) override;
  virtual int V4L2ToMetadata(TV4L2 value, TMetadata* conversion) override;

 private:
  std::shared_ptr<ConverterInterface<TMetadata, TMapKey>> wrapped_converter_;
  std::map<TMapKey, TV4L2> conversion_map_;

  DISALLOW_COPY_AND_ASSIGN(MapConverter);
};

// -----------------------------------------------------------------------------

template <typename TMetadata, typename TV4L2, typename TMapKey>
MapConverter<TMetadata, TV4L2, TMapKey>::MapConverter(
    std::shared_ptr<ConverterInterface<TMetadata, TMapKey>> wrapped_converter,
    std::map<TMapKey, TV4L2> conversion_map)
    : wrapped_converter_(std::move(wrapped_converter)),
      conversion_map_(conversion_map) {
  HAL_LOG_ENTER();
}

template <typename TMetadata, typename TV4L2, typename TMapKey>
int MapConverter<TMetadata, TV4L2, TMapKey>::MetadataToV4L2(TMetadata value,
                                                            TV4L2* conversion) {
  HAL_LOG_ENTER();

  if (conversion_map_.empty()) {
    HAL_LOGE("Empty conversion map.");
    return -EINVAL;
  }

  TMapKey raw_conversion = 0;
  int res = wrapped_converter_->MetadataToV4L2(value, &raw_conversion);
  if (res) {
    HAL_LOGE("Failed to perform underlying conversion.");
    return res;
  }

  // Find nearest key.
  auto kv = conversion_map_.lower_bound(raw_conversion);
  // lower_bound finds the first >= element.
  if (kv == conversion_map_.begin()) {
    // Searching for less than the smallest key, so that will be the nearest.
    *conversion = kv->second;
  } else if (kv == conversion_map_.end()) {
    // Searching for greater than the largest key, so that will be the nearest.
    --kv;
    *conversion = kv->second;
  } else {
    // Since kv points to the first >= element, either that or the previous
    // element will be nearest.
    *conversion = kv->second;
    TMapKey diff = kv->first - raw_conversion;

    // Now compare to the previous. This element will be < raw conversion,
    // so reverse the order of the subtraction.
    --kv;
    if (raw_conversion - kv->first < diff) {
      *conversion = kv->second;
    }
  }

  return 0;
}

template <typename TMetadata, typename TV4L2, typename TMapKey>
int MapConverter<TMetadata, TV4L2, TMapKey>::V4L2ToMetadata(
    TV4L2 value, TMetadata* conversion) {
  HAL_LOG_ENTER();

  // Unfortunately no bi-directional map lookup in C++.
  // Breaking on second, not first found so that a warning
  // can be given if there are multiple values.
  size_t count = 0;
  int res;
  for (auto kv : conversion_map_) {
    if (kv.second == value) {
      ++count;
      if (count == 1) {
        // First match.
        res = wrapped_converter_->V4L2ToMetadata(kv.first, conversion);
      } else {
        // second match.
        break;
      }
    }
  }

  if (count == 0) {
    HAL_LOGE("Couldn't find map conversion of V4L2 value %d.", value);
    return -EINVAL;
  } else if (count > 1) {
    HAL_LOGW("Multiple map conversions found for V4L2 value %d, using first.",
             value);
  }
  return res;
}

}  // namespace v4l2_camera_hal

#endif  // V4L2_CAMERA_HAL_METADATA_MAP_CONVERTER_H_