misc updates
[mplayer/glamo.git] / codec-cfg.c
blob2ba7fe60de455f1523d742e584959dce33f3dc05
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>
28 #include "config.h"
29 #include "mp_msg.h"
30 #ifdef CODECS2HTML
31 #ifdef __GNUC__
32 #define mp_msg(t, l, m, args...) fprintf(stderr, m, ##args)
33 #else
34 #define mp_msg(t, l, ...) fprintf(stderr, __VA_ARGS__)
35 #endif
36 #endif
38 #include "help_mp.h"
40 // for mmioFOURCC:
41 #include "libmpdemux/aviheader.h"
43 #include "libmpcodecs/img_format.h"
44 #include "codec-cfg.h"
46 #ifndef CODECS2HTML
47 #include "codecs.conf.h"
48 #endif
50 #define PRINT_LINENUM mp_msg(MSGT_CODECCFG,MSGL_ERR," at line %d\n", line_num)
52 #define MAX_NR_TOKEN 16
54 #define MAX_LINE_LEN 1000
56 #define RET_EOF -1
57 #define RET_EOL -2
59 #define TYPE_VIDEO 0
60 #define TYPE_AUDIO 1
62 char * codecs_file = NULL;
64 static int add_to_fourcc(char *s, char *alias, unsigned int *fourcc,
65 unsigned int *map)
67 int i, j, freeslots;
68 unsigned int tmp;
70 /* find first unused slot */
71 for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++)
72 /* NOTHING */;
73 freeslots = CODECS_MAX_FOURCC - i;
74 if (!freeslots)
75 goto err_out_too_many;
77 do {
78 tmp = mmioFOURCC(s[0], s[1], s[2], s[3]);
79 for (j = 0; j < i; j++)
80 if (tmp == fourcc[j])
81 goto err_out_duplicated;
82 fourcc[i] = tmp;
83 map[i] = alias ? mmioFOURCC(alias[0], alias[1], alias[2], alias[3]) : tmp;
84 s += 4;
85 i++;
86 } while ((*(s++) == ',') && --freeslots);
88 if (!freeslots)
89 goto err_out_too_many;
90 if (*(--s) != '\0')
91 goto err_out_parse_error;
92 return 1;
93 err_out_duplicated:
94 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_DuplicateFourcc);
95 return 0;
96 err_out_too_many:
97 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_TooManyFourccs);
98 return 0;
99 err_out_parse_error:
100 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseError);
101 return 0;
104 static int add_to_format(char *s, char *alias,unsigned int *fourcc, unsigned int *fourccmap)
106 int i, j;
107 char *endptr;
109 /* find first unused slot */
110 for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++)
111 /* NOTHING */;
112 if (i == CODECS_MAX_FOURCC) {
113 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_TooManyFourccs);
114 return 0;
117 fourcc[i]=strtoul(s,&endptr,0);
118 if (*endptr != '\0') {
119 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseErrorFIDNotNumber);
120 return 0;
123 if(alias){
124 fourccmap[i]=strtoul(alias,&endptr,0);
125 if (*endptr != '\0') {
126 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseErrorFIDAliasNotNumber);
127 return 0;
129 } else
130 fourccmap[i]=fourcc[i];
132 for (j = 0; j < i; j++)
133 if (fourcc[j] == fourcc[i]) {
134 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_DuplicateFID);
135 return 0;
138 return 1;
141 static struct {
142 const char *name;
143 const unsigned int num;
144 } fmt_table[] = {
145 {"YV12", IMGFMT_YV12},
146 {"I420", IMGFMT_I420},
147 {"IYUV", IMGFMT_IYUV},
148 {"NV12", IMGFMT_NV12},
149 {"NV21", IMGFMT_NV21},
150 {"YVU9", IMGFMT_YVU9},
151 {"IF09", IMGFMT_IF09},
152 {"444P", IMGFMT_444P},
153 {"422P", IMGFMT_422P},
154 {"411P", IMGFMT_411P},
155 {"Y800", IMGFMT_Y800},
156 {"Y8", IMGFMT_Y8},
158 {"YUY2", IMGFMT_YUY2},
159 {"UYVY", IMGFMT_UYVY},
160 {"YVYU", IMGFMT_YVYU},
162 {"RGB4", IMGFMT_RGB|4},
163 {"RGB8", IMGFMT_RGB|8},
164 {"RGB15", IMGFMT_RGB|15},
165 {"RGB16", IMGFMT_RGB|16},
166 {"RGB24", IMGFMT_RGB|24},
167 {"RGB32", IMGFMT_RGB|32},
168 {"BGR4", IMGFMT_BGR|4},
169 {"BGR8", IMGFMT_BGR|8},
170 {"BGR15", IMGFMT_BGR|15},
171 {"BGR16", IMGFMT_BGR|16},
172 {"BGR24", IMGFMT_BGR|24},
173 {"BGR32", IMGFMT_BGR|32},
174 {"RGB1", IMGFMT_RGB|1},
175 {"BGR1", IMGFMT_BGR|1},
177 {"MPES", IMGFMT_MPEGPES},
178 {"ZRMJPEGNI", IMGFMT_ZRMJPEGNI},
179 {"ZRMJPEGIT", IMGFMT_ZRMJPEGIT},
180 {"ZRMJPEGIB", IMGFMT_ZRMJPEGIB},
182 {"IDCT_MPEG2",IMGFMT_XVMC_IDCT_MPEG2},
183 {"MOCO_MPEG2",IMGFMT_XVMC_MOCO_MPEG2},
185 {"VDPAU_MPEG1",IMGFMT_VDPAU_MPEG1},
186 {"VDPAU_MPEG2",IMGFMT_VDPAU_MPEG2},
187 {"VDPAU_H264",IMGFMT_VDPAU_H264},
188 {"VDPAU_WMV3",IMGFMT_VDPAU_WMV3},
189 {"VDPAU_VC1",IMGFMT_VDPAU_VC1},
191 {NULL, 0}
195 static int add_to_inout(char *sfmt, char *sflags, unsigned int *outfmt,
196 unsigned char *outflags)
199 static char *flagstr[] = {
200 "flip",
201 "noflip",
202 "yuvhack",
203 "query",
204 "static",
205 NULL
208 int i, j, freeslots;
209 unsigned char flags;
211 for (i = 0; i < CODECS_MAX_OUTFMT && outfmt[i] != 0xffffffff; i++)
212 /* NOTHING */;
213 freeslots = CODECS_MAX_OUTFMT - i;
214 if (!freeslots)
215 goto err_out_too_many;
217 flags = 0;
218 if(sflags) {
219 do {
220 for (j = 0; flagstr[j] != NULL; j++)
221 if (!strncmp(sflags, flagstr[j],
222 strlen(flagstr[j])))
223 break;
224 if (flagstr[j] == NULL)
225 goto err_out_parse_error;
226 flags|=(1<<j);
227 sflags+=strlen(flagstr[j]);
228 } while (*(sflags++) == ',');
230 if (*(--sflags) != '\0')
231 goto err_out_parse_error;
234 do {
235 for (j = 0; fmt_table[j].name != NULL; j++)
236 if (!strncmp(sfmt, fmt_table[j].name, strlen(fmt_table[j].name)))
237 break;
238 if (fmt_table[j].name == NULL)
239 goto err_out_parse_error;
240 outfmt[i] = fmt_table[j].num;
241 outflags[i] = flags;
242 ++i;
243 sfmt+=strlen(fmt_table[j].name);
244 } while ((*(sfmt++) == ',') && --freeslots);
246 if (!freeslots)
247 goto err_out_too_many;
249 if (*(--sfmt) != '\0')
250 goto err_out_parse_error;
252 return 1;
253 err_out_too_many:
254 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_TooManyOut);
255 return 0;
256 err_out_parse_error:
257 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseError);
258 return 0;
261 #if 0
262 static short get_driver(char *s,int audioflag)
264 static char *audiodrv[] = {
265 "null",
266 "mp3lib",
267 "pcm",
268 "libac3",
269 "acm",
270 "alaw",
271 "msgsm",
272 "dshow",
273 "dvdpcm",
274 "hwac3",
275 "libvorbis",
276 "ffmpeg",
277 "libmad",
278 "msadpcm",
279 "liba52",
280 "g72x",
281 "imaadpcm",
282 "dk4adpcm",
283 "dk3adpcm",
284 "roqaudio",
285 "faad",
286 "realaud",
287 "libdv",
288 NULL
290 static char *videodrv[] = {
291 "null",
292 "libmpeg2",
293 "vfw",
294 "dshow",
295 "ffmpeg",
296 "vfwex",
297 "raw",
298 "msrle",
299 "xanim",
300 "msvidc",
301 "fli",
302 "cinepak",
303 "qtrle",
304 "nuv",
305 "cyuv",
306 "qtsmc",
307 "ducktm1",
308 "roqvideo",
309 "qtrpza",
310 "mpng",
311 "ijpg",
312 "zlib",
313 "mpegpes",
314 "zrmjpeg",
315 "realvid",
316 "xvid",
317 "libdv",
318 NULL
320 char **drv=audioflag?audiodrv:videodrv;
321 int i;
323 for(i=0;drv[i];i++) if(!strcmp(s,drv[i])) return i;
325 return -1;
327 #endif
329 static int validate_codec(codecs_t *c, int type)
331 unsigned int i;
332 char *tmp_name = c->name;
334 for (i = 0; i < strlen(tmp_name) && isalnum(tmp_name[i]); i++)
335 /* NOTHING */;
337 if (i < strlen(tmp_name)) {
338 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_InvalidCodecName, c->name);
339 return 0;
342 if (!c->info)
343 c->info = strdup(c->name);
345 #if 0
346 if (c->fourcc[0] == 0xffffffff) {
347 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecLacksFourcc, c->name);
348 return 0;
350 #endif
352 if (!c->drv) {
353 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecLacksDriver, c->name);
354 return 0;
357 #if 0
358 #warning codec->driver == 4;... <- this should not be put in here...
359 #warning Where are they defined ????????????
360 if (!c->dll && (c->driver == 4 ||
361 (c->driver == 2 && type == TYPE_VIDEO))) {
362 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecNeedsDLL, c->name);
363 return 0;
365 #warning Can guid.f1 be 0? How does one know that it was not given?
366 // if (!(codec->flags & CODECS_FLAG_AUDIO) && codec->driver == 4)
368 if (type == TYPE_VIDEO)
369 if (c->outfmt[0] == 0xffffffff) {
370 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecNeedsOutfmt, c->name);
371 return 0;
373 #endif
374 return 1;
377 static int add_comment(char *s, char **d)
379 int pos;
381 if (!*d)
382 pos = 0;
383 else {
384 pos = strlen(*d);
385 (*d)[pos++] = '\n';
387 if (!(*d = realloc(*d, pos + strlen(s) + 1))) {
388 mp_msg(MSGT_CODECCFG,MSGL_FATAL,MSGTR_CantAllocateComment);
389 return 0;
391 strcpy(*d + pos, s);
392 return 1;
395 static short get_cpuflags(char *s)
397 static char *flagstr[] = {
398 "mmx",
399 "sse",
400 "3dnow",
401 NULL
403 int i;
404 short flags = 0;
406 do {
407 for (i = 0; flagstr[i]; i++)
408 if (!strncmp(s, flagstr[i], strlen(flagstr[i])))
409 break;
410 if (!flagstr[i])
411 goto err_out_parse_error;
412 flags |= 1<<i;
413 s += strlen(flagstr[i]);
414 } while (*(s++) == ',');
416 if (*(--s) != '\0')
417 goto err_out_parse_error;
419 return flags;
420 err_out_parse_error:
421 return 0;
424 static FILE *fp;
425 static int line_num = 0;
426 static char *line;
427 static char *token[MAX_NR_TOKEN];
428 static int read_nextline = 1;
430 static int get_token(int min, int max)
432 static int line_pos;
433 int i;
434 char c;
436 if (max >= MAX_NR_TOKEN) {
437 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_GetTokenMaxNotLessThanMAX_NR_TOKEN);
438 goto out_eof;
441 memset(token, 0x00, sizeof(*token) * max);
443 if (read_nextline) {
444 if (!fgets(line, MAX_LINE_LEN, fp))
445 goto out_eof;
446 line_pos = 0;
447 ++line_num;
448 read_nextline = 0;
450 for (i = 0; i < max; i++) {
451 while (isspace(line[line_pos]))
452 ++line_pos;
453 if (line[line_pos] == '\0' || line[line_pos] == '#' ||
454 line[line_pos] == ';') {
455 read_nextline = 1;
456 if (i >= min)
457 goto out_ok;
458 goto out_eol;
460 token[i] = line + line_pos;
461 c = line[line_pos];
462 if (c == '"' || c == '\'') {
463 token[i]++;
464 while (line[++line_pos] != c && line[line_pos])
465 /* NOTHING */;
466 } else {
467 for (/* NOTHING */; !isspace(line[line_pos]) &&
468 line[line_pos]; line_pos++)
469 /* NOTHING */;
471 if (!line[line_pos]) {
472 read_nextline = 1;
473 if (i >= min - 1)
474 goto out_ok;
475 goto out_eol;
477 line[line_pos] = '\0';
478 line_pos++;
480 out_ok:
481 return i;
482 out_eof:
483 read_nextline = 1;
484 return RET_EOF;
485 out_eol:
486 return RET_EOL;
489 static codecs_t *video_codecs=NULL;
490 static codecs_t *audio_codecs=NULL;
491 static int nr_vcodecs = 0;
492 static int nr_acodecs = 0;
494 int parse_codec_cfg(const char *cfgfile)
496 codecs_t *codec = NULL; // current codec
497 codecs_t **codecsp = NULL;// points to audio_codecs or to video_codecs
498 char *endptr; // strtoul()...
499 int *nr_codecsp;
500 int codec_type; /* TYPE_VIDEO/TYPE_AUDIO */
501 int tmp, i;
503 // in case we call it a second time
504 codecs_uninit_free();
506 nr_vcodecs = 0;
507 nr_acodecs = 0;
509 if(cfgfile==NULL) {
510 #ifdef CODECS2HTML
511 return 0;
512 #else
513 video_codecs = builtin_video_codecs;
514 audio_codecs = builtin_audio_codecs;
515 nr_vcodecs = sizeof(builtin_video_codecs)/sizeof(codecs_t);
516 nr_acodecs = sizeof(builtin_audio_codecs)/sizeof(codecs_t);
517 return 1;
518 #endif
521 mp_msg(MSGT_CODECCFG,MSGL_V,MSGTR_ReadingFile, cfgfile);
523 if ((fp = fopen(cfgfile, "r")) == NULL) {
524 mp_msg(MSGT_CODECCFG,MSGL_V,MSGTR_CantOpenFileError, cfgfile, strerror(errno));
525 return 0;
528 if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) {
529 mp_msg(MSGT_CODECCFG,MSGL_FATAL,MSGTR_CantGetMemoryForLine, strerror(errno));
530 return 0;
532 read_nextline = 1;
535 * this only catches release lines at the start of
536 * codecs.conf, before audiocodecs and videocodecs.
538 while ((tmp = get_token(1, 1)) == RET_EOL)
539 /* NOTHING */;
540 if (tmp == RET_EOF)
541 goto out;
542 if (!strcmp(token[0], "release")) {
543 if (get_token(1, 2) < 0)
544 goto err_out_parse_error;
545 tmp = atoi(token[0]);
546 if (tmp < CODEC_CFG_MIN)
547 goto err_out_release_num;
548 while ((tmp = get_token(1, 1)) == RET_EOL)
549 /* NOTHING */;
550 if (tmp == RET_EOF)
551 goto out;
552 } else
553 goto err_out_release_num;
556 * check if the next block starts with 'audiocodec' or
557 * with 'videocodec'
559 if (!strcmp(token[0], "audiocodec") || !strcmp(token[0], "videocodec"))
560 goto loop_enter;
561 goto err_out_parse_error;
563 while ((tmp = get_token(1, 1)) != RET_EOF) {
564 if (tmp == RET_EOL)
565 continue;
566 if (!strcmp(token[0], "audiocodec") ||
567 !strcmp(token[0], "videocodec")) {
568 if (!validate_codec(codec, codec_type))
569 goto err_out_not_valid;
570 loop_enter:
571 if (*token[0] == 'v') {
572 codec_type = TYPE_VIDEO;
573 nr_codecsp = &nr_vcodecs;
574 codecsp = &video_codecs;
575 } else if (*token[0] == 'a') {
576 codec_type = TYPE_AUDIO;
577 nr_codecsp = &nr_acodecs;
578 codecsp = &audio_codecs;
579 #ifdef DEBUG
580 } else {
581 mp_msg(MSGT_CODECCFG,MSGL_ERR,"picsba\n");
582 goto err_out;
583 #endif
585 if (!(*codecsp = realloc(*codecsp,
586 sizeof(codecs_t) * (*nr_codecsp + 2)))) {
587 mp_msg(MSGT_CODECCFG,MSGL_FATAL,MSGTR_CantReallocCodecsp, strerror(errno));
588 goto err_out;
590 codec=*codecsp + *nr_codecsp;
591 ++*nr_codecsp;
592 memset(codec,0,sizeof(codecs_t));
593 memset(codec->fourcc, 0xff, sizeof(codec->fourcc));
594 memset(codec->outfmt, 0xff, sizeof(codec->outfmt));
595 memset(codec->infmt, 0xff, sizeof(codec->infmt));
597 if (get_token(1, 1) < 0)
598 goto err_out_parse_error;
599 for (i = 0; i < *nr_codecsp - 1; i++) {
600 if(( (*codecsp)[i].name!=NULL) &&
601 (!strcmp(token[0], (*codecsp)[i].name)) ) {
602 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecNameNotUnique, token[0]);
603 goto err_out_print_linenum;
606 if (!(codec->name = strdup(token[0]))) {
607 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupName, strerror(errno));
608 goto err_out;
610 } else if (!strcmp(token[0], "info")) {
611 if (codec->info || get_token(1, 1) < 0)
612 goto err_out_parse_error;
613 if (!(codec->info = strdup(token[0]))) {
614 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupInfo, strerror(errno));
615 goto err_out;
617 } else if (!strcmp(token[0], "comment")) {
618 if (get_token(1, 1) < 0)
619 goto err_out_parse_error;
620 add_comment(token[0], &codec->comment);
621 } else if (!strcmp(token[0], "fourcc")) {
622 if (get_token(1, 2) < 0)
623 goto err_out_parse_error;
624 if (!add_to_fourcc(token[0], token[1],
625 codec->fourcc,
626 codec->fourccmap))
627 goto err_out_print_linenum;
628 } else if (!strcmp(token[0], "format")) {
629 if (get_token(1, 2) < 0)
630 goto err_out_parse_error;
631 if (!add_to_format(token[0], token[1],
632 codec->fourcc,codec->fourccmap))
633 goto err_out_print_linenum;
634 } else if (!strcmp(token[0], "driver")) {
635 if (get_token(1, 1) < 0)
636 goto err_out_parse_error;
637 if (!(codec->drv = strdup(token[0]))) {
638 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupDriver, strerror(errno));
639 goto err_out;
641 } else if (!strcmp(token[0], "dll")) {
642 if (get_token(1, 1) < 0)
643 goto err_out_parse_error;
644 if (!(codec->dll = strdup(token[0]))) {
645 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupDLL, strerror(errno));
646 goto err_out;
648 } else if (!strcmp(token[0], "guid")) {
649 if (get_token(11, 11) < 0)
650 goto err_out_parse_error;
651 codec->guid.f1=strtoul(token[0],&endptr,0);
652 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
653 *endptr != '\0')
654 goto err_out_parse_error;
655 codec->guid.f2=strtoul(token[1],&endptr,0);
656 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
657 *endptr != '\0')
658 goto err_out_parse_error;
659 codec->guid.f3=strtoul(token[2],&endptr,0);
660 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
661 *endptr != '\0')
662 goto err_out_parse_error;
663 for (i = 0; i < 8; i++) {
664 codec->guid.f4[i]=strtoul(token[i + 3],&endptr,0);
665 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
666 *endptr != '\0')
667 goto err_out_parse_error;
669 } else if (!strcmp(token[0], "out")) {
670 if (get_token(1, 2) < 0)
671 goto err_out_parse_error;
672 if (!add_to_inout(token[0], token[1], codec->outfmt,
673 codec->outflags))
674 goto err_out_print_linenum;
675 } else if (!strcmp(token[0], "in")) {
676 if (get_token(1, 2) < 0)
677 goto err_out_parse_error;
678 if (!add_to_inout(token[0], token[1], codec->infmt,
679 codec->inflags))
680 goto err_out_print_linenum;
681 } else if (!strcmp(token[0], "flags")) {
682 if (get_token(1, 1) < 0)
683 goto err_out_parse_error;
684 if (!strcmp(token[0], "seekable"))
685 codec->flags |= CODECS_FLAG_SEEKABLE;
686 else
687 if (!strcmp(token[0], "align16"))
688 codec->flags |= CODECS_FLAG_ALIGN16;
689 else
690 goto err_out_parse_error;
691 } else if (!strcmp(token[0], "status")) {
692 if (get_token(1, 1) < 0)
693 goto err_out_parse_error;
694 if (!strcasecmp(token[0], "working"))
695 codec->status = CODECS_STATUS_WORKING;
696 else if (!strcasecmp(token[0], "crashing"))
697 codec->status = CODECS_STATUS_NOT_WORKING;
698 else if (!strcasecmp(token[0], "untested"))
699 codec->status = CODECS_STATUS_UNTESTED;
700 else if (!strcasecmp(token[0], "buggy"))
701 codec->status = CODECS_STATUS_PROBLEMS;
702 else
703 goto err_out_parse_error;
704 } else if (!strcmp(token[0], "cpuflags")) {
705 if (get_token(1, 1) < 0)
706 goto err_out_parse_error;
707 if (!(codec->cpuflags = get_cpuflags(token[0])))
708 goto err_out_parse_error;
709 } else
710 goto err_out_parse_error;
712 if (!validate_codec(codec, codec_type))
713 goto err_out_not_valid;
714 mp_msg(MSGT_CODECCFG,MSGL_INFO,MSGTR_AudioVideoCodecTotals, nr_acodecs, nr_vcodecs);
715 if(video_codecs) video_codecs[nr_vcodecs].name = NULL;
716 if(audio_codecs) audio_codecs[nr_acodecs].name = NULL;
717 out:
718 free(line);
719 line=NULL;
720 fclose(fp);
721 return 1;
723 err_out_parse_error:
724 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseError);
725 err_out_print_linenum:
726 PRINT_LINENUM;
727 err_out:
728 codecs_uninit_free();
730 free(line);
731 line=NULL;
732 line_num = 0;
733 fclose(fp);
734 return 0;
735 err_out_not_valid:
736 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecDefinitionIncorrect);
737 goto err_out_print_linenum;
738 err_out_release_num:
739 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_OutdatedCodecsConf);
740 goto err_out_print_linenum;
743 static void codecs_free(codecs_t* codecs,int count) {
744 int i;
745 for ( i = 0; i < count; i++)
746 if ( codecs[i].name ) {
747 if( codecs[i].name )
748 free(codecs[i].name);
749 if( codecs[i].info )
750 free(codecs[i].info);
751 if( codecs[i].comment )
752 free(codecs[i].comment);
753 if( codecs[i].dll )
754 free(codecs[i].dll);
755 if( codecs[i].drv )
756 free(codecs[i].drv);
758 if (codecs)
759 free(codecs);
762 void codecs_uninit_free(void) {
763 if (video_codecs)
764 codecs_free(video_codecs,nr_vcodecs);
765 video_codecs=NULL;
766 if (audio_codecs)
767 codecs_free(audio_codecs,nr_acodecs);
768 audio_codecs=NULL;
771 codecs_t *find_audio_codec(unsigned int fourcc, unsigned int *fourccmap,
772 codecs_t *start, int force)
774 return find_codec(fourcc, fourccmap, start, 1, force);
777 codecs_t *find_video_codec(unsigned int fourcc, unsigned int *fourccmap,
778 codecs_t *start, int force)
780 return find_codec(fourcc, fourccmap, start, 0, force);
783 codecs_t* find_codec(unsigned int fourcc,unsigned int *fourccmap,
784 codecs_t *start, int audioflag, int force)
786 int i, j;
787 codecs_t *c;
789 #if 0
790 if (start) {
791 for (/* NOTHING */; start->name; start++) {
792 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
793 if (start->fourcc[j] == fourcc) {
794 if (fourccmap)
795 *fourccmap = start->fourccmap[j];
796 return start;
800 } else
801 #endif
803 if (audioflag) {
804 i = nr_acodecs;
805 c = audio_codecs;
806 } else {
807 i = nr_vcodecs;
808 c = video_codecs;
810 if(!i) return NULL;
811 for (/* NOTHING */; i--; c++) {
812 if(start && c<=start) continue;
813 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
814 // FIXME: do NOT hardwire 'null' name here:
815 if (c->fourcc[j]==fourcc || !strcmp(c->drv,"null")) {
816 if (fourccmap)
817 *fourccmap = c->fourccmap[j];
818 return c;
821 if (force) return c;
824 return NULL;
827 void stringset_init(stringset_t *set) {
828 *set = calloc(1, sizeof(char *));
831 void stringset_free(stringset_t *set) {
832 int count = 0;
833 while ((*set)[count]) free((*set)[count++]);
834 free(*set);
835 *set = NULL;
838 void stringset_add(stringset_t *set, const char *str) {
839 int count = 0;
840 while ((*set)[count]) count++;
841 count++;
842 *set = realloc(*set, sizeof(char *) * (count + 1));
843 (*set)[count - 1] = strdup(str);
844 (*set)[count] = NULL;
847 int stringset_test(stringset_t *set, const char *str) {
848 stringset_t s;
849 for (s = *set; *s; s++)
850 if (strcmp(*s, str) == 0)
851 return 1;
852 return 0;
855 void list_codecs(int audioflag){
856 int i;
857 codecs_t *c;
859 if (audioflag) {
860 i = nr_acodecs;
861 c = audio_codecs;
862 mp_msg(MSGT_CODECCFG,MSGL_INFO,"ac: afm: status: info: [lib/dll]\n");
863 } else {
864 i = nr_vcodecs;
865 c = video_codecs;
866 mp_msg(MSGT_CODECCFG,MSGL_INFO,"vc: vfm: status: info: [lib/dll]\n");
868 if(!i) return;
869 for (/* NOTHING */; i--; c++) {
870 char* s="unknown ";
871 switch(c->status){
872 case CODECS_STATUS_WORKING: s="working ";break;
873 case CODECS_STATUS_PROBLEMS: s="problems";break;
874 case CODECS_STATUS_NOT_WORKING: s="crashing";break;
875 case CODECS_STATUS_UNTESTED: s="untested";break;
877 if(c->dll)
878 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s [%s]\n",c->name,c->drv,s,c->info,c->dll);
879 else
880 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s\n",c->name,c->drv,s,c->info);
888 #ifdef CODECS2HTML
889 void wrapline(FILE *f2,char *s){
890 int c;
891 if(!s){
892 fprintf(f2,"-");
893 return;
895 while((c=*s++)){
896 if(c==',') fprintf(f2,"<br>"); else fputc(c,f2);
900 void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
901 int c,d;
902 while((c=fgetc(f1))>=0){
903 if(c!='%'){
904 fputc(c,f2);
905 continue;
907 d=fgetc(f1);
909 switch(d){
910 case '.':
911 return; // end of section
912 case 'n':
913 wrapline(f2,codec->name); break;
914 case 'i':
915 wrapline(f2,codec->info); break;
916 case 'c':
917 wrapline(f2,codec->comment); break;
918 case 'd':
919 wrapline(f2,codec->dll); break;
920 case 'D':
921 fprintf(f2,"%c",!strcmp(codec->drv,"dshow")?'+':'-'); break;
922 case 'F':
923 for(d=0;d<CODECS_MAX_FOURCC;d++)
924 if(!d || codec->fourcc[d]!=0xFFFFFFFF)
925 fprintf(f2,"%s%.4s",d?"<br>":"",(codec->fourcc[d]==0xFFFFFFFF || codec->fourcc[d]<0x20202020)?!d?"-":"":(char*) &codec->fourcc[d]);
926 break;
927 case 'f':
928 for(d=0;d<CODECS_MAX_FOURCC;d++)
929 if(codec->fourcc[d]!=0xFFFFFFFF)
930 fprintf(f2,"%s0x%X",d?"<br>":"",codec->fourcc[d]);
931 break;
932 case 'Y':
933 for(d=0;d<CODECS_MAX_OUTFMT;d++)
934 if(codec->outfmt[d]!=0xFFFFFFFF){
935 for (c=0; fmt_table[c].name; c++)
936 if(fmt_table[c].num==codec->outfmt[d]) break;
937 if(fmt_table[c].name)
938 fprintf(f2,"%s%s",d?"<br>":"",fmt_table[c].name);
940 break;
941 default:
942 fputc(c,f2);
943 fputc(d,f2);
949 void skiphtml(FILE *f1){
950 int c,d;
951 while((c=fgetc(f1))>=0){
952 if(c!='%'){
953 continue;
955 d=fgetc(f1);
956 if(d=='.') return; // end of section
960 static void print_int_array(const int* a, int size)
962 printf("{ ");
963 while (size--)
964 if(abs(*a)<256)
965 printf("%d%s", *a++, size?", ":"");
966 else
967 printf("0x%X%s", *a++, size?", ":"");
968 printf(" }");
971 static void print_char_array(const unsigned char* a, int size)
973 printf("{ ");
974 while (size--)
975 if((*a)<10)
976 printf("%d%s", *a++, size?", ":"");
977 else
978 printf("0x%02x%s", *a++, size?", ":"");
979 printf(" }");
982 static void print_string(const char* s)
984 if (!s) printf("NULL");
985 else printf("\"%s\"", s);
988 int main(int argc, char* argv[])
990 codecs_t *cl;
991 FILE *f1;
992 FILE *f2;
993 int c,d,i;
994 int pos;
995 int section=-1;
996 int nr_codecs;
997 int win32=-1;
998 int dshow=-1;
999 int win32ex=-1;
1002 * Take path to codecs.conf from command line, or fall back on
1003 * etc/codecs.conf
1005 if (!(nr_codecs = parse_codec_cfg((argc>1)?argv[1]:"etc/codecs.conf")))
1006 exit(1);
1008 if (argc > 1) {
1009 int i, j;
1010 const char* nm[2];
1011 codecs_t* cod[2];
1012 int nr[2];
1014 nm[0] = "builtin_video_codecs";
1015 cod[0] = video_codecs;
1016 nr[0] = nr_vcodecs;
1018 nm[1] = "builtin_audio_codecs";
1019 cod[1] = audio_codecs;
1020 nr[1] = nr_acodecs;
1022 printf("/* GENERATED FROM %s, DO NOT EDIT! */\n\n",argv[1]);
1023 printf("#include <stddef.h>\n",argv[1]);
1024 printf("#include \"codec-cfg.h\"\n\n",argv[1]);
1026 for (i=0; i<2; i++) {
1027 printf("const codecs_t %s[] = {\n", nm[i]);
1028 for (j = 0; j < nr[i]; j++) {
1029 printf("{");
1031 print_int_array(cod[i][j].fourcc, CODECS_MAX_FOURCC);
1032 printf(", /* fourcc */\n");
1034 print_int_array(cod[i][j].fourccmap, CODECS_MAX_FOURCC);
1035 printf(", /* fourccmap */\n");
1037 print_int_array(cod[i][j].outfmt, CODECS_MAX_OUTFMT);
1038 printf(", /* outfmt */\n");
1040 print_char_array(cod[i][j].outflags, CODECS_MAX_OUTFMT);
1041 printf(", /* outflags */\n");
1043 print_int_array(cod[i][j].infmt, CODECS_MAX_INFMT);
1044 printf(", /* infmt */\n");
1046 print_char_array(cod[i][j].inflags, CODECS_MAX_INFMT);
1047 printf(", /* inflags */\n");
1049 print_string(cod[i][j].name); printf(", /* name */\n");
1050 print_string(cod[i][j].info); printf(", /* info */\n");
1051 print_string(cod[i][j].comment); printf(", /* comment */\n");
1052 print_string(cod[i][j].dll); printf(", /* dll */\n");
1053 print_string(cod[i][j].drv); printf(", /* drv */\n");
1055 printf("{ 0x%08lx, %hu, %hu,",
1056 cod[i][j].guid.f1,
1057 cod[i][j].guid.f2,
1058 cod[i][j].guid.f3);
1059 print_char_array(cod[i][j].guid.f4, sizeof(cod[i][j].guid.f4));
1060 printf(" }, /* GUID */\n");
1061 printf("%hd /* flags */, %hd /* status */, %hd /* cpuflags */ }\n",
1062 cod[i][j].flags,
1063 cod[i][j].status,
1064 cod[i][j].cpuflags);
1065 if (j < nr[i]) printf(",\n");
1067 printf("};\n\n");
1069 exit(0);
1072 f1=fopen("DOCS/tech/codecs-in.html","rb"); if(!f1) exit(1);
1073 f2=fopen("DOCS/codecs-status.html","wb"); if(!f2) exit(1);
1075 while((c=fgetc(f1))>=0){
1076 if(c!='%'){
1077 fputc(c,f2);
1078 continue;
1080 d=fgetc(f1);
1081 if(d>='0' && d<='9'){
1082 // begin section
1083 section=d-'0';
1084 //printf("BEGIN %d\n",section);
1085 if(section>=5){
1086 // audio
1087 cl = audio_codecs;
1088 nr_codecs = nr_acodecs;
1089 dshow=7;win32=4;
1090 } else {
1091 // video
1092 cl = video_codecs;
1093 nr_codecs = nr_vcodecs;
1094 dshow=4;win32=2;win32ex=6;
1096 pos=ftell(f1);
1097 for(i=0;i<nr_codecs;i++){
1098 fseek(f1,pos,SEEK_SET);
1099 switch(section){
1100 case 0:
1101 case 5:
1102 if(cl[i].status==CODECS_STATUS_WORKING)
1103 // if(!(!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1104 parsehtml(f1,f2,&cl[i],section,dshow);
1105 break;
1106 #if 0
1107 case 1:
1108 case 6:
1109 if(cl[i].status==CODECS_STATUS_WORKING)
1110 if((!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1111 parsehtml(f1,f2,&cl[i],section,dshow);
1112 break;
1113 #endif
1114 case 2:
1115 case 7:
1116 if(cl[i].status==CODECS_STATUS_PROBLEMS)
1117 parsehtml(f1,f2,&cl[i],section,dshow);
1118 break;
1119 case 3:
1120 case 8:
1121 if(cl[i].status==CODECS_STATUS_NOT_WORKING)
1122 parsehtml(f1,f2,&cl[i],section,dshow);
1123 break;
1124 case 4:
1125 case 9:
1126 if(cl[i].status==CODECS_STATUS_UNTESTED)
1127 parsehtml(f1,f2,&cl[i],section,dshow);
1128 break;
1129 default:
1130 printf("Warning! unimplemented section: %d\n",section);
1133 fseek(f1,pos,SEEK_SET);
1134 skiphtml(f1);
1135 //void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
1137 continue;
1139 fputc(c,f2);
1140 fputc(d,f2);
1143 fclose(f2);
1144 fclose(f1);
1145 return 0;
1148 #endif
1150 #ifdef TESTING
1151 int main(void)
1153 codecs_t *c;
1154 int i,j, nr_codecs, state;
1156 if (!(parse_codec_cfg("etc/codecs.conf")))
1157 return 0;
1158 if (!video_codecs)
1159 printf("no videoconfig.\n");
1160 if (!audio_codecs)
1161 printf("no audioconfig.\n");
1163 printf("videocodecs:\n");
1164 c = video_codecs;
1165 nr_codecs = nr_vcodecs;
1166 state = 0;
1167 next:
1168 if (c) {
1169 printf("number of %scodecs: %d\n", state==0?"video":"audio",
1170 nr_codecs);
1171 for(i=0;i<nr_codecs;i++, c++){
1172 printf("\n============== %scodec %02d ===============\n",
1173 state==0?"video":"audio",i);
1174 printf("name='%s'\n",c->name);
1175 printf("info='%s'\n",c->info);
1176 printf("comment='%s'\n",c->comment);
1177 printf("dll='%s'\n",c->dll);
1178 /* printf("flags=%X driver=%d status=%d cpuflags=%d\n",
1179 c->flags, c->driver, c->status, c->cpuflags); */
1180 printf("flags=%X status=%d cpuflags=%d\n",
1181 c->flags, c->status, c->cpuflags);
1183 for(j=0;j<CODECS_MAX_FOURCC;j++){
1184 if(c->fourcc[j]!=0xFFFFFFFF){
1185 printf("fourcc %02d: %08X (%.4s) ===> %08X (%.4s)\n",j,c->fourcc[j],(char *) &c->fourcc[j],c->fourccmap[j],(char *) &c->fourccmap[j]);
1189 for(j=0;j<CODECS_MAX_OUTFMT;j++){
1190 if(c->outfmt[j]!=0xFFFFFFFF){
1191 printf("outfmt %02d: %08X (%.4s) flags: %d\n",j,c->outfmt[j],(char *) &c->outfmt[j],c->outflags[j]);
1195 for(j=0;j<CODECS_MAX_INFMT;j++){
1196 if(c->infmt[j]!=0xFFFFFFFF){
1197 printf("infmt %02d: %08X (%.4s) flags: %d\n",j,c->infmt[j],(char *) &c->infmt[j],c->inflags[j]);
1201 printf("GUID: %08lX %04X %04X",c->guid.f1,c->guid.f2,c->guid.f3);
1202 for(j=0;j<8;j++) printf(" %02X",c->guid.f4[j]);
1203 printf("\n");
1208 if (!state) {
1209 printf("audiocodecs:\n");
1210 c = audio_codecs;
1211 nr_codecs = nr_acodecs;
1212 state = 1;
1213 goto next;
1215 return 0;
1218 #endif