Browse code

MPEG-2 DXVA2 implementation

It allows VLD MPEG-2 decoding using DXVA2 (GPU assisted decoding API under
VISTA and Windows 7).
It is implemented by using AVHWAccel API.

Originally committed as revision 23644 to svn://svn.ffmpeg.org/ffmpeg/trunk

Laurent Aimar authored on 2010/06/19 05:07:43
Showing 4 changed files
... ...
@@ -1260,6 +1260,8 @@ mpeg4_decoder_select="h263_decoder mpeg4video_parser"
1260 1260
 mpeg4_encoder_select="h263_encoder"
1261 1261
 mpeg_vdpau_decoder_select="vdpau mpegvideo_decoder"
1262 1262
 mpeg1_vdpau_decoder_select="vdpau mpeg1video_decoder"
1263
+mpeg2_dxva2_hwaccel_deps="dxva2api_h"
1264
+mpeg2_dxva2_hwaccel_select="dxva2 mpeg2video_decoder"
1263 1265
 mpeg2_vaapi_hwaccel_select="vaapi mpeg2video_decoder"
1264 1266
 mpeg4_vaapi_hwaccel_select="vaapi mpeg4_decoder"
1265 1267
 mpeg4_vdpau_decoder_select="vdpau mpeg4_decoder"
... ...
@@ -228,6 +228,7 @@ OBJS-$(CONFIG_MPEG1VIDEO_ENCODER)      += mpeg12enc.o mpegvideo_enc.o \
228 228
                                           motion_est.o ratecontrol.o  \
229 229
                                           mpeg12.o mpeg12data.o       \
230 230
                                           mpegvideo.o error_resilience.o
231
+OBJS-$(CONFIG_MPEG2_DXVA2_HWACCEL)     += dxva2_mpeg2.o
231 232
 OBJS-$(CONFIG_MPEG2_VAAPI_HWACCEL)     += vaapi_mpeg2.o
232 233
 OBJS-$(CONFIG_MPEG2VIDEO_DECODER)      += mpeg12.o mpeg12data.o \
233 234
                                           mpegvideo.o error_resilience.o
... ...
@@ -57,6 +57,7 @@ void avcodec_register_all(void)
57 57
     REGISTER_HWACCEL (H263_VAAPI, h263_vaapi);
58 58
     REGISTER_HWACCEL (H264_DXVA2, h264_dxva2);
59 59
     REGISTER_HWACCEL (H264_VAAPI, h264_vaapi);
60
+    REGISTER_HWACCEL (MPEG2_DXVA2, mpeg2_dxva2);
60 61
     REGISTER_HWACCEL (MPEG2_VAAPI, mpeg2_vaapi);
61 62
     REGISTER_HWACCEL (MPEG4_VAAPI, mpeg4_vaapi);
62 63
     REGISTER_HWACCEL (VC1_DXVA2, vc1_dxva2);
