Änderungen Gruppe 30_10_2022 V2

This commit is contained in:
2022-10-30 20:01:47 +01:00
parent 269f807b31
commit 2517e52e59
239 changed files with 54983 additions and 9 deletions
@@ -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)
@@ -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;
}
@@ -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 */
@@ -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;
}