This is the source for the FinePix webcam driver on http://bebits.com/app/4185

I have received permission from Øyvind Smestad to use the part he wrote under MIT licence, but some other parts are GPL sources from Linux.
The plan is to merge the core part into usb_webcam, and use either the JPEG Translator or libjpeg to replace the GPLed jpeg decoding part.
Here is what he said:

From Øyvind Smestad (o.smestad AT gmail.com):

When it comes to licencing, the media addon part is heavily based on
the VideoProducer sample code from Be (I don't remember their exact
licensing terms, but they were quite liberal weren't they?). The
driver part is partially based on the Linux FinePix driver by Frank
Zago (http://www.zago.net/v4l2/finepix/ -
http://sourceforge.net/projects/fpix/), that is where the Linux JPEG
code came from and also where I got the device IDs. If the JPEG part
is removed I don't think there should be enough left there to break
the GPL, as the rest of the code is probably more "inspired by" than
"copied from" the Linux driver. At least I remember having to monitor
the USB traffic under Windows to get the setup commands right, and I
also think there were some articles on writing a BeOS webcam driver
and on using the USBKit that I used as references.

I hope that made it a bit more clear!
As for what I did, I'm more than happy for it to be under MIT licence.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29066 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
François Revol
2009-01-27 22:19:35 +00:00
parent f2e161c535
commit 5fc1932331
15 changed files with 2448 additions and 0 deletions
@@ -0,0 +1,906 @@
/*
* linux/drivers/video/bootsplash/decode-jpg.c - a tiny jpeg decoder.
*
* (w) August 2001 by Michael Schroeder, <[email protected]>
*
* This version modified by Luc Willems to adapt to the JPEG format
* returned by the FinePix cameras.
*
*/
#include "finepix-jpeg.h"
#define ISHIFT 11
#define IFIX(a) ((int)((a) * (1 << ISHIFT) + .5))
#define IMULT(a, b) (((a) * (b)) >> ISHIFT)
#define ITOINT(a) ((a) >> ISHIFT)
#ifndef __P
# define __P(x) x
#endif
/* special markers */
#define M_BADHUFF -1
#define M_EOF 0x80
struct in {
unsigned char *p;
unsigned int bits;
int left;
int marker;
int (*func) __P((void *));
void *data;
};
/*********************************/
struct dec_hufftbl;
struct enc_hufftbl;
union hufftblp {
struct dec_hufftbl *dhuff;
struct enc_hufftbl *ehuff;
};
struct scan {
int dc; /* old dc value */
union hufftblp hudc;
union hufftblp huac;
int next; /* when to switch to next scan */
int cid; /* component id */
int hv; /* horiz/vert, copied from comp */
int tq; /* quant tbl, copied from comp */
};
/*********************************/
#define DECBITS 10 /* seems to be the optimum */
struct dec_hufftbl {
int maxcode[17];
int valptr[16];
unsigned char vals[256];
unsigned int llvals[1 << DECBITS];
};
static void decode_mcus __P((struct in *, int *, int, struct scan *, int *));
static int dec_readmarker __P((struct in *));
static void dec_makehuff __P((struct dec_hufftbl *, int *, unsigned char *));
static void setinput __P((struct in *, unsigned char *));
/*********************************/
#undef PREC
#define PREC int
static void idctqtab __P((unsigned char *, PREC *));
static void idct __P((int *, int *, PREC *, PREC, int));
static void scaleidctqtab __P((PREC *, PREC));
/*********************************/
static void initcol __P((PREC[][64]));
static void col211111 __P((int *, unsigned char *, int));
/*********************************/
#define M_SOI 0xd8
#define M_APP0 0xe0
#define M_DQT 0xdb
#define M_SOF0 0xc0
#define M_DHT 0xc4
#define M_DRI 0xdd
#define M_SOS 0xda
#define M_RST0 0xd0
#define M_EOI 0xd9
#define M_COM 0xfe
static unsigned char *datap;
static int getbyte(void)
{
return *datap++;
}
static int getword(void)
{
int c1, c2;
c1 = *datap++;
c2 = *datap++;
return c1 << 8 | c2;
}
struct comp {
int cid;
int hv;
int tq;
};
#define MAXCOMP 4
struct jpginfo {
int nc; /* number of components */
int ns; /* number of scans */
int dri; /* restart interval */
int nm; /* mcus til next marker */
int rm; /* next restart marker */
};
static struct jpginfo info;
static struct comp comps[MAXCOMP];
static struct scan dscans[MAXCOMP];
static unsigned char quant[4][64];
static struct dec_hufftbl dhuff[4];
#define dec_huffdc (dhuff + 0)
#define dec_huffac (dhuff + 2)
static struct in in;
static int readtables(int till)
{
int m, l, i, j, lq, pq, tq;
int tc, th, tt;
for (;;) {
if (getbyte() != 0xff)
return -1;
if ((m = getbyte()) == till)
break;
switch (m) {
case 0xc2:
return 0;
case M_DQT:
lq = getword();
while (lq > 2) {
pq = getbyte();
tq = pq & 15;
if (tq > 3)
return -1;
pq >>= 4;
if (pq != 0)
return -1;
for (i = 0; i < 64; i++)
quant[tq][i] = getbyte();
lq -= 64 + 1;
}
break;
case M_DHT:
l = getword();
while (l > 2) {
int hufflen[16], k;
unsigned char huffvals[256];
tc = getbyte();
th = tc & 15;
tc >>= 4;
tt = tc * 2 + th;
if (tc > 1 || th > 1)
return -1;
for (i = 0; i < 16; i++)
hufflen[i] = getbyte();
l -= 1 + 16;
k = 0;
for (i = 0; i < 16; i++) {
for (j = 0; j < hufflen[i]; j++)
huffvals[k++] = getbyte();
l -= hufflen[i];
}
dec_makehuff(dhuff + tt, hufflen, huffvals);
}
break;
case M_DRI:
l = getword();
info.dri = getword();
break;
default:
l = getword();
while (l-- > 2)
getbyte();
break;
}
}
return 0;
}
static void dec_initscans(void)
{
int i;
info.nm = info.dri + 1;
info.rm = M_RST0;
for (i = 0; i < info.ns; i++)
dscans[i].dc = 0;
}
static int dec_checkmarker(void)
{
int i;
if (dec_readmarker(&in) != info.rm)
return -1;
info.nm = info.dri;
info.rm = (info.rm + 1) & ~0x08;
for (i = 0; i < info.ns; i++)
dscans[i].dc = 0;
return 0;
}
int jpeg_check_size(unsigned char *buf, int width, int height)
{
datap = buf;
getbyte();
getbyte();
readtables(M_SOF0);
getword();
getbyte();
if (height != getword() || width != getword())
return 0;
return 1;
}
int jpeg_decode(unsigned char *buf, unsigned char *pic,
int width, int height, int depth, struct jpeg_decdata *decdata)
{
int i, j, m, tac, tdc;
int mcusx, mcusy, mx, my;
int max[6];
if (!decdata)
return -1;
memset(decdata, 0x00, sizeof(decdata));
datap = buf;
if (getbyte() != 0xff)
return ERR_NO_SOI;
if (getbyte() != M_SOI)
return ERR_NO_SOI;
if (readtables(M_SOF0))
return ERR_BAD_TABLES;
getword();
i = getbyte();
if (i != 8)
return ERR_NOT_8BIT;
if (((getword() + 15) & ~15) != height) ; //return ERR_HEIGHT_MISMATCH;
if (((getword() + 15) & ~15) != width) ; //return ERR_WIDTH_MISMATCH;
if ((height & 15) || (width & 15)) ; //return ERR_BAD_WIDTH_OR_HEIGHT;
info.nc = getbyte();
if (info.nc > MAXCOMP)
return ERR_TOO_MANY_COMPPS;
for (i = 0; i < info.nc; i++) {
int h, v;
comps[i].cid = getbyte();
comps[i].hv = getbyte();
v = comps[i].hv & 15;
h = comps[i].hv >> 4;
comps[i].tq = getbyte();
if (h > 3 || v > 3)
return ERR_ILLEGAL_HV;
if (comps[i].tq > 3)
return ERR_QUANT_TABLE_SELECTOR;
}
if (readtables(M_SOS))
return ERR_BAD_TABLES;
getword();
info.ns = getbyte();
if (info.ns != 3)
return ERR_NOT_YCBCR_221111;
for (i = 0; i < 3; i++) {
dscans[i].cid = getbyte();
tdc = getbyte();
tac = tdc & 15;
tdc >>= 4;
if (tdc > 1 || tac > 1)
return ERR_QUANT_TABLE_SELECTOR;
for (j = 0; j < info.nc; j++)
if (comps[j].cid == dscans[i].cid)
break;
if (j == info.nc)
return ERR_UNKNOWN_CID_IN_SCAN;
dscans[i].hv = comps[j].hv;
dscans[i].tq = comps[j].tq;
dscans[i].hudc.dhuff = dec_huffdc + tdc;
dscans[i].huac.dhuff = dec_huffac + tac;
}
i = getbyte();
j = getbyte();
m = getbyte();
if (i != 0 || j != 63 || m != 0)
return ERR_NOT_SEQUENTIAL_DCT;
if (dscans[0].cid != 1 || dscans[1].cid != 2 || dscans[2].cid != 3)
return ERR_NOT_YCBCR_221111;
/*if (dscans[0].hv != 0x22 || dscans[1].hv != 0x11 || dscans[2].hv != 0x11)
return ERR_NOT_YCBCR_221111; */
mcusx = width >> 4;
mcusy = height >> 3;
idctqtab(quant[dscans[0].tq], decdata->dquant[0]);
idctqtab(quant[dscans[1].tq], decdata->dquant[1]);
idctqtab(quant[dscans[2].tq], decdata->dquant[2]);
initcol(decdata->dquant);
setinput(&in, datap);
#if 0
/* landing zone */
img[len] = 0;
img[len + 1] = 0xff;
img[len + 2] = M_EOF;
#endif
dec_initscans();
dscans[0].next = 6 - 4;
dscans[1].next = 6 - 4 - 1;
dscans[2].next = 6 - 4 - 1 - 1; /* 411 encoding */
for (my = 0; my < mcusy; my++) {
for (mx = 0; mx < mcusx; mx++) {
if (info.dri && !--info.nm)
if (dec_checkmarker())
return ERR_WRONG_MARKER;
decode_mcus(&in, decdata->dcts, 4, dscans, max);
idct(decdata->dcts, decdata->out, decdata->dquant[0],
IFIX(128.5), max[0]);
idct(decdata->dcts + 64, decdata->out + 64,
decdata->dquant[0], IFIX(128.5), max[1]);
idct(decdata->dcts + 128, decdata->out + 128,
decdata->dquant[0], IFIX(128.5), max[2]);
idct(decdata->dcts + 192, decdata->out + 192,
decdata->dquant[0], IFIX(128.5), max[3]);
idct(decdata->dcts + 128, decdata->out + 256,
decdata->dquant[1], IFIX(0.5), max[4]);
idct(decdata->dcts + 192, decdata->out + 320,
decdata->dquant[2], IFIX(0.5), max[5]);
switch (depth) {
case 24:
col211111(decdata->out,
pic + (my * 8 * mcusx + mx) * 16 * 3,
mcusx * 16 * 3);
break;
default:
return ERR_DEPTH_MISMATCH;
break;
}
}
}
m = dec_readmarker(&in);
if (m != M_EOI)
return ERR_NO_EOI;
return 0;
}
/****************************************************************/
/************** huffman decoder ***************/
/****************************************************************/
static int fillbits __P((struct in *, int, unsigned int));
static int dec_rec2 __P((struct in *, struct dec_hufftbl *, int *, int, int));
static void setinput(struct in *in, unsigned char *p)
{
in->p = p;
in->left = 0;
in->bits = 0;
in->marker = 0;
}
static int fillbits(struct in *in, int le, unsigned int bi)
{
int b, m;
if (in->marker) {
if (le <= 16)
in->bits = bi << 16, le += 16;
return le;
}
while (le <= 24) {
b = *in->p++;
if (b == 0xff && (m = *in->p++) != 0) {
if (m == M_EOF) {
if (in->func && (m = in->func(in->data)) == 0)
continue;
}
in->marker = m;
if (le <= 16)
bi = bi << 16, le += 16;
break;
}
bi = bi << 8 | b;
le += 8;
}
in->bits = bi; /* tmp... 2 return values needed */
return le;
}
static int dec_readmarker(struct in *in)
{
int m;
in->left = fillbits(in, in->left, in->bits);
if ((m = in->marker) == 0)
return 0;
in->left = 0;
in->marker = 0;
return m;
}
#define LEBI_DCL int le, bi
#define LEBI_GET(in) (le = in->left, bi = in->bits)
#define LEBI_PUT(in) (in->left = le, in->bits = bi)
#define GETBITS(in, n) ( \
(le < (n) ? le = fillbits(in, le, bi), bi = in->bits : 0), \
(le -= (n)), \
bi >> le & ((1 << (n)) - 1) \
)
#define UNGETBITS(in, n) ( \
le += (n) \
)
static int dec_rec2(struct in *in, struct dec_hufftbl *hu,
int *runp, int c, int i)
{
LEBI_DCL;
LEBI_GET(in);
if (i) {
UNGETBITS(in, i & 127);
*runp = i >> 8 & 15;
i >>= 16;
} else {
for (i = DECBITS;
(c = ((c << 1) | GETBITS(in, 1))) >= (hu->maxcode[i]);
i++) ;
if (i >= 16) {
in->marker = M_BADHUFF;
return 0;
}
i = hu->vals[hu->valptr[i] + c - hu->maxcode[i - 1] * 2];
*runp = i >> 4;
i &= 15;
}
if (i == 0) { /* sigh, 0xf0 is 11 bit */
LEBI_PUT(in);
return 0;
}
/* receive part */
c = GETBITS(in, i);
if (c < (1 << (i - 1)))
c += (-1 << i) + 1;
LEBI_PUT(in);
return c;
}
#define DEC_REC(in, hu, r, i) ( \
r = GETBITS(in, DECBITS), \
i = hu->llvals[r], \
i & 128 ? \
( \
UNGETBITS(in, i & 127), \
r = i >> 8 & 15, \
i >> 16 \
) \
: \
( \
LEBI_PUT(in), \
i = dec_rec2(in, hu, &r, r, i), \
LEBI_GET(in), \
i \
) \
)
static void decode_mcus(struct in *in, int *dct, int n, struct scan *sc,
int *maxp)
{
struct dec_hufftbl *hu;
int i, r, t;
LEBI_DCL;
memset(dct, 0, n * 64 * sizeof(*dct));
LEBI_GET(in);
while (n-- > 0) {
hu = sc->hudc.dhuff;
*dct++ = (sc->dc += DEC_REC(in, hu, r, t));
hu = sc->huac.dhuff;
i = 63;
while (i > 0) {
t = DEC_REC(in, hu, r, t);
if (t == 0 && r == 0) {
dct += i;
break;
}
dct += r;
*dct++ = t;
i -= r + 1;
}
*maxp++ = 64 - i;
if (n == sc->next)
sc++;
}
LEBI_PUT(in);
}
static void dec_makehuff(struct dec_hufftbl *hu, int *hufflen,
unsigned char *huffvals)
{
int code, k, i, j, d, x, c, v;
for (i = 0; i < (1 << DECBITS); i++)
hu->llvals[i] = 0;
/*
* llvals layout:
*
* value v already known, run r, backup u bits:
* vvvvvvvvvvvvvvvv 0000 rrrr 1 uuuuuuu
* value unknown, size b bits, run r, backup u bits:
* 000000000000bbbb 0000 rrrr 0 uuuuuuu
* value and size unknown:
* 0000000000000000 0000 0000 0 0000000
*/
code = 0;
k = 0;
for (i = 0; i < 16; i++, code <<= 1) { /* sizes */
hu->valptr[i] = k;
for (j = 0; j < hufflen[i]; j++) {
hu->vals[k] = *huffvals++;
if (i < DECBITS) {
c = code << (DECBITS - 1 - i);
v = hu->vals[k] & 0x0f; /* size */
for (d = 1 << (DECBITS - 1 - i); --d >= 0;) {
if (v + i < DECBITS) { /* both fit in table */
x = d >> (DECBITS - 1 - v - i);
if (v && x < (1 << (v - 1)))
x += (-1 << v) + 1;
x = x << 16 | (hu->
vals[k] & 0xf0)
<< 4 | (DECBITS -
(i + 1 + v)) | 128;
} else
x = v << 16 | (hu->
vals[k] & 0xf0)
<< 4 | (DECBITS - (i + 1));
hu->llvals[c | d] = x;
}
}
code++;
k++;
}
hu->maxcode[i] = code;
}
hu->maxcode[16] = 0x20000; /* always terminate decode */
}
/****************************************************************/
/************** idct ***************/
/****************************************************************/
#define ONE ((PREC)IFIX(1.))
#define S2 ((PREC)IFIX(0.382683432))
#define C2 ((PREC)IFIX(0.923879532))
#define C4 ((PREC)IFIX(0.707106781))
#define S22 ((PREC)IFIX(2 * 0.382683432))
#define C22 ((PREC)IFIX(2 * 0.923879532))
#define IC4 ((PREC)IFIX(1 / 0.707106781))
#define C3IC1 ((PREC)IFIX(0.847759065)) /* c3/c1 */
#define C5IC1 ((PREC)IFIX(0.566454497)) /* c5/c1 */
#define C7IC1 ((PREC)IFIX(0.198912367)) /* c7/c1 */
#define XPP(a,b) (t = a + b, b = a - b, a = t)
#define XMP(a,b) (t = a - b, b = a + b, a = t)
#define XPM(a,b) (t = a + b, b = b - a, a = t)
#define ROT(a,b,s,c) ( t = IMULT(a + b, s), \
a = IMULT(a, c - s) + t, \
b = IMULT(b, c + s) - t)
#define IDCT \
( \
XPP(t0, t1), \
XMP(t2, t3), \
t2 = IMULT(t2, IC4) - t3, \
XPP(t0, t3), \
XPP(t1, t2), \
XMP(t4, t7), \
XPP(t5, t6), \
XMP(t5, t7), \
t5 = IMULT(t5, IC4), \
ROT(t4, t6, S22, C22),\
t6 -= t7, \
t5 -= t6, \
t4 -= t5, \
XPP(t0, t7), \
XPP(t1, t6), \
XPP(t2, t5), \
XPP(t3, t4) \
)
static unsigned char zig2[64] = {
0, 2, 3, 9, 10, 20, 21, 35,
14, 16, 25, 31, 39, 46, 50, 57,
5, 7, 12, 18, 23, 33, 37, 48,
27, 29, 41, 44, 52, 55, 59, 62,
15, 26, 30, 40, 45, 51, 56, 58,
1, 4, 8, 11, 19, 22, 34, 36,
28, 42, 43, 53, 54, 60, 61, 63,
6, 13, 17, 24, 32, 38, 47, 49
};
void idct(int *in, int *out, PREC * quant, PREC off, int max)
{
PREC t0, t1, t2, t3, t4, t5, t6, t7, t;
PREC tmp[64], *tmpp;
int i, j;
unsigned char *zig2p;
t0 = off;
if (max == 1) {
t0 += in[0] * quant[0];
for (i = 0; i < 64; i++)
out[i] = ITOINT(t0);
return;
}
zig2p = zig2;
tmpp = tmp;
for (i = 0; i < 8; i++) {
j = *zig2p++;
t0 += in[j] * quant[j];
j = *zig2p++;
t5 = in[j] * quant[j];
j = *zig2p++;
t2 = in[j] * quant[j];
j = *zig2p++;
t7 = in[j] * quant[j];
j = *zig2p++;
t1 = in[j] * quant[j];
j = *zig2p++;
t4 = in[j] * quant[j];
j = *zig2p++;
t3 = in[j] * quant[j];
j = *zig2p++;
t6 = in[j] * quant[j];
IDCT;
tmpp[0 * 8] = t0;
tmpp[1 * 8] = t1;
tmpp[2 * 8] = t2;
tmpp[3 * 8] = t3;
tmpp[4 * 8] = t4;
tmpp[5 * 8] = t5;
tmpp[6 * 8] = t6;
tmpp[7 * 8] = t7;
tmpp++;
t0 = 0;
}
for (i = 0; i < 8; i++) {
t0 = tmp[8 * i + 0];
t1 = tmp[8 * i + 1];
t2 = tmp[8 * i + 2];
t3 = tmp[8 * i + 3];
t4 = tmp[8 * i + 4];
t5 = tmp[8 * i + 5];
t6 = tmp[8 * i + 6];
t7 = tmp[8 * i + 7];
IDCT;
out[8 * i + 0] = ITOINT(t0);
out[8 * i + 1] = ITOINT(t1);
out[8 * i + 2] = ITOINT(t2);
out[8 * i + 3] = ITOINT(t3);
out[8 * i + 4] = ITOINT(t4);
out[8 * i + 5] = ITOINT(t5);
out[8 * i + 6] = ITOINT(t6);
out[8 * i + 7] = ITOINT(t7);
}
}
static unsigned char zig[64] = {
0, 1, 5, 6, 14, 15, 27, 28,
2, 4, 7, 13, 16, 26, 29, 42,
3, 8, 12, 17, 25, 30, 41, 43,
9, 11, 18, 24, 31, 40, 44, 53,
10, 19, 23, 32, 39, 45, 52, 54,
20, 22, 33, 38, 46, 51, 55, 60,
21, 34, 37, 47, 50, 56, 59, 61,
35, 36, 48, 49, 57, 58, 62, 63
};
static PREC aaidct[8] = {
IFIX(0.3535533906), IFIX(0.4903926402),
IFIX(0.4619397663), IFIX(0.4157348062),
IFIX(0.3535533906), IFIX(0.2777851165),
IFIX(0.1913417162), IFIX(0.0975451610)
};
static void idctqtab(unsigned char *qin, PREC * qout)
{
int i, j;
for (i = 0; i < 8; i++)
for (j = 0; j < 8; j++)
qout[zig[i * 8 + j]] = qin[zig[i * 8 + j]] *
IMULT(aaidct[i], aaidct[j]);
}
static void scaleidctqtab(PREC * q, PREC sc)
{
int i;
for (i = 0; i < 64; i++)
q[i] = IMULT(q[i], sc);
}
/****************************************************************/
/************** color decoder ***************/
/****************************************************************/
#define ROUND
/*
* YCbCr Color transformation:
*
* y:0..255 Cb:-128..127 Cr:-128..127
*
* R = Y + 1.40200 * Cr
* G = Y - 0.34414 * Cb - 0.71414 * Cr
* B = Y + 1.77200 * Cb
*
* =>
* Cr *= 1.40200;
* Cb *= 1.77200;
* Cg = 0.19421 * Cb + .50937 * Cr;
* R = Y + Cr;
* G = Y - Cg;
* B = Y + Cb;
*
* =>
* Cg = (50 * Cb + 130 * Cr + 128) >> 8;
*/
static void initcol(PREC q[][64])
{
scaleidctqtab(q[1], IFIX(1.77200));
scaleidctqtab(q[2], IFIX(1.40200));
}
/* This is optimized for the stupid sun SUNWspro compiler. */
#define STORECLAMP(a,x) \
( \
(a) = (x), \
(unsigned int)(x) >= 256 ? \
((a) = (x) < 0 ? 0 : 255) \
: \
0 \
)
#define CLAMP(x) ((unsigned int)(x) >= 256 ? ((x) < 0 ? 0 : 255) : (x))
#ifdef ROUND
#define CBCRCG(yin, xin) \
( \
cb = outc[0 +yin*8+xin], \
cr = outc[64+yin*8+xin], \
cg = (50 * cb + 130 * cr + 128) >> 8 \
)
#else
#define CBCRCG(yin, xin) \
( \
cb = outc[0 +yin*8+xin], \
cr = outc[64+yin*8+xin], \
cg = (3 * cb + 8 * cr) >> 4 \
)
#endif
#define PIC(yin, xin, p, xout) \
( \
y = outy[(yin) * 8 + xin], \
STORECLAMP(p[(xout) * 3 + 2], y + cr), \
STORECLAMP(p[(xout) * 3 + 1], y - cg), \
STORECLAMP(p[(xout) * 3 + 0], y + cb) \
)
#ifdef __LITTLE_ENDIAN
#define PIC_16(yin, xin, p, xout, add) \
( \
y = outy[(yin) * 8 + xin], \
y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 8) | \
((CLAMP(y - cg + add ) & 0xfc) << 3) | \
((CLAMP(y + cb + add*2+1) ) >> 3), \
p[(xout) * 2 + 0] = y & 0xff, \
p[(xout) * 2 + 1] = y >> 8 \
)
#else
#ifdef CONFIG_PPC
#define PIC_16(yin, xin, p, xout, add) \
( \
y = outy[(yin) * 8 + xin], \
y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 7) | \
((CLAMP(y - cg + add*2+1) & 0xf8) << 2) | \
((CLAMP(y + cb + add*2+1) ) >> 3), \
p[(xout) * 2 + 0] = y >> 8, \
p[(xout) * 2 + 1] = y & 0xff \
)
#else
#define PIC_16(yin, xin, p, xout, add) \
( \
y = outy[(yin) * 8 + xin], \
y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 8) | \
((CLAMP(y - cg + add ) & 0xfc) << 3) | \
((CLAMP(y + cb + add*2+1) ) >> 3), \
p[(xout) * 2 + 0] = y >> 8, \
p[(xout) * 2 + 1] = y & 0xff \
)
#endif
#endif
#define PIC211111(xin) \
( \
CBCRCG(0, xin), \
PIC(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0), \
PIC(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1) \
PIC(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0), \
PIC(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1) \
}
#define PIC221111(xin) \
( \
CBCRCG(0, xin), \
PIC(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0), \
PIC(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1), \
PIC(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0), \
PIC(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1) \
)
#define PIC221111_16(xin) \
( \
CBCRCG(0, xin), \
PIC_16(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0, 3), \
PIC_16(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1, 0), \
PIC_16(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0, 1), \
PIC_16(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1, 2) \
)
static void col211111(int *out, unsigned char *pic, int width)
{
int j, k;
unsigned char *pic0, *pic1;
int *outy, *outc;
int cr, cg, cb, y;
pic0 = pic;
pic1 = pic + width;
outy = out;
outc = out + 64 * 4;
for (j = 4; j > 0; j--) {
for (k = 0; k < 8; k++) {
PIC221111(k);
}
outc += 8;
outy += 16;
pic0 += 2 * width;
pic1 += 2 * width;
}
}
@@ -0,0 +1,36 @@
/*
* linux/drivers/video/bootsplash/decode-jpg.h - a tiny jpeg decoder.
*
* (w) August 2001 by Michael Schroeder, <[email protected]>
*/
#ifndef __DECODE_JPG_H
#define __DECODE_JPG_H
#define ERR_NO_SOI 1
#define ERR_NOT_8BIT 2
#define ERR_HEIGHT_MISMATCH 3
#define ERR_WIDTH_MISMATCH 4
#define ERR_BAD_WIDTH_OR_HEIGHT 5
#define ERR_TOO_MANY_COMPPS 6
#define ERR_ILLEGAL_HV 7
#define ERR_QUANT_TABLE_SELECTOR 8
#define ERR_NOT_YCBCR_221111 9
#define ERR_UNKNOWN_CID_IN_SCAN 10
#define ERR_NOT_SEQUENTIAL_DCT 11
#define ERR_WRONG_MARKER 12
#define ERR_NO_EOI 13
#define ERR_BAD_TABLES 14
#define ERR_DEPTH_MISMATCH 15
struct jpeg_decdata {
int dcts[6 * 64 + 16];
int out[64 * 6];
int dquant[3][64];
};
extern int jpeg_decode(unsigned char *, unsigned char *, int, int, int,
struct jpeg_decdata *);
extern int jpeg_check_size(unsigned char *, int, int);
#endif
@@ -0,0 +1,108 @@
#include <support/Autolock.h>
#include <media/MediaFormats.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "AddOn.h"
#include "Producer.h"
MediaAddOn::MediaAddOn(image_id imid)
: BMediaAddOn(imid)
{
/* Customize these parameters to match those of your node */
fFlavorInfo.name = "FinePixProducer";
fFlavorInfo.info = "FinePixProducer";
fFlavorInfo.kinds = B_BUFFER_PRODUCER | B_CONTROLLABLE | B_PHYSICAL_INPUT;
fFlavorInfo.flavor_flags = 0;
fFlavorInfo.internal_id = 0;
fFlavorInfo.possible_count = 1;
fFlavorInfo.in_format_count = 0;
fFlavorInfo.in_format_flags = 0;
fFlavorInfo.in_formats = NULL;
fFlavorInfo.out_format_count = 1;
fFlavorInfo.out_format_flags = 0;
fMediaFormat.type = B_MEDIA_RAW_VIDEO;
fMediaFormat.u.raw_video = media_raw_video_format::wildcard;
fMediaFormat.u.raw_video.interlace = 1;
fMediaFormat.u.raw_video.display.format = B_RGB32;
fFlavorInfo.out_formats = &fMediaFormat;
fInitStatus = B_OK;
}
MediaAddOn::~MediaAddOn()
{
}
status_t
MediaAddOn::InitCheck(const char **out_failure_text)
{
if (fInitStatus < B_OK) {
*out_failure_text = "Unknown error";
return fInitStatus;
}
return B_OK;
}
int32
MediaAddOn::CountFlavors()
{
if (fInitStatus < B_OK)
return fInitStatus;
/* This addon only supports a single flavor, as defined in the
* constructor */
return 1;
}
/*
* The pointer to the flavor received only needs to be valid between
* successive calls to BMediaAddOn::GetFlavorAt().
*/
status_t
MediaAddOn::GetFlavorAt(int32 n, const flavor_info **out_info)
{
if (fInitStatus < B_OK)
return fInitStatus;
if (n != 0)
return B_BAD_INDEX;
/* Return the flavor defined in the constructor */
*out_info = &fFlavorInfo;
return B_OK;
}
BMediaNode *
MediaAddOn::InstantiateNodeFor(
const flavor_info *info, BMessage *config, status_t *out_error)
{
FinePixProducer *node;
if (fInitStatus < B_OK)
return NULL;
if (info->internal_id != fFlavorInfo.internal_id)
return NULL;
/* At most one instance of the node should be instantiated at any given
* time. The locking for this restriction may be found in the FinePixProducer
* class. */
node = new FinePixProducer(this, fFlavorInfo.name, fFlavorInfo.internal_id);
if (node && (node->InitCheck() < B_OK)) {
delete node;
node = NULL;
}
return node;
}
BMediaAddOn *
make_media_addon(image_id imid)
{
return new MediaAddOn(imid);
}
@@ -0,0 +1,43 @@
#ifndef _VIDEO_ADDON_H
#define _VIDEO_ADDON_H
#include <media/MediaAddOn.h>
#define TOUCH(x) ((void)(x))
extern "C" _EXPORT BMediaAddOn *make_media_addon(image_id you);
class MediaAddOn : public BMediaAddOn
{
public:
MediaAddOn(image_id imid);
virtual ~MediaAddOn();
virtual status_t InitCheck(const char **out_failure_text);
virtual int32 CountFlavors();
virtual status_t GetFlavorAt(int32 n, const flavor_info ** out_info);
virtual BMediaNode *InstantiateNodeFor(
const flavor_info * info,
BMessage * config,
status_t * out_error);
virtual status_t GetConfigurationFor(BMediaNode *node, BMessage *message)
{ TOUCH(node); TOUCH(message); return B_OK; }
virtual status_t SaveConfigInfo(BMediaNode *node, BMessage *message)
{ TOUCH(node); TOUCH(message); return B_OK; }
virtual bool WantsAutoStart() { return false; }
virtual status_t AutoStart(int in_count, BMediaNode **out_node,
int32 *out_internal_id, bool *out_has_more)
{ TOUCH(in_count); TOUCH(out_node);
TOUCH(out_internal_id); TOUCH(out_has_more);
return B_ERROR; }
private:
status_t fInitStatus;
flavor_info fFlavorInfo;
media_format fMediaFormat;
};
#endif
@@ -0,0 +1,793 @@
#include <fcntl.h>
#include <malloc.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <sys/uio.h>
#include <unistd.h>
#include <media/Buffer.h>
#include <media/BufferGroup.h>
#include <media/ParameterWeb.h>
#include <media/TimeSource.h>
#include <support/Autolock.h>
#include <support/Debug.h>
#define TOUCH(x) ((void)(x))
#define PRINTF(a,b) \
do { \
if (a < 2) { \
printf("FinePixProducer::"); \
printf b; \
} \
} while (0)
#include "Producer.h"
#define FIELD_RATE 30.f
#define MAX_FRAME_SIZE 50000 // bytes (jpeg)
#define FPIX_RGB24_WIDTH 320
#define FPIX_RGB24_HEIGHT 240
#define FPIX_RGB24_FRAME_SIZE FPIX_RGB24_WIDTH * FPIX_RGB24_HEIGHT * 3
int32 FinePixProducer::fInstances = 0;
FinePixProducer::FinePixProducer(
BMediaAddOn *addon, const char *name, int32 internal_id)
: BMediaNode(name),
BMediaEventLooper(),
BBufferProducer(B_MEDIA_ENCODED_VIDEO),
BControllable()
{
//status_t err;
fInitStatus = B_NO_INIT;
/* Only allow one instance of the node to exist at any time */
if (atomic_add(&fInstances, 1) != 0)
return;
fInternalID = internal_id;
fAddOn = addon;
fBufferGroup = NULL;
fThread = -1;
fFrameSync = -1;
fProcessingLatency = 0LL;
fRunning = false;
fConnected = false;
fEnabled = false;
fOutput.destination = media_destination::null;
AddNodeKind(B_PHYSICAL_INPUT);
fDeltaBuffer = NULL; //øyvind
fCam = new FinePix();
fInitStatus = B_OK;
return;
}
FinePixProducer::~FinePixProducer()
{
if (fInitStatus == B_OK) {
/* Clean up after ourselves, in case the application didn't make us
* do so. */
if (fConnected)
Disconnect(fOutput.source, fOutput.destination);
if (fRunning)
HandleStop();
}
if( fCam ) //øyvind
{
delete fCam;
}
atomic_add(&fInstances, -1);
}
/* BMediaNode */
port_id
FinePixProducer::ControlPort() const
{
return BMediaNode::ControlPort();
}
BMediaAddOn *
FinePixProducer::AddOn(int32 *internal_id) const
{
if (internal_id)
*internal_id = fInternalID;
return fAddOn;
}
status_t
FinePixProducer::HandleMessage(int32 message, const void *data, size_t size)
{
return B_ERROR;
}
void
FinePixProducer::Preroll()
{
/* This hook may be called before the node is started to give the hardware
* a chance to start. */
}
void
FinePixProducer::SetTimeSource(BTimeSource *time_source)
{
/* Tell frame generation thread to recalculate delay value */
release_sem(fFrameSync);
}
status_t
FinePixProducer::RequestCompleted(const media_request_info &info)
{
return BMediaNode::RequestCompleted(info);
}
/* BMediaEventLooper */
void
FinePixProducer::NodeRegistered()
{
if (fInitStatus != B_OK) {
ReportError(B_NODE_IN_DISTRESS);
return;
}
fOutput.node = Node();
fOutput.source.port = ControlPort();
fOutput.source.id = 0;
fOutput.destination = media_destination::null;
strcpy(fOutput.name, Name());
/* Tailor these for the output of your device */
fOutput.format.type = B_MEDIA_RAW_VIDEO;
fOutput.format.u.raw_video = media_raw_video_format::wildcard;
fOutput.format.u.raw_video.interlace = 1;
fOutput.format.u.raw_video.display.format = B_RGB32;
/* Start the BMediaEventLooper control loop running */
Run();
}
void
FinePixProducer::Start(bigtime_t performance_time)
{
BMediaEventLooper::Start(performance_time);
}
void
FinePixProducer::Stop(bigtime_t performance_time, bool immediate)
{
BMediaEventLooper::Stop(performance_time, immediate);
}
void
FinePixProducer::Seek(bigtime_t media_time, bigtime_t performance_time)
{
BMediaEventLooper::Seek(media_time, performance_time);
}
void
FinePixProducer::TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time)
{
BMediaEventLooper::TimeWarp(at_real_time, to_performance_time);
}
status_t
FinePixProducer::AddTimer(bigtime_t at_performance_time, int32 cookie)
{
return BMediaEventLooper::AddTimer(at_performance_time, cookie);
}
void
FinePixProducer::SetRunMode(run_mode mode)
{
BMediaEventLooper::SetRunMode(mode);
}
void
FinePixProducer::HandleEvent(const media_timed_event *event,
bigtime_t lateness, bool realTimeEvent)
{
TOUCH(lateness); TOUCH(realTimeEvent);
switch(event->type)
{
case BTimedEventQueue::B_START:
HandleStart(event->event_time);
break;
case BTimedEventQueue::B_STOP:
HandleStop();
break;
case BTimedEventQueue::B_WARP:
HandleTimeWarp(event->bigdata);
break;
case BTimedEventQueue::B_SEEK:
HandleSeek(event->bigdata);
break;
case BTimedEventQueue::B_HANDLE_BUFFER:
case BTimedEventQueue::B_DATA_STATUS:
case BTimedEventQueue::B_PARAMETER:
default:
PRINTF(-1, ("HandleEvent: Unhandled event -- %lx\n", event->type));
break;
}
}
void
FinePixProducer::CleanUpEvent(const media_timed_event *event)
{
BMediaEventLooper::CleanUpEvent(event);
}
bigtime_t
FinePixProducer::OfflineTime()
{
return BMediaEventLooper::OfflineTime();
}
void
FinePixProducer::ControlLoop()
{
BMediaEventLooper::ControlLoop();
}
status_t
FinePixProducer::DeleteHook(BMediaNode * node)
{
return BMediaEventLooper::DeleteHook(node);
}
/* BBufferProducer */
status_t
FinePixProducer::FormatSuggestionRequested(
media_type type, int32 quality, media_format *format)
{
if (type != B_MEDIA_ENCODED_VIDEO)
return B_MEDIA_BAD_FORMAT;
TOUCH(quality);
*format = fOutput.format;
return B_OK;
}
status_t
FinePixProducer::FormatProposal(const media_source &output, media_format *format)
{
status_t err;
if (!format)
return B_BAD_VALUE;
if (output != fOutput.source)
return B_MEDIA_BAD_SOURCE;
err = format_is_compatible(*format, fOutput.format) ?
B_OK : B_MEDIA_BAD_FORMAT;
*format = fOutput.format;
return err;
}
status_t
FinePixProducer::FormatChangeRequested(const media_source &source,
const media_destination &destination, media_format *io_format,
int32 *_deprecated_)
{
TOUCH(destination); TOUCH(io_format); TOUCH(_deprecated_);
if (source != fOutput.source)
return B_MEDIA_BAD_SOURCE;
return B_ERROR;
}
status_t
FinePixProducer::GetNextOutput(int32 *cookie, media_output *out_output)
{
if (!out_output)
return B_BAD_VALUE;
if ((*cookie) != 0)
return B_BAD_INDEX;
*out_output = fOutput;
(*cookie)++;
return B_OK;
}
status_t
FinePixProducer::DisposeOutputCookie(int32 cookie)
{
TOUCH(cookie);
return B_OK;
}
status_t
FinePixProducer::SetBufferGroup(const media_source &for_source,
BBufferGroup *group)
{
TOUCH(for_source); TOUCH(group);
return B_ERROR;
}
status_t
FinePixProducer::VideoClippingChanged(const media_source &for_source,
int16 num_shorts, int16 *clip_data,
const media_video_display_info &display, int32 *_deprecated_)
{
TOUCH(for_source); TOUCH(num_shorts); TOUCH(clip_data);
TOUCH(display); TOUCH(_deprecated_);
return B_ERROR;
}
status_t
FinePixProducer::GetLatency(bigtime_t *out_latency)
{
*out_latency = EventLatency() + SchedulingLatency();
return B_OK;
}
status_t
FinePixProducer::PrepareToConnect(const media_source &source,
const media_destination &destination, media_format *format,
media_source *out_source, char *out_name)
{
//status_t err;
PRINTF(1, ("PrepareToConnect() %ldx%ld\n", \
format->u.raw_video.display.line_width, \
format->u.raw_video.display.line_count));
if (fConnected) {
PRINTF(0, ("PrepareToConnect: Already connected\n"));
return EALREADY;
}
if (source != fOutput.source)
return B_MEDIA_BAD_SOURCE;
if (fOutput.destination != media_destination::null)
return B_MEDIA_ALREADY_CONNECTED;
/* The format parameter comes in with the suggested format, and may be
* specialized as desired by the node */
if (!format_is_compatible(*format, fOutput.format)) {
*format = fOutput.format;
return B_MEDIA_BAD_FORMAT;
}
if (format->u.raw_video.display.line_width == 0)
format->u.raw_video.display.line_width = 320;
if (format->u.raw_video.display.line_count == 0)
format->u.raw_video.display.line_count = 240;
if (format->u.raw_video.field_rate == 0)
format->u.raw_video.field_rate = 29.97f;
*out_source = fOutput.source;
strcpy(out_name, fOutput.name);
fOutput.destination = destination;
return B_OK;
}
void
FinePixProducer::Connect(status_t error, const media_source &source,
const media_destination &destination, const media_format &format,
char *io_name)
{
PRINTF(1, ("Connect() %ldx%ld\n", \
format.u.raw_video.display.line_width, \
format.u.raw_video.display.line_count));
if (fConnected) {
PRINTF(0, ("Connect: Already connected\n"));
return;
}
if ( (source != fOutput.source) || (error < B_OK) ||
!const_cast<media_format *>(&format)->Matches(&fOutput.format)) {
PRINTF(1, ("Connect: Connect error\n"));
return;
}
fOutput.destination = destination;
strcpy(io_name, fOutput.name);
if (fOutput.format.u.raw_video.field_rate != 0.0f) {
fPerformanceTimeBase = fPerformanceTimeBase +
(bigtime_t)
((fFrame - fFrameBase) *
(1000000 / fOutput.format.u.raw_video.field_rate));
fFrameBase = fFrame;
}
fConnectedFormat = format.u.raw_video;
fDeltaBuffer = new uint8[MAX_FRAME_SIZE]; //ø in buffer
tempInBuffer = new uint8[3 * fConnectedFormat.display.line_width *
fConnectedFormat.display.line_count]; // for 24 bit color
fCam->SetupCam(); //øyvind
/* get the latency */
bigtime_t latency = 0;
media_node_id tsID = 0;
FindLatencyFor(fOutput.destination, &latency, &tsID);
#define NODE_LATENCY 1000
SetEventLatency(latency + NODE_LATENCY);
uint8 *tmp24 = (uint8*)tempInBuffer;
uint8 *buffer, *dst;
dst = buffer = (uint8 *)malloc(4 * fConnectedFormat.display.line_count *
fConnectedFormat.display.line_width);
if (!buffer) {
PRINTF(0, ("Connect: Out of memory\n"));
return;
}
bigtime_t now = system_time();
// Get a frame from the camera
fCam->GetPic(fDeltaBuffer, frame_size);
// Convert from jpeg to bitmap
if (jpeg_check_size(fDeltaBuffer,
FPIX_RGB24_WIDTH, FPIX_RGB24_HEIGHT))
{
int n = jpeg_decode(fDeltaBuffer, tmp24,
FPIX_RGB24_WIDTH, FPIX_RGB24_HEIGHT, 24, //32 not working
&decdata);
if (n)
{
PRINTF(-1, ("ooeps decode jpg result : %d", n));
}
} else
{
PRINTF(-1, ("ooeps check_size failed"));
}
// Convert from 24 bit to 32 bit
for (uint y=0; y<fConnectedFormat.display.line_count; y++)
for (uint x=0; x<fConnectedFormat.display.line_width; x++) {
*(dst++) = *tmp24; //red
tmp24++;
*(dst++) = *tmp24; //green
tmp24++;
*(dst++) = *tmp24; //blue
tmp24++;
dst++; //last 8 bit empty
}
fProcessingLatency = system_time() - now;
free(buffer);
/* Create the buffer group */
fBufferGroup = new BBufferGroup(4 * fConnectedFormat.display.line_width *
fConnectedFormat.display.line_count, 8);
if (fBufferGroup->InitCheck() < B_OK) {
delete fBufferGroup;
fBufferGroup = NULL;
return;
}
fConnected = true;
fEnabled = true;
/* Tell frame generation thread to recalculate delay value */
release_sem(fFrameSync);
}
void
FinePixProducer::Disconnect(const media_source &source,
const media_destination &destination)
{
PRINTF(1, ("Disconnect()\n"));
if (!fConnected) {
PRINTF(0, ("Disconnect: Not connected\n"));
return;
}
if ((source != fOutput.source) || (destination != fOutput.destination)) {
PRINTF(0, ("Disconnect: Bad source and/or destination\n"));
return;
}
fEnabled = false;
fOutput.destination = media_destination::null;
fLock.Lock();
delete fBufferGroup;
fBufferGroup = NULL;
delete fDeltaBuffer; //ø
fDeltaBuffer = NULL; //ø
delete tempInBuffer; //Ø
tempInBuffer = NULL; //Ø
fLock.Unlock();
fConnected = false;
}
void
FinePixProducer::LateNoticeReceived(const media_source &source,
bigtime_t how_much, bigtime_t performance_time)
{
TOUCH(source); TOUCH(how_much); TOUCH(performance_time);
}
void
FinePixProducer::EnableOutput(const media_source &source, bool enabled,
int32 *_deprecated_)
{
TOUCH(_deprecated_);
if (source != fOutput.source)
return;
fEnabled = enabled;
}
status_t
FinePixProducer::SetPlayRate(int32 numer, int32 denom)
{
TOUCH(numer); TOUCH(denom);
return B_ERROR;
}
void
FinePixProducer::AdditionalBufferRequested(const media_source &source,
media_buffer_id prev_buffer, bigtime_t prev_time,
const media_seek_tag *prev_tag)
{
TOUCH(source); TOUCH(prev_buffer); TOUCH(prev_time); TOUCH(prev_tag);
}
void
FinePixProducer::LatencyChanged(const media_source &source,
const media_destination &destination, bigtime_t new_latency,
uint32 flags)
{
TOUCH(source); TOUCH(destination); TOUCH(new_latency); TOUCH(flags);
}
/* BControllable */
status_t
FinePixProducer::GetParameterValue(
int32 id, bigtime_t *last_change, void *value, size_t *size)
{
return B_OK;
}
void
FinePixProducer::SetParameterValue(
int32 id, bigtime_t when, const void *value, size_t size)
{
}
status_t
FinePixProducer::StartControlPanel(BMessenger *out_messenger)
{
return BControllable::StartControlPanel(out_messenger);
}
/* FinePixProducer */
void
FinePixProducer::HandleStart(bigtime_t performance_time)
{
/* Start producing frames, even if the output hasn't been connected yet. */
PRINTF(1, ("HandleStart(%Ld)\n", performance_time));
if (fRunning) {
PRINTF(-1, ("HandleStart: Node already started\n"));
return;
}
fFrame = 0;
fFrameBase = 0;
fPerformanceTimeBase = performance_time;
fFrameSync = create_sem(0, "frame synchronization");
if (fFrameSync < B_OK)
goto err1;
fThread = spawn_thread(_frame_generator_, "frame generator",
B_NORMAL_PRIORITY, this);
if (fThread < B_OK)
goto err2;
resume_thread(fThread);
fRunning = true;
return;
err2:
delete_sem(fFrameSync);
err1:
return;
}
void
FinePixProducer::HandleStop(void)
{
PRINTF(1, ("HandleStop()\n"));
if (!fRunning) {
PRINTF(-1, ("HandleStop: Node isn't running\n"));
return;
}
delete_sem(fFrameSync);
wait_for_thread(fThread, &fThread);
fRunning = false;
}
void
FinePixProducer::HandleTimeWarp(bigtime_t performance_time)
{
fPerformanceTimeBase = performance_time;
fFrameBase = fFrame;
/* Tell frame generation thread to recalculate delay value */
release_sem(fFrameSync);
}
void
FinePixProducer::HandleSeek(bigtime_t performance_time)
{
fPerformanceTimeBase = performance_time;
fFrameBase = fFrame;
/* Tell frame generation thread to recalculate delay value */
release_sem(fFrameSync);
}
/* The following functions form the thread that generates frames. You should
* replace this with the code that interfaces to your hardware. */
int32
FinePixProducer::FrameGenerator()
{
bigtime_t wait_until = system_time();
while (1) {
status_t err = acquire_sem_etc(fFrameSync, 1, B_ABSOLUTE_TIMEOUT,
wait_until);
/* The only acceptable responses are B_OK and B_TIMED_OUT. Everything
* else means the thread should quit. Deleting the semaphore, as in
* FinePixProducer::HandleStop(), will trigger this behavior. */
if ((err != B_OK) && (err != B_TIMED_OUT))
break;
fFrame++;
/* Recalculate the time until the thread should wake up to begin
* processing the next frame. Subtract fProcessingLatency so that
* the frame is sent in time. */
wait_until = TimeSource()->RealTimeFor(fPerformanceTimeBase, 0) +
(bigtime_t)
((fFrame - fFrameBase) *
(1000000 / fConnectedFormat.field_rate)) -
fProcessingLatency;
/* Drop frame if it's at least a frame late */
if (wait_until < system_time())
continue;
/* If the semaphore was acquired successfully, it means something
* changed the timing information (see FinePixProducer::Connect()) and
* so the thread should go back to sleep until the newly-calculated
* wait_until time. */
if (err == B_OK)
continue;
/* Send buffers only if the node is running and the output has been
* enabled */
if (!fRunning || !fEnabled)
continue;
BAutolock _(fLock);
// Get the frame from the camera
fCam->GetPic(fDeltaBuffer, frame_size);
/* Fetch a buffer from the buffer group */
BBuffer *buffer = fBufferGroup->RequestBuffer(
4 * fConnectedFormat.display.line_width *
fConnectedFormat.display.line_count, 0LL);
if (!buffer)
continue;
/* Fill out the details about this buffer. */
media_header *h = buffer->Header();
h->type = B_MEDIA_RAW_VIDEO;
h->time_source = TimeSource()->ID();
h->size_used = 4 * fConnectedFormat.display.line_width *
fConnectedFormat.display.line_count;
/* For a buffer originating from a device, you might want to calculate
* this based on the PerformanceTimeFor the time your buffer arrived at
* the hardware (plus any applicable adjustments).
h->start_time = fPerformanceTimeBase +
(bigtime_t)
((fFrame - fFrameBase) *
(1000000 / fConnectedFormat.field_rate));*/
h->start_time = TimeSource()->Now();
h->file_pos = 0;
h->orig_size = 0;
h->data_offset = 0;
h->u.raw_video.field_gamma = 1.0;
h->u.raw_video.field_sequence = fFrame;
h->u.raw_video.field_number = 0;
h->u.raw_video.pulldown_number = 0;
h->u.raw_video.first_active_line = 1;
h->u.raw_video.line_count = fConnectedFormat.display.line_count;
// Frame data pointers
uint8 *tmp24 = (uint8*)tempInBuffer;
uint8 *dst = (uint8*)buffer->Data();
// Convert from jpeg to bitmap
if (jpeg_check_size(fDeltaBuffer,
FPIX_RGB24_WIDTH, FPIX_RGB24_HEIGHT))
{
int n = jpeg_decode(fDeltaBuffer, tmp24,
FPIX_RGB24_WIDTH, FPIX_RGB24_HEIGHT, 24, //32 not working
&decdata);
if (n)
{
PRINTF(-1, ("ooeps decode jpg result : %d", n));
}
} else
{
PRINTF(-1, ("ooeps check_size failed"));
}
// Convert from 24 bit to 32 bit
for (uint y=0; y<fConnectedFormat.display.line_count; y++)
for (uint x=0; x<fConnectedFormat.display.line_width; x++) {
*(dst++) = *tmp24; //red
tmp24++;
*(dst++) = *tmp24; //green
tmp24++;
*(dst++) = *tmp24; //blue
tmp24++;
dst++; //last 8 bit empty
}
/* Send the buffer on down to the consumer */
if (SendBuffer(buffer, fOutput.destination) < B_OK) {
PRINTF(-1, ("FrameGenerator: Error sending buffer\n"));
/* If there is a problem sending the buffer, return it to its
* buffer group. */
buffer->Recycle();
}
}
return B_OK;
}
int32
FinePixProducer::_frame_generator_(void *data)
{
return ((FinePixProducer *)data)->FrameGenerator();
}
@@ -0,0 +1,147 @@
#ifndef _VIDEO_PRODUCER_H
#define _VIDEO_PRODUCER_H
#include <kernel/OS.h>
#include <media/BufferProducer.h>
#include <media/Controllable.h>
#include <media/MediaDefs.h>
#include <media/MediaEventLooper.h>
#include <media/MediaNode.h>
#include <support/Locker.h>
#include "../FinePixUSBKit/FinePix.h"
extern "C"{
#include "../FinePixJpeg/finepix-jpeg.h"
}
class FinePixProducer :
public virtual BMediaEventLooper,
public virtual BBufferProducer,
public virtual BControllable
{
public:
FinePixProducer(BMediaAddOn *addon,
const char *name, int32 internal_id);
virtual ~FinePixProducer();
virtual status_t InitCheck() const { return fInitStatus; }
/* BMediaNode */
public:
virtual port_id ControlPort() const;
virtual BMediaAddOn *AddOn(int32 * internal_id) const;
virtual status_t HandleMessage(int32 message, const void *data,
size_t size);
protected:
virtual void Preroll();
virtual void SetTimeSource(BTimeSource * time_source);
virtual status_t RequestCompleted(const media_request_info & info);
/* BMediaEventLooper */
protected:
virtual void NodeRegistered();
virtual void Start(bigtime_t performance_time);
virtual void Stop(bigtime_t performance_time, bool immediate);
virtual void Seek(bigtime_t media_time, bigtime_t performance_time);
virtual void TimeWarp(bigtime_t at_real_time,
bigtime_t to_performance_time);
virtual status_t AddTimer(bigtime_t at_performance_time, int32 cookie);
virtual void SetRunMode(run_mode mode);
virtual void HandleEvent(const media_timed_event *event,
bigtime_t lateness, bool realTimeEvent = false);
virtual void CleanUpEvent(const media_timed_event *event);
virtual bigtime_t OfflineTime();
virtual void ControlLoop();
virtual status_t DeleteHook(BMediaNode * node);
/* BBufferProducer */
protected:
virtual status_t FormatSuggestionRequested(media_type type, int32 quality,
media_format * format);
virtual status_t FormatProposal(const media_source &output,
media_format *format);
virtual status_t FormatChangeRequested(const media_source &source,
const media_destination &destination,
media_format *io_format, int32 *_deprecated_);
virtual status_t GetNextOutput(int32 * cookie, media_output * out_output);
virtual status_t DisposeOutputCookie(int32 cookie);
virtual status_t SetBufferGroup(const media_source &for_source,
BBufferGroup * group);
virtual status_t VideoClippingChanged(const media_source &for_source,
int16 num_shorts, int16 *clip_data,
const media_video_display_info &display,
int32 * _deprecated_);
virtual status_t GetLatency(bigtime_t * out_latency);
virtual status_t PrepareToConnect(const media_source &what,
const media_destination &where,
media_format *format,
media_source *out_source, char *out_name);
virtual void Connect(status_t error, const media_source &source,
const media_destination &destination,
const media_format & format, char *io_name);
virtual void Disconnect(const media_source & what,
const media_destination & where);
virtual void LateNoticeReceived(const media_source & what,
bigtime_t how_much, bigtime_t performance_time);
virtual void EnableOutput(const media_source & what, bool enabled,
int32 * _deprecated_);
virtual status_t SetPlayRate(int32 numer,int32 denom);
virtual void AdditionalBufferRequested(const media_source & source,
media_buffer_id prev_buffer, bigtime_t prev_time,
const media_seek_tag * prev_tag);
virtual void LatencyChanged(const media_source & source,
const media_destination & destination,
bigtime_t new_latency, uint32 flags);
/* BControllable */
protected:
virtual status_t GetParameterValue(int32 id, bigtime_t *last_change,
void *value, size_t *size);
virtual void SetParameterValue(int32 id, bigtime_t when,
const void *value, size_t size);
virtual status_t StartControlPanel(BMessenger *out_messenger);
/* state */
private:
void HandleStart(bigtime_t performance_time);
void HandleStop();
void HandleTimeWarp(bigtime_t performance_time);
void HandleSeek(bigtime_t performance_time);
static int32 fInstances;
status_t fInitStatus;
int32 fInternalID;
BMediaAddOn *fAddOn;
BLocker fLock;
BBufferGroup *fBufferGroup;
thread_id fThread;
sem_id fFrameSync;
static int32 _frame_generator_(void *data);
int32 FrameGenerator();
/* The remaining variables should be declared volatile, but they
* are not here to improve the legibility of the sample code. */
uint32 fFrame;
uint32 fFrameBase;
bigtime_t fPerformanceTimeBase;
bigtime_t fProcessingLatency;
media_output fOutput;
media_raw_video_format fConnectedFormat;
bool fRunning;
bool fConnected;
bool fEnabled;
FinePix *fCam; //camera
uint8 *fDeltaBuffer; //in buffer
int frame_size; //size of jpeg in bytes
uint8 *tempInBuffer; //for 24 bit bitmap
// V4l : jpeg decoder data (not used here, needed as parameter in jpeg_decode())
struct jpeg_decdata decdata;
};
#endif
@@ -0,0 +1,245 @@
#include <stdio.h>
#include "FinePix.h"
/* Describes the hardware. */
struct camera_hw {
unsigned long /*__u16*/ vendor;
unsigned long /*__u16*/ product;
/* Offical name of the camera. */
char name[32];
};
static struct camera_hw cam_supp[23] = {
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_4800_PID, "Fujifilm FinePix 4800"},
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_A202_PID, "Fujifilm FinePix A202"},
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_A203_PID, "Fujifilm FinePix A203"},
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_A204_PID, "Fujifilm FinePix A204"},
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_A205_PID, "Fujifilm FinePix A205"},
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_A210_PID, "Fujifilm FinePix A210"},
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_A303_PID, "Fujifilm FinePix A303"},
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_A310_PID, "Fujifilm FinePix A310"},
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_F401_PID, "Fujifilm FinePix F401"},
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_F402_PID, "Fujifilm FinePix F402"},
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_F410_PID, "Fujifilm FinePix F410"},
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_F601_PID, "Fujifilm FinePix F601"},
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_F700_PID, "Fujifilm FinePix F700"},
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_M603_PID, "Fujifilm FinePix M603"},
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_S3000_PID,
"Fujifilm FinePix S3000"},
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_S304_PID, "Fujifilm FinePix S304"},
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_S5000_PID,
"Fujifilm FinePix S5000"},
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_S602_PID, "Fujifilm FinePix S602"},
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_S7000_PID,
"Fujifilm FinePix S7000"},
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_X1_PID,
"Fujifilm FinePix unknown model"},
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_X2_PID,
"Fujifilm FinePix unknown model"},
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_X3_PID,
"Fujifilm FinePix unknown model"},
{USB_FUJIFILM_VENDOR_ID, USB_FINEPIX_X4_PID,
"Fujifilm FinePix unknown model"},
};
FinePix::FinePix()
{
fprintf(stderr, "FinePix::FinePix()\n");
// Initially we don't have a camera device opened.
camera = NULL;
// Start the roster that will wait for FinePix USB devices.
BUSBRoster::Start();
}
FinePix::~FinePix()
{
fprintf(stderr, "FinePix: ~FinePix()\n");
BUSBRoster::Stop();
}
status_t FinePix::InitCheck()
{
fprintf(stderr, "FinePix: InitCheck()\n");
if (camera != NULL)
return B_NO_ERROR;
else
return B_ERROR;
}
int FinePix::SetupCam()
{
int ret; // Return value
fprintf(stderr, "FinePix: SetupCam()\n");
/* Reset bulk in endpoint */
camera->ControlTransfer (USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_IN,
USB_REQUEST_CLEAR_FEATURE, USB_FEATURE_ENDPOINT_HALT, 0, 0, NULL);
/* Reset the camera *//* Init the device */
unsigned char data[] = { 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00 };
ret = camera->ControlTransfer(USB_REQTYPE_INTERFACE_OUT |USB_REQTYPE_CLASS ,
USB_REQUEST_GET_STATUS, 0x00, 0x00, 12, data);
fprintf(stderr,"data: %x, %x, %x, %x, %x, %x, %x, %x, %x, %x, %x, %x\n",
data[0], data[1],data[2], data[3],data[4], data[5],
data[6], data[7],data[8], data[9],data[10], data[11]);
if (ret != 12) {
fprintf(stderr,"usb_control_msg failed (%d)\n", ret);
return 1;
}
unsigned char data3[MAX_BUFFER_SIZE];
ret = bulk_in->BulkTransfer(data3, MAX_BUFFER_SIZE);
fprintf(stderr,"BulkIn: %x, %x, %x, %x, %x, %x\n",
data3[0],data3[1],data3[2],data3[3],data3[4],data3[5]);
if (ret < 0) {
fprintf(stderr,"failed to read the result (%d)\n", ret);
//return 1;
}
/* Again, reset bulk in endpoints */
camera->ControlTransfer (USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_IN,
USB_REQUEST_CLEAR_FEATURE, USB_FEATURE_ENDPOINT_HALT, 0, 0, NULL);
return 0;
}
int FinePix::GetPic(uint8 *frame, int &total_size)
{
fprintf(stderr, "FinePix: GetPic()\n");
int ret; // Return value
/* Request a frame */
fprintf(stderr,"request a frame\n");
unsigned char data2[] = { 0xd3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 };
ret = camera->ControlTransfer(USB_REQTYPE_INTERFACE_OUT |USB_REQTYPE_CLASS ,
USB_REQUEST_GET_STATUS, 0x00, 0x00, 12, data2);
fprintf(stderr,"data: %x, %x, %x, %x, %x, %x, %x, %x, %x, %x, %x, %x\n",
data2[0], data2[1],data2[2], data2[3],data2[4], data2[5],
data2[6], data2[7],data2[8], data2[9],data2[10], data2[11]);
if (ret != 12)
{
fprintf(stderr,"usb_control_msg failed (%d)\n", ret);
return 1;
}
/* Read the frame */
int offset = 0;
total_size = 0;
do
{
fprintf(stderr,"reading part of the frame\n");
ret = bulk_in->BulkTransfer(&frame[offset], MAX_BUFFER_SIZE);
fprintf(stderr,"frame: %x, %x, %x, %x, %x, %x, %x, %x, %x, %x, %x, %x\n",
frame[offset+0], frame[offset+1],frame[offset+2], frame[offset+3],
frame[offset+4], frame[offset+5],frame[offset+6], frame[offset+7],
frame[offset+8], frame[offset+9],frame[offset+10], frame[offset+11]);
if (ret < 0) { //this doesn't help, if we have an error we hang at the transfer
fprintf(stderr,"failed to read (%d)\n", ret);
return 1;
}
offset += ret;
total_size += ret;
if (ret != MAX_BUFFER_SIZE) // not a full buffer, must be end of frame
break;
} while(1);
fprintf(stderr,"this frame was %d bytes\n", total_size);
return 0;
}
status_t FinePix::DeviceAdded(BUSBDevice *dev)
{
fprintf(stderr, "FinePix: DeviceAdded()\n");
// Waits for FinePix devices. When one is attached, configure it,
// so that we are ready to use it.
if (camera != NULL)
return B_ERROR;
int myCam = -1;
// Find the device in our hardware list
if (dev->VendorID() == USB_FUJIFILM_VENDOR_ID)
{
for (int j = 0; j < 23; j++) //TODO use a cleaner way to check j < cam_supp.count
{
if (cam_supp[j].product == dev->ProductID())
{
myCam = j;
break;
}
}
}
if (myCam >= 0)
{
fprintf(stderr, "Found cam: ");
fprintf(stderr, cam_supp[myCam].name);
fprintf(stderr, "\n");
if (dev->SetConfiguration(dev->ConfigurationAt(0)) == 0)
{
camera = dev;
//set endpoint
bulk_in = 0;
int num_epoints = camera->ActiveConfiguration()->InterfaceAt(0)->CountEndpoints();
fprintf(stderr, "CountEndpoints: %d\n", num_epoints);
for (int i = 0; i < num_epoints; i++)
{
if (camera->ActiveConfiguration()->InterfaceAt(0)->EndpointAt(i)->IsBulk())
if (camera->ActiveConfiguration()->InterfaceAt(0)->EndpointAt(i)->IsInput())
bulk_in = camera->ActiveConfiguration()->InterfaceAt(0)->EndpointAt(i);
}
if (bulk_in == 0)
{
fprintf(stderr, "bad endpoint");
return B_ERROR;
}
fprintf(stderr, "Successfully set configuration!\n");
return B_OK;
}
else
return B_ERROR;
}
else
return B_ERROR;
}
void FinePix::DeviceRemoved(BUSBDevice *dev)
{
fprintf(stderr, "FinePix: DeviceRemoved()\n");
// If they remove our device, then we can't use it anymore.
if (dev == camera)
camera = NULL;
}
@@ -0,0 +1,51 @@
#include <USBKit.h>
#define MAX_BUFFER_SIZE 4096 //Size ot transfer buffer from camera
/* IDs of cameras the driver (hopefully) supports. Some different
* cameras have the same USB ids, so we just keep one here. */
#define USB_FUJIFILM_VENDOR_ID 0x04cb
#define USB_FINEPIX_4800_PID 0x0104
#define USB_FINEPIX_F601_PID 0x0109
#define USB_FINEPIX_S602_PID 0x010b
#define USB_FINEPIX_F402_PID 0x010f
#define USB_FINEPIX_M603_PID 0x0111
#define USB_FINEPIX_A202_PID 0x0113
#define USB_FINEPIX_F401_PID 0x0115
#define USB_FINEPIX_A203_PID 0x0117
#define USB_FINEPIX_A303_PID 0x0119
#define USB_FINEPIX_S304_PID 0x011b
#define USB_FINEPIX_A204_PID 0x011d
#define USB_FINEPIX_F700_PID 0x0121
#define USB_FINEPIX_F410_PID 0x0123
#define USB_FINEPIX_A310_PID 0x0125
#define USB_FINEPIX_A210_PID 0x0127
#define USB_FINEPIX_A205_PID 0x0129
#define USB_FINEPIX_X1_PID 0x012B
#define USB_FINEPIX_S7000_PID 0x012d
#define USB_FINEPIX_X2_PID 0x012F
#define USB_FINEPIX_S5000_PID 0x0131
#define USB_FINEPIX_X3_PID 0x013B
#define USB_FINEPIX_S3000_PID 0x013d
#define USB_FINEPIX_X4_PID 0x013f
class FinePix : private BUSBRoster
{
public:
FinePix();
virtual ~FinePix();
status_t InitCheck(); // check if any error occurs
int SetupCam(); // ready camera for sending pictures
int GetPic(uint8 *frame, int &total_size); // get pictures!
status_t DeviceAdded(BUSBDevice* dev); //dev added
void DeviceRemoved(BUSBDevice* dev); //dev removed
private:
BUSBDevice* camera;
const BUSBEndpoint* bulk_in;
};
@@ -0,0 +1,43 @@
#include <stdio.h>
#include <unistd.h>
#include "../FinePixUSBKit/FinePix.h"
int main ()
{
FinePix* test = new FinePix();
uint8 *frame = new uint8[100000]; // Max frame size 100k
int total_size = 0;
while(1)
{ // Wait around and let the (usb)roster do its thing
snooze(1000000);
if (test->InitCheck() == B_OK)
{
fprintf(stderr, "Camera ready\n");
test->SetupCam();
for (int i=0; i<1; i++) { // Number of frames to get
// Get a frame
test->GetPic(frame, total_size);
// Save the frame
//fprintf(stderr,"This frame was %d bytes\n", total_size);
char fname[100];
sprintf(fname, "frame-%05d.jpg", i);
int fd = open(fname, O_WRONLY | O_CREAT,0644);
write(fd, frame, total_size);
close(fd);
fprintf(stderr,"Saved as file:%s \n", fname);
/* Wait before requesting next frame,
* for 30 fps wait less than 33333ms (1 sek / 30) */
snooze(30000);
}
break;
} else {
fprintf(stderr, "Camera not ready\n");
}
}
delete test;
return 0;
}
@@ -0,0 +1,21 @@
Here is the author's authorization to use the MIT licence for the part he wrote:
From Øyvind Smestad (o.smestad AT gmail.com):
When it comes to licencing, the media addon part is heavily based on
the VideoProducer sample code from Be (I don't remember their exact
licensing terms, but they were quite liberal weren't they?). The
driver part is partially based on the Linux FinePix driver by Frank
Zago (http://www.zago.net/v4l2/finepix/ -
http://sourceforge.net/projects/fpix/), that is where the Linux JPEG
code came from and also where I got the device IDs. If the JPEG part
is removed I don't think there should be enough left there to break
the GPL, as the rest of the code is probably more "inspired by" than
"copied from" the Linux driver. At least I remember having to monitor
the USB traffic under Windows to get the setup commands right, and I
also think there were some articles on writing a BeOS webcam driver
and on using the USBKit that I used as references.
I hope that made it a bit more clear!
As for what I did, I'm more than happy for it to be under MIT licence.
@@ -0,0 +1,55 @@
Driver for FujiFilm FinePix digital cameras in PcCam (WebCam) mode. Version 0.1.1
This driver is for FinePix cameras with a USB connection.
It should hopefully work with the following cameras under Zeta:
Fujifilm FinePix 4800
Fujifilm FinePix A202
Fujifilm FinePix A203
Fujifilm FinePix A204
Fujifilm FinePix A205
Fujifilm FinePix A210
Fujifilm FinePix A303
Fujifilm FinePix A310
Fujifilm FinePix F401
Fujifilm FinePix F402
Fujifilm FinePix F410
Fujifilm FinePix F601
Fujifilm FinePix F700
Fujifilm FinePix M603
Fujifilm FinePix S3000
Fujifilm FinePix S304
Fujifilm FinePix S5000
Fujifilm FinePix S602
Fujifilm FinePix S7000
, only tested with FinePix S602Zoom on Zeta 1.1 though.
TEST
You can test if it works with your camera by connecting the camera and running FinePixTest in the Terminal. It should output lots of debug info and save one image in the same folder it's run from. (PS the test might not work after the media addon is installed, as that then takes control over the camera.)
INSTALLATION
Drop the FinePix.media_addon on the "Drop media_addon here to install" link, or copy manually to /boot/home/config/add-ons/media. Then Restart Media Services in the Media preferences, and the FinePixProducer should appear as a Video Input under Video Settings.
USAGE
Should (hopefully) work with all applications that accept video input, tested with CodyCam and Cortex.
REMOVAL
Delete FinePix.media_addon from /boot/home/config/add-ons/media
KNOWN BUGS
Might crash the media_addon_server if camera is disconnected while in use or if application tries to access a camera that is not connected. This can be cleared up by restarting the media services in Media preferences.
IMPLEMENTATION DETAILS
Uses the USBKit. The media addon part is heavily based on the VideoProducer sample code from Be, and the driver is partially based on the Linux FinePix driver by Frank Zago and information gathered with the handy SnoopyPro USB Sniffer tool for Windows.
FUTURE PLANS
Make it harder to crash :-) Maybe move from USBKit to kernel mode for the actual driver part.
Made by:
Øyvind Smestad
[email protected]
PS
For transfering pictures taken with the camera (DSC mode) use the USB Storage Module by Siarzhuk Zharski (http://bebits.com/app/3889)