1/*
2 * Copyright 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 "stream_format.h"
18
19#include <linux/videodev2.h>
20
21#include <system/graphics.h>
22
23#include "arc/image_processor.h"
24#include "common.h"
25
26namespace v4l2_camera_hal {
27
28using arc::SupportedFormat;
29using arc::SupportedFormats;
30
31static const std::vector<uint32_t> GetSupportedFourCCs() {
32  // The preference of supported fourccs in the list is from high to low.
33  static const std::vector<uint32_t> kSupportedFourCCs = {V4L2_PIX_FMT_YUYV,
34                                                          V4L2_PIX_FMT_MJPEG};
35  return kSupportedFourCCs;
36}
37
38StreamFormat::StreamFormat(int format, uint32_t width, uint32_t height)
39    // TODO(b/30000211): multiplanar support.
40    : type_(V4L2_BUF_TYPE_VIDEO_CAPTURE),
41      v4l2_pixel_format_(StreamFormat::HalToV4L2PixelFormat(format)),
42      width_(width),
43      height_(height),
44      bytes_per_line_(0),
45      min_buffer_size_(0) {}
46
47StreamFormat::StreamFormat(const v4l2_format& format)
48    : type_(format.type),
49      // TODO(b/30000211): multiplanar support.
50      v4l2_pixel_format_(format.fmt.pix.pixelformat),
51      width_(format.fmt.pix.width),
52      height_(format.fmt.pix.height),
53      bytes_per_line_(format.fmt.pix.bytesperline),
54      min_buffer_size_(format.fmt.pix.sizeimage) {}
55
56StreamFormat::StreamFormat(const arc::SupportedFormat& format)
57    : type_(V4L2_BUF_TYPE_VIDEO_CAPTURE),
58      v4l2_pixel_format_(format.fourcc),
59      width_(format.width),
60      height_(format.height),
61      bytes_per_line_(0),
62      min_buffer_size_(0) {}
63
64void StreamFormat::FillFormatRequest(v4l2_format* format) const {
65  memset(format, 0, sizeof(*format));
66  format->type = type_;
67  format->fmt.pix.pixelformat = v4l2_pixel_format_;
68  format->fmt.pix.width = width_;
69  format->fmt.pix.height = height_;
70  // Bytes per line and min buffer size are outputs set by the driver,
71  // not part of the request.
72}
73
74FormatCategory StreamFormat::Category() const {
75  switch (v4l2_pixel_format_) {
76    case V4L2_PIX_FMT_JPEG:
77      return kFormatCategoryStalling;
78    case V4L2_PIX_FMT_YUV420:  // Fall through.
79    case V4L2_PIX_FMT_BGR32:
80      return kFormatCategoryNonStalling;
81    default:
82      // Note: currently no supported RAW formats.
83      return kFormatCategoryUnknown;
84  }
85}
86
87bool StreamFormat::operator==(const StreamFormat& other) const {
88  // Used to check that a requested format was actually set, so
89  // don't compare bytes per line or min buffer size.
90  return (type_ == other.type_ &&
91          v4l2_pixel_format_ == other.v4l2_pixel_format_ &&
92          width_ == other.width_ && height_ == other.height_);
93}
94
95bool StreamFormat::operator!=(const StreamFormat& other) const {
96  return !(*this == other);
97}
98
99int StreamFormat::V4L2ToHalPixelFormat(uint32_t v4l2_pixel_format) {
100  // Translate V4L2 format to HAL format.
101  switch (v4l2_pixel_format) {
102    case V4L2_PIX_FMT_BGR32:
103      return HAL_PIXEL_FORMAT_RGBA_8888;
104    case V4L2_PIX_FMT_JPEG:
105      return HAL_PIXEL_FORMAT_BLOB;
106    case V4L2_PIX_FMT_NV21:
107      return HAL_PIXEL_FORMAT_YCrCb_420_SP;
108    case V4L2_PIX_FMT_YUV420:
109      return HAL_PIXEL_FORMAT_YCbCr_420_888;
110    case V4L2_PIX_FMT_YUYV:
111      return HAL_PIXEL_FORMAT_YCbCr_422_I;
112    case V4L2_PIX_FMT_YVU420:
113      return HAL_PIXEL_FORMAT_YV12;
114    default:
115      // Unrecognized format.
116      HAL_LOGV("Unrecognized v4l2 pixel format %u", v4l2_pixel_format);
117      break;
118  }
119  return -1;
120}
121
122uint32_t StreamFormat::HalToV4L2PixelFormat(int hal_pixel_format) {
123  switch (hal_pixel_format) {
124    case HAL_PIXEL_FORMAT_BLOB:
125      return V4L2_PIX_FMT_JPEG;
126    case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:  // Fall-through
127    case HAL_PIXEL_FORMAT_RGBA_8888:
128      return V4L2_PIX_FMT_BGR32;
129    case HAL_PIXEL_FORMAT_YCbCr_420_888:
130      // This is a flexible YUV format that depends on platform. Different
131      // platform may have different format. It can be YVU420 or NV12. Now we
132      // return YVU420 first.
133      // TODO(): call drm_drv.get_fourcc() to get correct format.
134      return V4L2_PIX_FMT_YUV420;
135    case HAL_PIXEL_FORMAT_YCbCr_422_I:
136      return V4L2_PIX_FMT_YUYV;
137    case HAL_PIXEL_FORMAT_YCrCb_420_SP:
138      return V4L2_PIX_FMT_NV21;
139    case HAL_PIXEL_FORMAT_YV12:
140      return V4L2_PIX_FMT_YVU420;
141    default:
142      HAL_LOGV("Pixel format 0x%x is unsupported.", hal_pixel_format);
143      break;
144  }
145  return -1;
146}
147
148// Copy the qualified format into out_format and return true if there is a
149// proper and fitting format in the given format lists.
150bool StreamFormat::FindBestFitFormat(const SupportedFormats& supported_formats,
151                                     const SupportedFormats& qualified_formats,
152                                     uint32_t fourcc, uint32_t width,
153                                     uint32_t height,
154                                     SupportedFormat* out_format) {
155  // Match exact format and resolution if possible.
156  for (const auto& format : supported_formats) {
157    if (format.fourcc == fourcc && format.width == width &&
158        format.height == height) {
159      if (out_format != NULL) {
160        *out_format = format;
161      }
162      return true;
163    }
164  }
165  // All conversions will be done through CachedFrame for now, which will
166  // immediately convert the qualified format into YU12 (YUV420). We check
167  // here that the conversion between YU12 and |fourcc| is supported.
168  if (!arc::ImageProcessor::SupportsConversion(V4L2_PIX_FMT_YUV420, fourcc)) {
169    HAL_LOGE("Conversion between YU12 and 0x%x not supported.", fourcc);
170    return false;
171  }
172
173  // Choose the qualified format with a matching resolution.
174  for (const auto& format : qualified_formats) {
175    if (format.width == width && format.height == height) {
176      if (out_format != NULL) {
177        *out_format = format;
178      }
179      return true;
180    }
181  }
182  return false;
183}
184
185// Copy corresponding format into out_format and return true by matching
186// resolution |width|x|height| in |formats|.
187bool StreamFormat::FindFormatByResolution(const SupportedFormats& formats,
188                                          uint32_t width, uint32_t height,
189                                          SupportedFormat* out_format) {
190  for (const auto& format : formats) {
191    if (format.width == width && format.height == height) {
192      if (out_format != NULL) {
193        *out_format = format;
194      }
195      return true;
196    }
197  }
198  return false;
199}
200
201SupportedFormats StreamFormat::GetQualifiedFormats(
202    const SupportedFormats& supported_formats) {
203  // The preference of supported fourccs in the list is from high to low.
204  const std::vector<uint32_t> supported_fourccs = GetSupportedFourCCs();
205  SupportedFormats qualified_formats;
206  for (const auto& supported_fourcc : supported_fourccs) {
207    for (const auto& supported_format : supported_formats) {
208      if (supported_format.fourcc != supported_fourcc) {
209        continue;
210      }
211
212      // Skip if |qualified_formats| already has the same resolution with a more
213      // preferred fourcc.
214      if (FindFormatByResolution(qualified_formats, supported_format.width,
215                                 supported_format.height, NULL)) {
216        continue;
217      }
218      qualified_formats.push_back(supported_format);
219    }
220  }
221  return qualified_formats;
222}
223
224}  // namespace v4l2_camera_hal
225