63 64
new file mode 100644
... ...
@@ -0,0 +1,274 @@
0
+/*
1
+ * MPEG-2 HW acceleration.
2
+ *
3
+ * copyright (c) 2010 Laurent Aimar
4
+ *
5
+ * This file is part of FFmpeg.
6
+ *
7
+ * FFmpeg is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * FFmpeg is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with FFmpeg; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ */
21
+
22
+#include "dxva2_internal.h"
23
+
24
+#define MAX_SLICES (SLICE_MAX_START_CODE - SLICE_MIN_START_CODE + 1)
25
+struct dxva2_picture_context {
26
+    DXVA_PictureParameters pp;
27
+    DXVA_QmatrixData       qm;
28
+    unsigned               slice_count;
29
+    DXVA_SliceInfo         slice[MAX_SLICES];
30
+
31
+    const uint8_t          *bitstream;
32
+    unsigned               bitstream_size;
33
+};
34
+
35
+static void fill_picture_parameters(AVCodecContext *avctx,
36
+                                    struct dxva_context *ctx,
37
+                                    const struct MpegEncContext *s,
38
+                                    DXVA_PictureParameters *pp)
39
+{
40
+    const Picture *current_picture = s->current_picture_ptr;
41
+    int is_field = s->picture_structure != PICT_FRAME;
42
+
43
+    memset(pp, 0, sizeof(*pp));
44
+    pp->wDecodedPictureIndex         = ff_dxva2_get_surface_index(ctx, current_picture);
45
+    pp->wDeblockedPictureIndex       = 0;
46
+    if (s->pict_type != FF_I_TYPE)
47
+        pp->wForwardRefPictureIndex  = ff_dxva2_get_surface_index(ctx, &s->last_picture);
48
+    else
49
+        pp->wForwardRefPictureIndex  = 0xffff;
50
+    if (s->pict_type == FF_B_TYPE)
51
+        pp->wBackwardRefPictureIndex = ff_dxva2_get_surface_index(ctx, &s->next_picture);
52
+    else
53
+        pp->wBackwardRefPictureIndex = 0xffff;
54
+    pp->wPicWidthInMBminus1          = s->mb_width  - 1;
55
+    pp->wPicHeightInMBminus1         = (s->mb_height >> is_field) - 1;
56
+    pp->bMacroblockWidthMinus1       = 15;
57
+    pp->bMacroblockHeightMinus1      = 15;
58
+    pp->bBlockWidthMinus1            = 7;
59
+    pp->bBlockHeightMinus1           = 7;
60
+    pp->bBPPminus1                   = 7;
61
+    pp->bPicStructure                = s->picture_structure;
62
+    pp->bSecondField                 = is_field && !s->first_field;
63
+    pp->bPicIntra                    = s->pict_type == FF_I_TYPE;
64
+    pp->bPicBackwardPrediction       = s->pict_type == FF_B_TYPE;
65
+    pp->bBidirectionalAveragingMode  = 0;
66
+    pp->bMVprecisionAndChromaRelation= 0; /* FIXME */
67
+    pp->bChromaFormat                = s->chroma_format;
68
+    pp->bPicScanFixed                = 1;
69
+    pp->bPicScanMethod               = s->alternate_scan ? 1 : 0;
70
+    pp->bPicReadbackRequests         = 0;
71
+    pp->bRcontrol                    = 0;
72
+    pp->bPicSpatialResid8            = 0;
73
+    pp->bPicOverflowBlocks           = 0;
74
+    pp->bPicExtrapolation            = 0;
75
+    pp->bPicDeblocked                = 0;
76
+    pp->bPicDeblockConfined          = 0;
77
+    pp->bPic4MVallowed               = 0;
78
+    pp->bPicOBMC                     = 0;
79
+    pp->bPicBinPB                    = 0;
80
+    pp->bMV_RPS                      = 0;
81
+    pp->bReservedBits                = 0;
82
+    pp->wBitstreamFcodes             = (s->mpeg_f_code[0][0] << 12) |
83
+                                       (s->mpeg_f_code[0][1] <<  8) |
84
+                                       (s->mpeg_f_code[1][0] <<  4) |
85
+                                       (s->mpeg_f_code[1][1]      );
86
+    pp->wBitstreamPCEelements        = (s->intra_dc_precision         << 14) |
87
+                                       (s->picture_structure          << 12) |
88
+                                       (s->top_field_first            << 11) |
89
+                                       (s->frame_pred_frame_dct       << 10) |
90
+                                       (s->concealment_motion_vectors <<  9) |
91
+                                       (s->q_scale_type               <<  8) |
92
+                                       (s->intra_vlc_format           <<  7) |
93
+                                       (s->alternate_scan             <<  6) |
94
+                                       (s->repeat_first_field         <<  5) |
95
+                                       (s->chroma_420_type            <<  4) |
96
+                                       (s->progressive_frame          <<  3);
97
+    pp->bBitstreamConcealmentNeed    = 0;
98
+    pp->bBitstreamConcealmentMethod  = 0;
99
+}
100
+
101
+static void fill_quantization_matrices(AVCodecContext *avctx,
102
+                                       struct dxva_context *ctx,
103
+                                       const struct MpegEncContext *s,
104
+                                       DXVA_QmatrixData *qm)
105
+{
106
+    int i;
107
+    for (i = 0; i < 4; i++)
108
+        qm->bNewQmatrix[i] = 1;
109
+    for (i = 0; i < 64; i++) {
110
+        int n = s->dsp.idct_permutation[ff_zigzag_direct[i]];
111
+        qm->Qmatrix[0][i] = s->intra_matrix[n];;
112
+        qm->Qmatrix[1][i] = s->inter_matrix[n];;
113
+        qm->Qmatrix[2][i] = s->chroma_intra_matrix[n];;
114
+        qm->Qmatrix[3][i] = s->chroma_inter_matrix[n];;
115
+    }
116
+}
117
+
118
+static void fill_slice(AVCodecContext *avctx,
119
+                       const struct MpegEncContext *s,
120
+                       DXVA_SliceInfo *slice,
121
+                       unsigned position,
122
+                       const uint8_t *buffer, unsigned size)
123
+{
124
+    int is_field = s->picture_structure != PICT_FRAME;
125
+    GetBitContext gb;
126
+
127
+    memset(slice, 0, sizeof(*slice));
128
+    slice->wHorizontalPosition = s->mb_x;
129
+    slice->wVerticalPosition   = s->mb_y >> is_field;
130
+    slice->dwSliceBitsInBuffer = 8 * size;
131
+    slice->dwSliceDataLocation = position;
132
+    slice->bStartCodeBitOffset = 0;
133
+    slice->bReservedBits       = 0;
134
+    /* XXX We store the index of the first MB and it will be fixed later */
135
+    slice->wNumberMBsInSlice   = (s->mb_y >> is_field) * s->mb_width + s->mb_x;
136
+    slice->wBadSliceChopping   = 0;
137
+
138
+    init_get_bits(&gb, &buffer[4], 8 * (size - 4));
139
+
140
+    slice->wQuantizerScaleCode = get_bits(&gb, 5);
141
+    while (get_bits1(&gb))
142
+        skip_bits(&gb, 8);
143
+
144
+    slice->wMBbitOffset        = 4 * 8 + get_bits_count(&gb);
145
+}
146
+static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx,
147
+                                             DXVA2_DecodeBufferDesc *bs,
148
+                                             DXVA2_DecodeBufferDesc *sc)
149
+{
150
+    const struct MpegEncContext *s = avctx->priv_data;
151
+    struct dxva_context *ctx = avctx->hwaccel_context;
152
+    struct dxva2_picture_context *ctx_pic =
153
+        s->current_picture_ptr->hwaccel_picture_private;
154
+    const int is_field = s->picture_structure != PICT_FRAME;
155
+    const unsigned mb_count = s->mb_width * (s->mb_height >> is_field);
156
+    uint8_t  *dxva_data, *current, *end;
157
+    unsigned dxva_size;
158
+    unsigned i;
159
+
160
+    if (FAILED(IDirectXVideoDecoder_GetBuffer(ctx->decoder,
161
+                                              DXVA2_BitStreamDateBufferType,
162
+                                              &dxva_data, &dxva_size)))
163
+        return -1;
164
+    current = dxva_data;
165
+    end = dxva_data + dxva_size;
166
+
167
+    for (i = 0; i < ctx_pic->slice_count; i++) {
168
+        DXVA_SliceInfo *slice = &ctx_pic->slice[i];
169
+        unsigned position = slice->dwSliceDataLocation;
170
+        unsigned size     = slice->dwSliceBitsInBuffer / 8;
171
+        if (size > end - current) {
172
+            av_log(avctx, AV_LOG_ERROR, "Failed to build bitstream");
173
+            break;
174
+        }
175
+        slice->dwSliceDataLocation = current - dxva_data;
176
+
177
+        if (i < ctx_pic->slice_count - 1)
178
+            slice->wNumberMBsInSlice =
179
+                slice[1].wNumberMBsInSlice - slice[0].wNumberMBsInSlice;
180
+        else
181
+            slice->wNumberMBsInSlice =
182
+                mb_count - slice[0].wNumberMBsInSlice;
183
+
184
+        memcpy(current, &ctx_pic->bitstream[position], size);
185
+        current += size;
186
+    }
187
+    if (FAILED(IDirectXVideoDecoder_ReleaseBuffer(ctx->decoder,
188
+                                                  DXVA2_BitStreamDateBufferType)))
189
+        return -1;
190
+    if (i < ctx_pic->slice_count)
191
+        return -1;
192
+
193
+    memset(bs, 0, sizeof(*bs));
194
+    bs->CompressedBufferType = DXVA2_BitStreamDateBufferType;
195
+    bs->DataSize             = current - dxva_data;
196
+    bs->NumMBsInBuffer       = mb_count;
197
+
198
+    return ff_dxva2_commit_buffer(avctx, ctx, sc,
199
+                                  DXVA2_SliceControlBufferType,
200
+                                  ctx_pic->slice,
201
+                                  ctx_pic->slice_count * sizeof(*ctx_pic->slice),
202
+                                  mb_count);
203
+}
204
+
205
+static int start_frame(AVCodecContext *avctx,
206
+                       av_unused const uint8_t *buffer,
207
+                       av_unused uint32_t size)
208
+{
209
+    const struct MpegEncContext *s = avctx->priv_data;
210
+    struct dxva_context *ctx = avctx->hwaccel_context;
211
+    struct dxva2_picture_context *ctx_pic =
212
+        s->current_picture_ptr->hwaccel_picture_private;
213
+
214
+    if (!ctx->decoder || !ctx->cfg || ctx->surface_count <= 0)
215
+        return -1;
216
+    assert(ctx_pic);
217
+
218
+    fill_picture_parameters(avctx, ctx, s, &ctx_pic->pp);
219
+    fill_quantization_matrices(avctx, ctx, s, &ctx_pic->qm);
220
+
221
+    ctx_pic->slice_count    = 0;
222
+    ctx_pic->bitstream_size = 0;
223
+    ctx_pic->bitstream      = NULL;
224
+    return 0;
225
+}
226
+
227
+static int decode_slice(AVCodecContext *avctx,
228
+                        const uint8_t *buffer, uint32_t size)
229
+{
230
+    const struct MpegEncContext *s = avctx->priv_data;
231
+    struct dxva2_picture_context *ctx_pic =
232
+        s->current_picture_ptr->hwaccel_picture_private;
233
+    unsigned position;
234
+
235
+    if (ctx_pic->slice_count >= MAX_SLICES)
236
+        return -1;
237
+
238
+    if (!ctx_pic->bitstream)
239
+        ctx_pic->bitstream = buffer;
240
+    ctx_pic->bitstream_size += size;
241
+
242
+    position = buffer - ctx_pic->bitstream;
243
+    fill_slice(avctx, s, &ctx_pic->slice[ctx_pic->slice_count++], position,
244
+               buffer, size);
245
+    return 0;
246
+}
247
+
248
+static int end_frame(AVCodecContext *avctx)
249
+{
250
+    struct MpegEncContext *s = avctx->priv_data;
251
+    struct dxva2_picture_context *ctx_pic =
252
+        s->current_picture_ptr->hwaccel_picture_private;
253
+
254
+    if (ctx_pic->slice_count <= 0 || ctx_pic->bitstream_size <= 0)
255
+        return -1;
256
+    return ff_dxva2_common_end_frame(avctx, s,
257
+                                     &ctx_pic->pp, sizeof(ctx_pic->pp),
258
+                                     &ctx_pic->qm, sizeof(ctx_pic->qm),
259
+                                     commit_bitstream_and_slice_buffer);
260
+}
261
+
262
+AVHWAccel mpeg2_dxva2_hwaccel = {
263
+    .name           = "mpeg2_dxva2",
264
+    .type           = AVMEDIA_TYPE_VIDEO,
265
+    .id             = CODEC_ID_MPEG2VIDEO,
266
+    .pix_fmt        = PIX_FMT_DXVA2_VLD,
267
+    .capabilities   = 0,
268
+    .start_frame    = start_frame,
269
+    .decode_slice   = decode_slice,
270
+    .end_frame      = end_frame,
271
+    .priv_data_size = sizeof(struct dxva2_picture_context),
272
+};
273
+