V4L/DVB (11759): dvb-ttpci: Add TS replay capability
authorOliver Endriss <o.endriss@gmx.de>
Fri, 10 Apr 2009 13:20:00 +0000 (10:20 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 16 Jun 2009 21:21:02 +0000 (18:21 -0300)
Implemented TS replay capability.
audio/video devices are able to process PES and TS data now.

Signed-off-by: Oliver Endriss <o.endriss@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/dvb/ttpci/av7110_av.c

index e4d0900..2fc90e9 100644 (file)
@@ -89,6 +89,7 @@
 
 static void p_to_t(u8 const *buf, long int length, u16 pid,
                   u8 *counter, struct dvb_demux_feed *feed);
+static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len);
 
 
 int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len)
@@ -437,6 +438,45 @@ static void play_audio_cb(u8 *buf, int count, void *priv)
        aux_ring_buffer_write(&av7110->aout, buf, count);
 }
 
+
+#define FREE_COND_TS (dvb_ringbuffer_free(rb) >= 4096)
+
+static ssize_t ts_play(struct av7110 *av7110, const char __user *buf,
+                      unsigned long count, int nonblock, int type)
+{
+       struct dvb_ringbuffer *rb;
+       u8 *kb;
+       unsigned long todo = count;
+
+       dprintk(2, "%s: type %d cnt %lu\n", __func__, type, count);
+
+       rb = (type) ? &av7110->avout : &av7110->aout;
+       kb = av7110->kbuf[type];
+
+       if (!kb)
+               return -ENOBUFS;
+
+       if (nonblock && !FREE_COND_TS)
+               return -EWOULDBLOCK;
+
+       while (todo >= TS_SIZE) {
+               if (!FREE_COND_TS) {
+                       if (nonblock)
+                               return count - todo;
+                       if (wait_event_interruptible(rb->queue, FREE_COND_TS))
+                               return count - todo;
+               }
+               if (copy_from_user(kb, buf, TS_SIZE))
+                       return -EFAULT;
+               write_ts_to_decoder(av7110, type, kb, TS_SIZE);
+               todo -= TS_SIZE;
+               buf += TS_SIZE;
+       }
+
+       return count - todo;
+}
+
+
 #define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \
                   dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)
 
@@ -780,11 +820,32 @@ static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter,
 }
 
 
+static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len)
+{
+       struct ipack *ipack = &av7110->ipack[type];
+
+       if (!(buf[3] & PAYLOAD))
+               return -1;
+
+       if (buf[1] & PAY_START)
+               av7110_ipack_flush(ipack);
+
+       if (buf[3] & ADAPT_FIELD) {
+               len -= buf[4] + 1;
+               buf += buf[4] + 1;
+               if (!len)
+                       return 0;
+       }
+
+       av7110_ipack_instant_repack(buf + 4, len - 4, ipack);
+       return 0;
+}
+
+
 int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len)
 {
        struct dvb_demux *demux = feed->demux;
        struct av7110 *av7110 = (struct av7110 *) demux->priv;
-       struct ipack *ipack = &av7110->ipack[feed->pes_type];
 
        dprintk(2, "av7110:%p, \n", av7110);
 
@@ -804,20 +865,7 @@ int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t l
                return -1;
        }
 
-       if (!(buf[3] & 0x10)) /* no payload? */
-               return -1;
-       if (buf[1] & 0x40)
-               av7110_ipack_flush(ipack);
-
-       if (buf[3] & 0x20) {  /* adaptation field? */
-               len -= buf[4] + 1;
-               buf += buf[4] + 1;
-               if (!len)
-                       return 0;
-       }
-
-       av7110_ipack_instant_repack(buf + 4, len - 4, &av7110->ipack[feed->pes_type]);
-       return 0;
+       return write_ts_to_decoder(av7110, feed->pes_type, buf, len);
 }
 
 
@@ -916,6 +964,7 @@ static ssize_t dvb_video_write(struct file *file, const char __user *buf,
 {
        struct dvb_device *dvbdev = file->private_data;
        struct av7110 *av7110 = dvbdev->priv;
+       unsigned char c;
 
        dprintk(2, "av7110:%p, \n", av7110);
 
@@ -925,7 +974,12 @@ static ssize_t dvb_video_write(struct file *file, const char __user *buf,
        if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY)
                return -EPERM;
 
-       return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);
+       if (get_user(c, buf))
+               return -EFAULT;
+       if (c == 0x47 && count % TS_SIZE == 0)
+               return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);
+       else
+               return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);
 }
 
 static unsigned int dvb_audio_poll(struct file *file, poll_table *wait)
@@ -952,6 +1006,7 @@ static ssize_t dvb_audio_write(struct file *file, const char __user *buf,
 {
        struct dvb_device *dvbdev = file->private_data;
        struct av7110 *av7110 = dvbdev->priv;
+       unsigned char c;
 
        dprintk(2, "av7110:%p, \n", av7110);
 
@@ -959,7 +1014,13 @@ static ssize_t dvb_audio_write(struct file *file, const char __user *buf,
                printk(KERN_ERR "not audio source memory\n");
                return -EPERM;
        }
-       return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);
+
+       if (get_user(c, buf))
+               return -EFAULT;
+       if (c == 0x47 && count % TS_SIZE == 0)
+               return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);
+       else
+               return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);
 }
 
 static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 };