/* * 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 #include "arc/image_processor.h" #include "common.h" namespace v4l2_camera_hal { using arc::SupportedFormat; using arc::SupportedFormats; static const std::vector GetSupportedFourCCs() { // The preference of supported fourccs in the list is from high to low. static const std::vector 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 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