Originally written by Luca Barbato <[email protected]>.
Further contributions by Yukinori Yamazoe <[email protected]>.
---

I merged most of the fixes, left out what breaks for me on wine and what
requires more discussion, everything works up to vlc currently.
I plugged already some memory leaks I could spot, pity the current release
of drmemory is broken.

 configure              |   7 +
 libavcodec/Makefile    |   3 +
 libavcodec/allcodecs.c |   1 +
 libavcodec/qsv.c       | 415 +++++++++++++++++++++++++++++++++++++++++++++++++
 libavcodec/qsv.h       |  64 ++++++++
 libavcodec/qsv_h264.c  | 150 ++++++++++++++++++
 6 files changed, 640 insertions(+)
 create mode 100644 libavcodec/qsv.c
 create mode 100644 libavcodec/qsv.h
 create mode 100644 libavcodec/qsv_h264.c

diff --git a/configure b/configure
index 7afbf04..6b851c8 100755
--- a/configure
+++ b/configure
@@ -132,6 +132,7 @@ Component options:

 Hardware accelerators:
   --enable-dxva2           enable DXVA2 code
+  --enable-qsv             enable QSV code
   --enable-vaapi           enable VAAPI code
   --enable-vda             enable VDA code
   --enable-vdpau           enable VDPAU code
@@ -1073,6 +1074,7 @@ EXTERNAL_LIBRARY_LIST="

 HWACCEL_LIST="
     dxva2
+    qsv
     vaapi
     vda
     vdpau
@@ -1713,6 +1715,8 @@ zmbv_encoder_deps="zlib"

 # hardware accelerators
 dxva2_deps="dxva2api_h"
+qsv_deps="mfx_mfxvideo_h"
+qsv_extralibs="-lmfx"
 vaapi_deps="va_va_h"
 vda_deps="VideoDecodeAcceleration_VDADecoder_h pthreads"
 vda_extralibs="-framework CoreFoundation -framework VideoDecodeAcceleration 
-framework QuartzCore"
@@ -1724,6 +1728,8 @@ h263_vdpau_hwaccel_deps="vdpau"
 h263_vdpau_hwaccel_select="h263_decoder"
 h264_dxva2_hwaccel_deps="dxva2"
 h264_dxva2_hwaccel_select="h264_decoder"
+h264_qsv_decoder_deps="qsv"
+h264_qsv_decoder_select="h264_mp4toannexb_bsf"
 h264_vaapi_hwaccel_deps="vaapi"
 h264_vaapi_hwaccel_select="h264_decoder"
 h264_vda_hwaccel_deps="vda"
@@ -3711,6 +3717,7 @@ check_header dxva.h
 check_header dxva2api.h
 check_header io.h
 check_header malloc.h
+check_header mfx/mfxvideo.h
 check_header poll.h
 check_header sys/mman.h
 check_header sys/param.h
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 8e0d60d..e8e4e0c 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -61,6 +61,7 @@ OBJS-$(CONFIG_MPEGAUDIODSP)            += mpegaudiodsp.o      
          \
 OBJS-$(CONFIG_MPEGVIDEO)               += mpegvideo.o mpegvideo_motion.o
 OBJS-$(CONFIG_MPEGVIDEOENC)            += mpegvideo_enc.o mpeg12data.o  \
                                           motion_est.o ratecontrol.o
+OBJS-$(CONFIG_QSV)                     += qsv.o
 OBJS-$(CONFIG_RANGECODER)              += rangecoder.o
 RDFT-OBJS-$(CONFIG_HARDCODED_TABLES)   += sin_tables.o
 OBJS-$(CONFIG_RDFT)                    += rdft.o $(RDFT-OBJS-yes)
@@ -197,6 +198,7 @@ OBJS-$(CONFIG_H264_DECODER)            += h264.o            
                   \
                                           h264_loopfilter.o h264_direct.o      
\
                                           cabac.o h264_sei.o h264_ps.o         
\
                                           h264_refs.o h264_cavlc.o h264_cabac.o
+OBJS-$(CONFIG_H264_QSV_DECODER)        += qsv_h264.o
 OBJS-$(CONFIG_HUFFYUV_DECODER)         += huffyuv.o huffyuvdec.o
 OBJS-$(CONFIG_HUFFYUV_ENCODER)         += huffyuv.o huffyuvenc.o
 OBJS-$(CONFIG_IAC_DECODER)             += imc.o
