blob: d8ece75df4fe99a4d21f80e89a6a064534a3e6b3
1 | /* |
2 | * VP9 HW decode acceleration through VA API |
3 | * |
4 | * Copyright (C) 2015 Timo Rothenpieler <timo@rothenpieler.org> |
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 "libavutil/pixdesc.h" |
24 | |
25 | #include "hwaccel.h" |
26 | #include "vaapi_decode.h" |
27 | #include "vp9shared.h" |
28 | |
29 | static VASurfaceID vaapi_vp9_surface_id(const VP9Frame *vf) |
30 | { |
31 | if (vf) |
32 | return ff_vaapi_get_surface_id(vf->tf.f); |
33 | else |
34 | return VA_INVALID_SURFACE; |
35 | } |
36 | |
37 | static int vaapi_vp9_start_frame(AVCodecContext *avctx, |
38 | av_unused const uint8_t *buffer, |
39 | av_unused uint32_t size) |
40 | { |
41 | const VP9SharedContext *h = avctx->priv_data; |
42 | VAAPIDecodePicture *pic = h->frames[CUR_FRAME].hwaccel_picture_private; |
43 | VADecPictureParameterBufferVP9 pic_param; |
44 | const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); |
45 | int err, i; |
46 | |
47 | pic->output_surface = vaapi_vp9_surface_id(&h->frames[CUR_FRAME]); |
48 | |
49 | pic_param = (VADecPictureParameterBufferVP9) { |
50 | .frame_width = avctx->width, |
51 | .frame_height = avctx->height, |
52 | |
53 | .pic_fields.bits = { |
54 | .subsampling_x = pixdesc->log2_chroma_w, |
55 | .subsampling_y = pixdesc->log2_chroma_h, |
56 | .frame_type = !h->h.keyframe, |
57 | .show_frame = !h->h.invisible, |
58 | .error_resilient_mode = h->h.errorres, |
59 | .intra_only = h->h.intraonly, |
60 | .allow_high_precision_mv = h->h.keyframe ? 0 : h->h.highprecisionmvs, |
61 | .mcomp_filter_type = h->h.filtermode ^ (h->h.filtermode <= 1), |
62 | .frame_parallel_decoding_mode = h->h.parallelmode, |
63 | .reset_frame_context = h->h.resetctx, |
64 | .refresh_frame_context = h->h.refreshctx, |
65 | .frame_context_idx = h->h.framectxid, |
66 | |
67 | .segmentation_enabled = h->h.segmentation.enabled, |
68 | .segmentation_temporal_update = h->h.segmentation.temporal, |
69 | .segmentation_update_map = h->h.segmentation.update_map, |
70 | |
71 | .last_ref_frame = h->h.refidx[0], |
72 | .last_ref_frame_sign_bias = h->h.signbias[0], |
73 | .golden_ref_frame = h->h.refidx[1], |
74 | .golden_ref_frame_sign_bias = h->h.signbias[1], |
75 | .alt_ref_frame = h->h.refidx[2], |
76 | .alt_ref_frame_sign_bias = h->h.signbias[2], |
77 | .lossless_flag = h->h.lossless, |
78 | }, |
79 | |
80 | .filter_level = h->h.filter.level, |
81 | .sharpness_level = h->h.filter.sharpness, |
82 | .log2_tile_rows = h->h.tiling.log2_tile_rows, |
83 | .log2_tile_columns = h->h.tiling.log2_tile_cols, |
84 | |
85 | .frame_header_length_in_bytes = h->h.uncompressed_header_size, |
86 | .first_partition_size = h->h.compressed_header_size, |
87 | |
88 | .profile = h->h.profile, |
89 | .bit_depth = h->h.bpp, |
90 | }; |
91 | |
92 | for (i = 0; i < 7; i++) |
93 | pic_param.mb_segment_tree_probs[i] = h->h.segmentation.prob[i]; |
94 | |
95 | if (h->h.segmentation.temporal) { |
96 | for (i = 0; i < 3; i++) |
97 | pic_param.segment_pred_probs[i] = h->h.segmentation.pred_prob[i]; |
98 | } else { |
99 | memset(pic_param.segment_pred_probs, 255, sizeof(pic_param.segment_pred_probs)); |
100 | } |
101 | |
102 | for (i = 0; i < 8; i++) { |
103 | if (h->refs[i].f->buf[0]) |
104 | pic_param.reference_frames[i] = ff_vaapi_get_surface_id(h->refs[i].f); |
105 | else |
106 | pic_param.reference_frames[i] = VA_INVALID_ID; |
107 | } |
108 | |
109 | err = ff_vaapi_decode_make_param_buffer(avctx, pic, |
110 | VAPictureParameterBufferType, |
111 | &pic_param, sizeof(pic_param)); |
112 | if (err < 0) { |
113 | ff_vaapi_decode_cancel(avctx, pic); |
114 | return err; |
115 | } |
116 | |
117 | return 0; |
118 | } |
119 | |
120 | static int vaapi_vp9_end_frame(AVCodecContext *avctx) |
121 | { |
122 | const VP9SharedContext *h = avctx->priv_data; |
123 | VAAPIDecodePicture *pic = h->frames[CUR_FRAME].hwaccel_picture_private; |
124 | |
125 | return ff_vaapi_decode_issue(avctx, pic); |
126 | } |
127 | |
128 | static int vaapi_vp9_decode_slice(AVCodecContext *avctx, |
129 | const uint8_t *buffer, |
130 | uint32_t size) |
131 | { |
132 | const VP9SharedContext *h = avctx->priv_data; |
133 | VAAPIDecodePicture *pic = h->frames[CUR_FRAME].hwaccel_picture_private; |
134 | VASliceParameterBufferVP9 slice_param; |
135 | int err, i; |
136 | |
137 | slice_param = (VASliceParameterBufferVP9) { |
138 | .slice_data_size = size, |
139 | .slice_data_offset = 0, |
140 | .slice_data_flag = VA_SLICE_DATA_FLAG_ALL, |
141 | }; |
142 | |
143 | for (i = 0; i < 8; i++) { |
144 | slice_param.seg_param[i] = (VASegmentParameterVP9) { |
145 | .segment_flags.fields = { |
146 | .segment_reference_enabled = h->h.segmentation.feat[i].ref_enabled, |
147 | .segment_reference = h->h.segmentation.feat[i].ref_val, |
148 | .segment_reference_skipped = h->h.segmentation.feat[i].skip_enabled, |
149 | }, |
150 | |
151 | .luma_dc_quant_scale = h->h.segmentation.feat[i].qmul[0][0], |
152 | .luma_ac_quant_scale = h->h.segmentation.feat[i].qmul[0][1], |
153 | .chroma_dc_quant_scale = h->h.segmentation.feat[i].qmul[1][0], |
154 | .chroma_ac_quant_scale = h->h.segmentation.feat[i].qmul[1][1], |
155 | }; |
156 | |
157 | memcpy(slice_param.seg_param[i].filter_level, h->h.segmentation.feat[i].lflvl, sizeof(slice_param.seg_param[i].filter_level)); |
158 | } |
159 | |
160 | err = ff_vaapi_decode_make_slice_buffer(avctx, pic, |
161 | &slice_param, sizeof(slice_param), |
162 | buffer, size); |
163 | if (err) { |
164 | ff_vaapi_decode_cancel(avctx, pic); |
165 | return err; |
166 | } |
167 | |
168 | return 0; |
169 | } |
170 | |
171 | AVHWAccel ff_vp9_vaapi_hwaccel = { |
172 | .name = "vp9_vaapi", |
173 | .type = AVMEDIA_TYPE_VIDEO, |
174 | .id = AV_CODEC_ID_VP9, |
175 | .pix_fmt = AV_PIX_FMT_VAAPI, |
176 | .start_frame = vaapi_vp9_start_frame, |
177 | .end_frame = vaapi_vp9_end_frame, |
178 | .decode_slice = vaapi_vp9_decode_slice, |
179 | .frame_priv_data_size = sizeof(VAAPIDecodePicture), |
180 | .init = ff_vaapi_decode_init, |
181 | .uninit = ff_vaapi_decode_uninit, |
182 | .priv_data_size = sizeof(VAAPIDecodeContext), |
183 | .caps_internal = HWACCEL_CAP_ASYNC_SAFE, |
184 | }; |
185 |