diff options
author | Rodeo <[email protected]> | 2014-04-05 01:11:53 +0000 |
---|---|---|
committer | Rodeo <[email protected]> | 2014-04-05 01:11:53 +0000 |
commit | 7ef7d26d46c0d0f8de762d1adc6745745fa14a72 (patch) | |
tree | 1b6cdd94e9124a1f709e76fc27229021d6355bcd | |
parent | a031d4c918f9cfc20e821bae375b9530719e1c6f (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.c | 327 |
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) |