demux_asf, asfheader.c: cleanup
[mplayer.git] / codec-cfg.c
blob84402ada7ba468809782222a5b425472cef28045
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 {"ZRMJPEGNI", IMGFMT_ZRMJPEGNI},
216 {"ZRMJPEGIT", IMGFMT_ZRMJPEGIT},
217 {"ZRMJPEGIB", IMGFMT_ZRMJPEGIB},
219 {"IDCT_MPEG2",IMGFMT_XVMC_IDCT_MPEG2},
220 {"MOCO_MPEG2",IMGFMT_XVMC_MOCO_MPEG2},
222 {"VDPAU_MPEG1",IMGFMT_VDPAU_MPEG1},
223 {"VDPAU_MPEG2",IMGFMT_VDPAU_MPEG2},
224 {"VDPAU_H264",IMGFMT_VDPAU_H264},
225 {"VDPAU_WMV3",IMGFMT_VDPAU_WMV3},
226 {"VDPAU_VC1",IMGFMT_VDPAU_VC1},
227 {"VDPAU_MPEG4",IMGFMT_VDPAU_MPEG4},
229 {NULL, 0}
233 static int add_to_inout(char *sfmt, char *sflags, unsigned int *outfmt,
234 unsigned char *outflags)
237 static char *flagstr[] = {
238 "flip",
239 "noflip",
240 "yuvhack",
241 "query",
242 "static",
243 NULL
246 int i, j, freeslots;
247 unsigned char flags;
249 for (i = 0; i < CODECS_MAX_OUTFMT && outfmt[i] != 0xffffffff; i++)
250 /* NOTHING */;
251 freeslots = CODECS_MAX_OUTFMT - i;
252 if (!freeslots)
253 goto err_out_too_many;
255 flags = 0;
256 if(sflags) {
257 do {
258 for (j = 0; flagstr[j] != NULL; j++)
259 if (!strncmp(sflags, flagstr[j],
260 strlen(flagstr[j])))
261 break;
262 if (flagstr[j] == NULL)
263 goto err_out_parse_error;
264 flags|=(1<<j);
265 sflags+=strlen(flagstr[j]);
266 } while (*(sflags++) == ',');
268 if (*(--sflags) != '\0')
269 goto err_out_parse_error;
272 do {
273 for (j = 0; fmt_table[j].name != NULL; j++)
274 if (!strncmp(sfmt, fmt_table[j].name, strlen(fmt_table[j].name)))
275 break;
276 if (fmt_table[j].name == NULL)
277 goto err_out_parse_error;
278 outfmt[i] = fmt_table[j].num;
279 outflags[i] = flags;
280 ++i;
281 sfmt+=strlen(fmt_table[j].name);
282 } while ((*(sfmt++) == ',') && --freeslots);
284 if (!freeslots)
285 goto err_out_too_many;
287 if (*(--sfmt) != '\0')
288 goto err_out_parse_error;
290 return 1;
291 err_out_too_many:
292 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"too many out...");
293 return 0;
294 err_out_parse_error:
295 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
296 return 0;
299 #if 0
300 static short get_driver(char *s,int audioflag)
302 static char *audiodrv[] = {
303 "null",
304 "mp3lib",
305 "pcm",
306 "libac3",
307 "acm",
308 "alaw",
309 "msgsm",
310 "dshow",
311 "dvdpcm",
312 "hwac3",
313 "libvorbis",
314 "ffmpeg",
315 "libmad",
316 "msadpcm",
317 "liba52",
318 "g72x",
319 "imaadpcm",
320 "dk4adpcm",
321 "dk3adpcm",
322 "roqaudio",
323 "faad",
324 "realaud",
325 "libdv",
326 NULL
328 static char *videodrv[] = {
329 "null",
330 "libmpeg2",
331 "vfw",
332 "dshow",
333 "ffmpeg",
334 "vfwex",
335 "raw",
336 "msrle",
337 "xanim",
338 "msvidc",
339 "fli",
340 "cinepak",
341 "qtrle",
342 "nuv",
343 "cyuv",
344 "qtsmc",
345 "ducktm1",
346 "roqvideo",
347 "qtrpza",
348 "mpng",
349 "ijpg",
350 "zlib",
351 "mpegpes",
352 "zrmjpeg",
353 "realvid",
354 "xvid",
355 "libdv",
356 NULL
358 char **drv=audioflag?audiodrv:videodrv;
359 int i;
361 for(i=0;drv[i];i++) if(!strcmp(s,drv[i])) return i;
363 return -1;
365 #endif
367 static int validate_codec(codecs_t *c, int type)
369 unsigned int i;
370 char *tmp_name = c->name;
372 for (i = 0; i < strlen(tmp_name) && isalnum(tmp_name[i]); i++)
373 /* NOTHING */;
375 if (i < strlen(tmp_name)) {
376 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) name is not valid!\n", c->name);
377 return 0;
380 if (!c->info)
381 c->info = strdup(c->name);
383 #if 0
384 if (c->fourcc[0] == 0xffffffff) {
385 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) does not have FourCC/format!\n", c->name);
386 return 0;
388 #endif
390 if (!c->drv) {
391 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) does not have a driver!\n", c->name);
392 return 0;
395 #if 0
396 //FIXME: codec->driver == 4;... <- this should not be put in here...
397 //FIXME: Where are they defined ????????????
398 if (!c->dll && (c->driver == 4 ||
399 (c->driver == 2 && type == TYPE_VIDEO))) {
400 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) needs a 'dll'!\n", c->name);
401 return 0;
403 // FIXME: Can guid.f1 be 0? How does one know that it was not given?
404 // if (!(codec->flags & CODECS_FLAG_AUDIO) && codec->driver == 4)
406 if (type == TYPE_VIDEO)
407 if (c->outfmt[0] == 0xffffffff) {
408 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) needs an 'outfmt'!\n", c->name);
409 return 0;
411 #endif
412 return 1;
415 static int add_comment(char *s, char **d)
417 int pos;
419 if (!*d)
420 pos = 0;
421 else {
422 pos = strlen(*d);
423 (*d)[pos++] = '\n';
425 if (!(*d = realloc(*d, pos + strlen(s) + 1))) {
426 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't allocate memory for comment. ");
427 return 0;
429 strcpy(*d + pos, s);
430 return 1;
433 static short get_cpuflags(char *s)
435 static char *flagstr[] = {
436 "mmx",
437 "sse",
438 "3dnow",
439 NULL
441 int i;
442 short flags = 0;
444 do {
445 for (i = 0; flagstr[i]; i++)
446 if (!strncmp(s, flagstr[i], strlen(flagstr[i])))
447 break;
448 if (!flagstr[i])
449 goto err_out_parse_error;
450 flags |= 1<<i;
451 s += strlen(flagstr[i]);
452 } while (*(s++) == ',');
454 if (*(--s) != '\0')
455 goto err_out_parse_error;
457 return flags;
458 err_out_parse_error:
459 return 0;
462 static FILE *fp;
463 static int line_num = 0;
464 static char *line;
465 static char *token[MAX_NR_TOKEN];
466 static int read_nextline = 1;
468 static int get_token(int min, int max)
470 static int line_pos;
471 int i;
472 char c;
474 if (max >= MAX_NR_TOKEN) {
475 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"get_token(): max >= MAX_MR_TOKEN!");
476 goto out_eof;
479 memset(token, 0x00, sizeof(*token) * max);
481 if (read_nextline) {
482 if (!fgets(line, MAX_LINE_LEN, fp))
483 goto out_eof;
484 line_pos = 0;
485 ++line_num;
486 read_nextline = 0;
488 for (i = 0; i < max; i++) {
489 while (isspace(line[line_pos]))
490 ++line_pos;
491 if (line[line_pos] == '\0' || line[line_pos] == '#' ||
492 line[line_pos] == ';') {
493 read_nextline = 1;
494 if (i >= min)
495 goto out_ok;
496 goto out_eol;
498 token[i] = line + line_pos;
499 c = line[line_pos];
500 if (c == '"' || c == '\'') {
501 token[i]++;
502 while (line[++line_pos] != c && line[line_pos])
503 /* NOTHING */;
504 } else {
505 for (/* NOTHING */; !isspace(line[line_pos]) &&
506 line[line_pos]; line_pos++)
507 /* NOTHING */;
509 if (!line[line_pos]) {
510 read_nextline = 1;
511 if (i >= min - 1)
512 goto out_ok;
513 goto out_eol;
515 line[line_pos] = '\0';
516 line_pos++;
518 out_ok:
519 return i;
520 out_eof:
521 read_nextline = 1;
522 return RET_EOF;
523 out_eol:
524 return RET_EOL;
527 static codecs_t *video_codecs=NULL;
528 static codecs_t *audio_codecs=NULL;
529 static int nr_vcodecs = 0;
530 static int nr_acodecs = 0;
532 int parse_codec_cfg(const char *cfgfile)
534 codecs_t *codec = NULL; // current codec
535 codecs_t **codecsp = NULL;// points to audio_codecs or to video_codecs
536 char *endptr; // strtoul()...
537 int *nr_codecsp;
538 int codec_type; /* TYPE_VIDEO/TYPE_AUDIO */
539 int tmp, i;
541 // in case we call it a second time
542 codecs_uninit_free();
544 nr_vcodecs = 0;
545 nr_acodecs = 0;
547 if(cfgfile==NULL) {
548 #ifdef CODECS2HTML
549 return 0;
550 #else
551 video_codecs = builtin_video_codecs;
552 audio_codecs = builtin_audio_codecs;
553 nr_vcodecs = sizeof(builtin_video_codecs)/sizeof(codecs_t);
554 nr_acodecs = sizeof(builtin_audio_codecs)/sizeof(codecs_t);
555 return 1;
556 #endif
559 mp_tmsg(MSGT_CODECCFG,MSGL_V,"Reading %s: ", cfgfile);
561 if ((fp = fopen(cfgfile, "r")) == NULL) {
562 mp_tmsg(MSGT_CODECCFG,MSGL_V,"Can't open '%s': %s\n", cfgfile, strerror(errno));
563 return 0;
566 if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) {
567 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't get memory for 'line': %s\n", strerror(errno));
568 return 0;
570 read_nextline = 1;
573 * this only catches release lines at the start of
574 * codecs.conf, before audiocodecs and videocodecs.
576 while ((tmp = get_token(1, 1)) == RET_EOL)
577 /* NOTHING */;
578 if (tmp == RET_EOF)
579 goto out;
580 if (!strcmp(token[0], "release")) {
581 if (get_token(1, 2) < 0)
582 goto err_out_parse_error;
583 tmp = atoi(token[0]);
584 if (tmp < CODEC_CFG_MIN)
585 goto err_out_release_num;
586 codecs_conf_release = tmp;
587 while ((tmp = get_token(1, 1)) == RET_EOL)
588 /* NOTHING */;
589 if (tmp == RET_EOF)
590 goto out;
591 } else
592 goto err_out_release_num;
595 * check if the next block starts with 'audiocodec' or
596 * with 'videocodec'
598 if (!strcmp(token[0], "audiocodec") || !strcmp(token[0], "videocodec"))
599 goto loop_enter;
600 goto err_out_parse_error;
602 while ((tmp = get_token(1, 1)) != RET_EOF) {
603 if (tmp == RET_EOL)
604 continue;
605 if (!strcmp(token[0], "audiocodec") ||
606 !strcmp(token[0], "videocodec")) {
607 if (!validate_codec(codec, codec_type))
608 goto err_out_not_valid;
609 loop_enter:
610 if (*token[0] == 'v') {
611 codec_type = TYPE_VIDEO;
612 nr_codecsp = &nr_vcodecs;
613 codecsp = &video_codecs;
614 } else if (*token[0] == 'a') {
615 codec_type = TYPE_AUDIO;
616 nr_codecsp = &nr_acodecs;
617 codecsp = &audio_codecs;
618 #ifdef DEBUG
619 } else {
620 mp_msg(MSGT_CODECCFG,MSGL_ERR,"picsba\n");
621 goto err_out;
622 #endif
624 if (!(*codecsp = realloc(*codecsp,
625 sizeof(codecs_t) * (*nr_codecsp + 2)))) {
626 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't realloc '*codecsp': %s\n", strerror(errno));
627 goto err_out;
629 codec=*codecsp + *nr_codecsp;
630 ++*nr_codecsp;
631 memset(codec,0,sizeof(codecs_t));
632 memset(codec->fourcc, 0xff, sizeof(codec->fourcc));
633 memset(codec->outfmt, 0xff, sizeof(codec->outfmt));
634 memset(codec->infmt, 0xff, sizeof(codec->infmt));
636 if (get_token(1, 1) < 0)
637 goto err_out_parse_error;
638 for (i = 0; i < *nr_codecsp - 1; i++) {
639 if(( (*codecsp)[i].name!=NULL) &&
640 (!strcmp(token[0], (*codecsp)[i].name)) ) {
641 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Codec name '%s' isn't unique.", token[0]);
642 goto err_out_print_linenum;
645 if (!(codec->name = strdup(token[0]))) {
646 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'name': %s\n", strerror(errno));
647 goto err_out;
649 } else if (!strcmp(token[0], "info")) {
650 if (codec->info || get_token(1, 1) < 0)
651 goto err_out_parse_error;
652 if (!(codec->info = strdup(token[0]))) {
653 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'info': %s\n", strerror(errno));
654 goto err_out;
656 } else if (!strcmp(token[0], "comment")) {
657 if (get_token(1, 1) < 0)
658 goto err_out_parse_error;
659 add_comment(token[0], &codec->comment);
660 } else if (!strcmp(token[0], "fourcc")) {
661 if (get_token(1, 2) < 0)
662 goto err_out_parse_error;
663 if (!add_to_fourcc(token[0], token[1],
664 codec->fourcc,
665 codec->fourccmap))
666 goto err_out_print_linenum;
667 } else if (!strcmp(token[0], "format")) {
668 if (get_token(1, 2) < 0)
669 goto err_out_parse_error;
670 if (!add_to_format(token[0], token[1],
671 codec->fourcc,codec->fourccmap))
672 goto err_out_print_linenum;
673 } else if (!strcmp(token[0], "driver")) {
674 if (get_token(1, 1) < 0)
675 goto err_out_parse_error;
676 if (!(codec->drv = strdup(token[0]))) {
677 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'driver': %s\n", strerror(errno));
678 goto err_out;
680 } else if (!strcmp(token[0], "dll")) {
681 if (get_token(1, 1) < 0)
682 goto err_out_parse_error;
683 if (!(codec->dll = strdup(token[0]))) {
684 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'dll': %s", strerror(errno));
685 goto err_out;
687 } else if (!strcmp(token[0], "guid")) {
688 if (get_token(11, 11) < 0)
689 goto err_out_parse_error;
690 codec->guid.f1=strtoul(token[0],&endptr,0);
691 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
692 *endptr != '\0')
693 goto err_out_parse_error;
694 codec->guid.f2=strtoul(token[1],&endptr,0);
695 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
696 *endptr != '\0')
697 goto err_out_parse_error;
698 codec->guid.f3=strtoul(token[2],&endptr,0);
699 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
700 *endptr != '\0')
701 goto err_out_parse_error;
702 for (i = 0; i < 8; i++) {
703 codec->guid.f4[i]=strtoul(token[i + 3],&endptr,0);
704 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
705 *endptr != '\0')
706 goto err_out_parse_error;
708 } else if (!strcmp(token[0], "out")) {
709 if (get_token(1, 2) < 0)
710 goto err_out_parse_error;
711 if (!add_to_inout(token[0], token[1], codec->outfmt,
712 codec->outflags))
713 goto err_out_print_linenum;
714 } else if (!strcmp(token[0], "in")) {
715 if (get_token(1, 2) < 0)
716 goto err_out_parse_error;
717 if (!add_to_inout(token[0], token[1], codec->infmt,
718 codec->inflags))
719 goto err_out_print_linenum;
720 } else if (!strcmp(token[0], "flags")) {
721 if (get_token(1, 1) < 0)
722 goto err_out_parse_error;
723 if (!strcmp(token[0], "seekable"))
724 codec->flags |= CODECS_FLAG_SEEKABLE;
725 else if (!strcmp(token[0], "align16"))
726 codec->flags |= CODECS_FLAG_ALIGN16;
727 else
728 goto err_out_parse_error;
729 } else if (!strcmp(token[0], "status")) {
730 if (get_token(1, 1) < 0)
731 goto err_out_parse_error;
732 if (!strcasecmp(token[0], "working"))
733 codec->status = CODECS_STATUS_WORKING;
734 else if (!strcasecmp(token[0], "crashing"))
735 codec->status = CODECS_STATUS_NOT_WORKING;
736 else if (!strcasecmp(token[0], "untested"))
737 codec->status = CODECS_STATUS_UNTESTED;
738 else if (!strcasecmp(token[0], "buggy"))
739 codec->status = CODECS_STATUS_PROBLEMS;
740 else
741 goto err_out_parse_error;
742 } else if (!strcmp(token[0], "cpuflags")) {
743 if (get_token(1, 1) < 0)
744 goto err_out_parse_error;
745 if (!(codec->cpuflags = get_cpuflags(token[0])))
746 goto err_out_parse_error;
747 } else
748 goto err_out_parse_error;
750 if (!validate_codec(codec, codec_type))
751 goto err_out_not_valid;
752 mp_tmsg(MSGT_CODECCFG,MSGL_INFO,"%d audio & %d video codecs\n", nr_acodecs, nr_vcodecs);
753 if(video_codecs) video_codecs[nr_vcodecs].name = NULL;
754 if(audio_codecs) audio_codecs[nr_acodecs].name = NULL;
755 out:
756 free(line);
757 line=NULL;
758 fclose(fp);
759 return 1;
761 err_out_parse_error:
762 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
763 err_out_print_linenum:
764 PRINT_LINENUM;
765 err_out:
766 codecs_uninit_free();
768 free(line);
769 line=NULL;
770 line_num = 0;
771 fclose(fp);
772 return 0;
773 err_out_not_valid:
774 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Codec is not defined correctly.");
775 goto err_out_print_linenum;
776 err_out_release_num:
777 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"This codecs.conf is too old and incompatible with this MPlayer release!");
778 goto err_out_print_linenum;
781 static void codecs_free(codecs_t* codecs,int count) {
782 int i;
783 for ( i = 0; i < count; i++)
784 if ( codecs[i].name ) {
785 free(codecs[i].name);
786 free(codecs[i].info);
787 free(codecs[i].comment);
788 free(codecs[i].dll);
789 free(codecs[i].drv);
791 free(codecs);
794 void codecs_uninit_free(void) {
795 if (video_codecs)
796 codecs_free(video_codecs,nr_vcodecs);
797 video_codecs=NULL;
798 if (audio_codecs)
799 codecs_free(audio_codecs,nr_acodecs);
800 audio_codecs=NULL;
803 codecs_t *find_audio_codec(unsigned int fourcc, unsigned int *fourccmap,
804 codecs_t *start, int force)
806 return find_codec(fourcc, fourccmap, start, 1, force);
809 codecs_t *find_video_codec(unsigned int fourcc, unsigned int *fourccmap,
810 codecs_t *start, int force)
812 return find_codec(fourcc, fourccmap, start, 0, force);
815 codecs_t* find_codec(unsigned int fourcc,unsigned int *fourccmap,
816 codecs_t *start, int audioflag, int force)
818 int i, j;
819 codecs_t *c;
821 #if 0
822 if (start) {
823 for (/* NOTHING */; start->name; start++) {
824 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
825 if (start->fourcc[j] == fourcc) {
826 if (fourccmap)
827 *fourccmap = start->fourccmap[j];
828 return start;
832 } else
833 #endif
835 if (audioflag) {
836 i = nr_acodecs;
837 c = audio_codecs;
838 } else {
839 i = nr_vcodecs;
840 c = video_codecs;
842 if(!i) return NULL;
843 for (/* NOTHING */; i--; c++) {
844 if(start && c<=start) continue;
845 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
846 // FIXME: do NOT hardwire 'null' name here:
847 if (c->fourcc[j]==fourcc || !strcmp(c->drv,"null")) {
848 if (fourccmap)
849 *fourccmap = c->fourccmap[j];
850 return c;
853 if (force) return c;
856 return NULL;
859 void stringset_init(stringset_t *set) {
860 *set = calloc(1, sizeof(char *));
863 void stringset_free(stringset_t *set) {
864 int count = 0;
865 while ((*set)[count]) free((*set)[count++]);
866 free(*set);
867 *set = NULL;
870 void stringset_add(stringset_t *set, const char *str) {
871 int count = 0;
872 while ((*set)[count]) count++;
873 count++;
874 *set = realloc(*set, sizeof(char *) * (count + 1));
875 (*set)[count - 1] = strdup(str);
876 (*set)[count] = NULL;
879 int stringset_test(stringset_t *set, const char *str) {
880 stringset_t s;
881 for (s = *set; *s; s++)
882 if (strcmp(*s, str) == 0)
883 return 1;
884 return 0;
887 void list_codecs(int audioflag){
888 int i;
889 codecs_t *c;
891 if (audioflag) {
892 i = nr_acodecs;
893 c = audio_codecs;
894 mp_msg(MSGT_CODECCFG,MSGL_INFO,"ac: afm: status: info: [lib/dll]\n");
895 } else {
896 i = nr_vcodecs;
897 c = video_codecs;
898 mp_msg(MSGT_CODECCFG,MSGL_INFO,"vc: vfm: status: info: [lib/dll]\n");
900 if(!i) return;
901 for (/* NOTHING */; i--; c++) {
902 char* s="unknown ";
903 switch(c->status){
904 case CODECS_STATUS_WORKING: s="working ";break;
905 case CODECS_STATUS_PROBLEMS: s="problems";break;
906 case CODECS_STATUS_NOT_WORKING: s="crashing";break;
907 case CODECS_STATUS_UNTESTED: s="untested";break;
909 if(c->dll)
910 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s [%s]\n",c->name,c->drv,s,c->info,c->dll);
911 else
912 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s\n",c->name,c->drv,s,c->info);
917 #ifdef CODECS2HTML
918 static void wrapline(FILE *f2,char *s){
919 int c;
920 if(!s){
921 fprintf(f2,"-");
922 return;
924 while((c=*s++)){
925 if(c==',') fprintf(f2,"<br>"); else fputc(c,f2);
929 static void parsehtml(FILE *f1,FILE *f2,codecs_t *codec){
930 int c,d;
931 while((c=fgetc(f1))>=0){
932 if(c!='%'){
933 fputc(c,f2);
934 continue;
936 d=fgetc(f1);
938 switch(d){
939 case '.':
940 return; // end of section
941 case 'n':
942 wrapline(f2,codec->name); break;
943 case 'i':
944 wrapline(f2,codec->info); break;
945 case 'c':
946 wrapline(f2,codec->comment); break;
947 case 'd':
948 wrapline(f2,codec->dll); break;
949 case 'D':
950 fprintf(f2,"%c",!strcmp(codec->drv,"dshow")?'+':'-'); break;
951 case 'F':
952 for(d=0;d<CODECS_MAX_FOURCC;d++)
953 if(!d || codec->fourcc[d]!=0xFFFFFFFF)
954 fprintf(f2,"%s%.4s",d?"<br>":"",(codec->fourcc[d]==0xFFFFFFFF || codec->fourcc[d]<0x20202020)?!d?"-":"":(char*) &codec->fourcc[d]);
955 break;
956 case 'f':
957 for(d=0;d<CODECS_MAX_FOURCC;d++)
958 if(codec->fourcc[d]!=0xFFFFFFFF)
959 fprintf(f2,"%s0x%X",d?"<br>":"",codec->fourcc[d]);
960 break;
961 case 'Y':
962 for(d=0;d<CODECS_MAX_OUTFMT;d++)
963 if(codec->outfmt[d]!=0xFFFFFFFF){
964 for (c=0; fmt_table[c].name; c++)
965 if(fmt_table[c].num==codec->outfmt[d]) break;
966 if(fmt_table[c].name)
967 fprintf(f2,"%s%s",d?"<br>":"",fmt_table[c].name);
969 break;
970 default:
971 fputc(c,f2);
972 fputc(d,f2);
977 void skiphtml(FILE *f1){
978 int c,d;
979 while((c=fgetc(f1))>=0){
980 if(c!='%'){
981 continue;
983 d=fgetc(f1);
984 if(d=='.') return; // end of section
988 static void print_int_array(const unsigned int* a, int size)
990 printf("{ ");
991 while (size--)
992 if(abs(*a)<256)
993 printf("%d%s", *a++, size?", ":"");
994 else
995 printf("0x%X%s", *a++, size?", ":"");
996 printf(" }");
999 static void print_char_array(const unsigned char* a, int size)
1001 printf("{ ");
1002 while (size--)
1003 if((*a)<10)
1004 printf("%d%s", *a++, size?", ":"");
1005 else
1006 printf("0x%02x%s", *a++, size?", ":"");
1007 printf(" }");
1010 static void print_string(const char* s)
1012 if (!s) printf("NULL");
1013 else printf("\"%s\"", s);
1016 int main(int argc, char* argv[])
1018 codecs_t *cl;
1019 FILE *f1;
1020 FILE *f2;
1021 int c,d,i;
1022 int pos;
1023 int section=-1;
1024 int nr_codecs;
1025 int win32=-1;
1026 int dshow=-1;
1027 int win32ex=-1;
1030 * Take path to codecs.conf from command line, or fall back on
1031 * etc/codecs.conf
1033 if (!(nr_codecs = parse_codec_cfg((argc>1)?argv[1]:"etc/codecs.conf")))
1034 exit(1);
1035 if (codecs_conf_release < CODEC_CFG_MIN)
1036 exit(1);
1038 if (argc > 1) {
1039 int i, j;
1040 const char* nm[2];
1041 codecs_t* cod[2];
1042 int nr[2];
1044 nm[0] = "builtin_video_codecs";
1045 cod[0] = video_codecs;
1046 nr[0] = nr_vcodecs;
1048 nm[1] = "builtin_audio_codecs";
1049 cod[1] = audio_codecs;
1050 nr[1] = nr_acodecs;
1052 printf("/* GENERATED FROM %s, DO NOT EDIT! */\n\n",argv[1]);
1053 printf("#include <stddef.h>\n");
1054 printf("#include \"codec-cfg.h\"\n\n");
1055 printf("#define CODEC_CFG_MIN %i\n\n", codecs_conf_release);
1057 for (i=0; i<2; i++) {
1058 printf("const codecs_t %s[] = {\n", nm[i]);
1059 for (j = 0; j < nr[i]; j++) {
1060 printf("{");
1062 print_int_array(cod[i][j].fourcc, CODECS_MAX_FOURCC);
1063 printf(", /* fourcc */\n");
1065 print_int_array(cod[i][j].fourccmap, CODECS_MAX_FOURCC);
1066 printf(", /* fourccmap */\n");
1068 print_int_array(cod[i][j].outfmt, CODECS_MAX_OUTFMT);
1069 printf(", /* outfmt */\n");
1071 print_char_array(cod[i][j].outflags, CODECS_MAX_OUTFMT);
1072 printf(", /* outflags */\n");
1074 print_int_array(cod[i][j].infmt, CODECS_MAX_INFMT);
1075 printf(", /* infmt */\n");
1077 print_char_array(cod[i][j].inflags, CODECS_MAX_INFMT);
1078 printf(", /* inflags */\n");
1080 print_string(cod[i][j].name); printf(", /* name */\n");
1081 print_string(cod[i][j].info); printf(", /* info */\n");
1082 print_string(cod[i][j].comment); printf(", /* comment */\n");
1083 print_string(cod[i][j].dll); printf(", /* dll */\n");
1084 print_string(cod[i][j].drv); printf(", /* drv */\n");
1086 printf("{ 0x%08lx, %hu, %hu,",
1087 cod[i][j].guid.f1,
1088 cod[i][j].guid.f2,
1089 cod[i][j].guid.f3);
1090 print_char_array(cod[i][j].guid.f4, sizeof(cod[i][j].guid.f4));
1091 printf(" }, /* GUID */\n");
1092 printf("%hd /* flags */, %hd /* status */, %hd /* cpuflags */ }\n",
1093 cod[i][j].flags,
1094 cod[i][j].status,
1095 cod[i][j].cpuflags);
1096 if (j < nr[i]) printf(",\n");
1098 printf("};\n\n");
1100 exit(0);
1103 f1=fopen("DOCS/tech/codecs-in.html","rb"); if(!f1) exit(1);
1104 f2=fopen("DOCS/codecs-status.html","wb"); if(!f2) exit(1);
1106 while((c=fgetc(f1))>=0){
1107 if(c!='%'){
1108 fputc(c,f2);
1109 continue;
1111 d=fgetc(f1);
1112 if(d>='0' && d<='9'){
1113 // begin section
1114 section=d-'0';
1115 //printf("BEGIN %d\n",section);
1116 if(section>=5){
1117 // audio
1118 cl = audio_codecs;
1119 nr_codecs = nr_acodecs;
1120 dshow=7;win32=4;
1121 } else {
1122 // video
1123 cl = video_codecs;
1124 nr_codecs = nr_vcodecs;
1125 dshow=4;win32=2;win32ex=6;
1127 pos=ftell(f1);
1128 for(i=0;i<nr_codecs;i++){
1129 fseek(f1,pos,SEEK_SET);
1130 switch(section){
1131 case 0:
1132 case 5:
1133 if(cl[i].status==CODECS_STATUS_WORKING)
1134 // if(!(!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1135 parsehtml(f1,f2,&cl[i]);
1136 break;
1137 #if 0
1138 case 1:
1139 case 6:
1140 if(cl[i].status==CODECS_STATUS_WORKING)
1141 if((!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1142 parsehtml(f1,f2,&cl[i]);
1143 break;
1144 #endif
1145 case 2:
1146 case 7:
1147 if(cl[i].status==CODECS_STATUS_PROBLEMS)
1148 parsehtml(f1,f2,&cl[i]);
1149 break;
1150 case 3:
1151 case 8:
1152 if(cl[i].status==CODECS_STATUS_NOT_WORKING)
1153 parsehtml(f1,f2,&cl[i]);
1154 break;
1155 case 4:
1156 case 9:
1157 if(cl[i].status==CODECS_STATUS_UNTESTED)
1158 parsehtml(f1,f2,&cl[i]);
1159 break;
1160 default:
1161 printf("Warning! unimplemented section: %d\n",section);
1164 fseek(f1,pos,SEEK_SET);
1165 skiphtml(f1);
1167 continue;
1169 fputc(c,f2);
1170 fputc(d,f2);
1173 fclose(f2);
1174 fclose(f1);
1175 return 0;
1178 #endif
1180 #ifdef TESTING
1181 int main(void)
1183 codecs_t *c;
1184 int i,j, nr_codecs, state;
1186 if (!(parse_codec_cfg("etc/codecs.conf")))
1187 return 0;
1188 if (!video_codecs)
1189 printf("no videoconfig.\n");
1190 if (!audio_codecs)
1191 printf("no audioconfig.\n");
1193 printf("videocodecs:\n");
1194 c = video_codecs;
1195 nr_codecs = nr_vcodecs;
1196 state = 0;
1197 next:
1198 if (c) {
1199 printf("number of %scodecs: %d\n", state==0?"video":"audio",
1200 nr_codecs);
1201 for(i=0;i<nr_codecs;i++, c++){
1202 printf("\n============== %scodec %02d ===============\n",
1203 state==0?"video":"audio",i);
1204 printf("name='%s'\n",c->name);
1205 printf("info='%s'\n",c->info);
1206 printf("comment='%s'\n",c->comment);
1207 printf("dll='%s'\n",c->dll);
1208 /* printf("flags=%X driver=%d status=%d cpuflags=%d\n",
1209 c->flags, c->driver, c->status, c->cpuflags); */
1210 printf("flags=%X status=%d cpuflags=%d\n",
1211 c->flags, c->status, c->cpuflags);
1213 for(j=0;j<CODECS_MAX_FOURCC;j++){
1214 if(c->fourcc[j]!=0xFFFFFFFF){
1215 printf("fourcc %02d: %08X (%.4s) ===> %08X (%.4s)\n",j,c->fourcc[j],(char *) &c->fourcc[j],c->fourccmap[j],(char *) &c->fourccmap[j]);
1219 for(j=0;j<CODECS_MAX_OUTFMT;j++){
1220 if(c->outfmt[j]!=0xFFFFFFFF){
1221 printf("outfmt %02d: %08X (%.4s) flags: %d\n",j,c->outfmt[j],(char *) &c->outfmt[j],c->outflags[j]);
1225 for(j=0;j<CODECS_MAX_INFMT;j++){
1226 if(c->infmt[j]!=0xFFFFFFFF){
1227 printf("infmt %02d: %08X (%.4s) flags: %d\n",j,c->infmt[j],(char *) &c->infmt[j],c->inflags[j]);
1231 printf("GUID: %08lX %04X %04X",c->guid.f1,c->guid.f2,c->guid.f3);
1232 for(j=0;j<8;j++) printf(" %02X",c->guid.f4[j]);
1233 printf("\n");
1238 if (!state) {
1239 printf("audiocodecs:\n");
1240 c = audio_codecs;
1241 nr_codecs = nr_acodecs;
1242 state = 1;
1243 goto next;
1245 return 0;
1248 #endif