Line |
Branch |
Exec |
Source |
1 |
|
|
/* |
2 |
|
|
* This file is part of FFmpeg. |
3 |
|
|
* |
4 |
|
|
* FFmpeg is free software; you can redistribute it and/or |
5 |
|
|
* modify it under the terms of the GNU Lesser General Public |
6 |
|
|
* License as published by the Free Software Foundation; either |
7 |
|
|
* version 2.1 of the License, or (at your option) any later version. |
8 |
|
|
* |
9 |
|
|
* FFmpeg is distributed in the hope that it will be useful, |
10 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 |
|
|
* Lesser General Public License for more details. |
13 |
|
|
* |
14 |
|
|
* You should have received a copy of the GNU Lesser General Public |
15 |
|
|
* License along with FFmpeg; if not, write to the Free Software |
16 |
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
17 |
|
|
*/ |
18 |
|
|
|
19 |
|
|
#include <va/va.h> |
20 |
|
|
#include <va/va_dec_vp8.h> |
21 |
|
|
|
22 |
|
|
#include "hwaccel_internal.h" |
23 |
|
|
#include "vaapi_decode.h" |
24 |
|
|
#include "vp8.h" |
25 |
|
|
|
26 |
|
✗ |
static VASurfaceID vaapi_vp8_surface_id(VP8Frame *vf) |
27 |
|
|
{ |
28 |
|
✗ |
if (vf) |
29 |
|
✗ |
return ff_vaapi_get_surface_id(vf->tf.f); |
30 |
|
|
else |
31 |
|
✗ |
return VA_INVALID_SURFACE; |
32 |
|
|
} |
33 |
|
|
|
34 |
|
✗ |
static int vaapi_vp8_start_frame(AVCodecContext *avctx, |
35 |
|
|
av_unused const AVBufferRef *buffer_ref, |
36 |
|
|
av_unused const uint8_t *buffer, |
37 |
|
|
av_unused uint32_t size) |
38 |
|
|
{ |
39 |
|
✗ |
const VP8Context *s = avctx->priv_data; |
40 |
|
✗ |
VAAPIDecodePicture *pic = s->framep[VP8_FRAME_CURRENT]->hwaccel_picture_private; |
41 |
|
|
VAPictureParameterBufferVP8 pp; |
42 |
|
|
VAProbabilityDataBufferVP8 prob; |
43 |
|
|
VAIQMatrixBufferVP8 quant; |
44 |
|
|
int err, i, j, k; |
45 |
|
|
|
46 |
|
✗ |
pic->output_surface = vaapi_vp8_surface_id(s->framep[VP8_FRAME_CURRENT]); |
47 |
|
|
|
48 |
|
✗ |
pp = (VAPictureParameterBufferVP8) { |
49 |
|
✗ |
.frame_width = avctx->width, |
50 |
|
✗ |
.frame_height = avctx->height, |
51 |
|
|
|
52 |
|
✗ |
.last_ref_frame = vaapi_vp8_surface_id(s->framep[VP8_FRAME_PREVIOUS]), |
53 |
|
✗ |
.golden_ref_frame = vaapi_vp8_surface_id(s->framep[VP8_FRAME_GOLDEN]), |
54 |
|
✗ |
.alt_ref_frame = vaapi_vp8_surface_id(s->framep[VP8_FRAME_ALTREF]), |
55 |
|
|
.out_of_loop_frame = VA_INVALID_SURFACE, |
56 |
|
|
|
57 |
|
|
.pic_fields.bits = { |
58 |
|
✗ |
.key_frame = !s->keyframe, |
59 |
|
✗ |
.version = s->profile, |
60 |
|
|
|
61 |
|
✗ |
.segmentation_enabled = s->segmentation.enabled, |
62 |
|
✗ |
.update_mb_segmentation_map = s->segmentation.update_map, |
63 |
|
✗ |
.update_segment_feature_data = s->segmentation.update_feature_data, |
64 |
|
|
|
65 |
|
✗ |
.filter_type = s->filter.simple, |
66 |
|
✗ |
.sharpness_level = s->filter.sharpness, |
67 |
|
|
|
68 |
|
✗ |
.loop_filter_adj_enable = s->lf_delta.enabled, |
69 |
|
✗ |
.mode_ref_lf_delta_update = s->lf_delta.update, |
70 |
|
|
|
71 |
|
✗ |
.sign_bias_golden = s->sign_bias[VP8_FRAME_GOLDEN], |
72 |
|
✗ |
.sign_bias_alternate = s->sign_bias[VP8_FRAME_ALTREF], |
73 |
|
|
|
74 |
|
✗ |
.mb_no_coeff_skip = s->mbskip_enabled, |
75 |
|
✗ |
.loop_filter_disable = s->filter.level == 0, |
76 |
|
|
}, |
77 |
|
|
|
78 |
|
✗ |
.prob_skip_false = s->prob->mbskip, |
79 |
|
✗ |
.prob_intra = s->prob->intra, |
80 |
|
✗ |
.prob_last = s->prob->last, |
81 |
|
✗ |
.prob_gf = s->prob->golden, |
82 |
|
|
}; |
83 |
|
|
|
84 |
|
✗ |
for (i = 0; i < 3; i++) |
85 |
|
✗ |
pp.mb_segment_tree_probs[i] = s->prob->segmentid[i]; |
86 |
|
|
|
87 |
|
✗ |
for (i = 0; i < 4; i++) { |
88 |
|
✗ |
if (s->segmentation.enabled) { |
89 |
|
✗ |
pp.loop_filter_level[i] = s->segmentation.filter_level[i]; |
90 |
|
✗ |
if (!s->segmentation.absolute_vals) |
91 |
|
✗ |
pp.loop_filter_level[i] += s->filter.level; |
92 |
|
|
} else { |
93 |
|
✗ |
pp.loop_filter_level[i] = s->filter.level; |
94 |
|
|
} |
95 |
|
✗ |
pp.loop_filter_level[i] = av_clip_uintp2(pp.loop_filter_level[i], 6); |
96 |
|
|
} |
97 |
|
|
|
98 |
|
✗ |
for (i = 0; i < 4; i++) { |
99 |
|
✗ |
pp.loop_filter_deltas_ref_frame[i] = s->lf_delta.ref[i]; |
100 |
|
✗ |
pp.loop_filter_deltas_mode[i] = s->lf_delta.mode[i + 4]; |
101 |
|
|
} |
102 |
|
|
|
103 |
|
✗ |
if (s->keyframe) { |
104 |
|
|
static const uint8_t keyframe_y_mode_probs[4] = { |
105 |
|
|
145, 156, 163, 128 |
106 |
|
|
}; |
107 |
|
|
static const uint8_t keyframe_uv_mode_probs[3] = { |
108 |
|
|
142, 114, 183 |
109 |
|
|
}; |
110 |
|
✗ |
memcpy(pp.y_mode_probs, keyframe_y_mode_probs, 4); |
111 |
|
✗ |
memcpy(pp.uv_mode_probs, keyframe_uv_mode_probs, 3); |
112 |
|
|
} else { |
113 |
|
✗ |
for (i = 0; i < 4; i++) |
114 |
|
✗ |
pp.y_mode_probs[i] = s->prob->pred16x16[i]; |
115 |
|
✗ |
for (i = 0; i < 3; i++) |
116 |
|
✗ |
pp.uv_mode_probs[i] = s->prob->pred8x8c[i]; |
117 |
|
|
} |
118 |
|
✗ |
for (i = 0; i < 2; i++) |
119 |
|
✗ |
for (j = 0; j < 19; j++) |
120 |
|
✗ |
pp.mv_probs[i][j] = s->prob->mvc[i][j]; |
121 |
|
|
|
122 |
|
✗ |
pp.bool_coder_ctx.range = s->coder_state_at_header_end.range; |
123 |
|
✗ |
pp.bool_coder_ctx.value = s->coder_state_at_header_end.value; |
124 |
|
✗ |
pp.bool_coder_ctx.count = s->coder_state_at_header_end.bit_count; |
125 |
|
|
|
126 |
|
✗ |
err = ff_vaapi_decode_make_param_buffer(avctx, pic, |
127 |
|
|
VAPictureParameterBufferType, |
128 |
|
|
&pp, sizeof(pp)); |
129 |
|
✗ |
if (err < 0) |
130 |
|
✗ |
goto fail; |
131 |
|
|
|
132 |
|
✗ |
for (i = 0; i < 4; i++) { |
133 |
|
✗ |
for (j = 0; j < 8; j++) { |
134 |
|
|
static const int coeff_bands_inverse[8] = { |
135 |
|
|
0, 1, 2, 3, 5, 6, 4, 15 |
136 |
|
|
}; |
137 |
|
✗ |
int coeff_pos = coeff_bands_inverse[j]; |
138 |
|
|
|
139 |
|
✗ |
for (k = 0; k < 3; k++) { |
140 |
|
✗ |
memcpy(prob.dct_coeff_probs[i][j][k], |
141 |
|
✗ |
s->prob->token[i][coeff_pos][k], 11); |
142 |
|
|
} |
143 |
|
|
} |
144 |
|
|
} |
145 |
|
|
|
146 |
|
✗ |
err = ff_vaapi_decode_make_param_buffer(avctx, pic, |
147 |
|
|
VAProbabilityBufferType, |
148 |
|
|
&prob, sizeof(prob)); |
149 |
|
✗ |
if (err < 0) |
150 |
|
✗ |
goto fail; |
151 |
|
|
|
152 |
|
✗ |
for (i = 0; i < 4; i++) { |
153 |
|
✗ |
int base_qi = s->segmentation.base_quant[i]; |
154 |
|
✗ |
if (!s->segmentation.absolute_vals) |
155 |
|
✗ |
base_qi += s->quant.yac_qi; |
156 |
|
|
|
157 |
|
✗ |
quant.quantization_index[i][0] = av_clip_uintp2(base_qi, 7); |
158 |
|
✗ |
quant.quantization_index[i][1] = av_clip_uintp2(base_qi + s->quant.ydc_delta, 7); |
159 |
|
✗ |
quant.quantization_index[i][2] = av_clip_uintp2(base_qi + s->quant.y2dc_delta, 7); |
160 |
|
✗ |
quant.quantization_index[i][3] = av_clip_uintp2(base_qi + s->quant.y2ac_delta, 7); |
161 |
|
✗ |
quant.quantization_index[i][4] = av_clip_uintp2(base_qi + s->quant.uvdc_delta, 7); |
162 |
|
✗ |
quant.quantization_index[i][5] = av_clip_uintp2(base_qi + s->quant.uvac_delta, 7); |
163 |
|
|
} |
164 |
|
|
|
165 |
|
✗ |
err = ff_vaapi_decode_make_param_buffer(avctx, pic, |
166 |
|
|
VAIQMatrixBufferType, |
167 |
|
|
&quant, sizeof(quant)); |
168 |
|
✗ |
if (err < 0) |
169 |
|
✗ |
goto fail; |
170 |
|
|
|
171 |
|
✗ |
return 0; |
172 |
|
|
|
173 |
|
✗ |
fail: |
174 |
|
✗ |
ff_vaapi_decode_cancel(avctx, pic); |
175 |
|
✗ |
return err; |
176 |
|
|
} |
177 |
|
|
|
178 |
|
✗ |
static int vaapi_vp8_end_frame(AVCodecContext *avctx) |
179 |
|
|
{ |
180 |
|
✗ |
const VP8Context *s = avctx->priv_data; |
181 |
|
✗ |
VAAPIDecodePicture *pic = s->framep[VP8_FRAME_CURRENT]->hwaccel_picture_private; |
182 |
|
|
|
183 |
|
✗ |
return ff_vaapi_decode_issue(avctx, pic); |
184 |
|
|
} |
185 |
|
|
|
186 |
|
✗ |
static int vaapi_vp8_decode_slice(AVCodecContext *avctx, |
187 |
|
|
const uint8_t *buffer, |
188 |
|
|
uint32_t size) |
189 |
|
|
{ |
190 |
|
✗ |
const VP8Context *s = avctx->priv_data; |
191 |
|
✗ |
VAAPIDecodePicture *pic = s->framep[VP8_FRAME_CURRENT]->hwaccel_picture_private; |
192 |
|
|
VASliceParameterBufferVP8 sp; |
193 |
|
|
int err, i; |
194 |
|
|
|
195 |
|
✗ |
unsigned int header_size = 3 + 7 * s->keyframe; |
196 |
|
✗ |
const uint8_t *data = buffer + header_size; |
197 |
|
✗ |
unsigned int data_size = size - header_size; |
198 |
|
|
|
199 |
|
✗ |
sp = (VASliceParameterBufferVP8) { |
200 |
|
|
.slice_data_size = data_size, |
201 |
|
|
.slice_data_offset = 0, |
202 |
|
|
.slice_data_flag = VA_SLICE_DATA_FLAG_ALL, |
203 |
|
|
|
204 |
|
✗ |
.macroblock_offset = (8 * (s->coder_state_at_header_end.input - data) - |
205 |
|
✗ |
s->coder_state_at_header_end.bit_count - 8), |
206 |
|
✗ |
.num_of_partitions = s->num_coeff_partitions + 1, |
207 |
|
|
}; |
208 |
|
|
|
209 |
|
✗ |
sp.partition_size[0] = s->header_partition_size - ((sp.macroblock_offset + 7) / 8); |
210 |
|
✗ |
for (i = 0; i < 8; i++) |
211 |
|
✗ |
sp.partition_size[i+1] = s->coeff_partition_size[i]; |
212 |
|
|
|
213 |
|
✗ |
err = ff_vaapi_decode_make_slice_buffer(avctx, pic, &sp, 1, sizeof(sp), data, data_size); |
214 |
|
✗ |
if (err) |
215 |
|
✗ |
goto fail; |
216 |
|
|
|
217 |
|
✗ |
return 0; |
218 |
|
|
|
219 |
|
✗ |
fail: |
220 |
|
✗ |
ff_vaapi_decode_cancel(avctx, pic); |
221 |
|
✗ |
return err; |
222 |
|
|
} |
223 |
|
|
|
224 |
|
|
const FFHWAccel ff_vp8_vaapi_hwaccel = { |
225 |
|
|
.p.name = "vp8_vaapi", |
226 |
|
|
.p.type = AVMEDIA_TYPE_VIDEO, |
227 |
|
|
.p.id = AV_CODEC_ID_VP8, |
228 |
|
|
.p.pix_fmt = AV_PIX_FMT_VAAPI, |
229 |
|
|
.start_frame = &vaapi_vp8_start_frame, |
230 |
|
|
.end_frame = &vaapi_vp8_end_frame, |
231 |
|
|
.decode_slice = &vaapi_vp8_decode_slice, |
232 |
|
|
.frame_priv_data_size = sizeof(VAAPIDecodePicture), |
233 |
|
|
.init = &ff_vaapi_decode_init, |
234 |
|
|
.uninit = &ff_vaapi_decode_uninit, |
235 |
|
|
.frame_params = &ff_vaapi_common_frame_params, |
236 |
|
|
.priv_data_size = sizeof(VAAPIDecodeContext), |
237 |
|
|
.caps_internal = HWACCEL_CAP_ASYNC_SAFE, |
238 |
|
|
}; |
239 |
|
|
|