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.
|