Merge remote branch 'mplayer/master'
[mplayer/glamo.git] / codec-cfg.c
blobba794f2cd38b7feabf9c350157bd307d04444257
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 const struct {
145 const char *name;
146 const unsigned int num;
147 } fmt_table[] = {
148 // note: due to parser deficiencies/simplicity, if one format
149 // name matches the beginning of another, the longer one _must_
150 // come first in this list.
151 {"YV12", IMGFMT_YV12},
152 {"I420", IMGFMT_I420},
153 {"IYUV", IMGFMT_IYUV},
154 {"NV12", IMGFMT_NV12},
155 {"NV21", IMGFMT_NV21},
156 {"YVU9", IMGFMT_YVU9},
157 {"IF09", IMGFMT_IF09},
158 {"444P16LE", IMGFMT_444P16_LE},
159 {"444P16BE", IMGFMT_444P16_BE},
160 {"422P16LE", IMGFMT_422P16_LE},
161 {"422P16BE", IMGFMT_422P16_BE},
162 {"420P16LE", IMGFMT_420P16_LE},
163 {"420P16BE", IMGFMT_420P16_BE},
164 {"444P16", IMGFMT_444P16},
165 {"422P16", IMGFMT_422P16},
166 {"420P16", IMGFMT_420P16},
167 {"420A", IMGFMT_420A},
168 {"444P", IMGFMT_444P},
169 {"422P", IMGFMT_422P},
170 {"411P", IMGFMT_411P},
171 {"440P", IMGFMT_440P},
172 {"Y800", IMGFMT_Y800},
173 {"Y8", IMGFMT_Y8},
175 {"YUY2", IMGFMT_YUY2},
176 {"UYVY", IMGFMT_UYVY},
177 {"YVYU", IMGFMT_YVYU},
179 {"RGB48LE", IMGFMT_RGB48LE},
180 {"RGB48BE", IMGFMT_RGB48BE},
181 {"RGB4", IMGFMT_RGB4},
182 {"RGB8", IMGFMT_RGB8},
183 {"RGB15", IMGFMT_RGB15},
184 {"RGB16", IMGFMT_RGB16},
185 {"RGB24", IMGFMT_RGB24},
186 {"RGB32", IMGFMT_RGB32},
187 {"BGR4", IMGFMT_BGR4},
188 {"BGR8", IMGFMT_BGR8},
189 {"BGR15", IMGFMT_BGR15},
190 {"BGR16", IMGFMT_BGR16},
191 {"BGR24", IMGFMT_BGR24},
192 {"BGR32", IMGFMT_BGR32},
193 {"RGB1", IMGFMT_RGB1},
194 {"BGR1", IMGFMT_BGR1},
196 {"MPES", IMGFMT_MPEGPES},
197 {"MPG4", IMGFMT_MPEG4},
198 {"ZRMJPEGNI", IMGFMT_ZRMJPEGNI},
199 {"ZRMJPEGIT", IMGFMT_ZRMJPEGIT},
200 {"ZRMJPEGIB", IMGFMT_ZRMJPEGIB},
202 {"IDCT_MPEG2",IMGFMT_XVMC_IDCT_MPEG2},
203 {"MOCO_MPEG2",IMGFMT_XVMC_MOCO_MPEG2},
205 {"VDPAU_MPEG1",IMGFMT_VDPAU_MPEG1},
206 {"VDPAU_MPEG2",IMGFMT_VDPAU_MPEG2},
207 {"VDPAU_H264",IMGFMT_VDPAU_H264},
208 {"VDPAU_WMV3",IMGFMT_VDPAU_WMV3},
209 {"VDPAU_VC1",IMGFMT_VDPAU_VC1},
210 {"VDPAU_MPEG4",IMGFMT_VDPAU_MPEG4},
212 {NULL, 0}
216 static int add_to_inout(char *sfmt, char *sflags, unsigned int *outfmt,
217 unsigned char *outflags)
220 static char *flagstr[] = {
221 "flip",
222 "noflip",
223 "yuvhack",
224 "query",
225 "static",
226 NULL
229 int i, j, freeslots;
230 unsigned char flags;
232 for (i = 0; i < CODECS_MAX_OUTFMT && outfmt[i] != 0xffffffff; i++)
233 /* NOTHING */;
234 freeslots = CODECS_MAX_OUTFMT - i;
235 if (!freeslots)
236 goto err_out_too_many;
238 flags = 0;
239 if(sflags) {
240 do {
241 for (j = 0; flagstr[j] != NULL; j++)
242 if (!strncmp(sflags, flagstr[j],
243 strlen(flagstr[j])))
244 break;
245 if (flagstr[j] == NULL)
246 goto err_out_parse_error;
247 flags|=(1<<j);
248 sflags+=strlen(flagstr[j]);
249 } while (*(sflags++) == ',');
251 if (*(--sflags) != '\0')
252 goto err_out_parse_error;
255 do {
256 for (j = 0; fmt_table[j].name != NULL; j++)
257 if (!strncmp(sfmt, fmt_table[j].name, strlen(fmt_table[j].name)))
258 break;
259 if (fmt_table[j].name == NULL)
260 goto err_out_parse_error;
261 outfmt[i] = fmt_table[j].num;
262 outflags[i] = flags;
263 ++i;
264 sfmt+=strlen(fmt_table[j].name);
265 } while ((*(sfmt++) == ',') && --freeslots);
267 if (!freeslots)
268 goto err_out_too_many;
270 if (*(--sfmt) != '\0')
271 goto err_out_parse_error;
273 return 1;
274 err_out_too_many:
275 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"too many out...");
276 return 0;
277 err_out_parse_error:
278 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
279 return 0;
282 #if 0
283 static short get_driver(char *s,int audioflag)
285 static char *audiodrv[] = {
286 "null",
287 "mp3lib",
288 "pcm",
289 "libac3",
290 "acm",
291 "alaw",
292 "msgsm",
293 "dshow",
294 "dvdpcm",
295 "hwac3",
296 "libvorbis",
297 "ffmpeg",
298 "libmad",
299 "msadpcm",
300 "liba52",
301 "g72x",
302 "imaadpcm",
303 "dk4adpcm",
304 "dk3adpcm",
305 "roqaudio",
306 "faad",
307 "realaud",
308 "libdv",
309 NULL
311 static char *videodrv[] = {
312 "null",
313 "libmpeg2",
314 "vfw",
315 "dshow",
316 "ffmpeg",
317 "vfwex",
318 "raw",
319 "msrle",
320 "xanim",
321 "msvidc",
322 "fli",
323 "cinepak",
324 "qtrle",
325 "nuv",
326 "cyuv",
327 "qtsmc",
328 "ducktm1",
329 "roqvideo",
330 "qtrpza",
331 "mpng",
332 "ijpg",
333 "zlib",
334 "mpegpes",
335 "zrmjpeg",
336 "realvid",
337 "xvid",
338 "libdv",
339 NULL
341 char **drv=audioflag?audiodrv:videodrv;
342 int i;
344 for(i=0;drv[i];i++) if(!strcmp(s,drv[i])) return i;
346 return -1;
348 #endif
350 static int validate_codec(codecs_t *c, int type)
352 unsigned int i;
353 char *tmp_name = c->name;
355 for (i = 0; i < strlen(tmp_name) && isalnum(tmp_name[i]); i++)
356 /* NOTHING */;
358 if (i < strlen(tmp_name)) {
359 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) name is not valid!\n", c->name);
360 return 0;
363 if (!c->info)
364 c->info = strdup(c->name);
366 #if 0
367 if (c->fourcc[0] == 0xffffffff) {
368 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) does not have FourCC/format!\n", c->name);
369 return 0;
371 #endif
373 if (!c->drv) {
374 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) does not have a driver!\n", c->name);
375 return 0;
378 #if 0
379 #warning codec->driver == 4;... <- this should not be put in here...
380 #warning Where are they defined ????????????
381 if (!c->dll && (c->driver == 4 ||
382 (c->driver == 2 && type == TYPE_VIDEO))) {
383 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) needs a 'dll'!\n", c->name);
384 return 0;
386 #warning Can guid.f1 be 0? How does one know that it was not given?
387 // if (!(codec->flags & CODECS_FLAG_AUDIO) && codec->driver == 4)
389 if (type == TYPE_VIDEO)
390 if (c->outfmt[0] == 0xffffffff) {
391 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) needs an 'outfmt'!\n", c->name);
392 return 0;
394 #endif
395 return 1;
398 static int add_comment(char *s, char **d)
400 int pos;
402 if (!*d)
403 pos = 0;
404 else {
405 pos = strlen(*d);
406 (*d)[pos++] = '\n';
408 if (!(*d = realloc(*d, pos + strlen(s) + 1))) {
409 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't allocate memory for comment. ");
410 return 0;
412 strcpy(*d + pos, s);
413 return 1;
416 static short get_cpuflags(char *s)
418 static char *flagstr[] = {
419 "mmx",
420 "sse",
421 "3dnow",
422 NULL
424 int i;
425 short flags = 0;
427 do {
428 for (i = 0; flagstr[i]; i++)
429 if (!strncmp(s, flagstr[i], strlen(flagstr[i])))
430 break;
431 if (!flagstr[i])
432 goto err_out_parse_error;
433 flags |= 1<<i;
434 s += strlen(flagstr[i]);
435 } while (*(s++) == ',');
437 if (*(--s) != '\0')
438 goto err_out_parse_error;
440 return flags;
441 err_out_parse_error:
442 return 0;
445 static FILE *fp;
446 static int line_num = 0;
447 static char *line;
448 static char *token[MAX_NR_TOKEN];
449 static int read_nextline = 1;
451 static int get_token(int min, int max)
453 static int line_pos;
454 int i;
455 char c;
457 if (max >= MAX_NR_TOKEN) {
458 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"get_token(): max >= MAX_MR_TOKEN!");
459 goto out_eof;
462 memset(token, 0x00, sizeof(*token) * max);
464 if (read_nextline) {
465 if (!fgets(line, MAX_LINE_LEN, fp))
466 goto out_eof;
467 line_pos = 0;
468 ++line_num;
469 read_nextline = 0;
471 for (i = 0; i < max; i++) {
472 while (isspace(line[line_pos]))
473 ++line_pos;
474 if (line[line_pos] == '\0' || line[line_pos] == '#' ||
475 line[line_pos] == ';') {
476 read_nextline = 1;
477 if (i >= min)
478 goto out_ok;
479 goto out_eol;
481 token[i] = line + line_pos;
482 c = line[line_pos];
483 if (c == '"' || c == '\'') {
484 token[i]++;
485 while (line[++line_pos] != c && line[line_pos])
486 /* NOTHING */;
487 } else {
488 for (/* NOTHING */; !isspace(line[line_pos]) &&
489 line[line_pos]; line_pos++)
490 /* NOTHING */;
492 if (!line[line_pos]) {
493 read_nextline = 1;
494 if (i >= min - 1)
495 goto out_ok;
496 goto out_eol;
498 line[line_pos] = '\0';
499 line_pos++;
501 out_ok:
502 return i;
503 out_eof:
504 read_nextline = 1;
505 return RET_EOF;
506 out_eol:
507 return RET_EOL;
510 static codecs_t *video_codecs=NULL;
511 static codecs_t *audio_codecs=NULL;
512 static int nr_vcodecs = 0;
513 static int nr_acodecs = 0;
515 int parse_codec_cfg(const char *cfgfile)
517 codecs_t *codec = NULL; // current codec
518 codecs_t **codecsp = NULL;// points to audio_codecs or to video_codecs
519 char *endptr; // strtoul()...
520 int *nr_codecsp;
521 int codec_type; /* TYPE_VIDEO/TYPE_AUDIO */
522 int tmp, i;
524 // in case we call it a second time
525 codecs_uninit_free();
527 nr_vcodecs = 0;
528 nr_acodecs = 0;
530 if(cfgfile==NULL) {
531 #ifdef CODECS2HTML
532 return 0;
533 #else
534 video_codecs = builtin_video_codecs;
535 audio_codecs = builtin_audio_codecs;
536 nr_vcodecs = sizeof(builtin_video_codecs)/sizeof(codecs_t);
537 nr_acodecs = sizeof(builtin_audio_codecs)/sizeof(codecs_t);
538 return 1;
539 #endif
542 mp_tmsg(MSGT_CODECCFG,MSGL_V,"Reading %s: ", cfgfile);
544 if ((fp = fopen(cfgfile, "r")) == NULL) {
545 mp_tmsg(MSGT_CODECCFG,MSGL_V,"Can't open '%s': %s\n", cfgfile, strerror(errno));
546 return 0;
549 if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) {
550 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't get memory for 'line': %s\n", strerror(errno));
551 return 0;
553 read_nextline = 1;
556 * this only catches release lines at the start of
557 * codecs.conf, before audiocodecs and videocodecs.
559 while ((tmp = get_token(1, 1)) == RET_EOL)
560 /* NOTHING */;
561 if (tmp == RET_EOF)
562 goto out;
563 if (!strcmp(token[0], "release")) {
564 if (get_token(1, 2) < 0)
565 goto err_out_parse_error;
566 tmp = atoi(token[0]);
567 if (tmp < CODEC_CFG_MIN)
568 goto err_out_release_num;
569 while ((tmp = get_token(1, 1)) == RET_EOL)
570 /* NOTHING */;
571 if (tmp == RET_EOF)
572 goto out;
573 } else
574 goto err_out_release_num;
577 * check if the next block starts with 'audiocodec' or
578 * with 'videocodec'
580 if (!strcmp(token[0], "audiocodec") || !strcmp(token[0], "videocodec"))
581 goto loop_enter;
582 goto err_out_parse_error;
584 while ((tmp = get_token(1, 1)) != RET_EOF) {
585 if (tmp == RET_EOL)
586 continue;
587 if (!strcmp(token[0], "audiocodec") ||
588 !strcmp(token[0], "videocodec")) {
589 if (!validate_codec(codec, codec_type))
590 goto err_out_not_valid;
591 loop_enter:
592 if (*token[0] == 'v') {
593 codec_type = TYPE_VIDEO;
594 nr_codecsp = &nr_vcodecs;
595 codecsp = &video_codecs;
596 } else if (*token[0] == 'a') {
597 codec_type = TYPE_AUDIO;
598 nr_codecsp = &nr_acodecs;
599 codecsp = &audio_codecs;
600 #ifdef DEBUG
601 } else {
602 mp_msg(MSGT_CODECCFG,MSGL_ERR,"picsba\n");
603 goto err_out;
604 #endif
606 if (!(*codecsp = realloc(*codecsp,
607 sizeof(codecs_t) * (*nr_codecsp + 2)))) {
608 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't realloc '*codecsp': %s\n", strerror(errno));
609 goto err_out;
611 codec=*codecsp + *nr_codecsp;
612 ++*nr_codecsp;
613 memset(codec,0,sizeof(codecs_t));
614 memset(codec->fourcc, 0xff, sizeof(codec->fourcc));
615 memset(codec->outfmt, 0xff, sizeof(codec->outfmt));
616 memset(codec->infmt, 0xff, sizeof(codec->infmt));
618 if (get_token(1, 1) < 0)
619 goto err_out_parse_error;
620 for (i = 0; i < *nr_codecsp - 1; i++) {
621 if(( (*codecsp)[i].name!=NULL) &&
622 (!strcmp(token[0], (*codecsp)[i].name)) ) {
623 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Codec name '%s' isn't unique.", token[0]);
624 goto err_out_print_linenum;
627 if (!(codec->name = strdup(token[0]))) {
628 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'name': %s\n", strerror(errno));
629 goto err_out;
631 } else if (!strcmp(token[0], "info")) {
632 if (codec->info || get_token(1, 1) < 0)
633 goto err_out_parse_error;
634 if (!(codec->info = strdup(token[0]))) {
635 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'info': %s\n", strerror(errno));
636 goto err_out;
638 } else if (!strcmp(token[0], "comment")) {
639 if (get_token(1, 1) < 0)
640 goto err_out_parse_error;
641 add_comment(token[0], &codec->comment);
642 } else if (!strcmp(token[0], "fourcc")) {
643 if (get_token(1, 2) < 0)
644 goto err_out_parse_error;
645 if (!add_to_fourcc(token[0], token[1],
646 codec->fourcc,
647 codec->fourccmap))
648 goto err_out_print_linenum;
649 } else if (!strcmp(token[0], "format")) {
650 if (get_token(1, 2) < 0)
651 goto err_out_parse_error;
652 if (!add_to_format(token[0], token[1],
653 codec->fourcc,codec->fourccmap))
654 goto err_out_print_linenum;
655 } else if (!strcmp(token[0], "driver")) {
656 if (get_token(1, 1) < 0)
657 goto err_out_parse_error;
658 if (!(codec->drv = strdup(token[0]))) {
659 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'driver': %s\n", strerror(errno));
660 goto err_out;
662 } else if (!strcmp(token[0], "dll")) {
663 if (get_token(1, 1) < 0)
664 goto err_out_parse_error;
665 if (!(codec->dll = strdup(token[0]))) {
666 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'dll': %s", strerror(errno));
667 goto err_out;
669 } else if (!strcmp(token[0], "guid")) {
670 if (get_token(11, 11) < 0)
671 goto err_out_parse_error;
672 codec->guid.f1=strtoul(token[0],&endptr,0);
673 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
674 *endptr != '\0')
675 goto err_out_parse_error;
676 codec->guid.f2=strtoul(token[1],&endptr,0);
677 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
678 *endptr != '\0')
679 goto err_out_parse_error;
680 codec->guid.f3=strtoul(token[2],&endptr,0);
681 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
682 *endptr != '\0')
683 goto err_out_parse_error;
684 for (i = 0; i < 8; i++) {
685 codec->guid.f4[i]=strtoul(token[i + 3],&endptr,0);
686 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
687 *endptr != '\0')
688 goto err_out_parse_error;
690 } else if (!strcmp(token[0], "out")) {
691 if (get_token(1, 2) < 0)
692 goto err_out_parse_error;
693 if (!add_to_inout(token[0], token[1], codec->outfmt,
694 codec->outflags))
695 goto err_out_print_linenum;
696 } else if (!strcmp(token[0], "in")) {
697 if (get_token(1, 2) < 0)
698 goto err_out_parse_error;
699 if (!add_to_inout(token[0], token[1], codec->infmt,
700 codec->inflags))
701 goto err_out_print_linenum;
702 } else if (!strcmp(token[0], "flags")) {
703 if (get_token(1, 1) < 0)
704 goto err_out_parse_error;
705 if (!strcmp(token[0], "seekable"))
706 codec->flags |= CODECS_FLAG_SEEKABLE;
707 else
708 if (!strcmp(token[0], "align16"))
709 codec->flags |= CODECS_FLAG_ALIGN16;
710 else
711 goto err_out_parse_error;
712 } else if (!strcmp(token[0], "status")) {
713 if (get_token(1, 1) < 0)
714 goto err_out_parse_error;
715 if (!strcasecmp(token[0], "working"))
716 codec->status = CODECS_STATUS_WORKING;
717 else if (!strcasecmp(token[0], "crashing"))
718 codec->status = CODECS_STATUS_NOT_WORKING;
719 else if (!strcasecmp(token[0], "untested"))
720 codec->status = CODECS_STATUS_UNTESTED;
721 else if (!strcasecmp(token[0], "buggy"))
722 codec->status = CODECS_STATUS_PROBLEMS;
723 else
724 goto err_out_parse_error;
725 } else if (!strcmp(token[0], "cpuflags")) {
726 if (get_token(1, 1) < 0)
727 goto err_out_parse_error;
728 if (!(codec->cpuflags = get_cpuflags(token[0])))
729 goto err_out_parse_error;
730 } else
731 goto err_out_parse_error;
733 if (!validate_codec(codec, codec_type))
734 goto err_out_not_valid;
735 mp_tmsg(MSGT_CODECCFG,MSGL_INFO,"%d audio & %d video codecs\n", nr_acodecs, nr_vcodecs);
736 if(video_codecs) video_codecs[nr_vcodecs].name = NULL;
737 if(audio_codecs) audio_codecs[nr_acodecs].name = NULL;
738 out:
739 free(line);
740 line=NULL;
741 fclose(fp);
742 return 1;
744 err_out_parse_error:
745 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
746 err_out_print_linenum:
747 PRINT_LINENUM;
748 err_out:
749 codecs_uninit_free();
751 free(line);
752 line=NULL;
753 line_num = 0;
754 fclose(fp);
755 return 0;
756 err_out_not_valid:
757 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Codec is not defined correctly.");
758 goto err_out_print_linenum;
759 err_out_release_num:
760 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"This codecs.conf is too old and incompatible with this MPlayer release!");
761 goto err_out_print_linenum;
764 static void codecs_free(codecs_t* codecs,int count) {
765 int i;
766 for ( i = 0; i < count; i++)
767 if ( codecs[i].name ) {
768 if( codecs[i].name )
769 free(codecs[i].name);
770 if( codecs[i].info )
771 free(codecs[i].info);
772 if( codecs[i].comment )
773 free(codecs[i].comment);
774 if( codecs[i].dll )
775 free(codecs[i].dll);
776 if( codecs[i].drv )
777 free(codecs[i].drv);
779 if (codecs)
780 free(codecs);
783 void codecs_uninit_free(void) {
784 if (video_codecs)
785 codecs_free(video_codecs,nr_vcodecs);
786 video_codecs=NULL;
787 if (audio_codecs)
788 codecs_free(audio_codecs,nr_acodecs);
789 audio_codecs=NULL;
792 codecs_t *find_audio_codec(unsigned int fourcc, unsigned int *fourccmap,
793 codecs_t *start, int force)
795 return find_codec(fourcc, fourccmap, start, 1, force);
798 codecs_t *find_video_codec(unsigned int fourcc, unsigned int *fourccmap,
799 codecs_t *start, int force)
801 return find_codec(fourcc, fourccmap, start, 0, force);
804 codecs_t* find_codec(unsigned int fourcc,unsigned int *fourccmap,
805 codecs_t *start, int audioflag, int force)
807 int i, j;
808 codecs_t *c;
810 #if 0
811 if (start) {
812 for (/* NOTHING */; start->name; start++) {
813 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
814 if (start->fourcc[j] == fourcc) {
815 if (fourccmap)
816 *fourccmap = start->fourccmap[j];
817 return start;
821 } else
822 #endif
824 if (audioflag) {
825 i = nr_acodecs;
826 c = audio_codecs;
827 } else {
828 i = nr_vcodecs;
829 c = video_codecs;
831 if(!i) return NULL;
832 for (/* NOTHING */; i--; c++) {
833 if(start && c<=start) continue;
834 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
835 // FIXME: do NOT hardwire 'null' name here:
836 if (c->fourcc[j]==fourcc || !strcmp(c->drv,"null")) {
837 if (fourccmap)
838 *fourccmap = c->fourccmap[j];
839 return c;
842 if (force) return c;
845 return NULL;
848 void stringset_init(stringset_t *set) {
849 *set = calloc(1, sizeof(char *));
852 void stringset_free(stringset_t *set) {
853 int count = 0;
854 while ((*set)[count]) free((*set)[count++]);
855 free(*set);
856 *set = NULL;
859 void stringset_add(stringset_t *set, const char *str) {
860 int count = 0;
861 while ((*set)[count]) count++;
862 count++;
863 *set = realloc(*set, sizeof(char *) * (count + 1));
864 (*set)[count - 1] = strdup(str);
865 (*set)[count] = NULL;
868 int stringset_test(stringset_t *set, const char *str) {
869 stringset_t s;
870 for (s = *set; *s; s++)
871 if (strcmp(*s, str) == 0)
872 return 1;
873 return 0;
876 void list_codecs(int audioflag){
877 int i;
878 codecs_t *c;
880 if (audioflag) {
881 i = nr_acodecs;
882 c = audio_codecs;
883 mp_msg(MSGT_CODECCFG,MSGL_INFO,"ac: afm: status: info: [lib/dll]\n");
884 } else {
885 i = nr_vcodecs;
886 c = video_codecs;
887 mp_msg(MSGT_CODECCFG,MSGL_INFO,"vc: vfm: status: info: [lib/dll]\n");
889 if(!i) return;
890 for (/* NOTHING */; i--; c++) {
891 char* s="unknown ";
892 switch(c->status){
893 case CODECS_STATUS_WORKING: s="working ";break;
894 case CODECS_STATUS_PROBLEMS: s="problems";break;
895 case CODECS_STATUS_NOT_WORKING: s="crashing";break;
896 case CODECS_STATUS_UNTESTED: s="untested";break;
898 if(c->dll)
899 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s [%s]\n",c->name,c->drv,s,c->info,c->dll);
900 else
901 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s\n",c->name,c->drv,s,c->info);
909 #ifdef CODECS2HTML
910 void wrapline(FILE *f2,char *s){
911 int c;
912 if(!s){
913 fprintf(f2,"-");
914 return;
916 while((c=*s++)){
917 if(c==',') fprintf(f2,"<br>"); else fputc(c,f2);
921 void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
922 int c,d;
923 while((c=fgetc(f1))>=0){
924 if(c!='%'){
925 fputc(c,f2);
926 continue;
928 d=fgetc(f1);
930 switch(d){
931 case '.':
932 return; // end of section
933 case 'n':
934 wrapline(f2,codec->name); break;
935 case 'i':
936 wrapline(f2,codec->info); break;
937 case 'c':
938 wrapline(f2,codec->comment); break;
939 case 'd':
940 wrapline(f2,codec->dll); break;
941 case 'D':
942 fprintf(f2,"%c",!strcmp(codec->drv,"dshow")?'+':'-'); break;
943 case 'F':
944 for(d=0;d<CODECS_MAX_FOURCC;d++)
945 if(!d || codec->fourcc[d]!=0xFFFFFFFF)
946 fprintf(f2,"%s%.4s",d?"<br>":"",(codec->fourcc[d]==0xFFFFFFFF || codec->fourcc[d]<0x20202020)?!d?"-":"":(char*) &codec->fourcc[d]);
947 break;
948 case 'f':
949 for(d=0;d<CODECS_MAX_FOURCC;d++)
950 if(codec->fourcc[d]!=0xFFFFFFFF)
951 fprintf(f2,"%s0x%X",d?"<br>":"",codec->fourcc[d]);
952 break;
953 case 'Y':
954 for(d=0;d<CODECS_MAX_OUTFMT;d++)
955 if(codec->outfmt[d]!=0xFFFFFFFF){
956 for (c=0; fmt_table[c].name; c++)
957 if(fmt_table[c].num==codec->outfmt[d]) break;
958 if(fmt_table[c].name)
959 fprintf(f2,"%s%s",d?"<br>":"",fmt_table[c].name);
961 break;
962 default:
963 fputc(c,f2);
964 fputc(d,f2);
970 void skiphtml(FILE *f1){
971 int c,d;
972 while((c=fgetc(f1))>=0){
973 if(c!='%'){
974 continue;
976 d=fgetc(f1);
977 if(d=='.') return; // end of section
981 static void print_int_array(const unsigned int* a, int size)
983 printf("{ ");
984 while (size--)
985 if(abs(*a)<256)
986 printf("%d%s", *a++, size?", ":"");
987 else
988 printf("0x%X%s", *a++, size?", ":"");
989 printf(" }");
992 static void print_char_array(const unsigned char* a, int size)
994 printf("{ ");
995 while (size--)
996 if((*a)<10)
997 printf("%d%s", *a++, size?", ":"");
998 else
999 printf("0x%02x%s", *a++, size?", ":"");
1000 printf(" }");
1003 static void print_string(const char* s)
1005 if (!s) printf("NULL");
1006 else printf("\"%s\"", s);
1009 int main(int argc, char* argv[])
1011 codecs_t *cl;
1012 FILE *f1;
1013 FILE *f2;
1014 int c,d,i;
1015 int pos;
1016 int section=-1;
1017 int nr_codecs;
1018 int win32=-1;
1019 int dshow=-1;
1020 int win32ex=-1;
1023 * Take path to codecs.conf from command line, or fall back on
1024 * etc/codecs.conf
1026 if (!(nr_codecs = parse_codec_cfg((argc>1)?argv[1]:"etc/codecs.conf")))
1027 exit(1);
1029 if (argc > 1) {
1030 int i, j;
1031 const char* nm[2];
1032 codecs_t* cod[2];
1033 int nr[2];
1035 nm[0] = "builtin_video_codecs";
1036 cod[0] = video_codecs;
1037 nr[0] = nr_vcodecs;
1039 nm[1] = "builtin_audio_codecs";
1040 cod[1] = audio_codecs;
1041 nr[1] = nr_acodecs;
1043 printf("/* GENERATED FROM %s, DO NOT EDIT! */\n\n",argv[1]);
1044 printf("#include <stddef.h>\n");
1045 printf("#include \"codec-cfg.h\"\n\n");
1047 for (i=0; i<2; i++) {
1048 printf("const codecs_t %s[] = {\n", nm[i]);
1049 for (j = 0; j < nr[i]; j++) {
1050 printf("{");
1052 print_int_array(cod[i][j].fourcc, CODECS_MAX_FOURCC);
1053 printf(", /* fourcc */\n");
1055 print_int_array(cod[i][j].fourccmap, CODECS_MAX_FOURCC);
1056 printf(", /* fourccmap */\n");
1058 print_int_array(cod[i][j].outfmt, CODECS_MAX_OUTFMT);
1059 printf(", /* outfmt */\n");
1061 print_char_array(cod[i][j].outflags, CODECS_MAX_OUTFMT);
1062 printf(", /* outflags */\n");
1064 print_int_array(cod[i][j].infmt, CODECS_MAX_INFMT);
1065 printf(", /* infmt */\n");
1067 print_char_array(cod[i][j].inflags, CODECS_MAX_INFMT);
1068 printf(", /* inflags */\n");
1070 print_string(cod[i][j].name); printf(", /* name */\n");
1071 print_string(cod[i][j].info); printf(", /* info */\n");
1072 print_string(cod[i][j].comment); printf(", /* comment */\n");
1073 print_string(cod[i][j].dll); printf(", /* dll */\n");
1074 print_string(cod[i][j].drv); printf(", /* drv */\n");
1076 printf("{ 0x%08lx, %hu, %hu,",
1077 cod[i][j].guid.f1,
1078 cod[i][j].guid.f2,
1079 cod[i][j].guid.f3);
1080 print_char_array(cod[i][j].guid.f4, sizeof(cod[i][j].guid.f4));
1081 printf(" }, /* GUID */\n");
1082 printf("%hd /* flags */, %hd /* status */, %hd /* cpuflags */ }\n",
1083 cod[i][j].flags,
1084 cod[i][j].status,
1085 cod[i][j].cpuflags);
1086 if (j < nr[i]) printf(",\n");
1088 printf("};\n\n");
1090 exit(0);
1093 f1=fopen("DOCS/tech/codecs-in.html","rb"); if(!f1) exit(1);
1094 f2=fopen("DOCS/codecs-status.html","wb"); if(!f2) exit(1);
1096 while((c=fgetc(f1))>=0){
1097 if(c!='%'){
1098 fputc(c,f2);
1099 continue;
1101 d=fgetc(f1);
1102 if(d>='0' && d<='9'){
1103 // begin section
1104 section=d-'0';
1105 //printf("BEGIN %d\n",section);
1106 if(section>=5){
1107 // audio
1108 cl = audio_codecs;
1109 nr_codecs = nr_acodecs;
1110 dshow=7;win32=4;
1111 } else {
1112 // video
1113 cl = video_codecs;
1114 nr_codecs = nr_vcodecs;
1115 dshow=4;win32=2;win32ex=6;
1117 pos=ftell(f1);
1118 for(i=0;i<nr_codecs;i++){
1119 fseek(f1,pos,SEEK_SET);
1120 switch(section){
1121 case 0:
1122 case 5:
1123 if(cl[i].status==CODECS_STATUS_WORKING)
1124 // if(!(!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1125 parsehtml(f1,f2,&cl[i],section,dshow);
1126 break;
1127 #if 0
1128 case 1:
1129 case 6:
1130 if(cl[i].status==CODECS_STATUS_WORKING)
1131 if((!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1132 parsehtml(f1,f2,&cl[i],section,dshow);
1133 break;
1134 #endif
1135 case 2:
1136 case 7:
1137 if(cl[i].status==CODECS_STATUS_PROBLEMS)
1138 parsehtml(f1,f2,&cl[i],section,dshow);
1139 break;
1140 case 3:
1141 case 8:
1142 if(cl[i].status==CODECS_STATUS_NOT_WORKING)
1143 parsehtml(f1,f2,&cl[i],section,dshow);
1144 break;
1145 case 4:
1146 case 9:
1147 if(cl[i].status==CODECS_STATUS_UNTESTED)
1148 parsehtml(f1,f2,&cl[i],section,dshow);
1149 break;
1150 default:
1151 printf("Warning! unimplemented section: %d\n",section);
1154 fseek(f1,pos,SEEK_SET);
1155 skiphtml(f1);
1156 //void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
1158 continue;
1160 fputc(c,f2);
1161 fputc(d,f2);
1164 fclose(f2);
1165 fclose(f1);
1166 return 0;
1169 #endif
1171 #ifdef TESTING
1172 int main(void)
1174 codecs_t *c;
1175 int i,j, nr_codecs, state;
1177 if (!(parse_codec_cfg("etc/codecs.conf")))
1178 return 0;
1179 if (!video_codecs)
1180 printf("no videoconfig.\n");
1181 if (!audio_codecs)
1182 printf("no audioconfig.\n");
1184 printf("videocodecs:\n");
1185 c = video_codecs;
1186 nr_codecs = nr_vcodecs;
1187 state = 0;
1188 next:
1189 if (c) {
1190 printf("number of %scodecs: %d\n", state==0?"video":"audio",
1191 nr_codecs);
1192 for(i=0;i<nr_codecs;i++, c++){
1193 printf("\n============== %scodec %02d ===============\n",
1194 state==0?"video":"audio",i);
1195 printf("name='%s'\n",c->name);
1196 printf("info='%s'\n",c->info);
1197 printf("comment='%s'\n",c->comment);
1198 printf("dll='%s'\n",c->dll);
1199 /* printf("flags=%X driver=%d status=%d cpuflags=%d\n",
1200 c->flags, c->driver, c->status, c->cpuflags); */
1201 printf("flags=%X status=%d cpuflags=%d\n",
1202 c->flags, c->status, c->cpuflags);
1204 for(j=0;j<CODECS_MAX_FOURCC;j++){
1205 if(c->fourcc[j]!=0xFFFFFFFF){
1206 printf("fourcc %02d: %08X (%.4s) ===> %08X (%.4s)\n",j,c->fourcc[j],(char *) &c->fourcc[j],c->fourccmap[j],(char *) &c->fourccmap[j]);
1210 for(j=0;j<CODECS_MAX_OUTFMT;j++){
1211 if(c->outfmt[j]!=0xFFFFFFFF){
1212 printf("outfmt %02d: %08X (%.4s) flags: %d\n",j,c->outfmt[j],(char *) &c->outfmt[j],c->outflags[j]);
1216 for(j=0;j<CODECS_MAX_INFMT;j++){
1217 if(c->infmt[j]!=0xFFFFFFFF){
1218 printf("infmt %02d: %08X (%.4s) flags: %d\n",j,c->infmt[j],(char *) &c->infmt[j],c->inflags[j]);
1222 printf("GUID: %08lX %04X %04X",c->guid.f1,c->guid.f2,c->guid.f3);
1223 for(j=0;j<8;j++) printf(" %02X",c->guid.f4[j]);
1224 printf("\n");
1229 if (!state) {
1230 printf("audiocodecs:\n");
1231 c = audio_codecs;
1232 nr_codecs = nr_acodecs;
1233 state = 1;
1234 goto next;
1236 return 0;
1239 #endif