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"
16 V4L2Device::V4L2Device(Type type
) : type_(type
) {
19 V4L2Device::~V4L2Device() {
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())
36 DVLOG(1) << "Failed to create V4L2Device";
37 return scoped_refptr
<V4L2Device
>();
41 media::VideoPixelFormat
V4L2Device::V4L2PixFmtToVideoPixelFormat(
44 case V4L2_PIX_FMT_NV12
:
45 case V4L2_PIX_FMT_NV12M
:
46 return media::PIXEL_FORMAT_NV12
;
48 case V4L2_PIX_FMT_YUV420
:
49 case V4L2_PIX_FMT_YUV420M
:
50 return media::PIXEL_FORMAT_I420
;
52 case V4L2_PIX_FMT_RGB32
:
53 return media::PIXEL_FORMAT_ARGB
;
56 LOG(FATAL
) << "Add more cases as needed";
57 return media::PIXEL_FORMAT_UNKNOWN
;
62 uint32
V4L2Device::VideoPixelFormatToV4L2PixFmt(
63 media::VideoPixelFormat format
) {
65 case media::PIXEL_FORMAT_NV12
:
66 return V4L2_PIX_FMT_NV12M
;
68 case media::PIXEL_FORMAT_I420
:
69 return V4L2_PIX_FMT_YUV420M
;
72 LOG(FATAL
) << "Add more cases as needed";
78 uint32
V4L2Device::VideoCodecProfileToV4L2PixFmt(
79 media::VideoCodecProfile profile
,
81 if (profile
>= media::H264PROFILE_MIN
&&
82 profile
<= media::H264PROFILE_MAX
) {
84 return V4L2_PIX_FMT_H264_SLICE
;
86 return V4L2_PIX_FMT_H264
;
87 } else if (profile
>= media::VP8PROFILE_MIN
&&
88 profile
<= media::VP8PROFILE_MAX
) {
90 return V4L2_PIX_FMT_VP8_FRAME
;
92 return V4L2_PIX_FMT_VP8
;
93 } else if (profile
>= media::VP9PROFILE_MIN
&&
94 profile
<= media::VP9PROFILE_MAX
) {
95 return V4L2_PIX_FMT_VP9
;
97 LOG(FATAL
) << "Add more cases as needed";
103 uint32_t V4L2Device::V4L2PixFmtToDrmFormat(uint32_t format
) {
105 case V4L2_PIX_FMT_NV12
:
106 case V4L2_PIX_FMT_NV12M
:
107 return DRM_FORMAT_NV12
;
109 case V4L2_PIX_FMT_YUV420
:
110 case V4L2_PIX_FMT_YUV420M
:
111 return DRM_FORMAT_YUV420
;
113 case V4L2_PIX_FMT_RGB32
:
114 return DRM_FORMAT_ARGB8888
;
117 DVLOG(1) << "Add more cases as needed";
123 gfx::Size
V4L2Device::CodedSizeFromV4L2Format(struct v4l2_format format
) {
124 gfx::Size coded_size
;
125 gfx::Size visible_size
;
126 media::VideoPixelFormat frame_format
= media::PIXEL_FORMAT_UNKNOWN
;
127 size_t bytesperline
= 0;
128 // Total bytes in the frame.
129 size_t sizeimage
= 0;
131 if (V4L2_TYPE_IS_MULTIPLANAR(format
.type
)) {
132 DCHECK_GT(format
.fmt
.pix_mp
.num_planes
, 0);
134 base::checked_cast
<int>(format
.fmt
.pix_mp
.plane_fmt
[0].bytesperline
);
135 for (size_t i
= 0; i
< format
.fmt
.pix_mp
.num_planes
; ++i
) {
137 base::checked_cast
<int>(format
.fmt
.pix_mp
.plane_fmt
[i
].sizeimage
);
139 visible_size
.SetSize(base::checked_cast
<int>(format
.fmt
.pix_mp
.width
),
140 base::checked_cast
<int>(format
.fmt
.pix_mp
.height
));
142 V4L2Device::V4L2PixFmtToVideoPixelFormat(format
.fmt
.pix_mp
.pixelformat
);
144 bytesperline
= base::checked_cast
<int>(format
.fmt
.pix
.bytesperline
);
145 sizeimage
= base::checked_cast
<int>(format
.fmt
.pix
.sizeimage
);
146 visible_size
.SetSize(base::checked_cast
<int>(format
.fmt
.pix
.width
),
147 base::checked_cast
<int>(format
.fmt
.pix
.height
));
149 V4L2Device::V4L2PixFmtToVideoPixelFormat(format
.fmt
.pix
.pixelformat
);
152 // V4L2 does not provide per-plane bytesperline (bpl) when different
153 // components are sharing one physical plane buffer. In this case, it only
154 // provides bpl for the first component in the plane. So we can't depend on it
155 // for calculating height, because bpl may vary within one physical plane
156 // buffer. For example, YUV420 contains 3 components in one physical plane,
157 // with Y at 8 bits per pixel, and Cb/Cr at 4 bits per pixel per component,
158 // but we only get 8 pits per pixel from bytesperline in physical plane 0.
159 // So we need to get total frame bpp from elsewhere to calculate coded height.
161 // We need bits per pixel for one component only to calculate
162 // coded_width from bytesperline.
163 int plane_horiz_bits_per_pixel
=
164 media::VideoFrame::PlaneHorizontalBitsPerPixel(frame_format
, 0);
166 // Adding up bpp for each component will give us total bpp for all components.
168 for (size_t i
= 0; i
< media::VideoFrame::NumPlanes(frame_format
); ++i
)
169 total_bpp
+= media::VideoFrame::PlaneBitsPerPixel(frame_format
, i
);
171 if (sizeimage
== 0 || bytesperline
== 0 || plane_horiz_bits_per_pixel
== 0 ||
172 total_bpp
== 0 || (bytesperline
* 8) % plane_horiz_bits_per_pixel
!= 0) {
173 LOG(ERROR
) << "Invalid format provided";
177 // Coded width can be calculated by taking the first component's bytesperline,
178 // which in V4L2 always applies to the first component in physical plane
180 int coded_width
= bytesperline
* 8 / plane_horiz_bits_per_pixel
;
181 // Sizeimage is coded_width * coded_height * total_bpp.
182 int coded_height
= sizeimage
* 8 / coded_width
/ total_bpp
;
184 coded_size
.SetSize(coded_width
, coded_height
);
185 // It's possible the driver gave us a slightly larger sizeimage than what
186 // would be calculated from coded size. This is technically not allowed, but
187 // some drivers (Exynos) like to have some additional alignment that is not a
188 // multiple of bytesperline. The best thing we can do is to compensate by
189 // aligning to next full row.
190 if (sizeimage
> media::VideoFrame::AllocationSize(frame_format
, coded_size
))
191 coded_size
.SetSize(coded_width
, coded_height
+ 1);
192 DVLOG(3) << "coded_size=" << coded_size
.ToString();
194 // Sanity checks. Calculated coded size has to contain given visible size
195 // and fulfill buffer byte size requirements.
196 DCHECK(gfx::Rect(coded_size
).Contains(gfx::Rect(visible_size
)));
198 media::VideoFrame::AllocationSize(frame_format
, coded_size
));
203 void V4L2Device::GetSupportedResolution(uint32_t pixelformat
,
204 gfx::Size
* min_resolution
,
205 gfx::Size
* max_resolution
) {
206 max_resolution
->SetSize(0, 0);
207 min_resolution
->SetSize(0, 0);
208 v4l2_frmsizeenum frame_size
;
209 memset(&frame_size
, 0, sizeof(frame_size
));
210 frame_size
.pixel_format
= pixelformat
;
211 for (; Ioctl(VIDIOC_ENUM_FRAMESIZES
, &frame_size
) == 0; ++frame_size
.index
) {
212 if (frame_size
.type
== V4L2_FRMSIZE_TYPE_DISCRETE
) {
213 if (frame_size
.discrete
.width
>=
214 base::checked_cast
<uint32_t>(max_resolution
->width()) &&
215 frame_size
.discrete
.height
>=
216 base::checked_cast
<uint32_t>(max_resolution
->height())) {
217 max_resolution
->SetSize(frame_size
.discrete
.width
,
218 frame_size
.discrete
.height
);
220 if (min_resolution
->IsEmpty() ||
221 (frame_size
.discrete
.width
<=
222 base::checked_cast
<uint32_t>(min_resolution
->width()) &&
223 frame_size
.discrete
.height
<=
224 base::checked_cast
<uint32_t>(min_resolution
->height()))) {
225 min_resolution
->SetSize(frame_size
.discrete
.width
,
226 frame_size
.discrete
.height
);
228 } else if (frame_size
.type
== V4L2_FRMSIZE_TYPE_STEPWISE
||
229 frame_size
.type
== V4L2_FRMSIZE_TYPE_CONTINUOUS
) {
230 max_resolution
->SetSize(frame_size
.stepwise
.max_width
,
231 frame_size
.stepwise
.max_height
);
232 min_resolution
->SetSize(frame_size
.stepwise
.min_width
,
233 frame_size
.stepwise
.min_height
);
237 if (max_resolution
->IsEmpty()) {
238 max_resolution
->SetSize(1920, 1088);
239 LOG(ERROR
) << "GetSupportedResolution failed to get maximum resolution for "
240 << "fourcc " << std::hex
<< pixelformat
241 << ", fall back to " << max_resolution
->ToString();
243 if (min_resolution
->IsEmpty()) {
244 min_resolution
->SetSize(16, 16);
245 LOG(ERROR
) << "GetSupportedResolution failed to get minimum resolution for "
246 << "fourcc " << std::hex
<< pixelformat
247 << ", fall back to " << min_resolution
->ToString();
251 media::VideoDecodeAccelerator::SupportedProfiles
252 V4L2Device::GetSupportedDecodeProfiles(const size_t num_formats
,
253 const uint32_t pixelformats
[]) {
254 DCHECK_EQ(type_
, kDecoder
);
255 media::VideoDecodeAccelerator::SupportedProfiles profiles
;
256 media::VideoDecodeAccelerator::SupportedProfile profile
;
257 v4l2_fmtdesc fmtdesc
;
258 memset(&fmtdesc
, 0, sizeof(fmtdesc
));
259 fmtdesc
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
261 for (; Ioctl(VIDIOC_ENUM_FMT
, &fmtdesc
) == 0; ++fmtdesc
.index
) {
262 if (std::find(pixelformats
, pixelformats
+ num_formats
,
263 fmtdesc
.pixelformat
) == pixelformats
+ num_formats
)
265 int min_profile
, max_profile
;
266 switch (fmtdesc
.pixelformat
) {
267 case V4L2_PIX_FMT_H264
:
268 case V4L2_PIX_FMT_H264_SLICE
:
269 min_profile
= media::H264PROFILE_MIN
;
270 max_profile
= media::H264PROFILE_MAX
;
272 case V4L2_PIX_FMT_VP8
:
273 case V4L2_PIX_FMT_VP8_FRAME
:
274 min_profile
= media::VP8PROFILE_MIN
;
275 max_profile
= media::VP8PROFILE_MAX
;
277 case V4L2_PIX_FMT_VP9
:
278 min_profile
= media::VP9PROFILE_MIN
;
279 max_profile
= media::VP9PROFILE_MAX
;
282 NOTREACHED() << "Unhandled pixelformat " << std::hex
283 << fmtdesc
.pixelformat
;
286 GetSupportedResolution(fmtdesc
.pixelformat
, &profile
.min_resolution
,
287 &profile
.max_resolution
);
288 for (int media_profile
= min_profile
; media_profile
<= max_profile
;
290 profile
.profile
= static_cast<media::VideoCodecProfile
>(media_profile
);
291 profiles
.push_back(profile
);
297 } // namespace content