summaryrefslogtreecommitdiff
path: root/modules/camera/3_4/stream_format.cpp
blob: 401a2f09a4b44b8b36c63e1326b7c129e4f8031a (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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
/*
 * Copyright 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 "StreamFormat"

#include "stream_format.h"

#include <linux/videodev2.h>

#include <system/graphics.h>

#include "arc/image_processor.h"
#include "common.h"

namespace v4l2_camera_hal {

using arc::SupportedFormat;
using arc::SupportedFormats;

static const std::vector<uint32_t> GetSupportedFourCCs() {
  // The preference of supported fourccs in the list is from high to low.
  static const std::vector<uint32_t> kSupportedFourCCs = {V4L2_PIX_FMT_YUYV,
                                                          V4L2_PIX_FMT_MJPEG};
  return kSupportedFourCCs;
}

StreamFormat::StreamFormat(int format, uint32_t width, uint32_t height)
    // TODO(b/30000211): multiplanar support.
    : type_(V4L2_BUF_TYPE_VIDEO_CAPTURE),
      v4l2_pixel_format_(StreamFormat::HalToV4L2PixelFormat(format)),
      width_(width),
      height_(height),
      bytes_per_line_(0) {}

StreamFormat::StreamFormat(const v4l2_format& format)
    : type_(format.type),
      // TODO(b/30000211): multiplanar support.
      v4l2_pixel_format_(format.fmt.pix.pixelformat),
      width_(format.fmt.pix.width),
      height_(format.fmt.pix.height),
      bytes_per_line_(format.fmt.pix.bytesperline) {}

StreamFormat::StreamFormat(const arc::SupportedFormat& format)
    : type_(V4L2_BUF_TYPE_VIDEO_CAPTURE),
      v4l2_pixel_format_(format.fourcc),
      width_(format.width),
      height_(format.height),
      bytes_per_line_(0) {}

void StreamFormat::FillFormatRequest(v4l2_format* format) const {
  memset(format, 0, sizeof(*format));
  format->type = type_;
  format->fmt.pix.pixelformat = v4l2_pixel_format_;
  format->fmt.pix.width = width_;
  format->fmt.pix.height = height_;
  // Bytes per line and min buffer size are outputs set by the driver,
  // not part of the request.
}

FormatCategory StreamFormat::Category() const {
  switch (v4l2_pixel_format_) {
    case V4L2_PIX_FMT_JPEG:
      return kFormatCategoryStalling;
    case V4L2_PIX_FMT_YUV420:  // Fall through.
    case V4L2_PIX_FMT_BGR32:
      return kFormatCategoryNonStalling;
    default:
      // Note: currently no supported RAW formats.
      return kFormatCategoryUnknown;
  }
}

bool StreamFormat::operator==(const StreamFormat& other) const {
  // Used to check that a requested format was actually set, so
  // don't compare bytes per line or min buffer size.
  return (type_ == other.type_ &&
          v4l2_pixel_format_ == other.v4l2_pixel_format_ &&
          width_ == other.width_ && height_ == other.height_);
}

bool StreamFormat::operator!=(const StreamFormat& other) const {
  return !(*this == other);
}

int StreamFormat::V4L2ToHalPixelFormat(uint32_t v4l2_pixel_format) {
  // Translate V4L2 format to HAL format.
  switch (v4l2_pixel_format) {
    case V4L2_PIX_FMT_BGR32:
      return HAL_PIXEL_FORMAT_RGBA_8888;
    case V4L2_PIX_FMT_JPEG:
      return HAL_PIXEL_FORMAT_BLOB;
    case V4L2_PIX_FMT_NV21:
      return HAL_PIXEL_FORMAT_YCrCb_420_SP;
    case V4L2_PIX_FMT_YUV420:
      return HAL_PIXEL_FORMAT_YCbCr_420_888;
    case V4L2_PIX_FMT_YUYV:
      return HAL_PIXEL_FORMAT_YCbCr_422_I;
    case V4L2_PIX_FMT_YVU420:
      return HAL_PIXEL_FORMAT_YV12;
    default:
      // Unrecognized format.
      HAL_LOGV("Unrecognized v4l2 pixel format %u", v4l2_pixel_format);
      break;
  }
  return -1;
}

uint32_t StreamFormat::HalToV4L2PixelFormat(int hal_pixel_format) {
  switch (hal_pixel_format) {
    case HAL_PIXEL_FORMAT_BLOB:
      return V4L2_PIX_FMT_JPEG;
    case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:  // Fall-through
    case HAL_PIXEL_FORMAT_RGBA_8888:
      return V4L2_PIX_FMT_BGR32;
    case HAL_PIXEL_FORMAT_YCbCr_420_888:
      // This is a flexible YUV format that depends on platform. Different
      // platform may have different format. It can be YVU420 or NV12. Now we
      // return YVU420 first.
      // TODO(): call drm_drv.get_fourcc() to get correct format.
      return V4L2_PIX_FMT_YUV420;
    case HAL_PIXEL_FORMAT_YCbCr_422_I:
      return V4L2_PIX_FMT_YUYV;
    case HAL_PIXEL_FORMAT_YCrCb_420_SP:
      return V4L2_PIX_FMT_NV21;
    case HAL_PIXEL_FORMAT_YV12:
      return V4L2_PIX_FMT_YVU420;
    default:
      HAL_LOGV("Pixel format 0x%x is unsupported.", hal_pixel_format);
      break;
  }
  return -1;
}

// Copy the qualified format into out_format and return true if there is a
// proper and fitting format in the given format lists.
bool StreamFormat::FindBestFitFormat(const SupportedFormats& supported_formats,
                                     const SupportedFormats& qualified_formats,
                                     uint32_t fourcc, uint32_t width,
                                     uint32_t height,
                                     SupportedFormat* out_format) {
  // Match exact format and resolution if possible.
  for (const auto& format : supported_formats) {
    if (format.fourcc == fourcc && format.width == width &&
        format.height == height) {
      if (out_format != NULL) {
        *out_format = format;
      }
      return true;
    }
  }
  // All conversions will be done through CachedFrame for now, which will
  // immediately convert the qualified format into YU12 (YUV420). We check
  // here that the conversion between YU12 and |fourcc| is supported.
  if (!arc::ImageProcessor::SupportsConversion(V4L2_PIX_FMT_YUV420, fourcc)) {
    HAL_LOGE("Conversion between YU12 and 0x%x not supported.", fourcc);
    return false;
  }

  // Choose the qualified format with a matching resolution.
  for (const auto& format : qualified_formats) {
    if (format.width == width && format.height == height) {
      if (out_format != NULL) {
        *out_format = format;
      }
      return true;
    }
  }
  return false;
}

// Copy corresponding format into out_format and return true by matching
// resolution |width|x|height| in |formats|.
bool StreamFormat::FindFormatByResolution(const SupportedFormats& formats,
                                          uint32_t width, uint32_t height,
                                          SupportedFormat* out_format) {
  for (const auto& format : formats) {
    if (format.width == width && format.height == height) {
      if (out_format != NULL) {
        *out_format = format;
      }
      return true;
    }
  }
  return false;
}

SupportedFormats StreamFormat::GetQualifiedFormats(
    const SupportedFormats& supported_formats) {
  // The preference of supported fourccs in the list is from high to low.
  const std::vector<uint32_t> supported_fourccs = GetSupportedFourCCs();
  SupportedFormats qualified_formats;
  for (const auto& supported_fourcc : supported_fourccs) {
    for (const auto& supported_format : supported_formats) {
      if (supported_format.fourcc != supported_fourcc) {
        continue;
      }

      // Skip if |qualified_formats| already has the same resolution with a more
      // preferred fourcc.
      if (FindFormatByResolution(qualified_formats, supported_format.width,
                                 supported_format.height, NULL)) {
        continue;
      }
      qualified_formats.push_back(supported_format);
    }
  }
  return qualified_formats;
}

}  // namespace v4l2_camera_hal