Support for multiple editions in Matroska
[mplayer.git] / codec-cfg.c
blob27e07c92ac935b4aee0199d919cfddbe720a87d6
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 {"444P", IMGFMT_444P},
159 {"422P", IMGFMT_422P},
160 {"411P", IMGFMT_411P},
161 {"Y800", IMGFMT_Y800},
162 {"Y8", IMGFMT_Y8},
164 {"YUY2", IMGFMT_YUY2},
165 {"UYVY", IMGFMT_UYVY},
166 {"YVYU", IMGFMT_YVYU},
168 {"RGB48LE", IMGFMT_RGB48LE},
169 {"RGB48BE", IMGFMT_RGB48BE},
170 {"RGB4", IMGFMT_RGB4},
171 {"RGB8", IMGFMT_RGB8},
172 {"RGB15", IMGFMT_RGB15},
173 {"RGB16", IMGFMT_RGB16},
174 {"RGB24", IMGFMT_RGB24},
175 {"RGB32", IMGFMT_RGB32},
176 {"BGR4", IMGFMT_BGR4},
177 {"BGR8", IMGFMT_BGR8},
178 {"BGR15", IMGFMT_BGR15},
179 {"BGR16", IMGFMT_BGR16},
180 {"BGR24", IMGFMT_BGR24},
181 {"BGR32", IMGFMT_BGR32},
182 {"RGB1", IMGFMT_RGB1},
183 {"BGR1", IMGFMT_BGR1},
185 {"MPES", IMGFMT_MPEGPES},
186 {"ZRMJPEGNI", IMGFMT_ZRMJPEGNI},
187 {"ZRMJPEGIT", IMGFMT_ZRMJPEGIT},
188 {"ZRMJPEGIB", IMGFMT_ZRMJPEGIB},
190 {"IDCT_MPEG2",IMGFMT_XVMC_IDCT_MPEG2},
191 {"MOCO_MPEG2",IMGFMT_XVMC_MOCO_MPEG2},
193 {"VDPAU_MPEG1",IMGFMT_VDPAU_MPEG1},
194 {"VDPAU_MPEG2",IMGFMT_VDPAU_MPEG2},
195 {"VDPAU_H264",IMGFMT_VDPAU_H264},
196 {"VDPAU_WMV3",IMGFMT_VDPAU_WMV3},
197 {"VDPAU_VC1",IMGFMT_VDPAU_VC1},
198 {"VDPAU_MPEG4",IMGFMT_VDPAU_MPEG4},
200 {NULL, 0}
204 static int add_to_inout(char *sfmt, char *sflags, unsigned int *outfmt,
205 unsigned char *outflags)
208 static char *flagstr[] = {
209 "flip",
210 "noflip",
211 "yuvhack",
212 "query",
213 "static",
214 NULL
217 int i, j, freeslots;
218 unsigned char flags;
220 for (i = 0; i < CODECS_MAX_OUTFMT && outfmt[i] != 0xffffffff; i++)
221 /* NOTHING */;
222 freeslots = CODECS_MAX_OUTFMT - i;
223 if (!freeslots)
224 goto err_out_too_many;
226 flags = 0;
227 if(sflags) {
228 do {
229 for (j = 0; flagstr[j] != NULL; j++)
230 if (!strncmp(sflags, flagstr[j],
231 strlen(flagstr[j])))
232 break;
233 if (flagstr[j] == NULL)
234 goto err_out_parse_error;
235 flags|=(1<<j);
236 sflags+=strlen(flagstr[j]);
237 } while (*(sflags++) == ',');
239 if (*(--sflags) != '\0')
240 goto err_out_parse_error;
243 do {
244 for (j = 0; fmt_table[j].name != NULL; j++)
245 if (!strncmp(sfmt, fmt_table[j].name, strlen(fmt_table[j].name)))
246 break;
247 if (fmt_table[j].name == NULL)
248 goto err_out_parse_error;
249 outfmt[i] = fmt_table[j].num;
250 outflags[i] = flags;
251 ++i;
252 sfmt+=strlen(fmt_table[j].name);
253 } while ((*(sfmt++) == ',') && --freeslots);
255 if (!freeslots)
256 goto err_out_too_many;
258 if (*(--sfmt) != '\0')
259 goto err_out_parse_error;
261 return 1;
262 err_out_too_many:
263 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"too many out...");
264 return 0;
265 err_out_parse_error:
266 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
267 return 0;
270 #if 0
271 static short get_driver(char *s,int audioflag)
273 static char *audiodrv[] = {
274 "null",
275 "mp3lib",
276 "pcm",
277 "libac3",
278 "acm",
279 "alaw",
280 "msgsm",
281 "dshow",
282 "dvdpcm",
283 "hwac3",
284 "libvorbis",
285 "ffmpeg",
286 "libmad",
287 "msadpcm",
288 "liba52",
289 "g72x",
290 "imaadpcm",
291 "dk4adpcm",
292 "dk3adpcm",
293 "roqaudio",
294 "faad",
295 "realaud",
296 "libdv",
297 NULL
299 static char *videodrv[] = {
300 "null",
301 "libmpeg2",
302 "vfw",
303 "dshow",
304 "ffmpeg",
305 "vfwex",
306 "raw",
307 "msrle",
308 "xanim",
309 "msvidc",
310 "fli",
311 "cinepak",
312 "qtrle",
313 "nuv",
314 "cyuv",
315 "qtsmc",
316 "ducktm1",
317 "roqvideo",
318 "qtrpza",
319 "mpng",
320 "ijpg",
321 "zlib",
322 "mpegpes",
323 "zrmjpeg",
324 "realvid",
325 "xvid",
326 "libdv",
327 NULL
329 char **drv=audioflag?audiodrv:videodrv;
330 int i;
332 for(i=0;drv[i];i++) if(!strcmp(s,drv[i])) return i;
334 return -1;
336 #endif
338 static int validate_codec(codecs_t *c, int type)
340 unsigned int i;
341 char *tmp_name = c->name;
343 for (i = 0; i < strlen(tmp_name) && isalnum(tmp_name[i]); i++)
344 /* NOTHING */;
346 if (i < strlen(tmp_name)) {
347 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) name is not valid!\n", c->name);
348 return 0;
351 if (!c->info)
352 c->info = strdup(c->name);
354 #if 0
355 if (c->fourcc[0] == 0xffffffff) {
356 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) does not have FourCC/format!\n", c->name);
357 return 0;
359 #endif
361 if (!c->drv) {
362 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) does not have a driver!\n", c->name);
363 return 0;
366 #if 0
367 #warning codec->driver == 4;... <- this should not be put in here...
368 #warning Where are they defined ????????????
369 if (!c->dll && (c->driver == 4 ||
370 (c->driver == 2 && type == TYPE_VIDEO))) {
371 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) needs a 'dll'!\n", c->name);
372 return 0;
374 #warning Can guid.f1 be 0? How does one know that it was not given?
375 // if (!(codec->flags & CODECS_FLAG_AUDIO) && codec->driver == 4)
377 if (type == TYPE_VIDEO)
378 if (c->outfmt[0] == 0xffffffff) {
379 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) needs an 'outfmt'!\n", c->name);
380 return 0;
382 #endif
383 return 1;
386 static int add_comment(char *s, char **d)
388 int pos;
390 if (!*d)
391 pos = 0;
392 else {
393 pos = strlen(*d);
394 (*d)[pos++] = '\n';
396 if (!(*d = realloc(*d, pos + strlen(s) + 1))) {
397 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't allocate memory for comment. ");
398 return 0;
400 strcpy(*d + pos, s);
401 return 1;
404 static short get_cpuflags(char *s)
406 static char *flagstr[] = {
407 "mmx",
408 "sse",
409 "3dnow",
410 NULL
412 int i;
413 short flags = 0;
415 do {
416 for (i = 0; flagstr[i]; i++)
417 if (!strncmp(s, flagstr[i], strlen(flagstr[i])))
418 break;
419 if (!flagstr[i])
420 goto err_out_parse_error;
421 flags |= 1<<i;
422 s += strlen(flagstr[i]);
423 } while (*(s++) == ',');
425 if (*(--s) != '\0')
426 goto err_out_parse_error;
428 return flags;
429 err_out_parse_error:
430 return 0;
433 static FILE *fp;
434 static int line_num = 0;
435 static char *line;
436 static char *token[MAX_NR_TOKEN];
437 static int read_nextline = 1;
439 static int get_token(int min, int max)
441 static int line_pos;
442 int i;
443 char c;
445 if (max >= MAX_NR_TOKEN) {
446 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"get_token(): max >= MAX_MR_TOKEN!");
447 goto out_eof;
450 memset(token, 0x00, sizeof(*token) * max);
452 if (read_nextline) {
453 if (!fgets(line, MAX_LINE_LEN, fp))
454 goto out_eof;
455 line_pos = 0;
456 ++line_num;
457 read_nextline = 0;
459 for (i = 0; i < max; i++) {
460 while (isspace(line[line_pos]))
461 ++line_pos;
462 if (line[line_pos] == '\0' || line[line_pos] == '#' ||
463 line[line_pos] == ';') {
464 read_nextline = 1;
465 if (i >= min)
466 goto out_ok;
467 goto out_eol;
469 token[i] = line + line_pos;
470 c = line[line_pos];
471 if (c == '"' || c == '\'') {
472 token[i]++;
473 while (line[++line_pos] != c && line[line_pos])
474 /* NOTHING */;
475 } else {
476 for (/* NOTHING */; !isspace(line[line_pos]) &&
477 line[line_pos]; line_pos++)
478 /* NOTHING */;
480 if (!line[line_pos]) {
481 read_nextline = 1;
482 if (i >= min - 1)
483 goto out_ok;
484 goto out_eol;
486 line[line_pos] = '\0';
487 line_pos++;
489 out_ok:
490 return i;
491 out_eof:
492 read_nextline = 1;
493 return RET_EOF;
494 out_eol:
495 return RET_EOL;
498 static codecs_t *video_codecs=NULL;
499 static codecs_t *audio_codecs=NULL;
500 static int nr_vcodecs = 0;
501 static int nr_acodecs = 0;
503 int parse_codec_cfg(const char *cfgfile)
505 codecs_t *codec = NULL; // current codec
506 codecs_t **codecsp = NULL;// points to audio_codecs or to video_codecs
507 char *endptr; // strtoul()...
508 int *nr_codecsp;
509 int codec_type; /* TYPE_VIDEO/TYPE_AUDIO */
510 int tmp, i;
512 // in case we call it a second time
513 codecs_uninit_free();
515 nr_vcodecs = 0;
516 nr_acodecs = 0;
518 if(cfgfile==NULL) {
519 #ifdef CODECS2HTML
520 return 0;
521 #else
522 video_codecs = builtin_video_codecs;
523 audio_codecs = builtin_audio_codecs;
524 nr_vcodecs = sizeof(builtin_video_codecs)/sizeof(codecs_t);
525 nr_acodecs = sizeof(builtin_audio_codecs)/sizeof(codecs_t);
526 return 1;
527 #endif
530 mp_tmsg(MSGT_CODECCFG,MSGL_V,"Reading %s: ", cfgfile);
532 if ((fp = fopen(cfgfile, "r")) == NULL) {
533 mp_tmsg(MSGT_CODECCFG,MSGL_V,"Can't open '%s': %s\n", cfgfile, strerror(errno));
534 return 0;
537 if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) {
538 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't get memory for 'line': %s\n", strerror(errno));
539 return 0;
541 read_nextline = 1;
544 * this only catches release lines at the start of
545 * codecs.conf, before audiocodecs and videocodecs.
547 while ((tmp = get_token(1, 1)) == RET_EOL)
548 /* NOTHING */;
549 if (tmp == RET_EOF)
550 goto out;
551 if (!strcmp(token[0], "release")) {
552 if (get_token(1, 2) < 0)
553 goto err_out_parse_error;
554 tmp = atoi(token[0]);
555 if (tmp < CODEC_CFG_MIN)
556 goto err_out_release_num;
557 while ((tmp = get_token(1, 1)) == RET_EOL)
558 /* NOTHING */;
559 if (tmp == RET_EOF)
560 goto out;
561 } else
562 goto err_out_release_num;
565 * check if the next block starts with 'audiocodec' or
566 * with 'videocodec'
568 if (!strcmp(token[0], "audiocodec") || !strcmp(token[0], "videocodec"))
569 goto loop_enter;
570 goto err_out_parse_error;
572 while ((tmp = get_token(1, 1)) != RET_EOF) {
573 if (tmp == RET_EOL)
574 continue;
575 if (!strcmp(token[0], "audiocodec") ||
576 !strcmp(token[0], "videocodec")) {
577 if (!validate_codec(codec, codec_type))
578 goto err_out_not_valid;
579 loop_enter:
580 if (*token[0] == 'v') {
581 codec_type = TYPE_VIDEO;
582 nr_codecsp = &nr_vcodecs;
583 codecsp = &video_codecs;
584 } else if (*token[0] == 'a') {
585 codec_type = TYPE_AUDIO;
586 nr_codecsp = &nr_acodecs;
587 codecsp = &audio_codecs;
588 #ifdef DEBUG
589 } else {
590 mp_msg(MSGT_CODECCFG,MSGL_ERR,"picsba\n");
591 goto err_out;
592 #endif
594 if (!(*codecsp = realloc(*codecsp,
595 sizeof(codecs_t) * (*nr_codecsp + 2)))) {
596 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't realloc '*codecsp': %s\n", strerror(errno));
597 goto err_out;
599 codec=*codecsp + *nr_codecsp;
600 ++*nr_codecsp;
601 memset(codec,0,sizeof(codecs_t));
602 memset(codec->fourcc, 0xff, sizeof(codec->fourcc));
603 memset(codec->outfmt, 0xff, sizeof(codec->outfmt));
604 memset(codec->infmt, 0xff, sizeof(codec->infmt));
606 if (get_token(1, 1) < 0)
607 goto err_out_parse_error;
608 for (i = 0; i < *nr_codecsp - 1; i++) {
609 if(( (*codecsp)[i].name!=NULL) &&
610 (!strcmp(token[0], (*codecsp)[i].name)) ) {
611 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Codec name '%s' isn't unique.", token[0]);
612 goto err_out_print_linenum;
615 if (!(codec->name = strdup(token[0]))) {
616 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'name': %s\n", strerror(errno));
617 goto err_out;
619 } else if (!strcmp(token[0], "info")) {
620 if (codec->info || get_token(1, 1) < 0)
621 goto err_out_parse_error;
622 if (!(codec->info = strdup(token[0]))) {
623 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'info': %s\n", strerror(errno));
624 goto err_out;
626 } else if (!strcmp(token[0], "comment")) {
627 if (get_token(1, 1) < 0)
628 goto err_out_parse_error;
629 add_comment(token[0], &codec->comment);
630 } else if (!strcmp(token[0], "fourcc")) {
631 if (get_token(1, 2) < 0)
632 goto err_out_parse_error;
633 if (!add_to_fourcc(token[0], token[1],
634 codec->fourcc,
635 codec->fourccmap))
636 goto err_out_print_linenum;
637 } else if (!strcmp(token[0], "format")) {
638 if (get_token(1, 2) < 0)
639 goto err_out_parse_error;
640 if (!add_to_format(token[0], token[1],
641 codec->fourcc,codec->fourccmap))
642 goto err_out_print_linenum;
643 } else if (!strcmp(token[0], "driver")) {
644 if (get_token(1, 1) < 0)
645 goto err_out_parse_error;
646 if (!(codec->drv = strdup(token[0]))) {
647 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'driver': %s\n", strerror(errno));
648 goto err_out;
650 } else if (!strcmp(token[0], "dll")) {
651 if (get_token(1, 1) < 0)
652 goto err_out_parse_error;
653 if (!(codec->dll = strdup(token[0]))) {
654 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'dll': %s", strerror(errno));
655 goto err_out;
657 } else if (!strcmp(token[0], "guid")) {
658 if (get_token(11, 11) < 0)
659 goto err_out_parse_error;
660 codec->guid.f1=strtoul(token[0],&endptr,0);
661 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
662 *endptr != '\0')
663 goto err_out_parse_error;
664 codec->guid.f2=strtoul(token[1],&endptr,0);
665 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
666 *endptr != '\0')
667 goto err_out_parse_error;
668 codec->guid.f3=strtoul(token[2],&endptr,0);
669 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
670 *endptr != '\0')
671 goto err_out_parse_error;
672 for (i = 0; i < 8; i++) {
673 codec->guid.f4[i]=strtoul(token[i + 3],&endptr,0);
674 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
675 *endptr != '\0')
676 goto err_out_parse_error;
678 } else if (!strcmp(token[0], "out")) {
679 if (get_token(1, 2) < 0)
680 goto err_out_parse_error;
681 if (!add_to_inout(token[0], token[1], codec->outfmt,
682 codec->outflags))
683 goto err_out_print_linenum;
684 } else if (!strcmp(token[0], "in")) {
685 if (get_token(1, 2) < 0)
686 goto err_out_parse_error;
687 if (!add_to_inout(token[0], token[1], codec->infmt,
688 codec->inflags))
689 goto err_out_print_linenum;
690 } else if (!strcmp(token[0], "flags")) {
691 if (get_token(1, 1) < 0)
692 goto err_out_parse_error;
693 if (!strcmp(token[0], "seekable"))
694 codec->flags |= CODECS_FLAG_SEEKABLE;
695 else
696 if (!strcmp(token[0], "align16"))
697 codec->flags |= CODECS_FLAG_ALIGN16;
698 else
699 goto err_out_parse_error;
700 } else if (!strcmp(token[0], "status")) {
701 if (get_token(1, 1) < 0)
702 goto err_out_parse_error;
703 if (!strcasecmp(token[0], "working"))
704 codec->status = CODECS_STATUS_WORKING;
705 else if (!strcasecmp(token[0], "crashing"))
706 codec->status = CODECS_STATUS_NOT_WORKING;
707 else if (!strcasecmp(token[0], "untested"))
708 codec->status = CODECS_STATUS_UNTESTED;
709 else if (!strcasecmp(token[0], "buggy"))
710 codec->status = CODECS_STATUS_PROBLEMS;
711 else
712 goto err_out_parse_error;
713 } else if (!strcmp(token[0], "cpuflags")) {
714 if (get_token(1, 1) < 0)
715 goto err_out_parse_error;
716 if (!(codec->cpuflags = get_cpuflags(token[0])))
717 goto err_out_parse_error;
718 } else
719 goto err_out_parse_error;
721 if (!validate_codec(codec, codec_type))
722 goto err_out_not_valid;
723 mp_tmsg(MSGT_CODECCFG,MSGL_INFO,"%d audio & %d video codecs\n", nr_acodecs, nr_vcodecs);
724 if(video_codecs) video_codecs[nr_vcodecs].name = NULL;
725 if(audio_codecs) audio_codecs[nr_acodecs].name = NULL;
726 out:
727 free(line);
728 line=NULL;
729 fclose(fp);
730 return 1;
732 err_out_parse_error:
733 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
734 err_out_print_linenum:
735 PRINT_LINENUM;
736 err_out:
737 codecs_uninit_free();
739 free(line);
740 line=NULL;
741 line_num = 0;
742 fclose(fp);
743 return 0;
744 err_out_not_valid:
745 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Codec is not defined correctly.");
746 goto err_out_print_linenum;
747 err_out_release_num:
748 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"This codecs.conf is too old and incompatible with this MPlayer release!");
749 goto err_out_print_linenum;
752 static void codecs_free(codecs_t* codecs,int count) {
753 int i;
754 for ( i = 0; i < count; i++)
755 if ( codecs[i].name ) {
756 if( codecs[i].name )
757 free(codecs[i].name);
758 if( codecs[i].info )
759 free(codecs[i].info);
760 if( codecs[i].comment )
761 free(codecs[i].comment);
762 if( codecs[i].dll )
763 free(codecs[i].dll);
764 if( codecs[i].drv )
765 free(codecs[i].drv);
767 if (codecs)
768 free(codecs);
771 void codecs_uninit_free(void) {
772 if (video_codecs)
773 codecs_free(video_codecs,nr_vcodecs);
774 video_codecs=NULL;
775 if (audio_codecs)
776 codecs_free(audio_codecs,nr_acodecs);
777 audio_codecs=NULL;
780 codecs_t *find_audio_codec(unsigned int fourcc, unsigned int *fourccmap,
781 codecs_t *start, int force)
783 return find_codec(fourcc, fourccmap, start, 1, force);
786 codecs_t *find_video_codec(unsigned int fourcc, unsigned int *fourccmap,
787 codecs_t *start, int force)
789 return find_codec(fourcc, fourccmap, start, 0, force);
792 codecs_t* find_codec(unsigned int fourcc,unsigned int *fourccmap,
793 codecs_t *start, int audioflag, int force)
795 int i, j;
796 codecs_t *c;
798 #if 0
799 if (start) {
800 for (/* NOTHING */; start->name; start++) {
801 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
802 if (start->fourcc[j] == fourcc) {
803 if (fourccmap)
804 *fourccmap = start->fourccmap[j];
805 return start;
809 } else
810 #endif
812 if (audioflag) {
813 i = nr_acodecs;
814 c = audio_codecs;
815 } else {
816 i = nr_vcodecs;
817 c = video_codecs;
819 if(!i) return NULL;
820 for (/* NOTHING */; i--; c++) {
821 if(start && c<=start) continue;
822 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
823 // FIXME: do NOT hardwire 'null' name here:
824 if (c->fourcc[j]==fourcc || !strcmp(c->drv,"null")) {
825 if (fourccmap)
826 *fourccmap = c->fourccmap[j];
827 return c;
830 if (force) return c;
833 return NULL;
836 void stringset_init(stringset_t *set) {
837 *set = calloc(1, sizeof(char *));
840 void stringset_free(stringset_t *set) {
841 int count = 0;
842 while ((*set)[count]) free((*set)[count++]);
843 free(*set);
844 *set = NULL;
847 void stringset_add(stringset_t *set, const char *str) {
848 int count = 0;
849 while ((*set)[count]) count++;
850 count++;
851 *set = realloc(*set, sizeof(char *) * (count + 1));
852 (*set)[count - 1] = strdup(str);
853 (*set)[count] = NULL;
856 int stringset_test(stringset_t *set, const char *str) {
857 stringset_t s;
858 for (s = *set; *s; s++)
859 if (strcmp(*s, str) == 0)
860 return 1;
861 return 0;
864 void list_codecs(int audioflag){
865 int i;
866 codecs_t *c;
868 if (audioflag) {
869 i = nr_acodecs;
870 c = audio_codecs;
871 mp_msg(MSGT_CODECCFG,MSGL_INFO,"ac: afm: status: info: [lib/dll]\n");
872 } else {
873 i = nr_vcodecs;
874 c = video_codecs;
875 mp_msg(MSGT_CODECCFG,MSGL_INFO,"vc: vfm: status: info: [lib/dll]\n");
877 if(!i) return;
878 for (/* NOTHING */; i--; c++) {
879 char* s="unknown ";
880 switch(c->status){
881 case CODECS_STATUS_WORKING: s="working ";break;
882 case CODECS_STATUS_PROBLEMS: s="problems";break;
883 case CODECS_STATUS_NOT_WORKING: s="crashing";break;
884 case CODECS_STATUS_UNTESTED: s="untested";break;
886 if(c->dll)
887 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s [%s]\n",c->name,c->drv,s,c->info,c->dll);
888 else
889 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s\n",c->name,c->drv,s,c->info);
897 #ifdef CODECS2HTML
898 void wrapline(FILE *f2,char *s){
899 int c;
900 if(!s){
901 fprintf(f2,"-");
902 return;
904 while((c=*s++)){
905 if(c==',') fprintf(f2,"<br>"); else fputc(c,f2);
909 void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
910 int c,d;
911 while((c=fgetc(f1))>=0){
912 if(c!='%'){
913 fputc(c,f2);
914 continue;
916 d=fgetc(f1);
918 switch(d){
919 case '.':
920 return; // end of section
921 case 'n':
922 wrapline(f2,codec->name); break;
923 case 'i':
924 wrapline(f2,codec->info); break;
925 case 'c':
926 wrapline(f2,codec->comment); break;
927 case 'd':
928 wrapline(f2,codec->dll); break;
929 case 'D':
930 fprintf(f2,"%c",!strcmp(codec->drv,"dshow")?'+':'-'); break;
931 case 'F':
932 for(d=0;d<CODECS_MAX_FOURCC;d++)
933 if(!d || codec->fourcc[d]!=0xFFFFFFFF)
934 fprintf(f2,"%s%.4s",d?"<br>":"",(codec->fourcc[d]==0xFFFFFFFF || codec->fourcc[d]<0x20202020)?!d?"-":"":(char*) &codec->fourcc[d]);
935 break;
936 case 'f':
937 for(d=0;d<CODECS_MAX_FOURCC;d++)
938 if(codec->fourcc[d]!=0xFFFFFFFF)
939 fprintf(f2,"%s0x%X",d?"<br>":"",codec->fourcc[d]);
940 break;
941 case 'Y':
942 for(d=0;d<CODECS_MAX_OUTFMT;d++)
943 if(codec->outfmt[d]!=0xFFFFFFFF){
944 for (c=0; fmt_table[c].name; c++)
945 if(fmt_table[c].num==codec->outfmt[d]) break;
946 if(fmt_table[c].name)
947 fprintf(f2,"%s%s",d?"<br>":"",fmt_table[c].name);
949 break;
950 default:
951 fputc(c,f2);
952 fputc(d,f2);
958 void skiphtml(FILE *f1){
959 int c,d;
960 while((c=fgetc(f1))>=0){
961 if(c!='%'){
962 continue;
964 d=fgetc(f1);
965 if(d=='.') return; // end of section
969 static void print_int_array(const unsigned int* a, int size)
971 printf("{ ");
972 while (size--)
973 if(abs(*a)<256)
974 printf("%d%s", *a++, size?", ":"");
975 else
976 printf("0x%X%s", *a++, size?", ":"");
977 printf(" }");
980 static void print_char_array(const unsigned char* a, int size)
982 printf("{ ");
983 while (size--)
984 if((*a)<10)
985 printf("%d%s", *a++, size?", ":"");
986 else
987 printf("0x%02x%s", *a++, size?", ":"");
988 printf(" }");
991 static void print_string(const char* s)
993 if (!s) printf("NULL");
994 else printf("\"%s\"", s);
997 int main(int argc, char* argv[])
999 codecs_t *cl;
1000 FILE *f1;
1001 FILE *f2;
1002 int c,d,i;
1003 int pos;
1004 int section=-1;
1005 int nr_codecs;
1006 int win32=-1;
1007 int dshow=-1;
1008 int win32ex=-1;
1011 * Take path to codecs.conf from command line, or fall back on
1012 * etc/codecs.conf
1014 if (!(nr_codecs = parse_codec_cfg((argc>1)?argv[1]:"etc/codecs.conf")))
1015 exit(1);
1017 if (argc > 1) {
1018 int i, j;
1019 const char* nm[2];
1020 codecs_t* cod[2];
1021 int nr[2];
1023 nm[0] = "builtin_video_codecs";
1024 cod[0] = video_codecs;
1025 nr[0] = nr_vcodecs;
1027 nm[1] = "builtin_audio_codecs";
1028 cod[1] = audio_codecs;
1029 nr[1] = nr_acodecs;
1031 printf("/* GENERATED FROM %s, DO NOT EDIT! */\n\n",argv[1]);
1032 printf("#include <stddef.h>\n");
1033 printf("#include \"codec-cfg.h\"\n\n");
1035 for (i=0; i<2; i++) {
1036 printf("const codecs_t %s[] = {\n", nm[i]);
1037 for (j = 0; j < nr[i]; j++) {
1038 printf("{");
1040 print_int_array(cod[i][j].fourcc, CODECS_MAX_FOURCC);
1041 printf(", /* fourcc */\n");
1043 print_int_array(cod[i][j].fourccmap, CODECS_MAX_FOURCC);
1044 printf(", /* fourccmap */\n");
1046 print_int_array(cod[i][j].outfmt, CODECS_MAX_OUTFMT);
1047 printf(", /* outfmt */\n");
1049 print_char_array(cod[i][j].outflags, CODECS_MAX_OUTFMT);
1050 printf(", /* outflags */\n");
1052 print_int_array(cod[i][j].infmt, CODECS_MAX_INFMT);
1053 printf(", /* infmt */\n");
1055 print_char_array(cod[i][j].inflags, CODECS_MAX_INFMT);
1056 printf(", /* inflags */\n");
1058 print_string(cod[i][j].name); printf(", /* name */\n");
1059 print_string(cod[i][j].info); printf(", /* info */\n");
1060 print_string(cod[i][j].comment); printf(", /* comment */\n");
1061 print_string(cod[i][j].dll); printf(", /* dll */\n");
1062 print_string(cod[i][j].drv); printf(", /* drv */\n");
1064 printf("{ 0x%08lx, %hu, %hu,",
1065 cod[i][j].guid.f1,
1066 cod[i][j].guid.f2,
1067 cod[i][j].guid.f3);
1068 print_char_array(cod[i][j].guid.f4, sizeof(cod[i][j].guid.f4));
1069 printf(" }, /* GUID */\n");
1070 printf("%hd /* flags */, %hd /* status */, %hd /* cpuflags */ }\n",
1071 cod[i][j].flags,
1072 cod[i][j].status,
1073 cod[i][j].cpuflags);
1074 if (j < nr[i]) printf(",\n");
1076 printf("};\n\n");
1078 exit(0);
1081 f1=fopen("DOCS/tech/codecs-in.html","rb"); if(!f1) exit(1);
1082 f2=fopen("DOCS/codecs-status.html","wb"); if(!f2) exit(1);
1084 while((c=fgetc(f1))>=0){
1085 if(c!='%'){
1086 fputc(c,f2);
1087 continue;
1089 d=fgetc(f1);
1090 if(d>='0' && d<='9'){
1091 // begin section
1092 section=d-'0';
1093 //printf("BEGIN %d\n",section);
1094 if(section>=5){
1095 // audio
1096 cl = audio_codecs;
1097 nr_codecs = nr_acodecs;
1098 dshow=7;win32=4;
1099 } else {
1100 // video
1101 cl = video_codecs;
1102 nr_codecs = nr_vcodecs;
1103 dshow=4;win32=2;win32ex=6;
1105 pos=ftell(f1);
1106 for(i=0;i<nr_codecs;i++){
1107 fseek(f1,pos,SEEK_SET);
1108 switch(section){
1109 case 0:
1110 case 5:
1111 if(cl[i].status==CODECS_STATUS_WORKING)
1112 // if(!(!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1113 parsehtml(f1,f2,&cl[i],section,dshow);
1114 break;
1115 #if 0
1116 case 1:
1117 case 6:
1118 if(cl[i].status==CODECS_STATUS_WORKING)
1119 if((!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1120 parsehtml(f1,f2,&cl[i],section,dshow);
1121 break;
1122 #endif
1123 case 2:
1124 case 7:
1125 if(cl[i].status==CODECS_STATUS_PROBLEMS)
1126 parsehtml(f1,f2,&cl[i],section,dshow);
1127 break;
1128 case 3:
1129 case 8:
1130 if(cl[i].status==CODECS_STATUS_NOT_WORKING)
1131 parsehtml(f1,f2,&cl[i],section,dshow);
1132 break;
1133 case 4:
1134 case 9:
1135 if(cl[i].status==CODECS_STATUS_UNTESTED)
1136 parsehtml(f1,f2,&cl[i],section,dshow);
1137 break;
1138 default:
1139 printf("Warning! unimplemented section: %d\n",section);
1142 fseek(f1,pos,SEEK_SET);
1143 skiphtml(f1);
1144 //void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
1146 continue;
1148 fputc(c,f2);
1149 fputc(d,f2);
1152 fclose(f2);
1153 fclose(f1);
1154 return 0;
1157 #endif
1159 #ifdef TESTING
1160 int main(void)
1162 codecs_t *c;
1163 int i,j, nr_codecs, state;
1165 if (!(parse_codec_cfg("etc/codecs.conf")))
1166 return 0;
1167 if (!video_codecs)
1168 printf("no videoconfig.\n");
1169 if (!audio_codecs)
1170 printf("no audioconfig.\n");
1172 printf("videocodecs:\n");
1173 c = video_codecs;
1174 nr_codecs = nr_vcodecs;
1175 state = 0;
1176 next:
1177 if (c) {
1178 printf("number of %scodecs: %d\n", state==0?"video":"audio",
1179 nr_codecs);
1180 for(i=0;i<nr_codecs;i++, c++){
1181 printf("\n============== %scodec %02d ===============\n",
1182 state==0?"video":"audio",i);
1183 printf("name='%s'\n",c->name);
1184 printf("info='%s'\n",c->info);
1185 printf("comment='%s'\n",c->comment);
1186 printf("dll='%s'\n",c->dll);
1187 /* printf("flags=%X driver=%d status=%d cpuflags=%d\n",
1188 c->flags, c->driver, c->status, c->cpuflags); */
1189 printf("flags=%X status=%d cpuflags=%d\n",
1190 c->flags, c->status, c->cpuflags);
1192 for(j=0;j<CODECS_MAX_FOURCC;j++){
1193 if(c->fourcc[j]!=0xFFFFFFFF){
1194 printf("fourcc %02d: %08X (%.4s) ===> %08X (%.4s)\n",j,c->fourcc[j],(char *) &c->fourcc[j],c->fourccmap[j],(char *) &c->fourccmap[j]);
1198 for(j=0;j<CODECS_MAX_OUTFMT;j++){
1199 if(c->outfmt[j]!=0xFFFFFFFF){
1200 printf("outfmt %02d: %08X (%.4s) flags: %d\n",j,c->outfmt[j],(char *) &c->outfmt[j],c->outflags[j]);
1204 for(j=0;j<CODECS_MAX_INFMT;j++){
1205 if(c->infmt[j]!=0xFFFFFFFF){
1206 printf("infmt %02d: %08X (%.4s) flags: %d\n",j,c->infmt[j],(char *) &c->infmt[j],c->inflags[j]);
1210 printf("GUID: %08lX %04X %04X",c->guid.f1,c->guid.f2,c->guid.f3);
1211 for(j=0;j<8;j++) printf(" %02X",c->guid.f4[j]);
1212 printf("\n");
1217 if (!state) {
1218 printf("audiocodecs:\n");
1219 c = audio_codecs;
1220 nr_codecs = nr_acodecs;
1221 state = 1;
1222 goto next;
1224 return 0;
1227 #endif