319
|
1 /*
|
|
2 * codec.conf parser
|
|
3 * by Szabolcs Berecz <szabi@inf.elte.hu>
|
|
4 * (C) 2001
|
|
5 */
|
303
|
6
|
319
|
7 #define DEBUG
|
303
|
8
|
319
|
9 #ifdef DEBUG
|
|
10 #define DBG(str, args...) printf(str, ##args)
|
|
11 #else
|
|
12 #define DBG(str, args...) do {} while (0)
|
|
13 #endif
|
|
14
|
|
15 #define PRINT_LINENUM printf("%s(%d): ", cfgfile, line_num)
|
303
|
16
|
297
|
17 #include <stdio.h>
|
|
18 #include <stdlib.h>
|
|
19 #include <fcntl.h>
|
|
20 #include <unistd.h>
|
|
21 #include <errno.h>
|
|
22 #include <ctype.h>
|
|
23 #include <assert.h>
|
|
24 #include <string.h>
|
|
25
|
|
26 #include "libvo/video_out.h"
|
|
27 #include "codec-cfg.h"
|
|
28
|
319
|
29 #define MAX_NR_TOKEN 16
|
297
|
30
|
|
31 #define MAX_LINE_LEN 1000
|
|
32
|
|
33 #define STATE_MASK ((1<<7)-1)
|
|
34
|
|
35 #define GOT_NAME (1<<0)
|
|
36 #define GOT_INFO (1<<1)
|
|
37 #define GOT_FOURCC (1<<2)
|
|
38 #define GOT_FORMAT (1<<3)
|
|
39 #define GOT_DRIVER (1<<4)
|
|
40 #define GOT_DLL (1<<5)
|
|
41 #define GOT_OUT (1<<6)
|
|
42
|
|
43 #define RET_EOF -1
|
|
44 #define RET_EOL -2
|
|
45
|
303
|
46 static FILE *fp;
|
|
47 static int line_num = 0;
|
|
48 static int line_pos; /* line pos */
|
|
49 static char *line;
|
319
|
50 static char *token[MAX_NR_TOKEN];
|
297
|
51
|
303
|
52 static codecs_t *codecs=NULL;
|
|
53 static int nr_codecs = 0;
|
297
|
54
|
319
|
55 static int get_token(int min, int max)
|
297
|
56 {
|
|
57 static int read_nextline = 1;
|
319
|
58 int i;
|
|
59 char c;
|
|
60
|
|
61 if (max >= MAX_NR_TOKEN) {
|
|
62 printf("\nget_token(): max >= MAX_NR_TOKEN!\n");
|
|
63 goto ret_eof;
|
|
64 }
|
|
65
|
|
66 memset(token, 0x00, sizeof(*token) * max);
|
297
|
67
|
|
68 if (read_nextline) {
|
|
69 if (!fgets(line, MAX_LINE_LEN, fp))
|
|
70 goto ret_eof;
|
|
71 line_pos = 0;
|
|
72 ++line_num;
|
|
73 read_nextline = 0;
|
|
74 }
|
319
|
75 for (i = 0; i < max; i++) {
|
|
76 while (isspace(line[line_pos]))
|
|
77 ++line_pos;
|
|
78 if (line[line_pos] == '\0' || line[line_pos] == '#' ||
|
|
79 line[line_pos] == ';') {
|
297
|
80 read_nextline = 1;
|
319
|
81 if (i >= min)
|
|
82 goto ret_ok;
|
297
|
83 goto ret_eol;
|
|
84 }
|
319
|
85 token[i] = line + line_pos;
|
|
86 c = line[line_pos];
|
|
87 if (c == '"' || c == '\'') {
|
|
88 token[i]++;
|
|
89 while (line[++line_pos] != c && line[line_pos])
|
|
90 /* NOTHING */;
|
|
91 } else {
|
|
92 for (/* NOTHING */; !isspace(line[line_pos]) &&
|
|
93 line[line_pos]; line_pos++)
|
|
94 /* NOTHING */;
|
|
95 }
|
|
96 if (!line[line_pos]) {
|
|
97 read_nextline = 1;
|
|
98 if (i >= min - 1)
|
|
99 goto ret_ok;
|
|
100 goto ret_eol;
|
|
101 }
|
|
102 line[line_pos] = '\0';
|
|
103 line_pos++;
|
297
|
104 }
|
319
|
105 ret_ok:
|
|
106 return i;
|
297
|
107 ret_eof:
|
|
108 return RET_EOF;
|
|
109 ret_eol:
|
|
110 return RET_EOL;
|
|
111 }
|
|
112
|
303
|
113 static int add_to_fourcc(char *s, char *alias, unsigned int *fourcc,
|
297
|
114 unsigned int *map)
|
|
115 {
|
319
|
116 int i, j, freeslots;
|
297
|
117 char **aliasp;
|
319
|
118 unsigned int tmp;
|
|
119
|
|
120 /* find first unused slot */
|
|
121 for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++)
|
|
122 /* NOTHING */;
|
|
123 freeslots = CODECS_MAX_FOURCC - i;
|
|
124 if (!freeslots)
|
|
125 goto too_many_error_out;
|
|
126
|
|
127 aliasp = (alias) ? &alias : &s;
|
|
128 do {
|
|
129 tmp = *((unsigned int *) s);
|
|
130 for (j = 0; j < i; j++)
|
|
131 if (tmp == fourcc[j])
|
|
132 goto duplicated_error_out;
|
|
133 fourcc[i] = tmp;
|
|
134 map[i] = *((unsigned int *) (*aliasp));
|
|
135 s += 4;
|
|
136 i++;
|
|
137 } while ((*(s++) == ',') && --freeslots);
|
|
138
|
|
139 if (!freeslots)
|
|
140 goto too_many_error_out;
|
|
141 if (*(--s) != '\0')
|
|
142 return 0;
|
|
143 return 1;
|
|
144 duplicated_error_out:
|
|
145 printf("\nduplicated fourcc/format\n");
|
|
146 return 0;
|
|
147 too_many_error_out:
|
|
148 printf("\ntoo many fourcc/format...\n");
|
|
149 return 0;
|
|
150 }
|
|
151
|
|
152 static int add_to_format(char *s, unsigned int *fourcc, unsigned int *fourccmap)
|
|
153 {
|
|
154 //printf("\n-----[%s][%s]-----\n",s,format);
|
|
155
|
|
156 int i, j;
|
297
|
157
|
|
158 /* find first unused slot */
|
|
159 for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++)
|
|
160 /* NOTHING */;
|
|
161 if (i == CODECS_MAX_FOURCC) {
|
319
|
162 printf("\ntoo many fourcc/format...\n");
|
297
|
163 return 0;
|
|
164 }
|
|
165
|
300
|
166 fourcc[i]=fourccmap[i]=strtoul(s,NULL,0);
|
319
|
167 for (j = 0; j < i; j++)
|
|
168 if (fourcc[j] == fourcc[i]) {
|
|
169 printf("\nduplicated fourcc/format\n");
|
|
170 return 0;
|
|
171 }
|
300
|
172
|
297
|
173 return 1;
|
|
174 }
|
|
175
|
|
176
|
303
|
177 static int add_to_out(char *sfmt, char *sflags, unsigned int *outfmt,
|
297
|
178 unsigned char *outflags)
|
|
179 {
|
|
180 static char *fmtstr[] = {
|
|
181 "YUY2",
|
|
182 "YV12",
|
|
183 "RGB8",
|
|
184 "RGB15",
|
|
185 "RGB16",
|
|
186 "RGB24",
|
|
187 "RGB32",
|
|
188 "BGR8",
|
|
189 "BGR15",
|
|
190 "BGR16",
|
|
191 "BGR24",
|
|
192 "BGR32",
|
|
193 NULL
|
|
194 };
|
|
195 static unsigned int fmtnum[] = {
|
|
196 IMGFMT_YUY2,
|
|
197 IMGFMT_YV12,
|
|
198 IMGFMT_RGB|8,
|
|
199 IMGFMT_RGB|15,
|
|
200 IMGFMT_RGB|16,
|
|
201 IMGFMT_RGB|24,
|
|
202 IMGFMT_RGB|32,
|
|
203 IMGFMT_BGR|8,
|
|
204 IMGFMT_BGR|15,
|
|
205 IMGFMT_BGR|16,
|
|
206 IMGFMT_BGR|24,
|
|
207 IMGFMT_BGR|32
|
|
208 };
|
299
|
209 static char *flagstr[] = {
|
|
210 "flip",
|
|
211 "noflip",
|
|
212 "yuvhack",
|
|
213 NULL
|
|
214 };
|
|
215
|
319
|
216 int i, j, freeslots;
|
297
|
217 unsigned char flags;
|
|
218
|
|
219 for (i = 0; i < CODECS_MAX_OUTFMT && outfmt[i] != 0xffffffff; i++)
|
|
220 /* NOTHING */;
|
319
|
221 freeslots = CODECS_MAX_OUTFMT - i;
|
|
222 if (!freeslots)
|
|
223 goto too_many_error_out;
|
297
|
224
|
319
|
225 flags = 0;
|
299
|
226 if(sflags) do {
|
|
227 for (j = 0; flagstr[j] != NULL; j++)
|
|
228 if (!strncmp(sflags, flagstr[j], strlen(flagstr[j])))
|
|
229 break;
|
|
230 if (flagstr[j] == NULL) return 0; // error!
|
|
231 flags|=(1<<j);
|
|
232 sflags+=strlen(flagstr[j]);
|
|
233 } while (*(sflags++) == ',');
|
297
|
234
|
|
235 do {
|
299
|
236 for (j = 0; fmtstr[j] != NULL; j++)
|
297
|
237 if (!strncmp(sfmt, fmtstr[j], strlen(fmtstr[j])))
|
|
238 break;
|
|
239 if (fmtstr[j] == NULL)
|
|
240 return 0;
|
|
241 outfmt[i] = fmtnum[j];
|
|
242 outflags[i] = flags;
|
299
|
243 ++i;
|
297
|
244 sfmt+=strlen(fmtstr[j]);
|
319
|
245 } while ((*(sfmt++) == ',') && --freeslots);
|
|
246
|
|
247 if (!freeslots)
|
|
248 goto too_many_error_out;
|
|
249
|
299
|
250 if (*(--sfmt) != '\0') return 0;
|
|
251
|
297
|
252 return 1;
|
319
|
253 too_many_error_out:
|
|
254 printf("\ntoo many out...\n");
|
|
255 return 0;
|
297
|
256 }
|
|
257
|
303
|
258 static short get_driver(char *s,int audioflag)
|
297
|
259 {
|
301
|
260 static char *audiodrv[] = {
|
|
261 "mp3lib",
|
|
262 "pcm",
|
|
263 "libac3",
|
|
264 "acm",
|
|
265 "alaw",
|
|
266 "msgsm",
|
|
267 "dshow",
|
|
268 NULL
|
|
269 };
|
|
270 static char *videodrv[] = {
|
|
271 "libmpeg2",
|
|
272 "vfw",
|
|
273 "odivx",
|
|
274 "dshow",
|
|
275 NULL
|
|
276 };
|
|
277 char **drv=audioflag?audiodrv:videodrv;
|
|
278 int i;
|
|
279
|
|
280 for(i=0;drv[i];i++) if(!strcmp(s,drv[i])) return i+1;
|
|
281
|
297
|
282 return 0;
|
|
283 }
|
|
284
|
319
|
285 static int valid_codec(codecs_t *codec)
|
|
286 {
|
|
287 #warning FIXME mi is kell egy codec-be?
|
|
288 return 1;
|
|
289 }
|
|
290
|
|
291 static int add_comment(char *s, char **d)
|
|
292 {
|
|
293 int pos;
|
|
294
|
|
295 if (!*d)
|
|
296 pos = 0;
|
|
297 else {
|
|
298 pos = strlen(*d);
|
|
299 (*d)[pos++] = '\n';
|
|
300 }
|
|
301 if (!(*d = (char *) realloc(*d, pos + strlen(s) + 1))) {
|
|
302 printf("can't allocate mem for comment\n");
|
|
303 return 0;
|
|
304 }
|
|
305 strcpy(*d + pos, s);
|
|
306 return 1;
|
|
307 }
|
297
|
308
|
|
309 codecs_t *parse_codec_cfg(char *cfgfile)
|
|
310 {
|
319
|
311 codecs_t *codec = NULL; // current codec
|
297
|
312 int tmp, i;
|
|
313 int state = 0;
|
|
314
|
|
315 #ifdef DEBUG
|
|
316 assert(cfgfile != NULL);
|
|
317 #endif
|
|
318
|
|
319 printf("Reading codec config file: %s\n", cfgfile);
|
|
320
|
301
|
321 if ((fp = fopen(cfgfile, "r")) == NULL) {
|
|
322 printf("parse_codec_cfg: can't open '%s': %s\n", cfgfile, strerror(errno));
|
297
|
323 return NULL;
|
|
324 }
|
|
325
|
301
|
326 if ((line = (char *) malloc(MAX_LINE_LEN + 1)) == NULL) {
|
|
327 perror("parse_codec_cfg: can't get memory for 'line'");
|
297
|
328 return NULL;
|
|
329 }
|
|
330
|
319
|
331 while ((tmp = get_token(1, 1)) != RET_EOF) {
|
297
|
332 if (tmp == RET_EOL)
|
|
333 continue;
|
319
|
334 if (!strcmp(token[0], "audiocodec") || !strcmp(token[0], "videocodec")) {
|
|
335 if (nr_codecs)
|
|
336 if (!valid_codec(codec))
|
|
337 goto not_valid_error_out;
|
300
|
338 if (!(codecs = (codecs_t *) realloc(codecs,
|
|
339 sizeof(codecs_t) * (nr_codecs + 1)))) {
|
|
340 perror("parse_codec_cfg: can't realloc 'codecs'");
|
|
341 goto err_out;
|
|
342 }
|
319
|
343 codec=&codecs[nr_codecs];
|
300
|
344 nr_codecs++;
|
|
345 memset(codec,0,sizeof(codecs_t));
|
|
346 memset(codec->fourcc, 0xff, sizeof(codec->fourcc));
|
|
347 memset(codec->outfmt, 0xff, sizeof(codec->outfmt));
|
297
|
348 state = 0;
|
300
|
349
|
319
|
350 if (*token[0] == 'a') { /* audiocodec */
|
300
|
351 codec->flags |= CODECS_FLAG_AUDIO;
|
319
|
352 } else if (*token[0] == 'v') { /* videocodec */
|
300
|
353 codec->flags &= !CODECS_FLAG_AUDIO;
|
297
|
354 } else {
|
|
355 printf("itt valami nagyon el van baszva\n");
|
|
356 goto err_out;
|
|
357 }
|
319
|
358 if (get_token(1, 1) < 0)
|
297
|
359 goto parse_error_out;
|
319
|
360 for (i = 0; i < nr_codecs - 1; i++) {
|
|
361 #warning audio meg videocodecnek lehet ugyanaz a neve?
|
|
362 if ((codec->flags & CODECS_FLAG_AUDIO) !=
|
|
363 (codecs[i].flags & CODECS_FLAG_AUDIO))
|
|
364 continue;
|
|
365 if (!strcmp(token[0], codecs[i].name)) {
|
|
366 PRINT_LINENUM;
|
|
367 printf("codec name '%s' isn't unique\n", token[0]);
|
|
368 goto err_out;
|
|
369 }
|
|
370 }
|
|
371 codec->name = strdup(token[0]);
|
|
372 state |= GOT_NAME;
|
|
373 } else if (!strcmp(token[0], "info")) {
|
297
|
374 if (!(state & GOT_NAME))
|
|
375 goto parse_error_out;
|
319
|
376 if (state & GOT_INFO || get_token(1, 1) < 0)
|
297
|
377 goto parse_error_out;
|
319
|
378 codec->info = strdup(token[0]);
|
|
379 state |= GOT_INFO;
|
|
380 } else if (!strcmp(token[0], "comment")) {
|
297
|
381 if (!(state & GOT_NAME))
|
|
382 goto parse_error_out;
|
319
|
383 if (get_token(1, 1) < 0)
|
297
|
384 goto parse_error_out;
|
319
|
385 if (!add_comment(token[0], &codec->comment)) {
|
|
386 PRINT_LINENUM;
|
|
387 printf("add_comment()-tel valami sux\n");
|
|
388 }
|
|
389 } else if (!strcmp(token[0], "fourcc")) {
|
|
390 if (!(state & GOT_NAME))
|
|
391 goto parse_error_out;
|
|
392 if (get_token(1, 2) < 0)
|
|
393 goto parse_error_out;
|
|
394 if (!add_to_fourcc(token[0], token[1],
|
300
|
395 codec->fourcc,
|
|
396 codec->fourccmap))
|
319
|
397 goto parse_error_out;
|
297
|
398 state |= GOT_FOURCC;
|
319
|
399 } else if (!strcmp(token[0], "format")) {
|
297
|
400 if (!(state & GOT_NAME))
|
|
401 goto parse_error_out;
|
319
|
402 if (get_token(1, 1) < 0)
|
297
|
403 goto parse_error_out;
|
319
|
404 if (!add_to_format(token[0], codec->fourcc,codec->fourccmap))
|
|
405 goto parse_error_out;
|
297
|
406 state |= GOT_FORMAT;
|
319
|
407 } else if (!strcmp(token[0], "driver")) {
|
297
|
408 if (!(state & GOT_NAME))
|
|
409 goto parse_error_out;
|
319
|
410 if (get_token(1, 1) < 0)
|
297
|
411 goto parse_error_out;
|
319
|
412 if ((codec->driver = get_driver(token[0],codec->flags&CODECS_FLAG_AUDIO)) == -1)
|
297
|
413 goto err_out;
|
319
|
414 } else if (!strcmp(token[0], "dll")) {
|
297
|
415 if (!(state & GOT_NAME))
|
|
416 goto parse_error_out;
|
319
|
417 if (get_token(1, 1) < 0)
|
297
|
418 goto parse_error_out;
|
319
|
419 codec->dll = strdup(token[0]);
|
|
420 } else if (!strcmp(token[0], "guid")) {
|
297
|
421 if (!(state & GOT_NAME))
|
|
422 goto parse_error_out;
|
319
|
423 if (get_token(11, 11) < 0) goto parse_error_out;
|
|
424 codec->guid.f1=strtoul(token[0],NULL,0);
|
|
425 codec->guid.f2=strtoul(token[1],NULL,0);
|
|
426 codec->guid.f3=strtoul(token[2],NULL,0);
|
300
|
427 for (i = 0; i < 8; i++) {
|
319
|
428 codec->guid.f4[i]=strtoul(token[i + 3],NULL,0);
|
297
|
429 }
|
319
|
430 } else if (!strcmp(token[0], "out")) {
|
297
|
431 if (!(state & GOT_NAME))
|
|
432 goto parse_error_out;
|
319
|
433 if (get_token(1, 2) < 0)
|
297
|
434 goto parse_error_out;
|
319
|
435 if (!add_to_out(token[0], token[1], codec->outfmt,
|
300
|
436 codec->outflags))
|
297
|
437 goto err_out;
|
319
|
438 } else if (!strcmp(token[0], "flags")) {
|
297
|
439 if (!(state & GOT_NAME))
|
|
440 goto parse_error_out;
|
319
|
441 if (get_token(1, 1) < 0)
|
297
|
442 goto parse_error_out;
|
321
|
443 if (!strcmp(token[0], "seekable"))
|
|
444 codec->flags |= CODECS_FLAG_SEEKABLE;
|
|
445 else
|
|
446 goto parse_error_out;
|
319
|
447 } else if (!strcmp(token[0], "status")) {
|
316
|
448 if (!(state & GOT_NAME))
|
|
449 goto parse_error_out;
|
319
|
450 if (get_token(1, 1) < 0)
|
316
|
451 goto parse_error_out;
|
320
|
452 if (!strcasecmp(token[0], ":-)"))
|
316
|
453 codec->status = CODECS_STATUS_WORKING;
|
320
|
454 else if (!strcasecmp(token[0], ":-("))
|
316
|
455 codec->status = CODECS_STATUS_NOT_WORKING;
|
320
|
456 else if (!strcasecmp(token[0], "X-("))
|
316
|
457 codec->status = CODECS_STATUS_UNTESTED;
|
320
|
458 else if (!strcasecmp(token[0], ":-|"))
|
316
|
459 codec->status = CODECS_STATUS_PROBLEMS;
|
|
460 else
|
|
461 goto parse_error_out;
|
297
|
462 } else
|
|
463 goto parse_error_out;
|
|
464 }
|
319
|
465 if (!valid_codec(codec))
|
|
466 goto not_valid_error_out;
|
297
|
467 out:
|
|
468 free(line);
|
|
469 fclose(fp);
|
|
470 return codecs;
|
|
471 parse_error_out:
|
|
472 PRINT_LINENUM;
|
|
473 printf("parse error\n");
|
|
474 err_out:
|
|
475 printf("\nOops\n");
|
|
476 if (codecs)
|
|
477 free(codecs);
|
|
478 codecs = NULL;
|
|
479 goto out;
|
319
|
480 not_valid_error_out:
|
|
481 PRINT_LINENUM;
|
|
482 printf("codec is not definied correctly\n");
|
|
483 goto err_out;
|
297
|
484 }
|
|
485
|
303
|
486 codecs_t* find_codec(unsigned int fourcc,unsigned int *fourccmap,int audioflag){
|
|
487 int i,j;
|
|
488 for(i=0;i<nr_codecs;i++){
|
|
489 codecs_t *c=&codecs[i];
|
|
490 if(!audioflag && (c->flags&CODECS_FLAG_AUDIO)) continue;
|
|
491 if(audioflag && !(c->flags&CODECS_FLAG_AUDIO)) continue;
|
|
492 for(j=0;j<CODECS_MAX_FOURCC;j++){
|
|
493 if(c->fourcc[j]==fourcc){
|
|
494 if(fourccmap) *fourccmap=c->fourccmap[j];
|
|
495 return c;
|
|
496 }
|
|
497 }
|
|
498 }
|
|
499 return NULL;
|
|
500 }
|
|
501
|
|
502
|
297
|
503 #ifdef TESTING
|
|
504 int main(void)
|
|
505 {
|
|
506 codecs_t *codecs;
|
|
507 int i,j;
|
|
508
|
319
|
509 if (!(codecs = parse_codec_cfg("DOCS/codecs.conf")))
|
|
510 return 0;
|
297
|
511
|
|
512 printf("total %d codecs parsed\n",nr_codecs);
|
|
513 for(i=0;i<nr_codecs;i++){
|
|
514 codecs_t *c=&codecs[i];
|
|
515 printf("\n============== codec %02d ===============\n",i);
|
|
516 printf("name='%s'\n",c->name);
|
|
517 printf("info='%s'\n",c->info);
|
|
518 printf("comment='%s'\n",c->comment);
|
|
519 printf("dll='%s'\n",c->dll);
|
|
520 printf("flags=%X driver=%d\n",c->flags,c->driver);
|
300
|
521
|
297
|
522 for(j=0;j<CODECS_MAX_FOURCC;j++){
|
|
523 if(c->fourcc[j]!=0xFFFFFFFF){
|
|
524 printf("fourcc %02d: %08X (%.4s) ===> %08X (%.4s)\n",j,c->fourcc[j],&c->fourcc[j],c->fourccmap[j],&c->fourccmap[j]);
|
|
525 }
|
|
526 }
|
300
|
527
|
299
|
528 for(j=0;j<CODECS_MAX_OUTFMT;j++){
|
|
529 if(c->outfmt[j]!=0xFFFFFFFF){
|
|
530 printf("outfmt %02d: %08X (%.4s) flags: %d\n",j,c->outfmt[j],&c->outfmt[j],c->outflags[j]);
|
|
531 }
|
|
532 }
|
300
|
533
|
319
|
534 printf("GUID: %08lX %04X %04X",c->guid.f1,c->guid.f2,c->guid.f3);
|
300
|
535 for(j=0;j<8;j++) printf(" %02X",c->guid.f4[j]);
|
|
536 printf("\n");
|
|
537
|
|
538
|
297
|
539 }
|
|
540
|
|
541 return 0;
|
|
542 }
|
|
543
|
|
544 #endif
|