| 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 "vaapi_internal.h" |
| 24 | #include "vc1.h" |
| 25 | #include "vc1data.h" |
| 26 | |
| 27 | /** Translate FFmpeg MV modes to VA API */ |
| 28 | static int get_VAMvModeVC1(enum MVModes mv_mode) |
| 29 | { |
| 30 | switch (mv_mode) { |
| 31 | case MV_PMODE_1MV_HPEL_BILIN: return VAMvMode1MvHalfPelBilinear; |
| 32 | case MV_PMODE_1MV: return VAMvMode1Mv; |
| 33 | case MV_PMODE_1MV_HPEL: return VAMvMode1MvHalfPel; |
| 34 | case MV_PMODE_MIXED_MV: return VAMvModeMixedMv; |
| 35 | case MV_PMODE_INTENSITY_COMP: return VAMvModeIntensityCompensation; |
| 36 | } |
| 37 | return 0; |
| 38 | } |
| 39 | |
| 40 | /** Check whether the MVTYPEMB bitplane is present */ |
| 41 | static inline int vc1_has_MVTYPEMB_bitplane(VC1Context *v) |
| 42 | { |
| 43 | if (v->mv_type_is_raw) |
| 44 | return 0; |
| 45 | return v->s.pict_type == AV_PICTURE_TYPE_P && |
| 46 | (v->mv_mode == MV_PMODE_MIXED_MV || |
| 47 | (v->mv_mode == MV_PMODE_INTENSITY_COMP && |
| 48 | v->mv_mode2 == MV_PMODE_MIXED_MV)); |
| 49 | } |
| 50 | |
| 51 | /** Check whether the SKIPMB bitplane is present */ |
| 52 | static inline int vc1_has_SKIPMB_bitplane(VC1Context *v) |
| 53 | { |
| 54 | if (v->skip_is_raw) |
| 55 | return 0; |
| 56 | return v->s.pict_type == AV_PICTURE_TYPE_P || |
| 57 | (v->s.pict_type == AV_PICTURE_TYPE_B && !v->bi_type); |
| 58 | } |
| 59 | |
| 60 | /** Check whether the DIRECTMB bitplane is present */ |
| 61 | static inline int vc1_has_DIRECTMB_bitplane(VC1Context *v) |
| 62 | { |
| 63 | if (v->dmb_is_raw) |
| 64 | return 0; |
| 65 | return v->s.pict_type == AV_PICTURE_TYPE_B && !v->bi_type; |
| 66 | } |
| 67 | |
| 68 | /** Check whether the ACPRED bitplane is present */ |
| 69 | static inline int vc1_has_ACPRED_bitplane(VC1Context *v) |
| 70 | { |
| 71 | if (v->acpred_is_raw) |
| 72 | return 0; |
| 73 | return v->profile == PROFILE_ADVANCED && |
| 74 | (v->s.pict_type == AV_PICTURE_TYPE_I || |
| 75 | (v->s.pict_type == AV_PICTURE_TYPE_B && v->bi_type)); |
| 76 | } |
| 77 | |
| 78 | /** Check whether the OVERFLAGS bitplane is present */ |
| 79 | static inline int vc1_has_OVERFLAGS_bitplane(VC1Context *v) |
| 80 | { |
| 81 | if (v->overflg_is_raw) |
| 82 | return 0; |
| 83 | return v->profile == PROFILE_ADVANCED && |
| 84 | (v->s.pict_type == AV_PICTURE_TYPE_I || |
| 85 | (v->s.pict_type == AV_PICTURE_TYPE_B && v->bi_type)) && |
| 86 | (v->overlap && v->pq <= 8) && |
| 87 | v->condover == CONDOVER_SELECT; |
| 88 | } |
| 89 | |
| 90 | /** Reconstruct bitstream PTYPE (7.1.1.4, index into Table-35) */ |
| 91 | static int vc1_get_PTYPE(VC1Context *v) |
| 92 | { |
| 93 | MpegEncContext * const s = &v->s; |
| 94 | switch (s->pict_type) { |
| 95 | case AV_PICTURE_TYPE_I: return 0; |
| 96 | case AV_PICTURE_TYPE_P: return v->p_frame_skipped ? 4 : 1; |
| 97 | case AV_PICTURE_TYPE_B: return v->bi_type ? 3 : 2; |
| 98 | } |
| 99 | return 0; |
| 100 | } |
| 101 | |
| 102 | /** Reconstruct bitstream MVMODE (7.1.1.32) */ |
| 103 | static inline VAMvModeVC1 vc1_get_MVMODE(VC1Context *v) |
| 104 | { |
| 105 | if (v->s.pict_type == AV_PICTURE_TYPE_P || |
| 106 | (v->s.pict_type == AV_PICTURE_TYPE_B && !v->bi_type)) |
| 107 | return get_VAMvModeVC1(v->mv_mode); |
| 108 | return 0; |
| 109 | } |
| 110 | |
| 111 | /** Reconstruct bitstream MVMODE2 (7.1.1.33) */ |
| 112 | static inline VAMvModeVC1 vc1_get_MVMODE2(VC1Context *v) |
| 113 | { |
| 114 | if (v->s.pict_type == AV_PICTURE_TYPE_P && v->mv_mode == MV_PMODE_INTENSITY_COMP) |
| 115 | return get_VAMvModeVC1(v->mv_mode2); |
| 116 | return 0; |
| 117 | } |
| 118 | |
| 119 | /** Reconstruct bitstream TTFRM (7.1.1.41, Table-53) */ |
| 120 | static inline int vc1_get_TTFRM(VC1Context *v) |
| 121 | { |
| 122 | switch (v->ttfrm) { |
| 123 | case TT_8X8: return 0; |
| 124 | case TT_8X4: return 1; |
| 125 | case TT_4X8: return 2; |
| 126 | case TT_4X4: return 3; |
| 127 | } |
| 128 | return 0; |
| 129 | } |
| 130 | |
| 131 | /** Pack FFmpeg bitplanes into a VABitPlaneBuffer element */ |
| 132 | static inline void vc1_pack_bitplanes(uint8_t *bitplane, int n, const uint8_t *ff_bp[3], int x, int y, int stride) |
| 133 | { |
| 134 | const int bitplane_index = n / 2; |
| 135 | const int ff_bp_index = y * stride + x; |
| 136 | uint8_t v = 0; |
| 137 | if (ff_bp[0]) |
| 138 | v = ff_bp[0][ff_bp_index]; |
| 139 | if (ff_bp[1]) |
| 140 | v |= ff_bp[1][ff_bp_index] << 1; |
| 141 | if (ff_bp[2]) |
| 142 | v |= ff_bp[2][ff_bp_index] << 2; |
| 143 | bitplane[bitplane_index] = (bitplane[bitplane_index] << 4) | v; |
| 144 | } |
| 145 | |
| 146 | static int vaapi_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) |
| 147 | { |
| 148 | VC1Context * const v = avctx->priv_data; |
| 149 | MpegEncContext * const s = &v->s; |
| 150 | struct vaapi_context * const vactx = avctx->hwaccel_context; |
| 151 | VAPictureParameterBufferVC1 *pic_param; |
| 152 | |
| 153 | av_dlog(avctx, "vaapi_vc1_start_frame()\n"); |
| 154 | |
| 155 | vactx->slice_param_size = sizeof(VASliceParameterBufferVC1); |
| 156 | |
| 157 | /* Fill in VAPictureParameterBufferVC1 */ |
| 158 | pic_param = ff_vaapi_alloc_pic_param(vactx, sizeof(VAPictureParameterBufferVC1)); |
| 159 | if (!pic_param) |
| 160 | return -1; |
| 161 | pic_param->forward_reference_picture = VA_INVALID_ID; |
| 162 | pic_param->backward_reference_picture = VA_INVALID_ID; |
| 163 | pic_param->inloop_decoded_picture = VA_INVALID_ID; |
| 164 | pic_param->sequence_fields.value = 0; /* reset all bits */ |
| 165 | pic_param->sequence_fields.bits.pulldown = v->broadcast; |
| 166 | pic_param->sequence_fields.bits.interlace = v->interlace; |
| 167 | pic_param->sequence_fields.bits.tfcntrflag = v->tfcntrflag; |
| 168 | pic_param->sequence_fields.bits.finterpflag = v->finterpflag; |
| 169 | pic_param->sequence_fields.bits.psf = v->psf; |
| 170 | pic_param->sequence_fields.bits.multires = v->multires; |
| 171 | pic_param->sequence_fields.bits.overlap = v->overlap; |
| 172 | pic_param->sequence_fields.bits.syncmarker = v->resync_marker; |
| 173 | pic_param->sequence_fields.bits.rangered = v->rangered; |
| 174 | pic_param->sequence_fields.bits.max_b_frames = s->avctx->max_b_frames; |
| 175 | #if VA_CHECK_VERSION(0,32,0) |
| 176 | pic_param->sequence_fields.bits.profile = v->profile; |
| 177 | #endif |
| 178 | pic_param->coded_width = s->avctx->coded_width; |
| 179 | pic_param->coded_height = s->avctx->coded_height; |
| 180 | pic_param->entrypoint_fields.value = 0; /* reset all bits */ |
| 181 | pic_param->entrypoint_fields.bits.broken_link = v->broken_link; |
| 182 | pic_param->entrypoint_fields.bits.closed_entry = v->closed_entry; |
| 183 | pic_param->entrypoint_fields.bits.panscan_flag = v->panscanflag; |
| 184 | pic_param->entrypoint_fields.bits.loopfilter = s->loop_filter; |
| 185 | pic_param->conditional_overlap_flag = v->condover; |
| 186 | pic_param->fast_uvmc_flag = v->fastuvmc; |
| 187 | pic_param->range_mapping_fields.value = 0; /* reset all bits */ |
| 188 | pic_param->range_mapping_fields.bits.luma_flag = v->range_mapy_flag; |
| 189 | pic_param->range_mapping_fields.bits.luma = v->range_mapy; |
| 190 | pic_param->range_mapping_fields.bits.chroma_flag = v->range_mapuv_flag; |
| 191 | pic_param->range_mapping_fields.bits.chroma = v->range_mapuv; |
| 192 | pic_param->b_picture_fraction = v->bfraction_lut_index; |
| 193 | pic_param->cbp_table = v->cbpcy_vlc ? v->cbpcy_vlc - ff_vc1_cbpcy_p_vlc : 0; |
| 194 | pic_param->mb_mode_table = 0; /* XXX: interlaced frame */ |
| 195 | pic_param->range_reduction_frame = v->rangeredfrm; |
| 196 | pic_param->rounding_control = v->rnd; |
| 197 | pic_param->post_processing = v->postproc; |
| 198 | pic_param->picture_resolution_index = v->respic; |
| 199 | pic_param->luma_scale = v->lumscale; |
| 200 | pic_param->luma_shift = v->lumshift; |
| 201 | pic_param->picture_fields.value = 0; /* reset all bits */ |
| 202 | pic_param->picture_fields.bits.picture_type = vc1_get_PTYPE(v); |
| 203 | pic_param->picture_fields.bits.frame_coding_mode = v->fcm; |
| 204 | pic_param->picture_fields.bits.top_field_first = v->tff; |
| 205 | pic_param->picture_fields.bits.is_first_field = v->fcm == 0; /* XXX: interlaced frame */ |
| 206 | pic_param->picture_fields.bits.intensity_compensation = v->mv_mode == MV_PMODE_INTENSITY_COMP; |
| 207 | pic_param->raw_coding.value = 0; /* reset all bits */ |
| 208 | pic_param->raw_coding.flags.mv_type_mb = v->mv_type_is_raw; |
| 209 | pic_param->raw_coding.flags.direct_mb = v->dmb_is_raw; |
| 210 | pic_param->raw_coding.flags.skip_mb = v->skip_is_raw; |
| 211 | pic_param->raw_coding.flags.field_tx = 0; /* XXX: interlaced frame */ |
| 212 | pic_param->raw_coding.flags.forward_mb = 0; /* XXX: interlaced frame */ |
| 213 | pic_param->raw_coding.flags.ac_pred = v->acpred_is_raw; |
| 214 | pic_param->raw_coding.flags.overflags = v->overflg_is_raw; |
| 215 | pic_param->bitplane_present.value = 0; /* reset all bits */ |
| 216 | pic_param->bitplane_present.flags.bp_mv_type_mb = vc1_has_MVTYPEMB_bitplane(v); |
| 217 | pic_param->bitplane_present.flags.bp_direct_mb = vc1_has_DIRECTMB_bitplane(v); |
| 218 | pic_param->bitplane_present.flags.bp_skip_mb = vc1_has_SKIPMB_bitplane(v); |
| 219 | pic_param->bitplane_present.flags.bp_field_tx = 0; /* XXX: interlaced frame */ |
| 220 | pic_param->bitplane_present.flags.bp_forward_mb = 0; /* XXX: interlaced frame */ |
| 221 | pic_param->bitplane_present.flags.bp_ac_pred = vc1_has_ACPRED_bitplane(v); |
| 222 | pic_param->bitplane_present.flags.bp_overflags = vc1_has_OVERFLAGS_bitplane(v); |
| 223 | pic_param->reference_fields.value = 0; /* reset all bits */ |
| 224 | pic_param->reference_fields.bits.reference_distance_flag = v->refdist_flag; |
| 225 | pic_param->reference_fields.bits.reference_distance = 0; /* XXX: interlaced frame */ |
| 226 | pic_param->reference_fields.bits.num_reference_pictures = 0; /* XXX: interlaced frame */ |
| 227 | pic_param->reference_fields.bits.reference_field_pic_indicator = 0; /* XXX: interlaced frame */ |
| 228 | pic_param->mv_fields.value = 0; /* reset all bits */ |
| 229 | pic_param->mv_fields.bits.mv_mode = vc1_get_MVMODE(v); |
| 230 | pic_param->mv_fields.bits.mv_mode2 = vc1_get_MVMODE2(v); |
| 231 | pic_param->mv_fields.bits.mv_table = s->mv_table_index; |
| 232 | pic_param->mv_fields.bits.two_mv_block_pattern_table = 0; /* XXX: interlaced frame */ |
| 233 | pic_param->mv_fields.bits.four_mv_switch = 0; /* XXX: interlaced frame */ |
| 234 | pic_param->mv_fields.bits.four_mv_block_pattern_table = 0; /* XXX: interlaced frame */ |
| 235 | pic_param->mv_fields.bits.extended_mv_flag = v->extended_mv; |
| 236 | pic_param->mv_fields.bits.extended_mv_range = v->mvrange; |
| 237 | pic_param->mv_fields.bits.extended_dmv_flag = v->extended_dmv; |
| 238 | pic_param->mv_fields.bits.extended_dmv_range = 0; /* XXX: interlaced frame */ |
| 239 | pic_param->pic_quantizer_fields.value = 0; /* reset all bits */ |
| 240 | pic_param->pic_quantizer_fields.bits.dquant = v->dquant; |
| 241 | pic_param->pic_quantizer_fields.bits.quantizer = v->quantizer_mode; |
| 242 | pic_param->pic_quantizer_fields.bits.half_qp = v->halfpq; |
| 243 | pic_param->pic_quantizer_fields.bits.pic_quantizer_scale = v->pq; |
| 244 | pic_param->pic_quantizer_fields.bits.pic_quantizer_type = v->pquantizer; |
| 245 | pic_param->pic_quantizer_fields.bits.dq_frame = v->dquantfrm; |
| 246 | pic_param->pic_quantizer_fields.bits.dq_profile = v->dqprofile; |
| 247 | pic_param->pic_quantizer_fields.bits.dq_sb_edge = v->dqprofile == DQPROFILE_SINGLE_EDGE ? v->dqsbedge : 0; |
| 248 | pic_param->pic_quantizer_fields.bits.dq_db_edge = v->dqprofile == DQPROFILE_DOUBLE_EDGES ? v->dqsbedge : 0; |
| 249 | pic_param->pic_quantizer_fields.bits.dq_binary_level = v->dqbilevel; |
| 250 | pic_param->pic_quantizer_fields.bits.alt_pic_quantizer = v->altpq; |
| 251 | pic_param->transform_fields.value = 0; /* reset all bits */ |
| 252 | pic_param->transform_fields.bits.variable_sized_transform_flag = v->vstransform; |
| 253 | pic_param->transform_fields.bits.mb_level_transform_type_flag = v->ttmbf; |
| 254 | pic_param->transform_fields.bits.frame_level_transform_type = vc1_get_TTFRM(v); |
| 255 | pic_param->transform_fields.bits.transform_ac_codingset_idx1 = v->c_ac_table_index; |
| 256 | pic_param->transform_fields.bits.transform_ac_codingset_idx2 = v->y_ac_table_index; |
| 257 | pic_param->transform_fields.bits.intra_transform_dc_table = v->s.dc_table_index; |
| 258 | |
| 259 | switch (s->pict_type) { |
| 260 | case AV_PICTURE_TYPE_B: |
| 261 | pic_param->backward_reference_picture = ff_vaapi_get_surface_id(s->next_picture.f); |
| 262 | // fall-through |
| 263 | case AV_PICTURE_TYPE_P: |
| 264 | pic_param->forward_reference_picture = ff_vaapi_get_surface_id(s->last_picture.f); |
| 265 | break; |
| 266 | } |
| 267 | |
| 268 | if (pic_param->bitplane_present.value) { |
| 269 | uint8_t *bitplane; |
| 270 | const uint8_t *ff_bp[3]; |
| 271 | int x, y, n; |
| 272 | |
| 273 | switch (s->pict_type) { |
| 274 | case AV_PICTURE_TYPE_P: |
| 275 | ff_bp[0] = pic_param->bitplane_present.flags.bp_direct_mb ? v->direct_mb_plane : NULL; |
| 276 | ff_bp[1] = pic_param->bitplane_present.flags.bp_skip_mb ? s->mbskip_table : NULL; |
| 277 | ff_bp[2] = pic_param->bitplane_present.flags.bp_mv_type_mb ? v->mv_type_mb_plane : NULL; |
| 278 | break; |
| 279 | case AV_PICTURE_TYPE_B: |
| 280 | if (!v->bi_type) { |
| 281 | ff_bp[0] = pic_param->bitplane_present.flags.bp_direct_mb ? v->direct_mb_plane : NULL; |
| 282 | ff_bp[1] = pic_param->bitplane_present.flags.bp_skip_mb ? s->mbskip_table : NULL; |
| 283 | ff_bp[2] = NULL; /* XXX: interlaced frame (FORWARD plane) */ |
| 284 | break; |
| 285 | } |
| 286 | /* fall-through (BI-type) */ |
| 287 | case AV_PICTURE_TYPE_I: |
| 288 | ff_bp[0] = NULL; /* XXX: interlaced frame (FIELDTX plane) */ |
| 289 | ff_bp[1] = pic_param->bitplane_present.flags.bp_ac_pred ? v->acpred_plane : NULL; |
| 290 | ff_bp[2] = pic_param->bitplane_present.flags.bp_overflags ? v->over_flags_plane : NULL; |
| 291 | break; |
| 292 | default: |
| 293 | ff_bp[0] = NULL; |
| 294 | ff_bp[1] = NULL; |
| 295 | ff_bp[2] = NULL; |
| 296 | break; |
| 297 | } |
| 298 | |
| 299 | bitplane = ff_vaapi_alloc_bitplane(vactx, (s->mb_width * s->mb_height + 1) / 2); |
| 300 | if (!bitplane) |
| 301 | return -1; |
| 302 | |
| 303 | n = 0; |
| 304 | for (y = 0; y < s->mb_height; y++) |
| 305 | for (x = 0; x < s->mb_width; x++, n++) |
| 306 | vc1_pack_bitplanes(bitplane, n, ff_bp, x, y, s->mb_stride); |
| 307 | if (n & 1) /* move last nibble to the high order */ |
| 308 | bitplane[n/2] <<= 4; |
| 309 | } |
| 310 | return 0; |
| 311 | } |
| 312 | |
| 313 | static int vaapi_vc1_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) |
| 314 | { |
| 315 | VC1Context * const v = avctx->priv_data; |
| 316 | MpegEncContext * const s = &v->s; |
| 317 | VASliceParameterBufferVC1 *slice_param; |
| 318 | |
| 319 | av_dlog(avctx, "vaapi_vc1_decode_slice(): buffer %p, size %d\n", buffer, size); |
| 320 | |
| 321 | /* Current bit buffer is beyond any marker for VC-1, so skip it */ |
| 322 | if (avctx->codec_id == AV_CODEC_ID_VC1 && IS_MARKER(AV_RB32(buffer))) { |
| 323 | buffer += 4; |
| 324 | size -= 4; |
| 325 | } |
| 326 | |
| 327 | /* Fill in VASliceParameterBufferVC1 */ |
| 328 | slice_param = (VASliceParameterBufferVC1 *)ff_vaapi_alloc_slice(avctx->hwaccel_context, buffer, size); |
| 329 | if (!slice_param) |
| 330 | return -1; |
| 331 | slice_param->macroblock_offset = get_bits_count(&s->gb); |
| 332 | slice_param->slice_vertical_position = s->mb_y; |
| 333 | return 0; |
| 334 | } |
| 335 | |
| 336 | #if CONFIG_WMV3_VAAPI_HWACCEL |
| 337 | AVHWAccel ff_wmv3_vaapi_hwaccel = { |
| 338 | .name = "wmv3_vaapi", |
| 339 | .type = AVMEDIA_TYPE_VIDEO, |
| 340 | .id = AV_CODEC_ID_WMV3, |
| 341 | .pix_fmt = AV_PIX_FMT_VAAPI_VLD, |
| 342 | .start_frame = vaapi_vc1_start_frame, |
| 343 | .end_frame = ff_vaapi_mpeg_end_frame, |
| 344 | .decode_slice = vaapi_vc1_decode_slice, |
| 345 | }; |
| 346 | #endif |
| 347 | |
| 348 | AVHWAccel ff_vc1_vaapi_hwaccel = { |
| 349 | .name = "vc1_vaapi", |
| 350 | .type = AVMEDIA_TYPE_VIDEO, |
| 351 | .id = AV_CODEC_ID_VC1, |
| 352 | .pix_fmt = AV_PIX_FMT_VAAPI_VLD, |
| 353 | .start_frame = vaapi_vc1_start_frame, |
| 354 | .end_frame = ff_vaapi_mpeg_end_frame, |
| 355 | .decode_slice = vaapi_vc1_decode_slice, |
| 356 | }; |