1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
|
From 6724bfac7fd7c8b3fa31233983ac6979d0c3954d Mon Sep 17 00:00:00 2001
From: Boris Brezillon <boris.brezillon@collabora.com>
Date: Wed, 22 May 2019 14:46:58 +0200
Subject: [PATCH 09/13] avcodec: Add V4L2 Request API vp8 hwaccel
Add a V4L2 Request API hwaccel for VP8.
Support for VP8 is enabled when Linux kernel headers declare the
control id V4L2_CID_STATELESS_VP8_FRAME, added in v5.13.
Co-developed-by: Ezequiel Garcia <ezequiel@collabora.com>
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Co-developed-by: Jonas Karlman <jonas@kwiboo.se>
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
configure | 3 +
libavcodec/Makefile | 1 +
libavcodec/hwaccels.h | 1 +
libavcodec/v4l2_request_vp8.c | 242 ++++++++++++++++++++++++++++++++++
libavcodec/vp8.c | 6 +
5 files changed, 253 insertions(+)
create mode 100644 libavcodec/v4l2_request_vp8.c
--- a/configure
+++ b/configure
@@ -3540,6 +3540,8 @@ vc1_vdpau_hwaccel_deps="vdpau"
vc1_vdpau_hwaccel_select="vc1_decoder"
vp8_nvdec_hwaccel_deps="nvdec"
vp8_nvdec_hwaccel_select="vp8_decoder"
+vp8_v4l2request_hwaccel_deps="v4l2_request vp8_v4l2_request"
+vp8_v4l2request_hwaccel_select="vp8_decoder"
vp8_vaapi_hwaccel_deps="vaapi"
vp8_vaapi_hwaccel_select="vp8_decoder"
vp9_d3d11va_hwaccel_deps="d3d11va DXVA_PicParams_VP9"
@@ -7673,6 +7675,7 @@ if enabled v4l2_request; then
check_cc hevc_v4l2_request linux/videodev2.h "int i = V4L2_CID_STATELESS_HEVC_SPS"
check_cc mpeg2_v4l2_request linux/videodev2.h "int i = V4L2_CID_STATELESS_MPEG2_SEQUENCE"
check_cc v4l2_m2m_hold_capture_buf linux/videodev2.h "int i = V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF"
+ check_cc vp8_v4l2_request linux/videodev2.h "int i = V4L2_CID_STATELESS_VP8_FRAME"
check_func_headers "linux/media.h linux/videodev2.h" v4l2_timeval_to_ns
check_pkg_config libudev libudev libudev.h udev_new
check_struct linux/videodev2.h "struct v4l2_ctrl_hevc_decode_params" num_delta_pocs_of_ref_rps_idx
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -1102,6 +1102,7 @@ OBJS-$(CONFIG_VC1_QSV_HWACCEL)
OBJS-$(CONFIG_VC1_VAAPI_HWACCEL) += vaapi_vc1.o
OBJS-$(CONFIG_VC1_VDPAU_HWACCEL) += vdpau_vc1.o
OBJS-$(CONFIG_VP8_NVDEC_HWACCEL) += nvdec_vp8.o
+OBJS-$(CONFIG_VP8_V4L2REQUEST_HWACCEL) += v4l2_request_vp8.o
OBJS-$(CONFIG_VP8_VAAPI_HWACCEL) += vaapi_vp8.o
OBJS-$(CONFIG_VP9_D3D11VA_HWACCEL) += dxva2_vp9.o
OBJS-$(CONFIG_VP9_DXVA2_HWACCEL) += dxva2_vp9.o
--- a/libavcodec/hwaccels.h
+++ b/libavcodec/hwaccels.h
@@ -83,6 +83,7 @@ extern const struct FFHWAccel ff_vc1_nvd
extern const struct FFHWAccel ff_vc1_vaapi_hwaccel;
extern const struct FFHWAccel ff_vc1_vdpau_hwaccel;
extern const struct FFHWAccel ff_vp8_nvdec_hwaccel;
+extern const struct FFHWAccel ff_vp8_v4l2request_hwaccel;
extern const struct FFHWAccel ff_vp8_vaapi_hwaccel;
extern const struct FFHWAccel ff_vp9_d3d11va_hwaccel;
extern const struct FFHWAccel ff_vp9_d3d11va2_hwaccel;
--- /dev/null
+++ b/libavcodec/v4l2_request_vp8.c
@@ -0,0 +1,242 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include "hwaccel_internal.h"
+#include "hwconfig.h"
+#include "v4l2_request.h"
+#include "vp8.h"
+
+typedef struct V4L2RequestControlsVP8 {
+ V4L2RequestPictureContext pic;
+ struct v4l2_ctrl_vp8_frame frame;
+} V4L2RequestControlsVP8;
+
+static int v4l2_request_vp8_start_frame(AVCodecContext *avctx,
+ av_unused const AVBufferRef *buf_ref,
+ const uint8_t *buffer,
+ av_unused uint32_t size)
+{
+ const VP8Context *s = avctx->priv_data;
+ V4L2RequestControlsVP8 *controls = s->framep[VP8_FRAME_CURRENT]->hwaccel_picture_private;
+ struct v4l2_ctrl_vp8_frame *ctrl = &controls->frame;
+ unsigned int header_size = 3 + 7 * s->keyframe;
+ const uint8_t *data = buffer + header_size;
+ int ret, i, j, k;
+
+ ret = ff_v4l2_request_start_frame(avctx, &controls->pic,
+ s->framep[VP8_FRAME_CURRENT]->tf.f);
+ if (ret)
+ return ret;
+
+ *ctrl = (struct v4l2_ctrl_vp8_frame) {
+ .lf = {
+ .sharpness_level = s->filter.sharpness,
+ .level = s->filter.level,
+ },
+
+ .quant = {
+ .y_ac_qi = s->quant.yac_qi,
+ .y_dc_delta = s->quant.ydc_delta,
+ .y2_dc_delta = s->quant.y2dc_delta,
+ .y2_ac_delta = s->quant.y2ac_delta,
+ .uv_dc_delta = s->quant.uvdc_delta,
+ .uv_ac_delta = s->quant.uvac_delta,
+ },
+
+ .coder_state = {
+ .range = s->coder_state_at_header_end.range,
+ .value = s->coder_state_at_header_end.value,
+ .bit_count = s->coder_state_at_header_end.bit_count,
+ },
+
+ .width = avctx->width,
+ .height = avctx->height,
+
+ .horizontal_scale = 0, /* scale not supported by FFmpeg */
+ .vertical_scale = 0, /* scale not supported by FFmpeg */
+
+ .version = s->profile & 0x3,
+ .prob_skip_false = s->prob->mbskip,
+ .prob_intra = s->prob->intra,
+ .prob_last = s->prob->last,
+ .prob_gf = s->prob->golden,
+ .num_dct_parts = s->num_coeff_partitions,
+
+ .first_part_size = s->header_partition_size,
+ .first_part_header_bits = (8 * (s->coder_state_at_header_end.input - data) -
+ s->coder_state_at_header_end.bit_count - 8),
+ };
+
+ for (i = 0; i < 4; i++) {
+ ctrl->segment.quant_update[i] = s->segmentation.base_quant[i];
+ ctrl->segment.lf_update[i] = s->segmentation.filter_level[i];
+ }
+
+ for (i = 0; i < 3; i++)
+ ctrl->segment.segment_probs[i] = s->prob->segmentid[i];
+
+ if (s->segmentation.enabled)
+ ctrl->segment.flags |= V4L2_VP8_SEGMENT_FLAG_ENABLED;
+
+ if (s->segmentation.update_map)
+ ctrl->segment.flags |= V4L2_VP8_SEGMENT_FLAG_UPDATE_MAP;
+
+ if (s->segmentation.update_feature_data)
+ ctrl->segment.flags |= V4L2_VP8_SEGMENT_FLAG_UPDATE_FEATURE_DATA;
+
+ if (!s->segmentation.absolute_vals)
+ ctrl->segment.flags |= V4L2_VP8_SEGMENT_FLAG_DELTA_VALUE_MODE;
+
+ for (i = 0; i < 4; i++) {
+ ctrl->lf.ref_frm_delta[i] = s->lf_delta.ref[i];
+ ctrl->lf.mb_mode_delta[i] = s->lf_delta.mode[i + MODE_I4x4];
+ }
+
+ if (s->lf_delta.enabled)
+ ctrl->lf.flags |= V4L2_VP8_LF_ADJ_ENABLE;
+
+ if (s->lf_delta.update)
+ ctrl->lf.flags |= V4L2_VP8_LF_DELTA_UPDATE;
+
+ if (s->filter.simple)
+ ctrl->lf.flags |= V4L2_VP8_LF_FILTER_TYPE_SIMPLE;
+
+ if (s->keyframe) {
+ static const uint8_t keyframe_y_mode_probs[4] = {
+ 145, 156, 163, 128
+ };
+ static const uint8_t keyframe_uv_mode_probs[3] = {
+ 142, 114, 183
+ };
+
+ memcpy(ctrl->entropy.y_mode_probs, keyframe_y_mode_probs, 4);
+ memcpy(ctrl->entropy.uv_mode_probs, keyframe_uv_mode_probs, 3);
+ } else {
+ for (i = 0; i < 4; i++)
+ ctrl->entropy.y_mode_probs[i] = s->prob->pred16x16[i];
+ for (i = 0; i < 3; i++)
+ ctrl->entropy.uv_mode_probs[i] = s->prob->pred8x8c[i];
+ }
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < 19; j++)
+ ctrl->entropy.mv_probs[i][j] = s->prob->mvc[i][j];
+
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 8; j++) {
+ static const int coeff_bands_inverse[8] = {
+ 0, 1, 2, 3, 5, 6, 4, 15
+ };
+ int coeff_pos = coeff_bands_inverse[j];
+
+ for (k = 0; k < 3; k++) {
+ memcpy(ctrl->entropy.coeff_probs[i][j][k],
+ s->prob->token[i][coeff_pos][k], 11);
+ }
+ }
+ }
+
+ for (i = 0; i < 8; i++)
+ ctrl->dct_part_sizes[i] = s->coeff_partition_size[i];
+
+ if (s->framep[VP8_FRAME_PREVIOUS])
+ ctrl->last_frame_ts =
+ ff_v4l2_request_get_capture_timestamp(s->framep[VP8_FRAME_PREVIOUS]->tf.f);
+ if (s->framep[VP8_FRAME_GOLDEN])
+ ctrl->golden_frame_ts =
+ ff_v4l2_request_get_capture_timestamp(s->framep[VP8_FRAME_GOLDEN]->tf.f);
+ if (s->framep[VP8_FRAME_ALTREF])
+ ctrl->alt_frame_ts =
+ ff_v4l2_request_get_capture_timestamp(s->framep[VP8_FRAME_ALTREF]->tf.f);
+
+ if (s->keyframe)
+ ctrl->flags |= V4L2_VP8_FRAME_FLAG_KEY_FRAME;
+
+ if (s->profile & 0x4)
+ ctrl->flags |= V4L2_VP8_FRAME_FLAG_EXPERIMENTAL;
+
+ if (!s->invisible)
+ ctrl->flags |= V4L2_VP8_FRAME_FLAG_SHOW_FRAME;
+
+ if (s->mbskip_enabled)
+ ctrl->flags |= V4L2_VP8_FRAME_FLAG_MB_NO_SKIP_COEFF;
+
+ if (s->sign_bias[VP8_FRAME_GOLDEN])
+ ctrl->flags |= V4L2_VP8_FRAME_FLAG_SIGN_BIAS_GOLDEN;
+
+ if (s->sign_bias[VP8_FRAME_ALTREF])
+ ctrl->flags |= V4L2_VP8_FRAME_FLAG_SIGN_BIAS_ALT;
+
+ return 0;
+}
+
+static int v4l2_request_vp8_decode_slice(AVCodecContext *avctx,
+ const uint8_t *buffer, uint32_t size)
+{
+ const VP8Context *s = avctx->priv_data;
+ V4L2RequestControlsVP8 *controls = s->framep[VP8_FRAME_CURRENT]->hwaccel_picture_private;
+
+ return ff_v4l2_request_append_output(avctx, &controls->pic, buffer, size);
+}
+
+static int v4l2_request_vp8_end_frame(AVCodecContext *avctx)
+{
+ const VP8Context *s = avctx->priv_data;
+ V4L2RequestControlsVP8 *controls = s->framep[VP8_FRAME_CURRENT]->hwaccel_picture_private;
+
+ struct v4l2_ext_control control[] = {
+ {
+ .id = V4L2_CID_STATELESS_VP8_FRAME,
+ .ptr = &controls->frame,
+ .size = sizeof(controls->frame),
+ },
+ };
+
+ return ff_v4l2_request_decode_frame(avctx, &controls->pic,
+ control, FF_ARRAY_ELEMS(control));
+}
+
+static int v4l2_request_vp8_init(AVCodecContext *avctx)
+{
+ return ff_v4l2_request_init(avctx, NULL, 0, NULL);
+}
+
+static int v4l2_request_vp8_frame_params(AVCodecContext *avctx,
+ AVBufferRef *hw_frames_ctx)
+{
+ return ff_v4l2_request_frame_params(avctx, hw_frames_ctx,
+ V4L2_PIX_FMT_VP8_FRAME, 8);
+}
+
+const FFHWAccel ff_vp8_v4l2request_hwaccel = {
+ .p.name = "vp8_v4l2request",
+ .p.type = AVMEDIA_TYPE_VIDEO,
+ .p.id = AV_CODEC_ID_VP8,
+ .p.pix_fmt = AV_PIX_FMT_DRM_PRIME,
+ .start_frame = v4l2_request_vp8_start_frame,
+ .decode_slice = v4l2_request_vp8_decode_slice,
+ .end_frame = v4l2_request_vp8_end_frame,
+ .flush = ff_v4l2_request_flush,
+ .frame_priv_data_size = sizeof(V4L2RequestControlsVP8),
+ .init = v4l2_request_vp8_init,
+ .uninit = ff_v4l2_request_uninit,
+ .priv_data_size = sizeof(V4L2RequestContext),
+ .frame_params = v4l2_request_vp8_frame_params,
+ .caps_internal = HWACCEL_CAP_ASYNC_SAFE,
+};
--- a/libavcodec/vp8.c
+++ b/libavcodec/vp8.c
@@ -186,6 +186,9 @@ static enum AVPixelFormat get_pixel_form
#if CONFIG_VP8_NVDEC_HWACCEL
AV_PIX_FMT_CUDA,
#endif
+#if CONFIG_VP8_V4L2REQUEST_HWACCEL
+ AV_PIX_FMT_DRM_PRIME,
+#endif
AV_PIX_FMT_YUV420P,
AV_PIX_FMT_NONE,
};
@@ -2977,6 +2980,9 @@ const FFCodec ff_vp8_decoder = {
#if CONFIG_VP8_NVDEC_HWACCEL
HWACCEL_NVDEC(vp8),
#endif
+#if CONFIG_VP8_V4L2REQUEST_HWACCEL
+ HWACCEL_V4L2REQUEST(vp8),
+#endif
NULL
},
};
|