st/omx/enc: separate input buffer private and task structure

Keep tasks as linked list, this way we can associate
more than one encoding task with each buffer.

Signed-off-by: Christian König <christian.koenig@amd.com>
This commit is contained in:
Christian König
2014-04-06 17:07:41 +02:00
parent 7806dbeb70
commit 68bba1801e
2 changed files with 127 additions and 59 deletions
+123 -59
View File
@@ -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 OMX_ERRORTYPE enc_LoadImage(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf)
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 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);
enc_HandleTask(port, task);
/* -------------- allocate output buffer --------- */
inp->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, 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;
}
if (!inp->bitstream)
task = LIST_ENTRY(struct encode_task, inp->tasks.next, list);
LIST_DEL(&task->list);
LIST_ADDTAIL(&task->list, &priv->used_tasks);
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 */
+4
View File
@@ -41,6 +41,8 @@
#include <bellagio/st_static_component_loader.h>
#include <bellagio/omx_base_filter.h>
#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; \