[vlc-commits] qsv: use the same algorithm as ffmpeg to pick available encoding surfaces
Steve Lhomme
git at videolan.org
Wed Apr 4 18:28:33 CEST 2018
vlc | branch: master | Steve Lhomme <robux4 at videolabs.io> | Mon Sep 4 16:25:37 2017 +0200| [da6ec6c7d27e4be584ce99e2f7e11e7199480648] | committer: Steve Lhomme
qsv: use the same algorithm as ffmpeg to pick available encoding surfaces
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=da6ec6c7d27e4be584ce99e2f7e11e7199480648
---
modules/codec/qsv.c | 154 +++++++++++++++++++++++++++-------------------------
1 file changed, 81 insertions(+), 73 deletions(-)
diff --git a/modules/codec/qsv.c b/modules/codec/qsv.c
index be419eb0af..a1e5fc08c6 100644
--- a/modules/codec/qsv.c
+++ b/modules/codec/qsv.c
@@ -263,11 +263,14 @@ static const char *const sout_options[] = {
};
// Frame pool for QuickSync video encoder with Intel Media SDK's format frames.
-typedef struct qsv_frame_pool_t
+typedef struct _QSVFrame
{
- mfxFrameSurface1 *frames; // An allocated array of 'size' frames.
- size_t size; // The number of frame in the pool.
-} qsv_frame_pool_t;
+ struct _QSVFrame *next;
+ picture_t *pic;
+ mfxFrameSurface1 surface;
+ mfxEncodeCtrl enc_ctrl;
+ int used;
+} QSVFrame;
typedef struct async_task_t
{
@@ -283,7 +286,7 @@ struct encoder_sys_t
{
mfxSession session; // Intel Media SDK Session.
mfxVideoParam params; // Encoding parameters.
- qsv_frame_pool_t frames; // IntelMediaSDK's frame pool.
+ QSVFrame *work_frames; // IntelMediaSDK's frame pool.
uint64_t dts_warn_counter; // DTS warning counter for rate-limiting of msg;
uint64_t busy_warn_counter; // Device Busy warning counter for rate-limiting of msg;
uint64_t async_depth; // Number of parallel encoding operations.
@@ -305,42 +308,16 @@ static inline uint64_t qsv_mtime_to_timestamp(mtime_t vlc_ts)
return vlc_ts / UINT64_C(100) * UINT64_C(9);
}
-/*
- * Create a new frame pool with 'size' frames in it. Pools cannot be resized.
- */
-static int qsv_frame_pool_Init(qsv_frame_pool_t *pool,
- mfxFrameAllocRequest *request,
- uint64_t async_depth)
+static void clear_unused_frames(encoder_sys_t *sys)
{
- size_t size = request->NumFrameSuggested + async_depth;
-
- pool->frames = calloc(size, sizeof(mfxFrameSurface1));
- if (unlikely(!pool->frames))
- return VLC_ENOMEM;
-
- pool->size = size;
-
- for (size_t i = 0; i < size; i++) {
- memcpy(&pool->frames[i].Info, &request->Info, sizeof(request->Info));
- pool->frames[i].Data.Pitch = QSV_ALIGN(32, request->Info.Width);
- }
-
- return VLC_SUCCESS;
-}
-
-/*
- * Destroys a pool frame. Only call this function after a MFXClose
- * call since we doesn't check for Locked frames.
- */
-static void qsv_frame_pool_Destroy(qsv_frame_pool_t *pool)
-{
- for (size_t i = 0; i < pool->size; i++) {
- picture_t *pic = (picture_t *) pool->frames[i].Data.MemId;
- if (pic)
- picture_Release(pic);
+ QSVFrame *cur = sys->work_frames;
+ while (cur) {
+ if (cur->used && !cur->surface.Data.Locked) {
+ picture_Release(cur->pic);
+ cur->used = 0;
+ }
+ cur = cur->next;
}
-
- free(pool->frames);
}
/*
@@ -348,38 +325,34 @@ static void qsv_frame_pool_Destroy(qsv_frame_pool_t *pool)
* necessary associates the new picture with it and return the frame.
* Returns 0 if there's an error.
*/
-static mfxFrameSurface1 *qsv_frame_pool_Get(encoder_sys_t *sys, picture_t *pic)
+static int get_free_frame(encoder_sys_t *sys, QSVFrame **out)
{
- qsv_frame_pool_t *pool = &sys->frames;
- for (size_t i = 0; i < pool->size; i++) {
- mfxFrameSurface1 *frame = &pool->frames[i];
- if (frame->Data.Locked)
- continue;
- if (frame->Data.MemId)
- picture_Release((picture_t *)frame->Data.MemId);
-
- frame->Data.MemId = pic;
- frame->Data.PitchLow = pic->p[0].i_pitch;
- frame->Data.Y = pic->p[0].p_pixels;
- frame->Data.UV = pic->p[1].p_pixels;
- frame->Data.TimeStamp = qsv_mtime_to_timestamp(pic->date - sys->offset_pts);
-
- frame->Info = sys->params.mfx.FrameInfo;
-
- // Specify picture structure at runtime.
- if (pic->b_progressive)
- frame->Info.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
- else if (pic->b_top_field_first)
- frame->Info.PicStruct = MFX_PICSTRUCT_FIELD_TFF;
- else
- frame->Info.PicStruct = MFX_PICSTRUCT_FIELD_BFF;
+ QSVFrame *frame, **last;
- picture_Hold(pic);
+ clear_unused_frames(sys);
- return frame;
+ frame = sys->work_frames;
+ last = &sys->work_frames;
+ while (frame) {
+ if (!frame->used) {
+ *out = frame;
+ frame->used = 1;
+ return VLC_SUCCESS;
+ }
+
+ last = &frame->next;
+ frame = frame->next;
}
- return NULL;
+ frame = calloc(1,sizeof(QSVFrame));
+ if (unlikely(frame==NULL))
+ return VLC_ENOMEM;
+ *last = frame;
+
+ *out = frame;
+ frame->used = 1;
+
+ return VLC_SUCCESS;
}
static uint64_t qsv_params_get_value(const char *const *text,
@@ -587,9 +560,6 @@ static int Open(vlc_object_t *this)
msg_Err(enc, "Failed to query for allocation");
goto error;
}
- if (qsv_frame_pool_Init(&sys->frames, &alloc_request, sys->async_depth) != VLC_SUCCESS)
- goto nomem;
- msg_Dbg(enc, "Requested %d surfaces for work", alloc_request.NumFrameSuggested);
sys->params.ExtParam = (mfxExtBuffer**)&init_params;
sys->params.NumExtParam =
@@ -670,8 +640,6 @@ static void Close(vlc_object_t *this)
MFXClose(sys->session);
/* if (enc->fmt_out.p_extra) */
/* free(enc->fmt_out.p_extra); */
- if (sys->frames.size)
- qsv_frame_pool_Destroy(&sys->frames);
async_task_t_fifo_Release(&sys->packets);
free(sys);
}
@@ -753,10 +721,46 @@ static block_t *qsv_synchronize_block(encoder_t *enc, async_task_t *task)
return block;
}
+static int submit_frame(encoder_t *enc, picture_t *pic, QSVFrame **new_frame)
+{
+ encoder_sys_t *sys = enc->p_sys;
+ QSVFrame *qf = NULL;
+ int ret = get_free_frame(sys, &qf);
+ if (ret != VLC_SUCCESS) {
+ msg_Warn(enc, "Unable to find an unlocked surface in the pool");
+ return ret;
+ }
+
+ qf->pic = picture_Hold(pic);
+
+ qf->surface.Info = sys->params.mfx.FrameInfo;
+
+ // Specify picture structure at runtime.
+ if (pic->b_progressive)
+ qf->surface.Info.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
+ else if (pic->b_top_field_first)
+ qf->surface.Info.PicStruct = MFX_PICSTRUCT_FIELD_TFF;
+ else
+ qf->surface.Info.PicStruct = MFX_PICSTRUCT_FIELD_BFF;
+
+ //qf->surface.Data.Pitch = QSV_ALIGN(16, qf->surface.Info.Width);
+
+ qf->surface.Data.PitchLow = pic->p[0].i_pitch;
+ qf->surface.Data.Y = pic->p[0].p_pixels;
+ qf->surface.Data.UV = pic->p[1].p_pixels;
+
+ qf->surface.Data.TimeStamp = qsv_mtime_to_timestamp(pic->date - sys->offset_pts);
+
+ *new_frame = qf;
+
+ return VLC_SUCCESS;
+}
+
static async_task_t *encode_frame(encoder_t *enc, picture_t *pic)
{
encoder_sys_t *sys = enc->p_sys;
mfxStatus sts = MFX_ERR_MEMORY_ALLOC;
+ QSVFrame *qsv_frame = NULL;
mfxFrameSurface1 *surf = NULL;
async_task_t *task = calloc(1, sizeof(*task));
if (unlikely(task == NULL))
@@ -769,8 +773,8 @@ static async_task_t *encode_frame(encoder_t *enc, picture_t *pic)
if (!sys->offset_pts) // First frame
sys->offset_pts = pic->date;
- surf = qsv_frame_pool_Get(sys, pic);
- if (!surf) {
+ if (submit_frame(enc, pic, &qsv_frame) != VLC_SUCCESS)
+ {
msg_Warn(enc, "Unable to find an unlocked surface in the pool");
goto done;
}
@@ -790,6 +794,10 @@ static async_task_t *encode_frame(encoder_t *enc, picture_t *pic)
task->bs.MaxLength = task->block->i_buffer;
task->bs.Data = task->block->p_buffer;
+ if (qsv_frame) {
+ surf = &qsv_frame->surface;
+ }
+
for (;;) {
sts = MFXVideoENCODE_EncodeFrameAsync(sys->session, 0, surf, &task->bs, task->syncp);
if (sts != MFX_WRN_DEVICE_BUSY && sts != MFX_WRN_IN_EXECUTION)
More information about the vlc-commits
mailing list