blob: 30c9ed3c8b530d9ee3eef5c1f001157c09bf5d27
1 | /* |
2 | * VC-1 HW decode acceleration through VA API |
3 | * |
4 | * Copyright (C) 2008-2009 Splitted-Desktop Systems |
5 | * |
6 | * This file is part of FFmpeg. |
7 | * |
8 | * FFmpeg is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU Lesser General Public |
10 | * License as published by the Free Software Foundation; either |
11 | * version 2.1 of the License, or (at your option) any later version. |
12 | * |
13 | * FFmpeg is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | * Lesser General Public License for more details. |
17 | * |
18 | * You should have received a copy of the GNU Lesser General Public |
19 | * License along with FFmpeg; if not, write to the Free Software |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
21 | */ |
22 | |
23 | #include "hwaccel.h" |
24 | #include "internal.h" |
25 | #include "vaapi_decode.h" |
26 | #include "vc1.h" |
27 | #include "vc1data.h" |
28 | |
29 | /** Translate FFmpeg MV modes to VA API */ |
30 | static int get_VAMvModeVC1(enum MVModes mv_mode) |
31 | { |
32 | switch (mv_mode) { |
33 | case MV_PMODE_1MV_HPEL_BILIN: return VAMvMode1MvHalfPelBilinear; |
34 | case MV_PMODE_1MV: return VAMvMode1Mv; |
35 | case MV_PMODE_1MV_HPEL: return VAMvMode1MvHalfPel; |
36 | case MV_PMODE_MIXED_MV: return VAMvModeMixedMv; |
37 | case MV_PMODE_INTENSITY_COMP: return VAMvModeIntensityCompensation; |
38 | } |
39 | return 0; |
40 | } |
41 | |
42 | /** Check whether the MVTYPEMB bitplane is present */ |
43 | static inline int vc1_has_MVTYPEMB_bitplane(const VC1Context *v) |
44 | { |
45 | if (v->mv_type_is_raw) |
46 | return 0; |
47 | return v->s.pict_type == AV_PICTURE_TYPE_P && |
48 | (v->mv_mode == MV_PMODE_MIXED_MV || |
49 | (v->mv_mode == MV_PMODE_INTENSITY_COMP && |
50 | v->mv_mode2 == MV_PMODE_MIXED_MV)); |
51 | } |
52 | |
53 | /** Check whether the SKIPMB bitplane is present */ |
54 | static inline int vc1_has_SKIPMB_bitplane(const VC1Context *v) |
55 | { |
56 | if (v->skip_is_raw) |
57 | return 0; |
58 | return v->s.pict_type == AV_PICTURE_TYPE_P || |
59 | (v->s.pict_type == AV_PICTURE_TYPE_B && !v->bi_type); |
60 | } |
61 | |
62 | /** Check whether the DIRECTMB bitplane is present */ |
63 | static inline int vc1_has_DIRECTMB_bitplane(const VC1Context *v) |
64 | { |
65 | if (v->dmb_is_raw) |
66 | return 0; |
67 | return v->s.pict_type == AV_PICTURE_TYPE_B && !v->bi_type; |
68 | } |
69 | |
70 | /** Check whether the ACPRED bitplane is present */ |
71 | static inline int vc1_has_ACPRED_bitplane(const VC1Context *v) |
72 | { |
73 | if (v->acpred_is_raw) |
74 | return 0; |
75 | return v->profile == PROFILE_ADVANCED && |
76 | (v->s.pict_type == AV_PICTURE_TYPE_I || |
77 | (v->s.pict_type == AV_PICTURE_TYPE_B && v->bi_type)); |
78 | } |
79 | |
80 | /** Check whether the OVERFLAGS bitplane is present */ |
81 | static inline int vc1_has_OVERFLAGS_bitplane(const VC1Context *v) |
82 | { |
83 | if (v->overflg_is_raw) |
84 | return 0; |
85 | return v->profile == PROFILE_ADVANCED && |
86 | (v->s.pict_type == AV_PICTURE_TYPE_I || |
87 | (v->s.pict_type == AV_PICTURE_TYPE_B && v->bi_type)) && |
88 | (v->overlap && v->pq <= 8) && |
89 | v->condover == CONDOVER_SELECT; |
90 | } |
91 | |
92 | /** Reconstruct bitstream PTYPE (7.1.1.4, index into Table-35) */ |
93 | static int vc1_get_PTYPE(const VC1Context *v) |
94 | { |
95 | const MpegEncContext *s = &v->s; |
96 | switch (s->pict_type) { |
97 | case AV_PICTURE_TYPE_I: return 0; |
98 | case AV_PICTURE_TYPE_P: return v->p_frame_skipped ? 4 : 1; |
99 | case AV_PICTURE_TYPE_B: return v->bi_type ? 3 : 2; |
100 | } |
101 | return 0; |
102 | } |
103 | |
104 | /** Reconstruct bitstream MVMODE (7.1.1.32) */ |
105 | static inline VAMvModeVC1 vc1_get_MVMODE(const VC1Context *v) |
106 | { |
107 | if (v->s.pict_type == AV_PICTURE_TYPE_P || |
108 | (v->s.pict_type == AV_PICTURE_TYPE_B && !v->bi_type)) |
109 | return get_VAMvModeVC1(v->mv_mode); |
110 | return 0; |
111 | } |
112 | |
113 | /** Reconstruct bitstream MVMODE2 (7.1.1.33) */ |
114 | static inline VAMvModeVC1 vc1_get_MVMODE2(const VC1Context *v) |
115 | { |
116 | if (v->s.pict_type == AV_PICTURE_TYPE_P && v->mv_mode == MV_PMODE_INTENSITY_COMP) |
117 | return get_VAMvModeVC1(v->mv_mode2); |
118 | return 0; |
119 | } |
120 | |
121 | /** Reconstruct bitstream TTFRM (7.1.1.41, Table-53) */ |
122 | static inline int vc1_get_TTFRM(const VC1Context *v) |
123 | { |
124 | switch (v->ttfrm) { |
125 | case TT_8X8: return 0; |
126 | case TT_8X4: return 1; |
127 | case TT_4X8: return 2; |
128 | case TT_4X4: return 3; |
129 | } |
130 | return 0; |
131 | } |
132 | |
133 | /** Pack FFmpeg bitplanes into a VABitPlaneBuffer element */ |
134 | static inline void vc1_pack_bitplanes(uint8_t *bitplane, int n, const uint8_t *ff_bp[3], int x, int y, int stride) |
135 | { |
136 | const int bitplane_index = n / 2; |
137 | const int ff_bp_index = y * stride + x; |
138 | uint8_t v = 0; |
139 | if (ff_bp[0]) |
140 | v = ff_bp[0][ff_bp_index]; |
141 | if (ff_bp[1]) |
142 | v |= ff_bp[1][ff_bp_index] << 1; |
143 | if (ff_bp[2]) |
144 | v |= ff_bp[2][ff_bp_index] << 2; |
145 | bitplane[bitplane_index] = (bitplane[bitplane_index] << 4) | v; |
146 | } |
147 | |
148 | static int vaapi_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) |
149 | { |
150 | const VC1Context *v = avctx->priv_data; |
151 | const MpegEncContext *s = &v->s; |
152 | VAAPIDecodePicture *pic = s->current_picture_ptr->hwaccel_picture_private; |
153 | VAPictureParameterBufferVC1 pic_param; |
154 | int err; |
155 | |
156 | pic->output_surface = ff_vaapi_get_surface_id(s->current_picture_ptr->f); |
157 | |
158 | pic_param = (VAPictureParameterBufferVC1) { |
159 | .forward_reference_picture = VA_INVALID_ID, |
160 | .backward_reference_picture = VA_INVALID_ID, |
161 | .inloop_decoded_picture = VA_INVALID_ID, |
162 | .sequence_fields.bits = { |
163 | .pulldown = v->broadcast, |
164 | .interlace = v->interlace, |
165 | .tfcntrflag = v->tfcntrflag, |
166 | .finterpflag = v->finterpflag, |
167 | .psf = v->psf, |
168 | .multires = v->multires, |
169 | .overlap = v->overlap, |
170 | .syncmarker = v->resync_marker, |
171 | .rangered = v->rangered, |
172 | .max_b_frames = s->avctx->max_b_frames, |
173 | .profile = v->profile, |
174 | }, |
175 | .coded_width = s->avctx->coded_width, |
176 | .coded_height = s->avctx->coded_height, |
177 | .entrypoint_fields.bits = { |
178 | .broken_link = v->broken_link, |
179 | .closed_entry = v->closed_entry, |
180 | .panscan_flag = v->panscanflag, |
181 | .loopfilter = s->loop_filter, |
182 | }, |
183 | .conditional_overlap_flag = v->condover, |
184 | .fast_uvmc_flag = v->fastuvmc, |
185 | .range_mapping_fields.bits = { |
186 | .luma_flag = v->range_mapy_flag, |
187 | .luma = v->range_mapy, |
188 | .chroma_flag = v->range_mapuv_flag, |
189 | .chroma = v->range_mapuv, |
190 | }, |
191 | .b_picture_fraction = v->bfraction_lut_index, |
192 | .cbp_table = v->cbpcy_vlc ? v->cbpcy_vlc - ff_vc1_cbpcy_p_vlc : 0, |
193 | .mb_mode_table = 0, /* XXX: interlaced frame */ |
194 | .range_reduction_frame = v->rangeredfrm, |
195 | .rounding_control = v->rnd, |
196 | .post_processing = v->postproc, |
197 | .picture_resolution_index = v->respic, |
198 | .luma_scale = v->lumscale, |
199 | .luma_shift = v->lumshift, |
200 | .picture_fields.bits = { |
201 | .picture_type = vc1_get_PTYPE(v), |
202 | .frame_coding_mode = v->fcm, |
203 | .top_field_first = v->tff, |
204 | .is_first_field = v->fcm == 0, /* XXX: interlaced frame */ |
205 | .intensity_compensation = v->mv_mode == MV_PMODE_INTENSITY_COMP, |
206 | }, |
207 | .raw_coding.flags = { |
208 | .mv_type_mb = v->mv_type_is_raw, |
209 | .direct_mb = v->dmb_is_raw, |
210 | .skip_mb = v->skip_is_raw, |
211 | .field_tx = 0, /* XXX: interlaced frame */ |
212 | .forward_mb = 0, /* XXX: interlaced frame */ |
213 | .ac_pred = v->acpred_is_raw, |
214 | .overflags = v->overflg_is_raw, |
215 | }, |
216 | .bitplane_present.flags = { |
217 | .bp_mv_type_mb = vc1_has_MVTYPEMB_bitplane(v), |
218 | .bp_direct_mb = vc1_has_DIRECTMB_bitplane(v), |
219 | .bp_skip_mb = vc1_has_SKIPMB_bitplane(v), |
220 | .bp_field_tx = 0, /* XXX: interlaced frame */ |
221 | .bp_forward_mb = 0, /* XXX: interlaced frame */ |
222 | .bp_ac_pred = vc1_has_ACPRED_bitplane(v), |
223 | .bp_overflags = vc1_has_OVERFLAGS_bitplane(v), |
224 | }, |
225 | .reference_fields.bits = { |
226 | .reference_distance_flag = v->refdist_flag, |
227 | .reference_distance = 0, /* XXX: interlaced frame */ |
228 | .num_reference_pictures = 0, /* XXX: interlaced frame */ |
229 | .reference_field_pic_indicator = 0, /* XXX: interlaced frame */ |
230 | }, |
231 | .mv_fields.bits = { |
232 | .mv_mode = vc1_get_MVMODE(v), |
233 | .mv_mode2 = vc1_get_MVMODE2(v), |
234 | .mv_table = s->mv_table_index, |
235 | .two_mv_block_pattern_table = 0, /* XXX: interlaced frame */ |
236 | .four_mv_switch = 0, /* XXX: interlaced frame */ |
237 | .four_mv_block_pattern_table = 0, /* XXX: interlaced frame */ |
238 | .extended_mv_flag = v->extended_mv, |
239 | .extended_mv_range = v->mvrange, |
240 | .extended_dmv_flag = v->extended_dmv, |
241 | .extended_dmv_range = 0, /* XXX: interlaced frame */ |
242 | }, |
243 | .pic_quantizer_fields.bits = { |
244 | .dquant = v->dquant, |
245 | .quantizer = v->quantizer_mode, |
246 | .half_qp = v->halfpq, |
247 | .pic_quantizer_scale = v->pq, |
248 | .pic_quantizer_type = v->pquantizer, |
249 | .dq_frame = v->dquantfrm, |
250 | .dq_profile = v->dqprofile, |
251 | .dq_sb_edge = v->dqprofile == DQPROFILE_SINGLE_EDGE ? v->dqsbedge : 0, |
252 | .dq_db_edge = v->dqprofile == DQPROFILE_DOUBLE_EDGES ? v->dqsbedge : 0, |
253 | .dq_binary_level = v->dqbilevel, |
254 | .alt_pic_quantizer = v->altpq, |
255 | }, |
256 | .transform_fields.bits = { |
257 | .variable_sized_transform_flag = v->vstransform, |
258 | .mb_level_transform_type_flag = v->ttmbf, |
259 | .frame_level_transform_type = vc1_get_TTFRM(v), |
260 | .transform_ac_codingset_idx1 = v->c_ac_table_index, |
261 | .transform_ac_codingset_idx2 = v->y_ac_table_index, |
262 | .intra_transform_dc_table = v->s.dc_table_index, |
263 | }, |
264 | }; |
265 | |
266 | switch (s->pict_type) { |
267 | case AV_PICTURE_TYPE_B: |
268 | pic_param.backward_reference_picture = ff_vaapi_get_surface_id(s->next_picture.f); |
269 | // fall-through |
270 | case AV_PICTURE_TYPE_P: |
271 | pic_param.forward_reference_picture = ff_vaapi_get_surface_id(s->last_picture.f); |
272 | break; |
273 | } |
274 | |
275 | err = ff_vaapi_decode_make_param_buffer(avctx, pic, |
276 | VAPictureParameterBufferType, |
277 | &pic_param, sizeof(pic_param)); |
278 | if (err) |
279 | goto fail; |
280 | |
281 | if (pic_param.bitplane_present.value) { |
282 | uint8_t *bitplane; |
283 | const uint8_t *ff_bp[3]; |
284 | int x, y, n; |
285 | size_t size = (s->mb_width * s->mb_height + 1) / 2; |
286 | |
287 | bitplane = av_mallocz(size); |
288 | if (!bitplane) { |
289 | err = AVERROR(ENOMEM); |
290 | goto fail; |
291 | } |
292 | |
293 | switch (s->pict_type) { |
294 | case AV_PICTURE_TYPE_P: |
295 | ff_bp[0] = pic_param.bitplane_present.flags.bp_direct_mb ? v->direct_mb_plane : NULL; |
296 | ff_bp[1] = pic_param.bitplane_present.flags.bp_skip_mb ? s->mbskip_table : NULL; |
297 | ff_bp[2] = pic_param.bitplane_present.flags.bp_mv_type_mb ? v->mv_type_mb_plane : NULL; |
298 | break; |
299 | case AV_PICTURE_TYPE_B: |
300 | if (!v->bi_type) { |
301 | ff_bp[0] = pic_param.bitplane_present.flags.bp_direct_mb ? v->direct_mb_plane : NULL; |
302 | ff_bp[1] = pic_param.bitplane_present.flags.bp_skip_mb ? s->mbskip_table : NULL; |
303 | ff_bp[2] = NULL; /* XXX: interlaced frame (FORWARD plane) */ |
304 | break; |
305 | } |
306 | /* fall-through (BI-type) */ |
307 | case AV_PICTURE_TYPE_I: |
308 | ff_bp[0] = NULL; /* XXX: interlaced frame (FIELDTX plane) */ |
309 | ff_bp[1] = pic_param.bitplane_present.flags.bp_ac_pred ? v->acpred_plane : NULL; |
310 | ff_bp[2] = pic_param.bitplane_present.flags.bp_overflags ? v->over_flags_plane : NULL; |
311 | break; |
312 | default: |
313 | ff_bp[0] = NULL; |
314 | ff_bp[1] = NULL; |
315 | ff_bp[2] = NULL; |
316 | break; |
317 | } |
318 | |
319 | n = 0; |
320 | for (y = 0; y < s->mb_height; y++) |
321 | for (x = 0; x < s->mb_width; x++, n++) |
322 | vc1_pack_bitplanes(bitplane, n, ff_bp, x, y, s->mb_stride); |
323 | if (n & 1) /* move last nibble to the high order */ |
324 | bitplane[n/2] <<= 4; |
325 | |
326 | err = ff_vaapi_decode_make_param_buffer(avctx, pic, |
327 | VABitPlaneBufferType, |
328 | bitplane, size); |
329 | av_free(bitplane); |
330 | if (err) |
331 | goto fail; |
332 | } |
333 | return 0; |
334 | |
335 | fail: |
336 | ff_vaapi_decode_cancel(avctx, pic); |
337 | return err; |
338 | } |
339 | |
340 | static int vaapi_vc1_end_frame(AVCodecContext *avctx) |
341 | { |
342 | VC1Context *v = avctx->priv_data; |
343 | MpegEncContext *s = &v->s; |
344 | VAAPIDecodePicture *pic = s->current_picture_ptr->hwaccel_picture_private; |
345 | int ret; |
346 | |
347 | ret = ff_vaapi_decode_issue(avctx, pic); |
348 | if (ret < 0) |
349 | goto fail; |
350 | |
351 | ff_mpeg_draw_horiz_band(s, 0, s->avctx->height); |
352 | |
353 | fail: |
354 | return ret; |
355 | } |
356 | |
357 | static int vaapi_vc1_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) |
358 | { |
359 | const VC1Context *v = avctx->priv_data; |
360 | const MpegEncContext *s = &v->s; |
361 | VAAPIDecodePicture *pic = s->current_picture_ptr->hwaccel_picture_private; |
362 | VASliceParameterBufferVC1 slice_param; |
363 | int err; |
364 | |
365 | /* Current bit buffer is beyond any marker for VC-1, so skip it */ |
366 | if (avctx->codec_id == AV_CODEC_ID_VC1 && IS_MARKER(AV_RB32(buffer))) { |
367 | buffer += 4; |
368 | size -= 4; |
369 | } |
370 | |
371 | slice_param = (VASliceParameterBufferVC1) { |
372 | .slice_data_size = size, |
373 | .slice_data_offset = 0, |
374 | .slice_data_flag = VA_SLICE_DATA_FLAG_ALL, |
375 | .macroblock_offset = get_bits_count(&s->gb), |
376 | .slice_vertical_position = s->mb_y, |
377 | }; |
378 | |
379 | err = ff_vaapi_decode_make_slice_buffer(avctx, pic, |
380 | &slice_param, sizeof(slice_param), |
381 | buffer, size); |
382 | if (err < 0) { |
383 | ff_vaapi_decode_cancel(avctx, pic); |
384 | return err; |
385 | } |
386 | |
387 | return 0; |
388 | } |
389 | |
390 | #if CONFIG_WMV3_VAAPI_HWACCEL |
391 | AVHWAccel ff_wmv3_vaapi_hwaccel = { |
392 | .name = "wmv3_vaapi", |
393 | .type = AVMEDIA_TYPE_VIDEO, |
394 | .id = AV_CODEC_ID_WMV3, |
395 | .pix_fmt = AV_PIX_FMT_VAAPI, |
396 | .start_frame = &vaapi_vc1_start_frame, |
397 | .end_frame = &vaapi_vc1_end_frame, |
398 | .decode_slice = &vaapi_vc1_decode_slice, |
399 | .frame_priv_data_size = sizeof(VAAPIDecodePicture), |
400 | .init = &ff_vaapi_decode_init, |
401 | .uninit = &ff_vaapi_decode_uninit, |
402 | .priv_data_size = sizeof(VAAPIDecodeContext), |
403 | .caps_internal = HWACCEL_CAP_ASYNC_SAFE, |
404 | }; |
405 | #endif |
406 | |
407 | AVHWAccel ff_vc1_vaapi_hwaccel = { |
408 | .name = "vc1_vaapi", |
409 | .type = AVMEDIA_TYPE_VIDEO, |
410 | .id = AV_CODEC_ID_VC1, |
411 | .pix_fmt = AV_PIX_FMT_VAAPI, |
412 | .start_frame = &vaapi_vc1_start_frame, |
413 | .end_frame = &vaapi_vc1_end_frame, |
414 | .decode_slice = &vaapi_vc1_decode_slice, |
415 | .frame_priv_data_size = sizeof(VAAPIDecodePicture), |
416 | .init = &ff_vaapi_decode_init, |
417 | .uninit = &ff_vaapi_decode_uninit, |
418 | .priv_data_size = sizeof(VAAPIDecodeContext), |
419 | .caps_internal = HWACCEL_CAP_ASYNC_SAFE, |
420 | }; |
421 |