Merge commit '1bb56abb9b37bd208a66164339c92cad59b1087b'

* commit '1bb56abb9b37bd208a66164339c92cad59b1087b':
  omx: Add support for zerocopy input of frames

Merged-by: Derek Buitenhuis <derek.buitenhuis@gmail.com>
This commit is contained in:
Derek Buitenhuis 2016-05-11 19:24:26 +01:00
commit ec1d8abfb9
2 changed files with 75 additions and 4 deletions

View File

@ -224,6 +224,8 @@ typedef struct OMXCodecContext {
uint8_t *output_buf;
int output_buf_size;
int input_zerocopy;
} OMXCodecContext;
static void append_buffer(pthread_mutex_t *mutex, pthread_cond_t *cond,
@ -303,6 +305,15 @@ static OMX_ERRORTYPE empty_buffer_done(OMX_HANDLETYPE component, OMX_PTR app_dat
OMX_BUFFERHEADERTYPE *buffer)
{
OMXCodecContext *s = app_data;
if (s->input_zerocopy) {
if (buffer->pAppPrivate) {
if (buffer->pOutputPortPrivate)
av_free(buffer->pAppPrivate);
else
av_frame_free((AVFrame**)&buffer->pAppPrivate);
buffer->pAppPrivate = NULL;
}
}
append_buffer(&s->input_mutex, &s->input_cond,
&s->num_free_in_buffers, s->free_in_buffers, buffer);
return OMX_ErrorNone;
@ -525,8 +536,14 @@ static av_cold int omx_component_init(AVCodecContext *avctx, const char *role)
s->done_out_buffers = av_mallocz(sizeof(OMX_BUFFERHEADERTYPE*) * s->num_out_buffers);
if (!s->in_buffer_headers || !s->free_in_buffers || !s->out_buffer_headers || !s->done_out_buffers)
return AVERROR(ENOMEM);
for (i = 0; i < s->num_in_buffers && err == OMX_ErrorNone; i++)
err = OMX_AllocateBuffer(s->handle, &s->in_buffer_headers[i], s->in_port, s, in_port_params.nBufferSize);
for (i = 0; i < s->num_in_buffers && err == OMX_ErrorNone; i++) {
if (s->input_zerocopy)
err = OMX_UseBuffer(s->handle, &s->in_buffer_headers[i], s->in_port, s, in_port_params.nBufferSize, NULL);
else
err = OMX_AllocateBuffer(s->handle, &s->in_buffer_headers[i], s->in_port, s, in_port_params.nBufferSize);
if (err == OMX_ErrorNone)
s->in_buffer_headers[i]->pAppPrivate = s->in_buffer_headers[i]->pOutputPortPrivate = NULL;
}
CHECK(err);
s->num_in_buffers = i;
for (i = 0; i < s->num_out_buffers && err == OMX_ErrorNone; i++)
@ -571,6 +588,8 @@ static av_cold void cleanup(OMXCodecContext *s)
for (i = 0; i < s->num_in_buffers; i++) {
OMX_BUFFERHEADERTYPE *buffer = get_buffer(&s->input_mutex, &s->input_cond,
&s->num_free_in_buffers, s->free_in_buffers, 1);
if (s->input_zerocopy)
buffer->pBuffer = NULL;
OMX_FreeBuffer(s->handle, s->in_port, buffer);
}
for (i = 0; i < s->num_out_buffers; i++) {
@ -611,6 +630,10 @@ static av_cold int omx_encode_init(AVCodecContext *avctx)
OMX_BUFFERHEADERTYPE *buffer;
OMX_ERRORTYPE err;
#if CONFIG_OMX_RPI
s->input_zerocopy = 1;
#endif
s->omx_context = omx_init(avctx, s->libname, s->libprefix);
if (!s->omx_context)
return AVERROR_ENCODER_NOT_FOUND;
@ -706,11 +729,57 @@ static int omx_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
if (frame) {
uint8_t *dst[4];
int linesize[4];
int need_copy;
buffer = get_buffer(&s->input_mutex, &s->input_cond,
&s->num_free_in_buffers, s->free_in_buffers, 1);
buffer->nFilledLen = av_image_fill_arrays(dst, linesize, buffer->pBuffer, avctx->pix_fmt, s->stride, s->plane_size, 1);
av_image_copy(dst, linesize, (const uint8_t**) frame->data, frame->linesize, avctx->pix_fmt, avctx->width, avctx->height);
if (s->input_zerocopy) {
uint8_t *src[4] = { NULL };
int src_linesize[4];
av_image_fill_arrays(src, src_linesize, frame->data[0], avctx->pix_fmt, s->stride, s->plane_size, 1);
if (frame->linesize[0] == src_linesize[0] &&
frame->linesize[1] == src_linesize[1] &&
frame->linesize[2] == src_linesize[2] &&
frame->data[1] == src[1] &&
frame->data[2] == src[2]) {
// If the input frame happens to have all planes stored contiguously,
// with the right strides, just clone the frame and set the OMX
// buffer header to point to it
AVFrame *local = av_frame_clone(frame);
if (!local) {
// Return the buffer to the queue so it's not lost
append_buffer(&s->input_mutex, &s->input_cond, &s->num_free_in_buffers, s->free_in_buffers, buffer);
return AVERROR(ENOMEM);
} else {
buffer->pAppPrivate = local;
buffer->pOutputPortPrivate = NULL;
buffer->pBuffer = local->data[0];
need_copy = 0;
}
} else {
// If not, we need to allocate a new buffer with the right
// size and copy the input frame into it.
uint8_t *buf = av_malloc(av_image_get_buffer_size(avctx->pix_fmt, s->stride, s->plane_size, 1));
if (!buf) {
// Return the buffer to the queue so it's not lost
append_buffer(&s->input_mutex, &s->input_cond, &s->num_free_in_buffers, s->free_in_buffers, buffer);
return AVERROR(ENOMEM);
} else {
buffer->pAppPrivate = buf;
// Mark that pAppPrivate is an av_malloc'ed buffer, not an AVFrame
buffer->pOutputPortPrivate = (void*) 1;
buffer->pBuffer = buf;
need_copy = 1;
buffer->nFilledLen = av_image_fill_arrays(dst, linesize, buffer->pBuffer, avctx->pix_fmt, s->stride, s->plane_size, 1);
}
}
} else {
need_copy = 1;
}
if (need_copy)
av_image_copy(dst, linesize, (const uint8_t**) frame->data, frame->linesize, avctx->pix_fmt, avctx->width, avctx->height);
buffer->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
buffer->nOffset = 0;
// Convert the timestamps to microseconds; some encoders can ignore
@ -808,9 +877,11 @@ static av_cold int omx_encode_end(AVCodecContext *avctx)
#define OFFSET(x) offsetof(OMXCodecContext, x)
#define VDE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_ENCODING_PARAM
#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
{ "omx_libname", "OpenMAX library name", OFFSET(libname), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VDE },
{ "omx_libprefix", "OpenMAX library prefix", OFFSET(libprefix), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VDE },
{ "zerocopy", "Try to avoid copying input frames if possible", OFFSET(input_zerocopy), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
{ NULL }
};

View File

@ -29,7 +29,7 @@
#define LIBAVCODEC_VERSION_MAJOR 57
#define LIBAVCODEC_VERSION_MINOR 41
#define LIBAVCODEC_VERSION_MICRO 101
#define LIBAVCODEC_VERSION_MICRO 102
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \