cosmetics: Fix spelling mistakes
[libav.git] / avconv_qsv.c
CommitLineData
fb472e1a
AK
1/*
2 * This file is part of Libav.
3 *
4 * Libav 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 * Libav 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 Libav; 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 "avconv.h"
28
29typedef 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
44static void buffer_release(void *opaque, uint8_t *data)
45{
46 *(uint8_t*)opaque = 0;
47}
48
49static 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
71static 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
100static 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
115int 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
151static 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
183int 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
264fail:
265 av_freep(&hwctx);
266 av_freep(&qsv);
267 return AVERROR_UNKNOWN;
268}