big new year patch for documentations
[mplayer/glamo.git] / codec-cfg.c
blob840fb94ec143d92f9a784356a63c1214d1b17452
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 const struct {
142 const char *name;
143 const unsigned int num;
144 } fmt_table[] = {
145 // note: due to parser deficiencies/simplicity, if one format
146 // name matches the beginning of another, the longer one _must_
147 // come first in this list.
148 {"YV12", IMGFMT_YV12},
149 {"I420", IMGFMT_I420},
150 {"IYUV", IMGFMT_IYUV},
151 {"NV12", IMGFMT_NV12},
152 {"NV21", IMGFMT_NV21},
153 {"YVU9", IMGFMT_YVU9},
154 {"IF09", IMGFMT_IF09},
155 {"444P16LE", IMGFMT_444P16_LE},
156 {"444P16BE", IMGFMT_444P16_BE},
157 {"422P16LE", IMGFMT_422P16_LE},
158 {"422P16BE", IMGFMT_422P16_BE},
159 {"420P16LE", IMGFMT_420P16_LE},
160 {"420P16BE", IMGFMT_420P16_BE},
161 {"444P16", IMGFMT_444P16},
162 {"422P16", IMGFMT_422P16},
163 {"420P16", IMGFMT_420P16},
164 {"420A", IMGFMT_420A},
165 {"444P", IMGFMT_444P},
166 {"422P", IMGFMT_422P},
167 {"411P", IMGFMT_411P},
168 {"440P", IMGFMT_440P},
169 {"Y800", IMGFMT_Y800},
170 {"Y8", IMGFMT_Y8},
172 {"YUY2", IMGFMT_YUY2},
173 {"UYVY", IMGFMT_UYVY},
174 {"YVYU", IMGFMT_YVYU},
176 {"RGB48LE", IMGFMT_RGB48LE},
177 {"RGB48BE", IMGFMT_RGB48BE},
178 {"RGB4", IMGFMT_RGB4},
179 {"RGB8", IMGFMT_RGB8},
180 {"RGB15", IMGFMT_RGB15},
181 {"RGB16", IMGFMT_RGB16},
182 {"RGB24", IMGFMT_RGB24},
183 {"RGB32", IMGFMT_RGB32},
184 {"BGR4", IMGFMT_BGR4},
185 {"BGR8", IMGFMT_BGR8},
186 {"BGR15", IMGFMT_BGR15},
187 {"BGR16", IMGFMT_BGR16},
188 {"BGR24", IMGFMT_BGR24},
189 {"BGR32", IMGFMT_BGR32},
190 {"RGB1", IMGFMT_RGB1},
191 {"BGR1", IMGFMT_BGR1},
193 {"MPES", IMGFMT_MPEGPES},
194 {"ZRMJPEGNI", IMGFMT_ZRMJPEGNI},
195 {"ZRMJPEGIT", IMGFMT_ZRMJPEGIT},
196 {"ZRMJPEGIB", IMGFMT_ZRMJPEGIB},
198 {"IDCT_MPEG2",IMGFMT_XVMC_IDCT_MPEG2},
199 {"MOCO_MPEG2",IMGFMT_XVMC_MOCO_MPEG2},
201 {"VDPAU_MPEG1",IMGFMT_VDPAU_MPEG1},
202 {"VDPAU_MPEG2",IMGFMT_VDPAU_MPEG2},
203 {"VDPAU_H264",IMGFMT_VDPAU_H264},
204 {"VDPAU_WMV3",IMGFMT_VDPAU_WMV3},
205 {"VDPAU_VC1",IMGFMT_VDPAU_VC1},
206 {"VDPAU_MPEG4",IMGFMT_VDPAU_MPEG4},
208 {NULL, 0}
212 static int add_to_inout(char *sfmt, char *sflags, unsigned int *outfmt,
213 unsigned char *outflags)
216 static char *flagstr[] = {
217 "flip",
218 "noflip",
219 "yuvhack",
220 "query",
221 "static",
222 NULL
225 int i, j, freeslots;
226 unsigned char flags;
228 for (i = 0; i < CODECS_MAX_OUTFMT && outfmt[i] != 0xffffffff; i++)
229 /* NOTHING */;
230 freeslots = CODECS_MAX_OUTFMT - i;
231 if (!freeslots)
232 goto err_out_too_many;
234 flags = 0;
235 if(sflags) {
236 do {
237 for (j = 0; flagstr[j] != NULL; j++)
238 if (!strncmp(sflags, flagstr[j],
239 strlen(flagstr[j])))
240 break;
241 if (flagstr[j] == NULL)
242 goto err_out_parse_error;
243 flags|=(1<<j);
244 sflags+=strlen(flagstr[j]);
245 } while (*(sflags++) == ',');
247 if (*(--sflags) != '\0')
248 goto err_out_parse_error;
251 do {
252 for (j = 0; fmt_table[j].name != NULL; j++)
253 if (!strncmp(sfmt, fmt_table[j].name, strlen(fmt_table[j].name)))
254 break;
255 if (fmt_table[j].name == NULL)
256 goto err_out_parse_error;
257 outfmt[i] = fmt_table[j].num;
258 outflags[i] = flags;
259 ++i;
260 sfmt+=strlen(fmt_table[j].name);
261 } while ((*(sfmt++) == ',') && --freeslots);
263 if (!freeslots)
264 goto err_out_too_many;
266 if (*(--sfmt) != '\0')
267 goto err_out_parse_error;
269 return 1;
270 err_out_too_many:
271 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_TooManyOut);
272 return 0;
273 err_out_parse_error:
274 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseError);
275 return 0;
278 #if 0
279 static short get_driver(char *s,int audioflag)
281 static char *audiodrv[] = {
282 "null",
283 "mp3lib",
284 "pcm",
285 "libac3",
286 "acm",
287 "alaw",
288 "msgsm",
289 "dshow",
290 "dvdpcm",
291 "hwac3",
292 "libvorbis",
293 "ffmpeg",
294 "libmad",
295 "msadpcm",
296 "liba52",
297 "g72x",
298 "imaadpcm",
299 "dk4adpcm",
300 "dk3adpcm",
301 "roqaudio",
302 "faad",
303 "realaud",
304 "libdv",
305 NULL
307 static char *videodrv[] = {
308 "null",
309 "libmpeg2",
310 "vfw",
311 "dshow",
312 "ffmpeg",
313 "vfwex",
314 "raw",
315 "msrle",
316 "xanim",
317 "msvidc",
318 "fli",
319 "cinepak",
320 "qtrle",
321 "nuv",
322 "cyuv",
323 "qtsmc",
324 "ducktm1",
325 "roqvideo",
326 "qtrpza",
327 "mpng",
328 "ijpg",
329 "zlib",
330 "mpegpes",
331 "zrmjpeg",
332 "realvid",
333 "xvid",
334 "libdv",
335 NULL
337 char **drv=audioflag?audiodrv:videodrv;
338 int i;
340 for(i=0;drv[i];i++) if(!strcmp(s,drv[i])) return i;
342 return -1;
344 #endif
346 static int validate_codec(codecs_t *c, int type)
348 unsigned int i;
349 char *tmp_name = c->name;
351 for (i = 0; i < strlen(tmp_name) && isalnum(tmp_name[i]); i++)
352 /* NOTHING */;
354 if (i < strlen(tmp_name)) {
355 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_InvalidCodecName, c->name);
356 return 0;
359 if (!c->info)
360 c->info = strdup(c->name);
362 #if 0
363 if (c->fourcc[0] == 0xffffffff) {
364 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecLacksFourcc, c->name);
365 return 0;
367 #endif
369 if (!c->drv) {
370 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecLacksDriver, c->name);
371 return 0;
374 #if 0
375 #warning codec->driver == 4;... <- this should not be put in here...
376 #warning Where are they defined ????????????
377 if (!c->dll && (c->driver == 4 ||
378 (c->driver == 2 && type == TYPE_VIDEO))) {
379 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecNeedsDLL, c->name);
380 return 0;
382 #warning Can guid.f1 be 0? How does one know that it was not given?
383 // if (!(codec->flags & CODECS_FLAG_AUDIO) && codec->driver == 4)
385 if (type == TYPE_VIDEO)
386 if (c->outfmt[0] == 0xffffffff) {
387 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecNeedsOutfmt, c->name);
388 return 0;
390 #endif
391 return 1;
394 static int add_comment(char *s, char **d)
396 int pos;
398 if (!*d)
399 pos = 0;
400 else {
401 pos = strlen(*d);
402 (*d)[pos++] = '\n';
404 if (!(*d = realloc(*d, pos + strlen(s) + 1))) {
405 mp_msg(MSGT_CODECCFG,MSGL_FATAL,MSGTR_CantAllocateComment);
406 return 0;
408 strcpy(*d + pos, s);
409 return 1;
412 static short get_cpuflags(char *s)
414 static char *flagstr[] = {
415 "mmx",
416 "sse",
417 "3dnow",
418 NULL
420 int i;
421 short flags = 0;
423 do {
424 for (i = 0; flagstr[i]; i++)
425 if (!strncmp(s, flagstr[i], strlen(flagstr[i])))
426 break;
427 if (!flagstr[i])
428 goto err_out_parse_error;
429 flags |= 1<<i;
430 s += strlen(flagstr[i]);
431 } while (*(s++) == ',');
433 if (*(--s) != '\0')
434 goto err_out_parse_error;
436 return flags;
437 err_out_parse_error:
438 return 0;
441 static FILE *fp;
442 static int line_num = 0;
443 static char *line;
444 static char *token[MAX_NR_TOKEN];
445 static int read_nextline = 1;
447 static int get_token(int min, int max)
449 static int line_pos;
450 int i;
451 char c;
453 if (max >= MAX_NR_TOKEN) {
454 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_GetTokenMaxNotLessThanMAX_NR_TOKEN);
455 goto out_eof;
458 memset(token, 0x00, sizeof(*token) * max);
460 if (read_nextline) {
461 if (!fgets(line, MAX_LINE_LEN, fp))
462 goto out_eof;
463 line_pos = 0;
464 ++line_num;
465 read_nextline = 0;
467 for (i = 0; i < max; i++) {
468 while (isspace(line[line_pos]))
469 ++line_pos;
470 if (line[line_pos] == '\0' || line[line_pos] == '#' ||
471 line[line_pos] == ';') {
472 read_nextline = 1;
473 if (i >= min)
474 goto out_ok;
475 goto out_eol;
477 token[i] = line + line_pos;
478 c = line[line_pos];
479 if (c == '"' || c == '\'') {
480 token[i]++;
481 while (line[++line_pos] != c && line[line_pos])
482 /* NOTHING */;
483 } else {
484 for (/* NOTHING */; !isspace(line[line_pos]) &&
485 line[line_pos]; line_pos++)
486 /* NOTHING */;
488 if (!line[line_pos]) {
489 read_nextline = 1;
490 if (i >= min - 1)
491 goto out_ok;
492 goto out_eol;
494 line[line_pos] = '\0';
495 line_pos++;
497 out_ok:
498 return i;
499 out_eof:
500 read_nextline = 1;
501 return RET_EOF;
502 out_eol:
503 return RET_EOL;
506 static codecs_t *video_codecs=NULL;
507 static codecs_t *audio_codecs=NULL;
508 static int nr_vcodecs = 0;
509 static int nr_acodecs = 0;
511 int parse_codec_cfg(const char *cfgfile)
513 codecs_t *codec = NULL; // current codec
514 codecs_t **codecsp = NULL;// points to audio_codecs or to video_codecs
515 char *endptr; // strtoul()...
516 int *nr_codecsp;
517 int codec_type; /* TYPE_VIDEO/TYPE_AUDIO */
518 int tmp, i;
520 // in case we call it a second time
521 codecs_uninit_free();
523 nr_vcodecs = 0;
524 nr_acodecs = 0;
526 if(cfgfile==NULL) {
527 #ifdef CODECS2HTML
528 return 0;
529 #else
530 video_codecs = builtin_video_codecs;
531 audio_codecs = builtin_audio_codecs;
532 nr_vcodecs = sizeof(builtin_video_codecs)/sizeof(codecs_t);
533 nr_acodecs = sizeof(builtin_audio_codecs)/sizeof(codecs_t);
534 return 1;
535 #endif
538 mp_msg(MSGT_CODECCFG,MSGL_V,MSGTR_ReadingFile, cfgfile);
540 if ((fp = fopen(cfgfile, "r")) == NULL) {
541 mp_msg(MSGT_CODECCFG,MSGL_V,MSGTR_CantOpenFileError, cfgfile, strerror(errno));
542 return 0;
545 if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) {
546 mp_msg(MSGT_CODECCFG,MSGL_FATAL,MSGTR_CantGetMemoryForLine, strerror(errno));
547 return 0;
549 read_nextline = 1;
552 * this only catches release lines at the start of
553 * codecs.conf, before audiocodecs and videocodecs.
555 while ((tmp = get_token(1, 1)) == RET_EOL)
556 /* NOTHING */;
557 if (tmp == RET_EOF)
558 goto out;
559 if (!strcmp(token[0], "release")) {
560 if (get_token(1, 2) < 0)
561 goto err_out_parse_error;
562 tmp = atoi(token[0]);
563 if (tmp < CODEC_CFG_MIN)
564 goto err_out_release_num;
565 while ((tmp = get_token(1, 1)) == RET_EOL)
566 /* NOTHING */;
567 if (tmp == RET_EOF)
568 goto out;
569 } else
570 goto err_out_release_num;
573 * check if the next block starts with 'audiocodec' or
574 * with 'videocodec'
576 if (!strcmp(token[0], "audiocodec") || !strcmp(token[0], "videocodec"))
577 goto loop_enter;
578 goto err_out_parse_error;
580 while ((tmp = get_token(1, 1)) != RET_EOF) {
581 if (tmp == RET_EOL)
582 continue;
583 if (!strcmp(token[0], "audiocodec") ||
584 !strcmp(token[0], "videocodec")) {
585 if (!validate_codec(codec, codec_type))
586 goto err_out_not_valid;
587 loop_enter:
588 if (*token[0] == 'v') {
589 codec_type = TYPE_VIDEO;
590 nr_codecsp = &nr_vcodecs;
591 codecsp = &video_codecs;
592 } else if (*token[0] == 'a') {
593 codec_type = TYPE_AUDIO;
594 nr_codecsp = &nr_acodecs;
595 codecsp = &audio_codecs;
596 #ifdef DEBUG
597 } else {
598 mp_msg(MSGT_CODECCFG,MSGL_ERR,"picsba\n");
599 goto err_out;
600 #endif
602 if (!(*codecsp = realloc(*codecsp,
603 sizeof(codecs_t) * (*nr_codecsp + 2)))) {
604 mp_msg(MSGT_CODECCFG,MSGL_FATAL,MSGTR_CantReallocCodecsp, strerror(errno));
605 goto err_out;
607 codec=*codecsp + *nr_codecsp;
608 ++*nr_codecsp;
609 memset(codec,0,sizeof(codecs_t));
610 memset(codec->fourcc, 0xff, sizeof(codec->fourcc));
611 memset(codec->outfmt, 0xff, sizeof(codec->outfmt));
612 memset(codec->infmt, 0xff, sizeof(codec->infmt));
614 if (get_token(1, 1) < 0)
615 goto err_out_parse_error;
616 for (i = 0; i < *nr_codecsp - 1; i++) {
617 if(( (*codecsp)[i].name!=NULL) &&
618 (!strcmp(token[0], (*codecsp)[i].name)) ) {
619 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecNameNotUnique, token[0]);
620 goto err_out_print_linenum;
623 if (!(codec->name = strdup(token[0]))) {
624 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupName, strerror(errno));
625 goto err_out;
627 } else if (!strcmp(token[0], "info")) {
628 if (codec->info || get_token(1, 1) < 0)
629 goto err_out_parse_error;
630 if (!(codec->info = strdup(token[0]))) {
631 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupInfo, strerror(errno));
632 goto err_out;
634 } else if (!strcmp(token[0], "comment")) {
635 if (get_token(1, 1) < 0)
636 goto err_out_parse_error;
637 add_comment(token[0], &codec->comment);
638 } else if (!strcmp(token[0], "fourcc")) {
639 if (get_token(1, 2) < 0)
640 goto err_out_parse_error;
641 if (!add_to_fourcc(token[0], token[1],
642 codec->fourcc,
643 codec->fourccmap))
644 goto err_out_print_linenum;
645 } else if (!strcmp(token[0], "format")) {
646 if (get_token(1, 2) < 0)
647 goto err_out_parse_error;
648 if (!add_to_format(token[0], token[1],
649 codec->fourcc,codec->fourccmap))
650 goto err_out_print_linenum;
651 } else if (!strcmp(token[0], "driver")) {
652 if (get_token(1, 1) < 0)
653 goto err_out_parse_error;
654 if (!(codec->drv = strdup(token[0]))) {
655 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupDriver, strerror(errno));
656 goto err_out;
658 } else if (!strcmp(token[0], "dll")) {
659 if (get_token(1, 1) < 0)
660 goto err_out_parse_error;
661 if (!(codec->dll = strdup(token[0]))) {
662 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupDLL, strerror(errno));
663 goto err_out;
665 } else if (!strcmp(token[0], "guid")) {
666 if (get_token(11, 11) < 0)
667 goto err_out_parse_error;
668 codec->guid.f1=strtoul(token[0],&endptr,0);
669 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
670 *endptr != '\0')
671 goto err_out_parse_error;
672 codec->guid.f2=strtoul(token[1],&endptr,0);
673 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
674 *endptr != '\0')
675 goto err_out_parse_error;
676 codec->guid.f3=strtoul(token[2],&endptr,0);
677 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
678 *endptr != '\0')
679 goto err_out_parse_error;
680 for (i = 0; i < 8; i++) {
681 codec->guid.f4[i]=strtoul(token[i + 3],&endptr,0);
682 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
683 *endptr != '\0')
684 goto err_out_parse_error;
686 } else if (!strcmp(token[0], "out")) {
687 if (get_token(1, 2) < 0)
688 goto err_out_parse_error;
689 if (!add_to_inout(token[0], token[1], codec->outfmt,
690 codec->outflags))
691 goto err_out_print_linenum;
692 } else if (!strcmp(token[0], "in")) {
693 if (get_token(1, 2) < 0)
694 goto err_out_parse_error;
695 if (!add_to_inout(token[0], token[1], codec->infmt,
696 codec->inflags))
697 goto err_out_print_linenum;
698 } else if (!strcmp(token[0], "flags")) {
699 if (get_token(1, 1) < 0)
700 goto err_out_parse_error;
701 if (!strcmp(token[0], "seekable"))
702 codec->flags |= CODECS_FLAG_SEEKABLE;
703 else
704 if (!strcmp(token[0], "align16"))
705 codec->flags |= CODECS_FLAG_ALIGN16;
706 else
707 goto err_out_parse_error;
708 } else if (!strcmp(token[0], "status")) {
709 if (get_token(1, 1) < 0)
710 goto err_out_parse_error;
711 if (!strcasecmp(token[0], "working"))
712 codec->status = CODECS_STATUS_WORKING;
713 else if (!strcasecmp(token[0], "crashing"))
714 codec->status = CODECS_STATUS_NOT_WORKING;
715 else if (!strcasecmp(token[0], "untested"))
716 codec->status = CODECS_STATUS_UNTESTED;
717 else if (!strcasecmp(token[0], "buggy"))
718 codec->status = CODECS_STATUS_PROBLEMS;
719 else
720 goto err_out_parse_error;
721 } else if (!strcmp(token[0], "cpuflags")) {
722 if (get_token(1, 1) < 0)
723 goto err_out_parse_error;
724 if (!(codec->cpuflags = get_cpuflags(token[0])))
725 goto err_out_parse_error;
726 } else
727 goto err_out_parse_error;
729 if (!validate_codec(codec, codec_type))
730 goto err_out_not_valid;
731 mp_msg(MSGT_CODECCFG,MSGL_INFO,MSGTR_AudioVideoCodecTotals, nr_acodecs, nr_vcodecs);
732 if(video_codecs) video_codecs[nr_vcodecs].name = NULL;
733 if(audio_codecs) audio_codecs[nr_acodecs].name = NULL;
734 out:
735 free(line);
736 line=NULL;
737 fclose(fp);
738 return 1;
740 err_out_parse_error:
741 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseError);
742 err_out_print_linenum:
743 PRINT_LINENUM;
744 err_out:
745 codecs_uninit_free();
747 free(line);
748 line=NULL;
749 line_num = 0;
750 fclose(fp);
751 return 0;
752 err_out_not_valid:
753 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecDefinitionIncorrect);
754 goto err_out_print_linenum;
755 err_out_release_num:
756 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_OutdatedCodecsConf);
757 goto err_out_print_linenum;
760 static void codecs_free(codecs_t* codecs,int count) {
761 int i;
762 for ( i = 0; i < count; i++)
763 if ( codecs[i].name ) {
764 if( codecs[i].name )
765 free(codecs[i].name);
766 if( codecs[i].info )
767 free(codecs[i].info);
768 if( codecs[i].comment )
769 free(codecs[i].comment);
770 if( codecs[i].dll )
771 free(codecs[i].dll);
772 if( codecs[i].drv )
773 free(codecs[i].drv);
775 if (codecs)
776 free(codecs);
779 void codecs_uninit_free(void) {
780 if (video_codecs)
781 codecs_free(video_codecs,nr_vcodecs);
782 video_codecs=NULL;
783 if (audio_codecs)
784 codecs_free(audio_codecs,nr_acodecs);
785 audio_codecs=NULL;
788 codecs_t *find_audio_codec(unsigned int fourcc, unsigned int *fourccmap,
789 codecs_t *start, int force)
791 return find_codec(fourcc, fourccmap, start, 1, force);
794 codecs_t *find_video_codec(unsigned int fourcc, unsigned int *fourccmap,
795 codecs_t *start, int force)
797 return find_codec(fourcc, fourccmap, start, 0, force);
800 codecs_t* find_codec(unsigned int fourcc,unsigned int *fourccmap,
801 codecs_t *start, int audioflag, int force)
803 int i, j;
804 codecs_t *c;
806 #if 0
807 if (start) {
808 for (/* NOTHING */; start->name; start++) {
809 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
810 if (start->fourcc[j] == fourcc) {
811 if (fourccmap)
812 *fourccmap = start->fourccmap[j];
813 return start;
817 } else
818 #endif
820 if (audioflag) {
821 i = nr_acodecs;
822 c = audio_codecs;
823 } else {
824 i = nr_vcodecs;
825 c = video_codecs;
827 if(!i) return NULL;
828 for (/* NOTHING */; i--; c++) {
829 if(start && c<=start) continue;
830 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
831 // FIXME: do NOT hardwire 'null' name here:
832 if (c->fourcc[j]==fourcc || !strcmp(c->drv,"null")) {
833 if (fourccmap)
834 *fourccmap = c->fourccmap[j];
835 return c;
838 if (force) return c;
841 return NULL;
844 void stringset_init(stringset_t *set) {
845 *set = calloc(1, sizeof(char *));
848 void stringset_free(stringset_t *set) {
849 int count = 0;
850 while ((*set)[count]) free((*set)[count++]);
851 free(*set);
852 *set = NULL;
855 void stringset_add(stringset_t *set, const char *str) {
856 int count = 0;
857 while ((*set)[count]) count++;
858 count++;
859 *set = realloc(*set, sizeof(char *) * (count + 1));
860 (*set)[count - 1] = strdup(str);
861 (*set)[count] = NULL;
864 int stringset_test(stringset_t *set, const char *str) {
865 stringset_t s;
866 for (s = *set; *s; s++)
867 if (strcmp(*s, str) == 0)
868 return 1;
869 return 0;
872 void list_codecs(int audioflag){
873 int i;
874 codecs_t *c;
876 if (audioflag) {
877 i = nr_acodecs;
878 c = audio_codecs;
879 mp_msg(MSGT_CODECCFG,MSGL_INFO,"ac: afm: status: info: [lib/dll]\n");
880 } else {
881 i = nr_vcodecs;
882 c = video_codecs;
883 mp_msg(MSGT_CODECCFG,MSGL_INFO,"vc: vfm: status: info: [lib/dll]\n");
885 if(!i) return;
886 for (/* NOTHING */; i--; c++) {
887 char* s="unknown ";
888 switch(c->status){
889 case CODECS_STATUS_WORKING: s="working ";break;
890 case CODECS_STATUS_PROBLEMS: s="problems";break;
891 case CODECS_STATUS_NOT_WORKING: s="crashing";break;
892 case CODECS_STATUS_UNTESTED: s="untested";break;
894 if(c->dll)
895 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s [%s]\n",c->name,c->drv,s,c->info,c->dll);
896 else
897 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s\n",c->name,c->drv,s,c->info);
905 #ifdef CODECS2HTML
906 void wrapline(FILE *f2,char *s){
907 int c;
908 if(!s){
909 fprintf(f2,"-");
910 return;
912 while((c=*s++)){
913 if(c==',') fprintf(f2,"<br>"); else fputc(c,f2);
917 void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
918 int c,d;
919 while((c=fgetc(f1))>=0){
920 if(c!='%'){
921 fputc(c,f2);
922 continue;
924 d=fgetc(f1);
926 switch(d){
927 case '.':
928 return; // end of section
929 case 'n':
930 wrapline(f2,codec->name); break;
931 case 'i':
932 wrapline(f2,codec->info); break;
933 case 'c':
934 wrapline(f2,codec->comment); break;
935 case 'd':
936 wrapline(f2,codec->dll); break;
937 case 'D':
938 fprintf(f2,"%c",!strcmp(codec->drv,"dshow")?'+':'-'); break;
939 case 'F':
940 for(d=0;d<CODECS_MAX_FOURCC;d++)
941 if(!d || codec->fourcc[d]!=0xFFFFFFFF)
942 fprintf(f2,"%s%.4s",d?"<br>":"",(codec->fourcc[d]==0xFFFFFFFF || codec->fourcc[d]<0x20202020)?!d?"-":"":(char*) &codec->fourcc[d]);
943 break;
944 case 'f':
945 for(d=0;d<CODECS_MAX_FOURCC;d++)
946 if(codec->fourcc[d]!=0xFFFFFFFF)
947 fprintf(f2,"%s0x%X",d?"<br>":"",codec->fourcc[d]);
948 break;
949 case 'Y':
950 for(d=0;d<CODECS_MAX_OUTFMT;d++)
951 if(codec->outfmt[d]!=0xFFFFFFFF){
952 for (c=0; fmt_table[c].name; c++)
953 if(fmt_table[c].num==codec->outfmt[d]) break;
954 if(fmt_table[c].name)
955 fprintf(f2,"%s%s",d?"<br>":"",fmt_table[c].name);
957 break;
958 default:
959 fputc(c,f2);
960 fputc(d,f2);
966 void skiphtml(FILE *f1){
967 int c,d;
968 while((c=fgetc(f1))>=0){
969 if(c!='%'){
970 continue;
972 d=fgetc(f1);
973 if(d=='.') return; // end of section
977 static void print_int_array(const unsigned int* a, int size)
979 printf("{ ");
980 while (size--)
981 if(abs(*a)<256)
982 printf("%d%s", *a++, size?", ":"");
983 else
984 printf("0x%X%s", *a++, size?", ":"");
985 printf(" }");
988 static void print_char_array(const unsigned char* a, int size)
990 printf("{ ");
991 while (size--)
992 if((*a)<10)
993 printf("%d%s", *a++, size?", ":"");
994 else
995 printf("0x%02x%s", *a++, size?", ":"");
996 printf(" }");
999 static void print_string(const char* s)
1001 if (!s) printf("NULL");
1002 else printf("\"%s\"", s);
1005 int main(int argc, char* argv[])
1007 codecs_t *cl;
1008 FILE *f1;
1009 FILE *f2;
1010 int c,d,i;
1011 int pos;
1012 int section=-1;
1013 int nr_codecs;
1014 int win32=-1;
1015 int dshow=-1;
1016 int win32ex=-1;
1019 * Take path to codecs.conf from command line, or fall back on
1020 * etc/codecs.conf
1022 if (!(nr_codecs = parse_codec_cfg((argc>1)?argv[1]:"etc/codecs.conf")))
1023 exit(1);
1025 if (argc > 1) {
1026 int i, j;
1027 const char* nm[2];
1028 codecs_t* cod[2];
1029 int nr[2];
1031 nm[0] = "builtin_video_codecs";
1032 cod[0] = video_codecs;
1033 nr[0] = nr_vcodecs;
1035 nm[1] = "builtin_audio_codecs";
1036 cod[1] = audio_codecs;
1037 nr[1] = nr_acodecs;
1039 printf("/* GENERATED FROM %s, DO NOT EDIT! */\n\n",argv[1]);
1040 printf("#include <stddef.h>\n",argv[1]);
1041 printf("#include \"codec-cfg.h\"\n\n",argv[1]);
1043 for (i=0; i<2; i++) {
1044 printf("const codecs_t %s[] = {\n", nm[i]);
1045 for (j = 0; j < nr[i]; j++) {
1046 printf("{");
1048 print_int_array(cod[i][j].fourcc, CODECS_MAX_FOURCC);
1049 printf(", /* fourcc */\n");
1051 print_int_array(cod[i][j].fourccmap, CODECS_MAX_FOURCC);
1052 printf(", /* fourccmap */\n");
1054 print_int_array(cod[i][j].outfmt, CODECS_MAX_OUTFMT);
1055 printf(", /* outfmt */\n");
1057 print_char_array(cod[i][j].outflags, CODECS_MAX_OUTFMT);
1058 printf(", /* outflags */\n");
1060 print_int_array(cod[i][j].infmt, CODECS_MAX_INFMT);
1061 printf(", /* infmt */\n");
1063 print_char_array(cod[i][j].inflags, CODECS_MAX_INFMT);
1064 printf(", /* inflags */\n");
1066 print_string(cod[i][j].name); printf(", /* name */\n");
1067 print_string(cod[i][j].info); printf(", /* info */\n");
1068 print_string(cod[i][j].comment); printf(", /* comment */\n");
1069 print_string(cod[i][j].dll); printf(", /* dll */\n");
1070 print_string(cod[i][j].drv); printf(", /* drv */\n");
1072 printf("{ 0x%08lx, %hu, %hu,",
1073 cod[i][j].guid.f1,
1074 cod[i][j].guid.f2,
1075 cod[i][j].guid.f3);
1076 print_char_array(cod[i][j].guid.f4, sizeof(cod[i][j].guid.f4));
1077 printf(" }, /* GUID */\n");
1078 printf("%hd /* flags */, %hd /* status */, %hd /* cpuflags */ }\n",
1079 cod[i][j].flags,
1080 cod[i][j].status,
1081 cod[i][j].cpuflags);
1082 if (j < nr[i]) printf(",\n");
1084 printf("};\n\n");
1086 exit(0);
1089 f1=fopen("DOCS/tech/codecs-in.html","rb"); if(!f1) exit(1);
1090 f2=fopen("DOCS/codecs-status.html","wb"); if(!f2) exit(1);
1092 while((c=fgetc(f1))>=0){
1093 if(c!='%'){
1094 fputc(c,f2);
1095 continue;
1097 d=fgetc(f1);
1098 if(d>='0' && d<='9'){
1099 // begin section
1100 section=d-'0';
1101 //printf("BEGIN %d\n",section);
1102 if(section>=5){
1103 // audio
1104 cl = audio_codecs;
1105 nr_codecs = nr_acodecs;
1106 dshow=7;win32=4;
1107 } else {
1108 // video
1109 cl = video_codecs;
1110 nr_codecs = nr_vcodecs;
1111 dshow=4;win32=2;win32ex=6;
1113 pos=ftell(f1);
1114 for(i=0;i<nr_codecs;i++){
1115 fseek(f1,pos,SEEK_SET);
1116 switch(section){
1117 case 0:
1118 case 5:
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 #if 0
1124 case 1:
1125 case 6:
1126 if(cl[i].status==CODECS_STATUS_WORKING)
1127 if((!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1128 parsehtml(f1,f2,&cl[i],section,dshow);
1129 break;
1130 #endif
1131 case 2:
1132 case 7:
1133 if(cl[i].status==CODECS_STATUS_PROBLEMS)
1134 parsehtml(f1,f2,&cl[i],section,dshow);
1135 break;
1136 case 3:
1137 case 8:
1138 if(cl[i].status==CODECS_STATUS_NOT_WORKING)
1139 parsehtml(f1,f2,&cl[i],section,dshow);
1140 break;
1141 case 4:
1142 case 9:
1143 if(cl[i].status==CODECS_STATUS_UNTESTED)
1144 parsehtml(f1,f2,&cl[i],section,dshow);
1145 break;
1146 default:
1147 printf("Warning! unimplemented section: %d\n",section);
1150 fseek(f1,pos,SEEK_SET);
1151 skiphtml(f1);
1152 //void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
1154 continue;
1156 fputc(c,f2);
1157 fputc(d,f2);
1160 fclose(f2);
1161 fclose(f1);
1162 return 0;
1165 #endif
1167 #ifdef TESTING
1168 int main(void)
1170 codecs_t *c;
1171 int i,j, nr_codecs, state;
1173 if (!(parse_codec_cfg("etc/codecs.conf")))
1174 return 0;
1175 if (!video_codecs)
1176 printf("no videoconfig.\n");
1177 if (!audio_codecs)
1178 printf("no audioconfig.\n");
1180 printf("videocodecs:\n");
1181 c = video_codecs;
1182 nr_codecs = nr_vcodecs;
1183 state = 0;
1184 next:
1185 if (c) {
1186 printf("number of %scodecs: %d\n", state==0?"video":"audio",
1187 nr_codecs);
1188 for(i=0;i<nr_codecs;i++, c++){
1189 printf("\n============== %scodec %02d ===============\n",
1190 state==0?"video":"audio",i);
1191 printf("name='%s'\n",c->name);
1192 printf("info='%s'\n",c->info);
1193 printf("comment='%s'\n",c->comment);
1194 printf("dll='%s'\n",c->dll);
1195 /* printf("flags=%X driver=%d status=%d cpuflags=%d\n",
1196 c->flags, c->driver, c->status, c->cpuflags); */
1197 printf("flags=%X status=%d cpuflags=%d\n",
1198 c->flags, c->status, c->cpuflags);
1200 for(j=0;j<CODECS_MAX_FOURCC;j++){
1201 if(c->fourcc[j]!=0xFFFFFFFF){
1202 printf("fourcc %02d: %08X (%.4s) ===> %08X (%.4s)\n",j,c->fourcc[j],(char *) &c->fourcc[j],c->fourccmap[j],(char *) &c->fourccmap[j]);
1206 for(j=0;j<CODECS_MAX_OUTFMT;j++){
1207 if(c->outfmt[j]!=0xFFFFFFFF){
1208 printf("outfmt %02d: %08X (%.4s) flags: %d\n",j,c->outfmt[j],(char *) &c->outfmt[j],c->outflags[j]);
1212 for(j=0;j<CODECS_MAX_INFMT;j++){
1213 if(c->infmt[j]!=0xFFFFFFFF){
1214 printf("infmt %02d: %08X (%.4s) flags: %d\n",j,c->infmt[j],(char *) &c->infmt[j],c->inflags[j]);
1218 printf("GUID: %08lX %04X %04X",c->guid.f1,c->guid.f2,c->guid.f3);
1219 for(j=0;j<8;j++) printf(" %02X",c->guid.f4[j]);
1220 printf("\n");
1225 if (!state) {
1226 printf("audiocodecs:\n");
1227 c = audio_codecs;
1228 nr_codecs = nr_acodecs;
1229 state = 1;
1230 goto next;
1232 return 0;
1235 #endif