[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