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