ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Video-Capture-V4l/examples/capture
Revision: 1.1
Committed: Fri May 5 20:21:53 2000 UTC (24 years, 2 months ago) by pcg
Branch: MAIN
CVS Tags: rel-0_9, rel-0_902, HEAD
Log Message:
Initial check-in

File Contents

# Content
1 #!/usr/bin/perl
2
3 #
4 # capture a steady stream of video frames, compress it and split it into
5 # multiple files, for long recording sessions
6 #
7 # configure it below
8 #
9
10 use Socket;
11 use Fcntl;
12
13 use Video::Capture::V4l;
14 use Video::RTjpeg;
15 use Time::HiRes 'time';
16
17 use File::Sync 'sync';
18
19 use IPC::SysV;
20 use POSIX qw(nice WNOHANG);
21 use IO::Select;
22
23 BEGIN { require "linux-dsp-ioctl.ph" }
24
25 $|=1;
26
27 my $outprefix = "/tmp/vstream";
28
29 my $initial_fadein = 40; # initial settle time
30 my $consec = 25; # push this many frames to each encoder
31 my $syncfreq = 0.2; # pause this time between syncs
32 my $vencoders = 8; # number of encoder processes
33 my(@venc,@enc);
34
35 #my ($w, $h, $vformat) = (704, 528, PALETTE_YUV420P);
36
37 my ($cw, $ch, $vformat) = (576, 432, PALETTE_YUV420P);
38 my ($cl, $cr, $ct, $cb) = (16,16, 16,16);
39
40 #my ($cw, $ch, $vformat) = (320, 240, PALETTE_YUV420P);
41 #my ($cl, $cr, $ct, $cb) = (0,0, 0,0);
42
43 my $fps = 25;
44 my $spf = 1/$fps;
45
46 my ($x, $y, $w, $h) = ($cl, $ct, $cw-$cr-$cl, $ch-$cb-$ct);
47
48 my ($rate, $channels, $aformat) = (44100, 2, &AFMT_S16_LE);
49 my ($Q, $M) = (255, 0);
50 my $fsize = $cw*$ch*2;
51
52 my $buffers = int(32*1024*1024/$fsize);
53 my $bufsize = $fsize * $buffers;
54
55 my $shm = shmget IPC_PRIVATE, $bufsize, IPC_CREAT|0600;
56 $shm or die "unable to allocate $bufsize shm segment";
57 END { shmctl $shm, IPC_RMID, 0 }
58 $SIG{INT} = sub { exit };
59
60 my @buffers = (0..($buffers-1));
61
62 my $select = IO::Select->new();
63 my %cb;
64
65 # audio setup
66
67 sysopen DSP, "/dev/dsp", O_RDONLY
68 or sysopen DSP, "/dev/dsp", O_RDONLY
69 or die "unable to open /dev/dsp for reading: $!";
70
71 ioctl DSP, SNDCTL_DSP_SETFRAGMENT, pack "i", 0x7fff000e or die "SNDCTL_DSP_SETFRAGMENT: $!";
72 ioctl DSP, SNDCTL_DSP_SETFMT, pack "i", $aformat or die "SNDCTL_DSP_SETFMT: $!";
73 ioctl DSP, SNDCTL_DSP_CHANNELS, pack "i", $channels or die "SNDCTL_DSP_CHANNELS: $!";
74 ioctl DSP, SNDCTL_DSP_SPEED, pack "i", $rate or die "SNDCTL_DSP_SPEED: $!";
75
76 open AUDIO, ">$outprefix.a" or die;
77
78 # video setup
79
80 $grab = new Video::Capture::V4l
81 or die "Unable to open Videodevice: $!";
82
83 my $channel = $grab->channel (0);
84 my $tuner = $grab->tuner (0);
85 $tuner->mode(MODE_PAL);
86 $channel->norm(MODE_PAL);
87 $tuner->mode(8);
88 $tuner->set;
89 $channel->set;
90
91 #$CHANNEL69 = 855250;
92 #print $grab->freq ($CHANNEL69),"\n";
93
94 sub new_vencoder {
95 my $number = @enc;
96 my $encp = do { local *ENCODER_WRITER };
97 my $encc = do { local *ENCODER_READER };
98 socketpair $encc, $encp, AF_UNIX, SOCK_STREAM, PF_UNSPEC;
99 $select->add($encp);
100 $cb[fileno $encp] = sub {
101 my $buf;
102 4 == sysread $encp, $buf, 4 or die "unable to read bufferid";
103 $buf = unpack "N", $buf;
104 push @buffers, $buf;
105 };
106 if (0 == fork) {
107 open DATA, ">$outprefix.v$number" or die "$!";
108
109 my $tables = Video::RTjpeg::init_compress($cw,$ch,$Q);
110 Video::RTjpeg::init_mcompress();
111
112 syswrite DATA, pack "N", length($tables);
113 syswrite DATA, $tables;
114
115 my $buf;
116 my $count = $number * 313;
117 for(;;) {
118 8 == read $encc, $buf, 8 or die "incomplete frame time read: $!";
119 my ($buffer, $time) = unpack "NN", $buf;
120 last if $buffer >= $buffers;
121 shmread $shm, $buf, $buffer*$fsize, $fsize;
122 syswrite $encc, (pack "N", $buffer);
123 my $fr = Video::RTjpeg::mcompress($buf,$M,$M>>1, $x, $y, $w, $h);
124 #my $fr = Video::RTjpeg::compress($buf);
125 syswrite DATA, pack "NN", $time, length $fr;
126 syswrite DATA, $fr;
127
128 #Video::RTjpeg::fdatasync fileno DATA if ($count++ & 63) == 0;
129 print "+";
130 }
131 print "X";
132 exit;
133 }
134 push @enc, $encp;
135 }
136
137 new_vencoder for 1..$vencoders;
138
139 @venc = map (($_)x$consec, @enc);
140
141 my $frame = 0;
142 my $frames = 0;
143 my $dropped = 0;
144
145 sub put_vframe {
146 my $buffer = pop @buffers;
147 my $enc = pop @venc;
148 unshift @venc, $enc;
149 if (defined $buffer) {
150 print "-";
151 shmwrite $shm, ${$_[1]}, $buffer*$fsize, $fsize;
152 syswrite $enc, (pack "NN", $buffer, $_[0]);
153 } else {
154 print "o";
155 $dropped++;
156 }
157 }
158
159 my $syncpid = fork;
160 if ($syncpid==0) {
161 for(;;) {
162 select undef, undef, undef, $syncfreq;
163 print "S";
164 sync;
165 }
166 Video::RTjpeg::_exit;
167 };
168
169 system "rtprio -p $$";
170
171 my $fr = \$grab->capture ($frame, $cw, $ch, $vformat);
172 for(1..$initial_fadein) {
173 my $nfr = \$grab->capture (1-$frame, $cw, $ch, $vformat);
174 $grab->sync($frame) or die "unable to sync";
175 $frame = 1-$frame;
176 $fr = $nfr;
177 }
178
179 my $start = time;
180 my $nframe;
181
182 $fr = \$grab->capture ($frame, $cw, $ch, $vformat);
183
184 my $audpid = fork;
185 if ($audpid==0) {
186 my $count = 0;
187 my $in = ""; vec($in, fileno DSP, 1) = 1;
188 fcntl DSP, F_SETFL, O_NONBLOCK;
189 ioctl DSP, SNDCTL_DSP_SETTRIGGER, pack "i", 0;
190 ioctl DSP, SNDCTL_DSP_SETTRIGGER, pack "i", PCM_ENABLE_INPUT;
191 for(;;) {
192 my $buf;
193 select my $xin = $in, undef, undef, $spf*2;
194 print ".";
195 if (0 < sysread DSP, $buf, 128*1024) {
196 #print length $buf;
197 syswrite AUDIO, $buf;
198 }
199 }
200 Video::RTjpeg::_exit;
201 };
202
203 my $do_capture = 1;
204 $select->add(*STDIN);
205 $cb[fileno STDIN] = sub {
206 $do_capture = 0;
207 };
208
209 while($do_capture) {
210 printf "\n%02d:%02d +%2d %2ds %dd > ",
211 int($nframe*$spf/60), int($nframe*$spf)%60,
212 scalar@buffers, $frames-$nframe, $dropped
213 if $frames % $fps == 0;
214
215 my $nfr = \$grab->capture (1-$frame, $cw, $ch, $vformat);
216 $grab->sync($frame) or die "unable to sync";
217
218 my $now = time;
219 $nframe = int (($now-$start) / $spf + 0.5);
220 $start = $now - $nframe * $spf;
221
222 put_vframe($nframe, $fr);
223
224 for ($select->can_read(0)) {
225 $cb[fileno $_]->();
226 }
227
228 $frame = 1-$frame;
229 $frames++;
230 $fr = $nfr;
231 }
232
233 open CTRL, ">$outprefix" or die;
234 print CTRL <<EOF;
235 \$outprefix = "$outprefix";
236
237 \$fps = $fps;
238 \$spf = $spf;
239
240 \$frames = $frames;
241 \$nframe = $nframe;
242 \$dropped = $dropped;
243 \$vencoders = $vencoders;
244 \$rate = $rate;
245 \$channels = $channels;
246 \$aformat = $aformat;
247 \$w = $w;
248 \$h = $h;
249
250 \$buffers = $buffers;
251 \$fsize = $fsize;
252
253 1;
254 EOF
255 close CTRL;
256
257 $select->remove(*STDIN);
258
259 close DSP;
260 close AUDIO;
261 kill 'TERM', $syncpid;
262 kill 'TERM', $audpid;
263
264 for (@enc) {
265 syswrite $_, (pack "NN", -1, -1);
266 $select->remove($_);
267 }
268
269 for(;;) {
270 for ($select->can_read(0)) {
271 $cb[fileno $_]->();
272 }
273 }
274