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