| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "media/capture/video/win/capability_list_win.h" |
| |
| #include <algorithm> |
| #include <functional> |
| |
| #include "base/check.h" |
| #include "media/capture/video_capture_types.h" |
| |
| #include "base/logging.h" |
| namespace media { |
| |
| namespace { |
| |
| // Compares the priority of the capture formats. Returns true if |lhs| is the |
| // preferred capture format in comparison with |rhs|. Returns false otherwise. |
| bool CompareCapability(const VideoCaptureFormat& requested, |
| const CapabilityWin& lhs, |
| const CapabilityWin& rhs) { |
| // When 16-bit format or NV12 is requested and available, avoid other formats. |
| // If both lhs and rhs are 16-bit, we still need to compare them based on |
| // height, width and frame rate. |
| const bool use_requested = |
| (requested.pixel_format == media::PIXEL_FORMAT_Y16) || |
| (requested.pixel_format == media::PIXEL_FORMAT_NV12); |
| if (use_requested && |
| lhs.supported_format.pixel_format != rhs.supported_format.pixel_format) { |
| if (lhs.supported_format.pixel_format == requested.pixel_format) |
| return true; |
| if (rhs.supported_format.pixel_format == requested.pixel_format) |
| return false; |
| } |
| const int diff_height_lhs = std::abs( |
| lhs.supported_format.frame_size.height() - requested.frame_size.height()); |
| const int diff_height_rhs = std::abs( |
| rhs.supported_format.frame_size.height() - requested.frame_size.height()); |
| if (diff_height_lhs != diff_height_rhs) |
| return diff_height_lhs < diff_height_rhs; |
| |
| const int diff_width_lhs = std::abs(lhs.supported_format.frame_size.width() - |
| requested.frame_size.width()); |
| const int diff_width_rhs = std::abs(rhs.supported_format.frame_size.width() - |
| requested.frame_size.width()); |
| if (diff_width_lhs != diff_width_rhs) |
| return diff_width_lhs < diff_width_rhs; |
| |
| const float diff_fps_lhs = |
| std::fabs(lhs.supported_format.frame_rate - requested.frame_rate); |
| const float diff_fps_rhs = |
| std::fabs(rhs.supported_format.frame_rate - requested.frame_rate); |
| if (diff_fps_lhs != diff_fps_rhs) |
| return diff_fps_lhs < diff_fps_rhs; |
| |
| // Compare by internal pixel format to avoid conversions when possible. |
| if (lhs.source_pixel_format != rhs.source_pixel_format) { |
| // Choose the format with no conversion if possible. |
| if (lhs.source_pixel_format == requested.pixel_format) |
| return true; |
| if (rhs.source_pixel_format == requested.pixel_format) |
| return false; |
| // Prefer I420<->NV12 conversion over all. |
| if ((lhs.source_pixel_format == PIXEL_FORMAT_NV12 && |
| requested.pixel_format == PIXEL_FORMAT_I420) || |
| (lhs.source_pixel_format == PIXEL_FORMAT_I420 && |
| requested.pixel_format == PIXEL_FORMAT_NV12)) { |
| return true; |
| } |
| if ((rhs.source_pixel_format == PIXEL_FORMAT_NV12 && |
| requested.pixel_format == PIXEL_FORMAT_I420) || |
| (rhs.source_pixel_format == PIXEL_FORMAT_I420 && |
| requested.pixel_format == PIXEL_FORMAT_NV12)) { |
| return false; |
| } |
| // YUY2<->NV12 is the next best. |
| if ((lhs.source_pixel_format == PIXEL_FORMAT_NV12 && |
| requested.pixel_format == PIXEL_FORMAT_YUY2) || |
| (lhs.source_pixel_format == PIXEL_FORMAT_YUY2 && |
| requested.pixel_format == PIXEL_FORMAT_NV12)) { |
| return true; |
| } |
| if ((rhs.source_pixel_format == PIXEL_FORMAT_NV12 && |
| requested.pixel_format == PIXEL_FORMAT_YUY2) || |
| (rhs.source_pixel_format == PIXEL_FORMAT_YUY2 && |
| requested.pixel_format == PIXEL_FORMAT_NV12)) { |
| return false; |
| } |
| } |
| |
| return VideoCaptureFormat::ComparePixelFormatPreference( |
| lhs.supported_format.pixel_format, rhs.supported_format.pixel_format); |
| } |
| |
| } // namespace |
| |
| const CapabilityWin& GetBestMatchedCapability( |
| const VideoCaptureFormat& requested, |
| const CapabilityList& capabilities) { |
| DCHECK(!capabilities.empty()); |
| const CapabilityWin* best_match = &(*capabilities.begin()); |
| for (const CapabilityWin& capability : capabilities) { |
| if (CompareCapability(requested, capability, *best_match)) { |
| best_match = &capability; |
| } |
| } |
| return *best_match; |
| } |
| |
| } // namespace media |