Revert of [Chromecast] Ignore interfaces not used to connect to internet. (patchset...
[chromium-blink-merge.git] / content / common / gpu / media / v4l2_device.cc
blob7629bac5e19109bc35c7eb065b72950a5b4582e0
1 // Copyright 2014 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.
5 #include <libdrm/drm_fourcc.h>
6 #include <linux/videodev2.h>
8 #include "base/numerics/safe_conversions.h"
9 #include "content/common/gpu/media/generic_v4l2_device.h"
10 #if defined(ARCH_CPU_ARMEL)
11 #include "content/common/gpu/media/tegra_v4l2_device.h"
12 #endif
14 namespace content {
16 V4L2Device::~V4L2Device() {
19 // static
20 scoped_refptr<V4L2Device> V4L2Device::Create(Type type) {
21 DVLOG(3) << __PRETTY_FUNCTION__;
23 scoped_refptr<GenericV4L2Device> generic_device(new GenericV4L2Device(type));
24 if (generic_device->Initialize())
25 return generic_device;
27 #if defined(ARCH_CPU_ARMEL)
28 scoped_refptr<TegraV4L2Device> tegra_device(new TegraV4L2Device(type));
29 if (tegra_device->Initialize())
30 return tegra_device;
31 #endif
33 DVLOG(1) << "Failed to create V4L2Device";
34 return scoped_refptr<V4L2Device>();
37 // static
38 media::VideoFrame::Format V4L2Device::V4L2PixFmtToVideoFrameFormat(
39 uint32 pix_fmt) {
40 switch (pix_fmt) {
41 case V4L2_PIX_FMT_NV12:
42 case V4L2_PIX_FMT_NV12M:
43 return media::VideoFrame::NV12;
45 case V4L2_PIX_FMT_YUV420:
46 case V4L2_PIX_FMT_YUV420M:
47 return media::VideoFrame::I420;
49 case V4L2_PIX_FMT_RGB32:
50 return media::VideoFrame::ARGB;
52 default:
53 LOG(FATAL) << "Add more cases as needed";
54 return media::VideoFrame::UNKNOWN;
58 // static
59 uint32 V4L2Device::VideoFrameFormatToV4L2PixFmt(
60 media::VideoFrame::Format format) {
61 switch (format) {
62 case media::VideoFrame::NV12:
63 return V4L2_PIX_FMT_NV12M;
65 case media::VideoFrame::I420:
66 return V4L2_PIX_FMT_YUV420M;
68 default:
69 LOG(FATAL) << "Add more cases as needed";
70 return 0;
74 // static
75 uint32 V4L2Device::VideoCodecProfileToV4L2PixFmt(
76 media::VideoCodecProfile profile,
77 bool slice_based) {
78 if (profile >= media::H264PROFILE_MIN &&
79 profile <= media::H264PROFILE_MAX) {
80 if (slice_based)
81 return V4L2_PIX_FMT_H264_SLICE;
82 else
83 return V4L2_PIX_FMT_H264;
84 } else if (profile >= media::VP8PROFILE_MIN &&
85 profile <= media::VP8PROFILE_MAX) {
86 if (slice_based)
87 return V4L2_PIX_FMT_VP8_FRAME;
88 else
89 return V4L2_PIX_FMT_VP8;
90 } else if (profile >= media::VP9PROFILE_MIN &&
91 profile <= media::VP9PROFILE_MAX) {
92 return V4L2_PIX_FMT_VP9;
93 } else {
94 LOG(FATAL) << "Add more cases as needed";
95 return 0;
99 // static
100 uint32_t V4L2Device::V4L2PixFmtToDrmFormat(uint32_t format) {
101 switch (format) {
102 case V4L2_PIX_FMT_NV12:
103 case V4L2_PIX_FMT_NV12M:
104 return DRM_FORMAT_NV12;
106 case V4L2_PIX_FMT_YUV420:
107 case V4L2_PIX_FMT_YUV420M:
108 return DRM_FORMAT_YUV420;
110 case V4L2_PIX_FMT_RGB32:
111 return DRM_FORMAT_ARGB8888;
113 default:
114 DVLOG(1) << "Add more cases as needed";
115 return 0;
119 // static
120 gfx::Size V4L2Device::CodedSizeFromV4L2Format(struct v4l2_format format) {
121 gfx::Size coded_size;
122 gfx::Size visible_size;
123 media::VideoFrame::Format frame_format = media::VideoFrame::UNKNOWN;
124 size_t bytesperline = 0;
125 // Total bytes in the frame.
126 size_t sizeimage = 0;
128 if (V4L2_TYPE_IS_MULTIPLANAR(format.type)) {
129 DCHECK_GT(format.fmt.pix_mp.num_planes, 0);
130 bytesperline =
131 base::checked_cast<int>(format.fmt.pix_mp.plane_fmt[0].bytesperline);
132 for (size_t i = 0; i < format.fmt.pix_mp.num_planes; ++i) {
133 sizeimage +=
134 base::checked_cast<int>(format.fmt.pix_mp.plane_fmt[i].sizeimage);
136 visible_size.SetSize(base::checked_cast<int>(format.fmt.pix_mp.width),
137 base::checked_cast<int>(format.fmt.pix_mp.height));
138 frame_format =
139 V4L2Device::V4L2PixFmtToVideoFrameFormat(format.fmt.pix_mp.pixelformat);
140 } else {
141 bytesperline = base::checked_cast<int>(format.fmt.pix.bytesperline);
142 sizeimage = base::checked_cast<int>(format.fmt.pix.sizeimage);
143 visible_size.SetSize(base::checked_cast<int>(format.fmt.pix.width),
144 base::checked_cast<int>(format.fmt.pix.height));
145 frame_format =
146 V4L2Device::V4L2PixFmtToVideoFrameFormat(format.fmt.pix.pixelformat);
149 // V4L2 does not provide per-plane bytesperline (bpl) when different
150 // components are sharing one physical plane buffer. In this case, it only
151 // provides bpl for the first component in the plane. So we can't depend on it
152 // for calculating height, because bpl may vary within one physical plane
153 // buffer. For example, YUV420 contains 3 components in one physical plane,
154 // with Y at 8 bits per pixel, and Cb/Cr at 4 bits per pixel per component,
155 // but we only get 8 pits per pixel from bytesperline in physical plane 0.
156 // So we need to get total frame bpp from elsewhere to calculate coded height.
158 // We need bits per pixel for one component only to calculate
159 // coded_width from bytesperline.
160 int plane_horiz_bits_per_pixel =
161 media::VideoFrame::PlaneHorizontalBitsPerPixel(frame_format, 0);
163 // Adding up bpp for each component will give us total bpp for all components.
164 int total_bpp = 0;
165 for (size_t i = 0; i < media::VideoFrame::NumPlanes(frame_format); ++i)
166 total_bpp += media::VideoFrame::PlaneBitsPerPixel(frame_format, i);
168 if (sizeimage == 0 || bytesperline == 0 || plane_horiz_bits_per_pixel == 0 ||
169 total_bpp == 0 || (bytesperline * 8) % plane_horiz_bits_per_pixel != 0) {
170 LOG(ERROR) << "Invalid format provided";
171 return coded_size;
174 // Coded width can be calculated by taking the first component's bytesperline,
175 // which in V4L2 always applies to the first component in physical plane
176 // buffer.
177 int coded_width = bytesperline * 8 / plane_horiz_bits_per_pixel;
178 // Sizeimage is coded_width * coded_height * total_bpp.
179 int coded_height = sizeimage * 8 / coded_width / total_bpp;
181 coded_size.SetSize(coded_width, coded_height);
182 // It's possible the driver gave us a slightly larger sizeimage than what
183 // would be calculated from coded size. This is technically not allowed, but
184 // some drivers (Exynos) like to have some additional alignment that is not a
185 // multiple of bytesperline. The best thing we can do is to compensate by
186 // aligning to next full row.
187 if (sizeimage > media::VideoFrame::AllocationSize(frame_format, coded_size))
188 coded_size.SetSize(coded_width, coded_height + 1);
189 DVLOG(3) << "coded_size=" << coded_size.ToString();
191 // Sanity checks. Calculated coded size has to contain given visible size
192 // and fulfill buffer byte size requirements.
193 DCHECK(gfx::Rect(coded_size).Contains(gfx::Rect(visible_size)));
194 DCHECK_LE(sizeimage,
195 media::VideoFrame::AllocationSize(frame_format, coded_size));
197 return coded_size;
200 } // namespace content