Improve decode_tm6000 for better usage of mmap method
authorMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 14 Sep 2009 13:08:44 +0000 (10:08 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 14 Sep 2009 13:08:44 +0000 (10:08 -0300)
From: Mauro Carvalho Chehab <mchehab@redhat.com>

Now, mmap method is the default, when reading from tm6000 V4L2 device.

Also, now, it is possible to specify the channel frequency via command
line, and the number of video buffers to be used.

Priority: normal

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
contrib/libv4l2util/v4l2_driver.c
utils/decode_tm6000.c

index 94f8269..919119b 100644 (file)
@@ -646,6 +646,9 @@ int v4l2_mmap_bufs(struct v4l2_driver *drv, unsigned int num_buffers)
        return 0;
 }
 
+/* Returns <0, if error, 0 if nothing to read and <size>, if something
+   read
+ */
 int v4l2_rcvbuf(struct v4l2_driver *drv, v4l2_recebe_buffer *rec_buf)
 {
        int ret;
@@ -668,7 +671,7 @@ int v4l2_rcvbuf(struct v4l2_driver *drv, v4l2_recebe_buffer *rec_buf)
 
                default:
                        perror ("dqbuf");
-                       return errno;
+                       return -errno;
                }
        }
        prt_buf_info("DQBUF",&buf);
@@ -677,19 +680,18 @@ int v4l2_rcvbuf(struct v4l2_driver *drv, v4l2_recebe_buffer *rec_buf)
 
        ret = rec_buf (&buf,&drv->bufs[buf.index]);
 
-       if (ret) {
+       if (ret<0) {
                v4l2_free_bufs(drv);
                return ret;
        }
 
        if (-1 == xioctl (drv->fd, VIDIOC_QBUF, &buf)) {
                perror ("qbuf");
-               return errno;
+               return -errno;
        }
-       return 0;
+       return ret;
 }
 