@@ -686,6 +688,7 @@ SKIPHEADERS                            += %_tablegen.h      
            \
 SKIPHEADERS-$(CONFIG_DXVA2)            += dxva2.h dxva2_internal.h
 SKIPHEADERS-$(CONFIG_LIBSCHROEDINGER)  += libschroedinger.h
 SKIPHEADERS-$(CONFIG_MPEG_XVMC_DECODER) += xvmc.h
+SKIPHEADERS-$(CONFIG_QSV)              += qsv.h
 SKIPHEADERS-$(CONFIG_VAAPI)            += vaapi_internal.h
 SKIPHEADERS-$(CONFIG_VDA)              += vda.h
 SKIPHEADERS-$(CONFIG_VDPAU)            += vdpau.h vdpau_internal.h
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 55d7957..ff43bd5 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -153,6 +153,7 @@ void avcodec_register_all(void)
     REGISTER_DECODER(H263I,             h263i);
     REGISTER_ENCODER(H263P,             h263p);
     REGISTER_DECODER(H264,              h264);
+    REGISTER_DECODER(H264_QSV,          h264_qsv);
     REGISTER_ENCDEC (HUFFYUV,           huffyuv);
     REGISTER_DECODER(IDCIN,             idcin);
     REGISTER_DECODER(IFF_BYTERUN1,      iff_byterun1);
diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c
new file mode 100644
index 0000000..542f124
--- /dev/null
+++ b/libavcodec/qsv.c
@@ -0,0 +1,415 @@
+/*
+ * Intel MediaSDK QSV utility functions
+ *
+ * copyright (c) 2013 Luca Barbato
+ *
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <mfx/mfxvideo.h>
+
+#include "libavutil/common.h"
+#include "libavutil/mem.h"
+#include "libavutil/log.h"
+#include "libavutil/time.h"
+#include "internal.h"
+#include "avcodec.h"
+#include "qsv.h"
+
+int ff_qsv_error(int mfx_err)
+{
+    switch (mfx_err) {
+    case MFX_ERR_NONE:
+        return 0;
+    case MFX_ERR_MEMORY_ALLOC:
+    case MFX_ERR_NOT_ENOUGH_BUFFER:
+        return AVERROR(ENOMEM);
+    case MFX_ERR_INVALID_HANDLE:
+        return AVERROR(EINVAL);
+    case MFX_ERR_DEVICE_FAILED:
+    case MFX_ERR_DEVICE_LOST:
+    case MFX_ERR_LOCK_MEMORY:
+        return AVERROR(EIO);
+    case MFX_ERR_NULL_PTR:
+    case MFX_ERR_UNDEFINED_BEHAVIOR:
+    case MFX_ERR_NOT_INITIALIZED:
+        return AVERROR_BUG;
+    case MFX_ERR_UNSUPPORTED:
+    case MFX_ERR_NOT_FOUND:
+        return AVERROR(ENOSYS);
+    case MFX_ERR_MORE_DATA:
+    case MFX_ERR_MORE_SURFACE:
+    case MFX_ERR_MORE_BITSTREAM:
+        return AVERROR(EAGAIN);
+    case MFX_ERR_INCOMPATIBLE_VIDEO_PARAM:
+    case MFX_ERR_INVALID_VIDEO_PARAM:
+        return AVERROR(EINVAL);
+    case MFX_ERR_ABORTED:
+    case MFX_ERR_UNKNOWN:
+    default:
+        return AVERROR_UNKNOWN;
+    }
+}
+
+static int codec_id_to_mfx(enum AVCodecID codec_id)
+{
+    switch (codec_id) {
+    case AV_CODEC_ID_H264:
+        return MFX_CODEC_AVC;
+    case AV_CODEC_ID_MPEG1VIDEO:
+    case AV_CODEC_ID_MPEG2VIDEO:
+        return MFX_CODEC_MPEG2;
+    case AV_CODEC_ID_VC1:
+        return MFX_CODEC_VC1;
+    default:
+        break;
+    }
+
+    return AVERROR(ENOSYS);
+}
+
+static void qsv_surface_free(QSVContext *q)
+{
+    if (q->surfaces) {
+        for (int i = 0; i < q->nb_surfaces; i++)
+            av_free(q->surfaces[i].Data.Y);
+        av_freep(&q->surfaces);
+    }
+    av_free(q->dts);
+    av_free(q->pts);
+}
+
+static int qsv_surface_alloc(QSVContext *q, mfxFrameAllocRequest *req)
+{
+    int width  = FFALIGN(req->Info.Width, 32);
+    int height = FFALIGN(req->Info.Height, 32);
+    int ret    = AVERROR(ENOMEM);
+
+    q->surfaces = av_mallocz_array(q->nb_surfaces, sizeof(*q->surfaces));
+    q->dts      = av_mallocz_array(q->nb_surfaces, sizeof(*q->dts));
+    q->pts      = av_mallocz_array(q->nb_surfaces, sizeof(*q->pts));
+
+    if (!q->surfaces || !q->dts || !q->pts)
+        goto fail;
+
+    for (int i = 0; i < q->nb_surfaces; i++) {
+        if (!(q->surfaces[i].Data.Y = av_mallocz(width * height * 12 / 8)))
+            goto fail;
+        q->surfaces[i].Data.U = q->surfaces[i].Data.Y + width * height;
+        q->surfaces[i].Data.V = q->surfaces[i].Data.U + 1;
+        q->surfaces[i].Data.Pitch = width;
+        q->surfaces[i].Info = q->param.mfx.FrameInfo;
+        q->pts[i] = q->dts[i] = AV_NOPTS_VALUE;
+    }
+
+    if ((ret = MFXVideoDECODE_Init(q->session, &q->param)))
+        ret = ff_qsv_error(ret);
+
+fail:
+    if (ret)
+        qsv_surface_free(q);
+
+    return ret;
+}
+
+int ff_qsv_init(AVCodecContext *c, QSVContext *q)
+{
+    int ret;
+    mfxIMPL impl             = MFX_IMPL_AUTO_ANY;
+    mfxVersion ver           = { { QSV_VERSION_MINOR, QSV_VERSION_MAJOR } };
+    mfxBitstream *bs         = &q->bs;
+    mfxFrameAllocRequest req = { { 0 } };
+
+    if ((ret = codec_id_to_mfx(c->codec_id)) < 0)
+        return ret;
+
+    q->param.mfx.CodecId = ret;
+
+    if ((ret = MFXInit(impl, &ver, &q->session)) < 0)
+        return ff_qsv_error(ret);
+
+    MFXQueryIMPL(q->session, &impl);
+
+    if (impl & MFX_IMPL_SOFTWARE)
+        av_log(c, AV_LOG_INFO,
+               "Using Intel QuickSync software implementation.\n");
+    else if (impl & MFX_IMPL_HARDWARE)
+        av_log(c, AV_LOG_INFO,
+               "Using Intel QuickSync hardware accelerated implementation.\n");
+    else
+        av_log(c, AV_LOG_INFO,
+               "Unknown Intel QuickSync implementation %d.\n", impl);
+
+    q->param.IOPattern  = MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
+    q->param.AsyncDepth = q->async_depth;
+
+    if ((ret = MFXVideoDECODE_DecodeHeader(q->session, bs, &q->param)) < 0)
+        return ff_qsv_error(ret);
+
+    bs->DataFlag   = MFX_BITSTREAM_COMPLETE_FRAME;
+    bs->DataLength = bs->DataOffset = 0;
+
+    ret = MFXVideoDECODE_QueryIOSurf(q->session, &q->param, &req);
+    if (ret < 0)
+        return ff_qsv_error(ret);
+
+    q->nb_surfaces = req.NumFrameSuggested + q->param.AsyncDepth;
+    q->last_ret    = MFX_ERR_MORE_DATA;
+
+    return qsv_surface_alloc(q, &req);
+}
+
+static int bitstream_realloc(mfxBitstream *bs, int size)
+{
+    uint8_t *tmp;
+
+    if (bs->MaxLength >= size)
+        return 0;
+
+    tmp = av_realloc(bs->Data, size);
+    if (!tmp) {
+        av_freep(&bs->Data);
+        return AVERROR(ENOMEM);
+    }
+
+    bs->Data      = tmp;
+    bs->MaxLength = size;
+
+    return 0;
+}
+
+static int bitstream_enqueue(mfxBitstream *bs, uint8_t *data, int size)
+{
+    int bs_size = bs->DataLength + size;
+    int ret;
+
+    if ((ret = bitstream_realloc(bs, bs_size)) < 0)
+        return ret;
+
+    if (bs_size > bs->MaxLength - bs->DataOffset) {
+        memmove(bs->Data, bs->Data + bs->DataOffset, bs->DataLength);
+        bs->DataOffset = 0;
+    }
+
+    memcpy(bs->Data + bs->DataOffset + bs->DataLength, data, size);
+
+    bs->DataLength += size;
+
+    return 0;
+}
+
+static mfxFrameSurface1 *get_surface(QSVContext *q)
+{
+    int i;
+    for (i = 0; i < q->nb_surfaces; i++) {
+        if (!q->surfaces[i].Data.Locked)
+            break;
+    }
+    if (i == q->nb_surfaces) {
+        av_log(NULL, AV_LOG_INFO, "No surfaces!\n");
+        return NULL;
+    }
+    return q->surfaces + i;
+}
+
+static int get_dts(QSVContext *q, int64_t pts,  int64_t *dts)
+{
+    int i;
+
+    if (pts == AV_NOPTS_VALUE) {
+        *dts = AV_NOPTS_VALUE;
+        return 0;
+    }
+
+    for (i = 0; i < q->nb_surfaces; i++) {
+        if (q->pts[i] == pts)
+            break;
+    }
+    if (i == q->nb_surfaces) {
+        av_log(q, AV_LOG_ERROR,
+               "Requested pts %"PRId64" does not match any dts\n",
+               pts);
+        return AVERROR_BUG;
+    }
+    *dts = q->dts[i];
+
+    q->pts[i] = AV_NOPTS_VALUE;
+
+    return 0;
+}
+
+static int put_dts(QSVContext *q, int64_t pts, int64_t dts)
+{
+    int i;
+    for (i = 0; i < q->nb_surfaces; i++) {
+        if (q->pts[i] == AV_NOPTS_VALUE)
+            break;
+    }
+
+    if (i == q->nb_surfaces) {
+        av_log(q, AV_LOG_INFO, "No slot available.\n");
+        return AVERROR_BUG;
+    }
+
+    q->pts[i] = pts;
+    q->dts[i] = dts;
+
+    return 0;
+}
+
+int ff_qsv_decode(AVCodecContext *avctx, QSVContext *q,
+                  AVFrame *frame, int *got_frame,
+                  AVPacket *avpkt)
+{
+    mfxFrameSurface1 *insurf;
+    mfxFrameSurface1 *outsurf;
+    mfxSyncPoint sync;
+    mfxBitstream *bs = &q->bs;
+    int size         = avpkt->size;
+    int ret, i;
+
+    *got_frame = 0;
+
+    if (size)
+        ff_packet_list_put(&q->pending, &q->pending_end, avpkt);
+
+    ret = q->last_ret;
+    do {
+        if (ret == MFX_ERR_MORE_DATA) {
+            if (!bs) {
+                break;
+            } else if (q->pending) {
+                AVPacket pkt = { 0 };
+
+                ff_packet_list_get(&q->pending, &q->pending_end, &pkt);
+
+                if (!(ret = put_dts(q, pkt.pts, pkt.dts))) {
+                    q->bs.TimeStamp = pkt.pts;
+
+                    ret = bitstream_enqueue(&q->bs, pkt.data, pkt.size);
+                }
+
+                av_packet_unref(&pkt);
+
+                if (ret < 0)
+                    return ret;
+            } else if (!size) {
+                // Flush cached frames when EOF
+                bs = NULL;
+            } else {
+                break;
+            }
+        }
+
+        if (!(insurf = get_surface(q)))
+            break;
+
+        ret = MFXVideoDECODE_DecodeFrameAsync(q->session, bs,
+                                              insurf, &outsurf, &sync);
+
+    } while (ret == MFX_ERR_MORE_SURFACE || ret == MFX_ERR_MORE_DATA ||
+             ret == MFX_WRN_DEVICE_BUSY);
+
+    q->last_ret = ret;
+
+    switch (ret) {
+    case MFX_ERR_MORE_DATA:
+        ret = 0;
+        break;
+    case MFX_WRN_VIDEO_PARAM_CHANGED:
+    // FIXME handle the param change properly.
+    //  ret = MFXVideoDECODE_QueryIOSurf(q->session, &q->qsv.param, &req);
+    //    if (ret < 0)
+    //        return ff_qsv_error(ret);
+        ret = 0;
+    case MFX_WRN_DEVICE_BUSY:
+        return AVERROR(EAGAIN);
+    default:
+        break;
+    }
+
+    if (sync) {
+        int64_t dts;
+
+        MFXVideoCORE_SyncOperation(q->session, sync, 60000);
+
+        if ((ret = get_dts(q, outsurf->Data.TimeStamp, &dts)) < 0)
+            return ret;
+
+        if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
+            av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+            return ret;
+        }
+
+        *got_frame = 1;
+
+        frame->pkt_pts = frame->pts = outsurf->Data.TimeStamp;
+        frame->pkt_dts = dts;
+
+        frame->repeat_pict =
+            outsurf->Info.PicStruct & MFX_PICSTRUCT_FRAME_TRIPLING ? 4 :
+            outsurf->Info.PicStruct & MFX_PICSTRUCT_FRAME_DOUBLING ? 2 :
+            outsurf->Info.PicStruct & MFX_PICSTRUCT_FIELD_REPEATED ? 1 : 0;
+        frame->top_field_first =
+            outsurf->Info.PicStruct & MFX_PICSTRUCT_FIELD_TFF;
+        frame->interlaced_frame =
+            !(outsurf->Info.PicStruct & MFX_PICSTRUCT_PROGRESSIVE);
+
+        for (i = 0; i < frame->height; i++) {
+            memcpy(frame->data[0] + frame->linesize[0] * i,
+                   outsurf->Data.Y + outsurf->Data.Pitch * i,
+                   FFMIN(outsurf->Data.Pitch, frame->linesize[0]));
+        }
+        for (i = 0; i < frame->height/2; i++) {
+            memcpy(frame->data[1] + frame->linesize[1] * i,
+                   outsurf->Data.UV + outsurf->Data.Pitch * i,
+                   FFMIN(outsurf->Data.Pitch, frame->linesize[1]));
+        }
+    }
+
+    if (ret < 0)
+        return ff_qsv_error(ret);
+
+    return size;
+}
+
+int ff_qsv_flush(QSVContext *q)
+{
+    int ret;
+
+    if ((ret = MFXVideoDECODE_Reset(q->session, &q->param)));
+        ret = ff_qsv_error(ret);
+
+    q->bs.DataOffset = q->bs.DataLength = 0;
+
+    ff_packet_list_free(&q->pending, &q->pending_end);
+
+    return ret;
+}
+
+int ff_qsv_close(QSVContext *q)
+{
+    int ret = MFXClose(q->session);
+
+    qsv_surface_free(q);
+
+    ff_packet_list_free(&q->pending, &q->pending_end);
+
+    return ff_qsv_error(ret);
+}
diff --git a/libavcodec/qsv.h b/libavcodec/qsv.h
new file mode 100644
index 0000000..1dff119
--- /dev/null
+++ b/libavcodec/qsv.h
@@ -0,0 +1,64 @@
+/*
+ * Intel MediaSDK QSV utility functions
+ *
+ * copyright (c) 2013 Luca Barbato
+ *
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_QSV_H
+#define AVCODEC_QSV_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <mfx/mfxvideo.h>
+
+#include "libavutil/avutil.h"
+
+#define QSV_VERSION_MAJOR 1
+#define QSV_VERSION_MINOR 1
+
+#define ASYNC_DEPTH_DEFAULT 4       // internal parallelism
+
+typedef struct QSVContext {
+    AVClass *class;
+    mfxSession session;
+    mfxVideoParam param;
+    mfxFrameSurface1 *surfaces;
+    int64_t *dts;
+    int64_t *pts;
+    int nb_surfaces;
+    mfxSyncPoint sync;
+    mfxBitstream bs;
+    int last_ret;
+    int async_depth;
+    AVPacketList *pending, *pending_end;
+} QSVContext;
+
+int ff_qsv_error(int mfx_err);
+
+int ff_qsv_init(AVCodecContext *s, QSVContext *q);
+
+int ff_qsv_decode(AVCodecContext *s, QSVContext *q,
+                  AVFrame *frame, int *got_frame,
+                  AVPacket *avpkt);
+
+int ff_qsv_flush(QSVContext *q);
+
+int ff_qsv_close(QSVContext *q);
+
+#endif /* AVCODEC_QSV_H */
diff --git a/libavcodec/qsv_h264.c b/libavcodec/qsv_h264.c
new file mode 100644
index 0000000..8554649
--- /dev/null
+++ b/libavcodec/qsv_h264.c
@@ -0,0 +1,150 @@
+/*
+ * Intel MediaSDK QSV based H.264 decoder
+ *
+ * copyright (c) 2013 Luca Barbato
+ *
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <mfx/mfxvideo.h>
+
+#include "avcodec.h"
+#include "internal.h"
+#include "h264.h"
+#include "qsv.h"
+
+typedef struct QSVH264Context {
+    AVClass *class;
+    QSVContext qsv;
+    AVBitStreamFilterContext *bsf;
+} QSVH264Context;
+
+static const uint8_t fake_idr[] = { 0x00, 0x00, 0x01, 0x65 };
+
+static av_cold int qsv_dec_init(AVCodecContext *avctx)
+{
+    QSVH264Context *q        = avctx->priv_data;
+    mfxBitstream *bs         = &q->qsv.bs;
+    int ret;
+
+    avctx->pix_fmt = AV_PIX_FMT_NV12;
+
+    if (!(q->bsf = av_bitstream_filter_init("h264_mp4toannexb")))
+        return AVERROR(ENOMEM);
+
+    // Data and DataLength passed as dummy pointers
+    av_bitstream_filter_filter(q->bsf, avctx, NULL,
+                               &bs->Data, &bs->DataLength,
+                               NULL, 0, 0);
+
+    //FIXME feed it a fake IDR directly
+    bs->Data = av_malloc(avctx->extradata_size + sizeof(fake_idr));
+    bs->DataLength = avctx->extradata_size;
+
+    memcpy(bs->Data, avctx->extradata, avctx->extradata_size);
+    memcpy(bs->Data + bs->DataLength, fake_idr, sizeof(fake_idr));
+
+    bs->DataLength += sizeof(fake_idr);
+
+    bs->MaxLength = bs->DataLength;
+
+    ret = ff_qsv_init(avctx, &q->qsv);
+    if (ret < 0) {
+        av_freep(&bs->Data);
+        av_bitstream_filter_close(q->bsf);
+    }
+
+    return ret;
+}
+
+static int qsv_dec_frame(AVCodecContext *avctx, void *data,
+                         int *got_frame, AVPacket *avpkt)
+{
+    QSVH264Context *q = avctx->priv_data;
+    AVFrame *frame    = data;
+    uint8_t *p;
+    int size;
+    int ret;
+
+    av_bitstream_filter_filter(q->bsf, avctx, NULL,
+                               &p, &size,
+                               avpkt->data, avpkt->size, 0);
+
+    if (p != avpkt->data) {
+        AVPacket pkt = { 0 };
+
+        av_packet_copy_props(&pkt, avpkt);
+
+        pkt.data = p;
+        pkt.size = size;
+
+        ret = ff_qsv_decode(avctx, &q->qsv, frame, got_frame, &pkt);
+
+        av_free(p);
+    } else
+        ret = ff_qsv_decode(avctx, &q->qsv, frame, got_frame, avpkt);
+
+    return ret;
+}
+
+static int qsv_dec_close (AVCodecContext *avctx)
+{
+    QSVH264Context *q = avctx->priv_data;
+    int ret = ff_qsv_close(&q->qsv);
+
+    av_bitstream_filter_close(q->bsf);
+    av_freep(&q->qsv.bs.Data);
+    return ret;
+}
+
+static void qsv_dec_flush(AVCodecContext *avctx)
+{
+    QSVH264Context *q = avctx->priv_data;
+
+    ff_qsv_flush(&q->qsv);
+}
+
+#define OFFSET(x) offsetof(QSVH264Context, x)
+#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
+static const AVOption options[] = {
+    { "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 },
+    { NULL },
+};
+
+static const AVClass class = {
+    .class_name = "h264_qsv",
+    .item_name  = av_default_item_name,
+    .option     = options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_h264_qsv_decoder = {
+    .name           = "h264_qsv",
+    .long_name      = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 
part 10 (Intel Quick Sync Video acceleration)"),
+    .priv_data_size = sizeof(QSVH264Context),
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = AV_CODEC_ID_H264,
+    .init           = qsv_dec_init,
+    .decode         = qsv_dec_frame,
+    .flush          = qsv_dec_flush,
+    .close          = qsv_dec_close,
+    .capabilities   = CODEC_CAP_DELAY | CODEC_CAP_PKT_TS,
+    .priv_class     = &class,
+};
--
1.8.3.2

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to