Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * DXVA2 WMV3/VC-1 HW acceleration. | |
3 | * | |
4 | * copyright (c) 2010 Laurent Aimar | |
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 "dxva2_internal.h" | |
24 | #include "mpegutils.h" | |
25 | #include "vc1.h" | |
26 | #include "vc1data.h" | |
27 | ||
28 | struct dxva2_picture_context { | |
29 | DXVA_PictureParameters pp; | |
30 | DXVA_SliceInfo si; | |
31 | ||
32 | const uint8_t *bitstream; | |
33 | unsigned bitstream_size; | |
34 | }; | |
35 | ||
36 | static void fill_picture_parameters(AVCodecContext *avctx, | |
37 | struct dxva_context *ctx, const VC1Context *v, | |
38 | DXVA_PictureParameters *pp) | |
39 | { | |
40 | const MpegEncContext *s = &v->s; | |
41 | const Picture *current_picture = s->current_picture_ptr; | |
42 | int intcomp = 0; | |
43 | ||
44 | // determine if intensity compensation is needed | |
45 | if (s->pict_type == AV_PICTURE_TYPE_P) { | |
46 | if ((v->fcm == ILACE_FRAME && v->intcomp) || (v->fcm != ILACE_FRAME && v->mv_mode == MV_PMODE_INTENSITY_COMP)) { | |
47 | if (v->lumscale != 32 || v->lumshift != 0 || (s->picture_structure != PICT_FRAME && (v->lumscale2 != 32 || v->lumshift2 != 0))) | |
48 | intcomp = 1; | |
49 | } | |
50 | } | |
51 | ||
52 | memset(pp, 0, sizeof(*pp)); | |
53 | pp->wDecodedPictureIndex = | |
54 | pp->wDeblockedPictureIndex = ff_dxva2_get_surface_index(ctx, current_picture->f); | |
55 | if (s->pict_type != AV_PICTURE_TYPE_I && !v->bi_type) | |
56 | pp->wForwardRefPictureIndex = ff_dxva2_get_surface_index(ctx, s->last_picture.f); | |
57 | else | |
58 | pp->wForwardRefPictureIndex = 0xffff; | |
59 | if (s->pict_type == AV_PICTURE_TYPE_B && !v->bi_type) | |
60 | pp->wBackwardRefPictureIndex = ff_dxva2_get_surface_index(ctx, s->next_picture.f); | |
61 | else | |
62 | pp->wBackwardRefPictureIndex = 0xffff; | |
63 | if (v->profile == PROFILE_ADVANCED) { | |
64 | /* It is the cropped width/height -1 of the frame */ | |
65 | pp->wPicWidthInMBminus1 = avctx->width - 1; | |
66 | pp->wPicHeightInMBminus1= avctx->height - 1; | |
67 | } else { | |
68 | /* It is the coded width/height in macroblock -1 of the frame */ | |
69 | pp->wPicWidthInMBminus1 = s->mb_width - 1; | |
70 | pp->wPicHeightInMBminus1= s->mb_height - 1; | |
71 | } | |
72 | pp->bMacroblockWidthMinus1 = 15; | |
73 | pp->bMacroblockHeightMinus1 = 15; | |
74 | pp->bBlockWidthMinus1 = 7; | |
75 | pp->bBlockHeightMinus1 = 7; | |
76 | pp->bBPPminus1 = 7; | |
77 | if (s->picture_structure & PICT_TOP_FIELD) | |
78 | pp->bPicStructure |= 0x01; | |
79 | if (s->picture_structure & PICT_BOTTOM_FIELD) | |
80 | pp->bPicStructure |= 0x02; | |
81 | pp->bSecondField = v->interlace && v->fcm == ILACE_FIELD && v->second_field; | |
82 | pp->bPicIntra = s->pict_type == AV_PICTURE_TYPE_I || v->bi_type; | |
83 | pp->bPicBackwardPrediction = s->pict_type == AV_PICTURE_TYPE_B && !v->bi_type; | |
84 | pp->bBidirectionalAveragingMode = (1 << 7) | | |
85 | ((ctx->cfg->ConfigIntraResidUnsigned != 0) << 6) | | |
86 | ((ctx->cfg->ConfigResidDiffAccelerator != 0) << 5) | | |
87 | (intcomp << 4) | | |
88 | ((v->profile == PROFILE_ADVANCED) << 3); | |
89 | pp->bMVprecisionAndChromaRelation = ((v->mv_mode == MV_PMODE_1MV_HPEL_BILIN) << 3) | | |
90 | (1 << 2) | | |
91 | (0 << 1) | | |
92 | (!s->quarter_sample ); | |
93 | pp->bChromaFormat = v->chromaformat; | |
94 | ctx->report_id++; | |
95 | if (ctx->report_id >= (1 << 16)) | |
96 | ctx->report_id = 1; | |
97 | pp->bPicScanFixed = ctx->report_id >> 8; | |
98 | pp->bPicScanMethod = ctx->report_id & 0xff; | |
99 | pp->bPicReadbackRequests = 0; | |
100 | pp->bRcontrol = v->rnd; | |
101 | pp->bPicSpatialResid8 = (v->panscanflag << 7) | | |
102 | (v->refdist_flag << 6) | | |
103 | (s->loop_filter << 5) | | |
104 | (v->fastuvmc << 4) | | |
105 | (v->extended_mv << 3) | | |
106 | (v->dquant << 1) | | |
107 | (v->vstransform ); | |
108 | pp->bPicOverflowBlocks = (v->quantizer_mode << 6) | | |
109 | (v->multires << 5) | | |
110 | (v->resync_marker << 4) | | |
111 | (v->rangered << 3) | | |
112 | (s->max_b_frames ); | |
113 | pp->bPicExtrapolation = (!v->interlace || v->fcm == PROGRESSIVE) ? 1 : 2; | |
114 | pp->bPicDeblocked = ((!pp->bPicBackwardPrediction && v->overlap) << 6) | | |
115 | ((v->profile != PROFILE_ADVANCED && v->rangeredfrm) << 5) | | |
116 | (s->loop_filter << 1); | |
117 | pp->bPicDeblockConfined = (v->postprocflag << 7) | | |
118 | (v->broadcast << 6) | | |
119 | (v->interlace << 5) | | |
120 | (v->tfcntrflag << 4) | | |
121 | (v->finterpflag << 3) | | |
122 | ((s->pict_type != AV_PICTURE_TYPE_B) << 2) | | |
123 | (v->psf << 1) | | |
124 | (v->extended_dmv ); | |
125 | if (s->pict_type != AV_PICTURE_TYPE_I) | |
126 | pp->bPic4MVallowed = v->mv_mode == MV_PMODE_MIXED_MV || | |
127 | (v->mv_mode == MV_PMODE_INTENSITY_COMP && | |
128 | v->mv_mode2 == MV_PMODE_MIXED_MV); | |
129 | if (v->profile == PROFILE_ADVANCED) | |
130 | pp->bPicOBMC = (v->range_mapy_flag << 7) | | |
131 | (v->range_mapy << 4) | | |
132 | (v->range_mapuv_flag << 3) | | |
133 | (v->range_mapuv ); | |
134 | pp->bPicBinPB = 0; | |
135 | pp->bMV_RPS = (v->fcm == ILACE_FIELD && pp->bPicBackwardPrediction) ? v->refdist + 9 : 0; | |
136 | pp->bReservedBits = v->pq; | |
137 | if (s->picture_structure == PICT_FRAME) { | |
138 | if (intcomp) { | |
139 | pp->wBitstreamFcodes = v->lumscale; | |
140 | pp->wBitstreamPCEelements = v->lumshift; | |
141 | } else { | |
142 | pp->wBitstreamFcodes = 32; | |
143 | pp->wBitstreamPCEelements = 0; | |
144 | } | |
145 | } else { | |
146 | /* Syntax: (top_field_param << 8) | bottom_field_param */ | |
147 | if (intcomp) { | |
148 | pp->wBitstreamFcodes = (v->lumscale << 8) | v->lumscale2; | |
149 | pp->wBitstreamPCEelements = (v->lumshift << 8) | v->lumshift2; | |
150 | } else { | |
151 | pp->wBitstreamFcodes = (32 << 8) | 32; | |
152 | pp->wBitstreamPCEelements = 0; | |
153 | } | |
154 | } | |
155 | pp->bBitstreamConcealmentNeed = 0; | |
156 | pp->bBitstreamConcealmentMethod = 0; | |
157 | } | |
158 | ||
159 | static void fill_slice(AVCodecContext *avctx, DXVA_SliceInfo *slice, | |
160 | unsigned position, unsigned size) | |
161 | { | |
162 | const VC1Context *v = avctx->priv_data; | |
163 | const MpegEncContext *s = &v->s; | |
164 | ||
165 | memset(slice, 0, sizeof(*slice)); | |
166 | slice->wHorizontalPosition = 0; | |
167 | slice->wVerticalPosition = s->mb_y; | |
168 | slice->dwSliceBitsInBuffer = 8 * size; | |
169 | slice->dwSliceDataLocation = position; | |
170 | slice->bStartCodeBitOffset = 0; | |
171 | slice->bReservedBits = (s->pict_type == AV_PICTURE_TYPE_B && !v->bi_type) ? v->bfraction_lut_index + 9 : 0; | |
172 | slice->wMBbitOffset = v->p_frame_skipped ? 0xffff : get_bits_count(&s->gb) + (avctx->codec_id == AV_CODEC_ID_VC1 ? 32 : 0); | |
173 | slice->wNumberMBsInSlice = s->mb_width * s->mb_height; /* XXX We assume 1 slice */ | |
174 | slice->wQuantizerScaleCode = v->pq; | |
175 | slice->wBadSliceChopping = 0; | |
176 | } | |
177 | ||
178 | static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, | |
179 | DXVA2_DecodeBufferDesc *bs, | |
180 | DXVA2_DecodeBufferDesc *sc) | |
181 | { | |
182 | const VC1Context *v = avctx->priv_data; | |
183 | struct dxva_context *ctx = avctx->hwaccel_context; | |
184 | const MpegEncContext *s = &v->s; | |
185 | struct dxva2_picture_context *ctx_pic = s->current_picture_ptr->hwaccel_picture_private; | |
186 | ||
187 | DXVA_SliceInfo *slice = &ctx_pic->si; | |
188 | ||
189 | static const uint8_t start_code[] = { 0, 0, 1, 0x0d }; | |
190 | const unsigned start_code_size = avctx->codec_id == AV_CODEC_ID_VC1 ? sizeof(start_code) : 0; | |
191 | const unsigned slice_size = slice->dwSliceBitsInBuffer / 8; | |
192 | const unsigned padding = 128 - ((start_code_size + slice_size) & 127); | |
193 | const unsigned data_size = start_code_size + slice_size + padding; | |
194 | ||
195 | void *dxva_data_ptr; | |
196 | uint8_t *dxva_data; | |
197 | unsigned dxva_size; | |
198 | int result; | |
199 | ||
200 | if (FAILED(IDirectXVideoDecoder_GetBuffer(ctx->decoder, | |
201 | DXVA2_BitStreamDateBufferType, | |
202 | &dxva_data_ptr, &dxva_size))) | |
203 | return -1; | |
204 | ||
205 | dxva_data = dxva_data_ptr; | |
206 | result = data_size <= dxva_size ? 0 : -1; | |
207 | if (!result) { | |
208 | if (start_code_size > 0) { | |
209 | memcpy(dxva_data, start_code, start_code_size); | |
210 | if (v->second_field) | |
211 | dxva_data[3] = 0x0c; | |
212 | } | |
213 | memcpy(dxva_data + start_code_size, | |
214 | ctx_pic->bitstream + slice->dwSliceDataLocation, slice_size); | |
215 | if (padding > 0) | |
216 | memset(dxva_data + start_code_size + slice_size, 0, padding); | |
217 | slice->dwSliceBitsInBuffer = 8 * data_size; | |
218 | } | |
219 | if (FAILED(IDirectXVideoDecoder_ReleaseBuffer(ctx->decoder, | |
220 | DXVA2_BitStreamDateBufferType))) | |
221 | return -1; | |
222 | if (result) | |
223 | return result; | |
224 | ||
225 | memset(bs, 0, sizeof(*bs)); | |
226 | bs->CompressedBufferType = DXVA2_BitStreamDateBufferType; | |
227 | bs->DataSize = data_size; | |
228 | bs->NumMBsInBuffer = s->mb_width * s->mb_height; | |
229 | assert((bs->DataSize & 127) == 0); | |
230 | ||
231 | return ff_dxva2_commit_buffer(avctx, ctx, sc, | |
232 | DXVA2_SliceControlBufferType, | |
233 | slice, sizeof(*slice), bs->NumMBsInBuffer); | |
234 | } | |
235 | ||
236 | static int dxva2_vc1_start_frame(AVCodecContext *avctx, | |
237 | av_unused const uint8_t *buffer, | |
238 | av_unused uint32_t size) | |
239 | { | |
240 | const VC1Context *v = avctx->priv_data; | |
241 | struct dxva_context *ctx = avctx->hwaccel_context; | |
242 | struct dxva2_picture_context *ctx_pic = v->s.current_picture_ptr->hwaccel_picture_private; | |
243 | ||
244 | if (!ctx->decoder || !ctx->cfg || ctx->surface_count <= 0) | |
245 | return -1; | |
246 | assert(ctx_pic); | |
247 | ||
248 | fill_picture_parameters(avctx, ctx, v, &ctx_pic->pp); | |
249 | ||
250 | ctx_pic->bitstream_size = 0; | |
251 | ctx_pic->bitstream = NULL; | |
252 | return 0; | |
253 | } | |
254 | ||
255 | static int dxva2_vc1_decode_slice(AVCodecContext *avctx, | |
256 | const uint8_t *buffer, | |
257 | uint32_t size) | |
258 | { | |
259 | const VC1Context *v = avctx->priv_data; | |
260 | const Picture *current_picture = v->s.current_picture_ptr; | |
261 | struct dxva2_picture_context *ctx_pic = current_picture->hwaccel_picture_private; | |
262 | ||
263 | if (ctx_pic->bitstream_size > 0) | |
264 | return -1; | |
265 | ||
266 | if (avctx->codec_id == AV_CODEC_ID_VC1 && | |
267 | size >= 4 && IS_MARKER(AV_RB32(buffer))) { | |
268 | buffer += 4; | |
269 | size -= 4; | |
270 | } | |
271 | ||
272 | ctx_pic->bitstream_size = size; | |
273 | ctx_pic->bitstream = buffer; | |
274 | ||
275 | fill_slice(avctx, &ctx_pic->si, 0, size); | |
276 | return 0; | |
277 | } | |
278 | ||
279 | static int dxva2_vc1_end_frame(AVCodecContext *avctx) | |
280 | { | |
281 | VC1Context *v = avctx->priv_data; | |
282 | struct dxva2_picture_context *ctx_pic = v->s.current_picture_ptr->hwaccel_picture_private; | |
283 | int ret; | |
284 | ||
285 | if (ctx_pic->bitstream_size <= 0) | |
286 | return -1; | |
287 | ||
288 | ret = ff_dxva2_common_end_frame(avctx, v->s.current_picture_ptr->f, | |
289 | &ctx_pic->pp, sizeof(ctx_pic->pp), | |
290 | NULL, 0, | |
291 | commit_bitstream_and_slice_buffer); | |
292 | if (!ret) | |
293 | ff_mpeg_draw_horiz_band(&v->s, 0, avctx->height); | |
294 | return ret; | |
295 | } | |
296 | ||
297 | #if CONFIG_WMV3_DXVA2_HWACCEL | |
298 | AVHWAccel ff_wmv3_dxva2_hwaccel = { | |
299 | .name = "wmv3_dxva2", | |
300 | .type = AVMEDIA_TYPE_VIDEO, | |
301 | .id = AV_CODEC_ID_WMV3, | |
302 | .pix_fmt = AV_PIX_FMT_DXVA2_VLD, | |
303 | .start_frame = dxva2_vc1_start_frame, | |
304 | .decode_slice = dxva2_vc1_decode_slice, | |
305 | .end_frame = dxva2_vc1_end_frame, | |
306 | .frame_priv_data_size = sizeof(struct dxva2_picture_context), | |
307 | }; | |
308 | #endif | |
309 | ||
310 | AVHWAccel ff_vc1_dxva2_hwaccel = { | |
311 | .name = "vc1_dxva2", | |
312 | .type = AVMEDIA_TYPE_VIDEO, | |
313 | .id = AV_CODEC_ID_VC1, | |
314 | .pix_fmt = AV_PIX_FMT_DXVA2_VLD, | |
315 | .start_frame = dxva2_vc1_start_frame, | |
316 | .decode_slice = dxva2_vc1_decode_slice, | |
317 | .end_frame = dxva2_vc1_end_frame, | |
318 | .frame_priv_data_size = sizeof(struct dxva2_picture_context), | |
319 | }; |