-
 int v4l2_start_streaming(struct v4l2_driver *drv)
 {
        uint32_t        i;
index 77920a5..d622360 100644 (file)
 #include <string.h>
 #include <argp.h>
 #include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
 
 const char *argp_program_version="decode_tm6000 version 0.0.1";
 const char *argp_program_bug_address="Mauro Carvalho Chehab <mchehab@infradead.org>";
@@ -30,12 +34,16 @@ const struct argp_option options[] = {
        {"device",      'd',    "DEV",  0,      "uses device for reading", 0},
        {"output",      'o',    "FILE", 0,      "outputs raw stream to a file", 0},
        {"input",       'i',    "FILE", 0,      "parses a file, instead of a device", 0},
+       {"freq",        'f',    "Freq", 0,      "station frequency, in MHz (default is 193.25)", 0},
+       {"nbufs",       'n',    "quant",0,      "number of video buffers", 0},
        {"audio",       'a',    0,      0,      "outputs audio on stdout", 0},
        {"read",        'r',    0,      0,      "use read() instead of mmap method", 0},
        { 0, 0, 0, 0, 0, 0 }
 };
 
-static int debug=0, audio=0, use_mmap=1;
+static char outbuf[692224];
+static int debug=0, audio=0, use_mmap=1, nbufs=4;
+static float freq_mhz=193.25;
 static char *devname="/dev/video0";
 static char *filename=NULL;
 static enum {
@@ -76,6 +84,14 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
 
                filename=arg;
                break;
+       case 'f':
+               freq_mhz=atof(arg);
+               break;
+       case 'n':
+               nbufs=atoi(arg);
+               if  (nbufs<2)
+                       nbufs=2;
+               break;
        default:
                return ARGP_ERR_UNKNOWN;
        }
@@ -114,105 +130,150 @@ const char *tm6000_msg_type[]= {
 
 int recebe_buffer (struct v4l2_buffer *v4l2_buf, struct v4l2_t_buf *buf)
 {
-       fwrite (buf->start,buf->length,1,fout);
-       return 0;
+       dprintf("Received %d bytes\n",buf->length);
+fflush(stdout);
+       memcpy (outbuf,buf->start,buf->length);
+       return buf->length;
 }
 
 
-int read_mmap(struct v4l2_driver *drv)
+int prepare_read (struct v4l2_driver *drv)
 {
+       struct v4l2_format fmt;
        double freq;
+       int rc;
+
+       memset (drv,0,sizeof(*drv));
+
+       if (v4l2_open (devname, 1,drv)<0) {
+               perror ("Error opening dev");
+               return -1;
+       }
 
-       freq=193.25 * 1000 * 1000;
-       v4l2_getset_freq (drv,V4L2_SET, &freq);
+       memset (&fmt,0,sizeof(fmt));
 
-       printf("Preparing for frames...\n");
-       fflush (stdout);
-       sleep(1);
+       uint32_t pixelformat=V4L2_PIX_FMT_TM6000;
 
-       v4l2_mmap_bufs(drv, 2);
+       if (v4l2_gettryset_fmt_cap (drv,V4L2_SET,&fmt, 720, 480,
+                                   pixelformat,V4L2_FIELD_ANY)) {
+               perror("set_input to tm6000 raw format");
+               return -1;
+       }
+
+       if (freq_mhz) {
+               freq=freq_mhz * 1000 * 1000;
+               rc=v4l2_getset_freq (drv,V4L2_SET, &freq);
+               if (rc<0)
+                       printf ("Cannot set freq to %.3f MHz\n",freq_mhz);
+       }
 
-       v4l2_start_streaming(drv);
+       if (use_mmap) {
+               printf("Preparing for receiving frames on %d buffers...\n",nbufs);
+               fflush (stdout);
 
+               rc=v4l2_mmap_bufs(drv, nbufs);
+               if (rc<0) {
+                       printf ("Cannot mmap %d buffers\n",nbufs);
+                       return -1;
+               }
+
+//             v4l2_stop_streaming(&drv);
+               rc=v4l2_start_streaming(drv);
+               if (rc<0) {
+                       printf ("Cannot start streaming\n");
+                       return -1;
+               }
+       }
        printf("Waiting for frames...\n");
-       while (1) {
+
+       return 0;
+}
+
+int read_stream (struct v4l2_driver *drv, int fd)
+{
+       if (use_mmap) {
                fd_set fds;
                struct timeval tv;
                int r;
 
                FD_ZERO (&fds);
-               FD_SET (drv->fd, &fds);
+               FD_SET (fd, &fds);
 
                /* Timeout. */
                tv.tv_sec = 2;
                tv.tv_usec = 0;
 
-               r = select (drv->fd + 1, &fds, NULL, NULL, &tv);
+               r = select (fd + 1, &fds, NULL, NULL, &tv);
                if (-1 == r) {
-                       if (EINTR == errno)
-
-                       perror ("select");
-                       return errno;
+                       if (EINTR == errno) {
+                               perror ("select");
+                               return -errno;
+                       }
                }
 
                if (0 == r) {
                        fprintf (stderr, "select timeout\n");
-                       return errno;
+                       return -errno;
                }
 
-               if (v4l2_rcvbuf(drv, recebe_buffer))
-                       break;
+               return v4l2_rcvbuf(drv, recebe_buffer);
+       } else {
+               int size=read(fd, outbuf, sizeof(outbuf));
+               return size;
        }
+
        return 0;
 }
 
+int read_char (struct v4l2_driver *drv, int fd)
+{
+       static int sizebuf=0;
+       static unsigned char *p=NULL;
+       unsigned char c;
+
+       if (sizebuf<=0) {
+               sizebuf=read_stream(drv,fd);
+               if (sizebuf<=0)
+                       return -1;
+               p=(unsigned char *)outbuf;
+       }
+       c=*p;
+       p++;
+       sizebuf--;
+
+       return c;
+}
+
 
 int main (int argc, char*argv[])
 {
-       FILE *fp;
-       unsigned char c, buf[TM6000_URB_MSG_LEN], img[720*2*480];
+       int fd;
+       unsigned int i;
+       unsigned char buf[TM6000_URB_MSG_LEN], img[720*2*480];
        unsigned int  cmd, cpysize, pktsize, size, field, block, line, pos=0;
        unsigned long header=0;
        int           linesize=720*2,skip=0;
-       struct v4l2_format fmt;
        struct v4l2_driver drv;
 
        argp_parse (&argp, argc, argv, 0, 0, 0);
 
        if (mode!=INPUT) {
-               if (v4l2_open (devname, 1,&drv)<0) {
-                       perror ("Error opening dev");
-                       return -1;
-               }
-               fp=fdopen(drv.fd,"r");
-               if (!fp) {
-                       perror("error associating dev");
-                       return -1;
-               }
-
-               memset (&fmt,0,sizeof(fmt));
-
-               uint32_t pixelformat=V4L2_PIX_FMT_TM6000;
-
-               if (v4l2_gettryset_fmt_cap (&drv,V4L2_SET,&fmt, 720, 480,
-                                               pixelformat,V4L2_FIELD_ANY)) {
-                       perror("set_input to tm6000 raw format");
+               if (prepare_read (&drv)<0)
                        return -1;
-               }
-       }
+               fd=drv.fd;
+       } else {
+               /*mode == INPUT */
 
-       if (mode==INPUT) {
-               fp=fopen(filename,"r");
-               if (!fp) {
+               fd=open(filename,O_RDONLY);
+               if (fd<0) {
                        perror ("error opening a file for parsing");
                        return -1;
                }
                dprintf("file %s opened for parsing\n",filename);
+               use_mmap=0;
        }
 
        if (mode==OUTPUT) {
-               char outbuf[2<<18];
-
                fout=fopen(filename,"w");
                if (!fout) {
                        perror ("error opening a file to write");
@@ -220,15 +281,12 @@ int main (int argc, char*argv[])
                }
                dprintf("file %s opened for output\n",filename);
 
-               if (use_mmap) {
-                       return (read_mmap(&drv));
-               }
-
                do {
-                       size=fread(outbuf,1, sizeof(outbuf), fp);
-                       if (!size) {
-                               fclose (fp);
-                               return 0;
+                       size=read_stream (&drv,fd);
+
+                       if (size<=0) {
+                               close (fd);
+                               return -1;
                        }
                        dprintf("writing %d bytes\n",size);
                        fwrite(outbuf,1, size,fout);
@@ -236,11 +294,18 @@ int main (int argc, char*argv[])
                } while (1);
        }
 
+
        while (1) {
                skip=0;
                header=0;
                do {
-                       c=fgetc(fp);
+                       int c;
+                       c=read_char (&drv,fd);
+                       if (c<0) {
+                               perror("read");
+                               return -1;
+                       }
+
                        header=(header>>8)&0xffffff;
                        header=header|(c<<24);
                        skip++;
@@ -254,7 +319,15 @@ int main (int argc, char*argv[])
                cmd   = (header>>21) & 0x7;
 
                /* Read the remaining buffer */
-               fread((char *)buf,sizeof(buf), 1, fp);
+               for (i=0;i<sizeof(buf);i++) {
+                       int c;
+                       c=read_char (&drv,fd);
+                       if (c<0) {
+                               perror("read");
+                               return -1;
+                       }
+                       buf[i]=c;
+               }
 
                /* FIXME: Mounts the image as field0+field1
                        * It should, instead, check if the user selected
@@ -264,10 +337,10 @@ int main (int argc, char*argv[])
                                        block*TM6000_URB_MSG_LEN;
 
                        /* Prints debug info */
-               dprintf("0x%08x (skip %d), %s size=%d, num=%d,line=%d, field=%d\n",
+               dprintf("0x%08x (skip %d), %s size=%d, line=%d, field=%d, block=%d\n",
                                (unsigned int)header, skip,
                                 tm6000_msg_type[cmd],
-                                size, block, line, field);
+                                size, line, field, block);
 
                /* Don't allow to write out of the buffer */
                if (pos+sizeof(buf) > sizeof(img))
@@ -286,6 +359,6 @@ int main (int argc, char*argv[])
                break;
                }
        }
-       fclose(fp);
+       close(fd);
        return 0;
 }