Originally written by Luca Barbato <[email protected]>.
Further contributions by Yukinori Yamazoe <[email protected]>.
---
 configure                 |   7 +
 doc/APIchanges            |   3 +
 libavcodec/Makefile       |   4 +
 libavcodec/allcodecs.c    |   1 +
 libavcodec/qsv.c          | 472 ++++++++++++++++++++++++++++++++++++++++++++++
 libavcodec/qsv.h          |  54 ++++++
 libavcodec/qsv_h264.c     | 161 ++++++++++++++++
 libavcodec/qsv_internal.h |  47 +++++
 libavcodec/version.h      |   2 +-
 9 files changed, 750 insertions(+), 1 deletion(-)
 create mode 100644 libavcodec/qsv.c
 create mode 100644 libavcodec/qsv.h
 create mode 100644 libavcodec/qsv_h264.c
 create mode 100644 libavcodec/qsv_internal.h

diff --git a/configure b/configure
index d87871e..4f238c8 100755
--- a/configure
+++ b/configure
@@ -134,6 +134,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
@@ -1190,6 +1191,7 @@ FEATURE_LIST="
 
 HWACCEL_LIST="
     dxva2
+    qsv
     vaapi
     vda
     vdpau
@@ -1939,6 +1941,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_hwaccel_deps="qsv"
+h264_qsv_hwaccel_select="h264_mp4toannexb_bsf"
 h264_vaapi_hwaccel_deps="vaapi"
 h264_vaapi_hwaccel_select="h264_decoder"
 h264_vda_hwaccel_deps="vda"
@@ -4096,6 +4100,7 @@ check_header dxva2api.h
 check_header io.h
 check_header mach/mach_time.h
 check_header malloc.h
+check_header mfx/mfxvideo.h
 check_header poll.h
 check_header sys/mman.h
 check_header sys/param.h
@@ -4207,6 +4212,8 @@ enabled openssl           && { check_lib openssl/ssl.h 
SSL_library_init -lssl -l
                                check_lib openssl/ssl.h SSL_library_init -lssl 
-lcrypto -lws2_32 -lgdi32 ||
                                die "ERROR: openssl not found"; }
 
+enabled qsv                && require_pkg_config libmfx "mfx/mfxvideo.h" 
MFXInit
+
 if enabled gnutls; then
     { check_lib nettle/bignum.h nettle_mpz_get_str_256 -lnettle -lhogweed 
-lgmp && enable nettle; } ||
     { check_lib gcrypt.h gcry_mpi_new -lgcrypt && enable gcrypt; }
diff --git a/doc/APIchanges b/doc/APIchanges
index c318908..f4e9b33 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -13,6 +13,9 @@ libavutil:     2014-08-09
 
 API changes, most recent first:
 
+2014-10-xx - xxxxxxx - lavc 56.5.0 - qsv.h
+  Add libmfx-based QSV hwaccel.
+
 2014-10-xx - xxxxxxx - lavc 56.4.0 - avcodec.h
 2014-10-xx - xxxxxxx - lavf 56.7.0 - avformat.h
   Move AVPacketList to avcodec.
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 62e41b8..a5296e8 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -4,6 +4,7 @@ HEADERS = avcodec.h                                             
        \
           avfft.h                                                       \
           dv_profile.h                                                  \
           dxva2.h                                                       \
+          qsv.h                                                         \
           vaapi.h                                                       \
           vda.h                                                         \
           vdpau.h                                                       \
@@ -74,6 +75,7 @@ OBJS-$(CONFIG_MPEGVIDEOENC)            += mpegvideo_enc.o 
mpeg12data.o  \
                                           mpegvideoencdsp.o
 OBJS-$(CONFIG_PIXBLOCKDSP)             += pixblockdsp.o
 OBJS-$(CONFIG_QPELDSP)                 += qpeldsp.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)
@@ -548,6 +550,7 @@ OBJS-$(CONFIG_VDPAU)                      += vdpau.o
 OBJS-$(CONFIG_H263_VAAPI_HWACCEL)         += vaapi_mpeg4.o
 OBJS-$(CONFIG_H263_VDPAU_HWACCEL)         += vdpau_mpeg4.o
 OBJS-$(CONFIG_H264_DXVA2_HWACCEL)         += dxva2_h264.o
+OBJS-$(CONFIG_H264_QSV_HWACCEL)           += qsv_h264.o
 OBJS-$(CONFIG_H264_VAAPI_HWACCEL)         += vaapi_h264.o
 OBJS-$(CONFIG_H264_VDA_HWACCEL)           += vda_h264.o
 OBJS-$(CONFIG_H264_VDPAU_HWACCEL)         += vdpau_h264.o
@@ -713,6 +716,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 qsv_internal.h
 SKIPHEADERS-$(CONFIG_VAAPI)            += vaapi_internal.h
 SKIPHEADERS-$(CONFIG_VDA)              += vda.h vda_internal.h
 SKIPHEADERS-$(CONFIG_VDPAU)            += vdpau.h vdpau_internal.h
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index bd74e0b..c10d544 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -77,6 +77,7 @@ void avcodec_register_all(void)
     REGISTER_HWACCEL(H263_VAAPI,        h263_vaapi);
     REGISTER_HWACCEL(H263_VDPAU,        h263_vdpau);
     REGISTER_HWACCEL(H264_DXVA2,        h264_dxva2);
