1/* 2 * MPEG-2 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 "hwconfig.h" 24#include "mpegutils.h" 25#include "mpegvideo.h" 26#include "mpegvideodec.h" 27#include "vaapi_decode.h" 28 29/** Reconstruct bitstream f_code */ 30static inline int mpeg2_get_f_code(const MpegEncContext *s) 31{ 32 return (s->mpeg_f_code[0][0] << 12) | (s->mpeg_f_code[0][1] << 8) | 33 (s->mpeg_f_code[1][0] << 4) | s->mpeg_f_code[1][1]; 34} 35 36/** Determine frame start: first field for field picture or frame picture */ 37static inline int mpeg2_get_is_frame_start(const MpegEncContext *s) 38{ 39 return s->first_field || s->picture_structure == PICT_FRAME; 40} 41 42static int vaapi_mpeg2_start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) 43{ 44 const MpegEncContext *s = avctx->priv_data; 45 VAAPIDecodePicture *pic = s->current_picture_ptr->hwaccel_picture_private; 46 VAPictureParameterBufferMPEG2 pic_param; 47 VAIQMatrixBufferMPEG2 iq_matrix; 48 int i, err; 49 50 pic->output_surface = ff_vaapi_get_surface_id(s->current_picture_ptr->f); 51 52 pic_param = (VAPictureParameterBufferMPEG2) { 53 .horizontal_size = s->width, 54 .vertical_size = s->height, 55 .forward_reference_picture = VA_INVALID_ID, 56 .backward_reference_picture = VA_INVALID_ID, 57 .picture_coding_type = s->pict_type, 58 .f_code = mpeg2_get_f_code(s), 59 .picture_coding_extension.bits = { 60 .intra_dc_precision = s->intra_dc_precision, 61 .picture_structure = s->picture_structure, 62 .top_field_first = s->top_field_first, 63 .frame_pred_frame_dct = s->frame_pred_frame_dct, 64 .concealment_motion_vectors = s->concealment_motion_vectors, 65 .q_scale_type = s->q_scale_type, 66 .intra_vlc_format = s->intra_vlc_format, 67 .alternate_scan = s->alternate_scan, 68 .repeat_first_field = s->repeat_first_field, 69 .progressive_frame = s->progressive_frame, 70 .is_first_field = mpeg2_get_is_frame_start(s), 71 }, 72 }; 73 74 switch (s->pict_type) { 75 case AV_PICTURE_TYPE_B: 76 pic_param.backward_reference_picture = ff_vaapi_get_surface_id(s->next_picture.f); 77 // fall-through 78 case AV_PICTURE_TYPE_P: 79 pic_param.forward_reference_picture = ff_vaapi_get_surface_id(s->last_picture.f); 80 break; 81 } 82 83 err = ff_vaapi_decode_make_param_buffer(avctx, pic, 84 VAPictureParameterBufferType, 85 &pic_param, sizeof(pic_param)); 86 if (err < 0) 87 goto fail; 88 89 iq_matrix.load_intra_quantiser_matrix = 1; 90 iq_matrix.load_non_intra_quantiser_matrix = 1; 91 iq_matrix.load_chroma_intra_quantiser_matrix = 1; 92 iq_matrix.load_chroma_non_intra_quantiser_matrix = 1; 93 94 for (i = 0; i < 64; i++) { 95 int n = s->idsp.idct_permutation[ff_zigzag_direct[i]]; 96 iq_matrix.intra_quantiser_matrix[i] = s->intra_matrix[n]; 97 iq_matrix.non_intra_quantiser_matrix[i] = s->inter_matrix[n]; 98 iq_matrix.chroma_intra_quantiser_matrix[i] = s->chroma_intra_matrix[n]; 99 iq_matrix.chroma_non_intra_quantiser_matrix[i] = s->chroma_inter_matrix[n]; 100 } 101 102 err = ff_vaapi_decode_make_param_buffer(avctx, pic, 103 VAIQMatrixBufferType, 104 &iq_matrix, sizeof(iq_matrix)); 105 if (err < 0) 106 goto fail; 107 108 return 0; 109 110fail: 111 ff_vaapi_decode_cancel(avctx, pic); 112 return err; 113} 114 115static int vaapi_mpeg2_end_frame(AVCodecContext *avctx) 116{ 117 MpegEncContext *s = avctx->priv_data; 118 VAAPIDecodePicture *pic = s->current_picture_ptr->hwaccel_picture_private; 119 int ret; 120 121 ret = ff_vaapi_decode_issue(avctx, pic); 122 if (ret < 0) 123 goto fail; 124 125 ff_mpeg_draw_horiz_band(s, 0, s->avctx->height); 126 127fail: 128 return ret; 129} 130 131static int vaapi_mpeg2_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) 132{ 133 const MpegEncContext *s = avctx->priv_data; 134 VAAPIDecodePicture *pic = s->current_picture_ptr->hwaccel_picture_private; 135 VASliceParameterBufferMPEG2 slice_param; 136 GetBitContext gb; 137 uint32_t quantiser_scale_code, intra_slice_flag, macroblock_offset; 138 int err; 139 140 /* Determine macroblock_offset */ 141 init_get_bits(&gb, buffer, 8 * size); 142 if (get_bits_long(&gb, 32) >> 8 != 1) /* start code */ 143 return AVERROR_INVALIDDATA; 144 quantiser_scale_code = get_bits(&gb, 5); 145 intra_slice_flag = get_bits1(&gb); 146 if (intra_slice_flag) { 147 skip_bits(&gb, 8); 148 if (skip_1stop_8data_bits(&gb) < 0) 149 return AVERROR_INVALIDDATA; 150 } 151 macroblock_offset = get_bits_count(&gb); 152 153 slice_param = (VASliceParameterBufferMPEG2) { 154 .slice_data_size = size, 155 .slice_data_offset = 0, 156 .slice_data_flag = VA_SLICE_DATA_FLAG_ALL, 157 .macroblock_offset = macroblock_offset, 158 .slice_horizontal_position = s->mb_x, 159 .slice_vertical_position = s->mb_y >> (s->picture_structure != PICT_FRAME), 160 .quantiser_scale_code = quantiser_scale_code, 161 .intra_slice_flag = intra_slice_flag, 162 }; 163 164 err = ff_vaapi_decode_make_slice_buffer(avctx, pic, 165 &slice_param, sizeof(slice_param), 166 buffer, size); 167 if (err < 0) { 168 ff_vaapi_decode_cancel(avctx, pic); 169 return err; 170 } 171 172 return 0; 173} 174 175const AVHWAccel ff_mpeg2_vaapi_hwaccel = { 176 .name = "mpeg2_vaapi", 177 .type = AVMEDIA_TYPE_VIDEO, 178 .id = AV_CODEC_ID_MPEG2VIDEO, 179 .pix_fmt = AV_PIX_FMT_VAAPI, 180 .start_frame = &vaapi_mpeg2_start_frame, 181 .end_frame = &vaapi_mpeg2_end_frame, 182 .decode_slice = &vaapi_mpeg2_decode_slice, 183 .frame_priv_data_size = sizeof(VAAPIDecodePicture), 184 .init = &ff_vaapi_decode_init, 185 .uninit = &ff_vaapi_decode_uninit, 186 .frame_params = &ff_vaapi_common_frame_params, 187 .priv_data_size = sizeof(VAAPIDecodeContext), 188 .caps_internal = HWACCEL_CAP_ASYNC_SAFE, 189}; 190