Browse code

lavc: add an Intel libmfx-based H.264 decoder

Based on the code by Luca Barbato <lu_zero@gentoo.org> and Yukinori
Yamazoe <drocon11@gmail.com>.

Anton Khirnov authored on 2015/02/10 18:40:59
Showing 10 changed files
... ...
@@ -14,6 +14,7 @@ version <next>:
14 14
 - Support DNx100 (960x720@8)
15 15
 - DXVA2-accelerated HEVC decoding
16 16
 - AAC ELD 480 decoding
17
+- Intel QSV-accelerated H.264 decoding
17 18
 
18 19
 
19 20
 version 11:
... ...
@@ -189,6 +189,7 @@ External library support:
189 189
   --enable-libfreetype     enable libfreetype [no]
190 190
   --enable-libgsm          enable GSM de/encoding via libgsm [no]
191 191
   --enable-libilbc         enable iLBC de/encoding via libilbc [no]
192
+  --enable-libmfx          enable HW acceleration through libmfx
192 193
   --enable-libmp3lame      enable MP3 encoding via libmp3lame [no]
193 194
   --enable-libopencore-amrnb enable AMR-NB de/encoding via libopencore-amrnb [no]
194 195
   --enable-libopencore-amrwb enable AMR-WB decoding via libopencore-amrwb [no]
... ...
@@ -1153,6 +1154,7 @@ EXTERNAL_LIBRARY_LIST="
1153 1153
     libfreetype
1154 1154
     libgsm
1155 1155
     libilbc
1156
+    libmfx
1156 1157
     libmp3lame
1157 1158
     libopencore_amrnb
1158 1159
     libopencore_amrwb
... ...
@@ -1235,6 +1237,7 @@ SUBSYSTEM_LIST="
1235 1235
     lzo
1236 1236
     mdct
1237 1237
     network
1238
+    qsv
1238 1239
     rdft
1239 1240
 "
1240 1241
 
... ...
@@ -1820,6 +1823,8 @@ h263i_decoder_select="h263_decoder"
1820 1820
 h263p_encoder_select="h263_encoder"
1821 1821
 h264_decoder_select="cabac golomb h264chroma h264dsp h264pred h264qpel startcode videodsp"
1822 1822
 h264_decoder_suggest="error_resilience"
1823
+h264_qsv_decoder_deps="libmfx"
1824
+h264_qsv_decoder_select="h264_mp4toannexb_bsf h264_parser qsv h264_qsv_hwaccel"
1823 1825
 hevc_decoder_select="bswapdsp cabac golomb videodsp"
1824 1826
 huffyuv_decoder_select="bswapdsp huffyuvdsp"
1825 1827
 huffyuv_encoder_select="bswapdsp huffman huffyuvencdsp"
... ...
@@ -4195,6 +4200,7 @@ enabled libgsm            && { for gsm_hdr in "gsm.h" "gsm/gsm.h"; do
4195 4195
                                    check_lib "${gsm_hdr}" gsm_create -lgsm && break;
4196 4196
                                done || die "ERROR: libgsm not found"; }
4197 4197
 enabled libilbc           && require libilbc ilbc.h WebRtcIlbcfix_InitDecode -lilbc
4198
+enabled libmfx            && require_pkg_config libmfx "mfx/mfxvideo.h" MFXInit
4198 4199
 enabled libmp3lame        && require "libmp3lame >= 3.98.3" lame/lame.h lame_set_VBR_quality -lmp3lame
4199 4200
 enabled libopencore_amrnb && require libopencore_amrnb opencore-amrnb/interf_dec.h Decoder_Interface_init -lopencore-amrnb
4200 4201
 enabled libopencore_amrwb && require libopencore_amrwb opencore-amrwb/dec_if.h D_IF_init -lopencore-amrwb
... ...
@@ -4,6 +4,7 @@ HEADERS = avcodec.h                                                     \
4 4
           avfft.h                                                       \
5 5
           dv_profile.h                                                  \
6 6
           dxva2.h                                                       \
7
+          qsv.h                                                         \
7 8
           vaapi.h                                                       \
8 9
           vda.h                                                         \
9 10
           vdpau.h                                                       \
... ...
@@ -24,6 +25,7 @@ OBJS = allcodecs.o                                                      \
24 24
        mathtables.o                                                     \
25 25
        options.o                                                        \
26 26
        parser.o                                                         \
27
+       qsv_api.o                                                        \
27 28
        raw.o                                                            \
28 29
        utils.o                                                          \
29 30
        vorbis_parser.o                                                  \
... ...
@@ -78,6 +80,7 @@ OBJS-$(CONFIG_MPEGVIDEOENC)            += mpegvideo_enc.o mpeg12data.o  \
78 78
                                           mpegvideoencdsp.o
79 79
 OBJS-$(CONFIG_PIXBLOCKDSP)             += pixblockdsp.o
80 80
 OBJS-$(CONFIG_QPELDSP)                 += qpeldsp.o
