| Below, a running example of a piece of code grabbing a TV frame
via video4linux driver. Nice! |
Dato un driver BTTV per Linux e una scheda TV capace di
acquisizione, ecco un semplicissimo esempio di come si può "grabbare"
un frame video e salvarlo in un file in formato Targa.
La pagina di codice qui sotto fa riferimento al driver "Video for Linux"
versione 1 (non il "v4l2" che sta cominciando a circolare), anche se le
modifiche per quest'ultimo non dovrebbero essere affatto difficili.
Un paio di ultime cose:
- non è usando ripetutamente questo programma che otterremo sequenze
compatte di immagini per cavarne animazioni (vanno infatti sfruttati
alternatamente e continuamente i due frame 0 e 1; mentre uno "attende"
il frame video, l'altro è pronto per salvare);
- il formato Targa-uncompressed è banalissimo: diciotto bytes di
header (notare come al posto di 444 e 555 vengano sostituite
larghezza e altezza dell'immagine) seguiti dai pixel in formato r/g/b
(per cui il programmino qui sotto non ha bisogno di "spostare" i
pixel in giro);
- per convertire da Targa a JPEG è sufficiente il comando:
cjpeg <frame.tga >frame.jpg (si può anche usare quest'altro:
grab | cjpeg >frame.jpg); chiedere man cjpeg per maggiori
informazioni.
//
// grab.c
// 19-9-2001, a.martone@retepnet.it
// grab a TV frame (via video4linux) in TGA-uncompressed-RGB24 format
//
// compile: cc -s -O1 grab.c -o grab
// usage: grab >frame.tga
//
// info: thanks to Gerd Knorr's xawtv sources (www.bytesex.org/xawtv)
//
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/ioctl.h>
#include <linux/videodev.h>
#undef DEBUGGING
main()
{
int fd, siz;
short targaheader[9]={ 0,2,0,0,0,0,444,555,8216 }; /* 444 and 555 are fake */
void *map;
struct video_mmap v;
v.format=VIDEO_PALETTE_RGB24; // ... GREY, RGB555, RGB565, RGB24, RGB32
v.frame=0; // 0 or 1 (buffer 0 or buffer 1)
v.width=768; // from 32 to 924 (sometimes limited to 768)
v.height=576; // from 32 to 576
siz=v.width*v.height*3; // rgb24 is: 3; rgb32:4; rgb565:2; rgb555:2
targaheader[6]=v.width;
targaheader[7]=v.height; // update targa header for frame
fd=open("/dev/video",O_RDONLY); // open video device
if(fd<0) perror("/dev/video");
map=mmap(0, siz, PROT_READ, MAP_SHARED, fd, 0); // select memory-map
if(map==MAP_FAILED) perror("mmap");
#ifdef DEBUGGING
{
int xmin, xmax, ymin, ymax;
unsigned long freq;
struct video_capability cap;
struct video_buffer b;
struct video_picture p;
if(ioctl(fd, VIDIOCGFREQ, &freq)<0) perror("VIDIOCGFREQ");
fprintf(stderr,"freq: 0x%x\n", freq);
if(ioctl(fd, VIDIOCGCAP, &cap)<0) perror("VIDIOCGCAP");
xmin=cap.minwidth, xmax=cap.maxwidth;
ymin=cap.minheight,ymax=cap.maxheight;
fprintf(stderr, "capture sizes: (%dx%d)-->(%dx%d)\n",xmin,ymin,xmax,ymax);
if(ioctl(fd, VIDIOCGFBUF, &b)<0) perror("VIDIOCGFBUF");
fprintf(stderr,"base:%p, size:(%dx%d), depth:%d, bpl=%d\n",
b.base, b.width, b.height, b.depth, b.bytesperline);
if(ioctl(fd, VIDIOCGPICT, &p)<0) perror("VIDIOCGPICT");
fprintf(stderr, "brightness:%d, hue:%d, color=%d, contrast=%d\n"
"whiteness:%d, depth:%d, palette[%d]\n",
p.brightness, p.hue, p.colour, p.contrast,
p.whiteness, p.depth, p.palette);
}
#endif
if(ioctl(fd, VIDIOCMCAPTURE, &v)<0) // start capturing a frame
perror("VIDIOCMCAPTURE");
if(ioctl(fd, VIDIOCSYNC, &v.frame)<0) // wait for end of frame
perror("VIDIOCSYNC");
fwrite(targaheader, sizeof(targaheader), // save header & data to stdout
1, stdout);
fwrite(map, siz, 1, stdout);
}
send e-mail
- continua (next page)