Files
OpenTXW81X/sdk/app/zbar/video.c
T
2025-08-27 09:51:58 +01:00

441 lines
12 KiB
C

/*------------------------------------------------------------------------
* Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
#include "video.h"
#include "image.h"
#ifdef HAVE_LIBJPEG
extern struct jpeg_decompress_struct *_zbar_jpeg_decomp_create(void);
extern void _zbar_jpeg_decomp_destroy(struct jpeg_decompress_struct *cinfo);
#endif
static void _zbar_video_recycle_image (zbar_image_t *img)
{
zbar_video_t *vdo = img->src;
assert(vdo);
assert(img->srcidx >= 0);
video_lock(vdo);
if(vdo->images[img->srcidx] != img)
vdo->images[img->srcidx] = img;
if(vdo->active)
vdo->nq(vdo, img);
else
video_unlock(vdo);
}
static void _zbar_video_recycle_shadow (zbar_image_t *img)
{
zbar_video_t *vdo = img->src;
assert(vdo);
assert(img->srcidx == -1);
video_lock(vdo);
img->next = vdo->shadow_image;
vdo->shadow_image = img;
video_unlock(vdo);
}
zbar_video_t *zbar_video_create ()
{
zbar_video_t *vdo = calloc(1, sizeof(zbar_video_t));
int i;
if(!vdo)
return(NULL);
err_init(&vdo->err, ZBAR_MOD_VIDEO);
vdo->fd = -1;
(void)_zbar_mutex_init(&vdo->qlock);
/* pre-allocate images */
vdo->num_images = ZBAR_VIDEO_IMAGES_MAX;
vdo->images = calloc(ZBAR_VIDEO_IMAGES_MAX, sizeof(zbar_image_t*));
if(!vdo->images) {
zbar_video_destroy(vdo);
return(NULL);
}
for(i = 0; i < ZBAR_VIDEO_IMAGES_MAX; i++) {
zbar_image_t *img = vdo->images[i] = zbar_image_create();
if(!img) {
zbar_video_destroy(vdo);
return(NULL);
}
img->refcnt = 0;
img->cleanup = _zbar_video_recycle_image;
img->srcidx = i;
img->src = vdo;
}
return(vdo);
}
void zbar_video_destroy (zbar_video_t *vdo)
{
if(vdo->intf != VIDEO_INVALID)
zbar_video_open(vdo, NULL);
if(vdo->images) {
int i;
for(i = 0; i < ZBAR_VIDEO_IMAGES_MAX; i++)
if(vdo->images[i])
_zbar_image_free(vdo->images[i]);
free(vdo->images);
}
while(vdo->shadow_image) {
zbar_image_t *img = vdo->shadow_image;
vdo->shadow_image = img->next;
free((void*)img->data);
img->data = NULL;
free(img);
}
if(vdo->buf)
free(vdo->buf);
if(vdo->formats)
free(vdo->formats);
if(vdo->emu_formats)
free(vdo->emu_formats);
if(vdo->free)
vdo->free(vdo);
err_cleanup(&vdo->err);
_zbar_mutex_destroy(&vdo->qlock);
#ifdef HAVE_LIBJPEG
if(vdo->jpeg_img) {
zbar_image_destroy(vdo->jpeg_img);
vdo->jpeg_img = NULL;
}
if(vdo->jpeg) {
_zbar_jpeg_decomp_destroy(vdo->jpeg);
vdo->jpeg = NULL;
}
#endif
free(vdo);
}
int zbar_video_open (zbar_video_t *vdo,
const char *dev)
{
char *ldev = NULL;
int rc;
zbar_video_enable(vdo, 0);
video_lock(vdo);
if(vdo->intf != VIDEO_INVALID) {
if(vdo->cleanup) {
vdo->cleanup(vdo);
vdo->cleanup = NULL;
}
zprintf(1, "closed camera (fd=%d)\n", vdo->fd);
vdo->intf = VIDEO_INVALID;
}
video_unlock(vdo);
if(!dev)
return(0);
if((unsigned char)dev[0] < 0x10) {
/* default linux device, overloaded for other platforms */
int id = dev[0];
dev = ldev = strdup("/dev/video0");
ldev[10] = '0' + id;
}
rc = _zbar_video_open(vdo, dev);
if(ldev)
free(ldev);
return(rc);
}
int zbar_video_get_fd (const zbar_video_t *vdo)
{
if(vdo->intf == VIDEO_INVALID)
return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_INVALID, __func__,
"video device not opened"));
if(vdo->intf != VIDEO_V4L2)
return(err_capture(vdo, SEV_WARNING, ZBAR_ERR_UNSUPPORTED, __func__,
"video driver does not support polling"));
return(vdo->fd);
}
int zbar_video_request_size (zbar_video_t *vdo,
unsigned width,
unsigned height)
{
if(vdo->initialized)
/* FIXME re-init different format? */
return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_INVALID, __func__,
"already initialized, unable to resize"));
vdo->width = width;
vdo->height = height;
zprintf(1, "request size: %d x %d\n", width, height);
return(0);
}
int zbar_video_request_interface (zbar_video_t *vdo,
int ver)
{
if(vdo->intf != VIDEO_INVALID)
return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_INVALID, __func__,
"device already opened, unable to change interface"));
vdo->intf = (video_interface_t)ver;
zprintf(1, "request interface version %d\n", vdo->intf);
return(0);
}
int zbar_video_request_iomode (zbar_video_t *vdo,
int iomode)
{
if(vdo->intf != VIDEO_INVALID)
return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_INVALID, __func__,
"device already opened, unable to change iomode"));
if(iomode < 0 || iomode > VIDEO_USERPTR)
return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_INVALID, __func__,
"invalid iomode requested"));
vdo->iomode = iomode;
return(0);
}
int zbar_video_get_width (const zbar_video_t *vdo)
{
return(vdo->width);
}
int zbar_video_get_height (const zbar_video_t *vdo)
{
return(vdo->height);
}
uint32_t zbar_video_get_format (const zbar_video_t *vdo)
{
return(vdo->format);
}
static inline int video_init_images (zbar_video_t *vdo)
{
int i;
assert(vdo->datalen);
if(vdo->iomode != VIDEO_MMAP) {
assert(!vdo->buf);
vdo->buflen = vdo->num_images * vdo->datalen;
vdo->buf = calloc(1, vdo->buflen);
if(!vdo->buf)
return(err_capture(vdo, SEV_FATAL, ZBAR_ERR_NOMEM, __func__,
"unable to allocate image buffers"));
zprintf(1, "pre-allocated %d %s buffers size=0x%lx\n", vdo->num_images,
(vdo->iomode == VIDEO_READWRITE) ? "READ" : "USERPTR",
vdo->buflen);
}
for(i = 0; i < vdo->num_images; i++) {
zbar_image_t *img = vdo->images[i];
img->format = vdo->format;
zbar_image_set_size(img, vdo->width, vdo->height);
if(vdo->iomode != VIDEO_MMAP) {
unsigned long offset = i * vdo->datalen;
img->datalen = vdo->datalen;
img->data = (uint8_t*)vdo->buf + offset;
zprintf(2, " [%02d] @%08lx\n", i, offset);
}
}
return(0);
}
int zbar_video_init (zbar_video_t *vdo,
unsigned long fmt)
{
#ifdef HAVE_LIBJPEG
const zbar_format_def_t *vidfmt;
#endif
if(vdo->initialized)
/* FIXME re-init different format? */
return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_INVALID, __func__,
"already initialized, re-init unimplemented"));
if(vdo->init(vdo, fmt))
return(-1);
vdo->format = fmt;
if(video_init_images(vdo))
return(-1);
#ifdef HAVE_LIBJPEG
vidfmt = _zbar_format_lookup(fmt);
if(vidfmt && vidfmt->group == ZBAR_FMT_JPEG) {
zbar_image_t *img;
/* prepare for decoding */
if(!vdo->jpeg)
vdo->jpeg = _zbar_jpeg_decomp_create();
if(vdo->jpeg_img)
zbar_image_destroy(vdo->jpeg_img);
/* create intermediate image for decoder to use*/
img = vdo->jpeg_img = zbar_image_create();
img->format = fourcc('Y','8','0','0');
zbar_image_set_size(img, vdo->width, vdo->height);
img->datalen = vdo->width * vdo->height;
}
#endif
vdo->initialized = 1;
return(0);
}
int zbar_video_enable (zbar_video_t *vdo,
int enable)
{
if(vdo->active == enable)
return(0);
if(enable) {
if(vdo->intf == VIDEO_INVALID)
return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_INVALID, __func__,
"video device not opened"));
if(!vdo->initialized &&
zbar_negotiate_format(vdo, NULL))
return(-1);
}
if(video_lock(vdo))
return(-1);
vdo->active = enable;
if(enable) {
/* enqueue all buffers */
int i;
for(i = 0; i < vdo->num_images; i++)
if(vdo->nq(vdo, vdo->images[i]) ||
((i + 1 < vdo->num_images) && video_lock(vdo)))
return(-1);
return(vdo->start(vdo));
}
else {
int i;
for(i = 0; i < vdo->num_images; i++)
vdo->images[i]->next = NULL;
vdo->nq_image = vdo->dq_image = NULL;
if(video_unlock(vdo))
return(-1);
return(vdo->stop(vdo));
}
}
zbar_image_t *zbar_video_next_image (zbar_video_t *vdo)
{
unsigned frame;
zbar_image_t *img;
if(video_lock(vdo))
return(NULL);
if(!vdo->active) {
video_unlock(vdo);
return(NULL);
}
frame = vdo->frame++;
img = vdo->dq(vdo);
if(img) {
img->seq = frame;
if(vdo->num_images < 2) {
/* return a *copy* of the video image and immediately recycle
* the driver's buffer to avoid deadlocking the resources
*/
zbar_image_t *tmp = img;
video_lock(vdo);
img = vdo->shadow_image;
vdo->shadow_image = (img) ? img->next : NULL;
video_unlock(vdo);
if(!img) {
img = zbar_image_create();
assert(img);
img->refcnt = 0;
img->src = vdo;
/* recycle the shadow images */
img->format = vdo->format;
zbar_image_set_size(img, vdo->width, vdo->height);
img->datalen = vdo->datalen;
img->data = malloc(vdo->datalen);
}
img->cleanup = _zbar_video_recycle_shadow;
img->seq = frame;
memcpy((void*)img->data, tmp->data, img->datalen);
_zbar_video_recycle_image(tmp);
}
else
img->cleanup = _zbar_video_recycle_image;
_zbar_image_refcnt(img, 1);
}
return(img);
}
/** @brief return if fun unsupported, otherwise continue */
#define return_if_not_supported(fun, name) \
{ \
if(!(fun)) { \
zprintf(1, "video driver does not implement %s\n", name); \
return ZBAR_ERR_UNSUPPORTED; \
} \
}
#define return_if_non_zero(a) { int rv=a; if (rv!=0) return(rv); }
int zbar_video_set_control (zbar_video_t *vdo,
const char *control_name,
int value)
{
int loc_value, rv;
return_if_not_supported(vdo->set_control, "set_control");
loc_value = value;
rv = vdo->set_control(vdo, control_name, &loc_value);
if(rv==0)
zprintf(1, "value of %s set to: %d\n", control_name, loc_value);
return(rv);
}
int zbar_video_get_control (zbar_video_t *vdo,
const char *control_name,
int *value)
{
return_if_not_supported(vdo->get_control, "get_control");
return(vdo->get_control(vdo, control_name, value));
}
struct video_controls_s *zbar_video_get_controls (const zbar_video_t *vdo,
int index)
{
int i = 0;
struct video_controls_s *p = vdo->controls;
while (p && i != index) {
i++;
p = p->next;
}
if (!p)
return NULL;
return p;
}