Hello,
thank you for your hints, Gerd, but I have still problems with
bttv-0.8.38 and a patched 2.4.19-pre7 kernel.
If I use the v4l2-driver videodevX from http://www.thedirks.org/v4l2/
and the bttv2-driver from
http://bttv-v4l2.sourceforge.net/ it works (if I use 4 buffers) but
this site says that this drivers will be superseded by bttv-0.8.xx, so
I want to use
If I use mp1e, version 1.9.1, with progressive filter mode (./mp1e m 1
-vv -F 6) I lose 50% of the frames (i.e. echo other field) with
bttv-0.8.38 and I get all fields with bttv2.
Does anybody has a working piece of code to capture both field with
bttv-0.8.xx?
I attach my code, maybe some bugs could be found out.
Thank you
Bernd
> > //vid_fmt.fmt.pix.flags |= V4L2_FMT_FLAG_INTERLACED;
> > vid_fmt.fmt.pix.flags |= V4L2_FMT_FLAG_TOPFIELD;
> > vid_fmt.fmt.pix.flags |= V4L2_FMT_FLAG_BOTFIELD;
>
> Wrong. Use v4l2_buffer->flags = V4L2_BUF_FLAG_(TOP|BOT)FIELD when
> queuing buffers.
>
> Gerd
>
> --
> You can't please everybody. And usually if you _try_ to please
> everybody, the end result is one big mess.
> -- Linus Torvalds, 2002-04-20
>
/*
* $Id$
*
* each_field_v4l2.c
* capture odd and even (TOP/BOTTOM) fields
*
* Author: Bernd Blessmann
* Date: 2002-04-30
*
*/
/* ---------------------------- includes --------------------------- */
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/videodev.h>
/* ---------------------------- defines ---------------------------- */
/* ------------------------ static globals ------------------------- */
/* ------------------- static function prototypes ------------------ */
static void print_fmtpix(struct v4l2_format*);
/* ----------------------- public globals -------------------------- */
/* --------- public functions (prototypes in header only ----------- */
int main(int argc, char* argv[]) {
int fd; /* file descriptor (video device) */
struct v4l2_capability vid_cap;
/* open device */
if (argc != 2 || !argv[1] || !*argv[1]) {
fprintf(stderr, "usage:\t%s device\n", argv[0]);
exit(1);
}
if ( (fd = open(argv[1], O_RDWR)) == -1 ) {
fprintf(stderr, "unable to open video device %s: %s\n", argv[1], strerror(errno));
exit(1);
}
/* query capabilities */
if ( ioctl(fd, VIDIOC_QUERYCAP, &vid_cap) == -1 ) {
perror("unable to query capabilities");
close(fd);
exit(1);
}
/* is it a capture device? */
if (vid_cap.type != V4L2_TYPE_CAPTURE) {
fprintf(stderr, "Not a capture device. Giving up\n");
close(fd);
exit(1);
}
/* can we use streaming? */
if (!(vid_cap.flags & V4L2_FLAG_STREAMING)) {
fprintf(stderr, "Device does not support streaming capture. Giving up\n");
close(fd);
exit(1);
}
/* start capture (with settings) */
{
#define BUF_COUNT 4
int i;
int bufNr;
struct v4l2_format vid_fmt;
struct v4l2_requestbuffers vid_reqb;
struct v4l2_buffer vid_buf[BUF_COUNT];
int vid_type = V4L2_BUF_TYPE_CAPTURE;
void* map[BUF_COUNT]; /* mapped memory */
/* set input */
i = 1; /* Composite 1 */
if ( ioctl(fd, VIDIOC_S_INPUT, &i) == -1 ) {
perror("VIDIOC_S_INPUT");
close(fd);
exit(1);
}
/* set up capture image format */
/* query settings to init struct */
vid_fmt.type = vid_type;
if ( ioctl(fd, VIDIOC_G_FMT, &vid_fmt) == -1 ) {
perror("VIDIOC_G_FMT");
close(fd);
exit(1);
}
vid_fmt.fmt.pix.flags = 0x00;
//vid_fmt.fmt.pix.flags |= V4L2_FMT_FLAG_INTERLACED;
vid_fmt.fmt.pix.flags |= V4L2_FMT_FLAG_TOPFIELD;
vid_fmt.fmt.pix.flags |= V4L2_FMT_FLAG_BOTFIELD;
vid_fmt.fmt.pix.width = 384;
vid_fmt.fmt.pix.height = 144;
vid_fmt.fmt.pix.depth = 24;
vid_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
if ( ioctl(fd, VIDIOC_S_FMT, &vid_fmt) == -1 ) {
perror("VIDIOC_S_FMT");
close(fd);
exit(1);
}
/* query settings */
vid_fmt.type = vid_type;
if ( ioctl(fd, VIDIOC_G_FMT, &vid_fmt) == -1 ) {
perror("VIDIOC_G_FMT");
close(fd);
exit(1);
}
printf("after get\n");
print_fmtpix(&vid_fmt);
/* allocate capture bufferrs */
vid_reqb.count = BUF_COUNT;
vid_reqb.type = vid_type;
if ( ioctl(fd, VIDIOC_REQBUFS, &vid_reqb) == -1 ) {
perror("VIDIOC_REQBUFS");
close(fd);
exit(1);
}
if (vid_reqb.count != BUF_COUNT || vid_reqb.type != vid_type) {
fprintf(stderr, "VIDIOC_REQBUFS: got not what I wanted!\n");
close(fd);
exit(1);
}
for (bufNr = 0; bufNr < BUF_COUNT; bufNr++) {
vid_buf[bufNr].index = bufNr;
vid_buf[bufNr].type = vid_reqb.type;
if ( ioctl(fd, VIDIOC_QUERYBUF, &vid_buf[bufNr]) == -1 ) {
perror("VIDIOC_QUERYBUF");
close(fd);
exit(1);
}
/* memory map buffers */
map[bufNr] = mmap(0, vid_buf[bufNr].length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, vid_buf[bufNr].offset);
if (MAP_FAILED == map[bufNr]) {
perror("unable to map memory");
close(fd);
exit(1);
}
}
/* streaming on */
if ( ioctl(fd, VIDIOC_STREAMON, &vid_buf[0].type) == -1 ) {
perror("VIDIOC_STREAMON");
close(fd);
exit(1);
}
for (i = 0; i < 1000/BUF_COUNT; i++) {
/* capture buffers */
for (bufNr = 0; bufNr < BUF_COUNT; bufNr++) {
int n;
fd_set rdset;
struct timeval timeout;
static int lastSeq;
static long long lastStamp;
static int lastFieldType;
//if (lastFieldType == V4L2_BUF_FLAG_BOTFIELD) {
// lastFieldType = vid_buf[bufNr].flags = V4L2_BUF_FLAG_TOPFIELD;
//} else {
// lastFieldType = vid_buf[bufNr].flags = V4L2_BUF_FLAG_BOTFIELD;
//}
vid_buf[bufNr].flags = 0x00;
if ( ioctl(fd, VIDIOC_QBUF, &vid_buf[bufNr]) == -1 ) {
fprintf(stderr, "buf %d: loop %d: ", bufNr, i);
perror("VIDIOC_QBUF");
close(fd);
exit(1);
}
printf("Q%d ", bufNr);
if ( i > 0 || bufNr >= (BUF_COUNT/2) ) {
int otherBufNr = (bufNr + (BUF_COUNT/2)) % BUF_COUNT;
FD_ZERO (&rdset);
FD_SET (fd, &rdset);
timeout.tv_sec = 1;
timeout.tv_usec = 0;
n = select (fd + 1, &rdset, NULL, NULL, &timeout);
if (n == -1) {
perror("select error");
} else if (n == 0) {
fprintf (stderr, "select timeout buf %d\n", otherBufNr);
} else if (FD_ISSET (fd, &rdset)) {
if ( ioctl(fd, VIDIOC_DQBUF, &vid_buf[otherBufNr]) == -1 ) {
perror("VIDIOC_DQBUF");
close(fd);
exit(1);
}
}
printf(" DQ%d", otherBufNr);
printf(" buf%2d: seq%3u ts%Ld", otherBufNr,
vid_buf[otherBufNr].sequence, vid_buf[otherBufNr].timestamp);
if (vid_buf[otherBufNr].flags & V4L2_BUF_FLAG_TOPFIELD) {
printf(" TOPFIELD");
}
if (vid_buf[otherBufNr].flags & V4L2_BUF_FLAG_BOTFIELD) {
printf(" BOTFIELD");
}
printf("\t\t");
printf("-: seq %u ts%f ms\n", vid_buf[otherBufNr].sequence - lastSeq,
(vid_buf[otherBufNr].timestamp - lastStamp)/1000000.0);
lastSeq = vid_buf[otherBufNr].sequence;
lastStamp = vid_buf[otherBufNr].timestamp;
} else {
printf("\n");
}
}
}
/* stream off */
if ( ioctl(fd, VIDIOC_STREAMOFF, &vid_buf[0].type) == -1 ) {
perror("VIDIOC_STREAMOFF 0");
close(fd);
exit(1);
}
/* unmap memory */
for (bufNr = 0; bufNr < BUF_COUNT; bufNr++) {
if ( munmap(map[bufNr], vid_buf[bufNr].length) == -1 ) {
perror("unable to unmap memory");
close(fd);
exit(1);
}
}
#undef BUF_COUNT
}
/* close device */
if ( close(fd) == -1 ) {
perror("unable to close video device");
exit(1);
}
return 0;
}
/* ---------------------------- statics ---------------------------- */
static void print_fmtpix(struct v4l2_format* fp)
{
printf(" type: %d\n", fp->type);
printf(" flags: 0x%X\n", fp->fmt.pix.flags);
printf(" width: %d\n", fp->fmt.pix.width);
printf(" height: %d\n", fp->fmt.pix.height);
printf(" depth: %d\n", fp->fmt.pix.depth);
printf(" pixelformat: 0x%X\n", fp->fmt.pix.pixelformat);
printf(" sizeimage: %d\n", fp->fmt.pix.sizeimage);
printf(" INTERLACED: %s\n", (fp->fmt.pix.flags & V4L2_FMT_FLAG_INTERLACED)? "true": "false");
printf(" TOPFIELD: %s\n", (fp->fmt.pix.flags & V4L2_FMT_FLAG_TOPFIELD)? "true": "false");
printf(" BOTFIELD: %s\n", (fp->fmt.pix.flags & V4L2_FMT_FLAG_BOTFIELD)? "true": "false");
}