Merge svn changes up to r28862
[mplayer.git] / codec-cfg.c
blobd14eaff5d77ef9bce567a824096ca63acebc4b6a
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
891 void wrapline(FILE *f2,char *s){
892 int c;
893 if(!s){
894 fprintf(f2,"-");
895 return;
897 while((c=*s++)){
898 if(c==',') fprintf(f2,"<br>"); else fputc(c,f2);
902 void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
903 int c,d;
904 while((c=fgetc(f1))>=0){
905 if(c!='%'){
906 fputc(c,f2);
907 continue;
909 d=fgetc(f1);
911 switch(d){
912 case '.':
913 return; // end of section
914 case 'n':
915 wrapline(f2,codec->name); break;
916 case 'i':
917 wrapline(f2,codec->info); break;
918 case 'c':
919 wrapline(f2,codec->comment); break;
920 case 'd':
921 wrapline(f2,codec->dll); break;
922 case 'D':
923 fprintf(f2,"%c",!strcmp(codec->drv,"dshow")?'+':'-'); break;
924 case 'F':
925 for(d=0;d<CODECS_MAX_FOURCC;d++)
926 if(!d || codec->fourcc[d]!=0xFFFFFFFF)
927 fprintf(f2,"%s%.4s",d?"<br>":"",(codec->fourcc[d]==0xFFFFFFFF || codec->fourcc[d]<0x20202020)?!d?"-":"":(char*) &codec->fourcc[d]);
928 break;
929 case 'f':
930 for(d=0;d<CODECS_MAX_FOURCC;d++)
931 if(codec->fourcc[d]!=0xFFFFFFFF)
932 fprintf(f2,"%s0x%X",d?"<br>":"",codec->fourcc[d]);
933 break;
934 case 'Y':
935 for(d=0;d<CODECS_MAX_OUTFMT;d++)
936 if(codec->outfmt[d]!=0xFFFFFFFF){
937 for (c=0; fmt_table[c].name; c++)
938 if(fmt_table[c].num==codec->outfmt[d]) break;
939 if(fmt_table[c].name)
940 fprintf(f2,"%s%s",d?"<br>":"",fmt_table[c].name);
942 break;
943 default:
944 fputc(c,f2);
945 fputc(d,f2);
951 void skiphtml(FILE *f1){
952 int c,d;
953 while((c=fgetc(f1))>=0){
954 if(c!='%'){
955 continue;
957 d=fgetc(f1);
958 if(d=='.') return; // end of section
962 static void print_int_array(const int* a, int size)
964 printf("{ ");
965 while (size--)
966 if(abs(*a)<256)
967 printf("%d%s", *a++, size?", ":"");
968 else
969 printf("0x%X%s", *a++, size?", ":"");
970 printf(" }");
973 static void print_char_array(const unsigned char* a, int size)
975 printf("{ ");
976 while (size--)
977 if((*a)<10)
978 printf("%d%s", *a++, size?", ":"");
979 else
980 printf("0x%02x%s", *a++, size?", ":"");
981 printf(" }");
984 static void print_string(const char* s)
986 if (!s) printf("NULL");
987 else printf("\"%s\"", s);
990 int main(int argc, char* argv[])
992 codecs_t *cl;
993 FILE *f1;
994 FILE *f2;
995 int c,d,i;
996 int pos;
997 int section=-1;
998 int nr_codecs;
999 int win32=-1;
1000 int dshow=-1;
1001 int win32ex=-1;
1004 * Take path to codecs.conf from command line, or fall back on
1005 * etc/codecs.conf
1007 if (!(nr_codecs = parse_codec_cfg((argc>1)?argv[1]:"etc/codecs.conf")))
1008 exit(1);
1010 if (argc > 1) {
1011 int i, j;
1012 const char* nm[2];
1013 codecs_t* cod[2];
1014 int nr[2];
1016 nm[0] = "builtin_video_codecs";
1017 cod[0] = video_codecs;
1018 nr[0] = nr_vcodecs;
1020 nm[1] = "builtin_audio_codecs";
1021 cod[1] = audio_codecs;
1022 nr[1] = nr_acodecs;
1024 printf("/* GENERATED FROM %s, DO NOT EDIT! */\n\n",argv[1]);
1025 printf("#include <stddef.h>\n",argv[1]);
1026 printf("#include \"codec-cfg.h\"\n\n",argv[1]);
1028 for (i=0; i<2; i++) {
1029 printf("const codecs_t %s[] = {\n", nm[i]);
1030 for (j = 0; j < nr[i]; j++) {
1031 printf("{");
1033 print_int_array(cod[i][j].fourcc, CODECS_MAX_FOURCC);
1034 printf(", /* fourcc */\n");
1036 print_int_array(cod[i][j].fourccmap, CODECS_MAX_FOURCC);
1037 printf(", /* fourccmap */\n");
1039 print_int_array(cod[i][j].outfmt, CODECS_MAX_OUTFMT);
1040 printf(", /* outfmt */\n");
1042 print_char_array(cod[i][j].outflags, CODECS_MAX_OUTFMT);
1043 printf(", /* outflags */\n");
1045 print_int_array(cod[i][j].infmt, CODECS_MAX_INFMT);
1046 printf(", /* infmt */\n");
1048 print_char_array(cod[i][j].inflags, CODECS_MAX_INFMT);
1049 printf(", /* inflags */\n");
1051 print_string(cod[i][j].name); printf(", /* name */\n");
1052 print_string(cod[i][j].info); printf(", /* info */\n");
1053 print_string(cod[i][j].comment); printf(", /* comment */\n");
1054 print_string(cod[i][j].dll); printf(", /* dll */\n");
1055 print_string(cod[i][j].drv); printf(", /* drv */\n");
1057 printf("{ 0x%08lx, %hu, %hu,",
1058 cod[i][j].guid.f1,
1059 cod[i][j].guid.f2,
1060 cod[i][j].guid.f3);
1061 print_char_array(cod[i][j].guid.f4, sizeof(cod[i][j].guid.f4));
1062 printf(" }, /* GUID */\n");
1063 printf("%hd /* flags */, %hd /* status */, %hd /* cpuflags */ }\n",
1064 cod[i][j].flags,
1065 cod[i][j].status,
1066 cod[i][j].cpuflags);
1067 if (j < nr[i]) printf(",\n");
1069 printf("};\n\n");
1071 exit(0);
1074 f1=fopen("DOCS/tech/codecs-in.html","rb"); if(!f1) exit(1);
1075 f2=fopen("DOCS/codecs-status.html","wb"); if(!f2) exit(1);
1077 while((c=fgetc(f1))>=0){
1078 if(c!='%'){
1079 fputc(c,f2);
1080 continue;
1082 d=fgetc(f1);
1083 if(d>='0' && d<='9'){
1084 // begin section
1085 section=d-'0';
1086 //printf("BEGIN %d\n",section);
1087 if(section>=5){
1088 // audio
1089 cl = audio_codecs;
1090 nr_codecs = nr_acodecs;
1091 dshow=7;win32=4;
1092 } else {
1093 // video
1094 cl = video_codecs;
1095 nr_codecs = nr_vcodecs;
1096 dshow=4;win32=2;win32ex=6;
1098 pos=ftell(f1);
1099 for(i=0;i<nr_codecs;i++){
1100 fseek(f1,pos,SEEK_SET);
1101 switch(section){
1102 case 0:
1103 case 5:
1104 if(cl[i].status==CODECS_STATUS_WORKING)
1105 // if(!(!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1106 parsehtml(f1,f2,&cl[i],section,dshow);
1107 break;
1108 #if 0
1109 case 1:
1110 case 6:
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 #endif
1116 case 2:
1117 case 7:
1118 if(cl[i].status==CODECS_STATUS_PROBLEMS)
1119 parsehtml(f1,f2,&cl[i],section,dshow);
1120 break;
1121 case 3:
1122 case 8:
1123 if(cl[i].status==CODECS_STATUS_NOT_WORKING)
1124 parsehtml(f1,f2,&cl[i],section,dshow);
1125 break;
1126 case 4:
1127 case 9:
1128 if(cl[i].status==CODECS_STATUS_UNTESTED)
1129 parsehtml(f1,f2,&cl[i],section,dshow);
1130 break;
1131 default:
1132 printf("Warning! unimplemented section: %d\n",section);
1135 fseek(f1,pos,SEEK_SET);
1136 skiphtml(f1);
1137 //void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
1139 continue;
1141 fputc(c,f2);
1142 fputc(d,f2);
1145 fclose(f2);
1146 fclose(f1);
1147 return 0;
1150 #endif
1152 #ifdef TESTING
1153 int main(void)
1155 codecs_t *c;
1156 int i,j, nr_codecs, state;
1158 if (!(parse_codec_cfg("etc/codecs.conf")))
1159 return 0;
1160 if (!video_codecs)
1161 printf("no videoconfig.\n");
1162 if (!audio_codecs)
1163 printf("no audioconfig.\n");
1165 printf("videocodecs:\n");
1166 c = video_codecs;
1167 nr_codecs = nr_vcodecs;
1168 state = 0;
1169 next:
1170 if (c) {
1171 printf("number of %scodecs: %d\n", state==0?"video":"audio",
1172 nr_codecs);
1173 for(i=0;i<nr_codecs;i++, c++){
1174 printf("\n============== %scodec %02d ===============\n",
1175 state==0?"video":"audio",i);
1176 printf("name='%s'\n",c->name);
1177 printf("info='%s'\n",c->info);
1178 printf("comment='%s'\n",c->comment);
1179 printf("dll='%s'\n",c->dll);
1180 /* printf("flags=%X driver=%d status=%d cpuflags=%d\n",
1181 c->flags, c->driver, c->status, c->cpuflags); */
1182 printf("flags=%X status=%d cpuflags=%d\n",
1183 c->flags, c->status, c->cpuflags);
1185 for(j=0;j<CODECS_MAX_FOURCC;j++){
1186 if(c->fourcc[j]!=0xFFFFFFFF){
1187 printf("fourcc %02d: %08X (%.4s) ===> %08X (%.4s)\n",j,c->fourcc[j],(char *) &c->fourcc[j],c->fourccmap[j],(char *) &c->fourccmap[j]);
1191 for(j=0;j<CODECS_MAX_OUTFMT;j++){
1192 if(c->outfmt[j]!=0xFFFFFFFF){
1193 printf("outfmt %02d: %08X (%.4s) flags: %d\n",j,c->outfmt[j],(char *) &c->outfmt[j],c->outflags[j]);
1197 for(j=0;j<CODECS_MAX_INFMT;j++){
1198 if(c->infmt[j]!=0xFFFFFFFF){
1199 printf("infmt %02d: %08X (%.4s) flags: %d\n",j,c->infmt[j],(char *) &c->infmt[j],c->inflags[j]);
1203 printf("GUID: %08lX %04X %04X",c->guid.f1,c->guid.f2,c->guid.f3);
1204 for(j=0;j<8;j++) printf(" %02X",c->guid.f4[j]);
1205 printf("\n");
1210 if (!state) {
1211 printf("audiocodecs:\n");
1212 c = audio_codecs;
1213 nr_codecs = nr_acodecs;
1214 state = 1;
1215 goto next;
1217 return 0;
1220 #endif