first batch

Original commit message from CVS:
first batch
This commit is contained in:
Thomas Vander Stichele 2001-12-17 19:03:13 +00:00
parent 49d345d9ef
commit bb8c108211
13 changed files with 2620 additions and 0 deletions

5
sys/Makefile.am Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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*/