summaryrefslogtreecommitdiff
path: root/chromium/media/capture/video/win/capability_list_win.cc
blob: 5ce95b170373e57f12e4e57dc14614be016e69e1 (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
// 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