Changed to dynamic surface allocate in get_surface(), because number of
surfaces may be insufficient when it is a fixed value.
And reduced number of memcpy when output frame.
---
libavcodec/qsv.c | 136 ++++++++++++++++++++++++++++++++------------------
libavcodec/qsv.h | 9 +++-
libavcodec/qsv_h264.c | 2 +-
3 files changed, 95 insertions(+), 52 deletions(-)
diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c
index 86705eb..ac1a282 100644
--- a/libavcodec/qsv.c
+++ b/libavcodec/qsv.c
@@ -84,39 +84,24 @@ static int codec_id_to_mfx(enum AVCodecID codec_id)
return AVERROR(ENOSYS);
}
-static int qsv_surface_alloc(QSVContext *q, mfxFrameAllocRequest *req)
+static int qsv_timestamps_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));
+ q->dts = av_mallocz_array(q->nb_timestamps, sizeof(*q->dts));
+ q->pts = av_mallocz_array(q->nb_timestamps, sizeof(*q->pts));
- if (!q->surfaces || !q->dts || !q->pts)
+ if (!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;
+ for (int i = 0; i < q->nb_timestamps; i++)
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) {
- if (q->surfaces)
- for (int i = 0; i < q->nb_surfaces; i++)
- av_free(q->surfaces[i].Data.Y);
-
- av_free(q->surfaces);
av_free(q->dts);
av_free(q->pts);
}
@@ -165,10 +150,10 @@ int ff_qsv_init(AVCodecContext *c, QSVContext *q)
if (ret < 0)
return ff_qsv_error(ret);
- q->nb_surfaces = req.NumFrameSuggested + q->param.AsyncDepth;
- q->last_ret = MFX_ERR_MORE_DATA;
+ q->nb_timestamps = req.NumFrameSuggested + q->param.AsyncDepth;
+ q->last_ret = MFX_ERR_MORE_DATA;
- return qsv_surface_alloc(q, &req);
+ return qsv_timestamps_alloc(q, &req);
}
static int bitstream_realloc(mfxBitstream *bs, int size)
@@ -210,18 +195,73 @@ static int bitstream_enqueue(mfxBitstream *bs, uint8_t
*data, int size)
return 0;
}
-static mfxFrameSurface1 *get_surface(QSVContext *q)
+static void free_surface_list(QSVContext *q)
{
- int i;
- for (i = 0; i < q->nb_surfaces; i++) {
- if (!q->surfaces[i].Data.Locked)
- break;
+ QSVSurfaceList **next = &q->surflist;
+ QSVSurfaceList *sl;
+
+ while (*next) {
+ sl = *next;
+ *next = sl->next;
+ av_frame_free((AVFrame **)(&sl->surface.Data.MemId));
+ av_freep(&sl);
}
- if (i == q->nb_surfaces) {
- av_log(NULL, AV_LOG_INFO, "No surfaces!\n");
+}
+
+static QSVSurfaceList *alloc_surface_list_entry(AVCodecContext *avctx,
QSVContext *q)
+{
+ QSVSurfaceList *sl = NULL;
+ AVFrame *frame = NULL;
+ int ret = AVERROR(ENOMEM);
+
+ if (!(sl = av_mallocz(sizeof(*sl)))) {
+ av_log(avctx, AV_LOG_ERROR, "av_mallocz() failed\n");
+ goto fail;
+ }
+ if (!(frame = av_frame_alloc())) {
+ av_log(avctx, AV_LOG_ERROR, "av_frame_alloc() failed\n");
+ goto fail;
+ }
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ goto fail;
+ }
+
+ sl->surface.Data.MemId = frame;
+ sl->surface.Data.Y = frame->data[0];
+ sl->surface.Data.UV = frame->data[1];
+ sl->surface.Data.Pitch = frame->linesize[0];
+ sl->surface.Info = q->param.mfx.FrameInfo;
+
+fail:
+ if (ret) {
+ av_freep(&sl);
+ av_frame_free(&frame);
+ }
+
+ return sl;
+}
+
+static mfxFrameSurface1 *get_surface(AVCodecContext *avctx, QSVContext *q)
+{
+ QSVSurfaceList **next = &q->surflist;
+ QSVSurfaceList *sl;
+
+ while (*next) {
+ sl = *next;
+ next = &sl->next;
+ if (!sl->surface.Data.Locked)
+ return &sl->surface;
+ }
+
+ if (!(sl = alloc_surface_list_entry(avctx, q))) {
+ av_log(avctx, AV_LOG_INFO, "No surfaces!\n");
return NULL;
}
- return q->surfaces + i;
+
+ *next = sl;
+
+ return &sl->surface;
}
static int get_dts(QSVContext *q, int64_t pts, int64_t *dts)
@@ -233,11 +273,11 @@ static int get_dts(QSVContext *q, int64_t pts, int64_t
*dts)
return 0;
}
- for (i = 0; i < q->nb_surfaces; i++) {
+ for (i = 0; i < q->nb_timestamps; i++) {
if (q->pts[i] == pts)
break;
}
- if (i == q->nb_surfaces) {
+ if (i == q->nb_timestamps) {
av_log(q, AV_LOG_ERROR,
"Requested pts %"PRId64" does not match any dts\n",
pts);
@@ -253,12 +293,12 @@ static int get_dts(QSVContext *q, int64_t pts, int64_t
*dts)
static int put_dts(QSVContext *q, int64_t pts, int dts)
{
int i;
- for (i = 0; i < q->nb_surfaces; i++) {
+ for (i = 0; i < q->nb_timestamps; i++) {
if (q->pts[i] == AV_NOPTS_VALUE)
break;
}
- if (i == q->nb_surfaces) {
+ if (i == q->nb_timestamps) {
av_log(q, AV_LOG_INFO, "No slot available.\n");
return AVERROR_BUG;
}
@@ -279,7 +319,7 @@ int ff_qsv_decode(AVCodecContext *avctx, QSVContext *q,
mfxBitstream *bs = &q->bs;
int size = avpkt->size;
int busymsec = 0;
- int ret, i;
+ int ret;
*got_frame = 0;
@@ -314,7 +354,7 @@ int ff_qsv_decode(AVCodecContext *avctx, QSVContext *q,
}
}
- if (!(insurf = get_surface(q)))
+ if (!(insurf = get_surface(avctx, q)))
break;
ret = MFXVideoDECODE_DecodeFrameAsync(q->session, bs,
@@ -352,16 +392,21 @@ int ff_qsv_decode(AVCodecContext *avctx, QSVContext *q,
if (sync) {
int64_t dts;
+ AVFrame *workframe;
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) {
+ workframe = outsurf->Data.MemId;
+ av_frame_move_ref(frame, workframe);
+ if ((ret = ff_get_buffer(avctx, workframe, 0)) < 0) {
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
return ret;
}
+ outsurf->Data.Y = workframe->data[0];
+ outsurf->Data.UV = workframe->data[1];
*got_frame = 1;
@@ -376,17 +421,6 @@ int ff_qsv_decode(AVCodecContext *avctx, QSVContext *q,
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)
@@ -404,6 +438,8 @@ int ff_qsv_flush(QSVContext *q)
q->bs.DataOffset = q->bs.DataLength = 0;
+ free_surface_list(q);
+
ff_packet_list_free(&q->pending, &q->pending_end);
return ret;
@@ -413,6 +449,8 @@ int ff_qsv_close(QSVContext *q)
{
int ret = MFXClose(q->session);
+ free_surface_list(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
index 9acb7ca..a9f4583 100644
--- a/libavcodec/qsv.h
+++ b/libavcodec/qsv.h
@@ -37,14 +37,19 @@
#define TIMEOUT_DEFAULT 5 * 1000 // 5s
+typedef struct QSVSurfaceList {
+ mfxFrameSurface1 surface;
+ struct QSVSurfaceList *next;
+} QSVSurfaceList;
+
typedef struct QSVContext {
AVClass *class;
mfxSession session;
mfxVideoParam param;
- mfxFrameSurface1 *surfaces;
+ QSVSurfaceList *surflist;
int64_t *dts;
int64_t *pts;
- int nb_surfaces;
+ int nb_timestamps;
mfxSyncPoint sync;
mfxBitstream bs;
int last_ret;
diff --git a/libavcodec/qsv_h264.c b/libavcodec/qsv_h264.c
index 70580b9..504b8ab 100644
--- a/libavcodec/qsv_h264.c
+++ b/libavcodec/qsv_h264.c
@@ -145,6 +145,6 @@ AVCodec ff_h264_qsv_decoder = {
.decode = qsv_dec_frame,
.flush = qsv_dec_flush,
.close = qsv_dec_close,
- .capabilities = CODEC_CAP_DELAY | CODEC_CAP_PKT_TS,
+ .capabilities = CODEC_CAP_DELAY | CODEC_CAP_PKT_TS | CODEC_CAP_DR1,
.priv_class = &class,
};
--
1.8.3.msysgit.0
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel