Änderungen Gruppe 30_10_2022 V2
This commit is contained in:
@@ -0,0 +1 @@
|
||||
add_subdirectory(brcmjpeg)
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
add_library(brcmjpeg SHARED brcmjpeg.c)
|
||||
target_link_libraries(brcmjpeg mmal_core mmal_util mmal_vc_client)
|
||||
|
||||
include_directories(../../../../host_applications/linux/libs/sm)
|
||||
add_executable(brcmjpeg_test brcmjpeg_test.c)
|
||||
target_link_libraries(brcmjpeg_test brcmjpeg vcsm vcos)
|
||||
+914
@@ -0,0 +1,914 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* Jpeg encoder and decoder library using the hardware jpeg codec
|
||||
*/
|
||||
|
||||
#include "mmal.h"
|
||||
#include "util/mmal_component_wrapper.h"
|
||||
#include "util/mmal_util_params.h"
|
||||
#include "mmal_logging.h"
|
||||
#include "brcmjpeg.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Defines
|
||||
*******************************************************************************/
|
||||
#define MMAL_COMPONENT_IMAGE_DECODE "vc.aggregator.pipeline:ril.image_decode:video_convert"
|
||||
#define MMAL_COMPONENT_IMAGE_ENCODE "vc.ril.image_encode"
|
||||
|
||||
#define ENABLE_SLICE_MODE 0
|
||||
|
||||
#define CHECK_MMAL_STATUS(status, jerr, msg, ...) \
|
||||
if (status != MMAL_SUCCESS) {LOG_ERROR(msg, ## __VA_ARGS__); \
|
||||
err = BRCMJPEG_ERROR_##jerr; goto error;}
|
||||
|
||||
/*******************************************************************************
|
||||
* Type definitions
|
||||
*******************************************************************************/
|
||||
struct BRCMJPEG_T
|
||||
{
|
||||
BRCMJPEG_TYPE_T type;
|
||||
unsigned int ref_count;
|
||||
unsigned int init;
|
||||
|
||||
MMAL_WRAPPER_T *mmal;
|
||||
unsigned int slice_height;
|
||||
|
||||
VCOS_MUTEX_T lock;
|
||||
VCOS_MUTEX_T process_lock;
|
||||
VCOS_SEMAPHORE_T sema;
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* Local prototypes
|
||||
*******************************************************************************/
|
||||
static BRCMJPEG_STATUS_T brcmjpeg_init_encoder(BRCMJPEG_T *);
|
||||
static BRCMJPEG_STATUS_T brcmjpeg_init_decoder(BRCMJPEG_T *);
|
||||
static BRCMJPEG_STATUS_T brcmjpeg_configure_encoder(BRCMJPEG_T *, BRCMJPEG_REQUEST_T *);
|
||||
static BRCMJPEG_STATUS_T brcmjpeg_configure_decoder(BRCMJPEG_T *, BRCMJPEG_REQUEST_T *);
|
||||
static BRCMJPEG_STATUS_T brcmjpeg_encode(BRCMJPEG_T *, BRCMJPEG_REQUEST_T *);
|
||||
static BRCMJPEG_STATUS_T brcmjpeg_decode(BRCMJPEG_T *, BRCMJPEG_REQUEST_T *);
|
||||
static void brcmjpeg_destroy(BRCMJPEG_T *);
|
||||
|
||||
static MMAL_FOURCC_T brcmjpeg_pixfmt_to_encoding(BRCMJPEG_PIXEL_FORMAT_T);
|
||||
static unsigned int brcmjpeg_copy_pixels(uint8_t *out, unsigned int out_size,
|
||||
const uint8_t *in, unsigned int in_size, BRCMJPEG_PIXEL_FORMAT_T fmt,
|
||||
unsigned int out_width, unsigned int out_height,
|
||||
unsigned int in_width, unsigned int in_height,
|
||||
unsigned int line_offset, unsigned int convert_from);
|
||||
|
||||
static BRCMJPEG_T *brcmjpeg_encoder = NULL;
|
||||
static BRCMJPEG_T *brcmjpeg_decoder = NULL;
|
||||
|
||||
/*******************************************************************************
|
||||
* Platform specific code
|
||||
*******************************************************************************/
|
||||
static VCOS_ONCE_T once = VCOS_ONCE_INIT;
|
||||
static VCOS_MUTEX_T brcmjpeg_lock;
|
||||
|
||||
static void brcmjpeg_init_once(void)
|
||||
{
|
||||
vcos_mutex_create(&brcmjpeg_lock, VCOS_FUNCTION);
|
||||
}
|
||||
|
||||
#define LOCK() vcos_mutex_lock(&brcmjpeg_lock)
|
||||
#define UNLOCK() vcos_mutex_unlock(&brcmjpeg_lock)
|
||||
#define LOCK_COMP(ctx) vcos_mutex_lock(&(ctx)->lock)
|
||||
#define UNLOCK_COMP(ctx) vcos_mutex_unlock(&(ctx)->lock)
|
||||
#define LOCK_PROCESS(ctx) vcos_mutex_lock(&(ctx)->process_lock)
|
||||
#define UNLOCK_PROCESS(ctx) vcos_mutex_unlock(&(ctx)->process_lock)
|
||||
#define WAIT(ctx) vcos_semaphore_wait(&(ctx)->sema)
|
||||
#define SIGNAL(ctx) vcos_semaphore_post(&(ctx)->sema)
|
||||
|
||||
/*******************************************************************************
|
||||
* Implementation
|
||||
*******************************************************************************/
|
||||
|
||||
BRCMJPEG_STATUS_T brcmjpeg_create(BRCMJPEG_TYPE_T type, BRCMJPEG_T **ctx)
|
||||
{
|
||||
BRCMJPEG_STATUS_T status = BRCMJPEG_SUCCESS;
|
||||
BRCMJPEG_T **comp;
|
||||
|
||||
if (type == BRCMJPEG_TYPE_ENCODER)
|
||||
comp = &brcmjpeg_encoder;
|
||||
else
|
||||
comp = &brcmjpeg_decoder;
|
||||
|
||||
vcos_once(&once, brcmjpeg_init_once);
|
||||
LOCK();
|
||||
if (!*comp)
|
||||
{
|
||||
int init1, init2, init3;
|
||||
*comp = calloc(sizeof(BRCMJPEG_T), 1);
|
||||
if (!*comp)
|
||||
{
|
||||
UNLOCK();
|
||||
return BRCMJPEG_ERROR_NOMEM;
|
||||
}
|
||||
(*comp)->type = type;
|
||||
init1 = vcos_mutex_create(&(*comp)->lock, "brcmjpeg lock") != VCOS_SUCCESS;
|
||||
init2 = vcos_mutex_create(&(*comp)->process_lock, "brcmjpeg process lock") != VCOS_SUCCESS;
|
||||
init3 = vcos_semaphore_create(&(*comp)->sema, "brcmjpeg sema", 0) != VCOS_SUCCESS;
|
||||
if (init1 | init2 | init3)
|
||||
{
|
||||
if (init1) vcos_mutex_delete(&(*comp)->lock);
|
||||
if (init2) vcos_mutex_delete(&(*comp)->process_lock);
|
||||
if (init3) vcos_semaphore_delete(&(*comp)->sema);
|
||||
free(comp);
|
||||
UNLOCK();
|
||||
return BRCMJPEG_ERROR_NOMEM;
|
||||
}
|
||||
}
|
||||
(*comp)->ref_count++;
|
||||
UNLOCK();
|
||||
|
||||
LOCK_COMP(*comp);
|
||||
if (!(*comp)->init)
|
||||
{
|
||||
if (type == BRCMJPEG_TYPE_ENCODER)
|
||||
status = brcmjpeg_init_encoder(*comp);
|
||||
else
|
||||
status = brcmjpeg_init_decoder(*comp);
|
||||
|
||||
(*comp)->init = status == BRCMJPEG_SUCCESS;
|
||||
}
|
||||
UNLOCK_COMP(*comp);
|
||||
|
||||
if (status != BRCMJPEG_SUCCESS)
|
||||
brcmjpeg_release(*comp);
|
||||
|
||||
*ctx = *comp;
|
||||
return status;
|
||||
}
|
||||
|
||||
void brcmjpeg_acquire(BRCMJPEG_T *ctx)
|
||||
{
|
||||
LOCK_COMP(ctx);
|
||||
ctx->ref_count++;
|
||||
UNLOCK_COMP(ctx);
|
||||
}
|
||||
|
||||
void brcmjpeg_release(BRCMJPEG_T *ctx)
|
||||
{
|
||||
LOCK_COMP(ctx);
|
||||
if (--ctx->ref_count)
|
||||
{
|
||||
UNLOCK_COMP(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
LOCK();
|
||||
if (ctx->type == BRCMJPEG_TYPE_ENCODER)
|
||||
brcmjpeg_encoder = NULL;
|
||||
else
|
||||
brcmjpeg_decoder = NULL;
|
||||
UNLOCK();
|
||||
UNLOCK_COMP(ctx);
|
||||
|
||||
brcmjpeg_destroy(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
BRCMJPEG_STATUS_T brcmjpeg_process(BRCMJPEG_T *ctx, BRCMJPEG_REQUEST_T *req)
|
||||
{
|
||||
BRCMJPEG_STATUS_T status;
|
||||
|
||||
/* Sanity check */
|
||||
if ((req->input && req->input_handle) ||
|
||||
(req->output && req->output_handle))
|
||||
{
|
||||
LOG_ERROR("buffer pointer and handle both set (%p/%u %p/%u)",
|
||||
req->input, req->input_handle, req->output, req->output_handle);
|
||||
return BRCMJPEG_ERROR_REQUEST;
|
||||
}
|
||||
|
||||
LOCK_PROCESS(ctx);
|
||||
if (ctx->type == BRCMJPEG_TYPE_ENCODER)
|
||||
status = brcmjpeg_encode(ctx, req);
|
||||
else
|
||||
status = brcmjpeg_decode(ctx, req);
|
||||
UNLOCK_PROCESS(ctx);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void brcmjpeg_destroy(BRCMJPEG_T *ctx)
|
||||
{
|
||||
if (ctx->mmal)
|
||||
mmal_wrapper_destroy(ctx->mmal);
|
||||
vcos_mutex_delete(&ctx->lock);
|
||||
vcos_mutex_delete(&ctx->process_lock);
|
||||
vcos_semaphore_delete(&ctx->sema);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
static void brcmjpeg_mmal_cb(MMAL_WRAPPER_T *wrapper)
|
||||
{
|
||||
BRCMJPEG_T *ctx = wrapper->user_data;
|
||||
SIGNAL(ctx);
|
||||
}
|
||||
|
||||
static BRCMJPEG_STATUS_T brcmjpeg_init_encoder(BRCMJPEG_T *ctx)
|
||||
{
|
||||
MMAL_STATUS_T status;
|
||||
BRCMJPEG_STATUS_T err = BRCMJPEG_SUCCESS;
|
||||
|
||||
/* Create encoder component */
|
||||
status = mmal_wrapper_create(&ctx->mmal, MMAL_COMPONENT_IMAGE_ENCODE);
|
||||
CHECK_MMAL_STATUS(status, INIT, "failed to create encoder");
|
||||
ctx->mmal->user_data = ctx;
|
||||
ctx->mmal->callback = brcmjpeg_mmal_cb;
|
||||
|
||||
/* Configure things that won't change from encode to encode */
|
||||
mmal_port_parameter_set_boolean(ctx->mmal->control,
|
||||
MMAL_PARAMETER_EXIF_DISABLE, MMAL_TRUE);
|
||||
|
||||
ctx->mmal->output[0]->format->encoding = MMAL_ENCODING_JPEG;
|
||||
status = mmal_port_format_commit(ctx->mmal->output[0]);
|
||||
CHECK_MMAL_STATUS(status, INIT, "failed to commit output port format");
|
||||
|
||||
ctx->mmal->output[0]->buffer_size = ctx->mmal->output[0]->buffer_size_min;
|
||||
ctx->mmal->output[0]->buffer_num = 3;
|
||||
status = mmal_wrapper_port_enable(ctx->mmal->output[0], 0);
|
||||
CHECK_MMAL_STATUS(status, INIT, "failed to enable output port");
|
||||
|
||||
LOG_DEBUG("encoder initialised (output chunk size %i)",
|
||||
ctx->mmal->output[0]->buffer_size);
|
||||
return BRCMJPEG_SUCCESS;
|
||||
|
||||
error:
|
||||
return err;
|
||||
}
|
||||
|
||||
static BRCMJPEG_STATUS_T brcmjpeg_init_decoder(BRCMJPEG_T *ctx)
|
||||
{
|
||||
MMAL_STATUS_T status;
|
||||
BRCMJPEG_STATUS_T err = BRCMJPEG_SUCCESS;
|
||||
|
||||
/* Create decoder component */
|
||||
status = mmal_wrapper_create(&ctx->mmal, MMAL_COMPONENT_IMAGE_DECODE);
|
||||
CHECK_MMAL_STATUS(status, INIT, "failed to create decoder");
|
||||
ctx->mmal->user_data = ctx;
|
||||
ctx->mmal->callback = brcmjpeg_mmal_cb;
|
||||
|
||||
/* Configure things that won't change from decode to decode */
|
||||
ctx->mmal->input[0]->format->encoding = MMAL_ENCODING_JPEG;
|
||||
status = mmal_port_format_commit(ctx->mmal->input[0]);
|
||||
CHECK_MMAL_STATUS(status, INIT, "failed to commit input port format");
|
||||
|
||||
ctx->mmal->input[0]->buffer_size = ctx->mmal->input[0]->buffer_size_min;
|
||||
ctx->mmal->input[0]->buffer_num = 3;
|
||||
status = mmal_wrapper_port_enable(ctx->mmal->input[0], 0);
|
||||
CHECK_MMAL_STATUS(status, INIT, "failed to enable input port");
|
||||
|
||||
LOG_DEBUG("decoder initialised (input chunk size %i)",
|
||||
ctx->mmal->input[0]->buffer_size);
|
||||
return BRCMJPEG_SUCCESS;
|
||||
|
||||
error:
|
||||
return BRCMJPEG_ERROR_INIT;
|
||||
}
|
||||
|
||||
/* Configuration which needs to be done on a per encode basis */
|
||||
static BRCMJPEG_STATUS_T brcmjpeg_configure_encoder(BRCMJPEG_T *ctx,
|
||||
BRCMJPEG_REQUEST_T *req)
|
||||
{
|
||||
MMAL_STATUS_T status = MMAL_SUCCESS;
|
||||
MMAL_FOURCC_T encoding = brcmjpeg_pixfmt_to_encoding(req->pixel_format);
|
||||
MMAL_PORT_T *port_in;
|
||||
BRCMJPEG_STATUS_T err = BRCMJPEG_SUCCESS;
|
||||
MMAL_BOOL_T slice_mode = MMAL_FALSE;
|
||||
|
||||
if (encoding == MMAL_ENCODING_UNKNOWN)
|
||||
status = MMAL_EINVAL;
|
||||
CHECK_MMAL_STATUS(status, INPUT_FORMAT, "format not supported (%i)",
|
||||
req->pixel_format);
|
||||
|
||||
if (!req->buffer_width)
|
||||
req->buffer_width = req->width;
|
||||
if (!req->buffer_height)
|
||||
req->buffer_height = req->height;
|
||||
if (req->buffer_width < req->width || req->buffer_height < req->height)
|
||||
status = MMAL_EINVAL;
|
||||
CHECK_MMAL_STATUS(status, INPUT_FORMAT, "invalid buffer width/height "
|
||||
"(%i<=%i %i<=%i)", req->buffer_width, req->width, req->buffer_height,
|
||||
req->height);
|
||||
|
||||
ctx->slice_height = 0;
|
||||
ctx->mmal->status = MMAL_SUCCESS;
|
||||
port_in = ctx->mmal->input[0];
|
||||
|
||||
/* The input port needs to be re-configured to take into account
|
||||
* the properties of the new frame to encode */
|
||||
if (port_in->is_enabled)
|
||||
{
|
||||
status = mmal_wrapper_port_disable(port_in);
|
||||
CHECK_MMAL_STATUS(status, EXECUTE, "failed to disable input port");
|
||||
}
|
||||
|
||||
port_in->format->encoding = encoding;
|
||||
port_in->format->es->video.width =
|
||||
port_in->format->es->video.crop.width = req->width;
|
||||
port_in->format->es->video.height =
|
||||
port_in->format->es->video.crop.height = req->height;
|
||||
port_in->buffer_num = 1;
|
||||
|
||||
if (!req->input_handle &&
|
||||
(port_in->format->encoding == MMAL_ENCODING_I420 ||
|
||||
port_in->format->encoding == MMAL_ENCODING_I422))
|
||||
{
|
||||
if (port_in->format->encoding == MMAL_ENCODING_I420)
|
||||
port_in->format->encoding = MMAL_ENCODING_I420_SLICE;
|
||||
else if (port_in->format->encoding == MMAL_ENCODING_I422)
|
||||
port_in->format->encoding = MMAL_ENCODING_I422_SLICE;
|
||||
slice_mode = MMAL_TRUE;
|
||||
port_in->buffer_num = 3;
|
||||
}
|
||||
|
||||
status = mmal_port_format_commit(port_in);
|
||||
CHECK_MMAL_STATUS(status, INPUT_FORMAT, "failed to commit input port format");
|
||||
|
||||
ctx->slice_height = slice_mode ? 16 : port_in->format->es->video.height;
|
||||
port_in->buffer_size = port_in->buffer_size_min;
|
||||
|
||||
if (req->input_handle)
|
||||
status = mmal_wrapper_port_enable(port_in, MMAL_WRAPPER_FLAG_PAYLOAD_USE_SHARED_MEMORY);
|
||||
else
|
||||
status = mmal_wrapper_port_enable(port_in, MMAL_WRAPPER_FLAG_PAYLOAD_ALLOCATE);
|
||||
CHECK_MMAL_STATUS(status, EXECUTE, "failed to enable input port");
|
||||
|
||||
mmal_port_parameter_set_uint32(ctx->mmal->output[0],
|
||||
MMAL_PARAMETER_JPEG_Q_FACTOR, req->quality);
|
||||
|
||||
if (!ctx->mmal->output[0]->is_enabled)
|
||||
{
|
||||
status = mmal_wrapper_port_enable(ctx->mmal->output[0], 0);
|
||||
CHECK_MMAL_STATUS(status, EXECUTE, "failed to enable output port");
|
||||
}
|
||||
|
||||
LOG_DEBUG("encoder configured (%4.4s:%ux%u|%ux%u slice: %u)",
|
||||
(char *)&port_in->format->encoding,
|
||||
port_in->format->es->video.crop.width, port_in->format->es->video.crop.height,
|
||||
port_in->format->es->video.width, port_in->format->es->video.height,
|
||||
ctx->slice_height);
|
||||
return BRCMJPEG_SUCCESS;
|
||||
|
||||
error:
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Configuration which needs to be done on a per decode basis */
|
||||
static BRCMJPEG_STATUS_T brcmjpeg_configure_decoder(BRCMJPEG_T *ctx,
|
||||
BRCMJPEG_REQUEST_T *req)
|
||||
{
|
||||
MMAL_STATUS_T status = MMAL_SUCCESS;
|
||||
MMAL_FOURCC_T encoding = brcmjpeg_pixfmt_to_encoding(req->pixel_format);
|
||||
MMAL_PORT_T *port_out;
|
||||
BRCMJPEG_STATUS_T err = BRCMJPEG_SUCCESS;
|
||||
|
||||
if (encoding != MMAL_ENCODING_I420 &&
|
||||
encoding != MMAL_ENCODING_I422 &&
|
||||
encoding != MMAL_ENCODING_RGBA)
|
||||
status = MMAL_EINVAL;
|
||||
CHECK_MMAL_STATUS(status, OUTPUT_FORMAT, "format not supported");
|
||||
|
||||
ctx->slice_height = 0;
|
||||
ctx->mmal->status = MMAL_SUCCESS;
|
||||
port_out = ctx->mmal->output[0];
|
||||
|
||||
/* The input port needs to be re-configured to take into account
|
||||
* the properties of the new frame to decode */
|
||||
if (port_out->is_enabled)
|
||||
{
|
||||
status = mmal_wrapper_port_disable(port_out);
|
||||
CHECK_MMAL_STATUS(status, EXECUTE, "failed to disable output port");
|
||||
}
|
||||
|
||||
/* We assume that we do not know the format of the new jpeg to be decoded
|
||||
* and configure the input port for autodetecting the new format */
|
||||
port_out->format->encoding = encoding;
|
||||
port_out->format->es->video.width =
|
||||
port_out->format->es->video.crop.width = 0;
|
||||
port_out->format->es->video.height =
|
||||
port_out->format->es->video.crop.height = 0;
|
||||
status = mmal_port_format_commit(port_out);
|
||||
CHECK_MMAL_STATUS(status, OUTPUT_FORMAT, "failed to commit output port format");
|
||||
|
||||
port_out->buffer_num = 1;
|
||||
if (req->output_handle)
|
||||
status = mmal_wrapper_port_enable(port_out, MMAL_WRAPPER_FLAG_PAYLOAD_USE_SHARED_MEMORY);
|
||||
else
|
||||
status = mmal_wrapper_port_enable(port_out, MMAL_WRAPPER_FLAG_PAYLOAD_ALLOCATE);
|
||||
CHECK_MMAL_STATUS(status, EXECUTE, "failed to enable output port");
|
||||
|
||||
LOG_DEBUG("decoder configured (%4.4s:%ux%u|%ux%u)", (char *)&port_out->format->encoding,
|
||||
port_out->format->es->video.crop.width, port_out->format->es->video.crop.height,
|
||||
port_out->format->es->video.width, port_out->format->es->video.height);
|
||||
return BRCMJPEG_SUCCESS;
|
||||
|
||||
error:
|
||||
return err;
|
||||
}
|
||||
|
||||
static BRCMJPEG_STATUS_T brcmjpeg_encode(BRCMJPEG_T *ctx,
|
||||
BRCMJPEG_REQUEST_T *je)
|
||||
{
|
||||
BRCMJPEG_STATUS_T err;
|
||||
MMAL_STATUS_T status = MMAL_SUCCESS;
|
||||
MMAL_BUFFER_HEADER_T *in, *out;
|
||||
MMAL_BOOL_T eos = MMAL_FALSE;
|
||||
const uint8_t *outBuf = je->output;
|
||||
unsigned int loop = 0, slices = 0, outBufSize = je->output_alloc_size;
|
||||
MMAL_PORT_T *port_in = ctx->mmal->input[0];
|
||||
MMAL_PORT_T *port_out = ctx->mmal->output[0];
|
||||
|
||||
je->output_size = 0;
|
||||
err = brcmjpeg_configure_encoder(ctx, je);
|
||||
if (err != BRCMJPEG_SUCCESS)
|
||||
return err;
|
||||
|
||||
/* Then we read the encoded data back from the encoder */
|
||||
|
||||
while (!eos && status == MMAL_SUCCESS)
|
||||
{
|
||||
/* send buffers to be filled */
|
||||
while (mmal_wrapper_buffer_get_empty(port_out, &out, 0) == MMAL_SUCCESS)
|
||||
{
|
||||
out->data = (uint8_t *)outBuf;
|
||||
out->alloc_size = MMAL_MIN(port_out->buffer_size, outBufSize);
|
||||
outBufSize -= out->alloc_size;
|
||||
outBuf += out->alloc_size;
|
||||
status = mmal_port_send_buffer(port_out, out);
|
||||
CHECK_MMAL_STATUS(status, EXECUTE, "failed to send buffer");
|
||||
}
|
||||
|
||||
/* Send slices to be encoded */
|
||||
if (slices * ctx->slice_height < port_in->format->es->video.height &&
|
||||
mmal_wrapper_buffer_get_empty(port_in, &in, 0) == MMAL_SUCCESS)
|
||||
{
|
||||
if (je->input_handle)
|
||||
{
|
||||
in->data = (uint8_t *)je->input_handle;
|
||||
in->length = in->alloc_size = je->input_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
in->length = brcmjpeg_copy_pixels(in->data, in->alloc_size,
|
||||
je->input, je->input_size, je->pixel_format,
|
||||
port_in->format->es->video.width,
|
||||
ctx->slice_height, je->buffer_width, je->buffer_height,
|
||||
slices * ctx->slice_height, 1);
|
||||
if (!in->length)
|
||||
status = MMAL_EINVAL;
|
||||
CHECK_MMAL_STATUS(status, INPUT_BUFFER, "input buffer too small");
|
||||
}
|
||||
|
||||
slices++;
|
||||
if (slices * ctx->slice_height >= port_in->format->es->video.height)
|
||||
in->flags = MMAL_BUFFER_HEADER_FLAG_EOS;
|
||||
status = mmal_port_send_buffer(port_in, in);
|
||||
CHECK_MMAL_STATUS(status, EXECUTE, "failed to send buffer");
|
||||
}
|
||||
|
||||
status = mmal_wrapper_buffer_get_full(port_out, &out, 0);
|
||||
if (status == MMAL_EAGAIN)
|
||||
{
|
||||
status = MMAL_SUCCESS;
|
||||
WAIT(ctx);
|
||||
continue;
|
||||
}
|
||||
CHECK_MMAL_STATUS(status, EXECUTE, "failed to get full buffer");
|
||||
|
||||
LOG_DEBUG("received %i bytes", out->length);
|
||||
je->output_size += out->length;
|
||||
eos = out->flags & MMAL_BUFFER_HEADER_FLAG_EOS;
|
||||
|
||||
/* Detect when the encoder is running out of space for its output */
|
||||
if (++loop >= port_out->buffer_num && !eos && !out->length)
|
||||
{
|
||||
LOG_ERROR("no more output space for encoder");
|
||||
status = MMAL_EINVAL;
|
||||
}
|
||||
|
||||
mmal_buffer_header_release(out);
|
||||
}
|
||||
|
||||
/* Check if buffer was too small */
|
||||
CHECK_MMAL_STATUS(status, OUTPUT_BUFFER, "output buffer too small");
|
||||
|
||||
LOG_DEBUG("encoded W:%ixH:%i:%i (%i bytes) in %i slices",
|
||||
je->width, je->height, je->pixel_format, je->output_size, slices);
|
||||
mmal_port_flush(port_out);
|
||||
return BRCMJPEG_SUCCESS;
|
||||
|
||||
error:
|
||||
mmal_wrapper_port_disable(port_in);
|
||||
mmal_wrapper_port_disable(port_out);
|
||||
return err;
|
||||
}
|
||||
|
||||
static BRCMJPEG_STATUS_T brcmjpeg_decode(BRCMJPEG_T *ctx,
|
||||
BRCMJPEG_REQUEST_T *jd)
|
||||
{
|
||||
BRCMJPEG_STATUS_T err;
|
||||
MMAL_STATUS_T status;
|
||||
MMAL_BUFFER_HEADER_T *in, *out;
|
||||
MMAL_BOOL_T eos = MMAL_FALSE;
|
||||
const uint8_t *inBuf = jd->input;
|
||||
unsigned int slices = 0, inBufSize = jd->input_size;
|
||||
MMAL_PORT_T *port_in = ctx->mmal->input[0];
|
||||
MMAL_PORT_T *port_out = ctx->mmal->output[0];
|
||||
LOG_DEBUG("decode %i bytes", jd->input_size);
|
||||
|
||||
jd->output_size = 0;
|
||||
err = brcmjpeg_configure_decoder(ctx, jd);
|
||||
if (err != BRCMJPEG_SUCCESS)
|
||||
return err;
|
||||
|
||||
while (!eos)
|
||||
{
|
||||
/* Send as many chunks of data to decode as we can */
|
||||
while (inBufSize)
|
||||
{
|
||||
status = mmal_wrapper_buffer_get_empty(port_in, &in, 0);
|
||||
if (status == MMAL_EAGAIN)
|
||||
break;
|
||||
CHECK_MMAL_STATUS(status, EXECUTE, "failed to get empty buffer (%i)", status);
|
||||
|
||||
in->data = (uint8_t *)inBuf;
|
||||
in->length = MMAL_MIN(port_in->buffer_size, inBufSize);
|
||||
in->alloc_size = in->length;
|
||||
inBufSize -= in->length;
|
||||
inBuf += in->length;
|
||||
in->flags = inBufSize ? 0 : MMAL_BUFFER_HEADER_FLAG_EOS;
|
||||
LOG_DEBUG("send decode in (%i bytes)", in->length);
|
||||
status = mmal_port_send_buffer(port_in, in);
|
||||
CHECK_MMAL_STATUS(status, EXECUTE, "failed to send input buffer");
|
||||
}
|
||||
|
||||
/* Check for decoded data */
|
||||
status = mmal_wrapper_buffer_get_full(port_out, &out, 0);
|
||||
if (status == MMAL_EAGAIN)
|
||||
{
|
||||
WAIT(ctx);
|
||||
continue;
|
||||
}
|
||||
CHECK_MMAL_STATUS(status, EXECUTE, "error decoding");
|
||||
|
||||
/* Check if a new format has been auto-detected by the decoder */
|
||||
if (out->cmd == MMAL_EVENT_FORMAT_CHANGED)
|
||||
{
|
||||
MMAL_EVENT_FORMAT_CHANGED_T *event = mmal_event_format_changed_get(out);
|
||||
|
||||
if (event)
|
||||
mmal_format_copy(port_out->format, event->format);
|
||||
mmal_buffer_header_release(out);
|
||||
|
||||
if (!event)
|
||||
status = MMAL_EINVAL;
|
||||
CHECK_MMAL_STATUS(status, EXECUTE, "invalid format change event");
|
||||
|
||||
LOG_DEBUG("new format (%4.4s:%ux%u|%ux%u)", (char *)&event->format->encoding,
|
||||
event->format->es->video.crop.width, event->format->es->video.crop.height,
|
||||
event->format->es->video.width, event->format->es->video.height);
|
||||
|
||||
/* re-setup the output port for the new format */
|
||||
status = mmal_wrapper_port_disable(port_out);
|
||||
CHECK_MMAL_STATUS(status, EXECUTE, "failed to disable output port");
|
||||
|
||||
ctx->slice_height = event->format->es->video.height;
|
||||
if (ENABLE_SLICE_MODE && !jd->output_handle)
|
||||
{
|
||||
/* setup slice mode */
|
||||
if (port_out->format->encoding == MMAL_ENCODING_I420 ||
|
||||
port_out->format->encoding == MMAL_ENCODING_I422)
|
||||
{
|
||||
if (port_out->format->encoding == MMAL_ENCODING_I420)
|
||||
port_out->format->encoding = MMAL_ENCODING_I420_SLICE;
|
||||
if (port_out->format->encoding == MMAL_ENCODING_I422)
|
||||
port_out->format->encoding = MMAL_ENCODING_I422_SLICE;
|
||||
ctx->slice_height = 16;
|
||||
port_out->buffer_num = 3;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_DEBUG("using slice size %u", ctx->slice_height);
|
||||
status = mmal_port_format_commit(port_out);
|
||||
CHECK_MMAL_STATUS(status, EXECUTE, "invalid format change event");
|
||||
port_out->buffer_size = port_out->buffer_size_min;
|
||||
if (jd->output_handle)
|
||||
status = mmal_wrapper_port_enable(port_out, MMAL_WRAPPER_FLAG_PAYLOAD_USE_SHARED_MEMORY);
|
||||
else
|
||||
status = mmal_wrapper_port_enable(port_out, MMAL_WRAPPER_FLAG_PAYLOAD_ALLOCATE);
|
||||
CHECK_MMAL_STATUS(status, EXECUTE, "failed to enable output port");
|
||||
|
||||
/* send all our output buffers to the decoder */
|
||||
while (mmal_wrapper_buffer_get_empty(port_out, &out, 0) == MMAL_SUCCESS)
|
||||
{
|
||||
if (jd->output_handle)
|
||||
{
|
||||
out->data = (uint8_t*)jd->output_handle;
|
||||
out->alloc_size = jd->output_alloc_size;
|
||||
}
|
||||
status = mmal_port_send_buffer(port_out, out);
|
||||
CHECK_MMAL_STATUS(status, EXECUTE, "failed to send output buffer");
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We have part of our output frame */
|
||||
jd->width = port_out->format->es->video.crop.width;
|
||||
if (!jd->width)
|
||||
jd->width = port_out->format->es->video.width;
|
||||
if (jd->output_handle)
|
||||
jd->buffer_width = port_out->format->es->video.width;
|
||||
if (!jd->buffer_width)
|
||||
jd->buffer_width = jd->width;
|
||||
jd->height = port_out->format->es->video.crop.height;
|
||||
if (!jd->height)
|
||||
jd->height = port_out->format->es->video.height;
|
||||
if (jd->output_handle)
|
||||
jd->buffer_height = port_out->format->es->video.height;
|
||||
if (!jd->buffer_height)
|
||||
jd->buffer_height = jd->height;
|
||||
|
||||
if (jd->output_handle)
|
||||
{
|
||||
jd->output_size += out->length;
|
||||
}
|
||||
else
|
||||
{
|
||||
jd->output_size = brcmjpeg_copy_pixels(jd->output, jd->output_alloc_size,
|
||||
out->data, out->length, jd->pixel_format,
|
||||
jd->buffer_width, jd->buffer_height,
|
||||
port_out->format->es->video.width,
|
||||
ctx->slice_height, slices * ctx->slice_height, 0);
|
||||
slices++;
|
||||
}
|
||||
|
||||
eos = out->flags & MMAL_BUFFER_HEADER_FLAG_EOS;
|
||||
out->length = 0;
|
||||
if (eos)
|
||||
{
|
||||
mmal_buffer_header_release(out);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = mmal_port_send_buffer(port_out, out);
|
||||
CHECK_MMAL_STATUS(status, EXECUTE, "failed to send output buffer");
|
||||
}
|
||||
|
||||
if (!jd->output_size)
|
||||
status = MMAL_EINVAL;
|
||||
CHECK_MMAL_STATUS(status, OUTPUT_BUFFER, "invalid output buffer");
|
||||
}
|
||||
|
||||
LOG_DEBUG("decoded W:%ixH%i:(W%ixH%i):%i in %i slices",
|
||||
jd->width, jd->height, jd->buffer_width, jd->buffer_height,
|
||||
jd->pixel_format, slices);
|
||||
mmal_port_flush(port_in);
|
||||
return BRCMJPEG_SUCCESS;
|
||||
|
||||
error:
|
||||
mmal_port_flush(port_in);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static struct {
|
||||
BRCMJPEG_PIXEL_FORMAT_T pixel_format;
|
||||
MMAL_FOURCC_T encoding;
|
||||
} mmal_raw_conversion[] = {
|
||||
{PIXEL_FORMAT_I420, MMAL_ENCODING_I420},
|
||||
{PIXEL_FORMAT_YV12, MMAL_ENCODING_I420},
|
||||
{PIXEL_FORMAT_I422, MMAL_ENCODING_I422},
|
||||
{PIXEL_FORMAT_YV16, MMAL_ENCODING_I422},
|
||||
{PIXEL_FORMAT_YUYV, MMAL_ENCODING_I422},
|
||||
{PIXEL_FORMAT_RGBA, MMAL_ENCODING_RGBA},
|
||||
{PIXEL_FORMAT_UNKNOWN, MMAL_ENCODING_UNKNOWN} };
|
||||
|
||||
static MMAL_FOURCC_T brcmjpeg_pixfmt_to_encoding(BRCMJPEG_PIXEL_FORMAT_T pixel_format)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; mmal_raw_conversion[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
|
||||
if (mmal_raw_conversion[i].pixel_format == pixel_format)
|
||||
break;
|
||||
return mmal_raw_conversion[i].encoding;
|
||||
}
|
||||
|
||||
// Copy a raw frame from 1 buffer to another, taking care of
|
||||
// stride / height differences between the input and output buffers.
|
||||
static unsigned int brcmjpeg_copy_pixels(uint8_t *out, unsigned int out_size,
|
||||
const uint8_t *in, unsigned int in_size, BRCMJPEG_PIXEL_FORMAT_T fmt,
|
||||
unsigned int out_width, unsigned int out_height,
|
||||
unsigned int in_width, unsigned int in_height,
|
||||
unsigned int line_offset, unsigned int convert_from)
|
||||
{
|
||||
struct {
|
||||
uint8_t *data;
|
||||
unsigned int pitch;
|
||||
unsigned int height;
|
||||
} planes[2][3];
|
||||
unsigned int num_planes = 0;
|
||||
unsigned int i, size = 0;
|
||||
unsigned int in_height_full = in_height;
|
||||
unsigned int out_height_full = out_height;
|
||||
unsigned int k = convert_from ? 1 : 0;
|
||||
|
||||
// Sanity check line_offset
|
||||
if (line_offset >= (convert_from ? in_height : out_height))
|
||||
return 0;
|
||||
|
||||
if (convert_from)
|
||||
in_height -= line_offset;
|
||||
else
|
||||
out_height -= line_offset;
|
||||
|
||||
if (fmt == PIXEL_FORMAT_I420 ||
|
||||
fmt == PIXEL_FORMAT_YV12)
|
||||
{
|
||||
planes[0][0].data = out;
|
||||
planes[0][0].pitch = out_width;
|
||||
planes[0][0].height = out_height;
|
||||
|
||||
planes[1][0].data = (uint8_t *)in;
|
||||
planes[1][0].pitch = in_width;
|
||||
planes[1][0].height = in_height;
|
||||
|
||||
planes[0][1].pitch = planes[0][2].pitch = out_width / 2;
|
||||
planes[0][1].height = planes[0][2].height = out_height / 2;
|
||||
planes[0][1].data = planes[0][0].data + out_width * out_height_full;
|
||||
planes[0][2].data = planes[0][1].data + out_width * out_height_full / 4;
|
||||
|
||||
planes[1][1].pitch = planes[1][2].pitch = in_width / 2;
|
||||
planes[1][1].height = planes[1][2].height = in_height / 2;
|
||||
planes[1][1].data = planes[1][0].data + in_width * in_height_full;
|
||||
planes[1][2].data = planes[1][1].data + in_width * in_height_full / 4;
|
||||
|
||||
if (fmt == PIXEL_FORMAT_YV12)
|
||||
{
|
||||
// We need to swap U and V
|
||||
uint8_t *tmp = planes[1][2].data;
|
||||
planes[1][2].data = planes[1][1].data;
|
||||
planes[1][1].data = tmp;
|
||||
}
|
||||
|
||||
// Add the line offset
|
||||
planes[k][0].data += planes[k][0].pitch * line_offset;
|
||||
planes[k][1].data += planes[k][1].pitch * line_offset/2;
|
||||
planes[k][2].data += planes[k][2].pitch * line_offset/2;
|
||||
|
||||
num_planes = 3;
|
||||
size = out_width * out_height_full * 3 / 2;
|
||||
|
||||
if (in_size < in_width * in_height * 3 / 2)
|
||||
return 0;
|
||||
|
||||
} else if (fmt == PIXEL_FORMAT_I422 ||
|
||||
fmt == PIXEL_FORMAT_YV16 ||
|
||||
fmt == PIXEL_FORMAT_YUYV)
|
||||
{
|
||||
planes[0][0].data = out;
|
||||
planes[0][0].pitch = out_width;
|
||||
planes[0][0].height = out_height;
|
||||
|
||||
planes[1][0].data = (uint8_t *)in;
|
||||
planes[1][0].pitch = in_width;
|
||||
planes[1][0].height = in_height;
|
||||
|
||||
planes[0][1].pitch = planes[0][2].pitch = out_width / 2;
|
||||
planes[0][1].height = planes[0][2].height = out_height;
|
||||
planes[0][1].data = planes[0][0].data + out_width * out_height_full;
|
||||
planes[0][2].data = planes[0][1].data + out_width * out_height_full / 2;
|
||||
|
||||
planes[1][1].pitch = planes[1][2].pitch = in_width / 2;
|
||||
planes[1][1].height = planes[1][2].height = in_height;
|
||||
planes[1][1].data = planes[1][0].data + in_width * in_height_full;
|
||||
planes[1][2].data = planes[1][1].data + in_width * in_height_full / 2;
|
||||
|
||||
// Add the line offset
|
||||
planes[k][0].data += planes[k][0].pitch * line_offset;
|
||||
planes[k][1].data += planes[k][1].pitch * line_offset;
|
||||
planes[k][2].data += planes[k][2].pitch * line_offset;
|
||||
if (fmt == PIXEL_FORMAT_YUYV)
|
||||
planes[k][0].data += planes[k][0].pitch * line_offset;
|
||||
|
||||
if (fmt == PIXEL_FORMAT_YV16)
|
||||
{
|
||||
// We need to swap U and V
|
||||
uint8_t *tmp = planes[1][2].data;
|
||||
planes[1][2].data = planes[1][1].data;
|
||||
planes[1][1].data = tmp;
|
||||
}
|
||||
|
||||
num_planes = 3;
|
||||
size = out_width * out_height_full * 2;
|
||||
|
||||
if (in_size < in_width * in_height * 2)
|
||||
return 0;
|
||||
} else if (fmt == PIXEL_FORMAT_RGBA)
|
||||
{
|
||||
planes[0][0].data = out;
|
||||
planes[0][0].pitch = out_width * 4;
|
||||
planes[0][0].height = out_height;
|
||||
|
||||
planes[1][0].data = (uint8_t *)in;
|
||||
planes[1][0].pitch = in_width * 4;
|
||||
planes[1][0].height = in_height;
|
||||
|
||||
// Add the line offset
|
||||
planes[k][0].data += planes[k][0].pitch * line_offset;
|
||||
|
||||
num_planes = 1;
|
||||
size = out_width * out_height_full * 4;
|
||||
|
||||
if (in_size < in_width * in_height * 4)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (out_size < size)
|
||||
return 0;
|
||||
|
||||
// Special case for YUYV where don't just copy but convert to/from I422
|
||||
if (fmt == PIXEL_FORMAT_YUYV)
|
||||
{
|
||||
unsigned int width = in_width > out_width ? out_width : in_width;
|
||||
unsigned int height = in_height > out_height ? out_height : in_height;
|
||||
uint8_t *y = planes[convert_from ? 0 : 1][0].data;
|
||||
uint8_t *u = planes[convert_from ? 0 : 1][1].data;
|
||||
uint8_t *v = planes[convert_from ? 0 : 1][2].data;
|
||||
uint8_t *yuyv = planes[convert_from ? 1 : 0][0].data;
|
||||
unsigned int y_diff = (convert_from ? out_width : in_width) - width;
|
||||
unsigned int yuyv_diff = ((convert_from ? in_width : out_width) - width) * 2;
|
||||
|
||||
while (height--)
|
||||
{
|
||||
if (convert_from)
|
||||
for (i = width / 2; i; i--)
|
||||
{
|
||||
*y++ = *yuyv++;
|
||||
*u++ = *yuyv++;
|
||||
*y++ = *yuyv++;
|
||||
*v++ = *yuyv++;
|
||||
}
|
||||
else
|
||||
for (i = width / 2; i; i--)
|
||||
{
|
||||
*yuyv++ = *y++;
|
||||
*yuyv++ = *u++;
|
||||
*yuyv++ = *y++;
|
||||
*yuyv++ = *v++;
|
||||
}
|
||||
|
||||
yuyv += yuyv_diff;
|
||||
y += y_diff;
|
||||
u += y_diff >> 1;
|
||||
v += y_diff >> 1;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_planes; i++)
|
||||
{
|
||||
unsigned int width = MMAL_MIN(planes[0][i].pitch, planes[1][i].pitch);
|
||||
unsigned int height = MMAL_MIN(planes[0][i].height, planes[1][i].height);
|
||||
uint8_t *data_out = planes[0][i].data;
|
||||
uint8_t *data_in = planes[1][i].data;
|
||||
|
||||
while (height--)
|
||||
{
|
||||
memcpy(data_out, data_in, width);
|
||||
data_out += planes[0][i].pitch;
|
||||
data_in += planes[1][i].pitch;
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* Jpeg encoder and decoder library using the hardware jpeg codec
|
||||
*/
|
||||
|
||||
#ifndef BRCM_JPEG_H
|
||||
#define BRCM_JPEG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Status return codes from the API */
|
||||
typedef enum
|
||||
{
|
||||
BRCMJPEG_SUCCESS = 0,
|
||||
BRCMJPEG_ERROR_NOMEM,
|
||||
BRCMJPEG_ERROR_INIT,
|
||||
BRCMJPEG_ERROR_INPUT_FORMAT,
|
||||
BRCMJPEG_ERROR_OUTPUT_FORMAT,
|
||||
BRCMJPEG_ERROR_INPUT_BUFFER,
|
||||
BRCMJPEG_ERROR_OUTPUT_BUFFER,
|
||||
BRCMJPEG_ERROR_EXECUTE,
|
||||
BRCMJPEG_ERROR_REQUEST,
|
||||
} BRCMJPEG_STATUS_T;
|
||||
|
||||
/** Type of the codec instance to create */
|
||||
typedef enum
|
||||
{
|
||||
BRCMJPEG_TYPE_ENCODER = 0,
|
||||
BRCMJPEG_TYPE_DECODER
|
||||
} BRCMJPEG_TYPE_T;
|
||||
|
||||
/** Pixel formats supported by the codec */
|
||||
typedef enum
|
||||
{
|
||||
PIXEL_FORMAT_UNKNOWN = 0,
|
||||
PIXEL_FORMAT_I420, /* planar YUV 4:2:0 */
|
||||
PIXEL_FORMAT_YV12, /* planar YVU 4:2:0 */
|
||||
PIXEL_FORMAT_I422, /* planar YUV 4:2:2 */
|
||||
PIXEL_FORMAT_YV16, /* planar YVU 4:2:2 */
|
||||
PIXEL_FORMAT_YUYV, /* interleaved YUV 4:2:2 */
|
||||
PIXEL_FORMAT_RGBA, /* interleaved RGBA */
|
||||
} BRCMJPEG_PIXEL_FORMAT_T;
|
||||
|
||||
/** Definition of a codec request */
|
||||
typedef struct
|
||||
{
|
||||
/** Pointer to the buffer containing the input data
|
||||
* A client should set input OR input_handle, but not both. */
|
||||
const unsigned char *input;
|
||||
/** Actual size of the input data */
|
||||
unsigned int input_size;
|
||||
/** Handle to input buffer containing input data */
|
||||
unsigned int input_handle;
|
||||
|
||||
/** Pointer to the buffer used for the output data
|
||||
* A client should set output OR output_handle, but not both. */
|
||||
unsigned char *output;
|
||||
/** Total size of the output buffer */
|
||||
unsigned int output_alloc_size;
|
||||
/** Actual size of the output data (this is an output parameter) */
|
||||
unsigned int output_size;
|
||||
/** Handle to the buffer used for the output data */
|
||||
unsigned int output_handle;
|
||||
|
||||
/** Width of the raw frame (this is an input parameter for encode) */
|
||||
unsigned int width;
|
||||
/** Height of the raw frame (this is an input parameter for encode) */
|
||||
unsigned int height;
|
||||
/** Pixel format of the raw frame (this is an input parameter) */
|
||||
BRCMJPEG_PIXEL_FORMAT_T pixel_format;
|
||||
|
||||
/** Width of the buffer containing the raw frame (input parameter).
|
||||
* This is optional but if set, is used to specify the actual width
|
||||
* of the buffer containing the raw frame */
|
||||
unsigned int buffer_width;
|
||||
/** Height of the buffer containing the raw frame (input parameter).
|
||||
* This is optional but if set, is used to specify the actual height
|
||||
* of the buffer containing the raw frame */
|
||||
unsigned int buffer_height;
|
||||
|
||||
/** Encode quality - 0 to 100 */
|
||||
unsigned int quality;
|
||||
} BRCMJPEG_REQUEST_T;
|
||||
|
||||
/** Type of the codec instance */
|
||||
typedef struct BRCMJPEG_T BRCMJPEG_T;
|
||||
|
||||
/** Create an instance of the jpeg codec
|
||||
* This will actually re-use an existing instance if one is
|
||||
* available.
|
||||
*
|
||||
* @param type type of codec instance required
|
||||
* @param ctx will point to the newly created instance
|
||||
* @return BRCMJPEG_SUCCESS on success
|
||||
*/
|
||||
BRCMJPEG_STATUS_T brcmjpeg_create(BRCMJPEG_TYPE_T type, BRCMJPEG_T **ctx);
|
||||
|
||||
/** Acquire a new reference on a codec instance
|
||||
*
|
||||
* @param ctx instance to acquire a reference on
|
||||
*/
|
||||
void brcmjpeg_acquire(BRCMJPEG_T *ctx);
|
||||
|
||||
/** Release an instance of the jpeg codec
|
||||
* This will only trigger the destruction of the codec instance when
|
||||
* the last reference to it is being released.
|
||||
*
|
||||
* @param ctx instance to release
|
||||
*/
|
||||
void brcmjpeg_release(BRCMJPEG_T *ctx);
|
||||
|
||||
/** Process a jpeg codec request
|
||||
*
|
||||
* @param ctx instance of codec to use
|
||||
* @param request codec request to execute
|
||||
* @return BRCMJPEG_SUCCESS on success
|
||||
*/
|
||||
BRCMJPEG_STATUS_T brcmjpeg_process(BRCMJPEG_T *ctx, BRCMJPEG_REQUEST_T *request);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BRCM_JPEG_H */
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "brcmjpeg.h"
|
||||
#include <sys/time.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <user-vcsm.h>
|
||||
|
||||
#define MAX_WIDTH 5000
|
||||
#define MAX_HEIGHT 5000
|
||||
#define MAX_ENCODED (15*1024*1024)
|
||||
#define MAX_DECODED (MAX_WIDTH*MAX_HEIGHT*2)
|
||||
|
||||
static uint8_t encodedInBuf[MAX_ENCODED];
|
||||
static uint8_t encodedOutBuf[MAX_ENCODED];
|
||||
static uint8_t decodedBuf[MAX_DECODED];
|
||||
static char outFileName[2048];
|
||||
|
||||
int64_t get_time_microsec(void)
|
||||
{
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
return now.tv_sec * 1000000LL + now.tv_usec;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
BRCMJPEG_STATUS_T status;
|
||||
BRCMJPEG_REQUEST_T enc_request, dec_request;
|
||||
BRCMJPEG_T *enc = 0, *dec = 0;
|
||||
int64_t start, stop, time_dec = 0, time_enc = 0;
|
||||
unsigned int count = 1, format = PIXEL_FORMAT_YUYV;
|
||||
unsigned int use_vcsm = 0, handle = 0, vc_handle = 0;
|
||||
int i, arg = 1, help = 0;
|
||||
|
||||
// Parse command line arguments
|
||||
while (arg < argc && argv[arg][0] == '-')
|
||||
{
|
||||
if (!strcmp(argv[arg], "-n"))
|
||||
{
|
||||
if (++arg >= argc || sscanf(argv[arg++], "%u", &count) != 1)
|
||||
arg = argc;
|
||||
}
|
||||
else if (!strcmp(argv[arg], "-f"))
|
||||
{
|
||||
if (++arg >= argc || sscanf(argv[arg++], "%u", &format) != 1)
|
||||
arg = argc;
|
||||
}
|
||||
else if (!strcmp(argv[arg], "-s"))
|
||||
{
|
||||
use_vcsm = 1;
|
||||
arg++;
|
||||
}
|
||||
else if (!strcmp(argv[arg], "-h"))
|
||||
{
|
||||
help = 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
arg = argc;
|
||||
}
|
||||
}
|
||||
|
||||
if (arg == argc || help)
|
||||
{
|
||||
if (!help) fprintf(stderr, "invalid arguments\n");
|
||||
fprintf(stderr, "usage: %s [options] file1 ... fileN\n", argv[0]);
|
||||
fprintf(stderr, "options list:\n");
|
||||
fprintf(stderr, " -h : help\n");
|
||||
fprintf(stderr, " -n <N> : process each file N times\n");
|
||||
fprintf(stderr, " -f <N> : force color format\n");
|
||||
fprintf(stderr, " -s : use shared-memory for intermediate buffer\n");
|
||||
return !help;
|
||||
}
|
||||
|
||||
if (use_vcsm)
|
||||
{
|
||||
if (vcsm_init() < 0)
|
||||
{
|
||||
fprintf(stderr, "failed to initialise vcsm\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
handle = vcsm_malloc_cache(MAX_DECODED, VCSM_CACHE_TYPE_HOST, "brcmjpeg-test");
|
||||
if (!handle)
|
||||
{
|
||||
fprintf(stderr, "failed to alloc vcsm buffer\n");
|
||||
vcsm_exit();
|
||||
return 1;
|
||||
}
|
||||
|
||||
vc_handle = vcsm_vc_hdl_from_hdl(handle);
|
||||
|
||||
fprintf(stderr, "decodedBuf handle %u vc_handle %u\n", handle, vc_handle);
|
||||
}
|
||||
|
||||
// Setup of the dec / enc requests
|
||||
memset(&enc_request, 0, sizeof(enc_request));
|
||||
memset(&dec_request, 0, sizeof(dec_request));
|
||||
dec_request.input = encodedInBuf;
|
||||
dec_request.output = use_vcsm ? NULL : decodedBuf;
|
||||
dec_request.output_handle = use_vcsm ? vc_handle : 0;
|
||||
dec_request.output_alloc_size = MAX_DECODED;
|
||||
enc_request.input = dec_request.output;
|
||||
enc_request.input_handle = dec_request.output_handle;
|
||||
enc_request.output = encodedOutBuf;
|
||||
enc_request.output_alloc_size = sizeof(encodedOutBuf);
|
||||
enc_request.quality = 75;
|
||||
enc_request.pixel_format = dec_request.pixel_format = format;
|
||||
|
||||
status = brcmjpeg_create(BRCMJPEG_TYPE_ENCODER, &enc);
|
||||
if (status != BRCMJPEG_SUCCESS)
|
||||
{
|
||||
fprintf(stderr, "could not create encoder\n");
|
||||
return 1;
|
||||
}
|
||||
status = brcmjpeg_create(BRCMJPEG_TYPE_DECODER, &dec);
|
||||
if (status != BRCMJPEG_SUCCESS)
|
||||
{
|
||||
fprintf(stderr, "could not create decoder\n");
|
||||
brcmjpeg_release(enc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = arg; i < argc; i++)
|
||||
{
|
||||
unsigned int j;
|
||||
fprintf(stderr, "processing %s\n", argv[i]);
|
||||
|
||||
FILE *file_in = fopen(argv[i], "rb");
|
||||
if (!file_in) {
|
||||
fprintf(stderr, "could not open file %s\n", argv[i]);
|
||||
continue;
|
||||
}
|
||||
snprintf(outFileName, sizeof(outFileName), "%s.out", argv[i]);
|
||||
FILE *file_out = fopen(outFileName, "wb+");
|
||||
if (!file_out) {
|
||||
fprintf(stderr, "could not open file %s\n", outFileName);
|
||||
fclose(file_in);
|
||||
continue;
|
||||
}
|
||||
dec_request.input_size = fread(encodedInBuf, 1, sizeof(encodedInBuf), file_in);
|
||||
|
||||
for (j = 0; j < count; j++)
|
||||
{
|
||||
dec_request.buffer_width = 0;
|
||||
dec_request.buffer_height = 0;
|
||||
|
||||
start = get_time_microsec();
|
||||
status = brcmjpeg_process(dec, &dec_request);
|
||||
stop = get_time_microsec();
|
||||
if (status != BRCMJPEG_SUCCESS) {
|
||||
fprintf(stderr, "could not decode %s\n", argv[i]);
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(stderr, "decoded %ix%i(%ix%i), %i bytes in %lldus\n",
|
||||
dec_request.width, dec_request.height,
|
||||
dec_request.buffer_width, dec_request.buffer_height,
|
||||
dec_request.input_size, stop - start);
|
||||
time_dec += stop - start;
|
||||
|
||||
enc_request.input_size = dec_request.output_size;
|
||||
enc_request.width = dec_request.width;
|
||||
enc_request.height = dec_request.height;
|
||||
enc_request.buffer_width = dec_request.buffer_width;
|
||||
enc_request.buffer_height = dec_request.buffer_height;
|
||||
|
||||
start = get_time_microsec();
|
||||
status = brcmjpeg_process(enc, &enc_request);
|
||||
stop = get_time_microsec();
|
||||
if (status != BRCMJPEG_SUCCESS) {
|
||||
fprintf(stderr, "could not encode %s\n", outFileName);
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(stderr, "encoded %ix%i(%ix%i), %i bytes in %lldus\n",
|
||||
enc_request.width, enc_request.height,
|
||||
enc_request.buffer_width, enc_request.buffer_height,
|
||||
enc_request.output_size, stop - start);
|
||||
time_enc += stop - start;
|
||||
}
|
||||
|
||||
if (status != BRCMJPEG_SUCCESS)
|
||||
continue;
|
||||
|
||||
fwrite(enc_request.output, 1, enc_request.output_size, file_out);
|
||||
fclose(file_out);
|
||||
fclose(file_in);
|
||||
|
||||
fprintf(stderr, "decode times %lldus (%lldus per run)\n",
|
||||
time_dec, time_dec / count);
|
||||
fprintf(stderr, "encode times %lldus (%lldus per run)\n",
|
||||
time_enc, time_enc / count);
|
||||
}
|
||||
|
||||
brcmjpeg_release(dec);
|
||||
brcmjpeg_release(enc);
|
||||
|
||||
if (use_vcsm)
|
||||
{
|
||||
vcsm_free(handle);
|
||||
vcsm_exit();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user