Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / common / gpu / media / v4l2_device.cc
blob85cf1bea27db8246cc4261603da180ab73b5264e
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(Type type) : type_(type) {
19 V4L2Device::~V4L2Device() {
22 // static
23 scoped_refptr<V4L2Device> V4L2Device::Create(Type type) {
24 DVLOG(3) << __PRETTY_FUNCTION__;
26 scoped_refptr<GenericV4L2Device> generic_device(new GenericV4L2Device(type));
27 if (generic_device->Initialize())
28 return generic_device;
30 #if defined(ARCH_CPU_ARMEL)
31 scoped_refptr<TegraV4L2Device> tegra_device(new TegraV4L2Device(type));
32 if (tegra_device->Initialize())
33 return tegra_device;
34 #endif
36 DVLOG(1) << "Failed to create V4L2Device";
37 return scoped_refptr<V4L2Device>();
40 // static
41 media::VideoPixelFormat V4L2Device::V4L2PixFmtToVideoPixelFormat(
42 uint32 pix_fmt) {
43 switch (pix_fmt) {
44 case V4L2_PIX_FMT_NV12:
45 case V4L2_PIX_FMT_NV12M:
46 // MT21 is similar to NV21. We only need the information like number of
47 // planes, plane size, and bytes per row. We do not set the format of
48 // media::VideoFrame to be MT21. Pretend it is NV12 so we don't need to
49 // add PIXEL_FORMAT_MT21.
50 // TODO(wuchengli): find a better way to handle this.
51 case V4L2_PIX_FMT_MT21:
52 return media::PIXEL_FORMAT_NV12;
54 case V4L2_PIX_FMT_YUV420:
55 case V4L2_PIX_FMT_YUV420M:
56 return media::PIXEL_FORMAT_I420;
58 case V4L2_PIX_FMT_RGB32:
59 return media::PIXEL_FORMAT_ARGB;
61 default:
62 LOG(FATAL) << "Add more cases as needed";
63 return media::PIXEL_FORMAT_UNKNOWN;
67 // static
68 uint32 V4L2Device::VideoPixelFormatToV4L2PixFmt(
69 media::VideoPixelFormat format) {
70 switch (format) {
71 case media::PIXEL_FORMAT_NV12:
72 return V4L2_PIX_FMT_NV12M;
74 case media::PIXEL_FORMAT_I420:
75 return V4L2_PIX_FMT_YUV420M;
77 default:
78 LOG(FATAL) << "Add more cases as needed";
79 return 0;
83 // static
84 uint32 V4L2Device::VideoCodecProfileToV4L2PixFmt(
85 media::VideoCodecProfile profile,
86 bool slice_based) {
87 if (profile >= media::H264PROFILE_MIN &&
88 profile <= media::H264PROFILE_MAX) {
89 if (slice_based)
90 return V4L2_PIX_FMT_H264_SLICE;
91 else
92 return V4L2_PIX_FMT_H264;
93 } else if (profile >= media::VP8PROFILE_MIN &&
94 profile <= media::VP8PROFILE_MAX) {
95 if (slice_based)
96 return V4L2_PIX_FMT_VP8_FRAME;
97 else
98 return V4L2_PIX_FMT_VP8;
99 } else if (profile >= media::VP9PROFILE_MIN &&
100 profile <= media::VP9PROFILE_MAX) {
101 return V4L2_PIX_FMT_VP9;
102 } else {
103 LOG(FATAL) << "Add more cases as needed";
104 return 0;
108 // static
109 uint32_t V4L2Device::V4L2PixFmtToDrmFormat(uint32_t format) {
110 switch (format) {
111 case V4L2_PIX_FMT_NV12:
112 case V4L2_PIX_FMT_NV12M:
113 return DRM_FORMAT_NV12;
115 case V4L2_PIX_FMT_MT21:
116 // TODO(wuchengli): Change to DRM_FORMAT_MT21.
117 return DRM_FORMAT_MT12;
119 case V4L2_PIX_FMT_YUV420:
120 case V4L2_PIX_FMT_YUV420M:
121 return DRM_FORMAT_YUV420;
123 case V4L2_PIX_FMT_RGB32:
124 return DRM_FORMAT_ARGB8888;
126 default:
127 DVLOG(1) << "Add more cases as needed";
128 return 0;
132 // static
133 gfx::Size V4L2Device::CodedSizeFromV4L2Format(struct v4l2_format format) {
134 gfx::Size coded_size;
135 gfx::Size visible_size;
136 media::VideoPixelFormat frame_format = media::PIXEL_FORMAT_UNKNOWN;
137 size_t bytesperline = 0;
138 // Total bytes in the frame.
139 size_t sizeimage = 0;
141 if (V4L2_TYPE_IS_MULTIPLANAR(format.type)) {
142 DCHECK_GT(format.fmt.pix_mp.num_planes, 0);
143 bytesperline =
144 base::checked_cast<int>(format.fmt.pix_mp.plane_fmt[0].bytesperline);
145 for (size_t i = 0; i < format.fmt.pix_mp.num_planes; ++i) {
146 sizeimage +=
147 base::checked_cast<int>(format.fmt.pix_mp.plane_fmt[i].sizeimage);
149 visible_size.SetSize(base::checked_cast<int>(format.fmt.pix_mp.width),
150 base::checked_cast<int>(format.fmt.pix_mp.height));
151 frame_format =
152 V4L2Device::V4L2PixFmtToVideoPixelFormat(format.fmt.pix_mp.pixelformat);
153 } else {
154 bytesperline = base::checked_cast<int>(format.fmt.pix.bytesperline);
155 sizeimage = base::checked_cast<int>(format.fmt.pix.sizeimage);
156 visible_size.SetSize(base::checked_cast<int>(format.fmt.pix.width),
157 base::checked_cast<int>(format.fmt.pix.height));
158 frame_format =
159 V4L2Device::V4L2PixFmtToVideoPixelFormat(format.fmt.pix.pixelformat);
162 // V4L2 does not provide per-plane bytesperline (bpl) when different
163 // components are sharing one physical plane buffer. In this case, it only
164 // provides bpl for the first component in the plane. So we can't depend on it
165 // for calculating height, because bpl may vary within one physical plane
166 // buffer. For example, YUV420 contains 3 components in one physical plane,
167 // with Y at 8 bits per pixel, and Cb/Cr at 4 bits per pixel per component,
168 // but we only get 8 pits per pixel from bytesperline in physical plane 0.
169 // So we need to get total frame bpp from elsewhere to calculate coded height.
171 // We need bits per pixel for one component only to calculate
172 // coded_width from bytesperline.
173 int plane_horiz_bits_per_pixel =
174 media::VideoFrame::PlaneHorizontalBitsPerPixel(frame_format, 0);
176 // Adding up bpp for each component will give us total bpp for all components.
177 int total_bpp = 0;
178 for (size_t i = 0; i < media::VideoFrame::NumPlanes(frame_format); ++i)
179 total_bpp += media::VideoFrame::PlaneBitsPerPixel(frame_format, i);
181 if (sizeimage == 0 || bytesperline == 0 || plane_horiz_bits_per_pixel == 0 ||
182 total_bpp == 0 || (bytesperline * 8) % plane_horiz_bits_per_pixel != 0) {
183 LOG(ERROR) << "Invalid format provided";
184 return coded_size;
187 // Coded width can be calculated by taking the first component's bytesperline,
188 // which in V4L2 always applies to the first component in physical plane
189 // buffer.
190 int coded_width = bytesperline * 8 / plane_horiz_bits_per_pixel;
191 // Sizeimage is coded_width * coded_height * total_bpp.
192 int coded_height = sizeimage * 8 / coded_width / total_bpp;
194 coded_size.SetSize(coded_width, coded_height);
195 // It's possible the driver gave us a slightly larger sizeimage than what
196 // would be calculated from coded size. This is technically not allowed, but
197 // some drivers (Exynos) like to have some additional alignment that is not a
198 // multiple of bytesperline. The best thing we can do is to compensate by
199 // aligning to next full row.
200 if (sizeimage > media::VideoFrame::AllocationSize(frame_format, coded_size))
201 coded_size.SetSize(coded_width, coded_height + 1);
202 DVLOG(3) << "coded_size=" << coded_size.ToString();
204 // Sanity checks. Calculated coded size has to contain given visible size
205 // and fulfill buffer byte size requirements.
206 DCHECK(gfx::Rect(coded_size).Contains(gfx::Rect(visible_size)));
207 DCHECK_LE(sizeimage,
208 media::VideoFrame::AllocationSize(frame_format, coded_size));
210 return coded_size;
213 void V4L2Device::GetSupportedResolution(uint32_t pixelformat,
214 gfx::Size* min_resolution,
215 gfx::Size* max_resolution) {
216 max_resolution->SetSize(0, 0);
217 min_resolution->SetSize(0, 0);
218 v4l2_frmsizeenum frame_size;
219 memset(&frame_size, 0, sizeof(frame_size));
220 frame_size.pixel_format = pixelformat;
221 for (; Ioctl(VIDIOC_ENUM_FRAMESIZES, &frame_size) == 0; ++frame_size.index) {
222 if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
223 if (frame_size.discrete.width >=
224 base::checked_cast<uint32_t>(max_resolution->width()) &&
225 frame_size.discrete.height >=
226 base::checked_cast<uint32_t>(max_resolution->height())) {
227 max_resolution->SetSize(frame_size.discrete.width,
228 frame_size.discrete.height);
230 if (min_resolution->IsEmpty() ||
231 (frame_size.discrete.width <=
232 base::checked_cast<uint32_t>(min_resolution->width()) &&
233 frame_size.discrete.height <=
234 base::checked_cast<uint32_t>(min_resolution->height()))) {
235 min_resolution->SetSize(frame_size.discrete.width,
236 frame_size.discrete.height);
238 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE ||
239 frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
240 max_resolution->SetSize(frame_size.stepwise.max_width,
241 frame_size.stepwise.max_height);
242 min_resolution->SetSize(frame_size.stepwise.min_width,
243 frame_size.stepwise.min_height);
244 break;
247 if (max_resolution->IsEmpty()) {
248 max_resolution->SetSize(1920, 1088);
249 LOG(ERROR) << "GetSupportedResolution failed to get maximum resolution for "
250 << "fourcc " << std::hex << pixelformat
251 << ", fall back to " << max_resolution->ToString();
253 if (min_resolution->IsEmpty()) {
254 min_resolution->SetSize(16, 16);
255 LOG(ERROR) << "GetSupportedResolution failed to get minimum resolution for "
256 << "fourcc " << std::hex << pixelformat
257 << ", fall back to " << min_resolution->ToString();
261 media::VideoDecodeAccelerator::SupportedProfiles
262 V4L2Device::GetSupportedDecodeProfiles(const size_t num_formats,
263 const uint32_t pixelformats[]) {
264 DCHECK_EQ(type_, kDecoder);
265 media::VideoDecodeAccelerator::SupportedProfiles profiles;
266 media::VideoDecodeAccelerator::SupportedProfile profile;
267 v4l2_fmtdesc fmtdesc;
268 memset(&fmtdesc, 0, sizeof(fmtdesc));
269 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
271 for (; Ioctl(VIDIOC_ENUM_FMT, &fmtdesc) == 0; ++fmtdesc.index) {
272 if (std::find(pixelformats, pixelformats + num_formats,
273 fmtdesc.pixelformat) == pixelformats + num_formats)
274 continue;
275 int min_profile, max_profile;
276 switch (fmtdesc.pixelformat) {
277 case V4L2_PIX_FMT_H264:
278 case V4L2_PIX_FMT_H264_SLICE:
279 min_profile = media::H264PROFILE_MIN;
280 max_profile = media::H264PROFILE_MAX;
281 break;
282 case V4L2_PIX_FMT_VP8:
283 case V4L2_PIX_FMT_VP8_FRAME:
284 min_profile = media::VP8PROFILE_MIN;
285 max_profile = media::VP8PROFILE_MAX;
286 break;
287 case V4L2_PIX_FMT_VP9:
288 min_profile = media::VP9PROFILE_MIN;
289 max_profile = media::VP9PROFILE_MAX;
290 break;
291 default:
292 NOTREACHED() << "Unhandled pixelformat " << std::hex
293 << fmtdesc.pixelformat;
294 return profiles;
296 GetSupportedResolution(fmtdesc.pixelformat, &profile.min_resolution,
297 &profile.max_resolution);
298 for (int media_profile = min_profile; media_profile <= max_profile;
299 ++media_profile) {
300 profile.profile = static_cast<media::VideoCodecProfile>(media_profile);
301 profiles.push_back(profile);
304 return profiles;
307 } // namespace content