mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 16:50:47 +00:00
first batch
Original commit message from CVS: first batch
This commit is contained in:
parent
49d345d9ef
commit
bb8c108211
13 changed files with 2620 additions and 0 deletions
5
sys/Makefile.am
Normal file
5
sys/Makefile.am
Normal file
|
@ -0,0 +1,5 @@
|
|||
### use HAVE_ stuff to decide on dirs
|
||||
DIRS=qcam v4l vcdsrc vgasink xvideosink
|
||||
|
||||
DIST_SUBDIRS=qcam v4l vcdsrc vgasink xvideosink
|
||||
|
10
sys/qcam/Makefile.am
Normal file
10
sys/qcam/Makefile.am
Normal file
|
@ -0,0 +1,10 @@
|
|||
plugindir = $(libdir)/gst
|
||||
|
||||
plugin_LTLIBRARIES = libgstqcam.la
|
||||
|
||||
EXTRA_DIST = qcam-os.c qcam-Linux.c
|
||||
|
||||
libgstqcam_la_SOURCES = gstqcamsrc.c qcam-lib.c exposure.c
|
||||
libgstqcam_la_CFLAGS = -O2 $(GLIB_CFLAGS)
|
||||
|
||||
noinst_HEADERS = gstqcamsrc.h qcam-os.h qcam.h qcamip.h qcam-Linux.h
|
253
sys/qcam/dark.c
Normal file
253
sys/qcam/dark.c
Normal file
|
@ -0,0 +1,253 @@
|
|||
/******************************************************************
|
||||
|
||||
Copyright (C) 1996 by Brian Scearce
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
and/or distribute copies of the Software, and to permit persons to whom
|
||||
the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
1. The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
2. Redistribution for profit requires the express, written permission of
|
||||
the author.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL BRIAN SCEARCE BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
******************************************************************/
|
||||
|
||||
/** Fixdark
|
||||
Routine to repair dark current artifacts in qcam output.
|
||||
Basic idea: the Qcam CCD suffers from "dark current";
|
||||
that is, some of the CCD pixels will leak current under
|
||||
long exposures, even if they're in the dark, and this
|
||||
shows up as ugly speckling on images taken in low light.
|
||||
|
||||
Fortunately, the leaky pixels are the same from shot to
|
||||
shot. So, we can figure out which pixels are leaky by
|
||||
taking some establishing shots in the dark, and try to
|
||||
fix those pixels on subsequent shots. The dark
|
||||
establishing shots need only be done once per camera.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "qcam.h"
|
||||
#define MAX_LOOPS 10
|
||||
#define FNAME "qcam.darkfile"
|
||||
|
||||
static unsigned char master_darkmask1[MAX_HEIGHT][MAX_WIDTH];
|
||||
static unsigned char master_darkmask2[MAX_HEIGHT/2+1][MAX_WIDTH/2+1];
|
||||
static unsigned char master_darkmask4[MAX_HEIGHT/4+1][MAX_WIDTH/4+1];
|
||||
|
||||
/*
|
||||
int
|
||||
read_darkmask()
|
||||
{
|
||||
int x, y;
|
||||
int min_bright;
|
||||
char darkfile[BUFSIZ], *p;
|
||||
FILE *fp;
|
||||
|
||||
strcpy(darkfile, CONFIG_FILE);
|
||||
if ( (p = strrchr(darkfile, '/'))) {
|
||||
strcpy(p+1, FNAME);
|
||||
} else {
|
||||
strcpy(darkfile, FNAME);
|
||||
}
|
||||
|
||||
if (!(fp = fopen(darkfile, "r"))) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Can't open darkfile %s\n", darkfile);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fread(master_darkmask1, sizeof(unsigned char), MAX_WIDTH*MAX_HEIGHT, fp) !=
|
||||
MAX_WIDTH*MAX_HEIGHT) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Error reading darkfile\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (y = 0; y < MAX_HEIGHT; y += 2) {
|
||||
for (x = 0; x < MAX_WIDTH; x += 2) {
|
||||
min_bright = master_darkmask1[y][x];
|
||||
if (y < MAX_HEIGHT-1 && master_darkmask1[y+1][x] < min_bright)
|
||||
min_bright = master_darkmask1[y+1][x];
|
||||
if (x < MAX_WIDTH-1 && master_darkmask1[y][x+1] < min_bright)
|
||||
min_bright = master_darkmask1[y][x+1];
|
||||
if (y < MAX_HEIGHT-1 && x < MAX_WIDTH-1 && master_darkmask1[y+1][x+1] < min_bright)
|
||||
min_bright = master_darkmask1[y+1][x+1];
|
||||
master_darkmask2[y/2][x/2] = min_bright;
|
||||
assert(y/2 < MAX_HEIGHT/2+1);
|
||||
assert(x/2 < MAX_WIDTH/2+1);
|
||||
}
|
||||
}
|
||||
|
||||
for (y = 0; y < MAX_HEIGHT/2; y += 2) {
|
||||
for (x = 0; x < MAX_WIDTH/2; x += 2) {
|
||||
min_bright = master_darkmask2[y][x];
|
||||
if (y < MAX_HEIGHT/2-1 && master_darkmask2[y+1][x] < min_bright)
|
||||
min_bright = master_darkmask2[y+1][x];
|
||||
if (x < MAX_WIDTH/2-1 && master_darkmask2[y][x+1] < min_bright)
|
||||
min_bright = master_darkmask2[y][x+1];
|
||||
if (y < MAX_HEIGHT/2-1 && x < MAX_WIDTH-1 && master_darkmask2[y+1][x+1] < min_bright)
|
||||
min_bright = master_darkmask2[y+1][x+1];
|
||||
master_darkmask4[y/2][x/2] = min_bright;
|
||||
assert(y/2 < MAX_HEIGHT/4+1);
|
||||
assert(x/2 < MAX_WIDTH/4+1);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/** fixdark
|
||||
We first record a list of bad leaky pixels, by making a
|
||||
number of exposures in the dark. master_darkmask holds
|
||||
this information. It's a map of the CCD.
|
||||
master_darkmask[y][x] == val means that the pixel is
|
||||
unreliable for brightnesses of "val" and above.
|
||||
|
||||
We go over the image. If a pixel is bad, look at the
|
||||
adjacent four pixels, average the ones that have good
|
||||
values, and use that instead.
|
||||
*/
|
||||
|
||||
int
|
||||
fixdark(const struct qcam *q, scanbuf *scan)
|
||||
{
|
||||
static int init = 0;
|
||||
static int smallest_dm = 255;
|
||||
unsigned char darkmask[MAX_HEIGHT][MAX_WIDTH];
|
||||
unsigned char new_image[MAX_HEIGHT][MAX_WIDTH];
|
||||
int width, height;
|
||||
int max_width, max_height;
|
||||
int x, y;
|
||||
int ccd_x, ccd_y;
|
||||
int pixelcount, pixeltotal;
|
||||
int again, loopcount = 0;
|
||||
int val;
|
||||
int brightness = q->brightness;
|
||||
int scale = q->transfer_scale;
|
||||
|
||||
if (!init) {
|
||||
if (!read_darkmask()) return 0;
|
||||
for (y = 0; y < MAX_HEIGHT; y++)
|
||||
for (x = 0; x < MAX_HEIGHT; x++)
|
||||
if (master_darkmask1[y][x] < smallest_dm) {
|
||||
smallest_dm = master_darkmask1[y][x];
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Smallest mask is %d at (%d, %d)\n",
|
||||
smallest_dm, x, y);
|
||||
#endif
|
||||
}
|
||||
init = 1;
|
||||
}
|
||||
|
||||
if (brightness < smallest_dm) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Brightness %d (dark current starts at %d), no fixup needed\n",
|
||||
brightness, smallest_dm);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
width = q->width / scale;
|
||||
height = q->height / scale;
|
||||
|
||||
max_height = MAX_HEIGHT / scale;
|
||||
max_width = MAX_WIDTH / scale;
|
||||
for (y = 0; y < max_height; y++)
|
||||
for (x = 0; x < max_width; x++)
|
||||
if (scale == 1) {
|
||||
darkmask[y][x] = master_darkmask1[y][x];
|
||||
} else if (scale == 2) {
|
||||
darkmask[y][x] = master_darkmask2[y][x];
|
||||
} else if (scale == 4) {
|
||||
darkmask[y][x] = master_darkmask4[y][x];
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Bad transfer_scale in darkmask assignment!\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
again = 0;
|
||||
ccd_y = (q->top-1)/scale;
|
||||
for (y = 0; y < height; y++, ccd_y++) {
|
||||
ccd_x = q->left-1;
|
||||
ccd_x /= 2;
|
||||
ccd_x *= 2;
|
||||
ccd_x /= scale;
|
||||
for (x = 0; x < width; x++, ccd_x++) {
|
||||
val = scan[y*width + x];
|
||||
if (brightness < darkmask[ccd_y][ccd_x]) { /* good pixel */
|
||||
new_image[y][x] = val;
|
||||
} else { /* bad pixel */
|
||||
/* look at nearby pixels, average the good values */
|
||||
pixelcount = 0;
|
||||
pixeltotal = 0;
|
||||
if (x > 0) { /* left */
|
||||
if (brightness < darkmask[ccd_y][ccd_x-1]) {
|
||||
pixelcount++;
|
||||
pixeltotal += scan[y*width + x - 1];
|
||||
}
|
||||
}
|
||||
if (x < width-1) { /* right */
|
||||
if (brightness < darkmask[ccd_y][ccd_x+1]) {
|
||||
pixelcount++;
|
||||
pixeltotal += scan[y*width + x + 1];
|
||||
}
|
||||
}
|
||||
if (y > 0) { /* above */
|
||||
if (brightness < darkmask[ccd_y-1][ccd_x]) {
|
||||
pixelcount++;
|
||||
pixeltotal += scan[(y-1)*width + x];
|
||||
}
|
||||
}
|
||||
if (y < height-1) { /* below */
|
||||
if (brightness < darkmask[ccd_y+1][ccd_x]) {
|
||||
pixelcount++;
|
||||
pixeltotal += scan[(y+1)*width + x];
|
||||
}
|
||||
}
|
||||
|
||||
if (pixelcount == 0) { /* no valid neighbors! */
|
||||
again = 1;
|
||||
} else {
|
||||
new_image[y][x] = pixeltotal / pixelcount;
|
||||
/* mark this pixel as valid, so we don't loop forever */
|
||||
darkmask[ccd_y][ccd_x] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
for (x = 0; x < width; x++)
|
||||
scan[y*width + x] = new_image[y][x];
|
||||
|
||||
} while (loopcount++ < MAX_LOOPS && again);
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Darkmask fix took %d loop%s\n",
|
||||
loopcount, (loopcount == 1)?"":"s");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
284
sys/qcam/exposure.c
Normal file
284
sys/qcam/exposure.c
Normal file
|
@ -0,0 +1,284 @@
|
|||
/* exposure.c
|
||||
*
|
||||
* Time-stamp: <02 Sep 96 11:52:21 HST edo@eosys.com>
|
||||
*
|
||||
* Version 0.2
|
||||
*/
|
||||
|
||||
|
||||
/******************************************************************
|
||||
|
||||
Copyright (C) 1996 by Ed Orcutt Systems
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, and/or distribute copies of the
|
||||
Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
1. The above copyright notice and this permission notice shall
|
||||
be included in all copies or substantial portions of the
|
||||
Software.
|
||||
|
||||
2. Redistribution for profit requires the express, written
|
||||
permission of the author.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL ED ORCUTT SYSTEMS BE LIABLE
|
||||
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
******************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "qcam.h"
|
||||
#include "qcamip.h"
|
||||
|
||||
/* Prototypes for private (static) functions used by the routines
|
||||
* within this file. Externally visible functions should be
|
||||
* prototyped in qcamip.h
|
||||
*/
|
||||
|
||||
static int qcip_pixel_average(struct qcam *q, scanbuf *scan);
|
||||
static int qcip_luminance_std(struct qcam *q, scanbuf *scan, int avg);
|
||||
|
||||
/* Private data used by the auto exposure routine */
|
||||
|
||||
static int luminance_target = -1;
|
||||
static int luminance_tolerance = 0;
|
||||
static int luminance_std_target = -1;
|
||||
static int luminance_std_tolerance = 0;
|
||||
static int ae_mode = AE_ALL_AVG;
|
||||
|
||||
/* Calculate average pixel value for entire image */
|
||||
|
||||
static int
|
||||
qcip_pixel_average(struct qcam *q, scanbuf *scan)
|
||||
{
|
||||
int count = 0;
|
||||
int sum = 0;
|
||||
int pixels;
|
||||
int i;
|
||||
|
||||
pixels = q->height / q->transfer_scale;
|
||||
pixels *= q->width / q->transfer_scale;
|
||||
|
||||
for (i = 0; i < pixels; i++) {
|
||||
sum += scan[i];
|
||||
count++;
|
||||
}
|
||||
return (sum / count);
|
||||
}
|
||||
|
||||
/* Calculate average pixel value for center of image */
|
||||
|
||||
static int
|
||||
qcip_pixel_average_center(struct qcam *q, scanbuf *scan)
|
||||
{
|
||||
int count = 0;
|
||||
int sum = 0;
|
||||
int height, width;
|
||||
int maxrow, maxcol;
|
||||
int i, j;
|
||||
|
||||
/* actual image width & height after scaling */
|
||||
width = q->width / q->transfer_scale;
|
||||
height = q->height / q->transfer_scale;
|
||||
|
||||
maxcol = width * 2 / 3;
|
||||
maxrow = height * 2 / 3;
|
||||
|
||||
for (i = width/3; i < maxcol; i++) {
|
||||
for (j = height/3; j < maxrow; j++) {
|
||||
sum += scan[j*width+i];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return (sum / count);
|
||||
}
|
||||
|
||||
int
|
||||
qcip_set_luminance_target(struct qcam *q, int val)
|
||||
{
|
||||
const int max_pixel_val = q->bpp == 6 ? 63 : 15;
|
||||
|
||||
if ((val - luminance_tolerance) >= 0 &&
|
||||
(val + luminance_tolerance) <= max_pixel_val) {
|
||||
luminance_target = val;
|
||||
return QCIP_XPSR_OK;
|
||||
}
|
||||
return QCIP_XPSR_LUM_INVLD;
|
||||
}
|
||||
|
||||
int
|
||||
qcip_set_luminance_tolerance(struct qcam *q, int val)
|
||||
{
|
||||
const int max_pixel_val = q->bpp == 6 ? 63 : 15;
|
||||
|
||||
/* set target if it has not been explicitly set */
|
||||
if (luminance_target == -1) {
|
||||
luminance_target = q->bpp == 6 ? 32 : 8;
|
||||
}
|
||||
|
||||
if ((luminance_target - val) >= 0 &&
|
||||
(luminance_target + val) <= max_pixel_val) {
|
||||
luminance_tolerance = val;
|
||||
return QCIP_XPSR_OK;
|
||||
}
|
||||
return QCIP_XPSR_LUM_INVLD;
|
||||
}
|
||||
|
||||
int
|
||||
qcip_set_luminance_std_target(struct qcam *q, int val)
|
||||
{
|
||||
luminance_std_target = val;
|
||||
return QCIP_XPSR_OK;
|
||||
}
|
||||
|
||||
int
|
||||
qcip_set_luminance_std_tolerance(struct qcam *q, int val)
|
||||
{
|
||||
luminance_std_tolerance = val;
|
||||
return QCIP_XPSR_OK;
|
||||
}
|
||||
|
||||
int
|
||||
qcip_set_autoexposure_mode(int val)
|
||||
{
|
||||
ae_mode = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calculate standard deviation of pixel value for entire image */
|
||||
|
||||
static int
|
||||
qcip_luminance_std(struct qcam *q, scanbuf *scan, int avg)
|
||||
{
|
||||
int count = 0;
|
||||
int sum = 0;
|
||||
int pixels;
|
||||
int i;
|
||||
|
||||
pixels = q->height / q->transfer_scale;
|
||||
pixels *= q->width / q->transfer_scale;
|
||||
|
||||
for (i = 0; i < pixels; i++) {
|
||||
if (scan[i] < avg) {
|
||||
sum += avg - scan[i];
|
||||
} else {
|
||||
sum += scan[i] - avg;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
return (sum / count);
|
||||
}
|
||||
|
||||
|
||||
/* If necessary adjust the brightness in an attempt to achieve
|
||||
* a target average pixel value: 32 for 6 bpp, 8 for 4bpp.
|
||||
* This routine *will* modify the brightness value in preparation
|
||||
* for another scan unless the target average pixel values has
|
||||
* been reached. If the exposure is correct (yes, I realize that
|
||||
* this is subjective) QCIP_XPSR_OK will be returned, otherwise
|
||||
* return QCIP_XPSR_RSCN after adjusting the exposure.
|
||||
*
|
||||
* Caveat: If the new calculated brightness value is invalid,
|
||||
* QCIP_XPSR_ERR will be returned.
|
||||
*/
|
||||
|
||||
int
|
||||
qcip_autoexposure(struct qcam *q, scanbuf *scan)
|
||||
{
|
||||
int luminance_dif;
|
||||
int luminance_avg;
|
||||
int brightness_adj;
|
||||
int lum_min, lum_max;
|
||||
int lum_std, lum_std_min, lum_std_max;
|
||||
int ret = QCIP_XPSR_OK;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Brightness: %d Contrast: %d\n",
|
||||
qc_getbrightness(q), qc_getcontrast(q));
|
||||
#endif
|
||||
|
||||
switch (ae_mode) {
|
||||
case AE_CTR_AVG:
|
||||
luminance_avg = qcip_pixel_average_center(q, scan);
|
||||
break;
|
||||
case AE_STD_AVG:
|
||||
luminance_avg = qcip_pixel_average(q, scan);
|
||||
lum_std = qcip_luminance_std(q, scan, luminance_avg);
|
||||
break;
|
||||
case AE_ALL_AVG:
|
||||
default:
|
||||
luminance_avg = qcip_pixel_average(q, scan);
|
||||
break;
|
||||
}
|
||||
|
||||
/* ==>> Contrast adjustment <<== */
|
||||
|
||||
if (ae_mode == AE_STD_AVG) {
|
||||
|
||||
/* set target if it has not been explicitly set */
|
||||
if (luminance_std_target == -1) {
|
||||
luminance_std_target = q->bpp == 6 ? 10 : 2;
|
||||
}
|
||||
|
||||
/* Adjust contrast to reach target luminance standard deviation */
|
||||
lum_std_min = luminance_std_target - luminance_std_tolerance;
|
||||
lum_std_max = luminance_std_target + luminance_std_tolerance;
|
||||
|
||||
if (lum_std < lum_std_min || lum_std > lum_std_max) {
|
||||
ret = QCIP_XPSR_RSCN;
|
||||
if (qc_setcontrast(q, luminance_std_target - lum_std + qc_getcontrast(q))) {
|
||||
return QCIP_XPSR_ERR;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Luminance std/target/tolerance: %d/%d/%d\n",
|
||||
lum_std, luminance_std_target, luminance_std_tolerance );
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ==>> Brightness adjustment <<== */
|
||||
|
||||
/* set target if it has not been explicitly set */
|
||||
if (luminance_target == -1) {
|
||||
luminance_target = q->bpp == 6 ? 32 : 8;
|
||||
}
|
||||
|
||||
lum_min = luminance_target - luminance_tolerance;
|
||||
lum_max = luminance_target + luminance_tolerance;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Luminance avg/target/tolerance: %d/%d/%d\n",
|
||||
luminance_avg, luminance_target, luminance_tolerance );
|
||||
#endif
|
||||
|
||||
/* check for luminance within target range */
|
||||
if (luminance_avg < lum_min || luminance_avg > lum_max) {
|
||||
ret = QCIP_XPSR_RSCN;
|
||||
/* we need to adjust the brighness, which way? */
|
||||
luminance_dif = luminance_target - luminance_avg;
|
||||
if (luminance_dif > 0) {
|
||||
brightness_adj = luminance_dif / 2 + 1;
|
||||
} else {
|
||||
brightness_adj = luminance_dif / 2 - 1;
|
||||
}
|
||||
|
||||
/* Adjusted brightness is out of range ..
|
||||
* throw in the towel ... auto-exposure has failed!
|
||||
*/
|
||||
if (qc_setbrightness(q, brightness_adj + qc_getbrightness(q))) {
|
||||
return QCIP_XPSR_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
444
sys/qcam/gstqcamsrc.c
Normal file
444
sys/qcam/gstqcamsrc.c
Normal file
|
@ -0,0 +1,444 @@
|
|||
/* Gnome-Streamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string.h>
|
||||
|
||||
//#define DEBUG_ENABLED
|
||||
#include <gstqcamsrc.h>
|
||||
|
||||
#include "qcamip.h"
|
||||
|
||||
static GstElementDetails
|
||||
gst_qcamsrc_details =
|
||||
{
|
||||
"QCam Source",
|
||||
"Source/Video",
|
||||
"Read from a QuickCam device",
|
||||
VERSION,
|
||||
"Wim Taymans <wim.taymans@chello.be>",
|
||||
"(C) 2001",
|
||||
};
|
||||
|
||||
#define AE_NONE 3
|
||||
|
||||
#define DEF_WIDTH 320
|
||||
#define DEF_HEIGHT 224
|
||||
#define DEF_BRIGHTNESS 226
|
||||
#define DEF_WHITEBAL 128
|
||||
#define DEF_CONTRAST 72
|
||||
#define DEF_TOP 1
|
||||
#define DEF_LEFT 14
|
||||
#define DEF_TRANSFER_SCALE 2
|
||||
#define DEF_DEPTH 6
|
||||
#define DEF_PORT 0x378
|
||||
#define DEF_AUTOEXP AE_NONE
|
||||
|
||||
GST_PADTEMPLATE_FACTORY (gst_qcamsrc_src_factory,
|
||||
"src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_CAPS_NEW (
|
||||
"gstqcam_src",
|
||||
"video/raw",
|
||||
"format", GST_PROPS_FOURCC (GST_STR_FOURCC ("I420")),
|
||||
"width", GST_PROPS_INT_RANGE (0, 320),
|
||||
"height", GST_PROPS_INT_RANGE (0, 240)
|
||||
)
|
||||
)
|
||||
|
||||
#define GST_TYPE_AUTOEXP_MODE (gst_autoexp_mode_get_type())
|
||||
static GType
|
||||
gst_autoexp_mode_get_type (void)
|
||||
{
|
||||
static GType autoexp_mode_type = 0;
|
||||
static GEnumValue autoexp_modes[] = {
|
||||
{ AE_ALL_AVG, "0", "Average Picture" },
|
||||
{ AE_CTR_AVG, "1", "Average Center" },
|
||||
{ AE_STD_AVG, "2", "Standard Deviation" },
|
||||
{ AE_NONE, "3", "None" },
|
||||
{ 0, NULL, NULL },
|
||||
};
|
||||
if (!autoexp_mode_type) {
|
||||
autoexp_mode_type = g_enum_register_static ("GstAutoExposureMode", autoexp_modes);
|
||||
}
|
||||
return autoexp_mode_type;
|
||||
}
|
||||
|
||||
/* QCamSrc signals and args */
|
||||
enum {
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum {
|
||||
ARG_0,
|
||||
ARG_WIDTH,
|
||||
ARG_HEIGHT,
|
||||
ARG_BRIGHTNESS,
|
||||
ARG_WHITEBAL,
|
||||
ARG_CONTRAST,
|
||||
ARG_TOP,
|
||||
ARG_LEFT,
|
||||
ARG_TRANSFER_SCALE,
|
||||
ARG_DEPTH,
|
||||
ARG_PORT,
|
||||
ARG_AUTOEXP,
|
||||
};
|
||||
|
||||
static void gst_qcamsrc_class_init (GstQCamSrcClass *klass);
|
||||
static void gst_qcamsrc_init (GstQCamSrc *qcamsrc);
|
||||
|
||||
static void gst_qcamsrc_set_property (GObject *object, guint prop_id,
|
||||
const GValue *value, GParamSpec *pspec);
|
||||
static void gst_qcamsrc_get_property (GObject *object, guint prop_id,
|
||||
GValue *value, GParamSpec *pspec);
|
||||
|
||||
static GstElementStateReturn gst_qcamsrc_change_state (GstElement *element);
|
||||
static void gst_qcamsrc_close (GstQCamSrc *src);
|
||||
static gboolean gst_qcamsrc_open (GstQCamSrc *src);
|
||||
|
||||
static GstBuffer* gst_qcamsrc_get (GstPad *pad);
|
||||
|
||||
static GstElementClass *parent_class = NULL;
|
||||
////static guint gst_qcamsrc_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
GType
|
||||
gst_qcamsrc_get_type (void)
|
||||
{
|
||||
static GType qcamsrc_type = 0;
|
||||
|
||||
if (!qcamsrc_type) {
|
||||
static const GTypeInfo qcamsrc_info = {
|
||||
sizeof(GstQCamSrcClass),
|
||||
NULL,
|
||||
NULL,
|
||||
(GClassInitFunc)gst_qcamsrc_class_init,
|
||||
NULL,
|
||||
NULL,
|
||||
sizeof(GstQCamSrc),
|
||||
0,
|
||||
(GInstanceInitFunc)gst_qcamsrc_init,
|
||||
NULL
|
||||
};
|
||||
qcamsrc_type = g_type_register_static(GST_TYPE_ELEMENT, "GstQCamSrc", &qcamsrc_info, 0);
|
||||
}
|
||||
return qcamsrc_type;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_qcamsrc_class_init (GstQCamSrcClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
|
||||
gobject_class = (GObjectClass*)klass;
|
||||
gstelement_class = (GstElementClass*)klass;
|
||||
|
||||
parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_WIDTH,
|
||||
g_param_spec_int ("width", "width", "width",
|
||||
0, 320, DEF_WIDTH, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS(klass), ARG_HEIGHT,
|
||||
g_param_spec_int ("height", "height", "height",
|
||||
0, 240, DEF_HEIGHT, G_PARAM_READWRITE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BRIGHTNESS,
|
||||
g_param_spec_int ("brightness", "brightness", "brightness",
|
||||
0, 255, DEF_BRIGHTNESS, G_PARAM_READWRITE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_WHITEBAL,
|
||||
g_param_spec_int ("whitebal", "whitebal", "whitebal",
|
||||
0, 255, DEF_WHITEBAL, G_PARAM_READWRITE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CONTRAST,
|
||||
g_param_spec_int ("contrast", "contrast", "contrast",
|
||||
0, 255, DEF_CONTRAST, G_PARAM_READWRITE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_TOP,
|
||||
g_param_spec_int ("top", "top", "top",
|
||||
0, 240, DEF_TOP, G_PARAM_READWRITE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_LEFT,
|
||||
g_param_spec_int ("left", "left", "left",
|
||||
0, 320, DEF_LEFT, G_PARAM_READWRITE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_TRANSFER_SCALE,
|
||||
g_param_spec_int ("transfer_scale", "transfer_scale", "transfer_scale",
|
||||
1, 4, DEF_TRANSFER_SCALE, G_PARAM_READWRITE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEPTH,
|
||||
g_param_spec_int ("depth", "depth", "depth",
|
||||
4, 6, DEF_DEPTH, G_PARAM_READWRITE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_PORT,
|
||||
g_param_spec_int ("port","port","port",
|
||||
0, G_MAXINT, DEF_PORT, G_PARAM_READWRITE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_AUTOEXP,
|
||||
g_param_spec_enum ("autoexposure", "autoexposure", "autoexposure",
|
||||
GST_TYPE_AUTOEXP_MODE, DEF_AUTOEXP, G_PARAM_READWRITE));
|
||||
|
||||
gobject_class->set_property = gst_qcamsrc_set_property;
|
||||
gobject_class->get_property = gst_qcamsrc_get_property;
|
||||
|
||||
gstelement_class->change_state = gst_qcamsrc_change_state;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_qcamsrc_init (GstQCamSrc *qcamsrc)
|
||||
{
|
||||
qcamsrc->srcpad = gst_pad_new_from_template (
|
||||
GST_PADTEMPLATE_GET (gst_qcamsrc_src_factory), "src");
|
||||
gst_element_add_pad(GST_ELEMENT(qcamsrc),qcamsrc->srcpad);
|
||||
gst_pad_set_get_function (qcamsrc->srcpad,gst_qcamsrc_get);
|
||||
|
||||
/* if the destination cannot say what it wants, we give this */
|
||||
qcamsrc->qcam = qc_init();
|
||||
qcamsrc->qcam->port = DEF_PORT;
|
||||
qc_setwidth (qcamsrc->qcam, DEF_WIDTH);
|
||||
qc_setheight (qcamsrc->qcam, DEF_HEIGHT);
|
||||
qc_setbrightness (qcamsrc->qcam, DEF_BRIGHTNESS);
|
||||
qc_setwhitebal (qcamsrc->qcam, DEF_WHITEBAL);
|
||||
qc_setcontrast (qcamsrc->qcam, DEF_CONTRAST);
|
||||
qc_settop (qcamsrc->qcam, DEF_TOP);
|
||||
qc_setleft (qcamsrc->qcam, DEF_LEFT);
|
||||
qc_settransfer_scale (qcamsrc->qcam, DEF_TRANSFER_SCALE);
|
||||
qc_setbitdepth (qcamsrc->qcam, DEF_DEPTH);
|
||||
qcamsrc->autoexposure = DEF_AUTOEXP;
|
||||
if (qcamsrc->autoexposure != AE_NONE)
|
||||
qcip_set_autoexposure_mode (qcamsrc->autoexposure);
|
||||
}
|
||||
|
||||
static GstBuffer*
|
||||
gst_qcamsrc_get (GstPad *pad)
|
||||
{
|
||||
GstQCamSrc *qcamsrc;
|
||||
GstBuffer *buf;
|
||||
scanbuf *scan;
|
||||
guchar *outdata;
|
||||
gint i, frame, scale, convert;
|
||||
|
||||
g_return_val_if_fail (pad != NULL, NULL);
|
||||
|
||||
qcamsrc = GST_QCAMSRC (gst_pad_get_parent (pad));
|
||||
|
||||
scale = qc_gettransfer_scale (qcamsrc->qcam);
|
||||
|
||||
frame = qcamsrc->qcam->width * qcamsrc->qcam->height / (scale * scale);
|
||||
|
||||
buf = gst_buffer_new();
|
||||
outdata = GST_BUFFER_DATA(buf) = g_malloc0((frame * 3) / 2);
|
||||
GST_BUFFER_SIZE(buf) = (frame * 3) / 2;
|
||||
|
||||
qc_set (qcamsrc->qcam);
|
||||
if (!GST_PAD_CAPS (pad)) {
|
||||
gst_pad_set_caps (pad, GST_CAPS_NEW (
|
||||
"qcam_caps",
|
||||
"video/raw",
|
||||
"format", GST_PROPS_FOURCC (GST_STR_FOURCC ("I420")),
|
||||
"width", GST_PROPS_INT (qcamsrc->qcam->width / scale),
|
||||
"height", GST_PROPS_INT (qcamsrc->qcam->height / scale)
|
||||
));
|
||||
}
|
||||
scan = qc_scan (qcamsrc->qcam);
|
||||
|
||||
// FIXME, this doesn't seem to work...
|
||||
//fixdark(qcamsrc->qcam, scan);
|
||||
|
||||
if (qcamsrc->autoexposure != AE_NONE)
|
||||
qcip_autoexposure(qcamsrc->qcam, scan);
|
||||
|
||||
convert = (qcamsrc->qcam->bpp==4?4:2);
|
||||
|
||||
for (i=frame; i; i--) {
|
||||
outdata[i] = scan[i]<<convert;
|
||||
}
|
||||
memset (outdata+frame, 128, frame>>1);
|
||||
g_free (scan);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_qcamsrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
GstQCamSrc *src;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail(GST_IS_QCAMSRC(object));
|
||||
src = GST_QCAMSRC(object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_WIDTH:
|
||||
qc_setwidth (src->qcam, g_value_get_int (value));
|
||||
break;
|
||||
case ARG_HEIGHT:
|
||||
qc_setheight (src->qcam, g_value_get_int (value));
|
||||
break;
|
||||
case ARG_BRIGHTNESS:
|
||||
qc_setbrightness (src->qcam, g_value_get_int (value));
|
||||
break;
|
||||
case ARG_WHITEBAL:
|
||||
qc_setwhitebal (src->qcam, g_value_get_int (value));
|
||||
break;
|
||||
case ARG_CONTRAST:
|
||||
qc_setcontrast (src->qcam, g_value_get_int (value));
|
||||
break;
|
||||
case ARG_TOP:
|
||||
qc_settop (src->qcam, g_value_get_int (value));
|
||||
break;
|
||||
case ARG_LEFT:
|
||||
qc_setleft (src->qcam, g_value_get_int (value));
|
||||
break;
|
||||
case ARG_TRANSFER_SCALE:
|
||||
qc_settransfer_scale (src->qcam, g_value_get_int (value));
|
||||
break;
|
||||
case ARG_DEPTH:
|
||||
qc_setbitdepth (src->qcam, g_value_get_int (value));
|
||||
break;
|
||||
case ARG_PORT:
|
||||
src->qcam->port = g_value_get_int (value);
|
||||
break;
|
||||
case ARG_AUTOEXP:
|
||||
src->autoexposure = g_value_get_enum (value);
|
||||
if (src->autoexposure != AE_NONE)
|
||||
qcip_set_autoexposure_mode (src->autoexposure);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_qcamsrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
GstQCamSrc *src;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail(GST_IS_QCAMSRC(object));
|
||||
src = GST_QCAMSRC(object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_WIDTH:
|
||||
g_value_set_int (value, qc_getwidth (src->qcam));
|
||||
break;
|
||||
case ARG_HEIGHT:
|
||||
g_value_set_int (value, qc_getheight (src->qcam));
|
||||
break;
|
||||
case ARG_BRIGHTNESS:
|
||||
g_value_set_int (value, qc_getbrightness (src->qcam));
|
||||
break;
|
||||
case ARG_WHITEBAL:
|
||||
g_value_set_int (value, qc_getwhitebal (src->qcam));
|
||||
break;
|
||||
case ARG_CONTRAST:
|
||||
g_value_set_int (value, qc_getcontrast (src->qcam));
|
||||
break;
|
||||
case ARG_TOP:
|
||||
g_value_set_int (value, qc_gettop (src->qcam));
|
||||
break;
|
||||
case ARG_LEFT:
|
||||
g_value_set_int (value, qc_getleft (src->qcam));
|
||||
break;
|
||||
case ARG_TRANSFER_SCALE:
|
||||
g_value_set_int (value, qc_gettransfer_scale (src->qcam));
|
||||
break;
|
||||
case ARG_DEPTH:
|
||||
g_value_set_int (value, qc_getbitdepth (src->qcam));
|
||||
break;
|
||||
case ARG_PORT:
|
||||
g_value_set_int (value, src->qcam->port);
|
||||
break;
|
||||
case ARG_AUTOEXP:
|
||||
g_value_set_enum (value, src->autoexposure);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_qcamsrc_change_state (GstElement *element)
|
||||
{
|
||||
g_return_val_if_fail(GST_IS_QCAMSRC(element), FALSE);
|
||||
|
||||
/* if going down into NULL state, close the file if it's open */
|
||||
if (GST_STATE_PENDING(element) == GST_STATE_NULL) {
|
||||
if (GST_FLAG_IS_SET(element,GST_QCAMSRC_OPEN))
|
||||
gst_qcamsrc_close(GST_QCAMSRC(element));
|
||||
/* otherwise (READY or higher) we need to open the sound card */
|
||||
} else {
|
||||
if (!GST_FLAG_IS_SET(element,GST_QCAMSRC_OPEN)) {
|
||||
gst_info ("qcamsrc: opening\n");
|
||||
if (!gst_qcamsrc_open(GST_QCAMSRC(element))) {
|
||||
gst_info ("qcamsrc: open failed\n");
|
||||
return GST_STATE_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (GST_ELEMENT_CLASS(parent_class)->change_state)
|
||||
return GST_ELEMENT_CLASS(parent_class)->change_state(element);
|
||||
|
||||
return GST_STATE_SUCCESS;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_qcamsrc_open (GstQCamSrc *qcamsrc)
|
||||
{
|
||||
if (qc_open (qcamsrc->qcam)) {
|
||||
g_warning("qcamsrc: Cannot open QuickCam.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GST_FLAG_SET(qcamsrc, GST_QCAMSRC_OPEN);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_qcamsrc_close (GstQCamSrc *src)
|
||||
{
|
||||
qc_close (src->qcam);
|
||||
GST_FLAG_UNSET(src, GST_QCAMSRC_OPEN);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plugin_init (GModule *module, GstPlugin *plugin)
|
||||
{
|
||||
GstElementFactory *factory;
|
||||
|
||||
/* create an elementfactory for the qcamsrcparse element */
|
||||
factory = gst_elementfactory_new("qcamsrc",GST_TYPE_QCAMSRC,
|
||||
&gst_qcamsrc_details);
|
||||
g_return_val_if_fail(factory != NULL, FALSE);
|
||||
|
||||
gst_elementfactory_add_padtemplate (factory,
|
||||
GST_PADTEMPLATE_GET (gst_qcamsrc_src_factory));
|
||||
|
||||
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GstPluginDesc plugin_desc = {
|
||||
GST_VERSION_MAJOR,
|
||||
GST_VERSION_MINOR,
|
||||
"qcamsrc",
|
||||
plugin_init
|
||||
};
|
||||
|
79
sys/qcam/gstqcamsrc.h
Normal file
79
sys/qcam/gstqcamsrc.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
/* Gnome-Streamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __GST_QCAMSRC_H__
|
||||
#define __GST_QCAMSRC_H__
|
||||
|
||||
|
||||
#include <config.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/** QuickCam include files */
|
||||
#include "qcam.h"
|
||||
#include "qcam-os.h"
|
||||
|
||||
#define GST_TYPE_QCAMSRC \
|
||||
(gst_qcamsrc_get_type())
|
||||
#define GST_QCAMSRC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_QCAMSRC,GstQCamSrc))
|
||||
#define GST_QCAMSRC_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_QCAMSRC,GstQCamSrcClass))
|
||||
#define GST_IS_QCAMSRC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_QCAMSRC))
|
||||
#define GST_IS_QCAMSRC_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_QCAMSRC))
|
||||
|
||||
// NOTE: per-element flags start with 16 for now
|
||||
typedef enum {
|
||||
GST_QCAMSRC_OPEN = GST_ELEMENT_FLAG_LAST,
|
||||
|
||||
GST_QCAMSRC_FLAG_LAST = GST_ELEMENT_FLAG_LAST+2,
|
||||
} GstQCamSrcFlags;
|
||||
|
||||
typedef struct _GstQCamSrc GstQCamSrc;
|
||||
typedef struct _GstQCamSrcClass GstQCamSrcClass;
|
||||
|
||||
struct _GstQCamSrc {
|
||||
GstElement element;
|
||||
|
||||
/* pads */
|
||||
GstPad *srcpad;
|
||||
|
||||
struct qcam *qcam;
|
||||
gboolean autoexposure;
|
||||
gint port;
|
||||
};
|
||||
|
||||
struct _GstQCamSrcClass {
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_qcamsrc_get_type(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
#endif /* __GST_QCAMSRC_H__ */
|
246
sys/qcam/qcam-Linux.c
Normal file
246
sys/qcam/qcam-Linux.c
Normal file
|
@ -0,0 +1,246 @@
|
|||
/* qcam-Linux.c -- Linux-specific routines for accessing QuickCam */
|
||||
|
||||
/* Version 0.1, January 2, 1996 */
|
||||
/* Version 0.5, August 24, 1996 */
|
||||
|
||||
|
||||
/******************************************************************
|
||||
|
||||
Copyright (C) 1996 by Scott Laird
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
******************************************************************/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#ifdef TESTING
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#include <sys/io.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "qcam.h"
|
||||
#include "qcam-Linux.h"
|
||||
|
||||
int __inline__ read_lpstatus(const struct qcam *q) { return inb(q->port+1); }
|
||||
int read_lpcontrol(const struct qcam *q) { return inb(q->port+2); }
|
||||
int read_lpdata(const struct qcam *q) { return inb(q->port); }
|
||||
void write_lpdata(const struct qcam *q, int d) { outb(d,q->port); }
|
||||
void write_lpcontrol(const struct qcam *q, int d) { outb(d,q->port+2); }
|
||||
|
||||
int enable_ports(const struct qcam *q)
|
||||
{
|
||||
if(q->port<0x278) return 1; /* Better safe than sorry */
|
||||
if(q->port>0x3bc) return 1;
|
||||
return (ioperm(q->port, 3, 1));
|
||||
}
|
||||
|
||||
int disable_ports(const struct qcam *q)
|
||||
{
|
||||
return (ioperm(q->port, 3, 0));
|
||||
}
|
||||
|
||||
/* Lock port. This is currently sub-optimal, and is begging to be
|
||||
fixed. It should check for dead locks. Any takers? */
|
||||
|
||||
/* qc_lock_wait
|
||||
* This function uses POSIX fcntl-style locking on a file created in the
|
||||
* /tmp directory. Because it uses the Unix record locking facility, locks
|
||||
* are relinquished automatically on process termination, so "dead locks"
|
||||
* are not a problem. (FYI, the lock file will remain after process
|
||||
* termination, but this is actually desired so that the next process need
|
||||
* not re-creat(2)e it... just lock it.)
|
||||
* The wait argument indicates whether or not this funciton should "block"
|
||||
* waiting for the previous lock to be relinquished. This is ideal so that
|
||||
* multiple processes (eg. qcam) taking "snapshots" can peacefully coexist.
|
||||
* - Dave Plonka (plonka@carroll1.cc.edu)
|
||||
*/
|
||||
int qc_lock_wait(struct qcam *q, int wait)
|
||||
{
|
||||
#if 1
|
||||
static struct flock sfl;
|
||||
|
||||
if (-1 == q->fd) /* we've yet to open the lock file */
|
||||
{
|
||||
static char lockfile[128];
|
||||
|
||||
sprintf(lockfile,"/var/run/LOCK.qcam.0x%x",q->port);
|
||||
if (-1 == (q->fd = open(lockfile, O_WRONLY | O_CREAT, 0666)))
|
||||
{
|
||||
perror("open");
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef TESTING
|
||||
fprintf(stderr, "%s - %d: %s open(2)ed\n", __FILE__, __LINE__, lockfile);
|
||||
#endif
|
||||
|
||||
/* initialize the l_type memver to lock the file exclusively */
|
||||
sfl.l_type = F_WRLCK;
|
||||
}
|
||||
|
||||
#ifdef TESTING
|
||||
if (0 != fcntl(q->fd, F_SETLK, &sfl)) /* non-blocking set lock */
|
||||
#else
|
||||
if (0 != fcntl(q->fd, wait? F_SETLKW : F_SETLK, &sfl))
|
||||
#endif
|
||||
{
|
||||
#ifdef TESTING
|
||||
perror("fcntl");
|
||||
if (EAGAIN != errno || !wait) return 1;
|
||||
|
||||
fprintf(stderr, "%s - %d: waiting for exclusive lock on fd %d...\n", __FILE__, __LINE__, q->fd);
|
||||
|
||||
if (0 != fcntl(q->fd, F_SETLKW, &sfl)) /* "blocking" set lock */
|
||||
#endif
|
||||
{
|
||||
perror("fcntl");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TESTING
|
||||
fprintf(stderr, "%s - %d: fd %d locked exclusively\n", __FILE__, __LINE__, q->fd);
|
||||
#endif
|
||||
|
||||
#else
|
||||
char lockfile[128], tmp[128];
|
||||
struct stat statbuf;
|
||||
|
||||
sprintf(lockfile,"/var/run/LOCK.qcam.0x%x",q->port);
|
||||
sprintf(tmp,"%s-%d",lockfile,getpid());
|
||||
|
||||
if ((creat(tmp,0)==-1) ||
|
||||
(link(tmp,lockfile)==-1) ||
|
||||
(stat(tmp,&statbuf)==-1) ||
|
||||
(statbuf.st_nlink==1))
|
||||
{
|
||||
#ifdef DEBUGQC
|
||||
perror("QuickCam Locked");
|
||||
if(unlink(tmp)==-1)
|
||||
perror("Error unlinking temp file.");
|
||||
#else
|
||||
unlink(tmp);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
unlink(tmp);
|
||||
if (chown(lockfile,getuid(),getgid())==-1)
|
||||
perror("Chown problems");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qc_lock(struct qcam *q)
|
||||
{
|
||||
#if 1
|
||||
return qc_lock_wait(q, 1 /*wait*/);
|
||||
#else
|
||||
return qc_lock_wait(q, 0 /*don't wait*/);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Unlock port */
|
||||
|
||||
int qc_unlock(struct qcam *q)
|
||||
{
|
||||
static struct flock sfl;
|
||||
#if 1
|
||||
if (-1 == q->fd)
|
||||
{ /* port was not locked */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* clear the exclusive lock */
|
||||
sfl.l_type = F_UNLCK;
|
||||
if (0 != fcntl(q->fd, F_SETLK, &sfl))
|
||||
{
|
||||
perror("fcntl");
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef TESTING
|
||||
fprintf(stderr, "%s - %d: fd %d unlocked\n", __FILE__, __LINE__, q->fd);
|
||||
#endif
|
||||
|
||||
#else
|
||||
char lockfile[128];
|
||||
|
||||
sprintf(lockfile,"/var/run/LOCK.qcam.0x%x",q->port);
|
||||
unlink(lockfile); /* What would I do with an error? */
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Probe for camera. Returns 0 if found, 1 if not found, sets
|
||||
q->port.*/
|
||||
|
||||
int qc_probe(struct qcam *q)
|
||||
{
|
||||
int ioports[]={0x378, 0x278, 0x3bc,0};
|
||||
int i=0;
|
||||
|
||||
/* Attempt to get permission to access IO ports. Must be root */
|
||||
|
||||
while(ioports[i]!=0) {
|
||||
q->port=ioports[i++];
|
||||
|
||||
if (qc_open(q)) {
|
||||
perror("Can't get I/O permission");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(qc_detect(q)) {
|
||||
fprintf(stderr,"QuickCam detected at 0x%x\n",q->port);
|
||||
qc_close(q);
|
||||
return(0);
|
||||
}
|
||||
else
|
||||
qc_close(q);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* THIS IS UGLY. I need a short delay loop -- somthing well under a
|
||||
millisecond. Unfortunately, adding 2 usleep(1)'s to qc_command slowed
|
||||
it down by a factor of over 1000 over the same loop with 2
|
||||
usleep(0)'s, and that's too slow -- qc_start was taking over a second
|
||||
to run. This seems to help, but if anyone has a good
|
||||
speed-independent pause routine, please tell me. -- Scott */
|
||||
|
||||
void qc_wait(int val)
|
||||
{
|
||||
int i;
|
||||
|
||||
while(val--)
|
||||
for(i=0;i<50000;i++);
|
||||
}
|
32
sys/qcam/qcam-Linux.h
Normal file
32
sys/qcam/qcam-Linux.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/* qcam-linux.h -- Linux-specific routines for accessing QuickCam */
|
||||
|
||||
/* Version 0.1, January 2, 1996 */
|
||||
/* Version 0.5, August 24, 1996 */
|
||||
|
||||
|
||||
/******************************************************************
|
||||
|
||||
Copyright (C) 1996 by Scott Laird
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
******************************************************************/
|
||||
|
||||
|
788
sys/qcam/qcam-lib.c
Normal file
788
sys/qcam/qcam-lib.c
Normal file
|
@ -0,0 +1,788 @@
|
|||
/* qcam-lib.c -- Library for programming with the Connectix QuickCam.
|
||||
* See the included documentation for usage instructions and details
|
||||
* of the protocol involved. */
|
||||
|
||||
|
||||
/* Version 0.5, August 4, 1996 */
|
||||
/* Version 0.7, August 27, 1996 */
|
||||
/* Version 0.9, November 17, 1996 */
|
||||
|
||||
|
||||
/******************************************************************
|
||||
|
||||
Copyright (C) 1996 by Scott Laird
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
******************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "qcam.h"
|
||||
#include "qcam-os.h"
|
||||
#include "qcam-os.c"
|
||||
|
||||
/* Prototypes for static functions. Externally visible functions
|
||||
* should be prototyped in qcam.h */
|
||||
|
||||
static int qc_waithand(const struct qcam *q, int val);
|
||||
static int qc_command(const struct qcam *q, int command);
|
||||
static int qc_readparam(const struct qcam *q);
|
||||
static int qc_setscanmode(struct qcam *q);
|
||||
static int qc_readbytes(const struct qcam *q, char buffer[]);
|
||||
|
||||
/* The next several functions are used for controlling the qcam
|
||||
* structure. They aren't used inside this library, but they should
|
||||
* provide a clean interface for external programs.*/
|
||||
|
||||
/* Gets/sets the brightness. */
|
||||
|
||||
int qc_getbrightness(const struct qcam *q)
|
||||
{
|
||||
return q->brightness;
|
||||
}
|
||||
|
||||
int qc_setbrightness(struct qcam *q, int val)
|
||||
{
|
||||
if (val >= 0 && val <= 255) {
|
||||
q->brightness=val;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Gets/sets the contrast */
|
||||
|
||||
int qc_getcontrast(const struct qcam *q)
|
||||
{
|
||||
return q->contrast;
|
||||
}
|
||||
|
||||
int qc_setcontrast(struct qcam *q, int val)
|
||||
{
|
||||
if (val >= 0 && val <= 255) {
|
||||
q->contrast=val;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Gets/sets the white balance */
|
||||
|
||||
int qc_getwhitebal(const struct qcam *q)
|
||||
{
|
||||
return q->whitebal;
|
||||
}
|
||||
|
||||
int qc_setwhitebal(struct qcam *q, int val)
|
||||
{
|
||||
if (val >= 0 && val <= 255) {
|
||||
q->whitebal=val;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Gets/sets the resolution */
|
||||
|
||||
void qc_getresolution(const struct qcam *q, int *x, int *y)
|
||||
{
|
||||
*x=q->width;
|
||||
*y=q->height;
|
||||
}
|
||||
|
||||
int qc_setresolution(struct qcam *q, int x, int y)
|
||||
{
|
||||
if (x >= 0 && x <= 336 && y >= 0 && y <= 243) {
|
||||
q->width=x;
|
||||
q->height=y;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int qc_getheight(const struct qcam *q)
|
||||
{
|
||||
return q->height;
|
||||
}
|
||||
|
||||
int qc_setheight(struct qcam *q, int y)
|
||||
{
|
||||
if (y >= 0 && y <= 243) {
|
||||
q->height=y;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int qc_getwidth(const struct qcam *q)
|
||||
{
|
||||
return q->width;
|
||||
}
|
||||
|
||||
int qc_setwidth(struct qcam *q, int x)
|
||||
{
|
||||
if (x >= 0 && x <= 336) {
|
||||
q->width=x;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Gets/sets the bit depth */
|
||||
|
||||
int qc_getbitdepth(const struct qcam *q)
|
||||
{
|
||||
return q->bpp;
|
||||
}
|
||||
|
||||
int qc_setbitdepth(struct qcam *q, int val)
|
||||
{
|
||||
if (val == 4 || val == 6) {
|
||||
q->bpp=val;
|
||||
return qc_setscanmode(q);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int qc_gettop(const struct qcam *q)
|
||||
{
|
||||
return q->top;
|
||||
}
|
||||
|
||||
int qc_settop(struct qcam *q, int val)
|
||||
{
|
||||
if (val >= 1 && val <= 243) {
|
||||
q->top = val;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int qc_getleft(const struct qcam *q)
|
||||
{
|
||||
return q->left;
|
||||
}
|
||||
|
||||
int qc_setleft(struct qcam *q, int val)
|
||||
{
|
||||
if (val % 2 == 0 && val >= 2 && val <= 336) {
|
||||
q->left = val;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int qc_gettransfer_scale(const struct qcam *q)
|
||||
{
|
||||
return q->transfer_scale;
|
||||
}
|
||||
|
||||
int qc_settransfer_scale(struct qcam *q, int val)
|
||||
{
|
||||
if (val == 1 || val == 2 || val == 4) {
|
||||
q->transfer_scale = val;
|
||||
return qc_setscanmode(q);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
qc_calibrate(struct qcam *q)
|
||||
/* bugfix by Hanno Mueller hmueller@kabel.de, Mai 21 96 */
|
||||
/* The white balance is an individiual value for each */
|
||||
/* quickcam. Run calibration once, write the value down */
|
||||
/* and put it in your qcam.conf file. You won't need to */
|
||||
/* recalibrate your camera again. */
|
||||
{
|
||||
int value;
|
||||
#ifdef DEBUG
|
||||
int count = 0;
|
||||
#endif
|
||||
|
||||
qc_command(q, 27); /* AutoAdjustOffset */
|
||||
qc_command(q, 0); /* Dummy Parameter, ignored by the camera */
|
||||
|
||||
/* GetOffset (33) will read 255 until autocalibration */
|
||||
/* is finished. After that, a value of 1-254 will be */
|
||||
/* returned. */
|
||||
|
||||
do {
|
||||
qc_command(q, 33); value = qc_readparam(q);
|
||||
#ifdef DEBUG
|
||||
count++;
|
||||
#endif
|
||||
} while (value == 0xff);
|
||||
|
||||
q->whitebal = value;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%d loops to calibrate\n", count);
|
||||
fprintf(stderr, "Calibrated to %d\n", value);
|
||||
#endif
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
int
|
||||
qc_forceunidir(struct qcam *q)
|
||||
{
|
||||
q->port_mode = (q->port_mode & ~QC_FORCE_MASK) | QC_FORCE_UNIDIR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Initialize the QuickCam driver control structure. This is where
|
||||
* defaults are set for people who don't have a config file.*/
|
||||
struct qcam *
|
||||
qc_init(void)
|
||||
{
|
||||
struct qcam *q;
|
||||
|
||||
q=malloc(sizeof(struct qcam));
|
||||
|
||||
q->port=0; /* Port 0 == Autoprobe */
|
||||
q->port_mode=(QC_ANY | QC_NOTSET);
|
||||
q->width=160;
|
||||
q->height=120;
|
||||
q->bpp=4;
|
||||
q->transfer_scale = 2;
|
||||
q->contrast=104;
|
||||
q->brightness=150;
|
||||
q->whitebal=150;
|
||||
q->top = 1;
|
||||
q->left = 14;
|
||||
q->mode = -1;
|
||||
q->fd=-1; /* added initialization of fd member
|
||||
* BTW, there doesn't seem to be a place to close this fd...
|
||||
* I think we need a qc_free function.
|
||||
* - Dave Plonka (plonka@carroll1.cc.edu)
|
||||
*/
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
/* qc_open enables access to the port specified in q->port. It takes
|
||||
* care of locking and enabling I/O port access by calling the
|
||||
* appropriate routines.
|
||||
*
|
||||
* Returns 0 for success, 1 for opening error, 2 for locking error,
|
||||
* and 3 for qcam not found */
|
||||
|
||||
int qc_open(struct qcam *q)
|
||||
{
|
||||
if(q->port==0)
|
||||
if(qc_probe(q)) {
|
||||
fprintf(stderr,"Qcam not found\n");
|
||||
return 3;
|
||||
}
|
||||
|
||||
if(qc_lock(q)) {
|
||||
fprintf(stderr,"Cannot lock qcam.\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if(enable_ports(q)) {
|
||||
fprintf(stderr,"Cannot open QuickCam -- permission denied.");
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* qc_close closes and unlocks the driver. You *need* to call this,
|
||||
* or lockfiles will be left behind and everything will be screwed. */
|
||||
|
||||
int qc_close(struct qcam *q)
|
||||
{
|
||||
qc_unlock(q);
|
||||
|
||||
disable_ports(q);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* qc_command is probably a bit of a misnomer -- it's used to send
|
||||
* bytes *to* the camera. Generally, these bytes are either commands
|
||||
* or arguments to commands, so the name fits, but it still bugs me a
|
||||
* bit. See the documentation for a list of commands. */
|
||||
|
||||
static int qc_command(const struct qcam *q, int command)
|
||||
{
|
||||
int n1, n2;
|
||||
int cmd;
|
||||
|
||||
write_lpdata(q, command);
|
||||
write_lpcontrol(q,6);
|
||||
|
||||
n1 = qc_waithand(q,1);
|
||||
|
||||
write_lpcontrol(q,0xe);
|
||||
n2 = qc_waithand(q,0);
|
||||
|
||||
cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4);
|
||||
#ifdef DEBUG
|
||||
if (cmd != command) {
|
||||
fprintf(stderr, "Command 0x%02x sent, 0x%02x echoed", command, cmd);
|
||||
n2 = read_lpstatus(q);
|
||||
cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4);
|
||||
if (cmd != command) fprintf(stderr, " (re-read does not help)\n");
|
||||
else fprintf(stderr, " (fixed on re-read)\n");
|
||||
}
|
||||
#endif
|
||||
return cmd;
|
||||
}
|
||||
|
||||
static int
|
||||
qc_readparam(const struct qcam *q)
|
||||
{
|
||||
int n1, n2;
|
||||
int cmd;
|
||||
|
||||
write_lpcontrol(q,6);
|
||||
n1 = qc_waithand(q,1);
|
||||
|
||||
write_lpcontrol(q,0xe);
|
||||
n2 = qc_waithand(q,0);
|
||||
|
||||
cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
/* qc_waithand busy-waits for a handshake signal from the QuickCam.
|
||||
* Almost all communication with the camera requires handshaking. */
|
||||
|
||||
static int qc_waithand(const struct qcam *q, int val)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (val)
|
||||
while(! ((status = read_lpstatus(q))&8))
|
||||
;
|
||||
else
|
||||
while (((status = read_lpstatus(q))&8))
|
||||
;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Waithand2 is used when the qcam is in bidirectional mode, and the
|
||||
* handshaking signal is CamRdy2 (bit 0 of data reg) instead of CamRdy1
|
||||
* (bit 3 of status register). It also returns the last value read,
|
||||
* since this data is useful. */
|
||||
|
||||
static unsigned int
|
||||
qc_waithand2(const struct qcam *q, int val)
|
||||
{
|
||||
unsigned int status;
|
||||
do {
|
||||
status = read_lpdata(q);
|
||||
} while ( (status & 1) != val);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* Try to detect a QuickCam. It appears to flash the upper 4 bits of
|
||||
the status register at 5-10 Hz. This is only used in the autoprobe
|
||||
code. Be aware that this isn't the way Connectix detects the
|
||||
camera (they send a reset and try to handshake), but this should be
|
||||
almost completely safe, while their method screws up my printer if
|
||||
I plug it in before the camera. */
|
||||
|
||||
int qc_detect(const struct qcam *q)
|
||||
{
|
||||
int reg,lastreg;
|
||||
int count=0;
|
||||
int i;
|
||||
|
||||
lastreg=reg=read_lpstatus(q)&0xf0;
|
||||
|
||||
for(i=0;i<30;i++) {
|
||||
reg=read_lpstatus(q)&0xf0;
|
||||
if(reg!=lastreg) count++;
|
||||
lastreg=reg;
|
||||
usleep(10000);
|
||||
}
|
||||
|
||||
/* Be liberal in what you accept... */
|
||||
|
||||
if(count>3&&count<15)
|
||||
return 1; /* found */
|
||||
else
|
||||
return 0; /* not found */
|
||||
}
|
||||
|
||||
|
||||
/* Reset the QuickCam. This uses the same sequence the Windows
|
||||
* QuickPic program uses. Someone with a bi-directional port should
|
||||
* check that bi-directional mode is detected right, and then
|
||||
* implement bi-directional mode in qc_readbyte(). */
|
||||
|
||||
void qc_reset(struct qcam *q)
|
||||
{
|
||||
switch (q->port_mode & QC_FORCE_MASK)
|
||||
{
|
||||
case QC_FORCE_UNIDIR:
|
||||
q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
|
||||
break;
|
||||
|
||||
case QC_FORCE_BIDIR:
|
||||
q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
|
||||
break;
|
||||
|
||||
case QC_ANY:
|
||||
write_lpcontrol(q,0x20);
|
||||
write_lpdata(q,0x75);
|
||||
|
||||
if (read_lpdata(q) != 0x75) {
|
||||
q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
|
||||
} else {
|
||||
q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
|
||||
}
|
||||
break;
|
||||
|
||||
case QC_FORCE_SERIAL:
|
||||
default:
|
||||
fprintf(stderr, "Illegal port_mode %x\n", q->port_mode);
|
||||
break;
|
||||
}
|
||||
|
||||
/* usleep(250);*/
|
||||
write_lpcontrol(q,0xb);
|
||||
usleep(250);
|
||||
write_lpcontrol(q,0xe);
|
||||
(void)qc_setscanmode(q); /* in case port_mode changed */
|
||||
}
|
||||
|
||||
|
||||
/* Decide which scan mode to use. There's no real requirement that
|
||||
* the scanmode match the resolution in q->height and q-> width -- the
|
||||
* camera takes the picture at the resolution specified in the
|
||||
* "scanmode" and then returns the image at the resolution specified
|
||||
* with the resolution commands. If the scan is bigger than the
|
||||
* requested resolution, the upper-left hand corner of the scan is
|
||||
* returned. If the scan is smaller, then the rest of the image
|
||||
* returned contains garbage. */
|
||||
|
||||
static int qc_setscanmode(struct qcam *q)
|
||||
{
|
||||
switch (q->transfer_scale) {
|
||||
case 1: q->mode = 0; break;
|
||||
case 2: q->mode = 4; break;
|
||||
case 4: q->mode = 8; break;
|
||||
default: return 1;
|
||||
}
|
||||
|
||||
switch (q->bpp) {
|
||||
case 4: break;
|
||||
case 6: q->mode+=2; break;
|
||||
default:
|
||||
fprintf(stderr,"Error: Unsupported bit depth\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (q->port_mode & QC_MODE_MASK) {
|
||||
case QC_BIDIR: q->mode += 1; break;
|
||||
case QC_NOTSET:
|
||||
case QC_UNIDIR: break;
|
||||
default: return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Reset the QuickCam and program for brightness, contrast,
|
||||
* white-balance, and resolution. */
|
||||
|
||||
void qc_set(struct qcam *q)
|
||||
{
|
||||
int val;
|
||||
int val2;
|
||||
|
||||
qc_reset(q);
|
||||
|
||||
/* Set the brightness. Yes, this is repetitive, but it works.
|
||||
* Shorter versions seem to fail subtly. Feel free to try :-). */
|
||||
/* I think the problem was in qc_command, not here -- bls */
|
||||
qc_command(q,0xb);
|
||||
qc_command(q,q->brightness);
|
||||
|
||||
val = q->height / q->transfer_scale;
|
||||
qc_command(q,0x11); qc_command(q, val);
|
||||
if ((q->port_mode & QC_MODE_MASK) == QC_UNIDIR && q->bpp == 6) {
|
||||
/* The normal "transfers per line" calculation doesn't seem to work
|
||||
as expected here (and yet it works fine in qc_scan). No idea
|
||||
why this case is the odd man out. Fortunately, Laird's original
|
||||
working version gives me a good way to guess at working values.
|
||||
-- bls */
|
||||
val = q->width;
|
||||
val2 = q->transfer_scale * 4;
|
||||
} else {
|
||||
val = q->width * q->bpp;
|
||||
val2 = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR)?24:8) *
|
||||
q->transfer_scale;
|
||||
}
|
||||
val = (val + val2 - 1) / val2;
|
||||
qc_command(q,0x13); qc_command(q, val);
|
||||
|
||||
/* I still don't know what these do! */
|
||||
/* They're setting top and left -- bls */
|
||||
qc_command(q,0xd); qc_command(q,q->top);
|
||||
qc_command(q,0xf); qc_command(q,q->left/2);
|
||||
|
||||
qc_command(q,0x19); qc_command(q,q->contrast);
|
||||
qc_command(q,0x1f); qc_command(q,q->whitebal);
|
||||
}
|
||||
|
||||
|
||||
/* Qc_readbytes reads some bytes from the QC and puts them in
|
||||
the supplied buffer. It returns the number of bytes read,
|
||||
or -1 on error. */
|
||||
|
||||
static int
|
||||
__inline__
|
||||
qc_readbytes(const struct qcam *q, char buffer[])
|
||||
{
|
||||
int ret;
|
||||
unsigned int hi, lo;
|
||||
unsigned int hi2, lo2;
|
||||
static unsigned int saved_bits;
|
||||
static int state = 0;
|
||||
|
||||
if (buffer == NULL) {
|
||||
state = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (q->port_mode & QC_MODE_MASK) {
|
||||
case QC_BIDIR: /* Bi-directional Port */
|
||||
write_lpcontrol(q, 0x26);
|
||||
lo = (qc_waithand2(q, 1) >> 1);
|
||||
hi = (read_lpstatus(q) >> 3) & 0x1f;
|
||||
write_lpcontrol(q, 0x2e);
|
||||
lo2 = (qc_waithand2(q, 0) >> 1);
|
||||
hi2 = (read_lpstatus(q) >> 3) & 0x1f;
|
||||
switch (q->bpp) {
|
||||
case 4:
|
||||
buffer[0] = lo & 0xf;
|
||||
buffer[1] = ((lo & 0x70) >> 4) | ((hi & 1) << 3);
|
||||
buffer[2] = (hi & 0x1e) >> 1;
|
||||
buffer[3] = lo2 & 0xf;
|
||||
buffer[4] = ((lo2 & 0x70) >> 4) | ((hi2 & 1) << 3);
|
||||
buffer[5] = (hi2 & 0x1e) >> 1;
|
||||
ret = 6;
|
||||
break;
|
||||
case 6:
|
||||
buffer[0] = lo & 0x3f;
|
||||
buffer[1] = ((lo & 0x40) >> 6) | (hi << 1);
|
||||
buffer[2] = lo2 & 0x3f;
|
||||
buffer[3] = ((lo2 & 0x40) >> 6) | (hi2 << 1);
|
||||
ret = 4;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Bad bidir pixel depth %d\n", q->bpp);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case QC_UNIDIR: /* Unidirectional Port */
|
||||
write_lpcontrol(q,6);
|
||||
lo = (qc_waithand(q,1) & 0xf0) >> 4;
|
||||
write_lpcontrol(q,0xe);
|
||||
hi = (qc_waithand(q,0) & 0xf0) >> 4;
|
||||
|
||||
switch (q->bpp) {
|
||||
case 4:
|
||||
buffer[0] = lo;
|
||||
buffer[1] = hi;
|
||||
ret = 2;
|
||||
break;
|
||||
case 6:
|
||||
switch (state) {
|
||||
case 0:
|
||||
buffer[0] = (lo << 2) | ((hi & 0xc) >> 2);
|
||||
saved_bits = (hi & 3) << 4;
|
||||
state = 1; ret = 1; break;
|
||||
case 1:
|
||||
buffer[0] = lo | saved_bits;
|
||||
saved_bits = hi << 2;
|
||||
state = 2; ret = 1; break;
|
||||
case 2:
|
||||
buffer[0] = ((lo & 0xc) >> 2) | saved_bits;
|
||||
buffer[1] = ((lo & 3) << 4) | hi;
|
||||
state = 0; ret = 2; break;
|
||||
default:
|
||||
fprintf(stderr, "Unidir 6-bit state %d?\n", state);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Bad unidir pixel depth %d\n", q->bpp);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case QC_SERIAL: /* Serial Interface. Just in case.*/
|
||||
default:
|
||||
fprintf(stderr,"Mode %x not supported\n",q->port_mode);
|
||||
ret=-1;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read a scan from the QC. This takes the qcam structure and
|
||||
* requests a scan from the camera. It sends the correct instructions
|
||||
* to the camera and then reads back the correct number of bytes. In
|
||||
* previous versions of this routine the return structure contained
|
||||
* the raw output from the camera, and there was a 'qc_convertscan'
|
||||
* function that converted that to a useful format. In version 0.3 I
|
||||
* rolled qc_convertscan into qc_scan and now I only return the
|
||||
* converted scan. The format is just an one-dimensional array of
|
||||
* characters, one for each pixel, with 0=black up to n=white, where
|
||||
* n=2^(bit depth)-1. Ask me for more details if you don't understand
|
||||
* this. */
|
||||
|
||||
scanbuf *qc_scan(const struct qcam *q)
|
||||
{
|
||||
unsigned char *ret;
|
||||
int i, j, k;
|
||||
int bytes;
|
||||
int linestotrans, transperline;
|
||||
int divisor;
|
||||
int pixels_per_line;
|
||||
int pixels_read;
|
||||
char buffer[6];
|
||||
char invert;
|
||||
|
||||
if (q->mode != -1) {
|
||||
qc_command(q, 0x7);
|
||||
qc_command(q, q->mode);
|
||||
} else {
|
||||
struct qcam bogus_cam;
|
||||
/* We're going through these odd hoops to retain the "const"
|
||||
qualification on q. We can't do a qc_setscanmode directly on q,
|
||||
so we copy it, do a setscanmode on that, and pass in the newly
|
||||
computed mode. -- bls 11/21/96
|
||||
*/
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Warning! qc->mode not set!\n");
|
||||
#endif
|
||||
bogus_cam = *q;
|
||||
(void)qc_setscanmode(&bogus_cam);
|
||||
qc_command(q, 0x7);
|
||||
qc_command(q, bogus_cam.mode);
|
||||
}
|
||||
|
||||
if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) {
|
||||
write_lpcontrol(q, 0x2e); /* turn port around */
|
||||
write_lpcontrol(q, 0x26);
|
||||
(void) qc_waithand(q, 1);
|
||||
write_lpcontrol(q, 0x2e);
|
||||
(void) qc_waithand(q, 0);
|
||||
}
|
||||
|
||||
/* strange -- should be 15:63 below, but 4bpp is odd */
|
||||
invert = (q->bpp == 4) ? 16 : 63;
|
||||
|
||||
linestotrans = q->height / q->transfer_scale;
|
||||
pixels_per_line = q->width / q->transfer_scale;
|
||||
transperline = q->width * q->bpp;
|
||||
divisor = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR)?24:8) *
|
||||
q->transfer_scale;
|
||||
transperline = (transperline + divisor - 1) / divisor;
|
||||
|
||||
ret = malloc(linestotrans * pixels_per_line);
|
||||
assert(ret);
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%s %d bpp\n%d lines of %d transfers each\n",
|
||||
((q->port_mode & QC_MODE_MASK) == QC_BIDIR)?"Bidir":"Unidir",
|
||||
q->bpp, linestotrans, transperline);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < linestotrans; i++) {
|
||||
for (pixels_read = j = 0; j < transperline; j++) {
|
||||
bytes = qc_readbytes(q, buffer);
|
||||
assert(bytes > 0);
|
||||
for (k = 0; k < bytes && (pixels_read + k) < pixels_per_line; k++) {
|
||||
assert (buffer[k] <= invert);
|
||||
assert (buffer[k] >= 0);
|
||||
if (buffer[k] == 0 && invert == 16) {
|
||||
/* 4bpp is odd (again) -- inverter is 16, not 15, but output
|
||||
must be 0-15 -- bls */
|
||||
buffer[k] = 16;
|
||||
}
|
||||
ret[i*pixels_per_line + pixels_read + k] = invert - buffer[k];
|
||||
}
|
||||
pixels_read += bytes;
|
||||
}
|
||||
(void) qc_readbytes(q, 0); /* reset state machine */
|
||||
}
|
||||
|
||||
if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) {
|
||||
write_lpcontrol(q, 2);
|
||||
write_lpcontrol(q, 6);
|
||||
usleep(3);
|
||||
write_lpcontrol(q, 0xe);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
qc_dump(const struct qcam *q, char *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
time_t t;
|
||||
|
||||
if ((fp = fopen(fname, "w")) == 0)
|
||||
{
|
||||
fprintf(stderr, "Error: cannot open %s\n", fname);
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(fp, "# Version 0.9\n");
|
||||
time(&t);
|
||||
fprintf(fp, "# Created %s", ctime(&t));
|
||||
fprintf(fp, "Width %d\nHeight %d\n", q->width, q->height);
|
||||
fprintf(fp, "Top %d\nLeft %d\n", q->top, q->left);
|
||||
fprintf(fp, "Bpp %d\nContrast %d\n", q->bpp, q->contrast);
|
||||
fprintf(fp, "Brightness %d\nWhitebal %d\n", q->brightness, q->whitebal);
|
||||
fprintf(fp, "Port 0x%x\nScale %d\n", q->port, q->transfer_scale);
|
||||
fclose(fp);
|
||||
}
|
246
sys/qcam/qcam-os.c
Normal file
246
sys/qcam/qcam-os.c
Normal file
|
@ -0,0 +1,246 @@
|
|||
/* qcam-Linux.c -- Linux-specific routines for accessing QuickCam */
|
||||
|
||||
/* Version 0.1, January 2, 1996 */
|
||||
/* Version 0.5, August 24, 1996 */
|
||||
|
||||
|
||||
/******************************************************************
|
||||
|
||||
Copyright (C) 1996 by Scott Laird
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
******************************************************************/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#ifdef TESTING
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#include <sys/io.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "qcam.h"
|
||||
#include "qcam-Linux.h"
|
||||
|
||||
int __inline__ read_lpstatus(const struct qcam *q) { return inb(q->port+1); }
|
||||
int read_lpcontrol(const struct qcam *q) { return inb(q->port+2); }
|
||||
int read_lpdata(const struct qcam *q) { return inb(q->port); }
|
||||
void write_lpdata(const struct qcam *q, int d) { outb(d,q->port); }
|
||||
void write_lpcontrol(const struct qcam *q, int d) { outb(d,q->port+2); }
|
||||
|
||||
int enable_ports(const struct qcam *q)
|
||||
{
|
||||
if(q->port<0x278) return 1; /* Better safe than sorry */
|
||||
if(q->port>0x3bc) return 1;
|
||||
return (ioperm(q->port, 3, 1));
|
||||
}
|
||||
|
||||
int disable_ports(const struct qcam *q)
|
||||
{
|
||||
return (ioperm(q->port, 3, 0));
|
||||
}
|
||||
|
||||
/* Lock port. This is currently sub-optimal, and is begging to be
|
||||
fixed. It should check for dead locks. Any takers? */
|
||||
|
||||
/* qc_lock_wait
|
||||
* This function uses POSIX fcntl-style locking on a file created in the
|
||||
* /tmp directory. Because it uses the Unix record locking facility, locks
|
||||
* are relinquished automatically on process termination, so "dead locks"
|
||||
* are not a problem. (FYI, the lock file will remain after process
|
||||
* termination, but this is actually desired so that the next process need
|
||||
* not re-creat(2)e it... just lock it.)
|
||||
* The wait argument indicates whether or not this funciton should "block"
|
||||
* waiting for the previous lock to be relinquished. This is ideal so that
|
||||
* multiple processes (eg. qcam) taking "snapshots" can peacefully coexist.
|
||||
* - Dave Plonka (plonka@carroll1.cc.edu)
|
||||
*/
|
||||
int qc_lock_wait(struct qcam *q, int wait)
|
||||
{
|
||||
#if 1
|
||||
static struct flock sfl;
|
||||
|
||||
if (-1 == q->fd) /* we've yet to open the lock file */
|
||||
{
|
||||
static char lockfile[128];
|
||||
|
||||
sprintf(lockfile,"/var/run/LOCK.qcam.0x%x",q->port);
|
||||
if (-1 == (q->fd = open(lockfile, O_WRONLY | O_CREAT, 0666)))
|
||||
{
|
||||
perror("open");
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef TESTING
|
||||
fprintf(stderr, "%s - %d: %s open(2)ed\n", __FILE__, __LINE__, lockfile);
|
||||
#endif
|
||||
|
||||
/* initialize the l_type memver to lock the file exclusively */
|
||||
sfl.l_type = F_WRLCK;
|
||||
}
|
||||
|
||||
#ifdef TESTING
|
||||
if (0 != fcntl(q->fd, F_SETLK, &sfl)) /* non-blocking set lock */
|
||||
#else
|
||||
if (0 != fcntl(q->fd, wait? F_SETLKW : F_SETLK, &sfl))
|
||||
#endif
|
||||
{
|
||||
#ifdef TESTING
|
||||
perror("fcntl");
|
||||
if (EAGAIN != errno || !wait) return 1;
|
||||
|
||||
fprintf(stderr, "%s - %d: waiting for exclusive lock on fd %d...\n", __FILE__, __LINE__, q->fd);
|
||||
|
||||
if (0 != fcntl(q->fd, F_SETLKW, &sfl)) /* "blocking" set lock */
|
||||
#endif
|
||||
{
|
||||
perror("fcntl");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TESTING
|
||||
fprintf(stderr, "%s - %d: fd %d locked exclusively\n", __FILE__, __LINE__, q->fd);
|
||||
#endif
|
||||
|
||||
#else
|
||||
char lockfile[128], tmp[128];
|
||||
struct stat statbuf;
|
||||
|
||||
sprintf(lockfile,"/var/run/LOCK.qcam.0x%x",q->port);
|
||||
sprintf(tmp,"%s-%d",lockfile,getpid());
|
||||
|
||||
if ((creat(tmp,0)==-1) ||
|
||||
(link(tmp,lockfile)==-1) ||
|
||||
(stat(tmp,&statbuf)==-1) ||
|
||||
(statbuf.st_nlink==1))
|
||||
{
|
||||
#ifdef DEBUGQC
|
||||
perror("QuickCam Locked");
|
||||
if(unlink(tmp)==-1)
|
||||
perror("Error unlinking temp file.");
|
||||
#else
|
||||
unlink(tmp);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
unlink(tmp);
|
||||
if (chown(lockfile,getuid(),getgid())==-1)
|
||||
perror("Chown problems");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qc_lock(struct qcam *q)
|
||||
{
|
||||
#if 1
|
||||
return qc_lock_wait(q, 1 /*wait*/);
|
||||
#else
|
||||
return qc_lock_wait(q, 0 /*don't wait*/);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Unlock port */
|
||||
|
||||
int qc_unlock(struct qcam *q)
|
||||
{
|
||||
static struct flock sfl;
|
||||
#if 1
|
||||
if (-1 == q->fd)
|
||||
{ /* port was not locked */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* clear the exclusive lock */
|
||||
sfl.l_type = F_UNLCK;
|
||||
if (0 != fcntl(q->fd, F_SETLK, &sfl))
|
||||
{
|
||||
perror("fcntl");
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef TESTING
|
||||
fprintf(stderr, "%s - %d: fd %d unlocked\n", __FILE__, __LINE__, q->fd);
|
||||
#endif
|
||||
|
||||
#else
|
||||
char lockfile[128];
|
||||
|
||||
sprintf(lockfile,"/var/run/LOCK.qcam.0x%x",q->port);
|
||||
unlink(lockfile); /* What would I do with an error? */
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Probe for camera. Returns 0 if found, 1 if not found, sets
|
||||
q->port.*/
|
||||
|
||||
int qc_probe(struct qcam *q)
|
||||
{
|
||||
int ioports[]={0x378, 0x278, 0x3bc,0};
|
||||
int i=0;
|
||||
|
||||
/* Attempt to get permission to access IO ports. Must be root */
|
||||
|
||||
while(ioports[i]!=0) {
|
||||
q->port=ioports[i++];
|
||||
|
||||
if (qc_open(q)) {
|
||||
perror("Can't get I/O permission");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(qc_detect(q)) {
|
||||
fprintf(stderr,"QuickCam detected at 0x%x\n",q->port);
|
||||
qc_close(q);
|
||||
return(0);
|
||||
}
|
||||
else
|
||||
qc_close(q);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* THIS IS UGLY. I need a short delay loop -- somthing well under a
|
||||
millisecond. Unfortunately, adding 2 usleep(1)'s to qc_command slowed
|
||||
it down by a factor of over 1000 over the same loop with 2
|
||||
usleep(0)'s, and that's too slow -- qc_start was taking over a second
|
||||
to run. This seems to help, but if anyone has a good
|
||||
speed-independent pause routine, please tell me. -- Scott */
|
||||
|
||||
void qc_wait(int val)
|
||||
{
|
||||
int i;
|
||||
|
||||
while(val--)
|
||||
for(i=0;i<50000;i++);
|
||||
}
|
32
sys/qcam/qcam-os.h
Normal file
32
sys/qcam/qcam-os.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/* qcam-linux.h -- Linux-specific routines for accessing QuickCam */
|
||||
|
||||
/* Version 0.1, January 2, 1996 */
|
||||
/* Version 0.5, August 24, 1996 */
|
||||
|
||||
|
||||
/******************************************************************
|
||||
|
||||
Copyright (C) 1996 by Scott Laird
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
******************************************************************/
|
||||
|
||||
|
134
sys/qcam/qcam.h
Normal file
134
sys/qcam/qcam.h
Normal file
|
@ -0,0 +1,134 @@
|
|||
/* qcam.h -- routines for accessing the Connectix QuickCam */
|
||||
|
||||
/* Version 0.1, January 2, 1996 */
|
||||
/* Version 0.5, August 24, 1996 */
|
||||
/* Version 0.7, August 26, 1996 */
|
||||
|
||||
|
||||
/******************************************************************
|
||||
|
||||
Copyright (C) 1996 by Scott Laird
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
******************************************************************/
|
||||
|
||||
#ifndef _QCAM_H
|
||||
#define _QCAM_H
|
||||
|
||||
#define QC_VERSION "0.91"
|
||||
|
||||
/* One from column A... */
|
||||
#define QC_NOTSET 0
|
||||
#define QC_UNIDIR 1
|
||||
#define QC_BIDIR 2
|
||||
#define QC_SERIAL 3
|
||||
|
||||
/* ... and one from column B */
|
||||
#define QC_ANY 0x00
|
||||
#define QC_FORCE_UNIDIR 0x10
|
||||
#define QC_FORCE_BIDIR 0x20
|
||||
#define QC_FORCE_SERIAL 0x30
|
||||
/* in the port_mode member */
|
||||
|
||||
#define QC_MODE_MASK 0x07
|
||||
#define QC_FORCE_MASK 0x70
|
||||
|
||||
#define MAX_HEIGHT 243
|
||||
#define MAX_WIDTH 336
|
||||
|
||||
struct qcam {
|
||||
int width, height;
|
||||
int bpp;
|
||||
int mode;
|
||||
int contrast, brightness, whitebal;
|
||||
int port;
|
||||
int port_mode;
|
||||
int transfer_scale;
|
||||
int top, left;
|
||||
int fd; /* lock file descriptor
|
||||
* It was, unfortunately, necessary to add this member to the
|
||||
* struct qcam to conveniently implement POSIX fcntl-style locking.
|
||||
* We need a seperate lock file for each struct qcam, for instance,
|
||||
* if the same process (using qcam-lib) is accessing multiple
|
||||
* QuickCams on (of course) multiple ports.
|
||||
* - Dave Plonka (plonka@carroll1.cc.edu)
|
||||
*/
|
||||
};
|
||||
|
||||
typedef unsigned char scanbuf;
|
||||
|
||||
/* General QuickCam handling routines */
|
||||
|
||||
int qc_getbrightness(const struct qcam *q);
|
||||
int qc_setbrightness(struct qcam *q, int val);
|
||||
int qc_getcontrast(const struct qcam *q);
|
||||
int qc_setcontrast(struct qcam *q, int val);
|
||||
int qc_getwhitebal(const struct qcam *q);
|
||||
int qc_setwhitebal(struct qcam *q, int val);
|
||||
void qc_getresolution(const struct qcam *q, int *x, int *y);
|
||||
int qc_setresolution(struct qcam *q, int x, int y);
|
||||
int qc_getbitdepth(const struct qcam *q);
|
||||
int qc_setbitdepth(struct qcam *q, int val);
|
||||
int qc_getheight(const struct qcam *q);
|
||||
int qc_setheight(struct qcam *q, int y);
|
||||
int qc_getwidth(const struct qcam *q);
|
||||
int qc_setwidth(struct qcam *q, int x);
|
||||
int qc_gettop(const struct qcam *q);
|
||||
int qc_settop(struct qcam *q, int val);
|
||||
int qc_getleft(const struct qcam *q);
|
||||
int qc_setleft(struct qcam *q, int val);
|
||||
int qc_gettransfer_scale(const struct qcam *q);
|
||||
int qc_settransfer_scale(struct qcam *q, int val);
|
||||
int qc_calibrate(struct qcam *q);
|
||||
int qc_forceunidir(struct qcam *q);
|
||||
void qc_dump(const struct qcam *q, char *file);
|
||||
|
||||
struct qcam *qc_init(void);
|
||||
int qc_initfile(struct qcam *q, char *fname);
|
||||
int qc_open(struct qcam *q);
|
||||
int qc_close(struct qcam *q);
|
||||
int qc_detect(const struct qcam *q);
|
||||
void qc_reset(struct qcam *q);
|
||||
void qc_set(struct qcam *q);
|
||||
scanbuf *qc_scan(const struct qcam *q);
|
||||
scanbuf *qc_convertscan(struct qcam *q, scanbuf *scan);
|
||||
void qc_writepgm(const struct qcam *q, FILE *f, scanbuf *scan);
|
||||
void qc_wait(int val);
|
||||
|
||||
/* OS/hardware specific routines */
|
||||
|
||||
int read_lpstatus(const struct qcam *q);
|
||||
int read_lpcontrol(const struct qcam *q);
|
||||
int read_lpdata(const struct qcam *q);
|
||||
void write_lpdata(const struct qcam *q, int d);
|
||||
void write_lpcontrol(const struct qcam *q, int d);
|
||||
int enable_ports(const struct qcam *q);
|
||||
int disable_ports(const struct qcam *q);
|
||||
int qc_unlock(struct qcam *q);
|
||||
int qc_lock(struct qcam *q);
|
||||
void qc_wait(int val);
|
||||
int qc_probe(struct qcam *q);
|
||||
|
||||
/* Image processing routines */
|
||||
int fixdark(const struct qcam *q, scanbuf *scan);
|
||||
int qc_edge_detect(const struct qcam *q, scanbuf *scan, int tolerance);
|
||||
|
||||
#endif /*! _QCAM_H*/
|
67
sys/qcam/qcamip.h
Normal file
67
sys/qcam/qcamip.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* qcamip.h - Connectix QuickCam Image Processing routines
|
||||
*
|
||||
* Time-stamp: <02 Sep 96 11:19:27 HST edo@eosys.com>
|
||||
*
|
||||
* Version 0.2
|
||||
*/
|
||||
|
||||
/******************************************************************
|
||||
|
||||
Copyright (C) 1996 by Ed Orcutt Systems
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, and/or distribute copies of the
|
||||
Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
1. The above copyright notice and this permission notice shall
|
||||
be included in all copies or substantial portions of the
|
||||
Software.
|
||||
|
||||
2. Redistribution for profit requires the express, written
|
||||
permission of the author.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL ED ORCUTT SYSTEMS BE LIABLE
|
||||
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
******************************************************************/
|
||||
|
||||
#ifndef _QCAMIP_H
|
||||
#define _QCAMIP_H
|
||||
#include "qcam.h"
|
||||
|
||||
/* Auto exposure modes */
|
||||
|
||||
#define AE_ALL_AVG 0
|
||||
#define AE_CTR_AVG 1
|
||||
#define AE_STD_AVG 2
|
||||
|
||||
/* Return value of image processing routines */
|
||||
|
||||
#define QCIP_XPSR_OK 0
|
||||
#define QCIP_XPSR_RSCN 1
|
||||
#define QCIP_XPSR_ERR 2
|
||||
#define QCIP_XPSR_LUM_INVLD 3
|
||||
|
||||
/* Prototypes for image processing routines */
|
||||
|
||||
int qcip_autoexposure(struct qcam *q, scanbuf *scan);
|
||||
int qcip_set_luminance_target(struct qcam *q, int val);
|
||||
int qcip_set_luminance_tolerance(struct qcam *q, int val);
|
||||
int qcip_set_luminance_std_target(struct qcam *q, int val);
|
||||
int qcip_set_luminance_std_tolerance(struct qcam *q, int val);
|
||||
int qcip_set_autoexposure_mode(int val);
|
||||
void qcip_histogram(struct qcam *q, scanbuf *scan, int *histogram);
|
||||
void qcip_display_histogram(struct qcam *q, scanbuf *scan);
|
||||
|
||||
#endif /*! _QCAMIP_H*/
|
Loading…
Reference in a new issue