vo_glamo: sub.h was moved to sub directory in c9026cb3210205b07e2e068467a18ee40f9259a3
[mplayer/glamo.git] / codec-cfg.c
bloba39b2ac7177347ed0814df69cf8e27fb3910949b
1 /*
2 * codec.conf parser
4 * to compile test application:
5 * cc -I. -DTESTING -o codec-cfg-test codec-cfg.c mp_msg.o osdep/getch2.o -ltermcap
6 * to compile CODECS2HTML:
7 * gcc -DCODECS2HTML -o codecs2html codec-cfg.c mp_msg.o
9 * TODO: implement informat in CODECS2HTML too
11 * Copyright (C) 2001 Szabolcs Berecz <szabi@inf.elte.hu>
13 * This file is part of MPlayer.
15 * MPlayer is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * MPlayer is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License along
26 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #define DEBUG
32 //disable asserts
33 #define NDEBUG
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <errno.h>
40 #include <ctype.h>
41 #include <assert.h>
42 #include <string.h>
43 #include <stdint.h>
45 #include "config.h"
46 #include "mp_msg.h"
47 #ifdef CODECS2HTML
48 #define mp_tmsg mp_msg
49 #ifdef __GNUC__
50 #define mp_msg(t, l, m, args...) fprintf(stderr, m, ##args)
51 #else
52 #define mp_msg(t, l, ...) fprintf(stderr, __VA_ARGS__)
53 #endif
54 #endif
57 #include "libmpcodecs/img_format.h"
58 #include "codec-cfg.h"
60 #ifdef CODECS2HTML
61 #define CODEC_CFG_MIN 20100000
62 #else
63 #include "codecs.conf.h"
64 #endif
66 #define mmioFOURCC( ch0, ch1, ch2, ch3 ) \
67 ( (uint32_t)(uint8_t)(ch0) | ( (uint32_t)(uint8_t)(ch1) << 8 ) | \
68 ( (uint32_t)(uint8_t)(ch2) << 16 ) | ( (uint32_t)(uint8_t)(ch3) << 24 ) )
70 #define PRINT_LINENUM mp_msg(MSGT_CODECCFG,MSGL_ERR," at line %d\n", line_num)
72 #define MAX_NR_TOKEN 16
74 #define MAX_LINE_LEN 1000
76 #define RET_EOF -1
77 #define RET_EOL -2
79 #define TYPE_VIDEO 0
80 #define TYPE_AUDIO 1
82 static int codecs_conf_release;
83 char * codecs_file = NULL;
85 static int add_to_fourcc(char *s, char *alias, unsigned int *fourcc,
86 unsigned int *map)
88 int i, j, freeslots;
89 unsigned int tmp;
91 /* find first unused slot */
92 for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++)
93 /* NOTHING */;
94 freeslots = CODECS_MAX_FOURCC - i;
95 if (!freeslots)
96 goto err_out_too_many;
98 do {
99 tmp = mmioFOURCC(s[0], s[1], s[2], s[3]);
100 for (j = 0; j < i; j++)
101 if (tmp == fourcc[j])
102 goto err_out_duplicated;
103 fourcc[i] = tmp;
104 map[i] = alias ? mmioFOURCC(alias[0], alias[1], alias[2], alias[3]) : tmp;
105 s += 4;
106 i++;
107 } while ((*(s++) == ',') && --freeslots);
109 if (!freeslots)
110 goto err_out_too_many;
111 if (*(--s) != '\0')
112 goto err_out_parse_error;
113 return 1;
114 err_out_duplicated:
115 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"duplicated FourCC");
116 return 0;
117 err_out_too_many:
118 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"too many FourCCs/formats...");
119 return 0;
120 err_out_parse_error:
121 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
122 return 0;
125 static int add_to_format(char *s, char *alias,unsigned int *fourcc, unsigned int *fourccmap)
127 int i, j;
128 char *endptr;
130 /* find first unused slot */
131 for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++)
132 /* NOTHING */;
133 if (i == CODECS_MAX_FOURCC) {
134 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"too many FourCCs/formats...");
135 return 0;
138 fourcc[i]=strtoul(s,&endptr,0);
139 if (*endptr != '\0') {
140 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error (format ID not a number?)");
141 return 0;
144 if(alias){
145 fourccmap[i]=strtoul(alias,&endptr,0);
146 if (*endptr != '\0') {
147 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error (format ID alias not a number?)");
148 return 0;
150 } else
151 fourccmap[i]=fourcc[i];
153 for (j = 0; j < i; j++)
154 if (fourcc[j] == fourcc[i]) {
155 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"duplicated format ID");
156 return 0;
159 return 1;
162 static const struct {
163 const char *name;
164 const unsigned int num;
165 } fmt_table[] = {
166 // note: due to parser deficiencies/simplicity, if one format
167 // name matches the beginning of another, the longer one _must_
168 // come first in this list.
169 {"YV12", IMGFMT_YV12},
170 {"I420", IMGFMT_I420},
171 {"IYUV", IMGFMT_IYUV},
172 {"NV12", IMGFMT_NV12},
173 {"NV21", IMGFMT_NV21},
174 {"YVU9", IMGFMT_YVU9},
175 {"IF09", IMGFMT_IF09},
176 {"444P16LE", IMGFMT_444P16_LE},
177 {"444P16BE", IMGFMT_444P16_BE},
178 {"422P16LE", IMGFMT_422P16_LE},
179 {"422P16BE", IMGFMT_422P16_BE},
180 {"420P16LE", IMGFMT_420P16_LE},
181 {"420P16BE", IMGFMT_420P16_BE},
182 {"444P16", IMGFMT_444P16},
183 {"422P16", IMGFMT_422P16},
184 {"420P16", IMGFMT_420P16},
185 {"420A", IMGFMT_420A},
186 {"444P", IMGFMT_444P},
187 {"422P", IMGFMT_422P},
188 {"411P", IMGFMT_411P},
189 {"440P", IMGFMT_440P},
190 {"Y800", IMGFMT_Y800},
191 {"Y8", IMGFMT_Y8},
193 {"YUY2", IMGFMT_YUY2},
194 {"UYVY", IMGFMT_UYVY},
195 {"YVYU", IMGFMT_YVYU},
197 {"RGB48LE", IMGFMT_RGB48LE},
198 {"RGB48BE", IMGFMT_RGB48BE},
199 {"RGB4", IMGFMT_RGB4},
200 {"RGB8", IMGFMT_RGB8},
201 {"RGB15", IMGFMT_RGB15},
202 {"RGB16", IMGFMT_RGB16},
203 {"RGB24", IMGFMT_RGB24},
204 {"RGB32", IMGFMT_RGB32},
205 {"BGR4", IMGFMT_BGR4},
206 {"BGR8", IMGFMT_BGR8},
207 {"BGR15", IMGFMT_BGR15},
208 {"BGR16", IMGFMT_BGR16},
209 {"BGR24", IMGFMT_BGR24},
210 {"BGR32", IMGFMT_BGR32},
211 {"RGB1", IMGFMT_RGB1},
212 {"BGR1", IMGFMT_BGR1},
214 {"MPES", IMGFMT_MPEGPES},
215 {"MPG4", IMGFMT_MPEG4},
216 {"ZRMJPEGNI", IMGFMT_ZRMJPEGNI},
217 {"ZRMJPEGIT", IMGFMT_ZRMJPEGIT},
218 {"ZRMJPEGIB", IMGFMT_ZRMJPEGIB},
220 {"IDCT_MPEG2",IMGFMT_XVMC_IDCT_MPEG2},
221 {"MOCO_MPEG2",IMGFMT_XVMC_MOCO_MPEG2},
223 {"VDPAU_MPEG1",IMGFMT_VDPAU_MPEG1},
224 {"VDPAU_MPEG2",IMGFMT_VDPAU_MPEG2},
225 {"VDPAU_H264",IMGFMT_VDPAU_H264},
226 {"VDPAU_WMV3",IMGFMT_VDPAU_WMV3},
227 {"VDPAU_VC1",IMGFMT_VDPAU_VC1},
228 {"VDPAU_MPEG4",IMGFMT_VDPAU_MPEG4},
230 {NULL, 0}
234 static int add_to_inout(char *sfmt, char *sflags, unsigned int *outfmt,
235 unsigned char *outflags)
238 static char *flagstr[] = {
239 "flip",
240 "noflip",
241 "yuvhack",
242 "query",
243 "static",
244 NULL
247 int i, j, freeslots;
248 unsigned char flags;
250 for (i = 0; i < CODECS_MAX_OUTFMT && outfmt[i] != 0xffffffff; i++)
251 /* NOTHING */;
252 freeslots = CODECS_MAX_OUTFMT - i;
253 if (!freeslots)
254 goto err_out_too_many;
256 flags = 0;
257 if(sflags) {
258 do {
259 for (j = 0; flagstr[j] != NULL; j++)
260 if (!strncmp(sflags, flagstr[j],
261 strlen(flagstr[j])))
262 break;
263 if (flagstr[j] == NULL)
264 goto err_out_parse_error;
265 flags|=(1<<j);
266 sflags+=strlen(flagstr[j]);
267 } while (*(sflags++) == ',');
269 if (*(--sflags) != '\0')
270 goto err_out_parse_error;
273 do {
274 for (j = 0; fmt_table[j].name != NULL; j++)
275 if (!strncmp(sfmt, fmt_table[j].name, strlen(fmt_table[j].name)))
276 break;
277 if (fmt_table[j].name == NULL)
278 goto err_out_parse_error;
279 outfmt[i] = fmt_table[j].num;
280 outflags[i] = flags;
281 ++i;
282 sfmt+=strlen(fmt_table[j].name);
283 } while ((*(sfmt++) == ',') && --freeslots);
285 if (!freeslots)
286 goto err_out_too_many;
288 if (*(--sfmt) != '\0')
289 goto err_out_parse_error;
291 return 1;
292 err_out_too_many:
293 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"too many out...");
294 return 0;
295 err_out_parse_error:
296 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
297 return 0;
300 #if 0
301 static short get_driver(char *s,int audioflag)
303 static char *audiodrv[] = {
304 "null",
305 "mp3lib",
306 "pcm",
307 "libac3",
308 "acm",
309 "alaw",
310 "msgsm",
311 "dshow",
312 "dvdpcm",
313 "hwac3",
314 "libvorbis",
315 "ffmpeg",
316 "libmad",
317 "msadpcm",
318 "liba52",
319 "g72x",
320 "imaadpcm",
321 "dk4adpcm",
322 "dk3adpcm",
323 "roqaudio",
324 "faad",
325 "realaud",
326 "libdv",
327 NULL
329 static char *videodrv[] = {
330 "null",
331 "libmpeg2",
332 "vfw",
333 "dshow",
334 "ffmpeg",
335 "vfwex",
336 "raw",
337 "msrle",
338 "xanim",
339 "msvidc",
340 "fli",
341 "cinepak",
342 "qtrle",
343 "nuv",
344 "cyuv",
345 "qtsmc",
346 "ducktm1",
347 "roqvideo",
348 "qtrpza",
349 "mpng",
350 "ijpg",
351 "zlib",
352 "mpegpes",
353 "zrmjpeg",
354 "realvid",
355 "xvid",
356 "libdv",
357 NULL
359 char **drv=audioflag?audiodrv:videodrv;
360 int i;
362 for(i=0;drv[i];i++) if(!strcmp(s,drv[i])) return i;
364 return -1;
366 #endif
368 static int validate_codec(codecs_t *c, int type)
370 unsigned int i;
371 char *tmp_name = c->name;
373 for (i = 0; i < strlen(tmp_name) && isalnum(tmp_name[i]); i++)
374 /* NOTHING */;
376 if (i < strlen(tmp_name)) {
377 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) name is not valid!\n", c->name);
378 return 0;
381 if (!c->info)
382 c->info = strdup(c->name);
384 #if 0
385 if (c->fourcc[0] == 0xffffffff) {
386 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) does not have FourCC/format!\n", c->name);
387 return 0;
389 #endif
391 if (!c->drv) {
392 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) does not have a driver!\n", c->name);
393 return 0;
396 #if 0
397 //FIXME: codec->driver == 4;... <- this should not be put in here...
398 //FIXME: Where are they defined ????????????
399 if (!c->dll && (c->driver == 4 ||
400 (c->driver == 2 && type == TYPE_VIDEO))) {
401 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) needs a 'dll'!\n", c->name);
402 return 0;
404 // FIXME: Can guid.f1 be 0? How does one know that it was not given?
405 // if (!(codec->flags & CODECS_FLAG_AUDIO) && codec->driver == 4)
407 if (type == TYPE_VIDEO)
408 if (c->outfmt[0] == 0xffffffff) {
409 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) needs an 'outfmt'!\n", c->name);
410 return 0;
412 #endif
413 return 1;
416 static int add_comment(char *s, char **d)
418 int pos;
420 if (!*d)
421 pos = 0;
422 else {
423 pos = strlen(*d);
424 (*d)[pos++] = '\n';
426 if (!(*d = realloc(*d, pos + strlen(s) + 1))) {
427 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't allocate memory for comment. ");
428 return 0;
430 strcpy(*d + pos, s);
431 return 1;
434 static short get_cpuflags(char *s)
436 static char *flagstr[] = {
437 "mmx",
438 "sse",
439 "3dnow",
440 NULL
442 int i;
443 short flags = 0;
445 do {
446 for (i = 0; flagstr[i]; i++)
447 if (!strncmp(s, flagstr[i], strlen(flagstr[i])))
448 break;
449 if (!flagstr[i])
450 goto err_out_parse_error;
451 flags |= 1<<i;
452 s += strlen(flagstr[i]);
453 } while (*(s++) == ',');
455 if (*(--s) != '\0')
456 goto err_out_parse_error;
458 return flags;
459 err_out_parse_error:
460 return 0;
463 static FILE *fp;
464 static int line_num = 0;
465 static char *line;
466 static char *token[MAX_NR_TOKEN];
467 static int read_nextline = 1;
469 static int get_token(int min, int max)
471 static int line_pos;
472 int i;
473 char c;
475 if (max >= MAX_NR_TOKEN) {
476 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"get_token(): max >= MAX_MR_TOKEN!");
477 goto out_eof;
480 memset(token, 0x00, sizeof(*token) * max);
482 if (read_nextline) {
483 if (!fgets(line, MAX_LINE_LEN, fp))
484 goto out_eof;
485 line_pos = 0;
486 ++line_num;
487 read_nextline = 0;
489 for (i = 0; i < max; i++) {
490 while (isspace(line[line_pos]))
491 ++line_pos;
492 if (line[line_pos] == '\0' || line[line_pos] == '#' ||
493 line[line_pos] == ';') {
494 read_nextline = 1;
495 if (i >= min)
496 goto out_ok;
497 goto out_eol;
499 token[i] = line + line_pos;
500 c = line[line_pos];
501 if (c == '"' || c == '\'') {
502 token[i]++;
503 while (line[++line_pos] != c && line[line_pos])
504 /* NOTHING */;
505 } else {
506 for (/* NOTHING */; !isspace(line[line_pos]) &&
507 line[line_pos]; line_pos++)
508 /* NOTHING */;
510 if (!line[line_pos]) {
511 read_nextline = 1;
512 if (i >= min - 1)
513 goto out_ok;
514 goto out_eol;
516 line[line_pos] = '\0';
517 line_pos++;
519 out_ok:
520 return i;
521 out_eof:
522 read_nextline = 1;
523 return RET_EOF;
524 out_eol:
525 return RET_EOL;
528 static codecs_t *video_codecs=NULL;
529 static codecs_t *audio_codecs=NULL;
530 static int nr_vcodecs = 0;
531 static int nr_acodecs = 0;
533 int parse_codec_cfg(const char *cfgfile)
535 codecs_t *codec = NULL; // current codec
536 codecs_t **codecsp = NULL;// points to audio_codecs or to video_codecs
537 char *endptr; // strtoul()...
538 int *nr_codecsp;
539 int codec_type; /* TYPE_VIDEO/TYPE_AUDIO */
540 int tmp, i;
542 // in case we call it a second time
543 codecs_uninit_free();
545 nr_vcodecs = 0;
546 nr_acodecs = 0;
548 if(cfgfile==NULL) {
549 #ifdef CODECS2HTML
550 return 0;
551 #else
552 video_codecs = builtin_video_codecs;
553 audio_codecs = builtin_audio_codecs;
554 nr_vcodecs = sizeof(builtin_video_codecs)/sizeof(codecs_t);
555 nr_acodecs = sizeof(builtin_audio_codecs)/sizeof(codecs_t);
556 return 1;
557 #endif
560 mp_tmsg(MSGT_CODECCFG,MSGL_V,"Reading %s: ", cfgfile);
562 if ((fp = fopen(cfgfile, "r")) == NULL) {
563 mp_tmsg(MSGT_CODECCFG,MSGL_V,"Can't open '%s': %s\n", cfgfile, strerror(errno));
564 return 0;
567 if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) {
568 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't get memory for 'line': %s\n", strerror(errno));
569 return 0;
571 read_nextline = 1;
574 * this only catches release lines at the start of
575 * codecs.conf, before audiocodecs and videocodecs.
577 while ((tmp = get_token(1, 1)) == RET_EOL)
578 /* NOTHING */;
579 if (tmp == RET_EOF)
580 goto out;
581 if (!strcmp(token[0], "release")) {
582 if (get_token(1, 2) < 0)
583 goto err_out_parse_error;
584 tmp = atoi(token[0]);
585 if (tmp < CODEC_CFG_MIN)
586 goto err_out_release_num;
587 codecs_conf_release = tmp;
588 while ((tmp = get_token(1, 1)) == RET_EOL)
589 /* NOTHING */;
590 if (tmp == RET_EOF)
591 goto out;
592 } else
593 goto err_out_release_num;
596 * check if the next block starts with 'audiocodec' or
597 * with 'videocodec'
599 if (!strcmp(token[0], "audiocodec") || !strcmp(token[0], "videocodec"))
600 goto loop_enter;
601 goto err_out_parse_error;
603 while ((tmp = get_token(1, 1)) != RET_EOF) {
604 if (tmp == RET_EOL)
605 continue;
606 if (!strcmp(token[0], "audiocodec") ||
607 !strcmp(token[0], "videocodec")) {
608 if (!validate_codec(codec, codec_type))
609 goto err_out_not_valid;
610 loop_enter:
611 if (*token[0] == 'v') {
612 codec_type = TYPE_VIDEO;
613 nr_codecsp = &nr_vcodecs;
614 codecsp = &video_codecs;
615 } else if (*token[0] == 'a') {
616 codec_type = TYPE_AUDIO;
617 nr_codecsp = &nr_acodecs;
618 codecsp = &audio_codecs;
619 #ifdef DEBUG
620 } else {
621 mp_msg(MSGT_CODECCFG,MSGL_ERR,"picsba\n");
622 goto err_out;
623 #endif
625 if (!(*codecsp = realloc(*codecsp,
626 sizeof(codecs_t) * (*nr_codecsp + 2)))) {
627 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't realloc '*codecsp': %s\n", strerror(errno));
628 goto err_out;
630 codec=*codecsp + *nr_codecsp;
631 ++*nr_codecsp;
632 memset(codec,0,sizeof(codecs_t));
633 memset(codec->fourcc, 0xff, sizeof(codec->fourcc));
634 memset(codec->outfmt, 0xff, sizeof(codec->outfmt));
635 memset(codec->infmt, 0xff, sizeof(codec->infmt));
637 if (get_token(1, 1) < 0)
638 goto err_out_parse_error;
639 for (i = 0; i < *nr_codecsp - 1; i++) {
640 if(( (*codecsp)[i].name!=NULL) &&
641 (!strcmp(token[0], (*codecsp)[i].name)) ) {
642 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Codec name '%s' isn't unique.", token[0]);
643 goto err_out_print_linenum;
646 if (!(codec->name = strdup(token[0]))) {
647 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'name': %s\n", strerror(errno));
648 goto err_out;
650 } else if (!strcmp(token[0], "info")) {
651 if (codec->info || get_token(1, 1) < 0)
652 goto err_out_parse_error;
653 if (!(codec->info = strdup(token[0]))) {
654 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'info': %s\n", strerror(errno));
655 goto err_out;
657 } else if (!strcmp(token[0], "comment")) {
658 if (get_token(1, 1) < 0)
659 goto err_out_parse_error;
660 add_comment(token[0], &codec->comment);
661 } else if (!strcmp(token[0], "fourcc")) {
662 if (get_token(1, 2) < 0)
663 goto err_out_parse_error;
664 if (!add_to_fourcc(token[0], token[1],
665 codec->fourcc,
666 codec->fourccmap))
667 goto err_out_print_linenum;
668 } else if (!strcmp(token[0], "format")) {
669 if (get_token(1, 2) < 0)
670 goto err_out_parse_error;
671 if (!add_to_format(token[0], token[1],
672 codec->fourcc,codec->fourccmap))
673 goto err_out_print_linenum;
674 } else if (!strcmp(token[0], "driver")) {
675 if (get_token(1, 1) < 0)
676 goto err_out_parse_error;
677 if (!(codec->drv = strdup(token[0]))) {
678 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'driver': %s\n", strerror(errno));
679 goto err_out;
681 } else if (!strcmp(token[0], "dll")) {
682 if (get_token(1, 1) < 0)
683 goto err_out_parse_error;
684 if (!(codec->dll = strdup(token[0]))) {
685 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'dll': %s", strerror(errno));
686 goto err_out;
688 } else if (!strcmp(token[0], "guid")) {
689 if (get_token(11, 11) < 0)
690 goto err_out_parse_error;
691 codec->guid.f1=strtoul(token[0],&endptr,0);
692 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
693 *endptr != '\0')
694 goto err_out_parse_error;
695 codec->guid.f2=strtoul(token[1],&endptr,0);
696 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
697 *endptr != '\0')
698 goto err_out_parse_error;
699 codec->guid.f3=strtoul(token[2],&endptr,0);
700 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
701 *endptr != '\0')
702 goto err_out_parse_error;
703 for (i = 0; i < 8; i++) {
704 codec->guid.f4[i]=strtoul(token[i + 3],&endptr,0);
705 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
706 *endptr != '\0')
707 goto err_out_parse_error;
709 } else if (!strcmp(token[0], "out")) {
710 if (get_token(1, 2) < 0)
711 goto err_out_parse_error;
712 if (!add_to_inout(token[0], token[1], codec->outfmt,
713 codec->outflags))
714 goto err_out_print_linenum;
715 } else if (!strcmp(token[0], "in")) {
716 if (get_token(1, 2) < 0)
717 goto err_out_parse_error;
718 if (!add_to_inout(token[0], token[1], codec->infmt,
719 codec->inflags))
720 goto err_out_print_linenum;
721 } else if (!strcmp(token[0], "flags")) {
722 if (get_token(1, 1) < 0)
723 goto err_out_parse_error;
724 if (!strcmp(token[0], "seekable"))
725 codec->flags |= CODECS_FLAG_SEEKABLE;
726 else if (!strcmp(token[0], "align16"))
727 codec->flags |= CODECS_FLAG_ALIGN16;
728 else
729 goto err_out_parse_error;
730 } else if (!strcmp(token[0], "status")) {
731 if (get_token(1, 1) < 0)
732 goto err_out_parse_error;
733 if (!strcasecmp(token[0], "working"))
734 codec->status = CODECS_STATUS_WORKING;
735 else if (!strcasecmp(token[0], "crashing"))
736 codec->status = CODECS_STATUS_NOT_WORKING;
737 else if (!strcasecmp(token[0], "untested"))
738 codec->status = CODECS_STATUS_UNTESTED;
739 else if (!strcasecmp(token[0], "buggy"))
740 codec->status = CODECS_STATUS_PROBLEMS;
741 else
742 goto err_out_parse_error;
743 } else if (!strcmp(token[0], "cpuflags")) {
744 if (get_token(1, 1) < 0)
745 goto err_out_parse_error;
746 if (!(codec->cpuflags = get_cpuflags(token[0])))
747 goto err_out_parse_error;
748 } else
749 goto err_out_parse_error;
751 if (!validate_codec(codec, codec_type))
752 goto err_out_not_valid;
753 mp_tmsg(MSGT_CODECCFG,MSGL_INFO,"%d audio & %d video codecs\n", nr_acodecs, nr_vcodecs);
754 if(video_codecs) video_codecs[nr_vcodecs].name = NULL;
755 if(audio_codecs) audio_codecs[nr_acodecs].name = NULL;
756 out:
757 free(line);
758 line=NULL;
759 fclose(fp);
760 return 1;
762 err_out_parse_error:
763 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
764 err_out_print_linenum:
765 PRINT_LINENUM;
766 err_out:
767 codecs_uninit_free();
769 free(line);
770 line=NULL;
771 line_num = 0;
772 fclose(fp);
773 return 0;
774 err_out_not_valid:
775 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Codec is not defined correctly.");
776 goto err_out_print_linenum;
777 err_out_release_num:
778 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"This codecs.conf is too old and incompatible with this MPlayer release!");
779 goto err_out_print_linenum;
782 static void codecs_free(codecs_t* codecs,int count) {
783 int i;
784 for ( i = 0; i < count; i++)
785 if ( codecs[i].name ) {
786 free(codecs[i].name);
787 free(codecs[i].info);
788 free(codecs[i].comment);
789 free(codecs[i].dll);
790 free(codecs[i].drv);
792 free(codecs);
795 void codecs_uninit_free(void) {
796 if (video_codecs)
797 codecs_free(video_codecs,nr_vcodecs);
798 video_codecs=NULL;
799 if (audio_codecs)
800 codecs_free(audio_codecs,nr_acodecs);
801 audio_codecs=NULL;
804 codecs_t *find_audio_codec(unsigned int fourcc, unsigned int *fourccmap,
805 codecs_t *start, int force)
807 return find_codec(fourcc, fourccmap, start, 1, force);
810 codecs_t *find_video_codec(unsigned int fourcc, unsigned int *fourccmap,
811 codecs_t *start, int force)
813 return find_codec(fourcc, fourccmap, start, 0, force);
816 codecs_t* find_codec(unsigned int fourcc,unsigned int *fourccmap,
817 codecs_t *start, int audioflag, int force)
819 int i, j;
820 codecs_t *c;
822 #if 0
823 if (start) {
824 for (/* NOTHING */; start->name; start++) {
825 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
826 if (start->fourcc[j] == fourcc) {
827 if (fourccmap)
828 *fourccmap = start->fourccmap[j];
829 return start;
833 } else
834 #endif
836 if (audioflag) {
837 i = nr_acodecs;
838 c = audio_codecs;
839 } else {
840 i = nr_vcodecs;
841 c = video_codecs;
843 if(!i) return NULL;
844 for (/* NOTHING */; i--; c++) {
845 if(start && c<=start) continue;
846 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
847 // FIXME: do NOT hardwire 'null' name here:
848 if (c->fourcc[j]==fourcc || !strcmp(c->drv,"null")) {
849 if (fourccmap)
850 *fourccmap = c->fourccmap[j];
851 return c;
854 if (force) return c;
857 return NULL;
860 void stringset_init(stringset_t *set) {
861 *set = calloc(1, sizeof(char *));
864 void stringset_free(stringset_t *set) {
865 int count = 0;
866 while ((*set)[count]) free((*set)[count++]);
867 free(*set);
868 *set = NULL;
871 void stringset_add(stringset_t *set, const char *str) {
872 int count = 0;
873 while ((*set)[count]) count++;
874 count++;
875 *set = realloc(*set, sizeof(char *) * (count + 1));
876 (*set)[count - 1] = strdup(str);
877 (*set)[count] = NULL;
880 int stringset_test(stringset_t *set, const char *str) {
881 stringset_t s;
882 for (s = *set; *s; s++)
883 if (strcmp(*s, str) == 0)
884 return 1;
885 return 0;
888 void list_codecs(int audioflag){
889 int i;
890 codecs_t *c;
892 if (audioflag) {
893 i = nr_acodecs;
894 c = audio_codecs;
895 mp_msg(MSGT_CODECCFG,MSGL_INFO,"ac: afm: status: info: [lib/dll]\n");
896 } else {
897 i = nr_vcodecs;
898 c = video_codecs;
899 mp_msg(MSGT_CODECCFG,MSGL_INFO,"vc: vfm: status: info: [lib/dll]\n");
901 if(!i) return;
902 for (/* NOTHING */; i--; c++) {
903 char* s="unknown ";
904 switch(c->status){
905 case CODECS_STATUS_WORKING: s="working ";break;
906 case CODECS_STATUS_PROBLEMS: s="problems";break;
907 case CODECS_STATUS_NOT_WORKING: s="crashing";break;
908 case CODECS_STATUS_UNTESTED: s="untested";break;
910 if(c->dll)
911 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s [%s]\n",c->name,c->drv,s,c->info,c->dll);
912 else
913 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s\n",c->name,c->drv,s,c->info);
918 #ifdef CODECS2HTML
919 static void wrapline(FILE *f2,char *s){
920 int c;
921 if(!s){
922 fprintf(f2,"-");
923 return;
925 while((c=*s++)){
926 if(c==',') fprintf(f2,"<br>"); else fputc(c,f2);
930 static void parsehtml(FILE *f1,FILE *f2,codecs_t *codec){
931 int c,d;
932 while((c=fgetc(f1))>=0){
933 if(c!='%'){
934 fputc(c,f2);
935 continue;
937 d=fgetc(f1);
939 switch(d){
940 case '.':
941 return; // end of section
942 case 'n':
943 wrapline(f2,codec->name); break;
944 case 'i':
945 wrapline(f2,codec->info); break;
946 case 'c':
947 wrapline(f2,codec->comment); break;
948 case 'd':
949 wrapline(f2,codec->dll); break;
950 case 'D':
951 fprintf(f2,"%c",!strcmp(codec->drv,"dshow")?'+':'-'); break;
952 case 'F':
953 for(d=0;d<CODECS_MAX_FOURCC;d++)
954 if(!d || codec->fourcc[d]!=0xFFFFFFFF)
955 fprintf(f2,"%s%.4s",d?"<br>":"",(codec->fourcc[d]==0xFFFFFFFF || codec->fourcc[d]<0x20202020)?!d?"-":"":(char*) &codec->fourcc[d]);
956 break;
957 case 'f':
958 for(d=0;d<CODECS_MAX_FOURCC;d++)
959 if(codec->fourcc[d]!=0xFFFFFFFF)
960 fprintf(f2,"%s0x%X",d?"<br>":"",codec->fourcc[d]);
961 break;
962 case 'Y':
963 for(d=0;d<CODECS_MAX_OUTFMT;d++)
964 if(codec->outfmt[d]!=0xFFFFFFFF){
965 for (c=0; fmt_table[c].name; c++)
966 if(fmt_table[c].num==codec->outfmt[d]) break;
967 if(fmt_table[c].name)
968 fprintf(f2,"%s%s",d?"<br>":"",fmt_table[c].name);
970 break;
971 default:
972 fputc(c,f2);
973 fputc(d,f2);
978 void skiphtml(FILE *f1){
979 int c,d;
980 while((c=fgetc(f1))>=0){
981 if(c!='%'){
982 continue;
984 d=fgetc(f1);
985 if(d=='.') return; // end of section
989 static void print_int_array(const unsigned int* a, int size)
991 printf("{ ");
992 while (size--)
993 if(abs(*a)<256)
994 printf("%d%s", *a++, size?", ":"");
995 else
996 printf("0x%X%s", *a++, size?", ":"");
997 printf(" }");
1000 static void print_char_array(const unsigned char* a, int size)
1002 printf("{ ");
1003 while (size--)
1004 if((*a)<10)
1005 printf("%d%s", *a++, size?", ":"");
1006 else
1007 printf("0x%02x%s", *a++, size?", ":"");
1008 printf(" }");
1011 static void print_string(const char* s)
1013 if (!s) printf("NULL");
1014 else printf("\"%s\"", s);
1017 int main(int argc, char* argv[])
1019 codecs_t *cl;
1020 FILE *f1;
1021 FILE *f2;
1022 int c,d,i;
1023 int pos;
1024 int section=-1;
1025 int nr_codecs;
1026 int win32=-1;
1027 int dshow=-1;
1028 int win32ex=-1;
1031 * Take path to codecs.conf from command line, or fall back on
1032 * etc/codecs.conf
1034 if (!(nr_codecs = parse_codec_cfg((argc>1)?argv[1]:"etc/codecs.conf")))
1035 exit(1);
1036 if (codecs_conf_release < CODEC_CFG_MIN)
1037 exit(1);
1039 if (argc > 1) {
1040 int i, j;
1041 const char* nm[2];
1042 codecs_t* cod[2];
1043 int nr[2];
1045 nm[0] = "builtin_video_codecs";
1046 cod[0] = video_codecs;
1047 nr[0] = nr_vcodecs;
1049 nm[1] = "builtin_audio_codecs";
1050 cod[1] = audio_codecs;
1051 nr[1] = nr_acodecs;
1053 printf("/* GENERATED FROM %s, DO NOT EDIT! */\n\n",argv[1]);
1054 printf("#include <stddef.h>\n");
1055 printf("#include \"codec-cfg.h\"\n\n");
1056 printf("#define CODEC_CFG_MIN %i\n\n", codecs_conf_release);
1058 for (i=0; i<2; i++) {
1059 printf("const codecs_t %s[] = {\n", nm[i]);
1060 for (j = 0; j < nr[i]; j++) {
1061 printf("{");
1063 print_int_array(cod[i][j].fourcc, CODECS_MAX_FOURCC);
1064 printf(", /* fourcc */\n");
1066 print_int_array(cod[i][j].fourccmap, CODECS_MAX_FOURCC);
1067 printf(", /* fourccmap */\n");
1069 print_int_array(cod[i][j].outfmt, CODECS_MAX_OUTFMT);
1070 printf(", /* outfmt */\n");
1072 print_char_array(cod[i][j].outflags, CODECS_MAX_OUTFMT);
1073 printf(", /* outflags */\n");
1075 print_int_array(cod[i][j].infmt, CODECS_MAX_INFMT);
1076 printf(", /* infmt */\n");
1078 print_char_array(cod[i][j].inflags, CODECS_MAX_INFMT);
1079 printf(", /* inflags */\n");
1081 print_string(cod[i][j].name); printf(", /* name */\n");
1082 print_string(cod[i][j].info); printf(", /* info */\n");
1083 print_string(cod[i][j].comment); printf(", /* comment */\n");
1084 print_string(cod[i][j].dll); printf(", /* dll */\n");
1085 print_string(cod[i][j].drv); printf(", /* drv */\n");
1087 printf("{ 0x%08lx, %hu, %hu,",
1088 cod[i][j].guid.f1,
1089 cod[i][j].guid.f2,
1090 cod[i][j].guid.f3);
1091 print_char_array(cod[i][j].guid.f4, sizeof(cod[i][j].guid.f4));
1092 printf(" }, /* GUID */\n");
1093 printf("%hd /* flags */, %hd /* status */, %hd /* cpuflags */ }\n",
1094 cod[i][j].flags,
1095 cod[i][j].status,
1096 cod[i][j].cpuflags);
1097 if (j < nr[i]) printf(",\n");
1099 printf("};\n\n");
1101 exit(0);
1104 f1=fopen("DOCS/tech/codecs-in.html","rb"); if(!f1) exit(1);
1105 f2=fopen("DOCS/codecs-status.html","wb"); if(!f2) exit(1);
1107 while((c=fgetc(f1))>=0){
1108 if(c!='%'){
1109 fputc(c,f2);
1110 continue;
1112 d=fgetc(f1);
1113 if(d>='0' && d<='9'){
1114 // begin section
1115 section=d-'0';
1116 //printf("BEGIN %d\n",section);
1117 if(section>=5){
1118 // audio
1119 cl = audio_codecs;
1120 nr_codecs = nr_acodecs;
1121 dshow=7;win32=4;
1122 } else {
1123 // video
1124 cl = video_codecs;
1125 nr_codecs = nr_vcodecs;
1126 dshow=4;win32=2;win32ex=6;
1128 pos=ftell(f1);
1129 for(i=0;i<nr_codecs;i++){
1130 fseek(f1,pos,SEEK_SET);
1131 switch(section){
1132 case 0:
1133 case 5:
1134 if(cl[i].status==CODECS_STATUS_WORKING)
1135 // if(!(!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1136 parsehtml(f1,f2,&cl[i]);
1137 break;
1138 #if 0
1139 case 1:
1140 case 6:
1141 if(cl[i].status==CODECS_STATUS_WORKING)
1142 if((!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1143 parsehtml(f1,f2,&cl[i]);
1144 break;
1145 #endif
1146 case 2:
1147 case 7:
1148 if(cl[i].status==CODECS_STATUS_PROBLEMS)
1149 parsehtml(f1,f2,&cl[i]);
1150 break;
1151 case 3:
1152 case 8:
1153 if(cl[i].status==CODECS_STATUS_NOT_WORKING)
1154 parsehtml(f1,f2,&cl[i]);
1155 break;
1156 case 4:
1157 case 9:
1158 if(cl[i].status==CODECS_STATUS_UNTESTED)
1159 parsehtml(f1,f2,&cl[i]);
1160 break;
1161 default:
1162 printf("Warning! unimplemented section: %d\n",section);
1165 fseek(f1,pos,SEEK_SET);
1166 skiphtml(f1);
1168 continue;
1170 fputc(c,f2);
1171 fputc(d,f2);
1174 fclose(f2);
1175 fclose(f1);
1176 return 0;
1179 #endif
1181 #ifdef TESTING
1182 int main(void)
1184 codecs_t *c;
1185 int i,j, nr_codecs, state;
1187 if (!(parse_codec_cfg("etc/codecs.conf")))
1188 return 0;
1189 if (!video_codecs)
1190 printf("no videoconfig.\n");
1191 if (!audio_codecs)
1192 printf("no audioconfig.\n");
1194 printf("videocodecs:\n");
1195 c = video_codecs;
1196 nr_codecs = nr_vcodecs;
1197 state = 0;
1198 next:
1199 if (c) {
1200 printf("number of %scodecs: %d\n", state==0?"video":"audio",
1201 nr_codecs);
1202 for(i=0;i<nr_codecs;i++, c++){
1203 printf("\n============== %scodec %02d ===============\n",
1204 state==0?"video":"audio",i);
1205 printf("name='%s'\n",c->name);
1206 printf("info='%s'\n",c->info);
1207 printf("comment='%s'\n",c->comment);
1208 printf("dll='%s'\n",c->dll);
1209 /* printf("flags=%X driver=%d status=%d cpuflags=%d\n",
1210 c->flags, c->driver, c->status, c->cpuflags); */
1211 printf("flags=%X status=%d cpuflags=%d\n",
1212 c->flags, c->status, c->cpuflags);
1214 for(j=0;j<CODECS_MAX_FOURCC;j++){
1215 if(c->fourcc[j]!=0xFFFFFFFF){
1216 printf("fourcc %02d: %08X (%.4s) ===> %08X (%.4s)\n",j,c->fourcc[j],(char *) &c->fourcc[j],c->fourccmap[j],(char *) &c->fourccmap[j]);
1220 for(j=0;j<CODECS_MAX_OUTFMT;j++){
1221 if(c->outfmt[j]!=0xFFFFFFFF){
1222 printf("outfmt %02d: %08X (%.4s) flags: %d\n",j,c->outfmt[j],(char *) &c->outfmt[j],c->outflags[j]);
1226 for(j=0;j<CODECS_MAX_INFMT;j++){
1227 if(c->infmt[j]!=0xFFFFFFFF){
1228 printf("infmt %02d: %08X (%.4s) flags: %d\n",j,c->infmt[j],(char *) &c->infmt[j],c->inflags[j]);
1232 printf("GUID: %08lX %04X %04X",c->guid.f1,c->guid.f2,c->guid.f3);
1233 for(j=0;j<8;j++) printf(" %02X",c->guid.f4[j]);
1234 printf("\n");
1239 if (!state) {
1240 printf("audiocodecs:\n");
1241 c = audio_codecs;
1242 nr_codecs = nr_acodecs;
1243 state = 1;
1244 goto next;
1246 return 0;
1249 #endif