Merge branch 'master' of git://repo.or.cz/mplayer into mob
[mplayer/glamo.git] / codec-cfg.c
blob367b37602c012a39e3b88d6d9dc06d134965f97b
1 /*
2 * codec.conf parser
3 * by Szabolcs Berecz <szabi@inf.elte.hu>
4 * (C) 2001
6 * to compile test application:
7 * cc -I. -DTESTING -o codec-cfg-test codec-cfg.c mp_msg.o osdep/getch2.o -ltermcap
8 * to compile CODECS2HTML:
9 * gcc -DCODECS2HTML -o codecs2html codec-cfg.c mp_msg.o
11 * TODO: implement informat in CODECS2HTML too
14 #define DEBUG
16 //disable asserts
17 #define NDEBUG
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <ctype.h>
25 #include <assert.h>
26 #include <string.h>
27 #include <stdint.h>
29 #include "config.h"
30 #include "mp_msg.h"
31 #ifdef CODECS2HTML
32 #define mp_tmsg mp_msg
33 #ifdef __GNUC__
34 #define mp_msg(t, l, m, args...) fprintf(stderr, m, ##args)
35 #else
36 #define mp_msg(t, l, ...) fprintf(stderr, __VA_ARGS__)
37 #endif
38 #endif
40 #include "help_mp.h"
42 #include "libmpcodecs/img_format.h"
43 #include "codec-cfg.h"
45 #ifndef CODECS2HTML
46 #include "codecs.conf.h"
47 #endif
49 #define mmioFOURCC( ch0, ch1, ch2, ch3 ) \
50 ( (uint32_t)(uint8_t)(ch0) | ( (uint32_t)(uint8_t)(ch1) << 8 ) | \
51 ( (uint32_t)(uint8_t)(ch2) << 16 ) | ( (uint32_t)(uint8_t)(ch3) << 24 ) )
53 #define PRINT_LINENUM mp_msg(MSGT_CODECCFG,MSGL_ERR," at line %d\n", line_num)
55 #define MAX_NR_TOKEN 16
57 #define MAX_LINE_LEN 1000
59 #define RET_EOF -1
60 #define RET_EOL -2
62 #define TYPE_VIDEO 0
63 #define TYPE_AUDIO 1
65 char * codecs_file = NULL;
67 static int add_to_fourcc(char *s, char *alias, unsigned int *fourcc,
68 unsigned int *map)
70 int i, j, freeslots;
71 unsigned int tmp;
73 /* find first unused slot */
74 for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++)
75 /* NOTHING */;
76 freeslots = CODECS_MAX_FOURCC - i;
77 if (!freeslots)
78 goto err_out_too_many;
80 do {
81 tmp = mmioFOURCC(s[0], s[1], s[2], s[3]);
82 for (j = 0; j < i; j++)
83 if (tmp == fourcc[j])
84 goto err_out_duplicated;
85 fourcc[i] = tmp;
86 map[i] = alias ? mmioFOURCC(alias[0], alias[1], alias[2], alias[3]) : tmp;
87 s += 4;
88 i++;
89 } while ((*(s++) == ',') && --freeslots);
91 if (!freeslots)
92 goto err_out_too_many;
93 if (*(--s) != '\0')
94 goto err_out_parse_error;
95 return 1;
96 err_out_duplicated:
97 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"duplicated FourCC");
98 return 0;
99 err_out_too_many:
100 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"too many FourCCs/formats...");
101 return 0;
102 err_out_parse_error:
103 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
104 return 0;
107 static int add_to_format(char *s, char *alias,unsigned int *fourcc, unsigned int *fourccmap)
109 int i, j;
110 char *endptr;
112 /* find first unused slot */
113 for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++)
114 /* NOTHING */;
115 if (i == CODECS_MAX_FOURCC) {
116 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"too many FourCCs/formats...");
117 return 0;
120 fourcc[i]=strtoul(s,&endptr,0);
121 if (*endptr != '\0') {
122 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error (format ID not a number?)");
123 return 0;
126 if(alias){
127 fourccmap[i]=strtoul(alias,&endptr,0);
128 if (*endptr != '\0') {
129 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error (format ID alias not a number?)");
130 return 0;
132 } else
133 fourccmap[i]=fourcc[i];
135 for (j = 0; j < i; j++)
136 if (fourcc[j] == fourcc[i]) {
137 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"duplicated format ID");
138 return 0;
141 return 1;
144 static struct {
145 const char *name;
146 const unsigned int num;
147 } fmt_table[] = {
148 {"YV12", IMGFMT_YV12},
149 {"I420", IMGFMT_I420},
150 {"IYUV", IMGFMT_IYUV},
151 {"NV12", IMGFMT_NV12},
152 {"NV21", IMGFMT_NV21},
153 {"YVU9", IMGFMT_YVU9},
154 {"IF09", IMGFMT_IF09},
155 {"444P", IMGFMT_444P},
156 {"422P", IMGFMT_422P},
157 {"411P", IMGFMT_411P},
158 {"Y800", IMGFMT_Y800},
159 {"Y8", IMGFMT_Y8},
161 {"YUY2", IMGFMT_YUY2},
162 {"UYVY", IMGFMT_UYVY},
163 {"YVYU", IMGFMT_YVYU},
165 {"RGB4", IMGFMT_RGB|4},
166 {"RGB8", IMGFMT_RGB|8},
167 {"RGB15", IMGFMT_RGB|15},
168 {"RGB16", IMGFMT_RGB|16},
169 {"RGB24", IMGFMT_RGB|24},
170 {"RGB32", IMGFMT_RGB|32},
171 {"BGR4", IMGFMT_BGR|4},
172 {"BGR8", IMGFMT_BGR|8},
173 {"BGR15", IMGFMT_BGR|15},
174 {"BGR16", IMGFMT_BGR|16},
175 {"BGR24", IMGFMT_BGR|24},
176 {"BGR32", IMGFMT_BGR|32},
177 {"RGB1", IMGFMT_RGB|1},
178 {"BGR1", IMGFMT_BGR|1},
180 {"MPES", IMGFMT_MPEGPES},
181 {"MPG4", IMGFMT_MPEG4},
182 {"ZRMJPEGNI", IMGFMT_ZRMJPEGNI},
183 {"ZRMJPEGIT", IMGFMT_ZRMJPEGIT},
184 {"ZRMJPEGIB", IMGFMT_ZRMJPEGIB},
186 {"IDCT_MPEG2",IMGFMT_XVMC_IDCT_MPEG2},
187 {"MOCO_MPEG2",IMGFMT_XVMC_MOCO_MPEG2},
189 {"VDPAU_MPEG1",IMGFMT_VDPAU_MPEG1},
190 {"VDPAU_MPEG2",IMGFMT_VDPAU_MPEG2},
191 {"VDPAU_H264",IMGFMT_VDPAU_H264},
192 {"VDPAU_WMV3",IMGFMT_VDPAU_WMV3},
193 {"VDPAU_VC1",IMGFMT_VDPAU_VC1},
195 {NULL, 0}
199 static int add_to_inout(char *sfmt, char *sflags, unsigned int *outfmt,
200 unsigned char *outflags)
203 static char *flagstr[] = {
204 "flip",
205 "noflip",
206 "yuvhack",
207 "query",
208 "static",
209 NULL
212 int i, j, freeslots;
213 unsigned char flags;
215 for (i = 0; i < CODECS_MAX_OUTFMT && outfmt[i] != 0xffffffff; i++)
216 /* NOTHING */;
217 freeslots = CODECS_MAX_OUTFMT - i;
218 if (!freeslots)
219 goto err_out_too_many;
221 flags = 0;
222 if(sflags) {
223 do {
224 for (j = 0; flagstr[j] != NULL; j++)
225 if (!strncmp(sflags, flagstr[j],
226 strlen(flagstr[j])))
227 break;
228 if (flagstr[j] == NULL)
229 goto err_out_parse_error;
230 flags|=(1<<j);
231 sflags+=strlen(flagstr[j]);
232 } while (*(sflags++) == ',');
234 if (*(--sflags) != '\0')
235 goto err_out_parse_error;
238 do {
239 for (j = 0; fmt_table[j].name != NULL; j++)
240 if (!strncmp(sfmt, fmt_table[j].name, strlen(fmt_table[j].name)))
241 break;
242 if (fmt_table[j].name == NULL)
243 goto err_out_parse_error;
244 outfmt[i] = fmt_table[j].num;
245 outflags[i] = flags;
246 ++i;
247 sfmt+=strlen(fmt_table[j].name);
248 } while ((*(sfmt++) == ',') && --freeslots);
250 if (!freeslots)
251 goto err_out_too_many;
253 if (*(--sfmt) != '\0')
254 goto err_out_parse_error;
256 return 1;
257 err_out_too_many:
258 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"too many out...");
259 return 0;
260 err_out_parse_error:
261 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
262 return 0;
265 #if 0
266 static short get_driver(char *s,int audioflag)
268 static char *audiodrv[] = {
269 "null",
270 "mp3lib",
271 "pcm",
272 "libac3",
273 "acm",
274 "alaw",
275 "msgsm",
276 "dshow",
277 "dvdpcm",
278 "hwac3",
279 "libvorbis",
280 "ffmpeg",
281 "libmad",
282 "msadpcm",
283 "liba52",
284 "g72x",
285 "imaadpcm",
286 "dk4adpcm",
287 "dk3adpcm",
288 "roqaudio",
289 "faad",
290 "realaud",
291 "libdv",
292 NULL
294 static char *videodrv[] = {
295 "null",
296 "libmpeg2",
297 "vfw",
298 "dshow",
299 "ffmpeg",
300 "vfwex",
301 "raw",
302 "msrle",
303 "xanim",
304 "msvidc",
305 "fli",
306 "cinepak",
307 "qtrle",
308 "nuv",
309 "cyuv",
310 "qtsmc",
311 "ducktm1",
312 "roqvideo",
313 "qtrpza",
314 "mpng",
315 "ijpg",
316 "zlib",
317 "mpegpes",
318 "zrmjpeg",
319 "realvid",
320 "xvid",
321 "libdv",
322 NULL
324 char **drv=audioflag?audiodrv:videodrv;
325 int i;
327 for(i=0;drv[i];i++) if(!strcmp(s,drv[i])) return i;
329 return -1;
331 #endif
333 static int validate_codec(codecs_t *c, int type)
335 unsigned int i;
336 char *tmp_name = c->name;
338 for (i = 0; i < strlen(tmp_name) && isalnum(tmp_name[i]); i++)
339 /* NOTHING */;
341 if (i < strlen(tmp_name)) {
342 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) name is not valid!\n", c->name);
343 return 0;
346 if (!c->info)
347 c->info = strdup(c->name);
349 #if 0
350 if (c->fourcc[0] == 0xffffffff) {
351 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) does not have FourCC/format!\n", c->name);
352 return 0;
354 #endif
356 if (!c->drv) {
357 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) does not have a driver!\n", c->name);
358 return 0;
361 #if 0
362 #warning codec->driver == 4;... <- this should not be put in here...
363 #warning Where are they defined ????????????
364 if (!c->dll && (c->driver == 4 ||
365 (c->driver == 2 && type == TYPE_VIDEO))) {
366 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) needs a 'dll'!\n", c->name);
367 return 0;
369 #warning Can guid.f1 be 0? How does one know that it was not given?
370 // if (!(codec->flags & CODECS_FLAG_AUDIO) && codec->driver == 4)
372 if (type == TYPE_VIDEO)
373 if (c->outfmt[0] == 0xffffffff) {
374 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) needs an 'outfmt'!\n", c->name);
375 return 0;
377 #endif
378 return 1;
381 static int add_comment(char *s, char **d)
383 int pos;
385 if (!*d)
386 pos = 0;
387 else {
388 pos = strlen(*d);
389 (*d)[pos++] = '\n';
391 if (!(*d = realloc(*d, pos + strlen(s) + 1))) {
392 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't allocate memory for comment. ");
393 return 0;
395 strcpy(*d + pos, s);
396 return 1;
399 static short get_cpuflags(char *s)
401 static char *flagstr[] = {
402 "mmx",
403 "sse",
404 "3dnow",
405 NULL
407 int i;
408 short flags = 0;
410 do {
411 for (i = 0; flagstr[i]; i++)
412 if (!strncmp(s, flagstr[i], strlen(flagstr[i])))
413 break;
414 if (!flagstr[i])
415 goto err_out_parse_error;
416 flags |= 1<<i;
417 s += strlen(flagstr[i]);
418 } while (*(s++) == ',');
420 if (*(--s) != '\0')
421 goto err_out_parse_error;
423 return flags;
424 err_out_parse_error:
425 return 0;
428 static FILE *fp;
429 static int line_num = 0;
430 static char *line;
431 static char *token[MAX_NR_TOKEN];
432 static int read_nextline = 1;
434 static int get_token(int min, int max)
436 static int line_pos;
437 int i;
438 char c;
440 if (max >= MAX_NR_TOKEN) {
441 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"get_token(): max >= MAX_MR_TOKEN!");
442 goto out_eof;
445 memset(token, 0x00, sizeof(*token) * max);
447 if (read_nextline) {
448 if (!fgets(line, MAX_LINE_LEN, fp))
449 goto out_eof;
450 line_pos = 0;
451 ++line_num;
452 read_nextline = 0;
454 for (i = 0; i < max; i++) {
455 while (isspace(line[line_pos]))
456 ++line_pos;
457 if (line[line_pos] == '\0' || line[line_pos] == '#' ||
458 line[line_pos] == ';') {
459 read_nextline = 1;
460 if (i >= min)
461 goto out_ok;
462 goto out_eol;
464 token[i] = line + line_pos;
465 c = line[line_pos];
466 if (c == '"' || c == '\'') {
467 token[i]++;
468 while (line[++line_pos] != c && line[line_pos])
469 /* NOTHING */;
470 } else {
471 for (/* NOTHING */; !isspace(line[line_pos]) &&
472 line[line_pos]; line_pos++)
473 /* NOTHING */;
475 if (!line[line_pos]) {
476 read_nextline = 1;
477 if (i >= min - 1)
478 goto out_ok;
479 goto out_eol;
481 line[line_pos] = '\0';
482 line_pos++;
484 out_ok:
485 return i;
486 out_eof:
487 read_nextline = 1;
488 return RET_EOF;
489 out_eol:
490 return RET_EOL;
493 static codecs_t *video_codecs=NULL;
494 static codecs_t *audio_codecs=NULL;
495 static int nr_vcodecs = 0;
496 static int nr_acodecs = 0;
498 int parse_codec_cfg(const char *cfgfile)
500 codecs_t *codec = NULL; // current codec
501 codecs_t **codecsp = NULL;// points to audio_codecs or to video_codecs
502 char *endptr; // strtoul()...
503 int *nr_codecsp;
504 int codec_type; /* TYPE_VIDEO/TYPE_AUDIO */
505 int tmp, i;
507 // in case we call it a second time
508 codecs_uninit_free();
510 nr_vcodecs = 0;
511 nr_acodecs = 0;
513 if(cfgfile==NULL) {
514 #ifdef CODECS2HTML
515 return 0;
516 #else
517 video_codecs = builtin_video_codecs;
518 audio_codecs = builtin_audio_codecs;
519 nr_vcodecs = sizeof(builtin_video_codecs)/sizeof(codecs_t);
520 nr_acodecs = sizeof(builtin_audio_codecs)/sizeof(codecs_t);
521 return 1;
522 #endif
525 mp_tmsg(MSGT_CODECCFG,MSGL_V,"Reading %s: ", cfgfile);
527 if ((fp = fopen(cfgfile, "r")) == NULL) {
528 mp_tmsg(MSGT_CODECCFG,MSGL_V,"Can't open '%s': %s\n", cfgfile, strerror(errno));
529 return 0;
532 if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) {
533 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't get memory for 'line': %s\n", strerror(errno));
534 return 0;
536 read_nextline = 1;
539 * this only catches release lines at the start of
540 * codecs.conf, before audiocodecs and videocodecs.
542 while ((tmp = get_token(1, 1)) == RET_EOL)
543 /* NOTHING */;
544 if (tmp == RET_EOF)
545 goto out;
546 if (!strcmp(token[0], "release")) {
547 if (get_token(1, 2) < 0)
548 goto err_out_parse_error;
549 tmp = atoi(token[0]);
550 if (tmp < CODEC_CFG_MIN)
551 goto err_out_release_num;
552 while ((tmp = get_token(1, 1)) == RET_EOL)
553 /* NOTHING */;
554 if (tmp == RET_EOF)
555 goto out;
556 } else
557 goto err_out_release_num;
560 * check if the next block starts with 'audiocodec' or
561 * with 'videocodec'
563 if (!strcmp(token[0], "audiocodec") || !strcmp(token[0], "videocodec"))
564 goto loop_enter;
565 goto err_out_parse_error;
567 while ((tmp = get_token(1, 1)) != RET_EOF) {
568 if (tmp == RET_EOL)
569 continue;
570 if (!strcmp(token[0], "audiocodec") ||
571 !strcmp(token[0], "videocodec")) {
572 if (!validate_codec(codec, codec_type))
573 goto err_out_not_valid;
574 loop_enter:
575 if (*token[0] == 'v') {
576 codec_type = TYPE_VIDEO;
577 nr_codecsp = &nr_vcodecs;
578 codecsp = &video_codecs;
579 } else if (*token[0] == 'a') {
580 codec_type = TYPE_AUDIO;
581 nr_codecsp = &nr_acodecs;
582 codecsp = &audio_codecs;
583 #ifdef DEBUG
584 } else {
585 mp_msg(MSGT_CODECCFG,MSGL_ERR,"picsba\n");
586 goto err_out;
587 #endif
589 if (!(*codecsp = realloc(*codecsp,
590 sizeof(codecs_t) * (*nr_codecsp + 2)))) {
591 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't realloc '*codecsp': %s\n", strerror(errno));
592 goto err_out;
594 codec=*codecsp + *nr_codecsp;
595 ++*nr_codecsp;
596 memset(codec,0,sizeof(codecs_t));
597 memset(codec->fourcc, 0xff, sizeof(codec->fourcc));
598 memset(codec->outfmt, 0xff, sizeof(codec->outfmt));
599 memset(codec->infmt, 0xff, sizeof(codec->infmt));
601 if (get_token(1, 1) < 0)
602 goto err_out_parse_error;
603 for (i = 0; i < *nr_codecsp - 1; i++) {
604 if(( (*codecsp)[i].name!=NULL) &&
605 (!strcmp(token[0], (*codecsp)[i].name)) ) {
606 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Codec name '%s' isn't unique.", token[0]);
607 goto err_out_print_linenum;
610 if (!(codec->name = strdup(token[0]))) {
611 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'name': %s\n", strerror(errno));
612 goto err_out;
614 } else if (!strcmp(token[0], "info")) {
615 if (codec->info || get_token(1, 1) < 0)
616 goto err_out_parse_error;
617 if (!(codec->info = strdup(token[0]))) {
618 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'info': %s\n", strerror(errno));
619 goto err_out;
621 } else if (!strcmp(token[0], "comment")) {
622 if (get_token(1, 1) < 0)
623 goto err_out_parse_error;
624 add_comment(token[0], &codec->comment);
625 } else if (!strcmp(token[0], "fourcc")) {
626 if (get_token(1, 2) < 0)
627 goto err_out_parse_error;
628 if (!add_to_fourcc(token[0], token[1],
629 codec->fourcc,
630 codec->fourccmap))
631 goto err_out_print_linenum;
632 } else if (!strcmp(token[0], "format")) {
633 if (get_token(1, 2) < 0)
634 goto err_out_parse_error;
635 if (!add_to_format(token[0], token[1],
636 codec->fourcc,codec->fourccmap))
637 goto err_out_print_linenum;
638 } else if (!strcmp(token[0], "driver")) {
639 if (get_token(1, 1) < 0)
640 goto err_out_parse_error;
641 if (!(codec->drv = strdup(token[0]))) {
642 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'driver': %s\n", strerror(errno));
643 goto err_out;
645 } else if (!strcmp(token[0], "dll")) {
646 if (get_token(1, 1) < 0)
647 goto err_out_parse_error;
648 if (!(codec->dll = strdup(token[0]))) {
649 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'dll': %s", strerror(errno));
650 goto err_out;
652 } else if (!strcmp(token[0], "guid")) {
653 if (get_token(11, 11) < 0)
654 goto err_out_parse_error;
655 codec->guid.f1=strtoul(token[0],&endptr,0);
656 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
657 *endptr != '\0')
658 goto err_out_parse_error;
659 codec->guid.f2=strtoul(token[1],&endptr,0);
660 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
661 *endptr != '\0')
662 goto err_out_parse_error;
663 codec->guid.f3=strtoul(token[2],&endptr,0);
664 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
665 *endptr != '\0')
666 goto err_out_parse_error;
667 for (i = 0; i < 8; i++) {
668 codec->guid.f4[i]=strtoul(token[i + 3],&endptr,0);
669 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
670 *endptr != '\0')
671 goto err_out_parse_error;
673 } else if (!strcmp(token[0], "out")) {
674 if (get_token(1, 2) < 0)
675 goto err_out_parse_error;
676 if (!add_to_inout(token[0], token[1], codec->outfmt,
677 codec->outflags))
678 goto err_out_print_linenum;
679 } else if (!strcmp(token[0], "in")) {
680 if (get_token(1, 2) < 0)
681 goto err_out_parse_error;
682 if (!add_to_inout(token[0], token[1], codec->infmt,
683 codec->inflags))
684 goto err_out_print_linenum;
685 } else if (!strcmp(token[0], "flags")) {
686 if (get_token(1, 1) < 0)
687 goto err_out_parse_error;
688 if (!strcmp(token[0], "seekable"))
689 codec->flags |= CODECS_FLAG_SEEKABLE;
690 else
691 if (!strcmp(token[0], "align16"))
692 codec->flags |= CODECS_FLAG_ALIGN16;
693 else
694 goto err_out_parse_error;
695 } else if (!strcmp(token[0], "status")) {
696 if (get_token(1, 1) < 0)
697 goto err_out_parse_error;
698 if (!strcasecmp(token[0], "working"))
699 codec->status = CODECS_STATUS_WORKING;
700 else if (!strcasecmp(token[0], "crashing"))
701 codec->status = CODECS_STATUS_NOT_WORKING;
702 else if (!strcasecmp(token[0], "untested"))
703 codec->status = CODECS_STATUS_UNTESTED;
704 else if (!strcasecmp(token[0], "buggy"))
705 codec->status = CODECS_STATUS_PROBLEMS;
706 else
707 goto err_out_parse_error;
708 } else if (!strcmp(token[0], "cpuflags")) {
709 if (get_token(1, 1) < 0)
710 goto err_out_parse_error;
711 if (!(codec->cpuflags = get_cpuflags(token[0])))
712 goto err_out_parse_error;
713 } else
714 goto err_out_parse_error;
716 if (!validate_codec(codec, codec_type))
717 goto err_out_not_valid;
718 mp_tmsg(MSGT_CODECCFG,MSGL_INFO,"%d audio & %d video codecs\n", nr_acodecs, nr_vcodecs);
719 if(video_codecs) video_codecs[nr_vcodecs].name = NULL;
720 if(audio_codecs) audio_codecs[nr_acodecs].name = NULL;
721 out:
722 free(line);
723 line=NULL;
724 fclose(fp);
725 return 1;
727 err_out_parse_error:
728 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
729 err_out_print_linenum:
730 PRINT_LINENUM;
731 err_out:
732 codecs_uninit_free();
734 free(line);
735 line=NULL;
736 line_num = 0;
737 fclose(fp);
738 return 0;
739 err_out_not_valid:
740 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Codec is not defined correctly.");
741 goto err_out_print_linenum;
742 err_out_release_num:
743 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"This codecs.conf is too old and incompatible with this MPlayer release!");
744 goto err_out_print_linenum;
747 static void codecs_free(codecs_t* codecs,int count) {
748 int i;
749 for ( i = 0; i < count; i++)
750 if ( codecs[i].name ) {
751 if( codecs[i].name )
752 free(codecs[i].name);
753 if( codecs[i].info )
754 free(codecs[i].info);
755 if( codecs[i].comment )
756 free(codecs[i].comment);
757 if( codecs[i].dll )
758 free(codecs[i].dll);
759 if( codecs[i].drv )
760 free(codecs[i].drv);
762 if (codecs)
763 free(codecs);
766 void codecs_uninit_free(void) {
767 if (video_codecs)
768 codecs_free(video_codecs,nr_vcodecs);
769 video_codecs=NULL;
770 if (audio_codecs)
771 codecs_free(audio_codecs,nr_acodecs);
772 audio_codecs=NULL;
775 codecs_t *find_audio_codec(unsigned int fourcc, unsigned int *fourccmap,
776 codecs_t *start, int force)
778 return find_codec(fourcc, fourccmap, start, 1, force);
781 codecs_t *find_video_codec(unsigned int fourcc, unsigned int *fourccmap,
782 codecs_t *start, int force)
784 return find_codec(fourcc, fourccmap, start, 0, force);
787 codecs_t* find_codec(unsigned int fourcc,unsigned int *fourccmap,
788 codecs_t *start, int audioflag, int force)
790 int i, j;
791 codecs_t *c;
793 #if 0
794 if (start) {
795 for (/* NOTHING */; start->name; start++) {
796 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
797 if (start->fourcc[j] == fourcc) {
798 if (fourccmap)
799 *fourccmap = start->fourccmap[j];
800 return start;
804 } else
805 #endif
807 if (audioflag) {
808 i = nr_acodecs;
809 c = audio_codecs;
810 } else {
811 i = nr_vcodecs;
812 c = video_codecs;
814 if(!i) return NULL;
815 for (/* NOTHING */; i--; c++) {
816 if(start && c<=start) continue;
817 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
818 // FIXME: do NOT hardwire 'null' name here:
819 if (c->fourcc[j]==fourcc || !strcmp(c->drv,"null")) {
820 if (fourccmap)
821 *fourccmap = c->fourccmap[j];
822 return c;
825 if (force) return c;
828 return NULL;
831 void stringset_init(stringset_t *set) {
832 *set = calloc(1, sizeof(char *));
835 void stringset_free(stringset_t *set) {
836 int count = 0;
837 while ((*set)[count]) free((*set)[count++]);
838 free(*set);
839 *set = NULL;
842 void stringset_add(stringset_t *set, const char *str) {
843 int count = 0;
844 while ((*set)[count]) count++;
845 count++;
846 *set = realloc(*set, sizeof(char *) * (count + 1));
847 (*set)[count - 1] = strdup(str);
848 (*set)[count] = NULL;
851 int stringset_test(stringset_t *set, const char *str) {
852 stringset_t s;
853 for (s = *set; *s; s++)
854 if (strcmp(*s, str) == 0)
855 return 1;
856 return 0;
859 void list_codecs(int audioflag){
860 int i;
861 codecs_t *c;
863 if (audioflag) {
864 i = nr_acodecs;
865 c = audio_codecs;
866 mp_msg(MSGT_CODECCFG,MSGL_INFO,"ac: afm: status: info: [lib/dll]\n");
867 } else {
868 i = nr_vcodecs;
869 c = video_codecs;
870 mp_msg(MSGT_CODECCFG,MSGL_INFO,"vc: vfm: status: info: [lib/dll]\n");
872 if(!i) return;
873 for (/* NOTHING */; i--; c++) {
874 char* s="unknown ";
875 switch(c->status){
876 case CODECS_STATUS_WORKING: s="working ";break;
877 case CODECS_STATUS_PROBLEMS: s="problems";break;
878 case CODECS_STATUS_NOT_WORKING: s="crashing";break;
879 case CODECS_STATUS_UNTESTED: s="untested";break;
881 if(c->dll)
882 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s [%s]\n",c->name,c->drv,s,c->info,c->dll);
883 else
884 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s\n",c->name,c->drv,s,c->info);
892 #ifdef CODECS2HTML
893 void wrapline(FILE *f2,char *s){
894 int c;
895 if(!s){
896 fprintf(f2,"-");
897 return;
899 while((c=*s++)){
900 if(c==',') fprintf(f2,"<br>"); else fputc(c,f2);
904 void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
905 int c,d;
906 while((c=fgetc(f1))>=0){
907 if(c!='%'){
908 fputc(c,f2);
909 continue;
911 d=fgetc(f1);
913 switch(d){
914 case '.':
915 return; // end of section
916 case 'n':
917 wrapline(f2,codec->name); break;
918 case 'i':
919 wrapline(f2,codec->info); break;
920 case 'c':
921 wrapline(f2,codec->comment); break;
922 case 'd':
923 wrapline(f2,codec->dll); break;
924 case 'D':
925 fprintf(f2,"%c",!strcmp(codec->drv,"dshow")?'+':'-'); break;
926 case 'F':
927 for(d=0;d<CODECS_MAX_FOURCC;d++)
928 if(!d || codec->fourcc[d]!=0xFFFFFFFF)
929 fprintf(f2,"%s%.4s",d?"<br>":"",(codec->fourcc[d]==0xFFFFFFFF || codec->fourcc[d]<0x20202020)?!d?"-":"":(char*) &codec->fourcc[d]);
930 break;
931 case 'f':
932 for(d=0;d<CODECS_MAX_FOURCC;d++)
933 if(codec->fourcc[d]!=0xFFFFFFFF)
934 fprintf(f2,"%s0x%X",d?"<br>":"",codec->fourcc[d]);
935 break;
936 case 'Y':
937 for(d=0;d<CODECS_MAX_OUTFMT;d++)
938 if(codec->outfmt[d]!=0xFFFFFFFF){
939 for (c=0; fmt_table[c].name; c++)
940 if(fmt_table[c].num==codec->outfmt[d]) break;
941 if(fmt_table[c].name)
942 fprintf(f2,"%s%s",d?"<br>":"",fmt_table[c].name);
944 break;
945 default:
946 fputc(c,f2);
947 fputc(d,f2);
953 void skiphtml(FILE *f1){
954 int c,d;
955 while((c=fgetc(f1))>=0){
956 if(c!='%'){
957 continue;
959 d=fgetc(f1);
960 if(d=='.') return; // end of section
964 static void print_int_array(const unsigned int* a, int size)
966 printf("{ ");
967 while (size--)
968 if(abs(*a)<256)
969 printf("%d%s", *a++, size?", ":"");
970 else
971 printf("0x%X%s", *a++, size?", ":"");
972 printf(" }");
975 static void print_char_array(const unsigned char* a, int size)
977 printf("{ ");
978 while (size--)
979 if((*a)<10)
980 printf("%d%s", *a++, size?", ":"");
981 else
982 printf("0x%02x%s", *a++, size?", ":"");
983 printf(" }");
986 static void print_string(const char* s)
988 if (!s) printf("NULL");
989 else printf("\"%s\"", s);
992 int main(int argc, char* argv[])
994 codecs_t *cl;
995 FILE *f1;
996 FILE *f2;
997 int c,d,i;
998 int pos;
999 int section=-1;
1000 int nr_codecs;
1001 int win32=-1;
1002 int dshow=-1;
1003 int win32ex=-1;
1006 * Take path to codecs.conf from command line, or fall back on
1007 * etc/codecs.conf
1009 if (!(nr_codecs = parse_codec_cfg((argc>1)?argv[1]:"etc/codecs.conf")))
1010 exit(1);
1012 if (argc > 1) {
1013 int i, j;
1014 const char* nm[2];
1015 codecs_t* cod[2];
1016 int nr[2];
1018 nm[0] = "builtin_video_codecs";
1019 cod[0] = video_codecs;
1020 nr[0] = nr_vcodecs;
1022 nm[1] = "builtin_audio_codecs";
1023 cod[1] = audio_codecs;
1024 nr[1] = nr_acodecs;
1026 printf("/* GENERATED FROM %s, DO NOT EDIT! */\n\n",argv[1]);
1027 printf("#include <stddef.h>\n");
1028 printf("#include \"codec-cfg.h\"\n\n");
1030 for (i=0; i<2; i++) {
1031 printf("const codecs_t %s[] = {\n", nm[i]);
1032 for (j = 0; j < nr[i]; j++) {
1033 printf("{");
1035 print_int_array(cod[i][j].fourcc, CODECS_MAX_FOURCC);
1036 printf(", /* fourcc */\n");
1038 print_int_array(cod[i][j].fourccmap, CODECS_MAX_FOURCC);
1039 printf(", /* fourccmap */\n");
1041 print_int_array(cod[i][j].outfmt, CODECS_MAX_OUTFMT);
1042 printf(", /* outfmt */\n");
1044 print_char_array(cod[i][j].outflags, CODECS_MAX_OUTFMT);
1045 printf(", /* outflags */\n");
1047 print_int_array(cod[i][j].infmt, CODECS_MAX_INFMT);
1048 printf(", /* infmt */\n");
1050 print_char_array(cod[i][j].inflags, CODECS_MAX_INFMT);
1051 printf(", /* inflags */\n");
1053 print_string(cod[i][j].name); printf(", /* name */\n");
1054 print_string(cod[i][j].info); printf(", /* info */\n");
1055 print_string(cod[i][j].comment); printf(", /* comment */\n");
1056 print_string(cod[i][j].dll); printf(", /* dll */\n");
1057 print_string(cod[i][j].drv); printf(", /* drv */\n");
1059 printf("{ 0x%08lx, %hu, %hu,",
1060 cod[i][j].guid.f1,
1061 cod[i][j].guid.f2,
1062 cod[i][j].guid.f3);
1063 print_char_array(cod[i][j].guid.f4, sizeof(cod[i][j].guid.f4));
1064 printf(" }, /* GUID */\n");
1065 printf("%hd /* flags */, %hd /* status */, %hd /* cpuflags */ }\n",
1066 cod[i][j].flags,
1067 cod[i][j].status,
1068 cod[i][j].cpuflags);
1069 if (j < nr[i]) printf(",\n");
1071 printf("};\n\n");
1073 exit(0);
1076 f1=fopen("DOCS/tech/codecs-in.html","rb"); if(!f1) exit(1);
1077 f2=fopen("DOCS/codecs-status.html","wb"); if(!f2) exit(1);
1079 while((c=fgetc(f1))>=0){
1080 if(c!='%'){
1081 fputc(c,f2);
1082 continue;
1084 d=fgetc(f1);
1085 if(d>='0' && d<='9'){
1086 // begin section
1087 section=d-'0';
1088 //printf("BEGIN %d\n",section);
1089 if(section>=5){
1090 // audio
1091 cl = audio_codecs;
1092 nr_codecs = nr_acodecs;
1093 dshow=7;win32=4;
1094 } else {
1095 // video
1096 cl = video_codecs;
1097 nr_codecs = nr_vcodecs;
1098 dshow=4;win32=2;win32ex=6;
1100 pos=ftell(f1);
1101 for(i=0;i<nr_codecs;i++){
1102 fseek(f1,pos,SEEK_SET);
1103 switch(section){
1104 case 0:
1105 case 5:
1106 if(cl[i].status==CODECS_STATUS_WORKING)
1107 // if(!(!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1108 parsehtml(f1,f2,&cl[i],section,dshow);
1109 break;
1110 #if 0
1111 case 1:
1112 case 6:
1113 if(cl[i].status==CODECS_STATUS_WORKING)
1114 if((!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1115 parsehtml(f1,f2,&cl[i],section,dshow);
1116 break;
1117 #endif
1118 case 2:
1119 case 7:
1120 if(cl[i].status==CODECS_STATUS_PROBLEMS)
1121 parsehtml(f1,f2,&cl[i],section,dshow);
1122 break;
1123 case 3:
1124 case 8:
1125 if(cl[i].status==CODECS_STATUS_NOT_WORKING)
1126 parsehtml(f1,f2,&cl[i],section,dshow);
1127 break;
1128 case 4:
1129 case 9:
1130 if(cl[i].status==CODECS_STATUS_UNTESTED)
1131 parsehtml(f1,f2,&cl[i],section,dshow);
1132 break;
1133 default:
1134 printf("Warning! unimplemented section: %d\n",section);
1137 fseek(f1,pos,SEEK_SET);
1138 skiphtml(f1);
1139 //void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
1141 continue;
1143 fputc(c,f2);
1144 fputc(d,f2);
1147 fclose(f2);
1148 fclose(f1);
1149 return 0;
1152 #endif
1154 #ifdef TESTING
1155 int main(void)
1157 codecs_t *c;
1158 int i,j, nr_codecs, state;
1160 if (!(parse_codec_cfg("etc/codecs.conf")))
1161 return 0;
1162 if (!video_codecs)
1163 printf("no videoconfig.\n");
1164 if (!audio_codecs)
1165 printf("no audioconfig.\n");
1167 printf("videocodecs:\n");
1168 c = video_codecs;
1169 nr_codecs = nr_vcodecs;
1170 state = 0;
1171 next:
1172 if (c) {
1173 printf("number of %scodecs: %d\n", state==0?"video":"audio",
1174 nr_codecs);
1175 for(i=0;i<nr_codecs;i++, c++){
1176 printf("\n============== %scodec %02d ===============\n",
1177 state==0?"video":"audio",i);
1178 printf("name='%s'\n",c->name);
1179 printf("info='%s'\n",c->info);
1180 printf("comment='%s'\n",c->comment);
1181 printf("dll='%s'\n",c->dll);
1182 /* printf("flags=%X driver=%d status=%d cpuflags=%d\n",
1183 c->flags, c->driver, c->status, c->cpuflags); */
1184 printf("flags=%X status=%d cpuflags=%d\n",
1185 c->flags, c->status, c->cpuflags);
1187 for(j=0;j<CODECS_MAX_FOURCC;j++){
1188 if(c->fourcc[j]!=0xFFFFFFFF){
1189 printf("fourcc %02d: %08X (%.4s) ===> %08X (%.4s)\n",j,c->fourcc[j],(char *) &c->fourcc[j],c->fourccmap[j],(char *) &c->fourccmap[j]);
1193 for(j=0;j<CODECS_MAX_OUTFMT;j++){
1194 if(c->outfmt[j]!=0xFFFFFFFF){
1195 printf("outfmt %02d: %08X (%.4s) flags: %d\n",j,c->outfmt[j],(char *) &c->outfmt[j],c->outflags[j]);
1199 for(j=0;j<CODECS_MAX_INFMT;j++){
1200 if(c->infmt[j]!=0xFFFFFFFF){
1201 printf("infmt %02d: %08X (%.4s) flags: %d\n",j,c->infmt[j],(char *) &c->infmt[j],c->inflags[j]);
1205 printf("GUID: %08lX %04X %04X",c->guid.f1,c->guid.f2,c->guid.f3);
1206 for(j=0;j<8;j++) printf(" %02X",c->guid.f4[j]);
1207 printf("\n");
1212 if (!state) {
1213 printf("audiocodecs:\n");
1214 c = audio_codecs;
1215 nr_codecs = nr_acodecs;
1216 state = 1;
1217 goto next;
1219 return 0;
1222 #endif