diff options
author | Derek Buitenhuis <derek.buitenhuis@gmail.com> | 2016-05-11 19:24:26 +0100 |
---|---|---|
committer | Derek Buitenhuis <derek.buitenhuis@gmail.com> | 2016-05-11 19:24:26 +0100 |
commit | ec1d8abfb9bf91b84d0d3a89b6f62b4bdefab301 (patch) | |
tree | 2a26b8621703b04fa5240a0e43703964370d9a38 /libavcodec/omx.c | |
parent | e330ab0fb7cb140cfde98077e1a953c200282087 (diff) | |
parent | 1bb56abb9b37bd208a66164339c92cad59b1087b (diff) | |
download | ffmpeg-ec1d8abfb9bf91b84d0d3a89b6f62b4bdefab301.tar.gz |
Merge commit '1bb56abb9b37bd208a66164339c92cad59b1087b'
* commit '1bb56abb9b37bd208a66164339c92cad59b1087b':
omx: Add support for zerocopy input of frames
Merged-by: Derek Buitenhuis <derek.buitenhuis@gmail.com>
Diffstat (limited to 'libavcodec/omx.c')
-rw-r--r-- | libavcodec/omx.c | 77 |
1 files changed, 74 insertions, 3 deletions
diff --git a/libavcodec/omx.c b/libavcodec/omx.c index c219ec0775..887fc56378 100644 --- a/libavcodec/omx.c +++ b/libavcodec/omx.c @@ -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 } }; |