Use SHGetSpecialFolderPath instead of %appdata%
[mplayer/kovensky.git] / codec-cfg.c
blob5a7b7c9d9b6e9bd09e65ecd637e007e99322782f
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 {"ZRMJPEGNI", IMGFMT_ZRMJPEGNI},
198 {"ZRMJPEGIT", IMGFMT_ZRMJPEGIT},
199 {"ZRMJPEGIB", IMGFMT_ZRMJPEGIB},
201 {"IDCT_MPEG2",IMGFMT_XVMC_IDCT_MPEG2},
202 {"MOCO_MPEG2",IMGFMT_XVMC_MOCO_MPEG2},
204 {"VDPAU_MPEG1",IMGFMT_VDPAU_MPEG1},
205 {"VDPAU_MPEG2",IMGFMT_VDPAU_MPEG2},
206 {"VDPAU_H264",IMGFMT_VDPAU_H264},
207 {"VDPAU_WMV3",IMGFMT_VDPAU_WMV3},
208 {"VDPAU_VC1",IMGFMT_VDPAU_VC1},
209 {"VDPAU_MPEG4",IMGFMT_VDPAU_MPEG4},
211 {NULL, 0}
215 static int add_to_inout(char *sfmt, char *sflags, unsigned int *outfmt,
216 unsigned char *outflags)
219 static char *flagstr[] = {
220 "flip",
221 "noflip",
222 "yuvhack",
223 "query",
224 "static",
225 NULL
228 int i, j, freeslots;
229 unsigned char flags;
231 for (i = 0; i < CODECS_MAX_OUTFMT && outfmt[i] != 0xffffffff; i++)
232 /* NOTHING */;
233 freeslots = CODECS_MAX_OUTFMT - i;
234 if (!freeslots)
235 goto err_out_too_many;
237 flags = 0;
238 if(sflags) {
239 do {
240 for (j = 0; flagstr[j] != NULL; j++)
241 if (!strncmp(sflags, flagstr[j],
242 strlen(flagstr[j])))
243 break;
244 if (flagstr[j] == NULL)
245 goto err_out_parse_error;
246 flags|=(1<<j);
247 sflags+=strlen(flagstr[j]);
248 } while (*(sflags++) == ',');
250 if (*(--sflags) != '\0')
251 goto err_out_parse_error;
254 do {
255 for (j = 0; fmt_table[j].name != NULL; j++)
256 if (!strncmp(sfmt, fmt_table[j].name, strlen(fmt_table[j].name)))
257 break;
258 if (fmt_table[j].name == NULL)
259 goto err_out_parse_error;
260 outfmt[i] = fmt_table[j].num;
261 outflags[i] = flags;
262 ++i;
263 sfmt+=strlen(fmt_table[j].name);
264 } while ((*(sfmt++) == ',') && --freeslots);
266 if (!freeslots)
267 goto err_out_too_many;
269 if (*(--sfmt) != '\0')
270 goto err_out_parse_error;
272 return 1;
273 err_out_too_many:
274 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"too many out...");
275 return 0;
276 err_out_parse_error:
277 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
278 return 0;
281 #if 0
282 static short get_driver(char *s,int audioflag)
284 static char *audiodrv[] = {
285 "null",
286 "mp3lib",
287 "pcm",
288 "libac3",
289 "acm",
290 "alaw",
291 "msgsm",
292 "dshow",
293 "dvdpcm",
294 "hwac3",
295 "libvorbis",
296 "ffmpeg",
297 "libmad",
298 "msadpcm",
299 "liba52",
300 "g72x",
301 "imaadpcm",
302 "dk4adpcm",
303 "dk3adpcm",
304 "roqaudio",
305 "faad",
306 "realaud",
307 "libdv",
308 NULL
310 static char *videodrv[] = {
311 "null",
312 "libmpeg2",
313 "vfw",
314 "dshow",
315 "ffmpeg",
316 "vfwex",
317 "raw",
318 "msrle",
319 "xanim",
320 "msvidc",
321 "fli",
322 "cinepak",
323 "qtrle",
324 "nuv",
325 "cyuv",
326 "qtsmc",
327 "ducktm1",
328 "roqvideo",
329 "qtrpza",
330 "mpng",
331 "ijpg",
332 "zlib",
333 "mpegpes",
334 "zrmjpeg",
335 "realvid",
336 "xvid",
337 "libdv",
338 NULL
340 char **drv=audioflag?audiodrv:videodrv;
341 int i;
343 for(i=0;drv[i];i++) if(!strcmp(s,drv[i])) return i;
345 return -1;
347 #endif
349 static int validate_codec(codecs_t *c, int type)
351 unsigned int i;
352 char *tmp_name = c->name;
354 for (i = 0; i < strlen(tmp_name) && isalnum(tmp_name[i]); i++)
355 /* NOTHING */;
357 if (i < strlen(tmp_name)) {
358 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) name is not valid!\n", c->name);
359 return 0;
362 if (!c->info)
363 c->info = strdup(c->name);
365 #if 0
366 if (c->fourcc[0] == 0xffffffff) {
367 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) does not have FourCC/format!\n", c->name);
368 return 0;
370 #endif
372 if (!c->drv) {
373 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) does not have a driver!\n", c->name);
374 return 0;
377 #if 0
378 #warning codec->driver == 4;... <- this should not be put in here...
379 #warning Where are they defined ????????????
380 if (!c->dll && (c->driver == 4 ||
381 (c->driver == 2 && type == TYPE_VIDEO))) {
382 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) needs a 'dll'!\n", c->name);
383 return 0;
385 #warning Can guid.f1 be 0? How does one know that it was not given?
386 // if (!(codec->flags & CODECS_FLAG_AUDIO) && codec->driver == 4)
388 if (type == TYPE_VIDEO)
389 if (c->outfmt[0] == 0xffffffff) {
390 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) needs an 'outfmt'!\n", c->name);
391 return 0;
393 #endif
394 return 1;
397 static int add_comment(char *s, char **d)
399 int pos;
401 if (!*d)
402 pos = 0;
403 else {
404 pos = strlen(*d);
405 (*d)[pos++] = '\n';
407 if (!(*d = realloc(*d, pos + strlen(s) + 1))) {
408 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't allocate memory for comment. ");
409 return 0;
411 strcpy(*d + pos, s);
412 return 1;
415 static short get_cpuflags(char *s)
417 static char *flagstr[] = {
418 "mmx",
419 "sse",
420 "3dnow",
421 NULL
423 int i;
424 short flags = 0;
426 do {
427 for (i = 0; flagstr[i]; i++)
428 if (!strncmp(s, flagstr[i], strlen(flagstr[i])))
429 break;
430 if (!flagstr[i])
431 goto err_out_parse_error;
432 flags |= 1<<i;
433 s += strlen(flagstr[i]);
434 } while (*(s++) == ',');
436 if (*(--s) != '\0')
437 goto err_out_parse_error;
439 return flags;
440 err_out_parse_error:
441 return 0;
444 static FILE *fp;
445 static int line_num = 0;
446 static char *line;
447 static char *token[MAX_NR_TOKEN];
448 static int read_nextline = 1;
450 static int get_token(int min, int max)
452 static int line_pos;
453 int i;
454 char c;
456 if (max >= MAX_NR_TOKEN) {
457 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"get_token(): max >= MAX_MR_TOKEN!");
458 goto out_eof;
461 memset(token, 0x00, sizeof(*token) * max);
463 if (read_nextline) {
464 if (!fgets(line, MAX_LINE_LEN, fp))
465 goto out_eof;
466 line_pos = 0;
467 ++line_num;
468 read_nextline = 0;
470 for (i = 0; i < max; i++) {
471 while (isspace(line[line_pos]))
472 ++line_pos;
473 if (line[line_pos] == '\0' || line[line_pos] == '#' ||
474 line[line_pos] == ';') {
475 read_nextline = 1;
476 if (i >= min)
477 goto out_ok;
478 goto out_eol;
480 token[i] = line + line_pos;
481 c = line[line_pos];
482 if (c == '"' || c == '\'') {
483 token[i]++;
484 while (line[++line_pos] != c && line[line_pos])
485 /* NOTHING */;
486 } else {
487 for (/* NOTHING */; !isspace(line[line_pos]) &&
488 line[line_pos]; line_pos++)
489 /* NOTHING */;
491 if (!line[line_pos]) {
492 read_nextline = 1;
493 if (i >= min - 1)
494 goto out_ok;
495 goto out_eol;
497 line[line_pos] = '\0';
498 line_pos++;
500 out_ok:
501 return i;
502 out_eof:
503 read_nextline = 1;
504 return RET_EOF;
505 out_eol:
506 return RET_EOL;
509 static codecs_t *video_codecs=NULL;
510 static codecs_t *audio_codecs=NULL;
511 static int nr_vcodecs = 0;
512 static int nr_acodecs = 0;
514 int parse_codec_cfg(const char *cfgfile)
516 codecs_t *codec = NULL; // current codec
517 codecs_t **codecsp = NULL;// points to audio_codecs or to video_codecs
518 char *endptr; // strtoul()...
519 int *nr_codecsp;
520 int codec_type; /* TYPE_VIDEO/TYPE_AUDIO */
521 int tmp, i;
523 // in case we call it a second time
524 codecs_uninit_free();
526 nr_vcodecs = 0;
527 nr_acodecs = 0;
529 if(cfgfile==NULL) {
530 #ifdef CODECS2HTML
531 return 0;
532 #else
533 video_codecs = builtin_video_codecs;
534 audio_codecs = builtin_audio_codecs;
535 nr_vcodecs = sizeof(builtin_video_codecs)/sizeof(codecs_t);
536 nr_acodecs = sizeof(builtin_audio_codecs)/sizeof(codecs_t);
537 return 1;
538 #endif
541 mp_tmsg(MSGT_CODECCFG,MSGL_V,"Reading %s: ", cfgfile);
543 if ((fp = fopen(cfgfile, "r")) == NULL) {
544 mp_tmsg(MSGT_CODECCFG,MSGL_V,"Can't open '%s': %s\n", cfgfile, strerror(errno));
545 return 0;
548 if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) {
549 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't get memory for 'line': %s\n", strerror(errno));
550 return 0;
552 read_nextline = 1;
555 * this only catches release lines at the start of
556 * codecs.conf, before audiocodecs and videocodecs.
558 while ((tmp = get_token(1, 1)) == RET_EOL)
559 /* NOTHING */;
560 if (tmp == RET_EOF)
561 goto out;
562 if (!strcmp(token[0], "release")) {
563 if (get_token(1, 2) < 0)
564 goto err_out_parse_error;
565 tmp = atoi(token[0]);
566 if (tmp < CODEC_CFG_MIN)
567 goto err_out_release_num;
568 while ((tmp = get_token(1, 1)) == RET_EOL)
569 /* NOTHING */;
570 if (tmp == RET_EOF)
571 goto out;
572 } else
573 goto err_out_release_num;
576 * check if the next block starts with 'audiocodec' or
577 * with 'videocodec'
579 if (!strcmp(token[0], "audiocodec") || !strcmp(token[0], "videocodec"))
580 goto loop_enter;
581 goto err_out_parse_error;
583 while ((tmp = get_token(1, 1)) != RET_EOF) {
584 if (tmp == RET_EOL)
585 continue;
586 if (!strcmp(token[0], "audiocodec") ||
587 !strcmp(token[0], "videocodec")) {
588 if (!validate_codec(codec, codec_type))
589 goto err_out_not_valid;
590 loop_enter:
591 if (*token[0] == 'v') {
592 codec_type = TYPE_VIDEO;
593 nr_codecsp = &nr_vcodecs;
594 codecsp = &video_codecs;
595 } else if (*token[0] == 'a') {
596 codec_type = TYPE_AUDIO;
597 nr_codecsp = &nr_acodecs;
598 codecsp = &audio_codecs;
599 #ifdef DEBUG
600 } else {
601 mp_msg(MSGT_CODECCFG,MSGL_ERR,"picsba\n");
602 goto err_out;
603 #endif
605 if (!(*codecsp = realloc(*codecsp,
606 sizeof(codecs_t) * (*nr_codecsp + 2)))) {
607 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't realloc '*codecsp': %s\n", strerror(errno));
608 goto err_out;
610 codec=*codecsp + *nr_codecsp;
611 ++*nr_codecsp;
612 memset(codec,0,sizeof(codecs_t));
613 memset(codec->fourcc, 0xff, sizeof(codec->fourcc));
614 memset(codec->outfmt, 0xff, sizeof(codec->outfmt));
615 memset(codec->infmt, 0xff, sizeof(codec->infmt));
617 if (get_token(1, 1) < 0)
618 goto err_out_parse_error;
619 for (i = 0; i < *nr_codecsp - 1; i++) {
620 if(( (*codecsp)[i].name!=NULL) &&
621 (!strcmp(token[0], (*codecsp)[i].name)) ) {
622 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Codec name '%s' isn't unique.", token[0]);
623 goto err_out_print_linenum;
626 if (!(codec->name = strdup(token[0]))) {
627 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'name': %s\n", strerror(errno));
628 goto err_out;
630 } else if (!strcmp(token[0], "info")) {
631 if (codec->info || get_token(1, 1) < 0)
632 goto err_out_parse_error;
633 if (!(codec->info = strdup(token[0]))) {
634 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'info': %s\n", strerror(errno));
635 goto err_out;
637 } else if (!strcmp(token[0], "comment")) {
638 if (get_token(1, 1) < 0)
639 goto err_out_parse_error;
640 add_comment(token[0], &codec->comment);
641 } else if (!strcmp(token[0], "fourcc")) {
642 if (get_token(1, 2) < 0)
643 goto err_out_parse_error;
644 if (!add_to_fourcc(token[0], token[1],
645 codec->fourcc,
646 codec->fourccmap))
647 goto err_out_print_linenum;
648 } else if (!strcmp(token[0], "format")) {
649 if (get_token(1, 2) < 0)
650 goto err_out_parse_error;
651 if (!add_to_format(token[0], token[1],
652 codec->fourcc,codec->fourccmap))
653 goto err_out_print_linenum;
654 } else if (!strcmp(token[0], "driver")) {
655 if (get_token(1, 1) < 0)
656 goto err_out_parse_error;
657 if (!(codec->drv = strdup(token[0]))) {
658 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'driver': %s\n", strerror(errno));
659 goto err_out;
661 } else if (!strcmp(token[0], "dll")) {
662 if (get_token(1, 1) < 0)
663 goto err_out_parse_error;
664 if (!(codec->dll = strdup(token[0]))) {
665 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'dll': %s", strerror(errno));
666 goto err_out;
668 } else if (!strcmp(token[0], "guid")) {
669 if (get_token(11, 11) < 0)
670 goto err_out_parse_error;
671 codec->guid.f1=strtoul(token[0],&endptr,0);
672 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
673 *endptr != '\0')
674 goto err_out_parse_error;
675 codec->guid.f2=strtoul(token[1],&endptr,0);
676 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
677 *endptr != '\0')
678 goto err_out_parse_error;
679 codec->guid.f3=strtoul(token[2],&endptr,0);
680 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
681 *endptr != '\0')
682 goto err_out_parse_error;
683 for (i = 0; i < 8; i++) {
684 codec->guid.f4[i]=strtoul(token[i + 3],&endptr,0);
685 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
686 *endptr != '\0')
687 goto err_out_parse_error;
689 } else if (!strcmp(token[0], "out")) {
690 if (get_token(1, 2) < 0)
691 goto err_out_parse_error;
692 if (!add_to_inout(token[0], token[1], codec->outfmt,
693 codec->outflags))
694 goto err_out_print_linenum;
695 } else if (!strcmp(token[0], "in")) {
696 if (get_token(1, 2) < 0)
697 goto err_out_parse_error;
698 if (!add_to_inout(token[0], token[1], codec->infmt,
699 codec->inflags))
700 goto err_out_print_linenum;
701 } else if (!strcmp(token[0], "flags")) {
702 if (get_token(1, 1) < 0)
703 goto err_out_parse_error;
704 if (!strcmp(token[0], "seekable"))
705 codec->flags |= CODECS_FLAG_SEEKABLE;
706 else
707 if (!strcmp(token[0], "align16"))
708 codec->flags |= CODECS_FLAG_ALIGN16;
709 else
710 goto err_out_parse_error;
711 } else if (!strcmp(token[0], "status")) {
712 if (get_token(1, 1) < 0)
713 goto err_out_parse_error;
714 if (!strcasecmp(token[0], "working"))
715 codec->status = CODECS_STATUS_WORKING;
716 else if (!strcasecmp(token[0], "crashing"))
717 codec->status = CODECS_STATUS_NOT_WORKING;
718 else if (!strcasecmp(token[0], "untested"))
719 codec->status = CODECS_STATUS_UNTESTED;
720 else if (!strcasecmp(token[0], "buggy"))
721 codec->status = CODECS_STATUS_PROBLEMS;
722 else
723 goto err_out_parse_error;
724 } else if (!strcmp(token[0], "cpuflags")) {
725 if (get_token(1, 1) < 0)
726 goto err_out_parse_error;
727 if (!(codec->cpuflags = get_cpuflags(token[0])))
728 goto err_out_parse_error;
729 } else
730 goto err_out_parse_error;
732 if (!validate_codec(codec, codec_type))
733 goto err_out_not_valid;
734 mp_tmsg(MSGT_CODECCFG,MSGL_INFO,"%d audio & %d video codecs\n", nr_acodecs, nr_vcodecs);
735 if(video_codecs) video_codecs[nr_vcodecs].name = NULL;
736 if(audio_codecs) audio_codecs[nr_acodecs].name = NULL;
737 out:
738 free(line);
739 line=NULL;
740 fclose(fp);
741 return 1;
743 err_out_parse_error:
744 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
745 err_out_print_linenum:
746 PRINT_LINENUM;
747 err_out:
748 codecs_uninit_free();
750 free(line);
751 line=NULL;
752 line_num = 0;
753 fclose(fp);
754 return 0;
755 err_out_not_valid:
756 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Codec is not defined correctly.");
757 goto err_out_print_linenum;
758 err_out_release_num:
759 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"This codecs.conf is too old and incompatible with this MPlayer release!");
760 goto err_out_print_linenum;
763 static void codecs_free(codecs_t* codecs,int count) {
764 int i;
765 for ( i = 0; i < count; i++)
766 if ( codecs[i].name ) {
767 if( codecs[i].name )
768 free(codecs[i].name);
769 if( codecs[i].info )
770 free(codecs[i].info);
771 if( codecs[i].comment )
772 free(codecs[i].comment);
773 if( codecs[i].dll )
774 free(codecs[i].dll);
775 if( codecs[i].drv )
776 free(codecs[i].drv);
778 if (codecs)
779 free(codecs);
782 void codecs_uninit_free(void) {
783 if (video_codecs)
784 codecs_free(video_codecs,nr_vcodecs);
785 video_codecs=NULL;
786 if (audio_codecs)
787 codecs_free(audio_codecs,nr_acodecs);
788 audio_codecs=NULL;
791 codecs_t *find_audio_codec(unsigned int fourcc, unsigned int *fourccmap,
792 codecs_t *start, int force)
794 return find_codec(fourcc, fourccmap, start, 1, force);
797 codecs_t *find_video_codec(unsigned int fourcc, unsigned int *fourccmap,
798 codecs_t *start, int force)
800 return find_codec(fourcc, fourccmap, start, 0, force);
803 codecs_t* find_codec(unsigned int fourcc,unsigned int *fourccmap,
804 codecs_t *start, int audioflag, int force)
806 int i, j;
807 codecs_t *c;
809 #if 0
810 if (start) {
811 for (/* NOTHING */; start->name; start++) {
812 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
813 if (start->fourcc[j] == fourcc) {
814 if (fourccmap)
815 *fourccmap = start->fourccmap[j];
816 return start;
820 } else
821 #endif
823 if (audioflag) {
824 i = nr_acodecs;
825 c = audio_codecs;
826 } else {
827 i = nr_vcodecs;
828 c = video_codecs;
830 if(!i) return NULL;
831 for (/* NOTHING */; i--; c++) {
832 if(start && c<=start) continue;
833 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
834 // FIXME: do NOT hardwire 'null' name here:
835 if (c->fourcc[j]==fourcc || !strcmp(c->drv,"null")) {
836 if (fourccmap)
837 *fourccmap = c->fourccmap[j];
838 return c;
841 if (force) return c;
844 return NULL;
847 void stringset_init(stringset_t *set) {
848 *set = calloc(1, sizeof(char *));
851 void stringset_free(stringset_t *set) {
852 int count = 0;
853 while ((*set)[count]) free((*set)[count++]);
854 free(*set);
855 *set = NULL;
858 void stringset_add(stringset_t *set, const char *str) {
859 int count = 0;
860 while ((*set)[count]) count++;
861 count++;
862 *set = realloc(*set, sizeof(char *) * (count + 1));
863 (*set)[count - 1] = strdup(str);
864 (*set)[count] = NULL;
867 int stringset_test(stringset_t *set, const char *str) {
868 stringset_t s;
869 for (s = *set; *s; s++)
870 if (strcmp(*s, str) == 0)
871 return 1;
872 return 0;
875 void list_codecs(int audioflag){
876 int i;
877 codecs_t *c;
879 if (audioflag) {
880 i = nr_acodecs;
881 c = audio_codecs;
882 mp_msg(MSGT_CODECCFG,MSGL_INFO,"ac: afm: status: info: [lib/dll]\n");
883 } else {
884 i = nr_vcodecs;
885 c = video_codecs;
886 mp_msg(MSGT_CODECCFG,MSGL_INFO,"vc: vfm: status: info: [lib/dll]\n");
888 if(!i) return;
889 for (/* NOTHING */; i--; c++) {
890 char* s="unknown ";
891 switch(c->status){
892 case CODECS_STATUS_WORKING: s="working ";break;
893 case CODECS_STATUS_PROBLEMS: s="problems";break;
894 case CODECS_STATUS_NOT_WORKING: s="crashing";break;
895 case CODECS_STATUS_UNTESTED: s="untested";break;
897 if(c->dll)
898 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s [%s]\n",c->name,c->drv,s,c->info,c->dll);
899 else
900 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s\n",c->name,c->drv,s,c->info);
908 #ifdef CODECS2HTML
909 void wrapline(FILE *f2,char *s){
910 int c;
911 if(!s){
912 fprintf(f2,"-");
913 return;
915 while((c=*s++)){
916 if(c==',') fprintf(f2,"<br>"); else fputc(c,f2);
920 void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
921 int c,d;
922 while((c=fgetc(f1))>=0){
923 if(c!='%'){
924 fputc(c,f2);
925 continue;
927 d=fgetc(f1);
929 switch(d){
930 case '.':
931 return; // end of section
932 case 'n':
933 wrapline(f2,codec->name); break;
934 case 'i':
935 wrapline(f2,codec->info); break;
936 case 'c':
937 wrapline(f2,codec->comment); break;
938 case 'd':
939 wrapline(f2,codec->dll); break;
940 case 'D':
941 fprintf(f2,"%c",!strcmp(codec->drv,"dshow")?'+':'-'); break;
942 case 'F':
943 for(d=0;d<CODECS_MAX_FOURCC;d++)
944 if(!d || codec->fourcc[d]!=0xFFFFFFFF)
945 fprintf(f2,"%s%.4s",d?"<br>":"",(codec->fourcc[d]==0xFFFFFFFF || codec->fourcc[d]<0x20202020)?!d?"-":"":(char*) &codec->fourcc[d]);
946 break;
947 case 'f':
948 for(d=0;d<CODECS_MAX_FOURCC;d++)
949 if(codec->fourcc[d]!=0xFFFFFFFF)
950 fprintf(f2,"%s0x%X",d?"<br>":"",codec->fourcc[d]);
951 break;
952 case 'Y':
953 for(d=0;d<CODECS_MAX_OUTFMT;d++)
954 if(codec->outfmt[d]!=0xFFFFFFFF){
955 for (c=0; fmt_table[c].name; c++)
956 if(fmt_table[c].num==codec->outfmt[d]) break;
957 if(fmt_table[c].name)
958 fprintf(f2,"%s%s",d?"<br>":"",fmt_table[c].name);
960 break;
961 default:
962 fputc(c,f2);
963 fputc(d,f2);
969 void skiphtml(FILE *f1){
970 int c,d;
971 while((c=fgetc(f1))>=0){
972 if(c!='%'){
973 continue;
975 d=fgetc(f1);
976 if(d=='.') return; // end of section
980 static void print_int_array(const unsigned int* a, int size)
982 printf("{ ");
983 while (size--)
984 if(abs(*a)<256)
985 printf("%d%s", *a++, size?", ":"");
986 else
987 printf("0x%X%s", *a++, size?", ":"");
988 printf(" }");
991 static void print_char_array(const unsigned char* a, int size)
993 printf("{ ");
994 while (size--)
995 if((*a)<10)
996 printf("%d%s", *a++, size?", ":"");
997 else
998 printf("0x%02x%s", *a++, size?", ":"");
999 printf(" }");
1002 static void print_string(const char* s)
1004 if (!s) printf("NULL");
1005 else printf("\"%s\"", s);
1008 int main(int argc, char* argv[])
1010 codecs_t *cl;
1011 FILE *f1;
1012 FILE *f2;
1013 int c,d,i;
1014 int pos;
1015 int section=-1;
1016 int nr_codecs;
1017 int win32=-1;
1018 int dshow=-1;
1019 int win32ex=-1;
1022 * Take path to codecs.conf from command line, or fall back on
1023 * etc/codecs.conf
1025 if (!(nr_codecs = parse_codec_cfg((argc>1)?argv[1]:"etc/codecs.conf")))
1026 exit(1);
1028 if (argc > 1) {
1029 int i, j;
1030 const char* nm[2];
1031 codecs_t* cod[2];
1032 int nr[2];
1034 nm[0] = "builtin_video_codecs";
1035 cod[0] = video_codecs;
1036 nr[0] = nr_vcodecs;
1038 nm[1] = "builtin_audio_codecs";
1039 cod[1] = audio_codecs;
1040 nr[1] = nr_acodecs;
1042 printf("/* GENERATED FROM %s, DO NOT EDIT! */\n\n",argv[1]);
1043 printf("#include <stddef.h>\n");
1044 printf("#include \"codec-cfg.h\"\n\n");
1046 for (i=0; i<2; i++) {
1047 printf("const codecs_t %s[] = {\n", nm[i]);
1048 for (j = 0; j < nr[i]; j++) {
1049 printf("{");
1051 print_int_array(cod[i][j].fourcc, CODECS_MAX_FOURCC);
1052 printf(", /* fourcc */\n");
1054 print_int_array(cod[i][j].fourccmap, CODECS_MAX_FOURCC);
1055 printf(", /* fourccmap */\n");
1057 print_int_array(cod[i][j].outfmt, CODECS_MAX_OUTFMT);
1058 printf(", /* outfmt */\n");
1060 print_char_array(cod[i][j].outflags, CODECS_MAX_OUTFMT);
1061 printf(", /* outflags */\n");
1063 print_int_array(cod[i][j].infmt, CODECS_MAX_INFMT);
1064 printf(", /* infmt */\n");
1066 print_char_array(cod[i][j].inflags, CODECS_MAX_INFMT);
1067 printf(", /* inflags */\n");
1069 print_string(cod[i][j].name); printf(", /* name */\n");
1070 print_string(cod[i][j].info); printf(", /* info */\n");
1071 print_string(cod[i][j].comment); printf(", /* comment */\n");
1072 print_string(cod[i][j].dll); printf(", /* dll */\n");
1073 print_string(cod[i][j].drv); printf(", /* drv */\n");
1075 printf("{ 0x%08lx, %hu, %hu,",
1076 cod[i][j].guid.f1,
1077 cod[i][j].guid.f2,
1078 cod[i][j].guid.f3);
1079 print_char_array(cod[i][j].guid.f4, sizeof(cod[i][j].guid.f4));
1080 printf(" }, /* GUID */\n");
1081 printf("%hd /* flags */, %hd /* status */, %hd /* cpuflags */ }\n",
1082 cod[i][j].flags,
1083 cod[i][j].status,
1084 cod[i][j].cpuflags);
1085 if (j < nr[i]) printf(",\n");
1087 printf("};\n\n");
1089 exit(0);
1092 f1=fopen("DOCS/tech/codecs-in.html","rb"); if(!f1) exit(1);
1093 f2=fopen("DOCS/codecs-status.html","wb"); if(!f2) exit(1);
1095 while((c=fgetc(f1))>=0){
1096 if(c!='%'){
1097 fputc(c,f2);
1098 continue;
1100 d=fgetc(f1);
1101 if(d>='0' && d<='9'){
1102 // begin section
1103 section=d-'0';
1104 //printf("BEGIN %d\n",section);
1105 if(section>=5){
1106 // audio
1107 cl = audio_codecs;
1108 nr_codecs = nr_acodecs;
1109 dshow=7;win32=4;
1110 } else {
1111 // video
1112 cl = video_codecs;
1113 nr_codecs = nr_vcodecs;
1114 dshow=4;win32=2;win32ex=6;
1116 pos=ftell(f1);
1117 for(i=0;i<nr_codecs;i++){
1118 fseek(f1,pos,SEEK_SET);
1119 switch(section){
1120 case 0:
1121 case 5:
1122 if(cl[i].status==CODECS_STATUS_WORKING)
1123 // if(!(!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1124 parsehtml(f1,f2,&cl[i],section,dshow);
1125 break;
1126 #if 0
1127 case 1:
1128 case 6:
1129 if(cl[i].status==CODECS_STATUS_WORKING)
1130 if((!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1131 parsehtml(f1,f2,&cl[i],section,dshow);
1132 break;
1133 #endif
1134 case 2:
1135 case 7:
1136 if(cl[i].status==CODECS_STATUS_PROBLEMS)
1137 parsehtml(f1,f2,&cl[i],section,dshow);
1138 break;
1139 case 3:
1140 case 8:
1141 if(cl[i].status==CODECS_STATUS_NOT_WORKING)
1142 parsehtml(f1,f2,&cl[i],section,dshow);
1143 break;
1144 case 4:
1145 case 9:
1146 if(cl[i].status==CODECS_STATUS_UNTESTED)
1147 parsehtml(f1,f2,&cl[i],section,dshow);
1148 break;
1149 default:
1150 printf("Warning! unimplemented section: %d\n",section);
1153 fseek(f1,pos,SEEK_SET);
1154 skiphtml(f1);
1155 //void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
1157 continue;
1159 fputc(c,f2);
1160 fputc(d,f2);
1163 fclose(f2);
1164 fclose(f1);
1165 return 0;
1168 #endif
1170 #ifdef TESTING
1171 int main(void)
1173 codecs_t *c;
1174 int i,j, nr_codecs, state;
1176 if (!(parse_codec_cfg("etc/codecs.conf")))
1177 return 0;
1178 if (!video_codecs)
1179 printf("no videoconfig.\n");
1180 if (!audio_codecs)
1181 printf("no audioconfig.\n");
1183 printf("videocodecs:\n");
1184 c = video_codecs;
1185 nr_codecs = nr_vcodecs;
1186 state = 0;
1187 next:
1188 if (c) {
1189 printf("number of %scodecs: %d\n", state==0?"video":"audio",
1190 nr_codecs);
1191 for(i=0;i<nr_codecs;i++, c++){
1192 printf("\n============== %scodec %02d ===============\n",
1193 state==0?"video":"audio",i);
1194 printf("name='%s'\n",c->name);
1195 printf("info='%s'\n",c->info);
1196 printf("comment='%s'\n",c->comment);
1197 printf("dll='%s'\n",c->dll);
1198 /* printf("flags=%X driver=%d status=%d cpuflags=%d\n",
1199 c->flags, c->driver, c->status, c->cpuflags); */
1200 printf("flags=%X status=%d cpuflags=%d\n",
1201 c->flags, c->status, c->cpuflags);
1203 for(j=0;j<CODECS_MAX_FOURCC;j++){
1204 if(c->fourcc[j]!=0xFFFFFFFF){
1205 printf("fourcc %02d: %08X (%.4s) ===> %08X (%.4s)\n",j,c->fourcc[j],(char *) &c->fourcc[j],c->fourccmap[j],(char *) &c->fourccmap[j]);
1209 for(j=0;j<CODECS_MAX_OUTFMT;j++){
1210 if(c->outfmt[j]!=0xFFFFFFFF){
1211 printf("outfmt %02d: %08X (%.4s) flags: %d\n",j,c->outfmt[j],(char *) &c->outfmt[j],c->outflags[j]);
1215 for(j=0;j<CODECS_MAX_INFMT;j++){
1216 if(c->infmt[j]!=0xFFFFFFFF){
1217 printf("infmt %02d: %08X (%.4s) flags: %d\n",j,c->infmt[j],(char *) &c->infmt[j],c->inflags[j]);
1221 printf("GUID: %08lX %04X %04X",c->guid.f1,c->guid.f2,c->guid.f3);
1222 for(j=0;j<8;j++) printf(" %02X",c->guid.f4[j]);
1223 printf("\n");
1228 if (!state) {
1229 printf("audiocodecs:\n");
1230 c = audio_codecs;
1231 nr_codecs = nr_acodecs;
1232 state = 1;
1233 goto next;
1235 return 0;
1238 #endif