| 1 |
pcg |
1.1 |
#!/usr/bin/perl |
| 2 |
|
|
|
| 3 |
|
|
# EPG (Electronic Program Guide Decoder) |
| 4 |
|
|
# Commercial Name: nexTView |
| 5 |
|
|
|
| 6 |
|
|
use Video::Capture::V4l; |
| 7 |
|
|
use Video::Capture::VBI; |
| 8 |
|
|
|
| 9 |
|
|
package Video::Capture::VBI::EPG; |
| 10 |
|
|
|
| 11 |
pcg |
1.2 |
use Video::Capture::VBI qw(:DEFAULT %VPS_CNI %VT_NI); |
| 12 |
pcg |
1.1 |
use Storable; |
| 13 |
|
|
|
| 14 |
|
|
use base 'Video::Capture::VBI::VT'; |
| 15 |
|
|
|
| 16 |
|
|
sub new { |
| 17 |
|
|
my $class = shift; |
| 18 |
|
|
my $self = $class->SUPER::new(@_); |
| 19 |
|
|
$self; |
| 20 |
|
|
} |
| 21 |
|
|
|
| 22 |
|
|
my $lastcni = -1; |
| 23 |
|
|
sub feed { |
| 24 |
|
|
my $self = shift; |
| 25 |
|
|
my @r; |
| 26 |
|
|
for ($self->SUPER::feed(@_)) { |
| 27 |
|
|
if ($_->[0] == VBI_VPS) { |
| 28 |
|
|
if ($_->[3] != $lastcni) { |
| 29 |
|
|
$lastcni = $_->[3]; |
| 30 |
|
|
printf "CNI %04x (%s)\n", $_->[3], $VPS_CNI{$_->[3] & 0xfff}; |
| 31 |
|
|
} |
| 32 |
|
|
} else { |
| 33 |
|
|
push @r, $_; |
| 34 |
|
|
} |
| 35 |
|
|
} |
| 36 |
|
|
@r; |
| 37 |
|
|
} |
| 38 |
|
|
|
| 39 |
|
|
sub mydump { |
| 40 |
|
|
local $_ = shift; |
| 41 |
|
|
if (ref $_ eq "HASH") { |
| 42 |
|
|
print "{ "; |
| 43 |
|
|
while(my($k,$v)=each %$_) { |
| 44 |
|
|
print ", $k => "; |
| 45 |
|
|
mydump($v); |
| 46 |
|
|
} |
| 47 |
|
|
print " }"; |
| 48 |
|
|
} elsif (ref $_ eq "ARRAY") { |
| 49 |
|
|
print "[ "; |
| 50 |
|
|
for (@$_) { |
| 51 |
|
|
print ", "; |
| 52 |
|
|
mydump($_); |
| 53 |
|
|
} |
| 54 |
|
|
print " ]"; |
| 55 |
|
|
} else { |
| 56 |
|
|
y/\x20-\x7e//cd; |
| 57 |
|
|
print $_; |
| 58 |
|
|
} |
| 59 |
|
|
} |
| 60 |
|
|
|
| 61 |
|
|
sub set_epg { |
| 62 |
|
|
my $self = shift; |
| 63 |
|
|
my $name = shift; |
| 64 |
|
|
my $new_db = main::gen_db_name ($name); |
| 65 |
|
|
print "SET_EPG $new_db <= ", $self->{db_name}, "\n"; |
| 66 |
|
|
if ($self->{db_name} and $new_db eq $self->{db_name}) { |
| 67 |
|
|
print "saving ",$new_db,"..."; |
| 68 |
|
|
Storable::nstore($self->db, "$new_db~"); |
| 69 |
|
|
rename "$new_db~", $new_db; |
| 70 |
|
|
print "ok\n"; |
| 71 |
|
|
} else { |
| 72 |
|
|
$self->{db_name} = $new_db; |
| 73 |
|
|
print "trying to load $new_db..."; |
| 74 |
|
|
$self->db(eval { $self->db(Storable::retrieve($new_db)) }); |
| 75 |
|
|
print "ok\n"; |
| 76 |
|
|
} |
| 77 |
|
|
} |
| 78 |
|
|
|
| 79 |
|
|
# just display the page |
| 80 |
|
|
sub enter_page { |
| 81 |
|
|
my($self,$page)=@_; |
| 82 |
|
|
|
| 83 |
|
|
$pages++; |
| 84 |
|
|
|
| 85 |
|
|
return unless $page->{page} == 0x1df; |
| 86 |
|
|
|
| 87 |
|
|
my $sub = $page->{ctrl}; |
| 88 |
|
|
my $stream = VTX_S3($sub); |
| 89 |
|
|
my $height = VTX_S4($sub)<<3 | VTX_S2($sub); |
| 90 |
|
|
my $seq = VTX_S1($sub); |
| 91 |
|
|
|
| 92 |
|
|
my $s = \%{$self->{stream}{$stream}}; |
| 93 |
|
|
|
| 94 |
|
|
delete $s->{raw} unless (($seq-1)&15) == $s->{seq}; |
| 95 |
|
|
$s->{seq}=$seq; |
| 96 |
|
|
push @{$s->{raw}}, @{$page->{packet}}[1..$height]; |
| 97 |
|
|
|
| 98 |
|
|
$packets[$stream]++; |
| 99 |
|
|
#print "stream $stream, height $height, seq $seq, ",scalar @{$s->{raw}},"<\n"; |
| 100 |
|
|
|
| 101 |
|
|
for(decode_stream $s->{raw}) { |
| 102 |
|
|
if (my ($dt, $bi) = decode_block $_, \@{$self->{bundle}}) { |
| 103 |
|
|
if ($dt == 1) { |
| 104 |
|
|
my $ai = $self->{db}{ai}; |
| 105 |
|
|
$self->set_epg($bi->{service_name}); |
| 106 |
|
|
if ($ai) { |
| 107 |
|
|
print "$ai->{epg_version}, $ai->{epg_version_swo}, $ai->{this_network_op}, $ai->{service_name}\n"; |
| 108 |
|
|
if ($bi->{epg_version} != $ai->{epg_version} |
| 109 |
|
|
|| $bi->{epg_version_swo} != $ai->{epg_version_swo} |
| 110 |
|
|
|| $bi->{this_network_op} != $ai->{this_network_op}) { |
| 111 |
|
|
print "CHANNEL SWITCH, WIPING DATABASE\n"; |
| 112 |
|
|
delete $self->{db}; |
| 113 |
|
|
} |
| 114 |
|
|
} |
| 115 |
|
|
$self->{db}{ai} = $bi; |
| 116 |
|
|
} elsif ($dt == 2) { |
| 117 |
|
|
$self->{db}{pi}{$bi->{netwop_no}}{$bi->{block_no}} = $bi; |
| 118 |
|
|
} elsif ($dt == 3) { |
| 119 |
|
|
$self->{db}{ni}{$bi->{block_no}} = $bi; |
| 120 |
|
|
} elsif ($dt == 4) { |
| 121 |
|
|
$self->{db}{oi}{$bi->{block_no}} = $bi; |
| 122 |
|
|
} elsif ($dt == 5) { |
| 123 |
|
|
$self->{db}{mi}{$bi->{block_no}} = $bi; |
| 124 |
|
|
} else { |
| 125 |
|
|
print "UNKNOWN BLOCK TYPE $dt found\n"; |
| 126 |
|
|
} |
| 127 |
|
|
} |
| 128 |
|
|
} |
| 129 |
|
|
$|=1; |
| 130 |
|
|
printf "%7d %6d %6d %5d %5d %5d %5d\r", $pages, $packets[0], $packets[1], |
| 131 |
|
|
1*%{$self->{db}{pi}}, |
| 132 |
|
|
1*%{$self->{db}{ni}}, |
| 133 |
|
|
1*%{$self->{db}{oi}}, |
| 134 |
|
|
1*%{$self->{db}{mi}}; |
| 135 |
|
|
|
| 136 |
|
|
#printf "received epg page %04x\n", $sub; |
| 137 |
|
|
} |
| 138 |
|
|
|
| 139 |
|
|
sub enter_packet { |
| 140 |
|
|
my $self = shift; |
| 141 |
|
|
my $p = shift; |
| 142 |
|
|
return unless $p->[3] <= 1 && $p->[2] == 30; |
| 143 |
|
|
#printf "packet(@$p %04x)", $p->[6]; |
| 144 |
|
|
print "\n"; |
| 145 |
|
|
} |
| 146 |
|
|
|
| 147 |
|
|
sub db { |
| 148 |
|
|
my $self = shift; |
| 149 |
|
|
$self->{db} = shift if @_; |
| 150 |
|
|
$self->{db}; |
| 151 |
|
|
} |
| 152 |
|
|
|
| 153 |
|
|
package main; |
| 154 |
|
|
|
| 155 |
|
|
$vbi = new Video::Capture::V4l::VBI or die; |
| 156 |
|
|
|
| 157 |
|
|
# the next line is optional (it enables buffering) |
| 158 |
|
|
$vbi->backlog(150); # max. 5 seconds backlog (~4.6Mb) |
| 159 |
|
|
|
| 160 |
|
|
$inp_fd = fileno STDIN; |
| 161 |
|
|
$vbi_fd = $vbi->fileno; |
| 162 |
|
|
|
| 163 |
|
|
$vt = new Video::Capture::VBI::EPG; |
| 164 |
|
|
|
| 165 |
|
|
sub gen_db_name { |
| 166 |
|
|
shift() . ".epg"; |
| 167 |
|
|
} |
| 168 |
|
|
|
| 169 |
|
|
print "Capturing VBI block. Make sure you have tuned in to a channel with EPG!\n"; |
| 170 |
|
|
print "Aquisition may take up to twenty minutes (and more)!\n"; |
| 171 |
|
|
|
| 172 |
|
|
for(;;) { |
| 173 |
|
|
my $r=""; |
| 174 |
|
|
vec($r,$inp_fd,1)=1; |
| 175 |
|
|
vec($r,$vbi_fd,1)=1; |
| 176 |
|
|
select $r,undef,undef,0.04; |
| 177 |
|
|
$vt->feed(decode_field $vbi->field, VBI_VT|VBI_VPS) while $vbi->queued; |
| 178 |
|
|
if (vec($r,$inp_fd,1)) { |
| 179 |
|
|
$_ = <STDIN>; |
| 180 |
|
|
if (/^q/i) { |
| 181 |
|
|
last; |
| 182 |
|
|
} |
| 183 |
|
|
} |
| 184 |
|
|
} |
| 185 |
|
|
|