+    REGISTER_HWACCEL(H264_QSV,          h264_qsv);
     REGISTER_HWACCEL(H264_VAAPI,        h264_vaapi);
     REGISTER_HWACCEL(H264_VDA,          h264_vda);
     REGISTER_HWACCEL(H264_VDA_OLD,      h264_vda_old);
diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c
new file mode 100644
index 0000000..a8bcc94
--- /dev/null
+++ b/libavcodec/qsv.c
@@ -0,0 +1,472 @@
+/*
+ * 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/log.h"
+#include "libavutil/mem.h"
+#include "libavutil/time.h"
+
+#include "avcodec.h"
+#include "internal.h"
+#include "qsv.h"
+#include "qsv_internal.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)
+{
+    int width, height, ret;
+    mfxFrameAllocRequest req = { { 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->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;
+
+    width  = FFALIGN(req.Info.Width, 32);
+    height = FFALIGN(req.Info.Height, 32);
+
+    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;
+    }
+
+fail:
+    if (ret)
+        qsv_surface_free(q);
+    else
+        q->last_ret = MFX_ERR_MORE_DATA;
+
+    return ret;
+}
+
+static void qsv_setup(AVCodecContext *c, QSVContext *q)
+{
+    c->width         = q->param.mfx.FrameInfo.CropW;
+    c->height        = q->param.mfx.FrameInfo.CropH;
+    c->coded_width   = q->param.mfx.FrameInfo.Width;
+    c->coded_height  = q->param.mfx.FrameInfo.Height;
+
+    c->time_base.den = q->param.mfx.FrameInfo.FrameRateExtN;
+    c->time_base.num = q->param.mfx.FrameInfo.FrameRateExtD;
+}
+
+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;
+
+    if ((ret = codec_id_to_mfx(c->codec_id)) < 0)
+        return ret;
+
+    q->param.IOPattern   = MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
+    q->param.AsyncDepth  = q->async_depth;
+    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_VERBOSE,
+               "Using Intel QuickSync software implementation.\n");
+    else if (impl & MFX_IMPL_HARDWARE)
+        av_log(c, AV_LOG_VERBOSE,
+               "Using Intel QuickSync hardware accelerated implementation.\n");
+    else
+        av_log(c, AV_LOG_WARNING,
+               "Unknown Intel QuickSync implementation %d.\n", impl);
+
+    if ((ret = MFXVideoDECODE_DecodeHeader(q->session, bs, &q->param)) < 0)
+        return ff_qsv_error(ret);
+
+    bs->DataFlag = MFX_BITSTREAM_COMPLETE_FRAME;
+
+    qsv_setup(c, q);
+
+    ret = qsv_surface_alloc(q);
+    if (ret < 0)
+        return ret;
+
+    ret = MFXVideoDECODE_Init(q->session, &q->param);
+    if (ret < 0)
+        ret = ff_qsv_error(ret);
+
+    return ret;
+}
+
+static int qsv_reinit(AVCodecContext *c, QSVContext *q)
+{
+    int ret;
+
+    qsv_surface_free(q);
+
+    if ((ret = MFXVideoDECODE_Reset(q->session, &q->param))) {
+        av_log(NULL, AV_LOG_ERROR, "Reset failed: %d\n", ret);
+    }
+
+    memset(&q->param, 0, sizeof(q->param));
+
+    MFXClose(q->session);
+
+    ret = ff_qsv_init(c, q);
+
+    q->reinit = 0;
+
+    return 0;
+}
+
+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 (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) {
+                    q->last_ret = MFX_ERR_MORE_DATA;
+                    return ret;
+                }
+            } else if (!size && bs) {
+                // Flush cached frames when EOF
+                bs = NULL;
+            } else {
+                return size;
+            }
+
+            if (q->reinit) {
+                // We are done flushing the decoded frame queue
+                av_log(avctx, AV_LOG_VERBOSE, "Calling reinit\n");
+                if ((ret = qsv_reinit(avctx, q)) < 0)
+                    return ret;
+
+                return size;
+            }
+        }
+
+        if (q->reinit) // Flush the frame queue
+            bs = NULL;
+
+        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);
+
+    q->last_ret = ret;
+
+    switch (ret) {
+    case MFX_ERR_MORE_DATA:
+        ret = 0;
+        break;
+    case MFX_WRN_INCOMPATIBLE_VIDEO_PARAM:
+        av_log(avctx, AV_LOG_WARNING, "Incompatible Video parameters.\n");
+        ret = 0;
+        break;
+    case MFX_WRN_VIDEO_PARAM_CHANGED:
+        ret = 0;
+        break;
+    case MFX_WRN_DEVICE_BUSY:
+        av_usleep(100);
+        return size;
+    case MFX_ERR_INCOMPATIBLE_VIDEO_PARAM:
+        av_log(avctx, AV_LOG_VERBOSE, "Resetting the decoder.\n");
+        q->reinit = 1;
+        return size;
+    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..c94c68a
--- /dev/null
+++ b/libavcodec/qsv.h
@@ -0,0 +1,54 @@
+/*
+ * 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"
+
+#include "libavcodec/avcodec.h"
+
+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;
+    int reinit;
+    AVPacketList *pending, *pending_end;
+} QSVContext;
+
+int av_qsv_default_init(AVCodecContext *s);
+
+int av_qsv_default_free(AVCodecContext *s);
+
+#endif /* AVCODEC_QSV_H */
diff --git a/libavcodec/qsv_h264.c b/libavcodec/qsv_h264.c
new file mode 100644
index 0000000..6f46aa5
--- /dev/null
+++ b/libavcodec/qsv_h264.c
@@ -0,0 +1,161 @@
+/*
+ * Intel MediaSDK based H.264 QSV HWAccel
+ *
+ * Copyright (C) 2014 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 "libavutil/opt.h"
+
+#include "avcodec.h"
+#include "internal.h"
+#include "h264.h"
+#include "qsv.h"
+#include "qsv_internal.h"
+
+typedef struct QSVH264Context {
+    AVClass *class;
+    QSVContext qsv;
+    AVBitStreamFilterContext *bsf;
+} QSVH264Context;
+
+static const uint8_t fake_idr[] = { 0x00, 0x00, 0x01, 0x65 };
+
+av_cold int av_qsv_default_free(AVCodecContext *avctx)
+{
+    QSVH264Context *q = avctx->hwaccel_context;
+    int ret = ff_qsv_close(&q->qsv);
+
+    av_bitstream_filter_close(q->bsf);
+    av_freep(&q->qsv.bs.Data);
+    av_freep(&q);
+
+    return ret;
+}
+
+static int qsv_dec_frame(AVCodecContext *avctx, void *data,
+                         int *got_frame, AVPacket *avpkt)
+{
+    QSVH264Context *q = avctx->hwaccel_context;
+    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);
+
+    if (ret < 0) {
+        char buf[128];
+        av_strerror(ret, buf, sizeof(buf));
+        av_log(NULL, AV_LOG_ERROR, "Error %s\n", buf);
+    }
+
+    return ret;
+}
+
+static void qsv_dec_flush(AVCodecContext *avctx)
+{
+    QSVH264Context *q = avctx->hwaccel_context;
+
+    ff_qsv_flush(&q->qsv);
+}
+
+AVHWAccel ff_h264_qsv_hwaccel = {
+    .name           = "h264_qsv",
+    .priv_data_size = sizeof(QSVH264Context),
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = AV_CODEC_ID_H264,
+    .decode         = qsv_dec_frame,
+    .flush          = qsv_dec_flush,
+};
+
+av_cold int av_qsv_default_init(AVCodecContext *avctx)
+{
+    QSVH264Context *q;
+    mfxBitstream *bs;
+    int ret;
+
+    if (avctx->codec_id != AV_CODEC_ID_H264)
+        return AVERROR(ENOSYS);
+
+    q = av_mallocz(sizeof(*q))
+    if (!q)
+        return AVERROR(ENOMEM);
+
+    bs = &q->qsv.bs;
+
+    q->qsv.async_depth = ASYNC_DEPTH_DEFAULT;
+
+    avctx->hwaccel_context = q;
+
+    avctx->pix_fmt = AV_PIX_FMT_NV12;
+
+    if (!(q->bsf = av_bitstream_filter_init("h264_mp4toannexb"))) {
+        av_qsv_default_free(avctx);
+        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));
+    if (!bs->Data) {
+        av_qsv_default_free(avctx);
+        return AVERROR(ENOMEM);
+    }
+
+    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_qsv_default_free(avctx);
+    else
+        avctx->hwaccel = &ff_h264_qsv_hwaccel;
+    return ret;
+}
diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h
new file mode 100644
index 0000000..7531955
--- /dev/null
+++ b/libavcodec/qsv_internal.h
@@ -0,0 +1,47 @@
+/*
+ * Intel MediaSDK QSV internal 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_INTERNAL_H
+#define AVCODEC_QSV_INTERNAL_H
+
+#include <stdint.h>
+
+#include "qsv.h"
+
+#define QSV_VERSION_MAJOR 1
+#define QSV_VERSION_MINOR 1
+
+#define ASYNC_DEPTH_DEFAULT 4 // internal parallelism
+
+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_INTERNAL_H */
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 2535818..bd3ce2c 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -29,7 +29,7 @@
 #include "libavutil/version.h"
 
 #define LIBAVCODEC_VERSION_MAJOR 56
-#define LIBAVCODEC_VERSION_MINOR  4
+#define LIBAVCODEC_VERSION_MINOR  5
 #define LIBAVCODEC_VERSION_MICRO  0
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
-- 
2.1.0

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

Reply via email to