Merge svn changes up to r28610
[mplayer.git] / codec-cfg.c
blob56dae05c4571097d1668d3be4eeac0cf95baf7a6
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 #ifdef __GNUC__
33 #define mp_msg(t, l, m, args...) fprintf(stderr, m, ##args)
34 #else
35 #define mp_msg(t, l, ...) fprintf(stderr, __VA_ARGS__)
36 #endif
37 #endif
39 #include "help_mp.h"
41 #include "libmpcodecs/img_format.h"
42 #include "codec-cfg.h"
44 #ifndef CODECS2HTML
45 #include "codecs.conf.h"
46 #endif
48 #define mmioFOURCC( ch0, ch1, ch2, ch3 ) \
49 ( (uint32_t)(uint8_t)(ch0) | ( (uint32_t)(uint8_t)(ch1) << 8 ) | \
50 ( (uint32_t)(uint8_t)(ch2) << 16 ) | ( (uint32_t)(uint8_t)(ch3) << 24 ) )
52 #define PRINT_LINENUM mp_msg(MSGT_CODECCFG,MSGL_ERR," at line %d\n", line_num)
54 #define MAX_NR_TOKEN 16
56 #define MAX_LINE_LEN 1000
58 #define RET_EOF -1
59 #define RET_EOL -2
61 #define TYPE_VIDEO 0
62 #define TYPE_AUDIO 1
64 char * codecs_file = NULL;
66 static int add_to_fourcc(char *s, char *alias, unsigned int *fourcc,
67 unsigned int *map)
69 int i, j, freeslots;
70 unsigned int tmp;
72 /* find first unused slot */
73 for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++)
74 /* NOTHING */;
75 freeslots = CODECS_MAX_FOURCC - i;
76 if (!freeslots)
77 goto err_out_too_many;
79 do {
80 tmp = mmioFOURCC(s[0], s[1], s[2], s[3]);
81 for (j = 0; j < i; j++)
82 if (tmp == fourcc[j])
83 goto err_out_duplicated;
84 fourcc[i] = tmp;
85 map[i] = alias ? mmioFOURCC(alias[0], alias[1], alias[2], alias[3]) : tmp;
86 s += 4;
87 i++;
88 } while ((*(s++) == ',') && --freeslots);
90 if (!freeslots)
91 goto err_out_too_many;
92 if (*(--s) != '\0')
93 goto err_out_parse_error;
94 return 1;
95 err_out_duplicated:
96 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_DuplicateFourcc);
97 return 0;
98 err_out_too_many:
99 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_TooManyFourccs);
100 return 0;
101 err_out_parse_error:
102 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseError);
103 return 0;
106 static int add_to_format(char *s, char *alias,unsigned int *fourcc, unsigned int *fourccmap)
108 int i, j;
109 char *endptr;
111 /* find first unused slot */
112 for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++)
113 /* NOTHING */;
114 if (i == CODECS_MAX_FOURCC) {
115 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_TooManyFourccs);
116 return 0;
119 fourcc[i]=strtoul(s,&endptr,0);
120 if (*endptr != '\0') {
121 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseErrorFIDNotNumber);
122 return 0;
125 if(alias){
126 fourccmap[i]=strtoul(alias,&endptr,0);
127 if (*endptr != '\0') {
128 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseErrorFIDAliasNotNumber);
129 return 0;
131 } else
132 fourccmap[i]=fourcc[i];
134 for (j = 0; j < i; j++)
135 if (fourcc[j] == fourcc[i]) {
136 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_DuplicateFID);
137 return 0;
140 return 1;
143 static struct {
144 const char *name;
145 const unsigned int num;
146 } fmt_table[] = {
147 {"YV12", IMGFMT_YV12},
148 {"I420", IMGFMT_I420},
149 {"IYUV", IMGFMT_IYUV},
150 {"NV12", IMGFMT_NV12},
151 {"NV21", IMGFMT_NV21},
152 {"YVU9", IMGFMT_YVU9},
153 {"IF09", IMGFMT_IF09},
154 {"444P", IMGFMT_444P},
155 {"422P", IMGFMT_422P},
156 {"411P", IMGFMT_411P},
157 {"Y800", IMGFMT_Y800},
158 {"Y8", IMGFMT_Y8},
160 {"YUY2", IMGFMT_YUY2},
161 {"UYVY", IMGFMT_UYVY},
162 {"YVYU", IMGFMT_YVYU},
164 {"RGB4", IMGFMT_RGB|4},
165 {"RGB8", IMGFMT_RGB|8},
166 {"RGB15", IMGFMT_RGB|15},
167 {"RGB16", IMGFMT_RGB|16},
168 {"RGB24", IMGFMT_RGB|24},
169 {"RGB32", IMGFMT_RGB|32},
170 {"BGR4", IMGFMT_BGR|4},
171 {"BGR8", IMGFMT_BGR|8},
172 {"BGR15", IMGFMT_BGR|15},
173 {"BGR16", IMGFMT_BGR|16},
174 {"BGR24", IMGFMT_BGR|24},
175 {"BGR32", IMGFMT_BGR|32},
176 {"RGB1", IMGFMT_RGB|1},
177 {"BGR1", IMGFMT_BGR|1},
179 {"MPES", IMGFMT_MPEGPES},
180 {"ZRMJPEGNI", IMGFMT_ZRMJPEGNI},
181 {"ZRMJPEGIT", IMGFMT_ZRMJPEGIT},
182 {"ZRMJPEGIB", IMGFMT_ZRMJPEGIB},
184 {"IDCT_MPEG2",IMGFMT_XVMC_IDCT_MPEG2},
185 {"MOCO_MPEG2",IMGFMT_XVMC_MOCO_MPEG2},
187 {"VDPAU_MPEG1",IMGFMT_VDPAU_MPEG1},
188 {"VDPAU_MPEG2",IMGFMT_VDPAU_MPEG2},
189 {"VDPAU_H264",IMGFMT_VDPAU_H264},
190 {"VDPAU_WMV3",IMGFMT_VDPAU_WMV3},
191 {"VDPAU_VC1",IMGFMT_VDPAU_VC1},
193 {NULL, 0}
197 static int add_to_inout(char *sfmt, char *sflags, unsigned int *outfmt,
198 unsigned char *outflags)
201 static char *flagstr[] = {
202 "flip",
203 "noflip",
204 "yuvhack",
205 "query",
206 "static",
207 NULL
210 int i, j, freeslots;
211 unsigned char flags;
213 for (i = 0; i < CODECS_MAX_OUTFMT && outfmt[i] != 0xffffffff; i++)
214 /* NOTHING */;
215 freeslots = CODECS_MAX_OUTFMT - i;
216 if (!freeslots)
217 goto err_out_too_many;
219 flags = 0;
220 if(sflags) {
221 do {
222 for (j = 0; flagstr[j] != NULL; j++)
223 if (!strncmp(sflags, flagstr[j],
224 strlen(flagstr[j])))
225 break;
226 if (flagstr[j] == NULL)
227 goto err_out_parse_error;
228 flags|=(1<<j);
229 sflags+=strlen(flagstr[j]);
230 } while (*(sflags++) == ',');
232 if (*(--sflags) != '\0')
233 goto err_out_parse_error;
236 do {
237 for (j = 0; fmt_table[j].name != NULL; j++)
238 if (!strncmp(sfmt, fmt_table[j].name, strlen(fmt_table[j].name)))
239 break;
240 if (fmt_table[j].name == NULL)
241 goto err_out_parse_error;
242 outfmt[i] = fmt_table[j].num;
243 outflags[i] = flags;
244 ++i;
245 sfmt+=strlen(fmt_table[j].name);
246 } while ((*(sfmt++) == ',') && --freeslots);
248 if (!freeslots)
249 goto err_out_too_many;
251 if (*(--sfmt) != '\0')
252 goto err_out_parse_error;
254 return 1;
255 err_out_too_many:
256 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_TooManyOut);
257 return 0;
258 err_out_parse_error:
259 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseError);
260 return 0;
263 #if 0
264 static short get_driver(char *s,int audioflag)
266 static char *audiodrv[] = {
267 "null",
268 "mp3lib",
269 "pcm",
270 "libac3",
271 "acm",
272 "alaw",
273 "msgsm",
274 "dshow",
275 "dvdpcm",
276 "hwac3",
277 "libvorbis",
278 "ffmpeg",
279 "libmad",
280 "msadpcm",
281 "liba52",
282 "g72x",
283 "imaadpcm",
284 "dk4adpcm",
285 "dk3adpcm",
286 "roqaudio",
287 "faad",
288 "realaud",
289 "libdv",
290 NULL
292 static char *videodrv[] = {
293 "null",
294 "libmpeg2",
295 "vfw",
296 "dshow",
297 "ffmpeg",
298 "vfwex",
299 "raw",
300 "msrle",
301 "xanim",
302 "msvidc",
303 "fli",
304 "cinepak",
305 "qtrle",
306 "nuv",
307 "cyuv",
308 "qtsmc",
309 "ducktm1",
310 "roqvideo",
311 "qtrpza",
312 "mpng",
313 "ijpg",
314 "zlib",
315 "mpegpes",
316 "zrmjpeg",
317 "realvid",
318 "xvid",
319 "libdv",
320 NULL
322 char **drv=audioflag?audiodrv:videodrv;
323 int i;
325 for(i=0;drv[i];i++) if(!strcmp(s,drv[i])) return i;
327 return -1;
329 #endif
331 static int validate_codec(codecs_t *c, int type)
333 unsigned int i;
334 char *tmp_name = c->name;
336 for (i = 0; i < strlen(tmp_name) && isalnum(tmp_name[i]); i++)
337 /* NOTHING */;
339 if (i < strlen(tmp_name)) {
340 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_InvalidCodecName, c->name);
341 return 0;
344 if (!c->info)
345 c->info = strdup(c->name);
347 #if 0
348 if (c->fourcc[0] == 0xffffffff) {
349 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecLacksFourcc, c->name);
350 return 0;
352 #endif
354 if (!c->drv) {
355 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecLacksDriver, c->name);
356 return 0;
359 #if 0
360 #warning codec->driver == 4;... <- this should not be put in here...
361 #warning Where are they defined ????????????
362 if (!c->dll && (c->driver == 4 ||
363 (c->driver == 2 && type == TYPE_VIDEO))) {
364 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecNeedsDLL, c->name);
365 return 0;
367 #warning Can guid.f1 be 0? How does one know that it was not given?
368 // if (!(codec->flags & CODECS_FLAG_AUDIO) && codec->driver == 4)
370 if (type == TYPE_VIDEO)
371 if (c->outfmt[0] == 0xffffffff) {
372 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecNeedsOutfmt, c->name);
373 return 0;
375 #endif
376 return 1;
379 static int add_comment(char *s, char **d)
381 int pos;
383 if (!*d)
384 pos = 0;
385 else {
386 pos = strlen(*d);
387 (*d)[pos++] = '\n';
389 if (!(*d = realloc(*d, pos + strlen(s) + 1))) {
390 mp_msg(MSGT_CODECCFG,MSGL_FATAL,MSGTR_CantAllocateComment);
391 return 0;
393 strcpy(*d + pos, s);
394 return 1;
397 static short get_cpuflags(char *s)
399 static char *flagstr[] = {
400 "mmx",
401 "sse",
402 "3dnow",
403 NULL
405 int i;
406 short flags = 0;
408 do {
409 for (i = 0; flagstr[i]; i++)
410 if (!strncmp(s, flagstr[i], strlen(flagstr[i])))
411 break;
412 if (!flagstr[i])
413 goto err_out_parse_error;
414 flags |= 1<<i;
415 s += strlen(flagstr[i]);
416 } while (*(s++) == ',');
418 if (*(--s) != '\0')
419 goto err_out_parse_error;
421 return flags;
422 err_out_parse_error:
423 return 0;
426 static FILE *fp;
427 static int line_num = 0;
428 static char *line;
429 static char *token[MAX_NR_TOKEN];
430 static int read_nextline = 1;
432 static int get_token(int min, int max)
434 static int line_pos;
435 int i;
436 char c;
438 if (max >= MAX_NR_TOKEN) {
439 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_GetTokenMaxNotLessThanMAX_NR_TOKEN);
440 goto out_eof;
443 memset(token, 0x00, sizeof(*token) * max);
445 if (read_nextline) {
446 if (!fgets(line, MAX_LINE_LEN, fp))
447 goto out_eof;
448 line_pos = 0;
449 ++line_num;
450 read_nextline = 0;
452 for (i = 0; i < max; i++) {
453 while (isspace(line[line_pos]))
454 ++line_pos;
455 if (line[line_pos] == '\0' || line[line_pos] == '#' ||
456 line[line_pos] == ';') {
457 read_nextline = 1;
458 if (i >= min)
459 goto out_ok;
460 goto out_eol;
462 token[i] = line + line_pos;
463 c = line[line_pos];
464 if (c == '"' || c == '\'') {
465 token[i]++;
466 while (line[++line_pos] != c && line[line_pos])
467 /* NOTHING */;
468 } else {
469 for (/* NOTHING */; !isspace(line[line_pos]) &&
470 line[line_pos]; line_pos++)
471 /* NOTHING */;
473 if (!line[line_pos]) {
474 read_nextline = 1;
475 if (i >= min - 1)
476 goto out_ok;
477 goto out_eol;
479 line[line_pos] = '\0';
480 line_pos++;
482 out_ok:
483 return i;
484 out_eof:
485 read_nextline = 1;
486 return RET_EOF;
487 out_eol:
488 return RET_EOL;
491 static codecs_t *video_codecs=NULL;
492 static codecs_t *audio_codecs=NULL;
493 static int nr_vcodecs = 0;
494 static int nr_acodecs = 0;
496 int parse_codec_cfg(const char *cfgfile)
498 codecs_t *codec = NULL; // current codec
499 codecs_t **codecsp = NULL;// points to audio_codecs or to video_codecs
500 char *endptr; // strtoul()...
501 int *nr_codecsp;
502 int codec_type; /* TYPE_VIDEO/TYPE_AUDIO */
503 int tmp, i;
505 // in case we call it a second time
506 codecs_uninit_free();
508 nr_vcodecs = 0;
509 nr_acodecs = 0;
511 if(cfgfile==NULL) {
512 #ifdef CODECS2HTML
513 return 0;
514 #else
515 video_codecs = builtin_video_codecs;
516 audio_codecs = builtin_audio_codecs;
517 nr_vcodecs = sizeof(builtin_video_codecs)/sizeof(codecs_t);
518 nr_acodecs = sizeof(builtin_audio_codecs)/sizeof(codecs_t);
519 return 1;
520 #endif
523 mp_msg(MSGT_CODECCFG,MSGL_V,MSGTR_ReadingFile, cfgfile);
525 if ((fp = fopen(cfgfile, "r")) == NULL) {
526 mp_msg(MSGT_CODECCFG,MSGL_V,MSGTR_CantOpenFileError, cfgfile, strerror(errno));
527 return 0;
530 if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) {
531 mp_msg(MSGT_CODECCFG,MSGL_FATAL,MSGTR_CantGetMemoryForLine, strerror(errno));
532 return 0;
534 read_nextline = 1;
537 * this only catches release lines at the start of
538 * codecs.conf, before audiocodecs and videocodecs.
540 while ((tmp = get_token(1, 1)) == RET_EOL)
541 /* NOTHING */;
542 if (tmp == RET_EOF)
543 goto out;
544 if (!strcmp(token[0], "release")) {
545 if (get_token(1, 2) < 0)
546 goto err_out_parse_error;
547 tmp = atoi(token[0]);
548 if (tmp < CODEC_CFG_MIN)
549 goto err_out_release_num;
550 while ((tmp = get_token(1, 1)) == RET_EOL)
551 /* NOTHING */;
552 if (tmp == RET_EOF)
553 goto out;
554 } else
555 goto err_out_release_num;
558 * check if the next block starts with 'audiocodec' or
559 * with 'videocodec'
561 if (!strcmp(token[0], "audiocodec") || !strcmp(token[0], "videocodec"))
562 goto loop_enter;
563 goto err_out_parse_error;
565 while ((tmp = get_token(1, 1)) != RET_EOF) {
566 if (tmp == RET_EOL)
567 continue;
568 if (!strcmp(token[0], "audiocodec") ||
569 !strcmp(token[0], "videocodec")) {
570 if (!validate_codec(codec, codec_type))
571 goto err_out_not_valid;
572 loop_enter:
573 if (*token[0] == 'v') {
574 codec_type = TYPE_VIDEO;
575 nr_codecsp = &nr_vcodecs;
576 codecsp = &video_codecs;
577 } else if (*token[0] == 'a') {
578 codec_type = TYPE_AUDIO;
579 nr_codecsp = &nr_acodecs;
580 codecsp = &audio_codecs;
581 #ifdef DEBUG
582 } else {
583 mp_msg(MSGT_CODECCFG,MSGL_ERR,"picsba\n");
584 goto err_out;
585 #endif
587 if (!(*codecsp = realloc(*codecsp,
588 sizeof(codecs_t) * (*nr_codecsp + 2)))) {
589 mp_msg(MSGT_CODECCFG,MSGL_FATAL,MSGTR_CantReallocCodecsp, strerror(errno));
590 goto err_out;
592 codec=*codecsp + *nr_codecsp;
593 ++*nr_codecsp;
594 memset(codec,0,sizeof(codecs_t));
595 memset(codec->fourcc, 0xff, sizeof(codec->fourcc));
596 memset(codec->outfmt, 0xff, sizeof(codec->outfmt));
597 memset(codec->infmt, 0xff, sizeof(codec->infmt));
599 if (get_token(1, 1) < 0)
600 goto err_out_parse_error;
601 for (i = 0; i < *nr_codecsp - 1; i++) {
602 if(( (*codecsp)[i].name!=NULL) &&
603 (!strcmp(token[0], (*codecsp)[i].name)) ) {
604 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecNameNotUnique, token[0]);
605 goto err_out_print_linenum;
608 if (!(codec->name = strdup(token[0]))) {
609 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupName, strerror(errno));
610 goto err_out;
612 } else if (!strcmp(token[0], "info")) {
613 if (codec->info || get_token(1, 1) < 0)
614 goto err_out_parse_error;
615 if (!(codec->info = strdup(token[0]))) {
616 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupInfo, strerror(errno));
617 goto err_out;
619 } else if (!strcmp(token[0], "comment")) {
620 if (get_token(1, 1) < 0)
621 goto err_out_parse_error;
622 add_comment(token[0], &codec->comment);
623 } else if (!strcmp(token[0], "fourcc")) {
624 if (get_token(1, 2) < 0)
625 goto err_out_parse_error;
626 if (!add_to_fourcc(token[0], token[1],
627 codec->fourcc,
628 codec->fourccmap))
629 goto err_out_print_linenum;
630 } else if (!strcmp(token[0], "format")) {
631 if (get_token(1, 2) < 0)
632 goto err_out_parse_error;
633 if (!add_to_format(token[0], token[1],
634 codec->fourcc,codec->fourccmap))
635 goto err_out_print_linenum;
636 } else if (!strcmp(token[0], "driver")) {
637 if (get_token(1, 1) < 0)
638 goto err_out_parse_error;
639 if (!(codec->drv = strdup(token[0]))) {
640 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupDriver, strerror(errno));
641 goto err_out;
643 } else if (!strcmp(token[0], "dll")) {
644 if (get_token(1, 1) < 0)
645 goto err_out_parse_error;
646 if (!(codec->dll = strdup(token[0]))) {
647 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupDLL, strerror(errno));
648 goto err_out;
650 } else if (!strcmp(token[0], "guid")) {
651 if (get_token(11, 11) < 0)
652 goto err_out_parse_error;
653 codec->guid.f1=strtoul(token[0],&endptr,0);
654 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
655 *endptr != '\0')
656 goto err_out_parse_error;
657 codec->guid.f2=strtoul(token[1],&endptr,0);
658 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
659 *endptr != '\0')
660 goto err_out_parse_error;
661 codec->guid.f3=strtoul(token[2],&endptr,0);
662 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
663 *endptr != '\0')
664 goto err_out_parse_error;
665 for (i = 0; i < 8; i++) {
666 codec->guid.f4[i]=strtoul(token[i + 3],&endptr,0);
667 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
668 *endptr != '\0')
669 goto err_out_parse_error;
671 } else if (!strcmp(token[0], "out")) {
672 if (get_token(1, 2) < 0)
673 goto err_out_parse_error;
674 if (!add_to_inout(token[0], token[1], codec->outfmt,
675 codec->outflags))
676 goto err_out_print_linenum;
677 } else if (!strcmp(token[0], "in")) {
678 if (get_token(1, 2) < 0)
679 goto err_out_parse_error;
680 if (!add_to_inout(token[0], token[1], codec->infmt,
681 codec->inflags))
682 goto err_out_print_linenum;
683 } else if (!strcmp(token[0], "flags")) {
684 if (get_token(1, 1) < 0)
685 goto err_out_parse_error;
686 if (!strcmp(token[0], "seekable"))
687 codec->flags |= CODECS_FLAG_SEEKABLE;
688 else
689 if (!strcmp(token[0], "align16"))
690 codec->flags |= CODECS_FLAG_ALIGN16;
691 else
692 goto err_out_parse_error;
693 } else if (!strcmp(token[0], "status")) {
694 if (get_token(1, 1) < 0)
695 goto err_out_parse_error;
696 if (!strcasecmp(token[0], "working"))
697 codec->status = CODECS_STATUS_WORKING;
698 else if (!strcasecmp(token[0], "crashing"))
699 codec->status = CODECS_STATUS_NOT_WORKING;
700 else if (!strcasecmp(token[0], "untested"))
701 codec->status = CODECS_STATUS_UNTESTED;
702 else if (!strcasecmp(token[0], "buggy"))
703 codec->status = CODECS_STATUS_PROBLEMS;
704 else
705 goto err_out_parse_error;
706 } else if (!strcmp(token[0], "cpuflags")) {
707 if (get_token(1, 1) < 0)
708 goto err_out_parse_error;
709 if (!(codec->cpuflags = get_cpuflags(token[0])))
710 goto err_out_parse_error;
711 } else
712 goto err_out_parse_error;
714 if (!validate_codec(codec, codec_type))
715 goto err_out_not_valid;
716 mp_msg(MSGT_CODECCFG,MSGL_INFO,MSGTR_AudioVideoCodecTotals, nr_acodecs, nr_vcodecs);
717 if(video_codecs) video_codecs[nr_vcodecs].name = NULL;
718 if(audio_codecs) audio_codecs[nr_acodecs].name = NULL;
719 out:
720 free(line);
721 line=NULL;
722 fclose(fp);
723 return 1;
725 err_out_parse_error:
726 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseError);
727 err_out_print_linenum:
728 PRINT_LINENUM;
729 err_out:
730 codecs_uninit_free();
732 free(line);
733 line=NULL;
734 line_num = 0;
735 fclose(fp);
736 return 0;
737 err_out_not_valid:
738 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecDefinitionIncorrect);
739 goto err_out_print_linenum;
740 err_out_release_num:
741 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_OutdatedCodecsConf);
742 goto err_out_print_linenum;
745 static void codecs_free(codecs_t* codecs,int count) {
746 int i;
747 for ( i = 0; i < count; i++)
748 if ( codecs[i].name ) {
749 if( codecs[i].name )
750 free(codecs[i].name);
751 if( codecs[i].info )
752 free(codecs[i].info);
753 if( codecs[i].comment )
754 free(codecs[i].comment);
755 if( codecs[i].dll )
756 free(codecs[i].dll);
757 if( codecs[i].drv )
758 free(codecs[i].drv);
760 if (codecs)
761 free(codecs);
764 void codecs_uninit_free(void) {
765 if (video_codecs)
766 codecs_free(video_codecs,nr_vcodecs);
767 video_codecs=NULL;
768 if (audio_codecs)
769 codecs_free(audio_codecs,nr_acodecs);
770 audio_codecs=NULL;
773 codecs_t *find_audio_codec(unsigned int fourcc, unsigned int *fourccmap,
774 codecs_t *start, int force)
776 return find_codec(fourcc, fourccmap, start, 1, force);
779 codecs_t *find_video_codec(unsigned int fourcc, unsigned int *fourccmap,
780 codecs_t *start, int force)
782 return find_codec(fourcc, fourccmap, start, 0, force);
785 codecs_t* find_codec(unsigned int fourcc,unsigned int *fourccmap,
786 codecs_t *start, int audioflag, int force)
788 int i, j;
789 codecs_t *c;
791 #if 0
792 if (start) {
793 for (/* NOTHING */; start->name; start++) {
794 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
795 if (start->fourcc[j] == fourcc) {
796 if (fourccmap)
797 *fourccmap = start->fourccmap[j];
798 return start;
802 } else
803 #endif
805 if (audioflag) {
806 i = nr_acodecs;
807 c = audio_codecs;
808 } else {
809 i = nr_vcodecs;
810 c = video_codecs;
812 if(!i) return NULL;
813 for (/* NOTHING */; i--; c++) {
814 if(start && c<=start) continue;
815 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
816 // FIXME: do NOT hardwire 'null' name here:
817 if (c->fourcc[j]==fourcc || !strcmp(c->drv,"null")) {
818 if (fourccmap)
819 *fourccmap = c->fourccmap[j];
820 return c;
823 if (force) return c;
826 return NULL;
829 void stringset_init(stringset_t *set) {
830 *set = calloc(1, sizeof(char *));
833 void stringset_free(stringset_t *set) {
834 int count = 0;
835 while ((*set)[count]) free((*set)[count++]);
836 free(*set);
837 *set = NULL;
840 void stringset_add(stringset_t *set, const char *str) {
841 int count = 0;
842 while ((*set)[count]) count++;
843 count++;
844 *set = realloc(*set, sizeof(char *) * (count + 1));
845 (*set)[count - 1] = strdup(str);
846 (*set)[count] = NULL;
849 int stringset_test(stringset_t *set, const char *str) {
850 stringset_t s;
851 for (s = *set; *s; s++)
852 if (strcmp(*s, str) == 0)
853 return 1;
854 return 0;
857 void list_codecs(int audioflag){
858 int i;
859 codecs_t *c;
861 if (audioflag) {
862 i = nr_acodecs;
863 c = audio_codecs;
864 mp_msg(MSGT_CODECCFG,MSGL_INFO,"ac: afm: status: info: [lib/dll]\n");
865 } else {
866 i = nr_vcodecs;
867 c = video_codecs;
868 mp_msg(MSGT_CODECCFG,MSGL_INFO,"vc: vfm: status: info: [lib/dll]\n");
870 if(!i) return;
871 for (/* NOTHING */; i--; c++) {
872 char* s="unknown ";
873 switch(c->status){
874 case CODECS_STATUS_WORKING: s="working ";break;
875 case CODECS_STATUS_PROBLEMS: s="problems";break;
876 case CODECS_STATUS_NOT_WORKING: s="crashing";break;
877 case CODECS_STATUS_UNTESTED: s="untested";break;
879 if(c->dll)
880 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s [%s]\n",c->name,c->drv,s,c->info,c->dll);
881 else
882 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s\n",c->name,c->drv,s,c->info);
890 #ifdef CODECS2HTML
892 * Fake out GUI references when building the codecs2html utility.
894 #ifdef CONFIG_GUI
895 void gtkMessageBox( int type,char * str ) { return; }
896 int use_gui = 0;
897 #endif
899 void wrapline(FILE *f2,char *s){
900 int c;
901 if(!s){
902 fprintf(f2,"-");
903 return;
905 while((c=*s++)){
906 if(c==',') fprintf(f2,"<br>"); else fputc(c,f2);
910 void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
911 int c,d;
912 while((c=fgetc(f1))>=0){
913 if(c!='%'){
914 fputc(c,f2);
915 continue;
917 d=fgetc(f1);
919 switch(d){
920 case '.':
921 return; // end of section
922 case 'n':
923 wrapline(f2,codec->name); break;
924 case 'i':
925 wrapline(f2,codec->info); break;
926 case 'c':
927 wrapline(f2,codec->comment); break;
928 case 'd':
929 wrapline(f2,codec->dll); break;
930 case 'D':
931 fprintf(f2,"%c",!strcmp(codec->drv,"dshow")?'+':'-'); break;
932 case 'F':
933 for(d=0;d<CODECS_MAX_FOURCC;d++)
934 if(!d || codec->fourcc[d]!=0xFFFFFFFF)
935 fprintf(f2,"%s%.4s",d?"<br>":"",(codec->fourcc[d]==0xFFFFFFFF || codec->fourcc[d]<0x20202020)?!d?"-":"":(char*) &codec->fourcc[d]);
936 break;
937 case 'f':
938 for(d=0;d<CODECS_MAX_FOURCC;d++)
939 if(codec->fourcc[d]!=0xFFFFFFFF)
940 fprintf(f2,"%s0x%X",d?"<br>":"",codec->fourcc[d]);
941 break;
942 case 'Y':
943 for(d=0;d<CODECS_MAX_OUTFMT;d++)
944 if(codec->outfmt[d]!=0xFFFFFFFF){
945 for (c=0; fmt_table[c].name; c++)
946 if(fmt_table[c].num==codec->outfmt[d]) break;
947 if(fmt_table[c].name)
948 fprintf(f2,"%s%s",d?"<br>":"",fmt_table[c].name);
950 break;
951 default:
952 fputc(c,f2);
953 fputc(d,f2);
959 void skiphtml(FILE *f1){
960 int c,d;
961 while((c=fgetc(f1))>=0){
962 if(c!='%'){
963 continue;
965 d=fgetc(f1);
966 if(d=='.') return; // end of section
970 static void print_int_array(const int* a, int size)
972 printf("{ ");
973 while (size--)
974 if(abs(*a)<256)
975 printf("%d%s", *a++, size?", ":"");
976 else
977 printf("0x%X%s", *a++, size?", ":"");
978 printf(" }");
981 static void print_char_array(const unsigned char* a, int size)
983 printf("{ ");
984 while (size--)
985 if((*a)<10)
986 printf("%d%s", *a++, size?", ":"");
987 else
988 printf("0x%02x%s", *a++, size?", ":"");
989 printf(" }");
992 static void print_string(const char* s)
994 if (!s) printf("NULL");
995 else printf("\"%s\"", s);
998 int main(int argc, char* argv[])
1000 codecs_t *cl;
1001 FILE *f1;
1002 FILE *f2;
1003 int c,d,i;
1004 int pos;
1005 int section=-1;
1006 int nr_codecs;
1007 int win32=-1;
1008 int dshow=-1;
1009 int win32ex=-1;
1012 * Take path to codecs.conf from command line, or fall back on
1013 * etc/codecs.conf
1015 if (!(nr_codecs = parse_codec_cfg((argc>1)?argv[1]:"etc/codecs.conf")))
1016 exit(1);
1018 if (argc > 1) {
1019 int i, j;
1020 const char* nm[2];
1021 codecs_t* cod[2];
1022 int nr[2];
1024 nm[0] = "builtin_video_codecs";
1025 cod[0] = video_codecs;
1026 nr[0] = nr_vcodecs;
1028 nm[1] = "builtin_audio_codecs";
1029 cod[1] = audio_codecs;
1030 nr[1] = nr_acodecs;
1032 printf("/* GENERATED FROM %s, DO NOT EDIT! */\n\n",argv[1]);
1033 printf("#include <stddef.h>\n",argv[1]);
1034 printf("#include \"codec-cfg.h\"\n\n",argv[1]);
1036 for (i=0; i<2; i++) {
1037 printf("const codecs_t %s[] = {\n", nm[i]);
1038 for (j = 0; j < nr[i]; j++) {
1039 printf("{");
1041 print_int_array(cod[i][j].fourcc, CODECS_MAX_FOURCC);
1042 printf(", /* fourcc */\n");
1044 print_int_array(cod[i][j].fourccmap, CODECS_MAX_FOURCC);
1045 printf(", /* fourccmap */\n");
1047 print_int_array(cod[i][j].outfmt, CODECS_MAX_OUTFMT);
1048 printf(", /* outfmt */\n");
1050 print_char_array(cod[i][j].outflags, CODECS_MAX_OUTFMT);
1051 printf(", /* outflags */\n");
1053 print_int_array(cod[i][j].infmt, CODECS_MAX_INFMT);
1054 printf(", /* infmt */\n");
1056 print_char_array(cod[i][j].inflags, CODECS_MAX_INFMT);
1057 printf(", /* inflags */\n");
1059 print_string(cod[i][j].name); printf(", /* name */\n");
1060 print_string(cod[i][j].info); printf(", /* info */\n");
1061 print_string(cod[i][j].comment); printf(", /* comment */\n");
1062 print_string(cod[i][j].dll); printf(", /* dll */\n");
1063 print_string(cod[i][j].drv); printf(", /* drv */\n");
1065 printf("{ 0x%08lx, %hu, %hu,",
1066 cod[i][j].guid.f1,
1067 cod[i][j].guid.f2,
1068 cod[i][j].guid.f3);
1069 print_char_array(cod[i][j].guid.f4, sizeof(cod[i][j].guid.f4));
1070 printf(" }, /* GUID */\n");
1071 printf("%hd /* flags */, %hd /* status */, %hd /* cpuflags */ }\n",
1072 cod[i][j].flags,
1073 cod[i][j].status,
1074 cod[i][j].cpuflags);
1075 if (j < nr[i]) printf(",\n");
1077 printf("};\n\n");
1079 exit(0);
1082 f1=fopen("DOCS/tech/codecs-in.html","rb"); if(!f1) exit(1);
1083 f2=fopen("DOCS/codecs-status.html","wb"); if(!f2) exit(1);
1085 while((c=fgetc(f1))>=0){
1086 if(c!='%'){
1087 fputc(c,f2);
1088 continue;
1090 d=fgetc(f1);
1091 if(d>='0' && d<='9'){
1092 // begin section
1093 section=d-'0';
1094 //printf("BEGIN %d\n",section);
1095 if(section>=5){
1096 // audio
1097 cl = audio_codecs;
1098 nr_codecs = nr_acodecs;
1099 dshow=7;win32=4;
1100 } else {
1101 // video
1102 cl = video_codecs;
1103 nr_codecs = nr_vcodecs;
1104 dshow=4;win32=2;win32ex=6;
1106 pos=ftell(f1);
1107 for(i=0;i<nr_codecs;i++){
1108 fseek(f1,pos,SEEK_SET);
1109 switch(section){
1110 case 0:
1111 case 5:
1112 if(cl[i].status==CODECS_STATUS_WORKING)
1113 // if(!(!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1114 parsehtml(f1,f2,&cl[i],section,dshow);
1115 break;
1116 #if 0
1117 case 1:
1118 case 6:
1119 if(cl[i].status==CODECS_STATUS_WORKING)
1120 if((!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1121 parsehtml(f1,f2,&cl[i],section,dshow);
1122 break;
1123 #endif
1124 case 2:
1125 case 7:
1126 if(cl[i].status==CODECS_STATUS_PROBLEMS)
1127 parsehtml(f1,f2,&cl[i],section,dshow);
1128 break;
1129 case 3:
1130 case 8:
1131 if(cl[i].status==CODECS_STATUS_NOT_WORKING)
1132 parsehtml(f1,f2,&cl[i],section,dshow);
1133 break;
1134 case 4:
1135 case 9:
1136 if(cl[i].status==CODECS_STATUS_UNTESTED)
1137 parsehtml(f1,f2,&cl[i],section,dshow);
1138 break;
1139 default:
1140 printf("Warning! unimplemented section: %d\n",section);
1143 fseek(f1,pos,SEEK_SET);
1144 skiphtml(f1);
1145 //void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
1147 continue;
1149 fputc(c,f2);
1150 fputc(d,f2);
1153 fclose(f2);
1154 fclose(f1);
1155 return 0;
1158 #endif
1160 #ifdef TESTING
1161 int main(void)
1163 codecs_t *c;
1164 int i,j, nr_codecs, state;
1166 if (!(parse_codec_cfg("etc/codecs.conf")))
1167 return 0;
1168 if (!video_codecs)
1169 printf("no videoconfig.\n");
1170 if (!audio_codecs)
1171 printf("no audioconfig.\n");
1173 printf("videocodecs:\n");
1174 c = video_codecs;
1175 nr_codecs = nr_vcodecs;
1176 state = 0;
1177 next:
1178 if (c) {
1179 printf("number of %scodecs: %d\n", state==0?"video":"audio",
1180 nr_codecs);
1181 for(i=0;i<nr_codecs;i++, c++){
1182 printf("\n============== %scodec %02d ===============\n",
1183 state==0?"video":"audio",i);
1184 printf("name='%s'\n",c->name);
1185 printf("info='%s'\n",c->info);
1186 printf("comment='%s'\n",c->comment);
1187 printf("dll='%s'\n",c->dll);
1188 /* printf("flags=%X driver=%d status=%d cpuflags=%d\n",
1189 c->flags, c->driver, c->status, c->cpuflags); */
1190 printf("flags=%X status=%d cpuflags=%d\n",
1191 c->flags, c->status, c->cpuflags);
1193 for(j=0;j<CODECS_MAX_FOURCC;j++){
1194 if(c->fourcc[j]!=0xFFFFFFFF){
1195 printf("fourcc %02d: %08X (%.4s) ===> %08X (%.4s)\n",j,c->fourcc[j],(char *) &c->fourcc[j],c->fourccmap[j],(char *) &c->fourccmap[j]);
1199 for(j=0;j<CODECS_MAX_OUTFMT;j++){
1200 if(c->outfmt[j]!=0xFFFFFFFF){
1201 printf("outfmt %02d: %08X (%.4s) flags: %d\n",j,c->outfmt[j],(char *) &c->outfmt[j],c->outflags[j]);
1205 for(j=0;j<CODECS_MAX_INFMT;j++){
1206 if(c->infmt[j]!=0xFFFFFFFF){
1207 printf("infmt %02d: %08X (%.4s) flags: %d\n",j,c->infmt[j],(char *) &c->infmt[j],c->inflags[j]);
1211 printf("GUID: %08lX %04X %04X",c->guid.f1,c->guid.f2,c->guid.f3);
1212 for(j=0;j<8;j++) printf(" %02X",c->guid.f4[j]);
1213 printf("\n");
1218 if (!state) {
1219 printf("audiocodecs:\n");
1220 c = audio_codecs;
1221 nr_codecs = nr_acodecs;
1222 state = 1;
1223 goto next;
1225 return 0;
1228 #endif