81
+OBJS-$(CONFIG_QSV)                     += qsv.o
81 82
 OBJS-$(CONFIG_RANGECODER)              += rangecoder.o
82 83
 RDFT-OBJS-$(CONFIG_HARDCODED_TABLES)   += sin_tables.o
83 84
 OBJS-$(CONFIG_RDFT)                    += rdft.o $(RDFT-OBJS-yes)
... ...
@@ -218,6 +221,7 @@ OBJS-$(CONFIG_H264_DECODER)            += h264.o h264_cabac.o h264_cavlc.o \
218 218
                                           h264_direct.o h264_loopfilter.o  \
219 219
                                           h264_mb.o h264_picture.o h264_ps.o \
220 220
                                           h264_refs.o h264_sei.o h264_slice.o
221
+OBJS-$(CONFIG_H264_QSV_DECODER)        += qsv_h264.o
221 222
 OBJS-$(CONFIG_HEVC_DECODER)            += hevc.o hevc_mvs.o hevc_ps.o hevc_sei.o \
222 223
                                           hevc_cabac.o hevc_refs.o hevcpred.o    \
223 224
                                           hevcdsp.o hevc_filter.o
... ...
@@ -712,6 +716,7 @@ SKIPHEADERS                            += %_tablegen.h                  \
712 712
 SKIPHEADERS-$(CONFIG_DXVA2)            += dxva2.h dxva2_internal.h
713 713
 SKIPHEADERS-$(CONFIG_LIBSCHROEDINGER)  += libschroedinger.h
714 714
 SKIPHEADERS-$(CONFIG_MPEG_XVMC_DECODER) += xvmc.h
715
+SKIPHEADERS-$(CONFIG_QSV)              += qsv_internal.h
715 716
 SKIPHEADERS-$(CONFIG_VAAPI)            += vaapi_internal.h
716 717
 SKIPHEADERS-$(CONFIG_VDA)              += vda.h vda_internal.h
717 718
 SKIPHEADERS-$(CONFIG_VDPAU)            += vdpau.h vdpau_internal.h
... ...
@@ -77,6 +77,7 @@ void avcodec_register_all(void)
77 77
     REGISTER_HWACCEL(H263_VAAPI,        h263_vaapi);
78 78
     REGISTER_HWACCEL(H263_VDPAU,        h263_vdpau);
79 79
     REGISTER_HWACCEL(H264_DXVA2,        h264_dxva2);
80
+    REGISTER_HWACCEL(H264_QSV,          h264_qsv);
80 81
     REGISTER_HWACCEL(H264_VAAPI,        h264_vaapi);
81 82
     REGISTER_HWACCEL(H264_VDA,          h264_vda);
82 83
     REGISTER_HWACCEL(H264_VDA_OLD,      h264_vda_old);
... ...
@@ -160,6 +161,7 @@ void avcodec_register_all(void)
160 160
     REGISTER_DECODER(H263I,             h263i);
161 161
     REGISTER_ENCODER(H263P,             h263p);
162 162
     REGISTER_DECODER(H264,              h264);
163
+    REGISTER_DECODER(H264_QSV,          h264_qsv);
163 164
     REGISTER_DECODER(HEVC,              hevc);
164 165
     REGISTER_DECODER(HNM4_VIDEO,        hnm4_video);
165 166
     REGISTER_ENCDEC (HUFFYUV,           huffyuv);
