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 #include "config.h"
  2 
  3 #include <stdio.h>
  4 #include <stdlib.h>
  5 #include <unistd.h>
  6 #include <string.h>
  7 #include <fcntl.h>
  8 #include <errno.h>
  9 #include <sys/param.h>
 10 #include <sys/uio.h>
 11 
 12 #include "riff.h"
 13 #include "grab-ng.h"
 14 
 15 #if 0 /* debugging */
 16 # define LIMIT_OPENDML      (1024*1024) 
 17 #else
 18 # define LIMIT_OPENDML (2000*1024*1024)
 19 #endif
 20 
 21 /*
 22  * M$ vidcap avi video+audio layout
 23  *
 24  * riff avi
 25  *   list hdrl       header
 26  *     avih          avi header
 27  *     list strl     video stream header
 28  *       strh         
 29  *       strf        
 30  *     list strl     audio stream header
 31  *       strh        
 32  *       strf        
 33  *     istf          ??? software
 34  *     idit          ??? timestamp
 35  *   yunk            ??? 4k page pad
 36  *   list movi       data
 37  *     00db          video data
 38  *     yunk          ??? 4k page pad
 39  *     [ ... ]
 40  *     01wb          audio data
 41  *     [ ... ]
 42  *   idx1            video frame index
 43  *
 44  */
 45 
 46 /* ----------------------------------------------------------------------- */
 47 
 48 #define TRAP(txt) fprintf(stderr,"%s:%d:%s\n",__FILE__,__LINE__,txt);exit(1);
 49 
 50 #define size_strl_vids (sizeof(struct RIFF_strh) + \
 51                         sizeof(struct RIFF_strf_vids) + \
 52                         4*5)
 53 #define size_strl_auds (sizeof(struct RIFF_strh) + \
 54                         sizeof(struct RIFF_strf_auds) + \
 55                         4*5)
 56 
 57 static const struct AVI_HDR avi_hdr = {
 58     {'R','I','F','F'}, 0,                             {'A','V','I',' '},
 59     {'L','I','S','T'}, 0,                             {'h','d','r','l'},
 60     {'a','v','i','h'}, AVI_SWAP4(sizeof(struct RIFF_avih)),      {}
 61 };
 62 
 63 static const struct AVIX_HDR avix_hdr = {
 64     {'R','I','F','F'}, 0,                             {'A','V','I','X'},
 65     {'L','I','S','T'}, 0,                             {'m','o','v','i'},
 66 };
 67 
 68 static const struct AVI_HDR_VIDEO avi_hdr_video = {
 69     {'L','I','S','T'}, AVI_SWAP4(size_strl_vids),                {'s','t','r','l'},
 70     {'s','t','r','h'}, AVI_SWAP4(sizeof(struct RIFF_strh)),      {{'v','i','d','s'}},
 71     {'s','t','r','f'}, AVI_SWAP4(sizeof(struct RIFF_strf_vids)), {}
 72 };
 73 
 74 static const struct AVI_HDR_AUDIO avi_hdr_audio = {
 75     {'L','I','S','T'}, AVI_SWAP4(size_strl_auds),                {'s','t','r','l'},
 76     {'s','t','r','h'}, AVI_SWAP4(sizeof(struct RIFF_strh)),      {{'a','u','d','s'}},
 77     {'s','t','r','f'}, AVI_SWAP4(sizeof(struct RIFF_strf_auds)), {}
 78 };
 79 
 80 static const struct AVI_HDR_ODML avi_hdr_odml = {
 81     {'L','I','S','T'}, AVI_SWAP4(sizeof(uint32_t) + 4*3),  {'o','d','m','l'},
 82     {'d','m','l','h'}, AVI_SWAP4(sizeof(uint32_t)),
 83 };
 84 
 85 static const struct AVI_DATA avi_data = {
 86     {'L','I','S','T'}, 0,                   {'m','o','v','i'},
 87 };
 88 
 89 static const struct CHUNK_HDR frame_hdr = {
 90     {'','','d','b'}, 0
 91 };
 92 static const struct CHUNK_HDR sound_hdr = {
 93     {'','1','w','b'}, 0
 94 };
 95 static const struct CHUNK_HDR idx_hdr = {
 96     {'i','d','x','1'}, 0
 97 };
 98 
 99 /* ----------------------------------------------------------------------- */
