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"
14 // TODO(posciak): remove this once V4L2 headers are updated.
15 #define V4L2_PIX_FMT_VP9 v4l2_fourcc('V', 'P', '9', '0')
16 #define V4L2_PIX_FMT_H264_SLICE v4l2_fourcc('S', '2', '6', '4')
17 #define V4L2_PIX_FMT_VP8_FRAME v4l2_fourcc('V', 'P', '8', 'F')
21 V4L2Device::~V4L2Device() {
25 scoped_refptr
<V4L2Device
> V4L2Device::Create(Type type
) {
26 DVLOG(3) << __PRETTY_FUNCTION__
;
28 scoped_refptr
<GenericV4L2Device
> generic_device(new GenericV4L2Device(type
));
29 if (generic_device
->Initialize())
30 return generic_device
;
32 #if defined(ARCH_CPU_ARMEL)
33 scoped_refptr
<TegraV4L2Device
> tegra_device(new TegraV4L2Device(type
));
34 if (tegra_device
->Initialize())
38 LOG(ERROR
) << "Failed to create V4L2Device";
39 return scoped_refptr
<V4L2Device
>();
43 media::VideoFrame::Format
V4L2Device::V4L2PixFmtToVideoFrameFormat(
46 case V4L2_PIX_FMT_NV12
:
47 case V4L2_PIX_FMT_NV12M
:
48 return media::VideoFrame::NV12
;
50 case V4L2_PIX_FMT_YUV420
:
51 case V4L2_PIX_FMT_YUV420M
:
52 return media::VideoFrame::I420
;
54 case V4L2_PIX_FMT_RGB32
:
55 return media::VideoFrame::ARGB
;
58 LOG(FATAL
) << "Add more cases as needed";
59 return media::VideoFrame::UNKNOWN
;
64 uint32
V4L2Device::VideoFrameFormatToV4L2PixFmt(
65 media::VideoFrame::Format format
) {
67 case media::VideoFrame::NV12
:
68 return V4L2_PIX_FMT_NV12M
;
70 case media::VideoFrame::I420
:
71 return V4L2_PIX_FMT_YUV420M
;
74 LOG(FATAL
) << "Add more cases as needed";
80 uint32
V4L2Device::VideoCodecProfileToV4L2PixFmt(
81 media::VideoCodecProfile profile
,
83 if (profile
>= media::H264PROFILE_MIN
&&
84 profile
<= media::H264PROFILE_MAX
) {
86 return V4L2_PIX_FMT_H264_SLICE
;
88 return V4L2_PIX_FMT_H264
;
89 } else if (profile
>= media::VP8PROFILE_MIN
&&
90 profile
<= media::VP8PROFILE_MAX
) {
92 return V4L2_PIX_FMT_VP8_FRAME
;
94 return V4L2_PIX_FMT_VP8
;
95 } else if (profile
>= media::VP9PROFILE_MIN
&&
96 profile
<= media::VP9PROFILE_MAX
) {
97 return V4L2_PIX_FMT_VP9
;
99 LOG(FATAL
) << "Add more cases as needed";
105 uint32_t V4L2Device::V4L2PixFmtToDrmFormat(uint32_t format
) {
107 case V4L2_PIX_FMT_NV12
:
108 case V4L2_PIX_FMT_NV12M
:
109 return DRM_FORMAT_NV12
;
111 case V4L2_PIX_FMT_YUV420
:
112 case V4L2_PIX_FMT_YUV420M
:
113 return DRM_FORMAT_YUV420
;
115 case V4L2_PIX_FMT_RGB32
:
116 return DRM_FORMAT_ARGB8888
;
119 DVLOG(1) << "Add more cases as needed";
125 gfx::Size
V4L2Device::CodedSizeFromV4L2Format(struct v4l2_format format
) {
126 gfx::Size coded_size
;
127 gfx::Size visible_size
;
128 media::VideoFrame::Format frame_format
= media::VideoFrame::UNKNOWN
;
129 size_t bytesperline
= 0;
130 // Total bytes in the frame.
131 size_t sizeimage
= 0;
133 if (V4L2_TYPE_IS_MULTIPLANAR(format
.type
)) {
134 DCHECK_GT(format
.fmt
.pix_mp
.num_planes
, 0);
136 base::checked_cast
<int>(format
.fmt
.pix_mp
.plane_fmt
[0].bytesperline
);
137 for (size_t i
= 0; i
< format
.fmt
.pix_mp
.num_planes
; ++i
) {
139 base::checked_cast
<int>(format
.fmt
.pix_mp
.plane_fmt
[i
].sizeimage
);
141 visible_size
.SetSize(base::checked_cast
<int>(format
.fmt
.pix_mp
.width
),
142 base::checked_cast
<int>(format
.fmt
.pix_mp
.height
));
144 V4L2Device::V4L2PixFmtToVideoFrameFormat(format
.fmt
.pix_mp
.pixelformat
);
146 bytesperline
= base::checked_cast
<int>(format
.fmt
.pix
.bytesperline
);
147 sizeimage
= base::checked_cast
<int>(format
.fmt
.pix
.sizeimage
);
148 visible_size
.SetSize(base::checked_cast
<int>(format
.fmt
.pix
.width
),
149 base::checked_cast
<int>(format
.fmt
.pix
.height
));
151 V4L2Device::V4L2PixFmtToVideoFrameFormat(format
.fmt
.pix
.pixelformat
);
154 // V4L2 does not provide per-plane bytesperline (bpl) when different
155 // components are sharing one physical plane buffer. In this case, it only
156 // provides bpl for the first component in the plane. So we can't depend on it
157 // for calculating height, because bpl may vary within one physical plane
158 // buffer. For example, YUV420 contains 3 components in one physical plane,
159 // with Y at 8 bits per pixel, and Cb/Cr at 4 bits per pixel per component,
160 // but we only get 8 pits per pixel from bytesperline in physical plane 0.
161 // So we need to get total frame bpp from elsewhere to calculate coded height.
163 // We need bits per pixel for one component only to calculate
164 // coded_width from bytesperline.
165 int plane_horiz_bits_per_pixel
=
166 media::VideoFrame::PlaneHorizontalBitsPerPixel(frame_format
, 0);
168 // Adding up bpp for each component will give us total bpp for all components.
170 for (size_t i
= 0; i
< media::VideoFrame::NumPlanes(frame_format
); ++i
)
171 total_bpp
+= media::VideoFrame::PlaneBitsPerPixel(frame_format
, i
);
173 if (sizeimage
== 0 || bytesperline
== 0 || plane_horiz_bits_per_pixel
== 0 ||
174 total_bpp
== 0 || (bytesperline
* 8) % plane_horiz_bits_per_pixel
!= 0) {
175 LOG(ERROR
) << "Invalid format provided";
179 // Coded width can be calculated by taking the first component's bytesperline,
180 // which in V4L2 always applies to the first component in physical plane
182 int coded_width
= bytesperline
* 8 / plane_horiz_bits_per_pixel
;
183 // Sizeimage is coded_width * coded_height * total_bpp.
184 int coded_height
= sizeimage
* 8 / coded_width
/ total_bpp
;
186 coded_size
.SetSize(coded_width
, coded_height
);
187 // It's possible the driver gave us a slightly larger sizeimage than what
188 // would be calculated from coded size. This is technically not allowed, but
189 // some drivers (Exynos) like to have some additional alignment that is not a
190 // multiple of bytesperline. The best thing we can do is to compensate by
191 // aligning to next full row.
192 if (sizeimage
> media::VideoFrame::AllocationSize(frame_format
, coded_size
))
193 coded_size
.SetSize(coded_width
, coded_height
+ 1);
194 DVLOG(3) << "coded_size=" << coded_size
.ToString();
196 // Sanity checks. Calculated coded size has to contain given visible size
197 // and fulfill buffer byte size requirements.
198 DCHECK(gfx::Rect(coded_size
).Contains(gfx::Rect(visible_size
)));
200 media::VideoFrame::AllocationSize(frame_format
, coded_size
));
205 } // namespace content