1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "media/video/capture/win/capability_list_win.h"
6
7#include <algorithm>
8
9#include "base/logging.h"
10
11namespace media {
12namespace {
13
14// Help structure used for comparing video capture capabilities.
15struct ResolutionDiff {
16  const VideoCaptureCapabilityWin* capability;
17  int diff_height;
18  int diff_width;
19  int diff_frame_rate;
20};
21
22bool CompareHeight(const ResolutionDiff& item1, const ResolutionDiff& item2) {
23  return abs(item1.diff_height) < abs(item2.diff_height);
24}
25
26bool CompareWidth(const ResolutionDiff& item1, const ResolutionDiff& item2) {
27  return abs(item1.diff_width) < abs(item2.diff_width);
28}
29
30bool CompareFrameRate(const ResolutionDiff& item1,
31                      const ResolutionDiff& item2) {
32  return abs(item1.diff_frame_rate) < abs(item2.diff_frame_rate);
33}
34
35bool CompareColor(const ResolutionDiff& item1, const ResolutionDiff& item2) {
36  return item1.capability->supported_format.pixel_format <
37         item2.capability->supported_format.pixel_format;
38}
39
40}  // namespace.
41
42CapabilityList::CapabilityList() {
43  DetachFromThread();
44}
45
46CapabilityList::~CapabilityList() {}
47
48// Appends an entry to the list.
49void CapabilityList::Add(const VideoCaptureCapabilityWin& capability) {
50  DCHECK(CalledOnValidThread());
51  capabilities_.push_back(capability);
52}
53
54const VideoCaptureCapabilityWin& CapabilityList::GetBestMatchedFormat(
55    int requested_width,
56    int requested_height,
57    float requested_frame_rate) const {
58  DCHECK(CalledOnValidThread());
59  DCHECK(!capabilities_.empty());
60
61  std::list<ResolutionDiff> diff_list;
62
63  // Loop through the candidates to create a list of differentials between the
64  // requested resolution and the camera capability.
65  for (Capabilities::const_iterator it = capabilities_.begin();
66       it != capabilities_.end(); ++it) {
67    ResolutionDiff diff;
68    diff.capability = &(*it);
69    diff.diff_width = it->supported_format.frame_size.width() - requested_width;
70    diff.diff_height =
71        it->supported_format.frame_size.height() - requested_height;
72    // The 1000 allows using integer arithmetic for f.i. 29.971 fps.
73    diff.diff_frame_rate =
74        1000 * ((static_cast<float>(it->frame_rate_numerator) /
75                 it->frame_rate_denominator) -
76                requested_frame_rate);
77    diff_list.push_back(diff);
78  }
79
80  // Sort the best height candidates.
81  diff_list.sort(&CompareHeight);
82  int best_diff = diff_list.front().diff_height;
83  for (std::list<ResolutionDiff>::iterator it = diff_list.begin();
84       it != diff_list.end(); ++it) {
85    if (it->diff_height != best_diff) {
86      // Remove all candidates but the best.
87      diff_list.erase(it, diff_list.end());
88      break;
89    }
90  }
91
92  // Sort the best width candidates.
93  diff_list.sort(&CompareWidth);
94  best_diff = diff_list.front().diff_width;
95  for (std::list<ResolutionDiff>::iterator it = diff_list.begin();
96       it != diff_list.end(); ++it) {
97    if (it->diff_width != best_diff) {
98      // Remove all candidates but the best.
99      diff_list.erase(it, diff_list.end());
100      break;
101    }
102  }
103
104  // Sort the best frame rate candidates.
105  diff_list.sort(&CompareFrameRate);
106  best_diff = diff_list.front().diff_frame_rate;
107  for (std::list<ResolutionDiff>::iterator it = diff_list.begin();
108       it != diff_list.end(); ++it) {
109    if (it->diff_frame_rate != best_diff) {
110      diff_list.erase(it, diff_list.end());
111      break;
112    }
113  }
114
115  // Decide the best color format.
116  diff_list.sort(&CompareColor);
117  return *diff_list.front().capability;
118}
119
120}  // namespace media
121