Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  *   (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org>
  3  *
  4  */
  5 #include "config.h"
  6 
  7 #include <stdio.h>
  8 #include <stdlib.h>
  9 #include <unistd.h>
 10 #include <math.h>
 11 #include <errno.h>
 12 #include <fcntl.h>
 13 #include <string.h>
 14 #include <ctype.h>
 15 #include <signal.h>
 16 #include <pthread.h>
 17 #include <sys/types.h>
 18 #include <sys/socket.h>
 19 #include <sys/time.h>
 20 #include <sys/ioctl.h>
 21 #include <sys/stat.h>
 22 #include <sys/mman.h>
 23 #include <sys/shm.h>
 24 #include <sys/ipc.h>
 25 #include <sys/wait.h>
 26 
 27 #include "grab-ng.h"
 28 #include "writefile.h"
 29 #include "channel.h"
 30 #include "sound.h"
 31 #include "capture.h"
 32 #include "commands.h"
 33 
 34 /* ---------------------------------------------------------------------- */
 35 
 36 static int       bufcount = 16;
 37 static int       parallel = 1;
 38 static char*     tvnorm = NULL;
 39 static char*     input  = NULL;
 40 static char*     moviename = NULL;
 41 static char*     audioname = NULL;
 42 static char*     vfmt_name;
 43 static char*     afmt_name;
 44 
 45 static const struct ng_writer     *writer;
 46 static const void                 *video_priv;
 47 static const void                 *audio_priv;
 48 static struct ng_video_fmt        video = {
 49     width: 320,
 50     height: 240,
 51 };
 52 static struct ng_audio_fmt        audio = {
 53     rate: 44100,
 54 };
 55 static void *movie_state;
 56 
 57 static int  absframes = 1;
 58 static int  quiet = 0, fps = 10000;
 59 
 60 static int  signaled = 0, wait_seconds = 0;
 61 
 62 int debug = 0, have_dga = 0;
 63 
 64 /* ---------------------------------------------------------------------- */
 65 
 66 static void
 67 list_formats(FILE *out)
 68 {
 69     struct list_head *item;
 70     const struct ng_writer *wr;
 71     int j;
 72     
 73     fprintf(out,"\nmovie writers:\n");
 74     list_for_each(item,&ng_writers) {
 75         wr = list_entry(item, struct ng_writer, list);
 76         fprintf(out,"  %s - %s\n",wr->name,
 77                 wr->desc ? wr->desc : "-");
 78         if (NULL != wr->video) {
 79             fprintf(out,"    video formats:\n");
 80             for (j = 0; NULL != wr->video[j].name; j++) {
 81                 fprintf(out,"      %-7s %-28s [%s]\n",wr->video[j].name,
 82                         wr->video[j].desc ? wr->video[j].desc :
 83                         ng_vfmt_to_desc[wr->video[j].fmtid],
 84                         wr->video[j].ext);
 85             }
 86         }
 87         if (NULL != wr->audio) {
 88             fprintf(out,"    audio formats:\n");
 89             for (j = 0; NULL != wr->audio[j].name; j++) {
 90                 fprintf(out,"      %-7s %-28s [%s]\n",wr->audio[j].name,
 91                         wr->audio[j].desc ? wr->audio[j].desc :
 92                         ng_afmt_to_desc[wr->audio[j].fmtid],
 93                         wr->audio[j].ext ? wr->audio[j].ext : "-");
 94             }
 95         }
 96         fprintf(out,"\n");
 97     }
 98 }
 99 
100 static void
101 usage(FILE *out)
102 {
103     fprintf(out,
104             "streamer grabs image(s), records movies and sound\n"
105             "\n"
106             "usage: streamer [ options ]\n"
107             "\n"
108             "general options:\n"
109             "  -h          print this help text\n"
110             "  -q          quiet operation\n"
111             "  -d          enable debug output\n"
112             "  -p n        use n compression threads    [%d]\n"
113             "  -w seconds  wait before grabbing         [%d]\n"
114             "\n"
115             "video options:\n"
116             "  -o file     video/movie file name\n"
117             "  -f format   specify video format\n"
118             "  -c device   specify video4linux device   [%s]\n"
119             "  -r fps      frame rate                   [%d.%03d]\n"
120             "  -s size     specify size                 [%dx%d]\n"
121             "\n"
122             "  -t times    number of frames or hh:mm:ss [%d]\n"
123             "  -b buffers  specify # of buffers         [%d]\n"
124             "  -j quality  quality for mjpeg or jpeg    [%d]\n"
125             "  -n tvnorm   set pal/ntsc/secam\n"
126             "  -i input    set video source\n"
127             "  -a          don't unmute/mute v4l device.\n"
128             "\n"
129             "audio options:\n"
130             "  -O file     wav file name\n"
131             "  -F format   specify audio format\n"
132             "  -C device   specify dsp device           [%s]\n"
133             "  -R rate     sample rate                  [%d]\n"
134             "\n",
135             
136             parallel,wait_seconds,
137             ng_dev.video, fps/1000, fps%1000,
138             video.width, video.height,
139             absframes, bufcount, ng_jpeg_quality,
140             ng_dev.dsp, audio.rate
141         );
142 
143     list_formats(out);
144     fprintf(out,
145             "If you want to capture to multiple image files you should include some\n"
146             "digits into the movie filename (foo0000.jpeg for example), streamer will\n"
147             "use the digit block to enumerate the image files.\n"
148             "\n"
149             "For file formats which can hold *both* audio and video (like AVI and\n"
150             "QuickTime) the -O option has no effect.\n"
151             "\n"
152             "streamer will use the file extention of the output file name to figure\n"
153             "which format to use.  You need the -f/-F options only if the extention\n"
154             "allows more than one format.\n"
155             "\n"
156             "Examples:\n"
157             "  capture a single frame:\n"
158             "    streamer -o foobar.ppm\n"
159             "\n"
160             "  capture ten frames, two per second:\n"
161             "    streamer -t 10 -r 2 -o foobar00.jpeg\n"
162             "\n"
163             "  record 30 seconds stereo sound:\n"
164             "    streamer -t 0:30 -O soundtrack.wav -F stereo\n"
165             "\n"
166             "  record a quicktime movie with sound:\n"
167             "    streamer -t 0:30 -o movie.mov -f jpeg -F mono16\n"
168             "\n"
169             "  build mpeg movies using mjpegtools + compressed avi file:\n"
170             "    streamer -t 0:30 -s 352x240 -r 24 -o movie.avi -f mjpeg -F stereo\n"
171             "    lav2wav +p movie.avi | mp2enc -o audio.mp2\n"
172             "    lav2yuv +p movie.avi | mpeg2enc -o video.m1v\n"
173             "    mplex audio.mp2 video.m1v -o movie.mpg\n"
174             "\n"
175             "  build mpeg movies using mjpegtools + raw, uncompressed video:\n"
176             "    streamer -t 0:30 -s 352x240 -r 24 -o video.yuv -O audio.wav -F stereo\n"
177             "    mp2enc -o audio.mp2 < audio.wav\n"
178             "    mpeg2enc -o video.m1v < video.yuv\n"
179             "    mplex audio.mp2 video.m1v -o movie.mpg\n"
180             "\n"
181             "-- \n"
182             "(c) 1998-2001 Gerd Knorr <kraxel@bytesex.org>\n");
183 }
184 
185 /* ---------------------------------------------------------------------- */
186 
187 static void
188 find_formats(void)
189 {
190     struct list_head *item;
191     const struct ng_writer *wr = NULL;
192     char *mext = NULL;
193     char *aext = NULL;
194     int v=-1,a=-1;
195 
196     if (moviename) {
197         mext = strrchr(moviename,'.');
198         if (mext)
199             mext++;
200     }
201     if (audioname) {
202         aext = strrchr(audioname,'.');
203         if (aext)
204             aext++;
205     }
206     list_for_each(item,&ng_writers) {
207         wr = list_entry(item, struct ng_writer, list);
208         if (debug)
209             fprintf(stderr,"checking writer %s [%s] ...\n",wr->name,wr->desc);
210         if ((/*!wr->combined && */mext) || NULL != vfmt_name) {
211             if (NULL == wr->video) {
212                 if (debug)
213                     fprintf(stderr,"  no video, skipping\n");
214                 continue;
215             }
216             for (v = 0; NULL != wr->video[v].name; v++) {
217                 if (debug)
218                     fprintf(stderr,"  video name=%s ext=%s: ",
219                             wr->video[v].name,wr->video[v].ext);
220                 if (mext && 0 != strcasecmp(wr->video[v].ext,mext)) {
221                     if (debug)
222                         fprintf(stderr,"ext mismatch [need %s]\n",mext);
223                     continue;
224                 }
225                 if (vfmt_name && 0 != strcasecmp(wr->video[v].name,vfmt_name)) {
226                     if (debug)
227                         fprintf(stderr,"name mismatch [need %s]\n",vfmt_name);
228                     continue;
229                 }
230                 if (debug)
231                     fprintf(stderr,"OK\n");
232                 break;
233             }
234             if (NULL == wr->video[v].name)
235                 continue;
236         }
237         if ((!wr->combined && aext) || NULL != afmt_name) {
238             if (NULL == wr->audio) {
239                 if (debug)
240                     fprintf(stderr,"  no audio, skipping\n");
241                 continue;
242             }
243             for (a = 0; NULL != wr->audio[a].name; a++) {
244                 if (debug)
245                     fprintf(stderr,"  audio name=%s ext=%s: ",
246                             wr->audio[a].name,wr->audio[a].ext);
247                 if (!wr->combined &&
248                     aext && 0 != strcasecmp(wr->audio[a].ext,aext)) {
249                     if (debug)
250                         fprintf(stderr,"ext mismatch [need %s]\n",aext);
251                     continue;
252                 }
253                 if (wr->combined &&
254                     mext && 0 != strcasecmp(wr->audio[a].ext,mext)) {
255                     if (debug)
256                         fprintf(stderr,"ext mismatch [need %s]\n",mext);
257                     continue;
258                 }
259                 if (afmt_name && 0 != strcasecmp(wr->audio[a].name,afmt_name)) {
260                     if (debug)
261                         fprintf(stderr,"name mismatch [need %s]\n",afmt_name);
262                     continue;
263                 }
264                 if (debug)
265                     fprintf(stderr,"OK\n");
266                 break;
267             }
268             if (NULL == wr->audio[a].name)
269                 continue;
270         }
271         break;
272     }
273     if (item != &ng_writers) {
274         writer = wr;
275         if (-1 != v) {
276             video.fmtid = wr->video[v].fmtid;
277             video_priv  = wr->video[v].priv;
278         }
279         if (-1 != a) {
280             audio.fmtid = wr->audio[a].fmtid;
281             audio_priv  = wr->audio[a].priv;
282         }
283     } else {
284         if (debug)
285             fprintf(stderr,"no match found\n");
286     }
287 }
288 
289 static int
290 parse_time(char *time)
291 {
292     int hours, minutes, seconds, total=0;
293 
294     if (3 == sscanf(time,"%d:%d:%d",&hours,&minutes,&seconds))
295         total = hours * 60*60 + minutes * 60 + seconds;
296     else if (2 == sscanf(time,"%d:%d",&minutes,&seconds))
297         total = minutes * 60 + seconds;
298 
299     if (0 != total) {
300         /* hh:mm:ss => framecount */
301         return total * fps / 1000;
302     }
303 
304     return atoi(time);
305 }
306 
307 
308 /* ---------------------------------------------------------------------- */
309 
310 static void
311 do_rec_status(char *message)
312 {
313     if (!quiet)
314         fprintf(stderr,"%s  \r",message);
315 }
316 
317 static void
318 ctrlc(int signal)
319 {
320     static char text[] = "^C - one moment please\n";
321     if (!quiet)
322         write(2,text,strlen(text));
323     signaled=1;
324 }
325 
326 int
327 main(int argc, char **argv)
328 {
329     int  c,queued=0,noaudio=0;
330     char *raw_length=NULL;
331 
332     /* parse options */
333     ng_init();
334     for (;;) {
335         if (-1 == (c = getopt(argc, argv, "haqdp:w:"
336                               "o:c:f:r:s:t:n:i:b:j:" "O:C:F:R:")))
337             break;
338         switch (c) {
339             /* general options */
340         case 'q':
341             quiet = 1;
342             break;
343         case 'a':
344             noaudio = 1;
345             break;
346         case 'd':
347             debug++;
348             ng_debug++;
349             break;
350         case 'w':
351             wait_seconds = atoi(optarg);
352             break;
353         case 'p':
354             parallel = atoi(optarg);
355             break;
356 
357             /* video options */
358         case 'o':
359             moviename = optarg;
360             break;
361         case 'f':
362             vfmt_name = optarg;
363             break;
364         case 'c':
365             ng_dev.video = optarg;
366             break;
367         case 'r':
368             fps = (int)(atof(optarg) * 1000 + 0.5);
369             break;
370         case 's':
371             if (2 != sscanf(optarg,"%dx%d",&video.width,&video.height))
372                 video.width = video.height = 0;
373             break;
374             
375         case 't':
376             raw_length = optarg;
377             break;
378         case 'b':
379             bufcount = atoi(optarg);
380             break;
381         case 'j':
382             ng_jpeg_quality = atoi(optarg);
383             break;
384         case 'n':
385             tvnorm = optarg;
386             break;
387         case 'i':
388             input = optarg;
389             break;
390 
391             /* audio options */
392         case 'O':
393             audioname = optarg;
394             break;
395         case 'F':
396             afmt_name = optarg;
397             break;
398         case 'C':
399             ng_dev.dsp = optarg;
400             break;
401         case 'R':
402             audio.rate = atoi(optarg);
403             break;
404 
405             /* errors / help */
406         case 'h':
407             usage(stdout);
408             exit(0);
409         default:
410             usage(stderr);
411             exit(1);
412         }
413     }
414     if (raw_length)
415         absframes = parse_time(raw_length);
416     find_formats();
417 
418     /* sanity checks */
419     if (video.fmtid == VIDEO_NONE && audio.fmtid == AUDIO_NONE) {
420         fprintf(stderr,"neither audio nor video format specified/found\n");
421         exit(1);
422     }
423     if (NULL == writer) {
424         fprintf(stderr,"no output driver found\n");
425         exit(1);
426     }
427     if (audio.fmtid != AUDIO_NONE && !writer->combined && NULL == audioname) {
428         fprintf(stderr,"no audio file name specified\n");
429         exit(1);
430     }
431 
432     /* set hooks */
433     rec_status = do_rec_status;
434 
435     /* open */
436     if (writer && !quiet)
437         fprintf(stderr,"%s / video: %s / audio: %s\n",writer->name,
438                 ng_vfmt_to_desc[video.fmtid],ng_afmt_to_desc[audio.fmtid]);
439 
440     if (video.fmtid != VIDEO_NONE) {
441         drv = ng_vid_open(ng_dev.video,NULL,NULL,0,&h_drv);
442         if (NULL == drv) {
443             fprintf(stderr,"no grabber device available\n");
444             exit(1);
445         }
446         f_drv = drv->capabilities(h_drv);
447         add_attrs(drv->list_attrs(h_drv));
448         if (!(f_drv & CAN_CAPTURE)) {
449             fprintf(stderr,"%s: capture not supported\n",drv->name);
450             exit(1);
451         }
452         if (!noaudio)
453             audio_on();
454         audio_init();
455 
456         /* modify settings */
457         if (input != NULL)
458             do_va_cmd(2,"setinput",input);
459         if (tvnorm != NULL)
460             do_va_cmd(2,"setnorm",tvnorm);
461     }
462         
463     /* init movie writer */
464     ng_ratio_x = video.width;
465     ng_ratio_y = video.height;
466     movie_state = movie_writer_init
467         (moviename, audioname, writer,
468          &video, video_priv, fps,
469          &audio, audio_priv, ng_dev.dsp,
470          bufcount, parallel);
471     if (NULL == movie_state) {
472         fprintf(stderr,"movie writer initialisation failed\n");
473         if (video.fmtid != VIDEO_NONE) {
474             audio_off();
475             drv->close(h_drv);
476         }
477         exit(1);
478     }
479 
480     /* catch ^C */
481     signal(SIGINT,ctrlc);
482 
483     /* wait for some cameras to wake up and adjust light and all that */
484     if (wait_seconds)
485         sleep(wait_seconds);
486 
487     /* main loop */
488     movie_writer_start(movie_state);
489     for (;queued < absframes && !signaled;) {
490         if (video.fmtid != VIDEO_NONE) {
491             /* video */
492             queued = movie_grab_put_video(movie_state,NULL);
493         } else {
494             sleep(1);
495             queued += fps / 1000;
496         }
497     }
498     movie_writer_stop(movie_state);
499 
500     /* done */
501     if (video.fmtid != VIDEO_NONE) {
502         if (!noaudio)
503             audio_off();
504         drv->close(h_drv);
505     }
506     return 0;
507 }
508 
  This page was automatically generated by the LXR engine.