summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRodeo <[email protected]>2014-04-05 01:11:53 +0000
committerRodeo <[email protected]>2014-04-05 01:11:53 +0000
commit7ef7d26d46c0d0f8de762d1adc6745745fa14a72 (patch)
tree1b6cdd94e9124a1f709e76fc27229021d6355bcd
parenta031d4c918f9cfc20e821bae375b9530719e1c6f (diff)
enc_qsv: cleanup encoding loop, part 3.
Move encoding loop to its own function and simplify encqsvWork. git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@6150 b64f7644-9d1e-0410-96f1-a4d463321fa5
-rw-r--r--libhb/enc_qsv.c327
1 files changed, 169 insertions, 158 deletions
diff --git a/libhb/enc_qsv.c b/libhb/enc_qsv.c
index 9815e15f8..d71cca6c1 100644
--- a/libhb/enc_qsv.c
+++ b/libhb/enc_qsv.c
@@ -1575,171 +1575,52 @@ fail:
*pv->job->die = 1;
}
-static hb_buffer_t* link_buffer_list(hb_list_t *list)
+static int qsv_enc_work(hb_work_private_t *pv, av_qsv_list *qsv_atom,
+ mfxEncodeCtrl *ctrl, mfxFrameSurface1 *surface)
{
- hb_buffer_t *buf, *prev = NULL, *out = NULL;
-
- while ((buf = hb_list_item(list, 0)) != NULL)
- {
- hb_list_rem(list, buf);
-
- if (prev == NULL)
- {
- prev = out = buf;
- }
- else
- {
- prev->next = buf;
- prev = buf;
- }
- }
-
- return out;
-}
-
-int encqsvWork(hb_work_object_t *w, hb_buffer_t **buf_in, hb_buffer_t **buf_out)
-{
- hb_work_private_t *pv = w->private_data;
- hb_buffer_t *in = *buf_in;
- hb_job_t *job = pv->job;
-
- while (qsv_enc_init(pv) >= 2)
- {
- av_qsv_sleep(1); // encoding not initialized, wait and repeat the call
- }
-
- if (*job->die)
- {
- goto fail; // unrecoverable error, don't attempt to encode
- }
-
- av_qsv_list *received_item = NULL;
- mfxEncodeCtrl *work_control = NULL;
- mfxFrameSurface1 *work_surface = NULL;
- av_qsv_context *qsv = job->qsv.ctx;
- av_qsv_space *qsv_encode = job->qsv.ctx->enc_space;
-
- /*
- * EOF on input. Flush the decoder, then send the
- * EOF downstream to let the muxer know we're done.
- */
- if (in->size <= 0)
- {
- *buf_in = NULL; // don't let 'work_loop' close this buffer
- }
- else
- {
- if (pv->is_sys_mem)
- {
- mfxFrameInfo *info = &pv->param.videoParam->mfx.FrameInfo;
- int surface_index = av_qsv_get_free_surface(qsv_encode, qsv, info,
- QSV_PART_ANY);
- if (surface_index == -1)
- {
- hb_error("encqsv: av_qsv_get_free_surface failed");
- goto fail;
- }
-
- work_surface = qsv_encode->p_surfaces[surface_index];
- qsv_yuv420_to_nv12(pv->sws_context_to_nv12, work_surface, in);
- }
- else
- {
- received_item = in->qsv_details.qsv_atom;
- work_surface = av_qsv_get_last_stage(received_item)->out.p_surface;
-
- /*
- * QSV decoding fills the QSV context's dts_seq list, we need to
- * pop this surface's DTS so dts_seq doesn't grow unnecessarily.
- */
- av_qsv_dts_pop(qsv);
- }
-
- /*
- * Debugging code to check that the upstream modules have generated
- * a continuous, self-consistent frame stream.
- */
- if (pv->last_start > in->s.start)
- {
- hb_log("encqsv: input continuity error, "
- "last start %"PRId64" start %"PRId64"",
- pv->last_start, in->s.start);
- }
- pv->last_start = in->s.start;
-
- /* for DTS generation (when MSDK API < 1.6 or VFR) */
- if (pv->frames_in <= BFRM_DELAY_MAX)
- {
- pv->init_pts[pv->frames_in] = in->s.start;
- }
- if (pv->frames_in)
- {
- hb_qsv_add_new_dts(pv->list_dts, in->s.start);
- }
- pv->frames_in++;
-
- if (in->s.new_chap > 0 && job->chapter_markers)
- {
- save_chapter(pv, in);
-
- /* Chapters have to start with a keyframe, so request an IDR */
- work_control = &pv->force_keyframe;
- }
-
- /*
- * If interlaced encoding is requested during encoder initialization,
- * but the input mfxFrameSurface1 is flagged as progressive here,
- * the output bitstream will be progressive (according to MediaInfo).
- *
- * Assume the user knows what he's doing (say he is e.g. encoding a
- * progressive-flagged source using interlaced compression - he may
- * well have a good reason to do so; mis-flagged sources do exist).
- */
- work_surface->Info.PicStruct = pv->param.videoParam->mfx.FrameInfo.PicStruct;
- work_surface->Data.TimeStamp = in->s.start;
- save_frame_duration(pv, in);
- }
-
mfxStatus sts;
+ av_qsv_context *qsv_ctx = pv->job->qsv.ctx;
+ av_qsv_space *qsv_enc_space = pv->job->qsv.ctx->enc_space;
do
{
- int sync_idx = av_qsv_get_free_sync(qsv_encode, qsv);
+ int sync_idx = av_qsv_get_free_sync(qsv_enc_space, qsv_ctx);
if (sync_idx == -1)
{
hb_error("encqsv: av_qsv_get_free_sync failed");
- goto fail;
+ return -1;
}
- av_qsv_task *task = av_qsv_list_item(qsv_encode->tasks, pv->async_depth);
+ av_qsv_task *task = av_qsv_list_item(qsv_enc_space->tasks,
+ pv->async_depth);
do
{
- sts = MFXVideoENCODE_EncodeFrameAsync(qsv->mfx_session,
- work_control, work_surface, task->bs,
- qsv_encode->p_syncp[sync_idx]->p_sync);
+ sts = MFXVideoENCODE_EncodeFrameAsync(qsv_ctx->mfx_session,
+ ctrl, surface, task->bs,
+ qsv_enc_space->p_syncp[sync_idx]->p_sync);
if (sts == MFX_ERR_MORE_DATA || (sts >= MFX_ERR_NONE &&
sts != MFX_WRN_DEVICE_BUSY))
{
- if (work_surface != NULL && !pv->is_sys_mem)
+ if (surface != NULL && !pv->is_sys_mem)
{
- ff_qsv_atomic_dec(&work_surface->Data.Locked);
+ ff_qsv_atomic_dec(&surface->Data.Locked);
}
}
if (sts == MFX_ERR_MORE_DATA)
{
- if (work_surface != NULL && received_item != NULL)
+ if (qsv_atom != NULL)
{
- hb_list_add(pv->delayed_processing, received_item);
+ hb_list_add(pv->delayed_processing, qsv_atom);
}
- ff_qsv_atomic_dec(&qsv_encode->p_syncp[sync_idx]->in_use);
+ ff_qsv_atomic_dec(&qsv_enc_space->p_syncp[sync_idx]->in_use);
break;
}
else if (sts < MFX_ERR_NONE)
{
hb_error("encqsv: MFXVideoENCODE_EncodeFrameAsync failed (%d)", sts);
- goto fail;
+ return -1;
}
else if (sts == MFX_WRN_DEVICE_BUSY)
{
@@ -1750,22 +1631,22 @@ int encqsvWork(hb_work_object_t *w, hb_buffer_t **buf_in, hb_buffer_t **buf_out)
{
av_qsv_stage *new_stage = av_qsv_stage_init();
new_stage->type = AV_QSV_ENCODE;
- new_stage->in.p_surface = work_surface;
- new_stage->out.sync = qsv_encode->p_syncp[sync_idx];
+ new_stage->in.p_surface = surface;
+ new_stage->out.sync = qsv_enc_space->p_syncp[sync_idx];
new_stage->out.p_bs = task->bs;
task->stage = new_stage;
pv->async_depth++;
- if (received_item != NULL)
+ if (qsv_atom != NULL)
{
- av_qsv_add_stagee(&received_item, new_stage, HAVE_THREADS);
+ av_qsv_add_stagee(&qsv_atom, new_stage, HAVE_THREADS);
}
else
{
/* encode-only or flushing */
- av_qsv_list *new_atom = av_qsv_list_init(HAVE_THREADS);
- av_qsv_add_stagee(&new_atom, new_stage, HAVE_THREADS);
- av_qsv_list_add (qsv->pipes, new_atom);
+ av_qsv_list *new_qsv_atom = av_qsv_list_init(HAVE_THREADS);
+ av_qsv_add_stagee(&new_qsv_atom, new_stage, HAVE_THREADS);
+ av_qsv_list_add (qsv_ctx->pipes, new_qsv_atom);
}
int i = hb_list_count(pv->delayed_processing);
@@ -1775,14 +1656,14 @@ int encqsvWork(hb_work_object_t *w, hb_buffer_t **buf_in, hb_buffer_t **buf_out)
if (item != NULL)
{
- hb_list_rem(pv->delayed_processing, item);
- av_qsv_flush_stages(qsv->pipes, &item);
+ hb_list_rem(pv->delayed_processing, item);
+ av_qsv_flush_stages(qsv_ctx->pipes, &item);
}
}
break;
}
- ff_qsv_atomic_dec(&qsv_encode->p_syncp[sync_idx]->in_use);
+ ff_qsv_atomic_dec(&qsv_enc_space->p_syncp[sync_idx]->in_use);
break;
}
while (sts >= MFX_ERR_NONE);
@@ -1792,18 +1673,19 @@ int encqsvWork(hb_work_object_t *w, hb_buffer_t **buf_in, hb_buffer_t **buf_out)
if (pv->async_depth == 0) break;
/* we've done enough asynchronous operations or we're flushing */
- if (pv->async_depth >= pv->max_async_depth || work_surface == NULL)
+ if (pv->async_depth >= pv->max_async_depth || surface == NULL)
{
- av_qsv_task *task = av_qsv_list_item(qsv_encode->tasks, 0);
+ av_qsv_task *task = av_qsv_list_item(qsv_enc_space->tasks, 0);
pv->async_depth--;
/* perform a sync operation to get the output bitstream */
- av_qsv_wait_on_sync(qsv, task->stage);
+ av_qsv_wait_on_sync(qsv_ctx, task->stage);
if (task->bs->DataLength > 0)
{
- av_qsv_list *pipe = av_qsv_pipe_by_stage(qsv->pipes, task->stage);
- av_qsv_flush_stages(qsv->pipes, &pipe);
+ av_qsv_list *pipe = av_qsv_pipe_by_stage(qsv_ctx->pipes,
+ task->stage);
+ av_qsv_flush_stages(qsv_ctx->pipes, &pipe);
/* get the encoded frame from the bitstream */
qsv_bitstream_slurp(pv, task->bs);
@@ -1811,28 +1693,157 @@ int encqsvWork(hb_work_object_t *w, hb_buffer_t **buf_in, hb_buffer_t **buf_out)
/* shift for fifo */
if (pv->async_depth)
{
- av_qsv_list_rem(qsv_encode->tasks, task);
- av_qsv_list_add(qsv_encode->tasks, task);
+ av_qsv_list_rem(qsv_enc_space->tasks, task);
+ av_qsv_list_add(qsv_enc_space->tasks, task);
}
task->stage = NULL;
}
}
}
- while (work_surface == NULL);
+ while (surface == NULL);
}
- while (work_surface == NULL && sts != MFX_ERR_MORE_DATA);
+ while (surface == NULL && sts != MFX_ERR_MORE_DATA);
- if (work_surface == NULL)
+ return 0;
+}
+
+static hb_buffer_t* link_buffer_list(hb_list_t *list)
+{
+ hb_buffer_t *buf, *prev = NULL, *out = NULL;
+
+ while ((buf = hb_list_item(list, 0)) != NULL)
+ {
+ hb_list_rem(list, buf);
+
+ if (prev == NULL)
+ {
+ prev = out = buf;
+ }
+ else
+ {
+ prev->next = buf;
+ prev = buf;
+ }
+ }
+
+ return out;
+}
+
+int encqsvWork(hb_work_object_t *w, hb_buffer_t **buf_in, hb_buffer_t **buf_out)
+{
+ hb_work_private_t *pv = w->private_data;
+ hb_buffer_t *in = *buf_in;
+ hb_job_t *job = pv->job;
+
+ while (qsv_enc_init(pv) >= 2)
+ {
+ av_qsv_sleep(1); // encoding not initialized, wait and repeat the call
+ }
+
+ if (*job->die)
+ {
+ goto fail; // unrecoverable error, don't attempt to encode
+ }
+
+ /*
+ * EOF on input. Flush the decoder, then send the
+ * EOF downstream to let the muxer know we're done.
+ */
+ if (in->size <= 0)
{
+ qsv_enc_work(pv, NULL, NULL, NULL);
hb_list_add(pv->encoded_frames, in);
*buf_out = link_buffer_list(pv->encoded_frames);
+ *buf_in = NULL; // don't let 'work_loop' close this buffer
return HB_WORK_DONE;
}
+
+ mfxEncodeCtrl *ctrl = NULL;
+ mfxFrameSurface1 *surface = NULL;
+ av_qsv_list *qsv_atom = NULL;
+ av_qsv_context *qsv_ctx = job->qsv.ctx;
+ av_qsv_space *qsv_enc_space = job->qsv.ctx->enc_space;
+
+ if (pv->is_sys_mem)
+ {
+ mfxFrameInfo *info = &pv->param.videoParam->mfx.FrameInfo;
+ int surface_index = av_qsv_get_free_surface(qsv_enc_space, qsv_ctx, info,
+ QSV_PART_ANY);
+ if (surface_index == -1)
+ {
+ hb_error("encqsv: av_qsv_get_free_surface failed");
+ goto fail;
+ }
+
+ surface = qsv_enc_space->p_surfaces[surface_index];
+ qsv_yuv420_to_nv12(pv->sws_context_to_nv12, surface, in);
+ }
else
{
- *buf_out = link_buffer_list(pv->encoded_frames);
- return HB_WORK_OK;
+ qsv_atom = in->qsv_details.qsv_atom;
+ surface = av_qsv_get_last_stage(qsv_atom)->out.p_surface;
+
+ /*
+ * QSV decoding fills the QSV context's dts_seq list, we need to
+ * pop this surface's DTS so dts_seq doesn't grow unnecessarily.
+ */
+ av_qsv_dts_pop(qsv_ctx);
+ }
+
+ /*
+ * Debugging code to check that the upstream modules have generated
+ * a continuous, self-consistent frame stream.
+ */
+ if (pv->last_start > in->s.start)
+ {
+ hb_log("encqsv: input continuity error, "
+ "last start %"PRId64" start %"PRId64"",
+ pv->last_start, in->s.start);
+ }
+ pv->last_start = in->s.start;
+
+ /* for DTS generation (when MSDK API < 1.6 or VFR) */
+ if (pv->frames_in <= BFRM_DELAY_MAX)
+ {
+ pv->init_pts[pv->frames_in] = in->s.start;
+ }
+ if (pv->frames_in)
+ {
+ hb_qsv_add_new_dts(pv->list_dts, in->s.start);
}
+ pv->frames_in++;
+
+ if (in->s.new_chap > 0 && job->chapter_markers)
+ {
+ save_chapter(pv, in);
+
+ /* Chapters have to start with a keyframe, so request an IDR */
+ ctrl = &pv->force_keyframe;
+ }
+
+ /*
+ * If interlaced encoding is requested during encoder initialization,
+ * but the input mfxFrameSurface1 is flagged as progressive here,
+ * the output bitstream will be progressive (according to MediaInfo).
+ *
+ * Assume the user knows what he's doing (say he is e.g. encoding a
+ * progressive-flagged source using interlaced compression - he may
+ * well have a good reason to do so; mis-flagged sources do exist).
+ */
+ surface->Info.PicStruct = pv->param.videoParam->mfx.FrameInfo.PicStruct;
+ surface->Data.TimeStamp = in->s.start;
+ save_frame_duration(pv, in);
+
+ /*
+ * Now that the input surface is setup, we can encode it.
+ */
+ if (qsv_enc_work(pv, qsv_atom, ctrl, surface) < 0)
+ {
+ goto fail;
+ }
+
+ *buf_out = link_buffer_list(pv->encoded_frames);
+ return HB_WORK_OK;
fail:
if (*job->done_error == HB_ERROR_NONE)