100 
101 struct avi_video_priv {
102     const char handler[4];
103     const char compress[4];
104     const int  bytesperpixel;
105 };
106 
107 struct avi_handle {
108     /* file name+handle */
109     char   file[MAXPATHLEN];
110     int    fd;
111     struct iovec *vec;
112 
113     /* format */
114     struct ng_video_fmt video;
115     struct ng_audio_fmt audio;
116 
117     /* headers */
118     struct AVI_HDR        avi_hdr;
119     struct AVIX_HDR       avix_hdr;
120     struct AVI_HDR_ODML   avi_hdr_odml;
121     struct AVI_HDR_AUDIO  avi_hdr_audio;
122     struct AVI_HDR_VIDEO  avi_hdr_video;
123     struct AVI_DATA       avi_data;
124     struct CHUNK_HDR      frame_hdr;
125     struct CHUNK_HDR      sound_hdr;
126     struct CHUNK_HDR      idx_hdr;
127 
128     /* statistics -- first chunk */
129     int    frames;
130     off_t  hdr_size;
131     off_t  audio_size;
132     off_t  data_size;
133 
134     /* statistics -- current chunk */
135     int    bigfile;
136     int    framesx;
137     off_t  avix_start;
138     off_t  datax_size;
139     
140     /* statistics -- total */
141     int    frames_total;
142 
143     /* frame index */
144     struct IDX_RECORD *idx_array;
145     int    idx_index, idx_count;
146     off_t  idx_offset;
147     off_t  idx_size;
148 };
149 
150 /* ----------------------------------------------------------------------- */
151 /* idx1 frame index                                                        */
152 
153 static void
154 avi_addindex(struct avi_handle *h, char *fourcc,int flags,int chunksize)
155 {
156     if (h->idx_index == h->idx_count) {
157         h->idx_count += 256;
158         h->idx_array = realloc(h->idx_array,h->idx_count*sizeof(struct IDX_RECORD));
159     }
160     memcpy(h->idx_array[h->idx_index].id,fourcc,4);
161     h->idx_array[h->idx_index].flags=AVI_SWAP4(flags);
162     h->idx_array[h->idx_index].offset=AVI_SWAP4(h->idx_offset-h->hdr_size-8);
163     h->idx_array[h->idx_index].size=AVI_SWAP4(chunksize);
164     h->idx_index++;
165     h->idx_offset += chunksize + sizeof(struct CHUNK_HDR);
166 }
167 
168 static void
169 avi_writeindex(struct avi_handle *h)
170 {
171     /* write frame index */
172     h->idx_hdr.size = AVI_SWAP4(h->idx_index * sizeof(struct IDX_RECORD));
173     write(h->fd,&h->idx_hdr,sizeof(struct CHUNK_HDR));
174     write(h->fd,h->idx_array,h->idx_index*sizeof(struct IDX_RECORD));
175     h->idx_size += h->idx_index * sizeof(struct IDX_RECORD)
176         + sizeof(struct CHUNK_HDR);
177 
178     /* update header */
179     h->avi_hdr.avih.flags       |= AVI_SWAP4(AVIF_HASINDEX);
180 }   
181 
182 static void
183 avi_bigfile(struct avi_handle *h, int last)
184 {
185     off_t avix_end;
186     
187     if (h->bigfile) {
188         /* finish this chunk */
189         avix_end = lseek(h->fd,0,SEEK_CUR);
190         lseek(h->fd,h->avix_start,SEEK_SET);
191         h->avix_hdr.riff_size = h->datax_size + 4*4;
192         h->avix_hdr.data_size = h->datax_size + 4;
193         write(h->fd,&h->avix_hdr,sizeof(struct AVIX_HDR));
194         lseek(h->fd,avix_end,SEEK_SET);
195         h->avix_start = avix_end;
196     } else {
197         h->avix_start = lseek(h->fd,0,SEEK_CUR);
198     }
199     if (last)
200         return;
201     h->bigfile++;
202     h->framesx = 0;
203     h->datax_size = 0;
204     write(h->fd,&h->avix_hdr,sizeof(struct AVIX_HDR));
205     if (ng_debug)
206         fprintf(stderr,"avi bigfile #%d\n",h->bigfile);
207 }
208 
209 /* ----------------------------------------------------------------------- */
210 
211 static void
212 avi_write_header(struct avi_handle *h)
213 {
214     off_t curpos;
215 
216     /* fill in some statistic values ... */
217     h->avi_hdr.riff_size         = AVI_SWAP4(h->hdr_size+h->data_size+h->idx_size);
218     h->avi_hdr.hdrl_size         = AVI_SWAP4(h->hdr_size - 4*5);
219     h->avi_hdr.avih.frames       = AVI_SWAP4(h->frames);
220     if (h->video.fmtid != VIDEO_NONE)
221         h->avi_hdr_video.strh.length = AVI_SWAP4(h->frames);
222     if (h->audio.fmtid != AUDIO_NONE)
223         h->avi_hdr_audio.strh.length =
224             AVI_SWAP4(h->audio_size/h->avi_hdr_audio.strh.scale);
225     h->avi_data.data_size        = AVI_SWAP4(h->data_size);
226     
227     /* ... and write header again */
228     curpos = lseek(h->fd,0,SEEK_CUR);
229     lseek(h->fd,0,SEEK_SET);
230     write(h->fd,&h->avi_hdr,sizeof(struct AVI_HDR));
231     if (h->video.fmtid != VIDEO_NONE)
232         write(h->fd,&h->avi_hdr_video,sizeof(struct AVI_HDR_VIDEO));
233     if (h->audio.fmtid != AUDIO_NONE)
234         write(h->fd,&h->avi_hdr_audio,sizeof(struct AVI_HDR_AUDIO));
235     if (h->video.fmtid != VIDEO_NONE) {
236         h->avi_hdr_odml.total_frames = h->frames_total;
237         write(h->fd,&h->avi_hdr_odml,sizeof(struct AVI_HDR_ODML));
238     }
239     write(h->fd,&h->avi_data,sizeof(struct AVI_DATA));
240     lseek(h->fd,curpos,SEEK_SET);
241 }
242 
243 static void*
244 avi_open(char *filename, char *dummy,
245          struct ng_video_fmt *video, const void *priv_video, int fps,
246          struct ng_audio_fmt *audio, const void *priv_audio)
247 {
248     const struct avi_video_priv  *pvideo = priv_video;
249     struct avi_handle      *h;
250     int i,frame_bytes,depth,streams,rate,us_frame;
251 
252     if (NULL == (h = malloc(sizeof(*h))))
253         return NULL;
254     if (NULL == filename)
255         return NULL;
256 
257     /* init */
258     memset(h,0,sizeof(*h));
259     h->video         = *video;
260     h->audio         = *audio;
261     h->avi_hdr       = avi_hdr;
262     h->avix_hdr      = avix_hdr;
263     h->avi_hdr_odml  = avi_hdr_odml;
264     h->avi_hdr_video = avi_hdr_video;
265     h->avi_hdr_audio = avi_hdr_audio;
266     h->avi_data      = avi_data;
267     h->frame_hdr     = frame_hdr;
268     h->sound_hdr     = sound_hdr;
269     h->idx_hdr       = idx_hdr;
270     h->vec           = malloc(sizeof(struct iovec) * video->height);
271 
272     strcpy(h->file,filename);
273     if (-1 == (h->fd = open(h->file,O_CREAT | O_RDWR | O_TRUNC, 0666))) {
274         fprintf(stderr,"open %s: %s\n",h->file,strerror(errno));
275         free(h);
276         return NULL;
277     }
278 
279     /* general */
280     streams = 0;
281     rate = 0;
282     if (h->video.fmtid != VIDEO_NONE) {
283         streams++;
284         rate += pvideo->bytesperpixel * fps / 1000;
285         h->avi_hdr.avih.width       = AVI_SWAP4(h->video.width);
286         h->avi_hdr.avih.height      = AVI_SWAP4(h->video.height);
287     }
288     if (h->audio.fmtid != AUDIO_NONE) {
289         streams++;
290         rate += ng_afmt_to_channels[h->audio.fmtid] *
291             ng_afmt_to_bits[h->audio.fmtid] *
292             h->audio.rate / 8;
293     }
294     us_frame = (long long)1000000000/fps;
295     h->avi_hdr.avih.us_frame    = AVI_SWAP4(us_frame);
296     h->avi_hdr.avih.bps         = AVI_SWAP4(rate);
297     h->avi_hdr.avih.streams     = AVI_SWAP4(streams);
298     h->hdr_size += write(h->fd,&h->avi_hdr,sizeof(struct AVI_HDR));
299 
300     /* video */
301     if (h->video.fmtid != VIDEO_NONE) {
302         for (i = 0; i < 4; i++) {
303             h->avi_hdr_video.strh.handler[i]     = pvideo->handler[i];
304             h->avi_hdr_video.strf.compression[i] = pvideo->compress[i];
305         }
306         frame_bytes = pvideo->bytesperpixel * h->video.width * h->video.height;
307         depth = ng_vfmt_to_depth[h->video.fmtid];
308         h->frame_hdr.size                = AVI_SWAP4(frame_bytes);
309         h->avi_hdr_video.strh.scale      = AVI_SWAP4(us_frame);
310         h->avi_hdr_video.strh.rate       = AVI_SWAP4(1000000);
311         h->avi_hdr_video.strf.size       = AVI_SWAP4(sizeof(avi_hdr_video.strf));
312         h->avi_hdr_video.strf.width      = AVI_SWAP4(h->video.width);
313         h->avi_hdr_video.strf.height     = AVI_SWAP4(h->video.height);
314         h->avi_hdr_video.strf.planes     = AVI_SWAP2(1);
315         h->avi_hdr_video.strf.bit_cnt    = AVI_SWAP2(depth ? depth : 24);
316         h->avi_hdr_video.strf.image_size = AVI_SWAP4(frame_bytes);
317         h->hdr_size += write(h->fd,&h->avi_hdr_video,sizeof(struct AVI_HDR_VIDEO));
318     }
319 
320     /* audio */
321     if (h->audio.fmtid != AUDIO_NONE) {
322         h->avi_hdr_audio.strh.scale      =
323             AVI_SWAP4(ng_afmt_to_channels[h->audio.fmtid] *
324                       ng_afmt_to_bits[h->audio.fmtid] / 8);
325         h->avi_hdr_audio.strh.rate       =
326             AVI_SWAP4(ng_afmt_to_channels[h->audio.fmtid] *
327                       ng_afmt_to_bits[h->audio.fmtid] *
328                       h->audio.rate / 8);
329         h->avi_hdr_audio.strh.samplesize =
330             AVI_SWAP4(ng_afmt_to_channels[h->audio.fmtid] *
331                       ng_afmt_to_bits[h->audio.fmtid] / 8);
332         h->avi_hdr_audio.strf.format     =
333             AVI_SWAP2(WAVE_FORMAT_PCM);
334         h->avi_hdr_audio.strf.channels   =
335             AVI_SWAP2(ng_afmt_to_channels[h->audio.fmtid]);
336         h->avi_hdr_audio.strf.rate       =
337             AVI_SWAP4(h->audio.rate);
338         h->avi_hdr_audio.strf.av_bps     = 
339             AVI_SWAP4(ng_afmt_to_channels[h->audio.fmtid] *
340                       ng_afmt_to_bits[h->audio.fmtid] *
341                       h->audio.rate / 8);
342         h->avi_hdr_audio.strf.blockalign =
343             AVI_SWAP2(ng_afmt_to_channels[h->audio.fmtid] *
344                       ng_afmt_to_bits[h->audio.fmtid] / 8);
345         h->avi_hdr_audio.strf.size       =
346             AVI_SWAP2(ng_afmt_to_bits[h->audio.fmtid]);
347         h->hdr_size += write(h->fd,&h->avi_hdr_audio,
348                              sizeof(struct AVI_HDR_AUDIO));
349     }
350     if (h->video.fmtid != VIDEO_NONE)
351         h->hdr_size += write(h->fd,&h->avi_hdr_odml,sizeof(struct AVI_HDR_ODML));
352 
353     /* data */
354     if (-1 == write(h->fd,&h->avi_data,sizeof(struct AVI_DATA))) {
355         fprintf(stderr,"write %s: %s\n",h->file,strerror(errno));
356         free(h);
357         return NULL;
358     }
359     h->data_size  = 4; /* list type */
360 
361     h->idx_index  = 0;
362     h->idx_offset = h->hdr_size + sizeof(struct AVI_DATA);
363 
364     avi_write_header(h);
365     return h;
366 }
367 
368 static int
369 avi_video(void *handle, struct ng_video_buf *buf)
370 {
371     struct avi_handle *h = handle;
372     struct iovec *line;
373     int y,bpl,size=0;
374 
375     size = (buf->size + 3) & ~3;
376     h->frame_hdr.size = AVI_SWAP4(size);
377     if (-1 == write(h->fd,&h->frame_hdr,sizeof(struct CHUNK_HDR))) {
378         fprintf(stderr,"write %s: %s\n",h->file,strerror(errno));
379         return -1;
380     }
381     switch (h->video.fmtid) {
382     case VIDEO_RGB15_LE:
383     case VIDEO_BGR24:
384         bpl = h->video.width * ng_vfmt_to_depth[h->video.fmtid] / 8;
385         for (line = h->vec, y = h->video.height-1;
386              y >= 0; line++, y--) {
387             line->iov_base = ((unsigned char*)buf->data) + y * bpl;
388             line->iov_len  = bpl;
389         }
390         if (-1 == writev(h->fd,h->vec,h->video.height)) {
391             fprintf(stderr,"writev %s: %s\n",h->file,strerror(errno));
392             return -1;
393         }
394         break;
395     case VIDEO_MJPEG:
396     case VIDEO_JPEG:
397         if (-1 == write(h->fd,buf->data,size)) {
398             fprintf(stderr,"write %s: %s\n",h->file,strerror(errno));
399             return -1;
400         }
401         break;
402     }
403     h->frames_total += 1;
404     if (!h->bigfile) {
405         avi_addindex(h,h->frame_hdr.id,0x12,size);
406         h->data_size  += size + sizeof(struct CHUNK_HDR);
407         h->frames     += 1;
408     } else {
409         h->datax_size += size + sizeof(struct CHUNK_HDR);
410         h->framesx    += 1;
411     }
412     if ((h->bigfile ? h->datax_size : h->data_size) > LIMIT_OPENDML)
413         avi_bigfile(h,0);
414     return 0;
415 }
416 
417 static int
418 avi_audio(void *handle, struct ng_audio_buf *buf)
419 {
420     struct avi_handle *h = handle;
421 
422     h->sound_hdr.size = AVI_SWAP4(buf->size);
423     if (-1 == write(h->fd,&h->sound_hdr,sizeof(struct CHUNK_HDR))) {
424         fprintf(stderr,"write %s: %s\n",h->file,strerror(errno));
425         return -1;
426     }
427     if (-1 == write(h->fd,buf->data,buf->size)) {
428         fprintf(stderr,"write %s: %s\n",h->file,strerror(errno));
429         return -1;
430     }
431 
432     if (!h->bigfile) {
433         avi_addindex(h,h->sound_hdr.id,0x0,buf->size);
434         h->data_size  += buf->size + sizeof(struct CHUNK_HDR);
435         h->audio_size += buf->size;
436     } else {
437         h->datax_size += buf->size + sizeof(struct CHUNK_HDR);
438     }
439     return 0;
440 }
441 
442 static int
443 avi_close(void *handle)
444 {
445     struct avi_handle *h = handle;
446 
447     /* write frame index */
448     if (h->video.fmtid != VIDEO_NONE) {
449         if (!h->bigfile) {
450             avi_writeindex(h);
451         } else {
452             avi_bigfile(h,1);
453             h->idx_size = 0;
454         }
455     }
456 
457     avi_write_header(h);
458     close(h->fd);
459     free(h->vec);
460     free(h);
461     return 0;
462 }
463 
464 /* ----------------------------------------------------------------------- */
465 /* data structures describing our capabilities                             */
466 
467 static struct avi_video_priv avi_rgb15 = {
468     bytesperpixel:  2,
469 };
470 static struct avi_video_priv avi_rgb24 = {
471     bytesperpixel:  3,
472 };
473 static struct avi_video_priv avi_mjpeg = {
474     handler:        {'M','J','P','G'},
475     compress:       {'M','J','P','G'},
476     bytesperpixel:  3,
477 };
478 static const struct ng_format_list avi_vformats[] = {
479     {
480         name:  "rgb15",
481         ext:   "avi",
482         fmtid: VIDEO_RGB15_LE,
483         priv:  &avi_rgb15,
484     },{
485         name:  "rgb24",
486         ext:   "avi",
487         fmtid: VIDEO_BGR24,
488         priv:  &avi_rgb24,
489     },{
490         name:  "mjpeg",
491         ext:   "avi",
492         fmtid: VIDEO_MJPEG,
493         priv:  &avi_mjpeg,
494     },{
495         name:  "jpeg",
496         ext:   "avi",
497         fmtid: VIDEO_JPEG,
498         priv:  &avi_mjpeg,
499     },{
500         /* EOF */
501     }
502 };
503 
504 static const struct ng_format_list avi_aformats[] = {
505     {
506         name:  "mono8",
507         ext:   "avi",
508         fmtid: AUDIO_U8_MONO,
509     },{
510         name:  "mono16",
511         ext:   "avi",
512         fmtid: AUDIO_S16_LE_MONO,
513     },{
514         name:  "stereo",
515         ext:   "avi",
516         fmtid: AUDIO_S16_LE_STEREO,
517     },{
518         /* EOF */
519     }
520 };
521 
522 struct ng_writer avi_writer = {
523     name:      "avi",
524     desc:      "Microsoft AVI (RIFF) format",
525     combined:  1,
526     video:     avi_vformats,
527     audio:     avi_aformats,
528     wr_open:   avi_open,
529     wr_video:  avi_video,
530     wr_audio:  avi_audio,
531     wr_close:  avi_close,
532 };
533 
534 extern void ng_plugin_init(void);
535 void ng_plugin_init(void)
536 {
537     ng_writer_register(NG_PLUGIN_MAGIC,__FILE__,&avi_writer);
538 }
539 
  This page was automatically generated by the LXR engine.