166 167
new file mode 100644
... ...
@@ -0,0 +1,362 @@
0
+/*
1
+ * Intel MediaSDK QSV codec-independent code
2
+ *
3
+ * copyright (c) 2013 Luca Barbato
4
+ * copyright (c) 2015 Anton Khirnov <anton@khirnov.net>
5
+ *
6
+ * This file is part of Libav.
7
+ *
8
+ * Libav 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
+ * Libav 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 Libav; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
+ */
22
+
23
+#include <string.h>
24
+#include <sys/types.h>
25
+
26
+#include <mfx/mfxvideo.h>
27
+
28
+#include "libavutil/common.h"
29
+#include "libavutil/mem.h"
30
+#include "libavutil/log.h"
31
+#include "libavutil/pixfmt.h"
32
+#include "libavutil/time.h"
33
+
34
+#include "avcodec.h"
35
+#include "internal.h"
36
+#include "qsv_internal.h"
37
+
38
+int ff_qsv_error(int mfx_err)
39
+{
40
+    switch (mfx_err) {
41
+    case MFX_ERR_NONE:
42
+        return 0;
43
+    case MFX_ERR_MEMORY_ALLOC:
44
+    case MFX_ERR_NOT_ENOUGH_BUFFER:
45
+        return AVERROR(ENOMEM);
46
+    case MFX_ERR_INVALID_HANDLE:
47
+        return AVERROR(EINVAL);
48
+    case MFX_ERR_DEVICE_FAILED:
49
+    case MFX_ERR_DEVICE_LOST:
50
+    case MFX_ERR_LOCK_MEMORY:
51
+        return AVERROR(EIO);
52
+    case MFX_ERR_NULL_PTR:
53
+    case MFX_ERR_UNDEFINED_BEHAVIOR:
54
+    case MFX_ERR_NOT_INITIALIZED:
55
+        return AVERROR_BUG;
56
+    case MFX_ERR_UNSUPPORTED:
57
+    case MFX_ERR_NOT_FOUND:
58
+        return AVERROR(ENOSYS);
59
+    case MFX_ERR_MORE_DATA:
60
+    case MFX_ERR_MORE_SURFACE:
61
+    case MFX_ERR_MORE_BITSTREAM:
62
+        return AVERROR(EAGAIN);
63
+    case MFX_ERR_INCOMPATIBLE_VIDEO_PARAM:
64
+    case MFX_ERR_INVALID_VIDEO_PARAM:
65
+        return AVERROR(EINVAL);
66
+    case MFX_ERR_ABORTED:
67
+    case MFX_ERR_UNKNOWN:
68
+    default:
69
+        return AVERROR_UNKNOWN;
70
+    }
71
+}
72
+
73
+int ff_qsv_map_pixfmt(enum AVPixelFormat format)
74
+{
75
+    switch (format) {
76
+    case AV_PIX_FMT_YUV420P:
77
+    case AV_PIX_FMT_YUVJ420P:
78
+        return AV_PIX_FMT_NV12;
79
+    default:
80
+        return AVERROR(ENOSYS);
81
+    }
82
+}
83
+
84
+static int codec_id_to_mfx(enum AVCodecID codec_id)
85
+{
86
+    switch (codec_id) {
87
+    case AV_CODEC_ID_H264:
88
+        return MFX_CODEC_AVC;
89
+    case AV_CODEC_ID_MPEG1VIDEO:
90
+    case AV_CODEC_ID_MPEG2VIDEO:
91
+        return MFX_CODEC_MPEG2;
92
+    case AV_CODEC_ID_VC1:
93
+        return MFX_CODEC_VC1;
94
+    default:
95
+        break;
96
+    }
97
+
98
+    return AVERROR(ENOSYS);
99
+}
100
+
101
+static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession session)
102
+{
103
+    if (!session) {
104
+        if (!q->internal_session) {
105
+            mfxIMPL impl   = MFX_IMPL_AUTO_ANY;
106
+            mfxVersion ver = { { QSV_VERSION_MINOR, QSV_VERSION_MAJOR } };
107
+
108
+            const char *desc;
109
+            int ret;
110
+
111
+            ret = MFXInit(impl, &ver, &q->internal_session);
112
+            if (ret < 0) {
113
+                av_log(avctx, AV_LOG_ERROR, "Error initializing an internal MFX session\n");
114
+                return ff_qsv_error(ret);
115
+            }
116
+
117
+            MFXQueryIMPL(q->internal_session, &impl);
118
+
119
+            if (impl & MFX_IMPL_SOFTWARE)
120
+                desc = "software";
121
+            else if (impl & MFX_IMPL_HARDWARE)
122
+                desc = "hardware accelerated";
123
+            else
124
+                desc = "unknown";
125
+
126
+            av_log(avctx, AV_LOG_VERBOSE,
127
+                   "Initialized an internal MFX session using %s implementation\n",
128
+                   desc);
129
+        }
130
+
131
+        q->session = q->internal_session;
132
+    } else {
133
+        q->session = session;
134
+    }
135
+
136
+    /* make sure the decoder is uninitialized */
137
+    MFXVideoDECODE_Close(q->session);
138
+
139
+    return 0;
140
+}
141
+
142
+int ff_qsv_init(AVCodecContext *avctx, QSVContext *q, mfxSession session)
143
+{
144
+    mfxVideoParam param = { { 0 } };
145
+    int ret;
146
+
147
+    ret = qsv_init_session(avctx, q, session);
148
+    if (ret < 0) {
149
+        av_log(avctx, AV_LOG_ERROR, "Error initializing an MFX session\n");
150
+        return ret;
151
+    }
152
+
153
+
154
+    ret = codec_id_to_mfx(avctx->codec_id);
155
+    if (ret < 0)
156
+        return ret;
157
+
158
+    param.mfx.CodecId      = ret;
159
+    param.mfx.CodecProfile = avctx->profile;
160
+    param.mfx.CodecLevel   = avctx->level;
161
+
162
+    param.mfx.FrameInfo.BitDepthLuma   = 8;
163
+    param.mfx.FrameInfo.BitDepthChroma = 8;
164
+    param.mfx.FrameInfo.Shift          = 0;
165
+    param.mfx.FrameInfo.FourCC         = MFX_FOURCC_NV12;
166
+    param.mfx.FrameInfo.Width          = avctx->coded_width;
167
+    param.mfx.FrameInfo.Height         = avctx->coded_height;
168
+    param.mfx.FrameInfo.ChromaFormat   = MFX_CHROMAFORMAT_YUV420;
169
+
170
+    param.IOPattern   = q->iopattern;
171
+    param.AsyncDepth  = q->async_depth;
172
+    param.ExtParam    = q->ext_buffers;
173
+    param.NumExtParam = q->nb_ext_buffers;
174
+
175
+    ret = MFXVideoDECODE_Init(q->session, &param);
176
+    if (ret < 0) {
177
+        av_log(avctx, AV_LOG_ERROR, "Error initializing the MFX video decoder\n");
178
+        return ff_qsv_error(ret);
179
+    }
180
+
181
+    return 0;
182
+}
183
+
184
+static int alloc_frame(AVCodecContext *avctx, QSVFrame *frame)
185
+{
186
+    int ret;
187
+
188
+    ret = ff_get_buffer(avctx, frame->frame, AV_GET_BUFFER_FLAG_REF);
189
+    if (ret < 0)
190
+        return ret;
191
+
192
+    if (frame->frame->format == AV_PIX_FMT_QSV) {
193
+        frame->surface = (mfxFrameSurface1*)frame->frame->data[3];
194
+    } else {
195
+        frame->surface_internal.Info.BitDepthLuma   = 8;
196
+        frame->surface_internal.Info.BitDepthChroma = 8;
197
+        frame->surface_internal.Info.FourCC         = MFX_FOURCC_NV12;
198
+        frame->surface_internal.Info.Width          = avctx->coded_width;
199
+        frame->surface_internal.Info.Height         = avctx->coded_height;
200
+        frame->surface_internal.Info.ChromaFormat   = MFX_CHROMAFORMAT_YUV420;
201
+
202
+        frame->surface_internal.Data.PitchLow = frame->frame->linesize[0];
203
+        frame->surface_internal.Data.Y        = frame->frame->data[0];
204
+        frame->surface_internal.Data.UV       = frame->frame->data[1];
205
+
206
+        frame->surface = &frame->surface_internal;
207
+    }
208
+
209
+    return 0;
210
+}
211
+
212
+static void qsv_clear_unused_frames(QSVContext *q)
213
+{
214
+    QSVFrame *cur = q->work_frames;
215
+    while (cur) {
216
+        if (cur->surface && !cur->surface->Data.Locked) {
217
+            cur->surface = NULL;
218
+            av_frame_unref(cur->frame);
219
+        }
220
+        cur = cur->next;
221
+    }
222
+}
223
+
224
+static int get_surface(AVCodecContext *avctx, QSVContext *q, mfxFrameSurface1 **surf)
225
+{
226
+    QSVFrame *frame, **last;
227
+    int ret;
228
+
229
+    qsv_clear_unused_frames(q);
230
+
231
+    frame = q->work_frames;
232
+    last  = &q->work_frames;
233
+    while (frame) {
234
+        if (!frame->surface) {
235
+            ret = alloc_frame(avctx, frame);
236
+            if (ret < 0)
237
+                return ret;
238
+            *surf = frame->surface;
239
+            return 0;
240
+        }
241
+
242
+        last  = &frame->next;
243
+        frame = frame->next;
244
+    }
245
+
246
+    frame = av_mallocz(sizeof(*frame));
247
+    if (!frame)
248
+        return AVERROR(ENOMEM);
249
+    frame->frame = av_frame_alloc();
250
+    if (!frame->frame) {
251
+        av_freep(&frame);
252
+        return AVERROR(ENOMEM);
253
+    }
254
+    *last = frame;
255
+
256
+    ret = alloc_frame(avctx, frame);
257
+    if (ret < 0)
258
+        return ret;
259
+
260
+    *surf = frame->surface;
261
+
262
+    return 0;
263
+}
264
+
265
+static AVFrame *find_frame(QSVContext *q, mfxFrameSurface1 *surf)
266
+{
267
+    QSVFrame *cur = q->work_frames;
268
+    while (cur) {
269
+        if (surf == cur->surface)
270
+            return cur->frame;
271
+        cur = cur->next;
272
+    }
273
+    return NULL;
274
+}
275
+
276
+int ff_qsv_decode(AVCodecContext *avctx, QSVContext *q,
277
+                  AVFrame *frame, int *got_frame,
278
+                  AVPacket *avpkt)
279
+{
280
+    mfxFrameSurface1 *insurf;
281
+    mfxFrameSurface1 *outsurf;
282
+    mfxSyncPoint sync;
283
+    mfxBitstream bs = { { { 0 } } };
284
+    int ret;
285
+
286
+    if (avpkt->size) {
287
+        bs.Data       = avpkt->data;
288
+        bs.DataLength = avpkt->size;
289
+        bs.MaxLength  = bs.DataLength;
290
+        bs.TimeStamp  = avpkt->pts;
291
+    }
292
+
293
+    do {
294
+        ret = get_surface(avctx, q, &insurf);
295
+        if (ret < 0)
296
+            return ret;
297
+
298
+        ret = MFXVideoDECODE_DecodeFrameAsync(q->session, avpkt->size ? &bs : NULL,
299
+                                              insurf, &outsurf, &sync);
300
+        if (ret == MFX_WRN_DEVICE_BUSY)
301
+            av_usleep(1);
302
+
303
+    } while (ret == MFX_WRN_DEVICE_BUSY || ret == MFX_ERR_MORE_SURFACE);
304
+
305
+    if (ret != MFX_ERR_NONE &&
306
+        ret != MFX_ERR_MORE_DATA &&
307
+        ret != MFX_WRN_VIDEO_PARAM_CHANGED &&
308
+        ret != MFX_ERR_MORE_SURFACE) {
309
+        av_log(avctx, AV_LOG_ERROR, "Error during QSV decoding.\n");
310
+        return ff_qsv_error(ret);
311
+    }
312
+
313
+    if (sync) {
314
+        AVFrame *src_frame;
315
+
316
+        MFXVideoCORE_SyncOperation(q->session, sync, 60000);
317
+
318
+        src_frame = find_frame(q, outsurf);
319
+        if (!src_frame) {
320
+            av_log(avctx, AV_LOG_ERROR,
321
+                   "The returned surface does not correspond to any frame\n");
322
+            return AVERROR_BUG;
323
+        }
324
+
325
+        ret = av_frame_ref(frame, src_frame);
326
+        if (ret < 0)
327
+            return ret;
328
+
329
+        frame->pkt_pts = frame->pts = outsurf->Data.TimeStamp;
330
+
331
+        frame->repeat_pict =
332
+            outsurf->Info.PicStruct & MFX_PICSTRUCT_FRAME_TRIPLING ? 4 :
333
+            outsurf->Info.PicStruct & MFX_PICSTRUCT_FRAME_DOUBLING ? 2 :
334
+            outsurf->Info.PicStruct & MFX_PICSTRUCT_FIELD_REPEATED ? 1 : 0;
335
+        frame->top_field_first =
336
+            outsurf->Info.PicStruct & MFX_PICSTRUCT_FIELD_TFF;
337
+        frame->interlaced_frame =
338
+            !(outsurf->Info.PicStruct & MFX_PICSTRUCT_PROGRESSIVE);
339
+
340
+        *got_frame = 1;
341
+    }
342
+
343
+    return bs.DataOffset;
344
+}
345
+
346
+int ff_qsv_close(QSVContext *q)
347
+{
348
+    QSVFrame *cur = q->work_frames;
349
+
350
+    while (cur) {
351
+        q->work_frames = cur->next;
352
+        av_frame_free(&cur->frame);
353
+        av_freep(&cur);
354
+        cur = q->work_frames;
355
+    }
356
+
357
+    if (q->internal_session)
358
+        MFXClose(q->internal_session);
359
+
360
+    return 0;
361
+}
0 362
new file mode 100644
... ...
@@ -0,0 +1,41 @@
0
+/*
1
+ * Intel MediaSDK QSV public API
2
+ *
3
+ * This file is part of Libav.
4
+ *
5
+ * Libav is free software; you can redistribute it and/or
6
+ * modify it under the terms of the GNU Lesser General Public
7
+ * License as published by the Free Software Foundation; either
8
+ * version 2.1 of the License, or (at your option) any later version.
9
+ *
10
+ * Libav is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Lesser General Public
16
+ * License along with Libav; if not, write to the Free Software
17
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+ */
19
+
20
+#ifndef AVCODEC_QSV_H
21
+#define AVCODEC_QSV_H
22
+
23
+#include <mfx/mfxvideo.h>
24
+
25
+typedef struct AVQSVContext {
26
+    mfxSession session;
27
+    int iopattern;
28
+
29
+    mfxExtBuffer **ext_buffers;
30
+    int         nb_ext_buffers;
31
+} AVQSVContext;
32
+
33
+/**
34
+ * Allocate a new context.
35
+ *
36
+ * It must be freed by the caller with av_free().
37
+ */
38
+AVQSVContext *av_qsv_alloc_context(void);
39
+
40
+#endif /* AVCODEC_QSV_H */
0 41
new file mode 100644
... ...
@@ -0,0 +1,28 @@
0
+/*
1
+ * Intel MediaSDK QSV public API functions
2
+ *
3
+ * This file is part of Libav.
4
+ *
5
+ * Libav is free software; you can redistribute it and/or
6
+ * modify it under the terms of the GNU Lesser General Public
7
+ * License as published by the Free Software Foundation; either
8
+ * version 2.1 of the License, or (at your option) any later version.
9
+ *
10
+ * Libav is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Lesser General Public
16
+ * License along with Libav; if not, write to the Free Software
17
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+ */
19
+
20
+#include "libavutil/mem.h"
21
+
22
+#include "qsv.h"
23
+
24
+AVQSVContext *av_qsv_alloc_context(void)
25
+{
26
+    return av_mallocz(sizeof(AVQSVContext));
27
+}
0 28
new file mode 100644
... ...
@@ -0,0 +1,313 @@
0
+/*
1
+ * Intel MediaSDK QSV based H.264 decoder
2
+ *
3
+ * copyright (c) 2013 Luca Barbato
4
+ * copyright (c) 2015 Anton Khirnov
5
+ *
6
+ * This file is part of Libav.
7
+ *
8
+ * Libav 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
+ * Libav 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 Libav; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
+ */
22
+
23
+
24
+#include <stdint.h>
25
+#include <string.h>
26
+
27
+#include <mfx/mfxvideo.h>
28
+
29
+#include "libavutil/common.h"
30
+#include "libavutil/fifo.h"
31
+#include "libavutil/opt.h"
32
+
33
+#include "avcodec.h"
34
+#include "internal.h"
35
+#include "qsv_internal.h"
36
+#include "qsv.h"
37
+
38
+typedef struct QSVH264Context {
39
+    AVClass *class;
40
+    QSVContext qsv;
41
+
42
+    // the internal parser and codec context for parsing the data
43
+    AVCodecParserContext *parser;
44
+    AVCodecContext *avctx_internal;
45
+    enum AVPixelFormat orig_pix_fmt;
46
+
47
+    // the filter for converting to Annex B
48
+    AVBitStreamFilterContext *bsf;
49
+
50
+    AVFifoBuffer *packet_fifo;
51
+
52
+    AVPacket input_ref;
53
+    AVPacket pkt_filtered;
54
+    uint8_t *filtered_data;
55
+} QSVH264Context;
56
+
57
+static void qsv_clear_buffers(QSVH264Context *s)
58
+{
59
+    AVPacket pkt;
60
+    while (av_fifo_size(s->packet_fifo) >= sizeof(pkt)) {
61
+        av_fifo_generic_read(s->packet_fifo, &pkt, sizeof(pkt), NULL);
62
+        av_packet_unref(&pkt);
63
+    }
64
+
65
+    if (s->filtered_data != s->input_ref.data)
66
+        av_freep(&s->filtered_data);
67
+    s->filtered_data = NULL;
68
+    av_packet_unref(&s->input_ref);
69
+}
70
+
71
+static av_cold int qsv_decode_close(AVCodecContext *avctx)
72
+{
73
+    QSVH264Context *s = avctx->priv_data;
74
+
75
+    ff_qsv_close(&s->qsv);
76
+
77
+    qsv_clear_buffers(s);
78
+
79
+    av_fifo_free(s->packet_fifo);
80
+
81
+    av_bitstream_filter_close(s->bsf);
82
+    av_parser_close(s->parser);
83
+    avcodec_free_context(&s->avctx_internal);
84
+
85
+    return 0;
86
+}
87
+
88
+static av_cold int qsv_decode_init(AVCodecContext *avctx)
89
+{
90
+    QSVH264Context *s = avctx->priv_data;
91
+    int ret;
92
+
93
+    s->orig_pix_fmt = AV_PIX_FMT_NONE;
94
+
95
+    s->packet_fifo = av_fifo_alloc(sizeof(AVPacket));
96
+    if (!s->packet_fifo) {
97
+        ret = AVERROR(ENOMEM);
98
+        goto fail;
99
+    }
100
+
101
+    s->bsf = av_bitstream_filter_init("h264_mp4toannexb");
102
+    if (!s->bsf) {
103
+        ret = AVERROR(ENOMEM);
104
+        goto fail;
105
+    }
106
+
107
+    s->avctx_internal = avcodec_alloc_context3(NULL);
108
+    if (!s->avctx_internal) {
109
+        ret = AVERROR(ENOMEM);
110
+        goto fail;
111
+    }
112
+
113
+    if (avctx->extradata) {
114
+        s->avctx_internal->extradata = av_mallocz(avctx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
115
+        if (!s->avctx_internal->extradata) {
116
+            ret = AVERROR(ENOMEM);
117
+            goto fail;
118
+        }
119
+        memcpy(s->avctx_internal->extradata, avctx->extradata,
120
+               avctx->extradata_size);
121
+        s->avctx_internal->extradata_size = avctx->extradata_size;
122
+    }
123
+
124
+    s->parser = av_parser_init(AV_CODEC_ID_H264);
125
+    if (!s->parser) {
126
+        ret = AVERROR(ENOMEM);
127
+        goto fail;
128
+    }
129
+    s->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
130
+
131
+    s->qsv.iopattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
132
+
133
+    return 0;
134
+fail:
135
+    qsv_decode_close(avctx);
136
+    return ret;
137
+}
138
+
139
+static int qsv_process_data(AVCodecContext *avctx, AVFrame *frame,
140
+                            int *got_frame, AVPacket *pkt)
141
+{
142
+    QSVH264Context *s = avctx->priv_data;
143
+    uint8_t *dummy_data;
144
+    int dummy_size;
145
+    int ret;
146
+
147
+    /* we assume the packets are already split properly and want
148
+     * just the codec parameters here */
149
+    av_parser_parse2(s->parser, s->avctx_internal,
150
+                     &dummy_data, &dummy_size,
151
+                     pkt->data, pkt->size, pkt->pts, pkt->dts,
152
+                     pkt->pos);
153
+
154
+    /* TODO: flush delayed frames on reinit */
155
+    if (s->parser->format       != s->orig_pix_fmt    ||
156
+        s->parser->coded_width  != avctx->coded_width ||
157
+        s->parser->coded_height != avctx->coded_height) {
158
+        mfxSession session = NULL;
159
+
160
+        enum AVPixelFormat pix_fmts[3] = { AV_PIX_FMT_QSV,
161
+                                           AV_PIX_FMT_NONE,
162
+                                           AV_PIX_FMT_NONE };
163
+        enum AVPixelFormat qsv_format;
164
+
165
+        qsv_format = ff_qsv_map_pixfmt(s->parser->format);
166
+        if (qsv_format < 0) {
167
+            av_log(avctx, AV_LOG_ERROR,
168
+                   "Only 8-bit YUV420 streams are supported.\n");
169
+            ret = AVERROR(ENOSYS);
170
+            goto reinit_fail;
171
+        }
172
+
173
+        s->orig_pix_fmt     = s->parser->format;
174
+        avctx->pix_fmt      = pix_fmts[1] = qsv_format;
175
+        avctx->width        = s->parser->width;
176
+        avctx->height       = s->parser->height;
177
+        avctx->coded_width  = s->parser->coded_width;
178
+        avctx->coded_height = s->parser->coded_height;
179
+        avctx->level        = s->avctx_internal->level;
180
+        avctx->profile      = s->avctx_internal->profile;
181
+
182
+        ret = ff_get_format(avctx, pix_fmts);
183
+        if (ret < 0)
184
+            goto reinit_fail;
185
+
186
+        avctx->pix_fmt = ret;
187
+
188
+        if (avctx->hwaccel_context) {
189
+            AVQSVContext *user_ctx = avctx->hwaccel_context;
190
+            session               = user_ctx->session;
191
+            s->qsv.iopattern      = user_ctx->iopattern;
192
+            s->qsv.ext_buffers    = user_ctx->ext_buffers;
193
+            s->qsv.nb_ext_buffers = user_ctx->nb_ext_buffers;
194
+        }
195
+
196
+        ret = ff_qsv_init(avctx, &s->qsv, session);
197
+        if (ret < 0)
198
+            goto reinit_fail;
199
+    }
200
+
201
+    return ff_qsv_decode(avctx, &s->qsv, frame, got_frame, &s->pkt_filtered);
202
+
203
+reinit_fail:
204
+    s->orig_pix_fmt = s->parser->format = avctx->pix_fmt = AV_PIX_FMT_NONE;
205
+    return ret;
206
+}
207
+
208
+static int qsv_decode_frame(AVCodecContext *avctx, void *data,
209
+                            int *got_frame, AVPacket *avpkt)
210
+{
211
+    QSVH264Context *s = avctx->priv_data;
212
+    AVFrame *frame    = data;
213
+    int ret;
214
+
215
+    /* buffer the input packet */
216
+    if (avpkt->size) {
217
+        AVPacket input_ref = { 0 };
218
+
219
+        if (av_fifo_space(s->packet_fifo) < sizeof(input_ref)) {
220
+            ret = av_fifo_realloc2(s->packet_fifo,
221
+                                   av_fifo_size(s->packet_fifo) + sizeof(input_ref));
222
+            if (ret < 0)
223
+                return ret;
224
+        }
225
+
226
+        ret = av_packet_ref(&input_ref, avpkt);
227
+        if (ret < 0)
228
+            return ret;
229
+        av_fifo_generic_write(s->packet_fifo, &input_ref, sizeof(input_ref), NULL);
230
+    }
231
+
232
+    /* process buffered data */
233
+    while (!*got_frame) {
234
+        /* prepare the input data -- convert to Annex B if needed */
235
+        if (s->pkt_filtered.size <= 0) {
236
+            int size;
237
+
238
+            /* no more data */
239
+            if (av_fifo_size(s->packet_fifo) < sizeof(AVPacket))
240
+                return avpkt->size ? avpkt->size : ff_qsv_decode(avctx, &s->qsv, frame, got_frame, avpkt);
241
+
242
+            if (s->filtered_data != s->input_ref.data)
243
+                av_freep(&s->filtered_data);
244
+            s->filtered_data = NULL;
245
+            av_packet_unref(&s->input_ref);
246
+
247
+            av_fifo_generic_read(s->packet_fifo, &s->input_ref, sizeof(s->input_ref), NULL);
248
+            ret = av_bitstream_filter_filter(s->bsf, avctx, NULL,
249
+                                             &s->filtered_data, &size,
250
+                                             s->input_ref.data, s->input_ref.size, 0);
251
+            if (ret < 0) {
252
+                s->filtered_data = s->input_ref.data;
253
+                size             = s->input_ref.size;
254
+            }
255
+            s->pkt_filtered      = s->input_ref;
256
+            s->pkt_filtered.data = s->filtered_data;
257
+            s->pkt_filtered.size = size;
258
+        }
259
+
260
+        ret = qsv_process_data(avctx, frame, got_frame, &s->pkt_filtered);
261
+        if (ret < 0)
262
+            return ret;
263
+
264
+        s->pkt_filtered.size -= ret;
265
+        s->pkt_filtered.data += ret;
266
+    }
267
+
268
+    return avpkt->size;
269
+}
270
+
271
+static void qsv_decode_flush(AVCodecContext *avctx)
272
+{
273
+    QSVH264Context *s = avctx->priv_data;
274
+
275
+    qsv_clear_buffers(s);
276
+    s->orig_pix_fmt = AV_PIX_FMT_NONE;
277
+}
278
+
279
+AVHWAccel ff_h264_qsv_hwaccel = {
280
+    .name           = "h264_qsv",
281
+    .type           = AVMEDIA_TYPE_VIDEO,
282
+    .id             = AV_CODEC_ID_H264,
283
+    .pix_fmt        = AV_PIX_FMT_QSV,
284
+};
285
+
286
+#define OFFSET(x) offsetof(QSVH264Context, x)
287
+#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
288
+static const AVOption options[] = {
289
+    { "async_depth", "Internal parallelization depth, the higher the value the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 0, INT_MAX, VD },
290
+    { NULL },
291
+};
292
+
293
+static const AVClass class = {
294
+    .class_name = "h264_qsv",
295
+    .item_name  = av_default_item_name,
296
+    .option     = options,
297
+    .version    = LIBAVUTIL_VERSION_INT,
298
+};
299
+
300
+AVCodec ff_h264_qsv_decoder = {
301
+    .name           = "h264_qsv",
302
+    .long_name      = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (Intel Quick Sync Video acceleration)"),
303
+    .priv_data_size = sizeof(QSVH264Context),
304
+    .type           = AVMEDIA_TYPE_VIDEO,
305
+    .id             = AV_CODEC_ID_H264,
306
+    .init           = qsv_decode_init,
307
+    .decode         = qsv_decode_frame,
308
+    .flush          = qsv_decode_flush,
309
+    .close          = qsv_decode_close,
310
+    .capabilities   = CODEC_CAP_DELAY,
311
+    .priv_class     = &class,
312
+};
0 313
new file mode 100644
... ...
@@ -0,0 +1,86 @@
0
+/*
1
+ * Intel MediaSDK QSV utility functions
2
+ *
3
+ * copyright (c) 2013 Luca Barbato
4
+ *
5
+ * This file is part of Libav.
6
+ *
7
+ * Libav 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
+ * Libav 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 Libav; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ */
21
+
22
+#ifndef AVCODEC_QSV_INTERNAL_H
23
+#define AVCODEC_QSV_INTERNAL_H
24
+
25
+#include <stdint.h>
26
+#include <sys/types.h>
27
+
28
+#include <mfx/mfxvideo.h>
29
+
30
+#include "libavutil/frame.h"
31
+#include "libavutil/pixfmt.h"
32
+
33
+#include "avcodec.h"
34
+
35
+#define QSV_VERSION_MAJOR 1
36
+#define QSV_VERSION_MINOR 1
37
+
38
+#define ASYNC_DEPTH_DEFAULT 4       // internal parallelism
39
+
40
+typedef struct QSVFrame {
41
+    AVFrame *frame;
42
+    mfxFrameSurface1 *surface;
43
+
44
+    mfxFrameSurface1 surface_internal;
45
+
46
+    struct QSVFrame *next;
47
+} QSVFrame;
48
+
49
+typedef struct QSVContext {
50
+    // the session used for decoding
51
+    mfxSession session;
52
+
53
+    // the session we allocated internally, in case the caller did not provide
54
+    // one
55
+    mfxSession internal_session;
56
+
57
+    /**
58
+     * a linked list of frames currently being used by QSV
59
+     */
60
+    QSVFrame *work_frames;
61
+
62
+    // options set by the caller
63
+    int async_depth;
64
+    int iopattern;
65
+
66
+    mfxExtBuffer **ext_buffers;
67
+    int         nb_ext_buffers;
68
+} QSVContext;
69
+
70
+/**
71
+ * Convert a libmfx error code into a libav error code.
72
+ */
73
+int ff_qsv_error(int mfx_err);
74
+
75
+int ff_qsv_map_pixfmt(enum AVPixelFormat format);
76
+
77
+int ff_qsv_init(AVCodecContext *s, QSVContext *q, mfxSession session);
78
+
79
+int ff_qsv_decode(AVCodecContext *s, QSVContext *q,
80
+                  AVFrame *frame, int *got_frame,
81
+                  AVPacket *avpkt);
82
+
83
+int ff_qsv_close(QSVContext *q);
84
+
85
+#endif /* AVCODEC_QSV_INTERNAL_H */
... ...
@@ -29,7 +29,7 @@
29 29
 #include "libavutil/version.h"
30 30
 
31 31
 #define LIBAVCODEC_VERSION_MAJOR 56
32
-#define LIBAVCODEC_VERSION_MINOR 13
32
+#define LIBAVCODEC_VERSION_MINOR 14
33 33
 #define LIBAVCODEC_VERSION_MICRO  0
34 34
 
35 35
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \