Merge svn changes up to r31189
[mplayer/glamo.git] / codec-cfg.c
blob168529fd8c73d860206064ab7713253e4dacb2ab
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 #ifndef CODECS2HTML
61 #include "codecs.conf.h"
62 #endif
64 #define mmioFOURCC( ch0, ch1, ch2, ch3 ) \
65 ( (uint32_t)(uint8_t)(ch0) | ( (uint32_t)(uint8_t)(ch1) << 8 ) | \
66 ( (uint32_t)(uint8_t)(ch2) << 16 ) | ( (uint32_t)(uint8_t)(ch3) << 24 ) )
68 #define PRINT_LINENUM mp_msg(MSGT_CODECCFG,MSGL_ERR," at line %d\n", line_num)
70 #define MAX_NR_TOKEN 16
72 #define MAX_LINE_LEN 1000
74 #define RET_EOF -1
75 #define RET_EOL -2
77 #define TYPE_VIDEO 0
78 #define TYPE_AUDIO 1
80 char * codecs_file = NULL;
82 static int add_to_fourcc(char *s, char *alias, unsigned int *fourcc,
83 unsigned int *map)
85 int i, j, freeslots;
86 unsigned int tmp;
88 /* find first unused slot */
89 for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++)
90 /* NOTHING */;
91 freeslots = CODECS_MAX_FOURCC - i;
92 if (!freeslots)
93 goto err_out_too_many;
95 do {
96 tmp = mmioFOURCC(s[0], s[1], s[2], s[3]);
97 for (j = 0; j < i; j++)
98 if (tmp == fourcc[j])
99 goto err_out_duplicated;
100 fourcc[i] = tmp;
101 map[i] = alias ? mmioFOURCC(alias[0], alias[1], alias[2], alias[3]) : tmp;
102 s += 4;
103 i++;
104 } while ((*(s++) == ',') && --freeslots);
106 if (!freeslots)
107 goto err_out_too_many;
108 if (*(--s) != '\0')
109 goto err_out_parse_error;
110 return 1;
111 err_out_duplicated:
112 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"duplicated FourCC");
113 return 0;
114 err_out_too_many:
115 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"too many FourCCs/formats...");
116 return 0;
117 err_out_parse_error:
118 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
119 return 0;
122 static int add_to_format(char *s, char *alias,unsigned int *fourcc, unsigned int *fourccmap)
124 int i, j;
125 char *endptr;
127 /* find first unused slot */
128 for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++)
129 /* NOTHING */;
130 if (i == CODECS_MAX_FOURCC) {
131 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"too many FourCCs/formats...");
132 return 0;
135 fourcc[i]=strtoul(s,&endptr,0);
136 if (*endptr != '\0') {
137 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error (format ID not a number?)");
138 return 0;
141 if(alias){
142 fourccmap[i]=strtoul(alias,&endptr,0);
143 if (*endptr != '\0') {
144 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error (format ID alias not a number?)");
145 return 0;
147 } else
148 fourccmap[i]=fourcc[i];
150 for (j = 0; j < i; j++)
151 if (fourcc[j] == fourcc[i]) {
152 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"duplicated format ID");
153 return 0;
156 return 1;
159 static const struct {
160 const char *name;
161 const unsigned int num;
162 } fmt_table[] = {
163 // note: due to parser deficiencies/simplicity, if one format
164 // name matches the beginning of another, the longer one _must_
165 // come first in this list.
166 {"YV12", IMGFMT_YV12},
167 {"I420", IMGFMT_I420},
168 {"IYUV", IMGFMT_IYUV},
169 {"NV12", IMGFMT_NV12},
170 {"NV21", IMGFMT_NV21},
171 {"YVU9", IMGFMT_YVU9},
172 {"IF09", IMGFMT_IF09},
173 {"444P16LE", IMGFMT_444P16_LE},
174 {"444P16BE", IMGFMT_444P16_BE},
175 {"422P16LE", IMGFMT_422P16_LE},
176 {"422P16BE", IMGFMT_422P16_BE},
177 {"420P16LE", IMGFMT_420P16_LE},
178 {"420P16BE", IMGFMT_420P16_BE},
179 {"444P16", IMGFMT_444P16},
180 {"422P16", IMGFMT_422P16},
181 {"420P16", IMGFMT_420P16},
182 {"420A", IMGFMT_420A},
183 {"444P", IMGFMT_444P},
184 {"422P", IMGFMT_422P},
185 {"411P", IMGFMT_411P},
186 {"440P", IMGFMT_440P},
187 {"Y800", IMGFMT_Y800},
188 {"Y8", IMGFMT_Y8},
190 {"YUY2", IMGFMT_YUY2},
191 {"UYVY", IMGFMT_UYVY},
192 {"YVYU", IMGFMT_YVYU},
194 {"RGB48LE", IMGFMT_RGB48LE},
195 {"RGB48BE", IMGFMT_RGB48BE},
196 {"RGB4", IMGFMT_RGB4},
197 {"RGB8", IMGFMT_RGB8},
198 {"RGB15", IMGFMT_RGB15},
199 {"RGB16", IMGFMT_RGB16},
200 {"RGB24", IMGFMT_RGB24},
201 {"RGB32", IMGFMT_RGB32},
202 {"BGR4", IMGFMT_BGR4},
203 {"BGR8", IMGFMT_BGR8},
204 {"BGR15", IMGFMT_BGR15},
205 {"BGR16", IMGFMT_BGR16},
206 {"BGR24", IMGFMT_BGR24},
207 {"BGR32", IMGFMT_BGR32},
208 {"RGB1", IMGFMT_RGB1},
209 {"BGR1", IMGFMT_BGR1},
211 {"MPES", IMGFMT_MPEGPES},
212 {"ZRMJPEGNI", IMGFMT_ZRMJPEGNI},
213 {"ZRMJPEGIT", IMGFMT_ZRMJPEGIT},
214 {"ZRMJPEGIB", IMGFMT_ZRMJPEGIB},
216 {"IDCT_MPEG2",IMGFMT_XVMC_IDCT_MPEG2},
217 {"MOCO_MPEG2",IMGFMT_XVMC_MOCO_MPEG2},
219 {"VDPAU_MPEG1",IMGFMT_VDPAU_MPEG1},
220 {"VDPAU_MPEG2",IMGFMT_VDPAU_MPEG2},
221 {"VDPAU_H264",IMGFMT_VDPAU_H264},
222 {"VDPAU_WMV3",IMGFMT_VDPAU_WMV3},
223 {"VDPAU_VC1",IMGFMT_VDPAU_VC1},
224 {"VDPAU_MPEG4",IMGFMT_VDPAU_MPEG4},
226 {NULL, 0}
230 static int add_to_inout(char *sfmt, char *sflags, unsigned int *outfmt,
231 unsigned char *outflags)
234 static char *flagstr[] = {
235 "flip",
236 "noflip",
237 "yuvhack",
238 "query",
239 "static",
240 NULL
243 int i, j, freeslots;
244 unsigned char flags;
246 for (i = 0; i < CODECS_MAX_OUTFMT && outfmt[i] != 0xffffffff; i++)
247 /* NOTHING */;
248 freeslots = CODECS_MAX_OUTFMT - i;
249 if (!freeslots)
250 goto err_out_too_many;
252 flags = 0;
253 if(sflags) {
254 do {
255 for (j = 0; flagstr[j] != NULL; j++)
256 if (!strncmp(sflags, flagstr[j],
257 strlen(flagstr[j])))
258 break;
259 if (flagstr[j] == NULL)
260 goto err_out_parse_error;
261 flags|=(1<<j);
262 sflags+=strlen(flagstr[j]);
263 } while (*(sflags++) == ',');
265 if (*(--sflags) != '\0')
266 goto err_out_parse_error;
269 do {
270 for (j = 0; fmt_table[j].name != NULL; j++)
271 if (!strncmp(sfmt, fmt_table[j].name, strlen(fmt_table[j].name)))
272 break;
273 if (fmt_table[j].name == NULL)
274 goto err_out_parse_error;
275 outfmt[i] = fmt_table[j].num;
276 outflags[i] = flags;
277 ++i;
278 sfmt+=strlen(fmt_table[j].name);
279 } while ((*(sfmt++) == ',') && --freeslots);
281 if (!freeslots)
282 goto err_out_too_many;
284 if (*(--sfmt) != '\0')
285 goto err_out_parse_error;
287 return 1;
288 err_out_too_many:
289 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"too many out...");
290 return 0;
291 err_out_parse_error:
292 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
293 return 0;
296 #if 0
297 static short get_driver(char *s,int audioflag)
299 static char *audiodrv[] = {
300 "null",
301 "mp3lib",
302 "pcm",
303 "libac3",
304 "acm",
305 "alaw",
306 "msgsm",
307 "dshow",
308 "dvdpcm",
309 "hwac3",
310 "libvorbis",
311 "ffmpeg",
312 "libmad",
313 "msadpcm",
314 "liba52",
315 "g72x",
316 "imaadpcm",
317 "dk4adpcm",
318 "dk3adpcm",
319 "roqaudio",
320 "faad",
321 "realaud",
322 "libdv",
323 NULL
325 static char *videodrv[] = {
326 "null",
327 "libmpeg2",
328 "vfw",
329 "dshow",
330 "ffmpeg",
331 "vfwex",
332 "raw",
333 "msrle",
334 "xanim",
335 "msvidc",
336 "fli",
337 "cinepak",
338 "qtrle",
339 "nuv",
340 "cyuv",
341 "qtsmc",
342 "ducktm1",
343 "roqvideo",
344 "qtrpza",
345 "mpng",
346 "ijpg",
347 "zlib",
348 "mpegpes",
349 "zrmjpeg",
350 "realvid",
351 "xvid",
352 "libdv",
353 NULL
355 char **drv=audioflag?audiodrv:videodrv;
356 int i;
358 for(i=0;drv[i];i++) if(!strcmp(s,drv[i])) return i;
360 return -1;
362 #endif
364 static int validate_codec(codecs_t *c, int type)
366 unsigned int i;
367 char *tmp_name = c->name;
369 for (i = 0; i < strlen(tmp_name) && isalnum(tmp_name[i]); i++)
370 /* NOTHING */;
372 if (i < strlen(tmp_name)) {
373 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) name is not valid!\n", c->name);
374 return 0;
377 if (!c->info)
378 c->info = strdup(c->name);
380 #if 0
381 if (c->fourcc[0] == 0xffffffff) {
382 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) does not have FourCC/format!\n", c->name);
383 return 0;
385 #endif
387 if (!c->drv) {
388 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) does not have a driver!\n", c->name);
389 return 0;
392 #if 0
393 #warning codec->driver == 4;... <- this should not be put in here...
394 #warning Where are they defined ????????????
395 if (!c->dll && (c->driver == 4 ||
396 (c->driver == 2 && type == TYPE_VIDEO))) {
397 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) needs a 'dll'!\n", c->name);
398 return 0;
400 #warning Can guid.f1 be 0? How does one know that it was not given?
401 // if (!(codec->flags & CODECS_FLAG_AUDIO) && codec->driver == 4)
403 if (type == TYPE_VIDEO)
404 if (c->outfmt[0] == 0xffffffff) {
405 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) needs an 'outfmt'!\n", c->name);
406 return 0;
408 #endif
409 return 1;
412 static int add_comment(char *s, char **d)
414 int pos;
416 if (!*d)
417 pos = 0;
418 else {
419 pos = strlen(*d);
420 (*d)[pos++] = '\n';
422 if (!(*d = realloc(*d, pos + strlen(s) + 1))) {
423 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't allocate memory for comment. ");
424 return 0;
426 strcpy(*d + pos, s);
427 return 1;
430 static short get_cpuflags(char *s)
432 static char *flagstr[] = {
433 "mmx",
434 "sse",
435 "3dnow",
436 NULL
438 int i;
439 short flags = 0;
441 do {
442 for (i = 0; flagstr[i]; i++)
443 if (!strncmp(s, flagstr[i], strlen(flagstr[i])))
444 break;
445 if (!flagstr[i])
446 goto err_out_parse_error;
447 flags |= 1<<i;
448 s += strlen(flagstr[i]);
449 } while (*(s++) == ',');
451 if (*(--s) != '\0')
452 goto err_out_parse_error;
454 return flags;
455 err_out_parse_error:
456 return 0;
459 static FILE *fp;
460 static int line_num = 0;
461 static char *line;
462 static char *token[MAX_NR_TOKEN];
463 static int read_nextline = 1;
465 static int get_token(int min, int max)
467 static int line_pos;
468 int i;
469 char c;
471 if (max >= MAX_NR_TOKEN) {
472 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"get_token(): max >= MAX_MR_TOKEN!");
473 goto out_eof;
476 memset(token, 0x00, sizeof(*token) * max);
478 if (read_nextline) {
479 if (!fgets(line, MAX_LINE_LEN, fp))
480 goto out_eof;
481 line_pos = 0;
482 ++line_num;
483 read_nextline = 0;
485 for (i = 0; i < max; i++) {
486 while (isspace(line[line_pos]))
487 ++line_pos;
488 if (line[line_pos] == '\0' || line[line_pos] == '#' ||
489 line[line_pos] == ';') {
490 read_nextline = 1;
491 if (i >= min)
492 goto out_ok;
493 goto out_eol;
495 token[i] = line + line_pos;
496 c = line[line_pos];
497 if (c == '"' || c == '\'') {
498 token[i]++;
499 while (line[++line_pos] != c && line[line_pos])
500 /* NOTHING */;
501 } else {
502 for (/* NOTHING */; !isspace(line[line_pos]) &&
503 line[line_pos]; line_pos++)
504 /* NOTHING */;
506 if (!line[line_pos]) {
507 read_nextline = 1;
508 if (i >= min - 1)
509 goto out_ok;
510 goto out_eol;
512 line[line_pos] = '\0';
513 line_pos++;
515 out_ok:
516 return i;
517 out_eof:
518 read_nextline = 1;
519 return RET_EOF;
520 out_eol:
521 return RET_EOL;
524 static codecs_t *video_codecs=NULL;
525 static codecs_t *audio_codecs=NULL;
526 static int nr_vcodecs = 0;
527 static int nr_acodecs = 0;
529 int parse_codec_cfg(const char *cfgfile)
531 codecs_t *codec = NULL; // current codec
532 codecs_t **codecsp = NULL;// points to audio_codecs or to video_codecs
533 char *endptr; // strtoul()...
534 int *nr_codecsp;
535 int codec_type; /* TYPE_VIDEO/TYPE_AUDIO */
536 int tmp, i;
538 // in case we call it a second time
539 codecs_uninit_free();
541 nr_vcodecs = 0;
542 nr_acodecs = 0;
544 if(cfgfile==NULL) {
545 #ifdef CODECS2HTML
546 return 0;
547 #else
548 video_codecs = builtin_video_codecs;
549 audio_codecs = builtin_audio_codecs;
550 nr_vcodecs = sizeof(builtin_video_codecs)/sizeof(codecs_t);
551 nr_acodecs = sizeof(builtin_audio_codecs)/sizeof(codecs_t);
552 return 1;
553 #endif
556 mp_tmsg(MSGT_CODECCFG,MSGL_V,"Reading %s: ", cfgfile);
558 if ((fp = fopen(cfgfile, "r")) == NULL) {
559 mp_tmsg(MSGT_CODECCFG,MSGL_V,"Can't open '%s': %s\n", cfgfile, strerror(errno));
560 return 0;
563 if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) {
564 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't get memory for 'line': %s\n", strerror(errno));
565 return 0;
567 read_nextline = 1;
570 * this only catches release lines at the start of
571 * codecs.conf, before audiocodecs and videocodecs.
573 while ((tmp = get_token(1, 1)) == RET_EOL)
574 /* NOTHING */;
575 if (tmp == RET_EOF)
576 goto out;
577 if (!strcmp(token[0], "release")) {
578 if (get_token(1, 2) < 0)
579 goto err_out_parse_error;
580 tmp = atoi(token[0]);
581 if (tmp < CODEC_CFG_MIN)
582 goto err_out_release_num;
583 while ((tmp = get_token(1, 1)) == RET_EOL)
584 /* NOTHING */;
585 if (tmp == RET_EOF)
586 goto out;
587 } else
588 goto err_out_release_num;
591 * check if the next block starts with 'audiocodec' or
592 * with 'videocodec'
594 if (!strcmp(token[0], "audiocodec") || !strcmp(token[0], "videocodec"))
595 goto loop_enter;
596 goto err_out_parse_error;
598 while ((tmp = get_token(1, 1)) != RET_EOF) {
599 if (tmp == RET_EOL)
600 continue;
601 if (!strcmp(token[0], "audiocodec") ||
602 !strcmp(token[0], "videocodec")) {
603 if (!validate_codec(codec, codec_type))
604 goto err_out_not_valid;
605 loop_enter:
606 if (*token[0] == 'v') {
607 codec_type = TYPE_VIDEO;
608 nr_codecsp = &nr_vcodecs;
609 codecsp = &video_codecs;
610 } else if (*token[0] == 'a') {
611 codec_type = TYPE_AUDIO;
612 nr_codecsp = &nr_acodecs;
613 codecsp = &audio_codecs;
614 #ifdef DEBUG
615 } else {
616 mp_msg(MSGT_CODECCFG,MSGL_ERR,"picsba\n");
617 goto err_out;
618 #endif
620 if (!(*codecsp = realloc(*codecsp,
621 sizeof(codecs_t) * (*nr_codecsp + 2)))) {
622 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't realloc '*codecsp': %s\n", strerror(errno));
623 goto err_out;
625 codec=*codecsp + *nr_codecsp;
626 ++*nr_codecsp;
627 memset(codec,0,sizeof(codecs_t));
628 memset(codec->fourcc, 0xff, sizeof(codec->fourcc));
629 memset(codec->outfmt, 0xff, sizeof(codec->outfmt));
630 memset(codec->infmt, 0xff, sizeof(codec->infmt));
632 if (get_token(1, 1) < 0)
633 goto err_out_parse_error;
634 for (i = 0; i < *nr_codecsp - 1; i++) {
635 if(( (*codecsp)[i].name!=NULL) &&
636 (!strcmp(token[0], (*codecsp)[i].name)) ) {
637 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Codec name '%s' isn't unique.", token[0]);
638 goto err_out_print_linenum;
641 if (!(codec->name = strdup(token[0]))) {
642 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'name': %s\n", strerror(errno));
643 goto err_out;
645 } else if (!strcmp(token[0], "info")) {
646 if (codec->info || get_token(1, 1) < 0)
647 goto err_out_parse_error;
648 if (!(codec->info = strdup(token[0]))) {
649 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'info': %s\n", strerror(errno));
650 goto err_out;
652 } else if (!strcmp(token[0], "comment")) {
653 if (get_token(1, 1) < 0)
654 goto err_out_parse_error;
655 add_comment(token[0], &codec->comment);
656 } else if (!strcmp(token[0], "fourcc")) {
657 if (get_token(1, 2) < 0)
658 goto err_out_parse_error;
659 if (!add_to_fourcc(token[0], token[1],
660 codec->fourcc,
661 codec->fourccmap))
662 goto err_out_print_linenum;
663 } else if (!strcmp(token[0], "format")) {
664 if (get_token(1, 2) < 0)
665 goto err_out_parse_error;
666 if (!add_to_format(token[0], token[1],
667 codec->fourcc,codec->fourccmap))
668 goto err_out_print_linenum;
669 } else if (!strcmp(token[0], "driver")) {
670 if (get_token(1, 1) < 0)
671 goto err_out_parse_error;
672 if (!(codec->drv = strdup(token[0]))) {
673 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'driver': %s\n", strerror(errno));
674 goto err_out;
676 } else if (!strcmp(token[0], "dll")) {
677 if (get_token(1, 1) < 0)
678 goto err_out_parse_error;
679 if (!(codec->dll = strdup(token[0]))) {
680 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'dll': %s", strerror(errno));
681 goto err_out;
683 } else if (!strcmp(token[0], "guid")) {
684 if (get_token(11, 11) < 0)
685 goto err_out_parse_error;
686 codec->guid.f1=strtoul(token[0],&endptr,0);
687 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
688 *endptr != '\0')
689 goto err_out_parse_error;
690 codec->guid.f2=strtoul(token[1],&endptr,0);
691 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
692 *endptr != '\0')
693 goto err_out_parse_error;
694 codec->guid.f3=strtoul(token[2],&endptr,0);
695 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
696 *endptr != '\0')
697 goto err_out_parse_error;
698 for (i = 0; i < 8; i++) {
699 codec->guid.f4[i]=strtoul(token[i + 3],&endptr,0);
700 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
701 *endptr != '\0')
702 goto err_out_parse_error;
704 } else if (!strcmp(token[0], "out")) {
705 if (get_token(1, 2) < 0)
706 goto err_out_parse_error;
707 if (!add_to_inout(token[0], token[1], codec->outfmt,
708 codec->outflags))
709 goto err_out_print_linenum;
710 } else if (!strcmp(token[0], "in")) {
711 if (get_token(1, 2) < 0)
712 goto err_out_parse_error;
713 if (!add_to_inout(token[0], token[1], codec->infmt,
714 codec->inflags))
715 goto err_out_print_linenum;
716 } else if (!strcmp(token[0], "flags")) {
717 if (get_token(1, 1) < 0)
718 goto err_out_parse_error;
719 if (!strcmp(token[0], "seekable"))
720 codec->flags |= CODECS_FLAG_SEEKABLE;
721 else if (!strcmp(token[0], "align16"))
722 codec->flags |= CODECS_FLAG_ALIGN16;
723 else
724 goto err_out_parse_error;
725 } else if (!strcmp(token[0], "status")) {
726 if (get_token(1, 1) < 0)
727 goto err_out_parse_error;
728 if (!strcasecmp(token[0], "working"))
729 codec->status = CODECS_STATUS_WORKING;
730 else if (!strcasecmp(token[0], "crashing"))
731 codec->status = CODECS_STATUS_NOT_WORKING;
732 else if (!strcasecmp(token[0], "untested"))
733 codec->status = CODECS_STATUS_UNTESTED;
734 else if (!strcasecmp(token[0], "buggy"))
735 codec->status = CODECS_STATUS_PROBLEMS;
736 else
737 goto err_out_parse_error;
738 } else if (!strcmp(token[0], "cpuflags")) {
739 if (get_token(1, 1) < 0)
740 goto err_out_parse_error;
741 if (!(codec->cpuflags = get_cpuflags(token[0])))
742 goto err_out_parse_error;
743 } else
744 goto err_out_parse_error;
746 if (!validate_codec(codec, codec_type))
747 goto err_out_not_valid;
748 mp_tmsg(MSGT_CODECCFG,MSGL_INFO,"%d audio & %d video codecs\n", nr_acodecs, nr_vcodecs);
749 if(video_codecs) video_codecs[nr_vcodecs].name = NULL;
750 if(audio_codecs) audio_codecs[nr_acodecs].name = NULL;
751 out:
752 free(line);
753 line=NULL;
754 fclose(fp);
755 return 1;
757 err_out_parse_error:
758 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
759 err_out_print_linenum:
760 PRINT_LINENUM;
761 err_out:
762 codecs_uninit_free();
764 free(line);
765 line=NULL;
766 line_num = 0;
767 fclose(fp);
768 return 0;
769 err_out_not_valid:
770 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Codec is not defined correctly.");
771 goto err_out_print_linenum;
772 err_out_release_num:
773 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"This codecs.conf is too old and incompatible with this MPlayer release!");
774 goto err_out_print_linenum;
777 static void codecs_free(codecs_t* codecs,int count) {
778 int i;
779 for ( i = 0; i < count; i++)
780 if ( codecs[i].name ) {
781 if( codecs[i].name )
782 free(codecs[i].name);
783 if( codecs[i].info )
784 free(codecs[i].info);
785 if( codecs[i].comment )
786 free(codecs[i].comment);
787 if( codecs[i].dll )
788 free(codecs[i].dll);
789 if( codecs[i].drv )
790 free(codecs[i].drv);
792 if (codecs)
793 free(codecs);
796 void codecs_uninit_free(void) {
797 if (video_codecs)
798 codecs_free(video_codecs,nr_vcodecs);
799 video_codecs=NULL;
800 if (audio_codecs)
801 codecs_free(audio_codecs,nr_acodecs);
802 audio_codecs=NULL;
805 codecs_t *find_audio_codec(unsigned int fourcc, unsigned int *fourccmap,
806 codecs_t *start, int force)
808 return find_codec(fourcc, fourccmap, start, 1, force);
811 codecs_t *find_video_codec(unsigned int fourcc, unsigned int *fourccmap,
812 codecs_t *start, int force)
814 return find_codec(fourcc, fourccmap, start, 0, force);
817 codecs_t* find_codec(unsigned int fourcc,unsigned int *fourccmap,
818 codecs_t *start, int audioflag, int force)
820 int i, j;
821 codecs_t *c;
823 #if 0
824 if (start) {
825 for (/* NOTHING */; start->name; start++) {
826 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
827 if (start->fourcc[j] == fourcc) {
828 if (fourccmap)
829 *fourccmap = start->fourccmap[j];
830 return start;
834 } else
835 #endif
837 if (audioflag) {
838 i = nr_acodecs;
839 c = audio_codecs;
840 } else {
841 i = nr_vcodecs;
842 c = video_codecs;
844 if(!i) return NULL;
845 for (/* NOTHING */; i--; c++) {
846 if(start && c<=start) continue;
847 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
848 // FIXME: do NOT hardwire 'null' name here:
849 if (c->fourcc[j]==fourcc || !strcmp(c->drv,"null")) {
850 if (fourccmap)
851 *fourccmap = c->fourccmap[j];
852 return c;
855 if (force) return c;
858 return NULL;
861 void stringset_init(stringset_t *set) {
862 *set = calloc(1, sizeof(char *));
865 void stringset_free(stringset_t *set) {
866 int count = 0;
867 while ((*set)[count]) free((*set)[count++]);
868 free(*set);
869 *set = NULL;
872 void stringset_add(stringset_t *set, const char *str) {
873 int count = 0;
874 while ((*set)[count]) count++;
875 count++;
876 *set = realloc(*set, sizeof(char *) * (count + 1));
877 (*set)[count - 1] = strdup(str);
878 (*set)[count] = NULL;
881 int stringset_test(stringset_t *set, const char *str) {
882 stringset_t s;
883 for (s = *set; *s; s++)
884 if (strcmp(*s, str) == 0)
885 return 1;
886 return 0;
889 void list_codecs(int audioflag){
890 int i;
891 codecs_t *c;
893 if (audioflag) {
894 i = nr_acodecs;
895 c = audio_codecs;
896 mp_msg(MSGT_CODECCFG,MSGL_INFO,"ac: afm: status: info: [lib/dll]\n");
897 } else {
898 i = nr_vcodecs;
899 c = video_codecs;
900 mp_msg(MSGT_CODECCFG,MSGL_INFO,"vc: vfm: status: info: [lib/dll]\n");
902 if(!i) return;
903 for (/* NOTHING */; i--; c++) {
904 char* s="unknown ";
905 switch(c->status){
906 case CODECS_STATUS_WORKING: s="working ";break;
907 case CODECS_STATUS_PROBLEMS: s="problems";break;
908 case CODECS_STATUS_NOT_WORKING: s="crashing";break;
909 case CODECS_STATUS_UNTESTED: s="untested";break;
911 if(c->dll)
912 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s [%s]\n",c->name,c->drv,s,c->info,c->dll);
913 else
914 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s\n",c->name,c->drv,s,c->info);
919 #ifdef CODECS2HTML
920 void wrapline(FILE *f2,char *s){
921 int c;
922 if(!s){
923 fprintf(f2,"-");
924 return;
926 while((c=*s++)){
927 if(c==',') fprintf(f2,"<br>"); else fputc(c,f2);
931 void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
932 int c,d;
933 while((c=fgetc(f1))>=0){
934 if(c!='%'){
935 fputc(c,f2);
936 continue;
938 d=fgetc(f1);
940 switch(d){
941 case '.':
942 return; // end of section
943 case 'n':
944 wrapline(f2,codec->name); break;
945 case 'i':
946 wrapline(f2,codec->info); break;
947 case 'c':
948 wrapline(f2,codec->comment); break;
949 case 'd':
950 wrapline(f2,codec->dll); break;
951 case 'D':
952 fprintf(f2,"%c",!strcmp(codec->drv,"dshow")?'+':'-'); break;
953 case 'F':
954 for(d=0;d<CODECS_MAX_FOURCC;d++)
955 if(!d || codec->fourcc[d]!=0xFFFFFFFF)
956 fprintf(f2,"%s%.4s",d?"<br>":"",(codec->fourcc[d]==0xFFFFFFFF || codec->fourcc[d]<0x20202020)?!d?"-":"":(char*) &codec->fourcc[d]);
957 break;
958 case 'f':
959 for(d=0;d<CODECS_MAX_FOURCC;d++)
960 if(codec->fourcc[d]!=0xFFFFFFFF)
961 fprintf(f2,"%s0x%X",d?"<br>":"",codec->fourcc[d]);
962 break;
963 case 'Y':
964 for(d=0;d<CODECS_MAX_OUTFMT;d++)
965 if(codec->outfmt[d]!=0xFFFFFFFF){
966 for (c=0; fmt_table[c].name; c++)
967 if(fmt_table[c].num==codec->outfmt[d]) break;
968 if(fmt_table[c].name)
969 fprintf(f2,"%s%s",d?"<br>":"",fmt_table[c].name);
971 break;
972 default:
973 fputc(c,f2);
974 fputc(d,f2);
979 void skiphtml(FILE *f1){
980 int c,d;
981 while((c=fgetc(f1))>=0){
982 if(c!='%'){
983 continue;
985 d=fgetc(f1);
986 if(d=='.') return; // end of section
990 static void print_int_array(const unsigned int* a, int size)
992 printf("{ ");
993 while (size--)
994 if(abs(*a)<256)
995 printf("%d%s", *a++, size?", ":"");
996 else
997 printf("0x%X%s", *a++, size?", ":"");
998 printf(" }");
1001 static void print_char_array(const unsigned char* a, int size)
1003 printf("{ ");
1004 while (size--)
1005 if((*a)<10)
1006 printf("%d%s", *a++, size?", ":"");
1007 else
1008 printf("0x%02x%s", *a++, size?", ":"");
1009 printf(" }");
1012 static void print_string(const char* s)
1014 if (!s) printf("NULL");
1015 else printf("\"%s\"", s);
1018 int main(int argc, char* argv[])
1020 codecs_t *cl;
1021 FILE *f1;
1022 FILE *f2;
1023 int c,d,i;
1024 int pos;
1025 int section=-1;
1026 int nr_codecs;
1027 int win32=-1;
1028 int dshow=-1;
1029 int win32ex=-1;
1032 * Take path to codecs.conf from command line, or fall back on
1033 * etc/codecs.conf
1035 if (!(nr_codecs = parse_codec_cfg((argc>1)?argv[1]:"etc/codecs.conf")))
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");
1056 for (i=0; i<2; i++) {
1057 printf("const codecs_t %s[] = {\n", nm[i]);
1058 for (j = 0; j < nr[i]; j++) {
1059 printf("{");
1061 print_int_array(cod[i][j].fourcc, CODECS_MAX_FOURCC);
1062 printf(", /* fourcc */\n");
1064 print_int_array(cod[i][j].fourccmap, CODECS_MAX_FOURCC);
1065 printf(", /* fourccmap */\n");
1067 print_int_array(cod[i][j].outfmt, CODECS_MAX_OUTFMT);
1068 printf(", /* outfmt */\n");
1070 print_char_array(cod[i][j].outflags, CODECS_MAX_OUTFMT);
1071 printf(", /* outflags */\n");
1073 print_int_array(cod[i][j].infmt, CODECS_MAX_INFMT);
1074 printf(", /* infmt */\n");
1076 print_char_array(cod[i][j].inflags, CODECS_MAX_INFMT);
1077 printf(", /* inflags */\n");
1079 print_string(cod[i][j].name); printf(", /* name */\n");
1080 print_string(cod[i][j].info); printf(", /* info */\n");
1081 print_string(cod[i][j].comment); printf(", /* comment */\n");
1082 print_string(cod[i][j].dll); printf(", /* dll */\n");
1083 print_string(cod[i][j].drv); printf(", /* drv */\n");
1085 printf("{ 0x%08lx, %hu, %hu,",
1086 cod[i][j].guid.f1,
1087 cod[i][j].guid.f2,
1088 cod[i][j].guid.f3);
1089 print_char_array(cod[i][j].guid.f4, sizeof(cod[i][j].guid.f4));
1090 printf(" }, /* GUID */\n");
1091 printf("%hd /* flags */, %hd /* status */, %hd /* cpuflags */ }\n",
1092 cod[i][j].flags,
1093 cod[i][j].status,
1094 cod[i][j].cpuflags);
1095 if (j < nr[i]) printf(",\n");
1097 printf("};\n\n");
1099 exit(0);
1102 f1=fopen("DOCS/tech/codecs-in.html","rb"); if(!f1) exit(1);
1103 f2=fopen("DOCS/codecs-status.html","wb"); if(!f2) exit(1);
1105 while((c=fgetc(f1))>=0){
1106 if(c!='%'){
1107 fputc(c,f2);
1108 continue;
1110 d=fgetc(f1);
1111 if(d>='0' && d<='9'){
1112 // begin section
1113 section=d-'0';
1114 //printf("BEGIN %d\n",section);
1115 if(section>=5){
1116 // audio
1117 cl = audio_codecs;
1118 nr_codecs = nr_acodecs;
1119 dshow=7;win32=4;
1120 } else {
1121 // video
1122 cl = video_codecs;
1123 nr_codecs = nr_vcodecs;
1124 dshow=4;win32=2;win32ex=6;
1126 pos=ftell(f1);
1127 for(i=0;i<nr_codecs;i++){
1128 fseek(f1,pos,SEEK_SET);
1129 switch(section){
1130 case 0:
1131 case 5:
1132 if(cl[i].status==CODECS_STATUS_WORKING)
1133 // if(!(!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1134 parsehtml(f1,f2,&cl[i],section,dshow);
1135 break;
1136 #if 0
1137 case 1:
1138 case 6:
1139 if(cl[i].status==CODECS_STATUS_WORKING)
1140 if((!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1141 parsehtml(f1,f2,&cl[i],section,dshow);
1142 break;
1143 #endif
1144 case 2:
1145 case 7:
1146 if(cl[i].status==CODECS_STATUS_PROBLEMS)
1147 parsehtml(f1,f2,&cl[i],section,dshow);
1148 break;
1149 case 3:
1150 case 8:
1151 if(cl[i].status==CODECS_STATUS_NOT_WORKING)
1152 parsehtml(f1,f2,&cl[i],section,dshow);
1153 break;
1154 case 4:
1155 case 9:
1156 if(cl[i].status==CODECS_STATUS_UNTESTED)
1157 parsehtml(f1,f2,&cl[i],section,dshow);
1158 break;
1159 default:
1160 printf("Warning! unimplemented section: %d\n",section);
1163 fseek(f1,pos,SEEK_SET);
1164 skiphtml(f1);
1165 //void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
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