From 68bba1801eb49f749ea91e36905d3b99245fa03c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Christian=20K=C3=B6nig?= Date: Sun, 6 Apr 2014 17:07:41 +0200 Subject: [PATCH] st/omx/enc: separate input buffer private and task structure MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Keep tasks as linked list, this way we can associate more than one encoding task with each buffer. Signed-off-by: Christian König --- src/gallium/state_trackers/omx/vid_enc.c | 182 +++++++++++++++-------- src/gallium/state_trackers/omx/vid_enc.h | 4 + 2 files changed, 127 insertions(+), 59 deletions(-) diff --git a/src/gallium/state_trackers/omx/vid_enc.c b/src/gallium/state_trackers/omx/vid_enc.c index 080730bd294..88d15a97cbd 100644 --- a/src/gallium/state_trackers/omx/vid_enc.c +++ b/src/gallium/state_trackers/omx/vid_enc.c @@ -54,12 +54,18 @@ #include "entrypoint.h" #include "vid_enc.h" -struct input_buf_private { +struct encode_task { + struct list_head list; + struct pipe_video_buffer *buf; struct pipe_resource *bitstream; void *feedback; }; +struct input_buf_private { + struct list_head tasks; +}; + struct output_buf_private { struct pipe_resource *bitstream; struct pipe_transfer *transfer; @@ -79,6 +85,8 @@ static OMX_ERRORTYPE vid_enc_AllocateOutBuffer(omx_base_PortType *comp, OMX_INOU static OMX_ERRORTYPE vid_enc_FreeOutBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf); static void vid_enc_BufferEncoded(OMX_COMPONENTTYPE *comp, OMX_BUFFERHEADERTYPE* input, OMX_BUFFERHEADERTYPE* output); +static void enc_ReleaseTasks(struct list_head *head); + static void vid_enc_name(char str[OMX_MAX_STRINGNAME_SIZE]) { snprintf(str, OMX_MAX_STRINGNAME_SIZE, OMX_VID_ENC_BASE_NAME, driver_descriptor.name); @@ -243,6 +251,9 @@ static OMX_ERRORTYPE vid_enc_Constructor(OMX_COMPONENTTYPE *comp, OMX_STRING nam 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); + return OMX_ErrorNone; } @@ -251,6 +262,9 @@ static OMX_ERRORTYPE vid_enc_Destructor(OMX_COMPONENTTYPE *comp) vid_enc_PrivateType* priv = comp->pComponentPrivate; int i; + enc_ReleaseTasks(&priv->free_tasks); + enc_ReleaseTasks(&priv->used_tasks); + if (priv->ports) { for (i = 0; i < priv->sPortTypesParam[OMX_PortDomainVideo].nPorts; ++i) { if(priv->ports[i]) @@ -563,9 +577,10 @@ static OMX_ERRORTYPE vid_enc_MessageHandler(OMX_COMPONENTTYPE* comp, internalReq static OMX_ERRORTYPE vid_enc_FreeInBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf) { struct input_buf_private *inp = buf->pInputPortPrivate; - pipe_resource_reference(&inp->bitstream, NULL); - inp->buf->destroy(inp->buf); - FREE(inp); + if (inp) { + enc_ReleaseTasks(&inp->tasks); + FREE(inp); + } return base_port_FreeBuffer(port, idx, buf); } @@ -607,22 +622,25 @@ static OMX_ERRORTYPE vid_enc_FreeOutBuffer(omx_base_PortType *port, OMX_U32 idx, return base_port_FreeBuffer(port, idx, buf); } -static OMX_ERRORTYPE enc_NeedInputPortPrivate(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf) +static struct encode_task *enc_NeedTask(omx_base_PortType *port) { + OMX_VIDEO_PORTDEFINITIONTYPE *def = &port->sPortParam.format.video; OMX_COMPONENTTYPE* comp = port->standCompContainer; vid_enc_PrivateType *priv = comp->pComponentPrivate; - OMX_VIDEO_PORTDEFINITIONTYPE *def = &port->sPortParam.format.video; - struct input_buf_private **inp = (struct input_buf_private **)&buf->pInputPortPrivate; + struct pipe_video_buffer templat = {}; + struct encode_task *task; - if (*inp) { - pipe_resource_reference(&(*inp)->bitstream, NULL); - return OMX_ErrorNone; + if (!LIST_IS_EMPTY(&priv->free_tasks)) { + task = LIST_ENTRY(struct encode_task, priv->free_tasks.next, list); + LIST_DEL(&task->list); + return task; } - if (!(*inp = CALLOC(1, sizeof(struct input_buf_private)))) { - return OMX_ErrorInsufficientResources; - } + /* allocate a new one */ + task = CALLOC_STRUCT(encode_task); + if (!task) + return NULL; templat.buffer_format = PIPE_FORMAT_NV12; templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420; @@ -630,25 +648,46 @@ static OMX_ERRORTYPE enc_NeedInputPortPrivate(omx_base_PortType *port, OMX_BUFFE templat.height = def->nFrameHeight; templat.interlaced = false; - if (!((*inp)->buf = priv->s_pipe->create_video_buffer(priv->s_pipe, &templat))) { - FREE(*inp); - return OMX_ErrorInsufficientResources; + task->buf = priv->s_pipe->create_video_buffer(priv->s_pipe, &templat); + if (!task->buf) { + FREE(task); + return NULL; } - return OMX_ErrorNone; + return task; +} + +static void enc_MoveTasks(struct list_head *from, struct list_head *to) +{ + to->prev->next = from->next; + from->next->prev = to->prev; + from->prev->next = to; + to->prev = from->prev; + LIST_INITHEAD(from); } -static OMX_ERRORTYPE enc_LoadImage(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf) +static void enc_ReleaseTasks(struct list_head *head) +{ + struct encode_task *i, *next; + + LIST_FOR_EACH_ENTRY_SAFE(i, next, head, list) { + pipe_resource_reference(&i->bitstream, NULL); + i->buf->destroy(i->buf); + FREE(i); + } +} + +static OMX_ERRORTYPE enc_LoadImage(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf, + struct pipe_video_buffer *vbuf) { OMX_COMPONENTTYPE* comp = port->standCompContainer; vid_enc_PrivateType *priv = comp->pComponentPrivate; OMX_VIDEO_PORTDEFINITIONTYPE *def = &port->sPortParam.format.video; - struct input_buf_private *inp = buf->pInputPortPrivate; struct pipe_sampler_view **views; struct pipe_box box = {}; void *ptr; - views = inp->buf->get_sampler_view_planes(inp->buf); + views = vbuf->get_sampler_view_planes(vbuf); if (!views) return OMX_ErrorInsufficientResources; @@ -669,14 +708,12 @@ static OMX_ERRORTYPE enc_LoadImage(omx_base_PortType *port, OMX_BUFFERHEADERTYPE return OMX_ErrorNone; } -static void enc_ScaleInput(omx_base_PortType *port, - OMX_BUFFERHEADERTYPE *buf, struct pipe_video_buffer **vbuf, unsigned *size) +static void enc_ScaleInput(omx_base_PortType *port, struct pipe_video_buffer **vbuf, unsigned *size) { OMX_COMPONENTTYPE* comp = port->standCompContainer; vid_enc_PrivateType *priv = comp->pComponentPrivate; OMX_VIDEO_PORTDEFINITIONTYPE *def = &port->sPortParam.format.video; - struct pipe_video_buffer *src_buf = - ((struct input_buf_private *)buf->pInputPortPrivate)->buf; + struct pipe_video_buffer *src_buf = *vbuf; struct vl_compositor *compositor = &priv->compositor; struct vl_compositor_state *s = &priv->cstate; struct pipe_sampler_view **views; @@ -711,8 +748,7 @@ static void enc_ScaleInput(omx_base_PortType *port, priv->current_scale_buffer %= OMX_VID_ENC_NUM_SCALING_BUFFERS; } -static void enc_ControlPicture(omx_base_PortType *port, - struct pipe_h264_enc_picture_desc *picture) +static void enc_ControlPicture(omx_base_PortType *port, struct pipe_h264_enc_picture_desc *picture) { OMX_COMPONENTTYPE* comp = port->standCompContainer; vid_enc_PrivateType *priv = comp->pComponentPrivate; @@ -783,19 +819,48 @@ static void enc_ControlPicture(omx_base_PortType *port, priv->force_pic_type.IntraRefreshVOP = OMX_FALSE; } -static OMX_ERRORTYPE vid_enc_EncodeFrame(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf) +static void enc_HandleTask(omx_base_PortType *port, struct encode_task *task) { OMX_COMPONENTTYPE* comp = port->standCompContainer; vid_enc_PrivateType *priv = comp->pComponentPrivate; unsigned size = priv->ports[OMX_BASE_FILTER_OUTPUTPORT_INDEX]->sPortParam.nBufferSize; - struct pipe_h264_enc_picture_desc picture; - struct input_buf_private *inp; - struct pipe_video_buffer *vbuf; + struct pipe_video_buffer *vbuf = task->buf; + struct pipe_h264_enc_picture_desc picture = {}; + + /* -------------- scale input image --------- */ + enc_ScaleInput(port, &vbuf, &size); + priv->s_pipe->flush(priv->s_pipe, NULL, 0); + + /* -------------- allocate output buffer --------- */ + task->bitstream = pipe_buffer_create(priv->s_pipe->screen, PIPE_BIND_VERTEX_BUFFER, + PIPE_USAGE_STREAM, size); + enc_ControlPicture(port, &picture); + + /* -------------- encode frame --------- */ + priv->codec->begin_frame(priv->codec, vbuf, &picture.base); + priv->codec->encode_bitstream(priv->codec, vbuf, task->bitstream, &task->feedback); + priv->codec->end_frame(priv->codec, vbuf, &picture.base); +} + +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; + struct encode_task *task; OMX_ERRORTYPE err; - err = enc_NeedInputPortPrivate(port, buf); - if (err != OMX_ErrorNone) - return err; + if (!inp) { + inp = buf->pInputPortPrivate = CALLOC_STRUCT(input_buf_private); + if (!inp) + return OMX_ErrorInsufficientResources; + LIST_INITHEAD(&inp->tasks); + } else + enc_MoveTasks(&inp->tasks, &priv->free_tasks); + + task = enc_NeedTask(port); + if (!task) + return OMX_ErrorInsufficientResources; if (buf->nFilledLen == 0) { if (buf->nFlags & OMX_BUFFERFLAG_EOS) @@ -803,47 +868,45 @@ static OMX_ERRORTYPE vid_enc_EncodeFrame(omx_base_PortType *port, OMX_BUFFERHEAD return base_port_SendBufferFunction(port, buf); } - inp = buf->pInputPortPrivate; if (buf->pOutputPortPrivate) { - vbuf = buf->pOutputPortPrivate; - buf->pOutputPortPrivate = inp->buf; - inp->buf = vbuf; + struct pipe_video_buffer *vbuf = buf->pOutputPortPrivate; + buf->pOutputPortPrivate = task->buf; + task->buf = vbuf; } else { /* ------- load input image into video buffer ---- */ - err = enc_LoadImage(port, buf); + err = enc_LoadImage(port, buf, task->buf); if (err != OMX_ErrorNone) return err; } - vbuf = inp->buf; - - /* -------------- scale input image --------- */ - enc_ScaleInput(port, buf, &vbuf, &size); - priv->s_pipe->flush(priv->s_pipe, NULL, 0); - /* -------------- allocate output buffer --------- */ - inp->bitstream = pipe_buffer_create(priv->s_pipe->screen, PIPE_BIND_VERTEX_BUFFER, - PIPE_USAGE_STREAM, size); - enc_ControlPicture(port, &picture); + enc_HandleTask(port, task); - /* -------------- encode frame --------- */ - priv->codec->begin_frame(priv->codec, vbuf, &picture.base); - priv->codec->encode_bitstream(priv->codec, vbuf, inp->bitstream, &inp->feedback); - priv->codec->end_frame(priv->codec, vbuf, &picture.base); + /* put list of encode operations on input buffer */ + LIST_ADDTAIL(&task->list, &inp->tasks); return base_port_SendBufferFunction(port, buf); } static void vid_enc_BufferEncoded(OMX_COMPONENTTYPE *comp, OMX_BUFFERHEADERTYPE* input, OMX_BUFFERHEADERTYPE* output) { - struct input_buf_private *inp = input->pInputPortPrivate; vid_enc_PrivateType *priv = comp->pComponentPrivate; struct output_buf_private *outp = output->pOutputPortPrivate; + struct input_buf_private *inp = input->pInputPortPrivate; + struct encode_task *task; struct pipe_box box = {}; unsigned size; - input->nFilledLen = 0; /* mark buffer as empty */ + if (!inp || LIST_IS_EMPTY(&inp->tasks)) { + input->nFilledLen = 0; /* mark buffer as empty */ + enc_MoveTasks(&priv->used_tasks, &inp->tasks); + return; + } + + task = LIST_ENTRY(struct encode_task, inp->tasks.next, list); + LIST_DEL(&task->list); + LIST_ADDTAIL(&task->list, &priv->used_tasks); - if (!inp->bitstream) + if (!task->bitstream) return; /* ------------- map result buffer ----------------- */ @@ -851,11 +914,12 @@ static void vid_enc_BufferEncoded(OMX_COMPONENTTYPE *comp, OMX_BUFFERHEADERTYPE* if (outp->transfer) pipe_transfer_unmap(priv->t_pipe, outp->transfer); - pipe_resource_reference(&outp->bitstream, inp->bitstream); + pipe_resource_reference(&outp->bitstream, task->bitstream); + pipe_resource_reference(&task->bitstream, NULL); - box.width = inp->bitstream->width0; - box.height = inp->bitstream->height0; - box.depth = inp->bitstream->depth0; + box.width = outp->bitstream->width0; + box.height = outp->bitstream->height0; + box.depth = outp->bitstream->depth0; output->pBuffer = priv->t_pipe->transfer_map(priv->t_pipe, outp->bitstream, 0, PIPE_TRANSFER_READ_WRITE, @@ -863,7 +927,7 @@ static void vid_enc_BufferEncoded(OMX_COMPONENTTYPE *comp, OMX_BUFFERHEADERTYPE* /* ------------- get size of result ----------------- */ - priv->codec->get_feedback(priv->codec, inp->feedback, &size); + priv->codec->get_feedback(priv->codec, task->feedback, &size); output->nOffset = 0; output->nFilledLen = size; /* mark buffer as full */ diff --git a/src/gallium/state_trackers/omx/vid_enc.h b/src/gallium/state_trackers/omx/vid_enc.h index a3fdfaeec6c..76bfbea0917 100644 --- a/src/gallium/state_trackers/omx/vid_enc.h +++ b/src/gallium/state_trackers/omx/vid_enc.h @@ -41,6 +41,8 @@ #include #include +#include "util/u_double_list.h" + #include "vl/vl_defines.h" #include "vl/vl_compositor.h" @@ -67,6 +69,8 @@ DERIVEDCLASS(vid_enc_PrivateType, omx_base_filter_PrivateType) struct pipe_context *s_pipe; \ struct pipe_context *t_pipe; \ struct pipe_video_codec *codec; \ + struct list_head free_tasks; \ + struct list_head used_tasks; \ OMX_U32 frame_rate; \ OMX_U32 frame_num; \ OMX_VIDEO_PARAM_BITRATETYPE bitrate; \ -- 2.30.2