]> git.sesse.net Git - ffmpeg/blob - ffmpeg_qsv.c
Merge commit 'ac6d53589f3631ae08467c784fb371a15c957f01'
[ffmpeg] / ffmpeg_qsv.c
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18
19 #include <mfx/mfxvideo.h>
20 #include <stdlib.h>
21
22 #include "libavutil/dict.h"
23 #include "libavutil/mem.h"
24 #include "libavutil/opt.h"
25 #include "libavcodec/qsv.h"
26
27 #include "ffmpeg.h"
28
29 typedef struct QSVContext {
30     OutputStream *ost;
31
32     mfxSession session;
33
34     mfxExtOpaqueSurfaceAlloc opaque_alloc;
35     AVBufferRef             *opaque_surfaces_buf;
36
37     uint8_t           *surface_used;
38     mfxFrameSurface1 **surface_ptrs;
39     int nb_surfaces;
40
41     mfxExtBuffer *ext_buffers[1];
42 } QSVContext;
43
44 static void buffer_release(void *opaque, uint8_t *data)
45 {
46     *(uint8_t*)opaque = 0;
47 }
48
49 static int qsv_get_buffer(AVCodecContext *s, AVFrame *frame, int flags)
50 {
51     InputStream *ist = s->opaque;
52     QSVContext  *qsv = ist->hwaccel_ctx;
53     int i;
54
55     for (i = 0; i < qsv->nb_surfaces; i++) {
56         if (qsv->surface_used[i])
57             continue;
58
59         frame->buf[0] = av_buffer_create((uint8_t*)qsv->surface_ptrs[i], sizeof(*qsv->surface_ptrs[i]),
60                                          buffer_release, &qsv->surface_used[i], 0);
61         if (!frame->buf[0])
62             return AVERROR(ENOMEM);
63         frame->data[3]       = (uint8_t*)qsv->surface_ptrs[i];
64         qsv->surface_used[i] = 1;
65         return 0;
66     }
67
68     return AVERROR(ENOMEM);
69 }
70
71 static int init_opaque_surf(QSVContext *qsv)
72 {
73     AVQSVContext *hwctx_enc = qsv->ost->enc_ctx->hwaccel_context;
74     mfxFrameSurface1 *surfaces;
75     int i;
76
77     qsv->nb_surfaces = hwctx_enc->nb_opaque_surfaces;
78
79     qsv->opaque_surfaces_buf = av_buffer_ref(hwctx_enc->opaque_surfaces);
80     qsv->surface_ptrs        = av_mallocz_array(qsv->nb_surfaces, sizeof(*qsv->surface_ptrs));
81     qsv->surface_used        = av_mallocz_array(qsv->nb_surfaces, sizeof(*qsv->surface_used));
82     if (!qsv->opaque_surfaces_buf || !qsv->surface_ptrs || !qsv->surface_used)
83         return AVERROR(ENOMEM);
84
85     surfaces = (mfxFrameSurface1*)qsv->opaque_surfaces_buf->data;
86     for (i = 0; i < qsv->nb_surfaces; i++)
87         qsv->surface_ptrs[i] = surfaces + i;
88
89     qsv->opaque_alloc.Out.Surfaces   = qsv->surface_ptrs;
90     qsv->opaque_alloc.Out.NumSurface = qsv->nb_surfaces;
91     qsv->opaque_alloc.Out.Type       = hwctx_enc->opaque_alloc_type;
92
93     qsv->opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION;
94     qsv->opaque_alloc.Header.BufferSz = sizeof(qsv->opaque_alloc);
95     qsv->ext_buffers[0]               = (mfxExtBuffer*)&qsv->opaque_alloc;
96
97     return 0;
98 }
99
100 static void qsv_uninit(AVCodecContext *s)
101 {
102     InputStream *ist = s->opaque;
103     QSVContext  *qsv = ist->hwaccel_ctx;
104
105     av_freep(&qsv->ost->enc_ctx->hwaccel_context);
106     av_freep(&s->hwaccel_context);
107
108     av_buffer_unref(&qsv->opaque_surfaces_buf);
109     av_freep(&qsv->surface_used);
110     av_freep(&qsv->surface_ptrs);
111
112     av_freep(&qsv);
113 }
114
115 int qsv_init(AVCodecContext *s)
116 {
117     InputStream *ist = s->opaque;
118     QSVContext  *qsv = ist->hwaccel_ctx;
119     AVQSVContext *hwctx_dec;
120     int ret;
121
122     if (!qsv) {
123         av_log(NULL, AV_LOG_ERROR, "QSV transcoding is not initialized. "
124                "-hwaccel qsv should only be used for one-to-one QSV transcoding "
125                "with no filters.\n");
126         return AVERROR_BUG;
127     }
128
129     ret = init_opaque_surf(qsv);
130     if (ret < 0)
131         return ret;
132
133     hwctx_dec = av_qsv_alloc_context();
134     if (!hwctx_dec)
135         return AVERROR(ENOMEM);
136
137     hwctx_dec->session        = qsv->session;
138     hwctx_dec->iopattern      = MFX_IOPATTERN_OUT_OPAQUE_MEMORY;
139     hwctx_dec->ext_buffers    = qsv->ext_buffers;
140     hwctx_dec->nb_ext_buffers = FF_ARRAY_ELEMS(qsv->ext_buffers);
141
142     av_freep(&s->hwaccel_context);
143     s->hwaccel_context = hwctx_dec;
144
145     ist->hwaccel_get_buffer = qsv_get_buffer;
146     ist->hwaccel_uninit     = qsv_uninit;
147
148     return 0;
149 }
150
151 static mfxIMPL choose_implementation(const InputStream *ist)
152 {
153     static const struct {
154         const char *name;
155         mfxIMPL     impl;
156     } impl_map[] = {
157         { "auto",     MFX_IMPL_AUTO         },
158         { "sw",       MFX_IMPL_SOFTWARE     },
159         { "hw",       MFX_IMPL_HARDWARE     },
160         { "auto_any", MFX_IMPL_AUTO_ANY     },
161         { "hw_any",   MFX_IMPL_HARDWARE_ANY },
162         { "hw2",      MFX_IMPL_HARDWARE2    },
163         { "hw3",      MFX_IMPL_HARDWARE3    },
164         { "hw4",      MFX_IMPL_HARDWARE4    },
165     };
166
167     mfxIMPL impl = MFX_IMPL_AUTO_ANY;
168     int i;
169
170     if (ist->hwaccel_device) {
171         for (i = 0; i < FF_ARRAY_ELEMS(impl_map); i++)
172             if (!strcmp(ist->hwaccel_device, impl_map[i].name)) {
173                 impl = impl_map[i].impl;
174                 break;
175             }
176         if (i == FF_ARRAY_ELEMS(impl_map))
177             impl = strtol(ist->hwaccel_device, NULL, 0);
178     }
179
180     return impl;
181 }
182
183 int qsv_transcode_init(OutputStream *ost)
184 {
185     InputStream *ist;
186     const enum AVPixelFormat *pix_fmt;
187
188     AVDictionaryEntry *e;
189     const AVOption *opt;
190     int flags = 0;
191
192     int err, i;
193
194     QSVContext *qsv = NULL;
195     AVQSVContext *hwctx = NULL;
196     mfxIMPL impl;
197     mfxVersion ver = { { 3, 1 } };
198
199     /* check if the encoder supports QSV */
200     if (!ost->enc->pix_fmts)
201         return 0;
202     for (pix_fmt = ost->enc->pix_fmts; *pix_fmt != AV_PIX_FMT_NONE; pix_fmt++)
203         if (*pix_fmt == AV_PIX_FMT_QSV)
204             break;
205     if (*pix_fmt == AV_PIX_FMT_NONE)
206         return 0;
207
208     if (strcmp(ost->avfilter, "null") || ost->source_index < 0)
209         return 0;
210
211     /* check if the decoder supports QSV and the output only goes to this stream */
212     ist = input_streams[ost->source_index];
213     if (ist->nb_filters || ist->hwaccel_id != HWACCEL_QSV ||
214         !ist->dec || !ist->dec->pix_fmts)
215         return 0;
216     for (pix_fmt = ist->dec->pix_fmts; *pix_fmt != AV_PIX_FMT_NONE; pix_fmt++)
217         if (*pix_fmt == AV_PIX_FMT_QSV)
218             break;
219     if (*pix_fmt == AV_PIX_FMT_NONE)
220         return 0;
221
222     for (i = 0; i < nb_output_streams; i++)
223         if (output_streams[i] != ost &&
224             output_streams[i]->source_index == ost->source_index)
225             return 0;
226
227     av_log(NULL, AV_LOG_VERBOSE, "Setting up QSV transcoding\n");
228
229     qsv   = av_mallocz(sizeof(*qsv));
230     hwctx = av_qsv_alloc_context();
231     if (!qsv || !hwctx)
232         goto fail;
233
234     impl = choose_implementation(ist);
235
236     err = MFXInit(impl, &ver, &qsv->session);
237     if (err != MFX_ERR_NONE) {
238         av_log(NULL, AV_LOG_ERROR, "Error initializing an MFX session: %d\n", err);
239         goto fail;
240     }
241
242     e = av_dict_get(ost->encoder_opts, "flags", NULL, 0);
243     opt = av_opt_find(ost->enc_ctx, "flags", NULL, 0, 0);
244     if (e && opt)
245         av_opt_eval_flags(ost->enc_ctx, opt, e->value, &flags);
246
247     qsv->ost = ost;
248
249     hwctx->session                = qsv->session;
250     hwctx->iopattern              = MFX_IOPATTERN_IN_OPAQUE_MEMORY;
251     hwctx->opaque_alloc           = 1;
252     hwctx->nb_opaque_surfaces     = 16;
253
254     ost->hwaccel_ctx              = qsv;
255     ost->enc_ctx->hwaccel_context = hwctx;
256     ost->enc_ctx->pix_fmt         = AV_PIX_FMT_QSV;
257
258     ist->hwaccel_ctx              = qsv;
259     ist->dec_ctx->pix_fmt         = AV_PIX_FMT_QSV;
260     ist->resample_pix_fmt         = AV_PIX_FMT_QSV;
261
262     return 0;
263
264 fail:
265     av_freep(&hwctx);
266     av_freep(&qsv);
267     return AVERROR_UNKNOWN;
268 }