|
|
|
@@ -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 } |
|
|
|
}; |
|
|
|
|
|
|
|
|