History

avconv: add support for Intel QSV-accelerated transcoding

Anton Khirnov committed 11 years ago

Commit fb472e11 parent dc923bc7 files · +307 −0Browse files

Unified · Split

7 files
  1. Changelog +1 −0
  2. Makefile +1 −0
  3. avconv.c +5 −0
  4. avconv.h +5 −0
  5. avconv_opt.c +3 −0
  6. avconv_qsv.c +268 −0
  7. doc/avconv.texi +24 −0
Changelog+1−0
@@ -44,6 +44,7 @@ version <next>: · 43 unmodified lines
4444 - Support DNx100 (1440x1080@8)
4545 - DXV decoding
4646 - Screenpresso SPV1 decoding
47+- zero-copy Intel QSV transcoding in avconv
4748
4849
4950 version 11:
Makefile+1−0
@@ -78,6 +78,7 @@ OBJS-avconv += avconv_opt.o avconv_filter.o · 77 unmodified lines
7878 OBJS-avconv-$(HAVE_VDPAU_X11) += avconv_vdpau.o
7979 OBJS-avconv-$(HAVE_DXVA2_LIB) += avconv_dxva2.o
8080 OBJS-avconv-$(CONFIG_VDA) += avconv_vda.o
81+OBJS-avconv-$(CONFIG_LIBMFX) += avconv_qsv.o
8182
8283 TESTTOOLS = audiogen videogen rotozoom tiny_psnr base64
8384 HOSTPROGS := $(TESTTOOLS:%=tests/%) doc/print_options
avconv.c+5−0
@@ -1852,6 +1852,11 @@ static int transcode_init(void) · 1851 unmodified lines
18521852 }
18531853 }
18541854
1855+#if CONFIG_LIBMFX
1856+ if (qsv_transcode_init(ost))
1857+ exit_program(1);
1858+#endif
1859+
18551860 if (!ost->filter &&
18561861 (enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
18571862 enc_ctx->codec_type == AVMEDIA_TYPE_AUDIO)) {
avconv.h+5−0
@@ -54,6 +54,7 @@ enum HWAccelID { · 53 unmodified lines
5454 HWACCEL_VDPAU,
5555 HWACCEL_DXVA2,
5656 HWACCEL_VDA,
57+ HWACCEL_QSV,
5758 };
5859
5960 typedef struct HWAccel {
@@ -331,6 +332,8 @@ typedef struct OutputStream { · 271 unmodified lines
331332 int64_t max_frames;
332333 AVFrame *filtered_frame;
333334
335+ void *hwaccel_ctx;
336+
334337 /* video only */
335338 AVRational frame_rate;
336339 int force_fps;
@@ -443,5 +446,7 @@ int avconv_parse_options(int argc, char **argv); · 106 unmodified lines
443446 int vdpau_init(AVCodecContext *s);
444447 int dxva2_init(AVCodecContext *s);
445448 int vda_init(AVCodecContext *s);
449+int qsv_init(AVCodecContext *s);
450+int qsv_transcode_init(OutputStream *ost);
446451
447452 #endif /* AVCONV_H */
avconv_opt.c+3−0
@@ -64,6 +64,9 @@ const HWAccel hwaccels[] = { · 63 unmodified lines
6464 #endif
6565 #if CONFIG_VDA
6666 { "vda", vda_init, HWACCEL_VDA, AV_PIX_FMT_VDA },
67+#endif
68+#if CONFIG_LIBMFX
69+ { "qsv", qsv_init, HWACCEL_QSV, AV_PIX_FMT_QSV },
6770 #endif
6871 { 0 },
6972 };
avconv_qsv.c+268−0
@@ -0,0 +1,268 @@
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+
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+}
doc/avconv.texi+24−0
@@ -602,6 +602,16 @@ Use VDPAU (Video Decode and Presentation API for Unix) hardware acceleration. · 601 unmodified lines
602602
603603 @item dxva2
604604 Use DXVA2 (DirectX Video Acceleration) hardware acceleration.
605+
606+@item qsv
607+Use the Intel QuickSync Video acceleration for video transcoding.
608+
609+Unlike most other values, this option does not enable accelerated decoding (that
610+is used automatically whenever a qsv decoder is selected), but accelerated
611+transcoding, without copying the frames into the system memory.
612+
613+For it to work, both the decoder and the encoder must support QSV acceleration
614+and no filters must be used.
605615 @end table
606616
607617 This option has no effect if the selected hwaccel is not available or not
@@ -628,6 +638,20 @@ is not specified, the value of the @var{DISPLAY} environment variable is used · 20 unmodified lines
628638 @item dxva2
629639 For DXVA2, this option should contain the number of the display adapter to use.
630640 If this option is not specified, the default adapter is used.
641+
642+@item qsv
643+For QSV, this option corresponds to the valus of MFX_IMPL_* . Allowed values
644+are:
645+@table @option
646+@item auto
647+@item sw
648+@item hw
649+@item auto_any
650+@item hw_any
651+@item hw2
652+@item hw3
653+@item hw4
654+@end table
631655 @end table
632656
633657 @item -hwaccels

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t