diff options
author | Oliver Endriss <o.endriss@gmx.de> | 2009-04-10 09:20:00 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-06-16 17:21:02 -0400 |
commit | fd46d16d602ab7fd53cef7ff55b9dcb0b47ad3bf (patch) | |
tree | 26bf9c0d2aa0130decae58943cdc6eea3feaf52a /drivers/media/dvb/ttpci/av7110_av.c | |
parent | b7fd6067143181becb5b14765f4ad25857846491 (diff) |
V4L/DVB (11759): dvb-ttpci: Add TS replay capability
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>
Diffstat (limited to 'drivers/media/dvb/ttpci/av7110_av.c')
-rw-r--r-- | drivers/media/dvb/ttpci/av7110_av.c | 95 |
1 files changed, 78 insertions, 17 deletions
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index e4d0900d5121..2fc90e9a8b77 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c | |||
@@ -89,6 +89,7 @@ | |||
89 | 89 | ||
90 | static void p_to_t(u8 const *buf, long int length, u16 pid, | 90 | static void p_to_t(u8 const *buf, long int length, u16 pid, |
91 | u8 *counter, struct dvb_demux_feed *feed); | 91 | u8 *counter, struct dvb_demux_feed *feed); |
92 | static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len); | ||
92 | 93 | ||
93 | 94 | ||
94 | int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len) | 95 | 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) | |||
437 | aux_ring_buffer_write(&av7110->aout, buf, count); | 438 | aux_ring_buffer_write(&av7110->aout, buf, count); |
438 | } | 439 | } |
439 | 440 | ||
441 | |||
442 | #define FREE_COND_TS (dvb_ringbuffer_free(rb) >= 4096) | ||
443 | |||
444 | static ssize_t ts_play(struct av7110 *av7110, const char __user *buf, | ||
445 | unsigned long count, int nonblock, int type) | ||
446 | { | ||
447 | struct dvb_ringbuffer *rb; | ||
448 | u8 *kb; | ||
449 | unsigned long todo = count; | ||
450 | |||
451 | dprintk(2, "%s: type %d cnt %lu\n", __func__, type, count); | ||
452 | |||
453 | rb = (type) ? &av7110->avout : &av7110->aout; | ||
454 | kb = av7110->kbuf[type]; | ||
455 | |||
456 | if (!kb) | ||
457 | return -ENOBUFS; | ||
458 | |||
459 | if (nonblock && !FREE_COND_TS) | ||
460 | return -EWOULDBLOCK; | ||
461 | |||
462 | while (todo >= TS_SIZE) { | ||
463 | if (!FREE_COND_TS) { | ||
464 | if (nonblock) | ||
465 | return count - todo; | ||
466 | if (wait_event_interruptible(rb->queue, FREE_COND_TS)) | ||
467 | return count - todo; | ||
468 | } | ||
469 | if (copy_from_user(kb, buf, TS_SIZE)) | ||
470 | return -EFAULT; | ||
471 | write_ts_to_decoder(av7110, type, kb, TS_SIZE); | ||
472 | todo -= TS_SIZE; | ||
473 | buf += TS_SIZE; | ||
474 | } | ||
475 | |||
476 | return count - todo; | ||
477 | } | ||
478 | |||
479 | |||
440 | #define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \ | 480 | #define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \ |
441 | dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024) | 481 | dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024) |
442 | 482 | ||
@@ -780,11 +820,32 @@ static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter, | |||
780 | } | 820 | } |
781 | 821 | ||
782 | 822 | ||
823 | static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len) | ||
824 | { | ||
825 | struct ipack *ipack = &av7110->ipack[type]; | ||
826 | |||
827 | if (!(buf[3] & PAYLOAD)) | ||
828 | return -1; | ||
829 | |||
830 | if (buf[1] & PAY_START) | ||
831 | av7110_ipack_flush(ipack); | ||
832 | |||
833 | if (buf[3] & ADAPT_FIELD) { | ||
834 | len -= buf[4] + 1; | ||
835 | buf += buf[4] + 1; | ||
836 | if (!len) | ||
837 | return 0; | ||
838 | } | ||
839 | |||
840 | av7110_ipack_instant_repack(buf + 4, len - 4, ipack); | ||
841 | return 0; | ||
842 | } | ||
843 | |||
844 | |||
783 | int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len) | 845 | int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len) |
784 | { | 846 | { |
785 | struct dvb_demux *demux = feed->demux; | 847 | struct dvb_demux *demux = feed->demux; |
786 | struct av7110 *av7110 = (struct av7110 *) demux->priv; | 848 | struct av7110 *av7110 = (struct av7110 *) demux->priv; |
787 | struct ipack *ipack = &av7110->ipack[feed->pes_type]; | ||
788 | 849 | ||
789 | dprintk(2, "av7110:%p, \n", av7110); | 850 | dprintk(2, "av7110:%p, \n", av7110); |
790 | 851 | ||
@@ -804,20 +865,7 @@ int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t l | |||
804 | return -1; | 865 | return -1; |
805 | } | 866 | } |
806 | 867 | ||
807 | if (!(buf[3] & 0x10)) /* no payload? */ | 868 | return write_ts_to_decoder(av7110, feed->pes_type, buf, len); |
808 | return -1; | ||
809 | if (buf[1] & 0x40) | ||
810 | av7110_ipack_flush(ipack); | ||
811 | |||
812 | if (buf[3] & 0x20) { /* adaptation field? */ | ||
813 | len -= buf[4] + 1; | ||
814 | buf += buf[4] + 1; | ||
815 | if (!len) | ||
816 | return 0; | ||
817 | } | ||
818 | |||
819 | av7110_ipack_instant_repack(buf + 4, len - 4, &av7110->ipack[feed->pes_type]); | ||
820 | return 0; | ||
821 | } | 869 | } |
822 | 870 | ||
823 | 871 | ||
@@ -916,6 +964,7 @@ static ssize_t dvb_video_write(struct file *file, const char __user *buf, | |||
916 | { | 964 | { |
917 | struct dvb_device *dvbdev = file->private_data; | 965 | struct dvb_device *dvbdev = file->private_data; |
918 | struct av7110 *av7110 = dvbdev->priv; | 966 | struct av7110 *av7110 = dvbdev->priv; |
967 | unsigned char c; | ||
919 | 968 | ||
920 | dprintk(2, "av7110:%p, \n", av7110); | 969 | dprintk(2, "av7110:%p, \n", av7110); |
921 | 970 | ||
@@ -925,7 +974,12 @@ static ssize_t dvb_video_write(struct file *file, const char __user *buf, | |||
925 | if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY) | 974 | if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY) |
926 | return -EPERM; | 975 | return -EPERM; |
927 | 976 | ||
928 | return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1); | 977 | if (get_user(c, buf)) |
978 | return -EFAULT; | ||
979 | if (c == 0x47 && count % TS_SIZE == 0) | ||
980 | return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1); | ||
981 | else | ||
982 | return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1); | ||
929 | } | 983 | } |
930 | 984 | ||
931 | static unsigned int dvb_audio_poll(struct file *file, poll_table *wait) | 985 | 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, | |||
952 | { | 1006 | { |
953 | struct dvb_device *dvbdev = file->private_data; | 1007 | struct dvb_device *dvbdev = file->private_data; |
954 | struct av7110 *av7110 = dvbdev->priv; | 1008 | struct av7110 *av7110 = dvbdev->priv; |
1009 | unsigned char c; | ||
955 | 1010 | ||
956 | dprintk(2, "av7110:%p, \n", av7110); | 1011 | dprintk(2, "av7110:%p, \n", av7110); |
957 | 1012 | ||
@@ -959,7 +1014,13 @@ static ssize_t dvb_audio_write(struct file *file, const char __user *buf, | |||
959 | printk(KERN_ERR "not audio source memory\n"); | 1014 | printk(KERN_ERR "not audio source memory\n"); |
960 | return -EPERM; | 1015 | return -EPERM; |
961 | } | 1016 | } |
962 | return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0); | 1017 | |
1018 | if (get_user(c, buf)) | ||
1019 | return -EFAULT; | ||
1020 | if (c == 0x47 && count % TS_SIZE == 0) | ||
1021 | return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 0); | ||
1022 | else | ||
1023 | return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0); | ||
963 | } | 1024 | } |
964 | 1025 | ||
965 | static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 }; | 1026 | static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 }; |