[Mesa-dev] [PATCH 6/7] st/omx/enc: implement frame reordering and B-frames
Christian König
deathsimple at vodafone.de
Wed Apr 9 02:21:01 PDT 2014
From: Christian König <christian.koenig at amd.com>
Signed-off-by: Christian König <christian.koenig at amd.com>
---
src/gallium/state_trackers/omx/vid_enc.c | 91 +++++++++++++++++++++++++-------
src/gallium/state_trackers/omx/vid_enc.h | 5 +-
2 files changed, 76 insertions(+), 20 deletions(-)
diff --git a/src/gallium/state_trackers/omx/vid_enc.c b/src/gallium/state_trackers/omx/vid_enc.c
index 88d15a9..7633cd6 100644
--- a/src/gallium/state_trackers/omx/vid_enc.c
+++ b/src/gallium/state_trackers/omx/vid_enc.c
@@ -58,6 +58,7 @@ struct encode_task {
struct list_head list;
struct pipe_video_buffer *buf;
+ unsigned pic_order_cnt;
struct pipe_resource *bitstream;
void *feedback;
};
@@ -247,12 +248,14 @@ static OMX_ERRORTYPE vid_enc_Constructor(OMX_COMPONENTTYPE *comp, OMX_STRING nam
priv->force_pic_type.IntraRefreshVOP = OMX_FALSE;
priv->frame_num = 0;
+ priv->pic_order_cnt = 0;
priv->scale.xWidth = OMX_VID_ENC_SCALING_WIDTH_DEFAULT;
priv->scale.xHeight = OMX_VID_ENC_SCALING_WIDTH_DEFAULT;
LIST_INITHEAD(&priv->free_tasks);
LIST_INITHEAD(&priv->used_tasks);
+ LIST_INITHEAD(&priv->b_frames);
return OMX_ErrorNone;
}
@@ -264,6 +267,7 @@ static OMX_ERRORTYPE vid_enc_Destructor(OMX_COMPONENTTYPE *comp)
enc_ReleaseTasks(&priv->free_tasks);
enc_ReleaseTasks(&priv->used_tasks);
+ enc_ReleaseTasks(&priv->b_frames);
if (priv->ports) {
for (i = 0; i < priv->sPortTypesParam[OMX_PortDomainVideo].nPorts; ++i) {
@@ -803,23 +807,13 @@ static void enc_ControlPicture(omx_base_PortType *port, struct pipe_h264_enc_pic
picture->quant_p_frames = priv->quant.nQpP;
picture->quant_b_frames = priv->quant.nQpB;
- if (!(priv->frame_num % OMX_VID_ENC_IDR_PERIOD_DEFAULT) || priv->force_pic_type.IntraRefreshVOP) {
- picture->picture_type = PIPE_H264_ENC_PICTURE_TYPE_IDR;
- picture->ref_idx_l0 = 0;
- picture->ref_idx_l1 = 0;
- priv->frame_num = 0;
- } else {
- picture->picture_type = PIPE_H264_ENC_PICTURE_TYPE_P;
- picture->ref_idx_l0 = priv->frame_num - 1;
- picture->ref_idx_l1 = 0;
- }
-
- picture->frame_num = priv->frame_num++;
- picture->pic_order_cnt = picture->frame_num;
- priv->force_pic_type.IntraRefreshVOP = OMX_FALSE;
+ picture->frame_num = priv->frame_num;
+ picture->ref_idx_l0 = priv->ref_idx_l0;
+ picture->ref_idx_l1 = priv->ref_idx_l1;
}
-static void enc_HandleTask(omx_base_PortType *port, struct encode_task *task)
+static void enc_HandleTask(omx_base_PortType *port, struct encode_task *task,
+ enum pipe_h264_enc_picture_type picture_type)
{
OMX_COMPONENTTYPE* comp = port->standCompContainer;
vid_enc_PrivateType *priv = comp->pComponentPrivate;
@@ -834,6 +828,9 @@ static void enc_HandleTask(omx_base_PortType *port, struct encode_task *task)
/* -------------- allocate output buffer --------- */
task->bitstream = pipe_buffer_create(priv->s_pipe->screen, PIPE_BIND_VERTEX_BUFFER,
PIPE_USAGE_STREAM, size);
+
+ picture.picture_type = picture_type;
+ picture.pic_order_cnt = task->pic_order_cnt;
enc_ControlPicture(port, &picture);
/* -------------- encode frame --------- */
@@ -842,11 +839,39 @@ static void enc_HandleTask(omx_base_PortType *port, struct encode_task *task)
priv->codec->end_frame(priv->codec, vbuf, &picture.base);
}
+static void enc_ClearBframes(omx_base_PortType *port, struct input_buf_private *inp)
+{
+ OMX_COMPONENTTYPE* comp = port->standCompContainer;
+ vid_enc_PrivateType *priv = comp->pComponentPrivate;
+ struct encode_task *task;
+
+ if (LIST_IS_EMPTY(&priv->b_frames))
+ return;
+
+ task = LIST_ENTRY(struct encode_task, priv->b_frames.prev, list);
+ LIST_DEL(&task->list);
+
+ /* promote last from to P frame */
+ priv->ref_idx_l0 = priv->ref_idx_l1;
+ enc_HandleTask(port, task, PIPE_H264_ENC_PICTURE_TYPE_P);
+ LIST_ADDTAIL(&task->list, &inp->tasks);
+ priv->ref_idx_l1 = priv->frame_num++;
+
+ /* handle B frames */
+ LIST_FOR_EACH_ENTRY(task, &priv->b_frames, list) {
+ enc_HandleTask(port, task, PIPE_H264_ENC_PICTURE_TYPE_B);
+ priv->ref_idx_l0 = priv->frame_num++;
+ }
+
+ enc_MoveTasks(&priv->b_frames, &inp->tasks);
+}
+
static OMX_ERRORTYPE vid_enc_EncodeFrame(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf)
{
OMX_COMPONENTTYPE* comp = port->standCompContainer;
vid_enc_PrivateType *priv = comp->pComponentPrivate;
struct input_buf_private *inp = buf->pInputPortPrivate;
+ enum pipe_h264_enc_picture_type picture_type;
struct encode_task *task;
OMX_ERRORTYPE err;
@@ -863,8 +888,10 @@ static OMX_ERRORTYPE vid_enc_EncodeFrame(omx_base_PortType *port, OMX_BUFFERHEAD
return OMX_ErrorInsufficientResources;
if (buf->nFilledLen == 0) {
- if (buf->nFlags & OMX_BUFFERFLAG_EOS)
+ if (buf->nFlags & OMX_BUFFERFLAG_EOS) {
buf->nFilledLen = buf->nAllocLen;
+ enc_ClearBframes(port, inp);
+ }
return base_port_SendBufferFunction(port, buf);
}
@@ -879,10 +906,36 @@ static OMX_ERRORTYPE vid_enc_EncodeFrame(omx_base_PortType *port, OMX_BUFFERHEAD
return err;
}
- enc_HandleTask(port, task);
+ /* -------------- determine picture type --------- */
+ if (!(priv->pic_order_cnt % OMX_VID_ENC_IDR_PERIOD_DEFAULT) || priv->force_pic_type.IntraRefreshVOP) {
+ enc_ClearBframes(port, inp);
+ picture_type = PIPE_H264_ENC_PICTURE_TYPE_IDR;
+ priv->force_pic_type.IntraRefreshVOP = OMX_FALSE;
+ priv->frame_num = 0;
+ } else {
+ picture_type = PIPE_H264_ENC_PICTURE_TYPE_P;
+ }
+
+ task->pic_order_cnt = priv->pic_order_cnt++;
- /* put list of encode operations on input buffer */
- LIST_ADDTAIL(&task->list, &inp->tasks);
+ if (picture_type == PIPE_H264_ENC_PICTURE_TYPE_B) {
+ /* put frame at the tail of the queue */
+ LIST_ADDTAIL(&task->list, &priv->b_frames);
+ } else {
+ /* handle I or P frame */
+ priv->ref_idx_l0 = priv->ref_idx_l1;
+ enc_HandleTask(port, task, picture_type);
+ LIST_ADDTAIL(&task->list, &inp->tasks);
+ priv->ref_idx_l1 = priv->frame_num++;
+
+ /* handle B frames */
+ LIST_FOR_EACH_ENTRY(task, &priv->b_frames, list) {
+ enc_HandleTask(port, task, PIPE_H264_ENC_PICTURE_TYPE_B);
+ priv->ref_idx_l0 = priv->frame_num++;
+ }
+
+ enc_MoveTasks(&priv->b_frames, &inp->tasks);
+ }
return base_port_SendBufferFunction(port, buf);
}
diff --git a/src/gallium/state_trackers/omx/vid_enc.h b/src/gallium/state_trackers/omx/vid_enc.h
index 76bfbea..6f6226a 100644
--- a/src/gallium/state_trackers/omx/vid_enc.h
+++ b/src/gallium/state_trackers/omx/vid_enc.h
@@ -56,7 +56,7 @@
#define OMX_VID_ENC_CONTROL_FRAME_RATE_DEN_DEFAULT 1001
#define OMX_VID_ENC_QUANT_I_FRAMES_DEFAULT 0x1c
#define OMX_VID_ENC_QUANT_P_FRAMES_DEFAULT 0x1c
-#define OMX_VID_ENC_QUANT_B_FRAMES_DEFAULT 0
+#define OMX_VID_ENC_QUANT_B_FRAMES_DEFAULT 0x1c
#define OMX_VID_ENC_SCALING_WIDTH_DEFAULT 0xffffffff
#define OMX_VID_ENC_SCALING_HEIGHT_DEFAULT 0xffffffff
#define OMX_VID_ENC_IDR_PERIOD_DEFAULT 1000
@@ -71,8 +71,11 @@ DERIVEDCLASS(vid_enc_PrivateType, omx_base_filter_PrivateType)
struct pipe_video_codec *codec; \
struct list_head free_tasks; \
struct list_head used_tasks; \
+ struct list_head b_frames; \
OMX_U32 frame_rate; \
OMX_U32 frame_num; \
+ OMX_U32 pic_order_cnt; \
+ OMX_U32 ref_idx_l0, ref_idx_l1; \
OMX_VIDEO_PARAM_BITRATETYPE bitrate; \
OMX_VIDEO_PARAM_QUANTIZATIONTYPE quant; \
OMX_CONFIG_INTRAREFRESHVOPTYPE force_pic_type; \
--
1.8.3.2
More information about the mesa-dev
mailing list