]> git.sesse.net Git - ffmpeg/blob - libavcodec/dxva2.c
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / libavcodec / dxva2.c
1 /*
2  * DXVA2 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 "libavutil/time.h"
25
26 void *ff_dxva2_get_surface(const Picture *picture)
27 {
28     return picture->f.data[3];
29 }
30
31 unsigned ff_dxva2_get_surface_index(const struct dxva_context *ctx,
32                                     const Picture *picture)
33 {
34     void *surface = ff_dxva2_get_surface(picture);
35     unsigned i;
36
37     for (i = 0; i < ctx->surface_count; i++)
38         if (ctx->surface[i] == surface)
39             return i;
40
41     assert(0);
42     return 0;
43 }
44
45 int ff_dxva2_commit_buffer(AVCodecContext *avctx,
46                            struct dxva_context *ctx,
47                            DXVA2_DecodeBufferDesc *dsc,
48                            unsigned type, const void *data, unsigned size,
49                            unsigned mb_count)
50 {
51     void     *dxva_data;
52     unsigned dxva_size;
53     int      result;
54     HRESULT hr;
55
56     hr = IDirectXVideoDecoder_GetBuffer(ctx->decoder, type,
57                                         &dxva_data, &dxva_size);
58     if (FAILED(hr)) {
59         av_log(avctx, AV_LOG_ERROR, "Failed to get a buffer for %d: 0x%x\n",
60                type, hr);
61         return -1;
62     }
63     if (size <= dxva_size) {
64         memcpy(dxva_data, data, size);
65
66         memset(dsc, 0, sizeof(*dsc));
67         dsc->CompressedBufferType = type;
68         dsc->DataSize             = size;
69         dsc->NumMBsInBuffer       = mb_count;
70
71         result = 0;
72     } else {
73         av_log(avctx, AV_LOG_ERROR, "Buffer for type %d was too small\n", type);
74         result = -1;
75     }
76
77     hr = IDirectXVideoDecoder_ReleaseBuffer(ctx->decoder, type);
78     if (FAILED(hr)) {
79         av_log(avctx, AV_LOG_ERROR,
80                "Failed to release buffer type %d: 0x%x\n",
81                type, hr);
82         result = -1;
83     }
84     return result;
85 }
86
87 int ff_dxva2_common_end_frame(AVCodecContext *avctx, Picture *pic,
88                               const void *pp, unsigned pp_size,
89                               const void *qm, unsigned qm_size,
90                               int (*commit_bs_si)(AVCodecContext *,
91                                                   DXVA2_DecodeBufferDesc *bs,
92                                                   DXVA2_DecodeBufferDesc *slice))
93 {
94     struct dxva_context *ctx = avctx->hwaccel_context;
95     unsigned               buffer_count = 0;
96     DXVA2_DecodeBufferDesc buffer[4];
97     DXVA2_DecodeExecuteParams exec = { 0 };
98     int result, runs = 0;
99     HRESULT hr;
100
101     do {
102         hr = IDirectXVideoDecoder_BeginFrame(ctx->decoder,
103                                              ff_dxva2_get_surface(pic),
104                                              NULL);
105         if (hr == E_PENDING)
106             av_usleep(2000);
107     } while (hr == E_PENDING && ++runs < 50);
108
109     if (FAILED(hr)) {
110         av_log(avctx, AV_LOG_ERROR, "Failed to begin frame: 0x%x\n", hr);
111         return -1;
112     }
113
114     result = ff_dxva2_commit_buffer(avctx, ctx, &buffer[buffer_count],
115                                     DXVA2_PictureParametersBufferType,
116                                     pp, pp_size, 0);
117     if (result) {
118         av_log(avctx, AV_LOG_ERROR,
119                "Failed to add picture parameter buffer\n");
120         goto end;
121     }
122     buffer_count++;
123
124     if (qm_size > 0) {
125         result = ff_dxva2_commit_buffer(avctx, ctx, &buffer[buffer_count],
126                                         DXVA2_InverseQuantizationMatrixBufferType,
127                                         qm, qm_size, 0);
128         if (result) {
129             av_log(avctx, AV_LOG_ERROR,
130                    "Failed to add inverse quantization matrix buffer\n");
131             goto end;
132         }
133         buffer_count++;
134     }
135
136     result = commit_bs_si(avctx,
137                           &buffer[buffer_count + 0],
138                           &buffer[buffer_count + 1]);
139     if (result) {
140         av_log(avctx, AV_LOG_ERROR,
141                "Failed to add bitstream or slice control buffer\n");
142         goto end;
143     }
144     buffer_count += 2;
145
146     /* TODO Film Grain when possible */
147
148     assert(buffer_count == 1 + (qm_size > 0) + 2);
149
150     exec.NumCompBuffers      = buffer_count;
151     exec.pCompressedBuffers  = buffer;
152     exec.pExtensionData      = NULL;
153     hr = IDirectXVideoDecoder_Execute(ctx->decoder, &exec);
154     if (FAILED(hr)) {
155         av_log(avctx, AV_LOG_ERROR, "Failed to execute: 0x%x\n", hr);
156         result = -1;
157     }
158
159 end:
160     hr = IDirectXVideoDecoder_EndFrame(ctx->decoder, NULL);
161     if (FAILED(hr)) {
162         av_log(avctx, AV_LOG_ERROR, "Failed to end frame: 0x%x\n", hr);
163         result = -1;
164     }
165
166     return result;
167 }