Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * MPEG-2 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 "libavutil/log.h" | |
24 | #include "dxva2_internal.h" | |
25 | #include "mpegutils.h" | |
26 | ||
27 | #define MAX_SLICES 1024 | |
28 | struct dxva2_picture_context { | |
29 | DXVA_PictureParameters pp; | |
30 | DXVA_QmatrixData qm; | |
31 | unsigned slice_count; | |
32 | DXVA_SliceInfo slice[MAX_SLICES]; | |
33 | ||
34 | const uint8_t *bitstream; | |
35 | unsigned bitstream_size; | |
36 | }; | |
37 | ||
38 | static void fill_picture_parameters(AVCodecContext *avctx, | |
39 | struct dxva_context *ctx, | |
40 | const struct MpegEncContext *s, | |
41 | DXVA_PictureParameters *pp) | |
42 | { | |
43 | const Picture *current_picture = s->current_picture_ptr; | |
44 | int is_field = s->picture_structure != PICT_FRAME; | |
45 | ||
46 | memset(pp, 0, sizeof(*pp)); | |
47 | pp->wDecodedPictureIndex = ff_dxva2_get_surface_index(ctx, current_picture->f); | |
48 | pp->wDeblockedPictureIndex = 0; | |
49 | if (s->pict_type != AV_PICTURE_TYPE_I) | |
50 | pp->wForwardRefPictureIndex = ff_dxva2_get_surface_index(ctx, s->last_picture.f); | |
51 | else | |
52 | pp->wForwardRefPictureIndex = 0xffff; | |
53 | if (s->pict_type == AV_PICTURE_TYPE_B) | |
54 | pp->wBackwardRefPictureIndex = ff_dxva2_get_surface_index(ctx, s->next_picture.f); | |
55 | else | |
56 | pp->wBackwardRefPictureIndex = 0xffff; | |
57 | pp->wPicWidthInMBminus1 = s->mb_width - 1; | |
58 | pp->wPicHeightInMBminus1 = (s->mb_height >> is_field) - 1; | |
59 | pp->bMacroblockWidthMinus1 = 15; | |
60 | pp->bMacroblockHeightMinus1 = 15; | |
61 | pp->bBlockWidthMinus1 = 7; | |
62 | pp->bBlockHeightMinus1 = 7; | |
63 | pp->bBPPminus1 = 7; | |
64 | pp->bPicStructure = s->picture_structure; | |
65 | pp->bSecondField = is_field && !s->first_field; | |
66 | pp->bPicIntra = s->pict_type == AV_PICTURE_TYPE_I; | |
67 | pp->bPicBackwardPrediction = s->pict_type == AV_PICTURE_TYPE_B; | |
68 | pp->bBidirectionalAveragingMode = 0; | |
69 | pp->bMVprecisionAndChromaRelation= 0; /* FIXME */ | |
70 | pp->bChromaFormat = s->chroma_format; | |
71 | pp->bPicScanFixed = 1; | |
72 | pp->bPicScanMethod = s->alternate_scan ? 1 : 0; | |
73 | pp->bPicReadbackRequests = 0; | |
74 | pp->bRcontrol = 0; | |
75 | pp->bPicSpatialResid8 = 0; | |
76 | pp->bPicOverflowBlocks = 0; | |
77 | pp->bPicExtrapolation = 0; | |
78 | pp->bPicDeblocked = 0; | |
79 | pp->bPicDeblockConfined = 0; | |
80 | pp->bPic4MVallowed = 0; | |
81 | pp->bPicOBMC = 0; | |
82 | pp->bPicBinPB = 0; | |
83 | pp->bMV_RPS = 0; | |
84 | pp->bReservedBits = 0; | |
85 | pp->wBitstreamFcodes = (s->mpeg_f_code[0][0] << 12) | | |
86 | (s->mpeg_f_code[0][1] << 8) | | |
87 | (s->mpeg_f_code[1][0] << 4) | | |
88 | (s->mpeg_f_code[1][1] ); | |
89 | pp->wBitstreamPCEelements = (s->intra_dc_precision << 14) | | |
90 | (s->picture_structure << 12) | | |
91 | (s->top_field_first << 11) | | |
92 | (s->frame_pred_frame_dct << 10) | | |
93 | (s->concealment_motion_vectors << 9) | | |
94 | (s->q_scale_type << 8) | | |
95 | (s->intra_vlc_format << 7) | | |
96 | (s->alternate_scan << 6) | | |
97 | (s->repeat_first_field << 5) | | |
98 | (s->chroma_420_type << 4) | | |
99 | (s->progressive_frame << 3); | |
100 | pp->bBitstreamConcealmentNeed = 0; | |
101 | pp->bBitstreamConcealmentMethod = 0; | |
102 | } | |
103 | ||
104 | static void fill_quantization_matrices(AVCodecContext *avctx, | |
105 | struct dxva_context *ctx, | |
106 | const struct MpegEncContext *s, | |
107 | DXVA_QmatrixData *qm) | |
108 | { | |
109 | int i; | |
110 | for (i = 0; i < 4; i++) | |
111 | qm->bNewQmatrix[i] = 1; | |
112 | for (i = 0; i < 64; i++) { | |
113 | int n = s->idsp.idct_permutation[ff_zigzag_direct[i]]; | |
114 | qm->Qmatrix[0][i] = s->intra_matrix[n]; | |
115 | qm->Qmatrix[1][i] = s->inter_matrix[n]; | |
116 | qm->Qmatrix[2][i] = s->chroma_intra_matrix[n]; | |
117 | qm->Qmatrix[3][i] = s->chroma_inter_matrix[n]; | |
118 | } | |
119 | } | |
120 | ||
121 | static void fill_slice(AVCodecContext *avctx, | |
122 | const struct MpegEncContext *s, | |
123 | DXVA_SliceInfo *slice, | |
124 | unsigned position, | |
125 | const uint8_t *buffer, unsigned size) | |
126 | { | |
127 | int is_field = s->picture_structure != PICT_FRAME; | |
128 | GetBitContext gb; | |
129 | ||
130 | memset(slice, 0, sizeof(*slice)); | |
131 | slice->wHorizontalPosition = s->mb_x; | |
132 | slice->wVerticalPosition = s->mb_y >> is_field; | |
133 | slice->dwSliceBitsInBuffer = 8 * size; | |
134 | slice->dwSliceDataLocation = position; | |
135 | slice->bStartCodeBitOffset = 0; | |
136 | slice->bReservedBits = 0; | |
137 | /* XXX We store the index of the first MB and it will be fixed later */ | |
138 | slice->wNumberMBsInSlice = (s->mb_y >> is_field) * s->mb_width + s->mb_x; | |
139 | slice->wBadSliceChopping = 0; | |
140 | ||
141 | init_get_bits(&gb, &buffer[4], 8 * (size - 4)); | |
142 | ||
143 | slice->wQuantizerScaleCode = get_bits(&gb, 5); | |
144 | skip_1stop_8data_bits(&gb); | |
145 | ||
146 | slice->wMBbitOffset = 4 * 8 + get_bits_count(&gb); | |
147 | } | |
148 | static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, | |
149 | DXVA2_DecodeBufferDesc *bs, | |
150 | DXVA2_DecodeBufferDesc *sc) | |
151 | { | |
152 | const struct MpegEncContext *s = avctx->priv_data; | |
153 | struct dxva_context *ctx = avctx->hwaccel_context; | |
154 | struct dxva2_picture_context *ctx_pic = | |
155 | s->current_picture_ptr->hwaccel_picture_private; | |
156 | const int is_field = s->picture_structure != PICT_FRAME; | |
157 | const unsigned mb_count = s->mb_width * (s->mb_height >> is_field); | |
158 | void *dxva_data_ptr; | |
159 | uint8_t *dxva_data, *current, *end; | |
160 | unsigned dxva_size; | |
161 | unsigned i; | |
162 | ||
163 | if (FAILED(IDirectXVideoDecoder_GetBuffer(ctx->decoder, | |
164 | DXVA2_BitStreamDateBufferType, | |
165 | &dxva_data_ptr, &dxva_size))) | |
166 | return -1; | |
167 | ||
168 | dxva_data = dxva_data_ptr; | |
169 | current = dxva_data; | |
170 | end = dxva_data + dxva_size; | |
171 | ||
172 | for (i = 0; i < ctx_pic->slice_count; i++) { | |
173 | DXVA_SliceInfo *slice = &ctx_pic->slice[i]; | |
174 | unsigned position = slice->dwSliceDataLocation; | |
175 | unsigned size = slice->dwSliceBitsInBuffer / 8; | |
176 | if (size > end - current) { | |
177 | av_log(avctx, AV_LOG_ERROR, "Failed to build bitstream"); | |
178 | break; | |
179 | } | |
180 | slice->dwSliceDataLocation = current - dxva_data; | |
181 | ||
182 | if (i < ctx_pic->slice_count - 1) | |
183 | slice->wNumberMBsInSlice = | |
184 | slice[1].wNumberMBsInSlice - slice[0].wNumberMBsInSlice; | |
185 | else | |
186 | slice->wNumberMBsInSlice = | |
187 | mb_count - slice[0].wNumberMBsInSlice; | |
188 | ||
189 | memcpy(current, &ctx_pic->bitstream[position], size); | |
190 | current += size; | |
191 | } | |
192 | if (FAILED(IDirectXVideoDecoder_ReleaseBuffer(ctx->decoder, | |
193 | DXVA2_BitStreamDateBufferType))) | |
194 | return -1; | |
195 | if (i < ctx_pic->slice_count) | |
196 | return -1; | |
197 | ||
198 | memset(bs, 0, sizeof(*bs)); | |
199 | bs->CompressedBufferType = DXVA2_BitStreamDateBufferType; | |
200 | bs->DataSize = current - dxva_data; | |
201 | bs->NumMBsInBuffer = mb_count; | |
202 | ||
203 | return ff_dxva2_commit_buffer(avctx, ctx, sc, | |
204 | DXVA2_SliceControlBufferType, | |
205 | ctx_pic->slice, | |
206 | ctx_pic->slice_count * sizeof(*ctx_pic->slice), | |
207 | mb_count); | |
208 | } | |
209 | ||
210 | static int dxva2_mpeg2_start_frame(AVCodecContext *avctx, | |
211 | av_unused const uint8_t *buffer, | |
212 | av_unused uint32_t size) | |
213 | { | |
214 | const struct MpegEncContext *s = avctx->priv_data; | |
215 | struct dxva_context *ctx = avctx->hwaccel_context; | |
216 | struct dxva2_picture_context *ctx_pic = | |
217 | s->current_picture_ptr->hwaccel_picture_private; | |
218 | ||
219 | if (!ctx->decoder || !ctx->cfg || ctx->surface_count <= 0) | |
220 | return -1; | |
221 | assert(ctx_pic); | |
222 | ||
223 | fill_picture_parameters(avctx, ctx, s, &ctx_pic->pp); | |
224 | fill_quantization_matrices(avctx, ctx, s, &ctx_pic->qm); | |
225 | ||
226 | ctx_pic->slice_count = 0; | |
227 | ctx_pic->bitstream_size = 0; | |
228 | ctx_pic->bitstream = NULL; | |
229 | return 0; | |
230 | } | |
231 | ||
232 | static int dxva2_mpeg2_decode_slice(AVCodecContext *avctx, | |
233 | const uint8_t *buffer, uint32_t size) | |
234 | { | |
235 | const struct MpegEncContext *s = avctx->priv_data; | |
236 | struct dxva2_picture_context *ctx_pic = | |
237 | s->current_picture_ptr->hwaccel_picture_private; | |
238 | unsigned position; | |
239 | ||
240 | if (ctx_pic->slice_count >= MAX_SLICES) { | |
241 | avpriv_request_sample(avctx, "%d slices in dxva2", | |
242 | ctx_pic->slice_count); | |
243 | return -1; | |
244 | } | |
245 | if (!ctx_pic->bitstream) | |
246 | ctx_pic->bitstream = buffer; | |
247 | ctx_pic->bitstream_size += size; | |
248 | ||
249 | position = buffer - ctx_pic->bitstream; | |
250 | fill_slice(avctx, s, &ctx_pic->slice[ctx_pic->slice_count++], position, | |
251 | buffer, size); | |
252 | return 0; | |
253 | } | |
254 | ||
255 | static int dxva2_mpeg2_end_frame(AVCodecContext *avctx) | |
256 | { | |
257 | struct MpegEncContext *s = avctx->priv_data; | |
258 | struct dxva2_picture_context *ctx_pic = | |
259 | s->current_picture_ptr->hwaccel_picture_private; | |
260 | int ret; | |
261 | ||
262 | if (ctx_pic->slice_count <= 0 || ctx_pic->bitstream_size <= 0) | |
263 | return -1; | |
264 | ret = ff_dxva2_common_end_frame(avctx, s->current_picture_ptr->f, | |
265 | &ctx_pic->pp, sizeof(ctx_pic->pp), | |
266 | &ctx_pic->qm, sizeof(ctx_pic->qm), | |
267 | commit_bitstream_and_slice_buffer); | |
268 | if (!ret) | |
269 | ff_mpeg_draw_horiz_band(s, 0, avctx->height); | |
270 | return ret; | |
271 | } | |
272 | ||
273 | AVHWAccel ff_mpeg2_dxva2_hwaccel = { | |
274 | .name = "mpeg2_dxva2", | |
275 | .type = AVMEDIA_TYPE_VIDEO, | |
276 | .id = AV_CODEC_ID_MPEG2VIDEO, | |
277 | .pix_fmt = AV_PIX_FMT_DXVA2_VLD, | |
278 | .start_frame = dxva2_mpeg2_start_frame, | |
279 | .decode_slice = dxva2_mpeg2_decode_slice, | |
280 | .end_frame = dxva2_mpeg2_end_frame, | |
281 | .frame_priv_data_size = sizeof(struct dxva2_picture_context), | |
282 | }; |