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 uint8_t *buffer, |
36 |
|
|
av_unused uint32_t size) |
37 |
|
|
{ |
38 |
|
✗ |
const VP8Context *s = avctx->priv_data; |
39 |
|
✗ |
VAAPIDecodePicture *pic = s->framep[VP8_FRAME_CURRENT]->hwaccel_picture_private; |
40 |
|
|
VAPictureParameterBufferVP8 pp; |
41 |
|
|
VAProbabilityDataBufferVP8 prob; |
42 |
|
|
VAIQMatrixBufferVP8 quant; |
43 |
|
|
int err, i, j, k; |
44 |
|
|
|
45 |
|
✗ |
pic->output_surface = vaapi_vp8_surface_id(s->framep[VP8_FRAME_CURRENT]); |
46 |
|
|
|
47 |
|
✗ |
pp = (VAPictureParameterBufferVP8) { |
48 |
|
✗ |
.frame_width = avctx->width, |
49 |
|
✗ |
.frame_height = avctx->height, |
50 |
|
|
|
51 |
|
✗ |
.last_ref_frame = vaapi_vp8_surface_id(s->framep[VP8_FRAME_PREVIOUS]), |
52 |
|
✗ |
.golden_ref_frame = vaapi_vp8_surface_id(s->framep[VP8_FRAME_GOLDEN]), |
53 |
|
✗ |
.alt_ref_frame = vaapi_vp8_surface_id(s->framep[VP8_FRAME_ALTREF]), |
54 |
|
|
.out_of_loop_frame = VA_INVALID_SURFACE, |
55 |
|
|
|
56 |
|
|
.pic_fields.bits = { |
57 |
|
✗ |
.key_frame = !s->keyframe, |
58 |
|
✗ |
.version = s->profile, |
59 |
|
|
|
60 |
|
✗ |
.segmentation_enabled = s->segmentation.enabled, |
61 |
|
✗ |
.update_mb_segmentation_map = s->segmentation.update_map, |
62 |
|
✗ |
.update_segment_feature_data = s->segmentation.update_feature_data, |
63 |
|
|
|
64 |
|
✗ |
.filter_type = s->filter.simple, |
65 |
|
✗ |
.sharpness_level = s->filter.sharpness, |
66 |
|
|
|
67 |
|
✗ |
.loop_filter_adj_enable = s->lf_delta.enabled, |
68 |
|
✗ |
.mode_ref_lf_delta_update = s->lf_delta.update, |
69 |
|
|
|
70 |
|
✗ |
.sign_bias_golden = s->sign_bias[VP8_FRAME_GOLDEN], |
71 |
|
✗ |
.sign_bias_alternate = s->sign_bias[VP8_FRAME_ALTREF], |
72 |
|
|
|
73 |
|
✗ |
.mb_no_coeff_skip = s->mbskip_enabled, |
74 |
|
✗ |
.loop_filter_disable = s->filter.level == 0, |
75 |
|
|
}, |
76 |
|
|
|
77 |
|
✗ |
.prob_skip_false = s->prob->mbskip, |
78 |
|
✗ |
.prob_intra = s->prob->intra, |
79 |
|
✗ |
.prob_last = s->prob->last, |
80 |
|
✗ |
.prob_gf = s->prob->golden, |
81 |
|
|
}; |
82 |
|
|
|
83 |
|
✗ |
for (i = 0; i < 3; i++) |
84 |
|
✗ |
pp.mb_segment_tree_probs[i] = s->prob->segmentid[i]; |
85 |
|
|
|
86 |
|
✗ |
for (i = 0; i < 4; i++) { |
87 |
|
✗ |
if (s->segmentation.enabled) { |
88 |
|
✗ |
pp.loop_filter_level[i] = s->segmentation.filter_level[i]; |
89 |
|
✗ |
if (!s->segmentation.absolute_vals) |
90 |
|
✗ |
pp.loop_filter_level[i] += s->filter.level; |
91 |
|
|
} else { |
92 |
|
✗ |
pp.loop_filter_level[i] = s->filter.level; |
93 |
|
|
} |
94 |
|
✗ |
pp.loop_filter_level[i] = av_clip_uintp2(pp.loop_filter_level[i], 6); |
95 |
|
|
} |
96 |
|
|
|
97 |
|
✗ |
for (i = 0; i < 4; i++) { |
98 |
|
✗ |
pp.loop_filter_deltas_ref_frame[i] = s->lf_delta.ref[i]; |
99 |
|
✗ |
pp.loop_filter_deltas_mode[i] = s->lf_delta.mode[i + 4]; |
100 |
|
|
} |
101 |
|
|
|
102 |
|
✗ |
if (s->keyframe) { |
103 |
|
|
static const uint8_t keyframe_y_mode_probs[4] = { |
104 |
|
|
145, 156, 163, 128 |
105 |
|
|
}; |
106 |
|
|
static const uint8_t keyframe_uv_mode_probs[3] = { |
107 |
|
|
142, 114, 183 |
108 |
|
|
}; |
109 |
|
✗ |
memcpy(pp.y_mode_probs, keyframe_y_mode_probs, 4); |
110 |
|
✗ |
memcpy(pp.uv_mode_probs, keyframe_uv_mode_probs, 3); |
111 |
|
|
} else { |
112 |
|
✗ |
for (i = 0; i < 4; i++) |
113 |
|
✗ |
pp.y_mode_probs[i] = s->prob->pred16x16[i]; |
114 |
|
✗ |
for (i = 0; i < 3; i++) |
115 |
|
✗ |
pp.uv_mode_probs[i] = s->prob->pred8x8c[i]; |
116 |
|
|
} |
117 |
|
✗ |
for (i = 0; i < 2; i++) |
118 |
|
✗ |
for (j = 0; j < 19; j++) |
119 |
|
✗ |
pp.mv_probs[i][j] = s->prob->mvc[i][j]; |
120 |
|
|
|
121 |
|
✗ |
pp.bool_coder_ctx.range = s->coder_state_at_header_end.range; |
122 |
|
✗ |
pp.bool_coder_ctx.value = s->coder_state_at_header_end.value; |
123 |
|
✗ |
pp.bool_coder_ctx.count = s->coder_state_at_header_end.bit_count; |
124 |
|
|
|
125 |
|
✗ |
err = ff_vaapi_decode_make_param_buffer(avctx, pic, |
126 |
|
|
VAPictureParameterBufferType, |
127 |
|
|
&pp, sizeof(pp)); |
128 |
|
✗ |
if (err < 0) |
129 |
|
✗ |
goto fail; |
130 |
|
|
|
131 |
|
✗ |
for (i = 0; i < 4; i++) { |
132 |
|
✗ |
for (j = 0; j < 8; j++) { |
133 |
|
|
static const int coeff_bands_inverse[8] = { |
134 |
|
|
0, 1, 2, 3, 5, 6, 4, 15 |
135 |
|
|
}; |
136 |
|
✗ |
int coeff_pos = coeff_bands_inverse[j]; |
137 |
|
|
|
138 |
|
✗ |
for (k = 0; k < 3; k++) { |
139 |
|
✗ |
memcpy(prob.dct_coeff_probs[i][j][k], |
140 |
|
✗ |
s->prob->token[i][coeff_pos][k], 11); |
141 |
|
|
} |
142 |
|
|
} |
143 |
|
|
} |
144 |
|
|
|
145 |
|
✗ |
err = ff_vaapi_decode_make_param_buffer(avctx, pic, |
146 |
|
|
VAProbabilityBufferType, |
147 |
|
|
&prob, sizeof(prob)); |
148 |
|
✗ |
if (err < 0) |
149 |
|
✗ |
goto fail; |
150 |
|
|
|
151 |
|
✗ |
for (i = 0; i < 4; i++) { |
152 |
|
✗ |
int base_qi = s->segmentation.base_quant[i]; |
153 |
|
✗ |
if (!s->segmentation.absolute_vals) |
154 |
|
✗ |
base_qi += s->quant.yac_qi; |
155 |
|
|
|
156 |
|
✗ |
quant.quantization_index[i][0] = av_clip_uintp2(base_qi, 7); |
157 |
|
✗ |
quant.quantization_index[i][1] = av_clip_uintp2(base_qi + s->quant.ydc_delta, 7); |
158 |
|
✗ |
quant.quantization_index[i][2] = av_clip_uintp2(base_qi + s->quant.y2dc_delta, 7); |
159 |
|
✗ |
quant.quantization_index[i][3] = av_clip_uintp2(base_qi + s->quant.y2ac_delta, 7); |
160 |
|
✗ |
quant.quantization_index[i][4] = av_clip_uintp2(base_qi + s->quant.uvdc_delta, 7); |
161 |
|
✗ |
quant.quantization_index[i][5] = av_clip_uintp2(base_qi + s->quant.uvac_delta, 7); |
162 |
|
|
} |
163 |
|
|
|
164 |
|
✗ |
err = ff_vaapi_decode_make_param_buffer(avctx, pic, |
165 |
|
|
VAIQMatrixBufferType, |
166 |
|
|
&quant, sizeof(quant)); |
167 |
|
✗ |
if (err < 0) |
168 |
|
✗ |
goto fail; |
169 |
|
|
|
170 |
|
✗ |
return 0; |
171 |
|
|
|
172 |
|
✗ |
fail: |
173 |
|
✗ |
ff_vaapi_decode_cancel(avctx, pic); |
174 |
|
✗ |
return err; |
175 |
|
|
} |
176 |
|
|
|
177 |
|
✗ |
static int vaapi_vp8_end_frame(AVCodecContext *avctx) |
178 |
|
|
{ |
179 |
|
✗ |
const VP8Context *s = avctx->priv_data; |
180 |
|
✗ |
VAAPIDecodePicture *pic = s->framep[VP8_FRAME_CURRENT]->hwaccel_picture_private; |
181 |
|
|
|
182 |
|
✗ |
return ff_vaapi_decode_issue(avctx, pic); |
183 |
|
|
} |
184 |
|
|
|
185 |
|
✗ |
static int vaapi_vp8_decode_slice(AVCodecContext *avctx, |
186 |
|
|
const uint8_t *buffer, |
187 |
|
|
uint32_t size) |
188 |
|
|
{ |
189 |
|
✗ |
const VP8Context *s = avctx->priv_data; |
190 |
|
✗ |
VAAPIDecodePicture *pic = s->framep[VP8_FRAME_CURRENT]->hwaccel_picture_private; |
191 |
|
|
VASliceParameterBufferVP8 sp; |
192 |
|
|
int err, i; |
193 |
|
|
|
194 |
|
✗ |
unsigned int header_size = 3 + 7 * s->keyframe; |
195 |
|
✗ |
const uint8_t *data = buffer + header_size; |
196 |
|
✗ |
unsigned int data_size = size - header_size; |
197 |
|
|
|
198 |
|
✗ |
sp = (VASliceParameterBufferVP8) { |
199 |
|
|
.slice_data_size = data_size, |
200 |
|
|
.slice_data_offset = 0, |
201 |
|
|
.slice_data_flag = VA_SLICE_DATA_FLAG_ALL, |
202 |
|
|
|
203 |
|
✗ |
.macroblock_offset = (8 * (s->coder_state_at_header_end.input - data) - |
204 |
|
✗ |
s->coder_state_at_header_end.bit_count - 8), |
205 |
|
✗ |
.num_of_partitions = s->num_coeff_partitions + 1, |
206 |
|
|
}; |
207 |
|
|
|
208 |
|
✗ |
sp.partition_size[0] = s->header_partition_size - ((sp.macroblock_offset + 7) / 8); |
209 |
|
✗ |
for (i = 0; i < 8; i++) |
210 |
|
✗ |
sp.partition_size[i+1] = s->coeff_partition_size[i]; |
211 |
|
|
|
212 |
|
✗ |
err = ff_vaapi_decode_make_slice_buffer(avctx, pic, &sp, 1, sizeof(sp), data, data_size); |
213 |
|
✗ |
if (err) |
214 |
|
✗ |
goto fail; |
215 |
|
|
|
216 |
|
✗ |
return 0; |
217 |
|
|
|
218 |
|
✗ |
fail: |
219 |
|
✗ |
ff_vaapi_decode_cancel(avctx, pic); |
220 |
|
✗ |
return err; |
221 |
|
|
} |
222 |
|
|
|
223 |
|
|
const FFHWAccel ff_vp8_vaapi_hwaccel = { |
224 |
|
|
.p.name = "vp8_vaapi", |
225 |
|
|
.p.type = AVMEDIA_TYPE_VIDEO, |
226 |
|
|
.p.id = AV_CODEC_ID_VP8, |
227 |
|
|
.p.pix_fmt = AV_PIX_FMT_VAAPI, |
228 |
|
|
.start_frame = &vaapi_vp8_start_frame, |
229 |
|
|
.end_frame = &vaapi_vp8_end_frame, |
230 |
|
|
.decode_slice = &vaapi_vp8_decode_slice, |
231 |
|
|
.frame_priv_data_size = sizeof(VAAPIDecodePicture), |
232 |
|
|
.init = &ff_vaapi_decode_init, |
233 |
|
|
.uninit = &ff_vaapi_decode_uninit, |
234 |
|
|
.frame_params = &ff_vaapi_common_frame_params, |
235 |
|
|
.priv_data_size = sizeof(VAAPIDecodeContext), |
236 |
|
|
.caps_internal = HWACCEL_CAP_ASYNC_SAFE, |
237 |
|
|
}; |
238 |
|
|
|