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/uio.h>
 10 
 11 #include "riff.h"
 12 #include "list.h"
 13 #include "grab-ng.h"
 14 
 15 /* ----------------------------------------------------------------------- */
 16 
 17 struct movi_range {
 18     off_t start;
 19     off_t size;
 20 };
 21 
 22 struct avi_handle {
 23     int                   fd;
 24     struct iovec          *vec;
 25 
 26     /* avi header */
 27     unsigned char         riff_type[4];
 28     unsigned char         fcc_type[4];
 29     struct RIFF_avih      avih;
 30     struct RIFF_strh      v_strh;
 31     struct RIFF_strh      a_strh;
 32     struct RIFF_strf_vids vids;
 33     struct RIFF_strf_auds auds;
 34     int32_t               dml_frames;
 35     struct movi_range     *movi;
 36     int                   movi_cnt;
 37     struct movi_range     wave;
 38 
 39     /* libng stuff */
 40     struct ng_video_fmt   vfmt;
 41     struct ng_audio_fmt   afmt;
 42 
 43     /* status data */
 44     off_t                 a_pos;
 45     off_t                 v_pos;
 46     int                   frames;
 47     off_t                 a_bytes;
 48 };
 49 
 50 /* ----------------------------------------------------------------------- */
 51 
 52 #define FCC(a,b,c,d) (((uint32_t)a << 24) |\
 53                       ((uint32_t)b << 16) |\
 54                       ((uint32_t)c << 8)  |\
 55                       (uint32_t)d)
 56 #define FCCS(str) FCC(str[0],str[1],str[2],str[3])
 57 
 58 static void avi_add_movi(struct avi_handle *h,  int level,
 59                         off_t start, off_t size)
 60 {
 61     if (0 == h->movi_cnt % 16)
 62         h->movi = realloc(h->movi,sizeof(struct movi_range)*(h->movi_cnt+16));
 63     h->movi[h->movi_cnt].start = start;
 64     h->movi[h->movi_cnt].size  = size;
 65     h->movi_cnt++;
 66     if (ng_debug)
 67         fprintf(stderr,"%*s[movie data list: 0x%llx+0x%llx]\n",
 68                 level, "", start, size);
 69 }
 70 
 71 static void avi_swap_strh(struct RIFF_strh *strh)
 72 {
 73     strh->flags       = AVI_SWAP4(strh->flags);
 74     strh->priority    = AVI_SWAP4(strh->priority);
 75     strh->init_frames = AVI_SWAP4(strh->init_frames);
 76     strh->scale       = AVI_SWAP4(strh->scale);
 77     strh->rate        = AVI_SWAP4(strh->rate);
 78     strh->start       = AVI_SWAP4(strh->start);
 79     strh->length      = AVI_SWAP4(strh->length);
 80     strh->bufsize     = AVI_SWAP4(strh->bufsize);
 81     strh->quality     = AVI_SWAP4(strh->quality);
 82     strh->samplesize  = AVI_SWAP4(strh->samplesize);
 83 }
 84 
 85 static void avi_swap_vids(struct RIFF_strf_vids *fmt)
 86 {
 87     fmt->size        = AVI_SWAP4(fmt->size);
 88     fmt->width       = AVI_SWAP4(fmt->width);
 89     fmt->height      = AVI_SWAP4(fmt->height);
 90     fmt->planes      = AVI_SWAP2(fmt->planes);
 91     fmt->bit_cnt     = AVI_SWAP2(fmt->bit_cnt);
 92     fmt->image_size  = AVI_SWAP4(fmt->image_size);
 93     fmt->xpels_meter = AVI_SWAP4(fmt->xpels_meter);
 94     fmt->ypels_meter = AVI_SWAP4(fmt->ypels_meter);
 95     fmt->num_colors  = AVI_SWAP4(fmt->num_colors);
 96     fmt->imp_colors  = AVI_SWAP4(fmt->imp_colors);
 97 }
 98 
 99 static void avi_swap_auds(struct RIFF_strf_auds *fmt)
