Merge commit '1bb56abb9b37bd208a66164339c92cad59b1087b'

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

Merged-by: Derek Buitenhuis <derek.buitenhuis@gmail.com>
pull/213/head
Derek Buitenhuis 9 years ago
commit ec1d8abfb9
  1. 77
      libavcodec/omx.c
  2. 2
      libavcodec/version.h

@ -224,6 +224,8 @@ typedef struct OMXCodecContext {
uint8_t *output_buf; uint8_t *output_buf;
int output_buf_size; int output_buf_size;
int input_zerocopy;
} OMXCodecContext; } OMXCodecContext;
static void append_buffer(pthread_mutex_t *mutex, pthread_cond_t *cond, 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) OMX_BUFFERHEADERTYPE *buffer)
{ {
OMXCodecContext *s = app_data; 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, append_buffer(&s->input_mutex, &s->input_cond,
&s->num_free_in_buffers, s->free_in_buffers, buffer); &s->num_free_in_buffers, s->free_in_buffers, buffer);
return OMX_ErrorNone; 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); 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) if (!s->in_buffer_headers || !s->free_in_buffers || !s->out_buffer_headers || !s->done_out_buffers)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
for (i = 0; i < s->num_in_buffers && err == OMX_ErrorNone; i++) 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); 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); CHECK(err);
s->num_in_buffers = i; s->num_in_buffers = i;
for (i = 0; i < s->num_out_buffers && err == OMX_ErrorNone; 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++) { for (i = 0; i < s->num_in_buffers; i++) {
OMX_BUFFERHEADERTYPE *buffer = get_buffer(&s->input_mutex, &s->input_cond, OMX_BUFFERHEADERTYPE *buffer = get_buffer(&s->input_mutex, &s->input_cond,
&s->num_free_in_buffers, s->free_in_buffers, 1); &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); OMX_FreeBuffer(s->handle, s->in_port, buffer);
} }
for (i = 0; i < s->num_out_buffers; i++) { 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_BUFFERHEADERTYPE *buffer;
OMX_ERRORTYPE err; OMX_ERRORTYPE err;
#if CONFIG_OMX_RPI
s->input_zerocopy = 1;
#endif
s->omx_context = omx_init(avctx, s->libname, s->libprefix); s->omx_context = omx_init(avctx, s->libname, s->libprefix);
if (!s->omx_context) if (!s->omx_context)
return AVERROR_ENCODER_NOT_FOUND; return AVERROR_ENCODER_NOT_FOUND;
@ -706,11 +729,57 @@ static int omx_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
if (frame) { if (frame) {
uint8_t *dst[4]; uint8_t *dst[4];
int linesize[4]; int linesize[4];
int need_copy;
buffer = get_buffer(&s->input_mutex, &s->input_cond, buffer = get_buffer(&s->input_mutex, &s->input_cond,
&s->num_free_in_buffers, s->free_in_buffers, 1); &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); 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->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
buffer->nOffset = 0; buffer->nOffset = 0;
// Convert the timestamps to microseconds; some encoders can ignore // 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 OFFSET(x) offsetof(OMXCodecContext, x)
#define VDE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_ENCODING_PARAM #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[] = { static const AVOption options[] = {
{ "omx_libname", "OpenMAX library name", OFFSET(libname), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VDE }, { "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 }, { "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 } { NULL }
}; };

@ -29,7 +29,7 @@
#define LIBAVCODEC_VERSION_MAJOR 57 #define LIBAVCODEC_VERSION_MAJOR 57
#define LIBAVCODEC_VERSION_MINOR 41 #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, \ #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \ LIBAVCODEC_VERSION_MINOR, \

Loading…
Cancel
Save