100 {
101     fmt->format     = AVI_SWAP2(fmt->format);
102     fmt->channels   = AVI_SWAP2(fmt->channels);
103     fmt->rate       = AVI_SWAP4(fmt->rate);
104     fmt->av_bps     = AVI_SWAP4(fmt->av_bps);
105     fmt->blockalign = AVI_SWAP2(fmt->blockalign);
106     fmt->size       = AVI_SWAP2(fmt->size);
107 }
108 
109 static int avi_parse_header(struct avi_handle *h, off_t offset, int level)
110 {
111     struct CHUNK_HDR chunk;
112     struct RIFF_strh strh;
113     unsigned char id[4];
114     off_t pos = offset;
115 
116     lseek(h->fd,offset,SEEK_SET);
117     pos += read(h->fd,&chunk,sizeof(chunk));
118     chunk.size = AVI_SWAP4(chunk.size);
119     if (ng_debug)
120         fprintf(stderr,"%*s%4.4s <0x%x>\n",level,"",chunk.id,chunk.size);
121     switch (FCCS(chunk.id)) {
122     case FCC('R','I','F','F'):
123     case FCC('L','I','S','T'):
124         pos += read(h->fd,&id,sizeof(id));
125         if (FCCS(chunk.id) == FCC('R','I','F','F'))
126             memcpy(h->riff_type,id,4);
127         if (ng_debug)
128             fprintf(stderr,"%*s[list type is %4.4s]\n",level,"",id);
129         if (FCCS(id) == FCC('m','o','v','i')) {
130             avi_add_movi(h,level,pos,chunk.size-4);
131         } else {
132             while (pos < offset + chunk.size)
133                 pos += avi_parse_header(h,pos,level+3);
134         }
135         break;
136     case FCC('a','v','i','h'):
137         read(h->fd,&h->avih,sizeof(h->avih));
138         break;
139     case FCC('s','t','r','h'):
140         read(h->fd,&strh,sizeof(strh));
141         memcpy(h->fcc_type,strh.type,sizeof(h->fcc_type));
142         if (ng_debug)
143             fprintf(stderr,"%*s[header type is %4.4s]\n",level,"",h->fcc_type);
144         avi_swap_strh(&strh);
145         if (FCCS(h->fcc_type) == FCC('a','u','d','s'))
146             h->a_strh = strh;
147         if (FCCS(h->fcc_type) == FCC('v','i','d','s'))
148             h->v_strh = strh;
149         break;
150     case FCC('s','t','r','f'):
151         if (FCCS(h->fcc_type) == FCC('a','u','d','s')) {
152             read(h->fd,&h->auds,sizeof(h->auds));
153             avi_swap_auds(&h->auds);
154         }
155         if (FCCS(h->fcc_type) == FCC('v','i','d','s')) {
156             read(h->fd,&h->vids,sizeof(h->vids));
157             avi_swap_vids(&h->vids);
158         }
159         break;
160     case FCC('d','m','l','h'):
161         read(h->fd,&h->dml_frames,sizeof(h->dml_frames));
162         h->dml_frames = AVI_SWAP4(h->dml_frames);
163         break;
164     case FCC('f','m','t',' '):
165         if (FCCS(h->riff_type) == FCC('W','A','V','E')) {
166             read(h->fd,&h->auds,sizeof(h->auds));
167             avi_swap_auds(&h->auds);
168         }
169         break;
170     case FCC('d','a','t','a'):
171         if (FCCS(h->riff_type) == FCC('W','A','V','E')) {
172             h->wave.start = pos;
173             h->wave.size  = chunk.size-4;
174         }
175         break;
176     }
177     return chunk.size+8;
178 }
179 
180 static uint32_t avi_find_chunk(struct avi_handle *h, uint32_t id, off_t *pos)
181 {
182     struct CHUNK_HDR chunk;
183     int n = 0, bytes;
184 
185     if (NULL == h->movi) {
186         /* WAVE */
187         if (*pos >= h->wave.start + h->wave.size)
188             return 0;
189         lseek(h->fd,*pos,SEEK_SET);
190         bytes = h->wave.start + h->wave.size - *pos;
191         if (bytes > 64*1024)
192             bytes = 64*1024;
193         *pos += bytes;
194         return bytes;
195     }
196 
197     /* AVI + AVIX */
198     while (*pos >= h->movi[n].start + h->movi[n].size) {
199         n++;
200         if (n >= h->movi_cnt)
201             return 0;
202     }
203     for (;;) {
204         if (*pos >= h->movi[n].start + h->movi[n].size) {
205             n++;
206             if (n >= h->movi_cnt)
207                 return 0;
208             *pos = h->movi[n].start;
209         }
210         lseek(h->fd,*pos,SEEK_SET);
211         *pos += read(h->fd,&chunk,sizeof(chunk));
212         chunk.size = AVI_SWAP4(chunk.size);
213         *pos += (chunk.size + 3) & ~0x03; /* 32-bit align */
214         if (FCCS(chunk.id) == id) {
215             if (ng_debug)
216                 fprintf(stderr,"avi: chunk %4.4s: 0x%llx+0x%x\n",
217                         chunk.id,*pos,chunk.size);
218             return chunk.size;
219         }
220     }
221 }
222 
223 /* ----------------------------------------------------------------------- */
224 
225 static void* avi_open(char *moviename)
226 {
227     struct avi_handle *h;
228     off_t pos, size;
229 
230     h = malloc(sizeof(*h));
231     memset(h,0,sizeof(*h));
232     h->fd = -1;
233 
234     h->fd = open(moviename,O_RDONLY);
235     if (-1 == h->fd) {
236         fprintf(stderr,"open %s: %s\n",moviename,strerror(errno));
237         goto fail;
238     }
239 
240     size = lseek(h->fd,0,SEEK_END);
241     for (pos = 0; pos < size;)
242         pos += avi_parse_header(h,pos,0);
243     
244     if (h->movi) {
245         h->a_pos = h->movi[0].start;
246         h->v_pos = h->movi[0].start;
247     } else if (h->wave.start) {
248         h->a_pos = h->wave.start;
249     }
250     
251     /* audio stream ?? */
252     if (FCCS(h->a_strh.type) == FCC('a','u','d','s') ||
253         FCCS(h->riff_type) == FCC('W','A','V','E')) {
254         switch (h->auds.format) {
255         case WAVE_FORMAT_PCM:
256             if (h->auds.size == 8)
257                 h->afmt.fmtid = AUDIO_U8_MONO;
258             if (h->auds.size == 16)
259                 h->afmt.fmtid = AUDIO_S16_LE_MONO;
260             if (h->afmt.fmtid) {
261                 if (h->auds.channels > 1)
262                     h->afmt.fmtid++; /* mono => stereo */
263                 h->afmt.rate = h->auds.rate;
264             }
265             break;
266         }
267         if (h->afmt.fmtid != AUDIO_NONE && ng_debug)
268             fprintf(stderr,"avi: audio is %s @ %d Hz\n",
269                     ng_afmt_to_desc[h->afmt.fmtid],h->afmt.rate);
270     }
271 
272     /* video stream ?? */
273     if (FCCS(h->v_strh.type) == FCC('v','i','d','s')) {
274         switch (FCCS(h->v_strh.handler)) {
275         case 0:
276             if (h->vids.bit_cnt == 15)
277                 h->vfmt.fmtid = VIDEO_RGB15_LE;
278             if (h->vids.bit_cnt == 24)
279                 h->vfmt.fmtid = VIDEO_BGR24;
280             break;
281         case FCC('M','J','P','G'):
282             h->vfmt.fmtid = VIDEO_MJPEG;
283             break;
284         }
285         if (VIDEO_NONE != h->vfmt.fmtid) {
286             h->vfmt.width  = h->vids.width;
287             h->vfmt.height = h->vids.height;
288             h->vfmt.bytesperline = (h->vfmt.width*ng_vfmt_to_depth[h->vfmt.fmtid]) >> 3;
289             h->vec = malloc(sizeof(struct iovec) * h->vfmt.height);
290             if (ng_debug)
291                 fprintf(stderr,"avi: video is %s, %dx%d @ %d fps\n",
292                         ng_vfmt_to_desc[h->vfmt.fmtid],
293                         h->vfmt.width, h->vfmt.height,
294                         (int)((long long) 1000000 / h->avih.us_frame));
295         }
296     }
297     return h;
298     
299  fail:
300     if (-1 != h->fd)
301         close(h->fd);
302     free(h);
303     return NULL;
304 }
305 
306 static struct ng_video_fmt* avi_vfmt(void *handle, int *vfmt, int vn)
307 {
308     struct avi_handle *h = handle;
309 
310     return &h->vfmt;
311 }
312 
313 static struct ng_audio_fmt* avi_afmt(void *handle)
314 {
315     struct avi_handle *h = handle;
316 
317     return AUDIO_NONE != h->afmt.fmtid ? &h->afmt : NULL;
318 }
319 
320 static struct ng_video_buf* avi_vdata(void *handle, unsigned int drop)
321 {
322     struct avi_handle *h = handle;
323     struct ng_video_buf *buf;
324     struct iovec *line;
325     uint32_t size;
326     unsigned int i,y;
327 
328     /* drop frames */
329     for (i = 0; i < drop; i++) {
330         if (0 == avi_find_chunk(h,FCC('','','d','b'),&h->v_pos))
331             return NULL;
332         h->frames++;
333     }
334 
335     size = avi_find_chunk(h,FCC('','','d','b'),&h->v_pos);
336     if (0 == size)
337         return NULL;
338     buf = ng_malloc_video_buf(&h->vfmt,size);
339     switch (h->vfmt.fmtid) {
340     case VIDEO_RGB15_LE:
341     case VIDEO_BGR24:
342         for (line = h->vec, y = h->vfmt.height-1; y >= 0; line++, y--) {
343             line->iov_base = ((unsigned char*)buf->data) +
344                 y * h->vfmt.bytesperline;
345             line->iov_len = h->vfmt.bytesperline;
346         }
347         readv(h->fd,h->vec,h->vfmt.height);
348         break;
349     case VIDEO_MJPEG:
350     case VIDEO_JPEG:
351         read(h->fd,buf->data,size);
352         break;
353     }
354     buf->info.seq = h->frames;
355     buf->info.ts  = (long long)h->frames * h->avih.us_frame * 1000;
356     h->frames++;
357     return buf;
358 }
359 
360 static struct ng_audio_buf* avi_adata(void *handle)
361 {
362     struct avi_handle *h = handle;
363     struct ng_audio_buf *buf;
364     uint32_t size, samples;
365 
366     size = avi_find_chunk(h,FCC('','1','w','b'),&h->a_pos);
367     if (0 == size)
368         return NULL;
369     buf = ng_malloc_audio_buf(&h->afmt,size);
370     read(h->fd,buf->data,size);
371     samples = h->a_bytes * 8
372         / ng_afmt_to_channels[h->afmt.fmtid]
373         / ng_afmt_to_bits[h->afmt.fmtid];
374     buf->info.ts = (long long)samples * 1000000000 / h->afmt.rate;
375     h->a_bytes += size;
376     return buf;
377 }
378 
379 static int64_t avi_frame_time(void *handle)
380 {
381     struct avi_handle *h = handle;
382 
383     return h->avih.us_frame * 1000;
384 }
385 
386 static int avi_close(void *handle)
387 {
388     struct avi_handle *h = handle;
389 
390     if (h->vec)
391         free(h->vec);
392     close(h->fd);
393     free(h);
394     return 0;
395 }
396 
397 /* ----------------------------------------------------------------------- */
398 
399 struct ng_reader avi_reader = {
400     name:       "avi",
401     desc:       "Microsoft AVI (RIFF) format",
402 
403     magic:      { "RIFF" },
404     moff:       {  0     },
405     mlen:       {  4     },
406     
407     rd_open:    avi_open,
408     rd_vfmt:    avi_vfmt,
409     rd_afmt:    avi_afmt,
410     rd_vdata:   avi_vdata,
411     rd_adata:   avi_adata,
412     frame_time: avi_frame_time,
413     rd_close:   avi_close,
414 };
415 
416 extern void ng_plugin_init(void);
417 void ng_plugin_init(void)
418 {
419     ng_reader_register(NG_PLUGIN_MAGIC,__FILE__,&avi_reader);
420 }
421 
  This page was automatically generated by the LXR engine.