Merge svn changes up to r30876
[mplayer/kovensky.git] / codec-cfg.c
blobae84af4c1ae73ea071bec1d7c5d6c0b6503442ee
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
56 #include "help_mp.h"
58 #include "libmpcodecs/img_format.h"
59 #include "codec-cfg.h"
61 #ifndef CODECS2HTML
62 #include "codecs.conf.h"
63 #endif
65 #define mmioFOURCC( ch0, ch1, ch2, ch3 ) \
66 ( (uint32_t)(uint8_t)(ch0) | ( (uint32_t)(uint8_t)(ch1) << 8 ) | \
67 ( (uint32_t)(uint8_t)(ch2) << 16 ) | ( (uint32_t)(uint8_t)(ch3) << 24 ) )
69 #define PRINT_LINENUM mp_msg(MSGT_CODECCFG,MSGL_ERR," at line %d\n", line_num)
71 #define MAX_NR_TOKEN 16
73 #define MAX_LINE_LEN 1000
75 #define RET_EOF -1
76 #define RET_EOL -2
78 #define TYPE_VIDEO 0
79 #define TYPE_AUDIO 1
81 char * codecs_file = NULL;
83 static int add_to_fourcc(char *s, char *alias, unsigned int *fourcc,
84 unsigned int *map)
86 int i, j, freeslots;
87 unsigned int tmp;
89 /* find first unused slot */
90 for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++)
91 /* NOTHING */;
92 freeslots = CODECS_MAX_FOURCC - i;
93 if (!freeslots)
94 goto err_out_too_many;
96 do {
97 tmp = mmioFOURCC(s[0], s[1], s[2], s[3]);
98 for (j = 0; j < i; j++)
99 if (tmp == fourcc[j])
100 goto err_out_duplicated;
101 fourcc[i] = tmp;
102 map[i] = alias ? mmioFOURCC(alias[0], alias[1], alias[2], alias[3]) : tmp;
103 s += 4;
104 i++;
105 } while ((*(s++) == ',') && --freeslots);
107 if (!freeslots)
108 goto err_out_too_many;
109 if (*(--s) != '\0')
110 goto err_out_parse_error;
111 return 1;
112 err_out_duplicated:
113 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"duplicated FourCC");
114 return 0;
115 err_out_too_many:
116 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"too many FourCCs/formats...");
117 return 0;
118 err_out_parse_error:
119 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
120 return 0;
123 static int add_to_format(char *s, char *alias,unsigned int *fourcc, unsigned int *fourccmap)
125 int i, j;
126 char *endptr;
128 /* find first unused slot */
129 for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++)
130 /* NOTHING */;
131 if (i == CODECS_MAX_FOURCC) {
132 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"too many FourCCs/formats...");
133 return 0;
136 fourcc[i]=strtoul(s,&endptr,0);
137 if (*endptr != '\0') {
138 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error (format ID not a number?)");
139 return 0;
142 if(alias){
143 fourccmap[i]=strtoul(alias,&endptr,0);
144 if (*endptr != '\0') {
145 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error (format ID alias not a number?)");
146 return 0;
148 } else
149 fourccmap[i]=fourcc[i];
151 for (j = 0; j < i; j++)
152 if (fourcc[j] == fourcc[i]) {
153 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"duplicated format ID");
154 return 0;
157 return 1;
160 static const struct {
161 const char *name;
162 const unsigned int num;
163 } fmt_table[] = {
164 // note: due to parser deficiencies/simplicity, if one format
165 // name matches the beginning of another, the longer one _must_
166 // come first in this list.
167 {"YV12", IMGFMT_YV12},
168 {"I420", IMGFMT_I420},
169 {"IYUV", IMGFMT_IYUV},
170 {"NV12", IMGFMT_NV12},
171 {"NV21", IMGFMT_NV21},
172 {"YVU9", IMGFMT_YVU9},
173 {"IF09", IMGFMT_IF09},
174 {"444P16LE", IMGFMT_444P16_LE},
175 {"444P16BE", IMGFMT_444P16_BE},
176 {"422P16LE", IMGFMT_422P16_LE},
177 {"422P16BE", IMGFMT_422P16_BE},
178 {"420P16LE", IMGFMT_420P16_LE},
179 {"420P16BE", IMGFMT_420P16_BE},
180 {"444P16", IMGFMT_444P16},
181 {"422P16", IMGFMT_422P16},
182 {"420P16", IMGFMT_420P16},
183 {"420A", IMGFMT_420A},
184 {"444P", IMGFMT_444P},
185 {"422P", IMGFMT_422P},
186 {"411P", IMGFMT_411P},
187 {"440P", IMGFMT_440P},
188 {"Y800", IMGFMT_Y800},
189 {"Y8", IMGFMT_Y8},
191 {"YUY2", IMGFMT_YUY2},
192 {"UYVY", IMGFMT_UYVY},
193 {"YVYU", IMGFMT_YVYU},
195 {"RGB48LE", IMGFMT_RGB48LE},
196 {"RGB48BE", IMGFMT_RGB48BE},
197 {"RGB4", IMGFMT_RGB4},
198 {"RGB8", IMGFMT_RGB8},
199 {"RGB15", IMGFMT_RGB15},
200 {"RGB16", IMGFMT_RGB16},
201 {"RGB24", IMGFMT_RGB24},
202 {"RGB32", IMGFMT_RGB32},
203 {"BGR4", IMGFMT_BGR4},
204 {"BGR8", IMGFMT_BGR8},
205 {"BGR15", IMGFMT_BGR15},
206 {"BGR16", IMGFMT_BGR16},
207 {"BGR24", IMGFMT_BGR24},
208 {"BGR32", IMGFMT_BGR32},
209 {"RGB1", IMGFMT_RGB1},
210 {"BGR1", IMGFMT_BGR1},
212 {"MPES", IMGFMT_MPEGPES},
213 {"ZRMJPEGNI", IMGFMT_ZRMJPEGNI},
214 {"ZRMJPEGIT", IMGFMT_ZRMJPEGIT},
215 {"ZRMJPEGIB", IMGFMT_ZRMJPEGIB},
217 {"IDCT_MPEG2",IMGFMT_XVMC_IDCT_MPEG2},
218 {"MOCO_MPEG2",IMGFMT_XVMC_MOCO_MPEG2},
220 {"VDPAU_MPEG1",IMGFMT_VDPAU_MPEG1},
221 {"VDPAU_MPEG2",IMGFMT_VDPAU_MPEG2},
222 {"VDPAU_H264",IMGFMT_VDPAU_H264},
223 {"VDPAU_WMV3",IMGFMT_VDPAU_WMV3},
224 {"VDPAU_VC1",IMGFMT_VDPAU_VC1},
225 {"VDPAU_MPEG4",IMGFMT_VDPAU_MPEG4},
227 {NULL, 0}
231 static int add_to_inout(char *sfmt, char *sflags, unsigned int *outfmt,
232 unsigned char *outflags)
235 static char *flagstr[] = {
236 "flip",
237 "noflip",
238 "yuvhack",
239 "query",
240 "static",
241 NULL
244 int i, j, freeslots;
245 unsigned char flags;
247 for (i = 0; i < CODECS_MAX_OUTFMT && outfmt[i] != 0xffffffff; i++)
248 /* NOTHING */;
249 freeslots = CODECS_MAX_OUTFMT - i;
250 if (!freeslots)
251 goto err_out_too_many;
253 flags = 0;
254 if(sflags) {
255 do {
256 for (j = 0; flagstr[j] != NULL; j++)
257 if (!strncmp(sflags, flagstr[j],
258 strlen(flagstr[j])))
259 break;
260 if (flagstr[j] == NULL)
261 goto err_out_parse_error;
262 flags|=(1<<j);
263 sflags+=strlen(flagstr[j]);
264 } while (*(sflags++) == ',');
266 if (*(--sflags) != '\0')
267 goto err_out_parse_error;
270 do {
271 for (j = 0; fmt_table[j].name != NULL; j++)
272 if (!strncmp(sfmt, fmt_table[j].name, strlen(fmt_table[j].name)))
273 break;
274 if (fmt_table[j].name == NULL)
275 goto err_out_parse_error;
276 outfmt[i] = fmt_table[j].num;
277 outflags[i] = flags;
278 ++i;
279 sfmt+=strlen(fmt_table[j].name);
280 } while ((*(sfmt++) == ',') && --freeslots);
282 if (!freeslots)
283 goto err_out_too_many;
285 if (*(--sfmt) != '\0')
286 goto err_out_parse_error;
288 return 1;
289 err_out_too_many:
290 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"too many out...");
291 return 0;
292 err_out_parse_error:
293 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
294 return 0;
297 #if 0
298 static short get_driver(char *s,int audioflag)
300 static char *audiodrv[] = {
301 "null",
302 "mp3lib",
303 "pcm",
304 "libac3",
305 "acm",
306 "alaw",
307 "msgsm",
308 "dshow",
309 "dvdpcm",
310 "hwac3",
311 "libvorbis",
312 "ffmpeg",
313 "libmad",
314 "msadpcm",
315 "liba52",
316 "g72x",
317 "imaadpcm",
318 "dk4adpcm",
319 "dk3adpcm",
320 "roqaudio",
321 "faad",
322 "realaud",
323 "libdv",
324 NULL
326 static char *videodrv[] = {
327 "null",
328 "libmpeg2",
329 "vfw",
330 "dshow",
331 "ffmpeg",
332 "vfwex",
333 "raw",
334 "msrle",
335 "xanim",
336 "msvidc",
337 "fli",
338 "cinepak",
339 "qtrle",
340 "nuv",
341 "cyuv",
342 "qtsmc",
343 "ducktm1",
344 "roqvideo",
345 "qtrpza",
346 "mpng",
347 "ijpg",
348 "zlib",
349 "mpegpes",
350 "zrmjpeg",
351 "realvid",
352 "xvid",
353 "libdv",
354 NULL
356 char **drv=audioflag?audiodrv:videodrv;
357 int i;
359 for(i=0;drv[i];i++) if(!strcmp(s,drv[i])) return i;
361 return -1;
363 #endif
365 static int validate_codec(codecs_t *c, int type)
367 unsigned int i;
368 char *tmp_name = c->name;
370 for (i = 0; i < strlen(tmp_name) && isalnum(tmp_name[i]); i++)
371 /* NOTHING */;
373 if (i < strlen(tmp_name)) {
374 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) name is not valid!\n", c->name);
375 return 0;
378 if (!c->info)
379 c->info = strdup(c->name);
381 #if 0
382 if (c->fourcc[0] == 0xffffffff) {
383 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) does not have FourCC/format!\n", c->name);
384 return 0;
386 #endif
388 if (!c->drv) {
389 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) does not have a driver!\n", c->name);
390 return 0;
393 #if 0
394 #warning codec->driver == 4;... <- this should not be put in here...
395 #warning Where are they defined ????????????
396 if (!c->dll && (c->driver == 4 ||
397 (c->driver == 2 && type == TYPE_VIDEO))) {
398 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) needs a 'dll'!\n", c->name);
399 return 0;
401 #warning Can guid.f1 be 0? How does one know that it was not given?
402 // if (!(codec->flags & CODECS_FLAG_AUDIO) && codec->driver == 4)
404 if (type == TYPE_VIDEO)
405 if (c->outfmt[0] == 0xffffffff) {
406 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) needs an 'outfmt'!\n", c->name);
407 return 0;
409 #endif
410 return 1;
413 static int add_comment(char *s, char **d)
415 int pos;
417 if (!*d)
418 pos = 0;
419 else {
420 pos = strlen(*d);
421 (*d)[pos++] = '\n';
423 if (!(*d = realloc(*d, pos + strlen(s) + 1))) {
424 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't allocate memory for comment. ");
425 return 0;
427 strcpy(*d + pos, s);
428 return 1;
431 static short get_cpuflags(char *s)
433 static char *flagstr[] = {
434 "mmx",
435 "sse",
436 "3dnow",
437 NULL
439 int i;
440 short flags = 0;
442 do {
443 for (i = 0; flagstr[i]; i++)
444 if (!strncmp(s, flagstr[i], strlen(flagstr[i])))
445 break;
446 if (!flagstr[i])
447 goto err_out_parse_error;
448 flags |= 1<<i;
449 s += strlen(flagstr[i]);
450 } while (*(s++) == ',');
452 if (*(--s) != '\0')
453 goto err_out_parse_error;
455 return flags;
456 err_out_parse_error:
457 return 0;
460 static FILE *fp;
461 static int line_num = 0;
462 static char *line;
463 static char *token[MAX_NR_TOKEN];
464 static int read_nextline = 1;
466 static int get_token(int min, int max)
468 static int line_pos;
469 int i;
470 char c;
472 if (max >= MAX_NR_TOKEN) {
473 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"get_token(): max >= MAX_MR_TOKEN!");
474 goto out_eof;
477 memset(token, 0x00, sizeof(*token) * max);
479 if (read_nextline) {
480 if (!fgets(line, MAX_LINE_LEN, fp))
481 goto out_eof;
482 line_pos = 0;
483 ++line_num;
484 read_nextline = 0;
486 for (i = 0; i < max; i++) {
487 while (isspace(line[line_pos]))
488 ++line_pos;
489 if (line[line_pos] == '\0' || line[line_pos] == '#' ||
490 line[line_pos] == ';') {
491 read_nextline = 1;
492 if (i >= min)
493 goto out_ok;
494 goto out_eol;
496 token[i] = line + line_pos;
497 c = line[line_pos];
498 if (c == '"' || c == '\'') {
499 token[i]++;
500 while (line[++line_pos] != c && line[line_pos])
501 /* NOTHING */;
502 } else {
503 for (/* NOTHING */; !isspace(line[line_pos]) &&
504 line[line_pos]; line_pos++)
505 /* NOTHING */;
507 if (!line[line_pos]) {
508 read_nextline = 1;
509 if (i >= min - 1)
510 goto out_ok;
511 goto out_eol;
513 line[line_pos] = '\0';
514 line_pos++;
516 out_ok:
517 return i;
518 out_eof:
519 read_nextline = 1;
520 return RET_EOF;
521 out_eol:
522 return RET_EOL;
525 static codecs_t *video_codecs=NULL;
526 static codecs_t *audio_codecs=NULL;
527 static int nr_vcodecs = 0;
528 static int nr_acodecs = 0;
530 int parse_codec_cfg(const char *cfgfile)
532 codecs_t *codec = NULL; // current codec
533 codecs_t **codecsp = NULL;// points to audio_codecs or to video_codecs
534 char *endptr; // strtoul()...
535 int *nr_codecsp;
536 int codec_type; /* TYPE_VIDEO/TYPE_AUDIO */
537 int tmp, i;
539 // in case we call it a second time
540 codecs_uninit_free();
542 nr_vcodecs = 0;
543 nr_acodecs = 0;
545 if(cfgfile==NULL) {
546 #ifdef CODECS2HTML
547 return 0;
548 #else
549 video_codecs = builtin_video_codecs;
550 audio_codecs = builtin_audio_codecs;
551 nr_vcodecs = sizeof(builtin_video_codecs)/sizeof(codecs_t);
552 nr_acodecs = sizeof(builtin_audio_codecs)/sizeof(codecs_t);
553 return 1;
554 #endif
557 mp_tmsg(MSGT_CODECCFG,MSGL_V,"Reading %s: ", cfgfile);
559 if ((fp = fopen(cfgfile, "r")) == NULL) {
560 mp_tmsg(MSGT_CODECCFG,MSGL_V,"Can't open '%s': %s\n", cfgfile, strerror(errno));
561 return 0;
564 if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) {
565 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't get memory for 'line': %s\n", strerror(errno));
566 return 0;
568 read_nextline = 1;
571 * this only catches release lines at the start of
572 * codecs.conf, before audiocodecs and videocodecs.
574 while ((tmp = get_token(1, 1)) == RET_EOL)
575 /* NOTHING */;
576 if (tmp == RET_EOF)
577 goto out;
578 if (!strcmp(token[0], "release")) {
579 if (get_token(1, 2) < 0)
580 goto err_out_parse_error;
581 tmp = atoi(token[0]);
582 if (tmp < CODEC_CFG_MIN)
583 goto err_out_release_num;
584 while ((tmp = get_token(1, 1)) == RET_EOL)
585 /* NOTHING */;
586 if (tmp == RET_EOF)
587 goto out;
588 } else
589 goto err_out_release_num;
592 * check if the next block starts with 'audiocodec' or
593 * with 'videocodec'
595 if (!strcmp(token[0], "audiocodec") || !strcmp(token[0], "videocodec"))
596 goto loop_enter;
597 goto err_out_parse_error;
599 while ((tmp = get_token(1, 1)) != RET_EOF) {
600 if (tmp == RET_EOL)
601 continue;
602 if (!strcmp(token[0], "audiocodec") ||
603 !strcmp(token[0], "videocodec")) {
604 if (!validate_codec(codec, codec_type))
605 goto err_out_not_valid;
606 loop_enter:
607 if (*token[0] == 'v') {
608 codec_type = TYPE_VIDEO;
609 nr_codecsp = &nr_vcodecs;
610 codecsp = &video_codecs;
611 } else if (*token[0] == 'a') {
612 codec_type = TYPE_AUDIO;
613 nr_codecsp = &nr_acodecs;
614 codecsp = &audio_codecs;
615 #ifdef DEBUG
616 } else {
617 mp_msg(MSGT_CODECCFG,MSGL_ERR,"picsba\n");
618 goto err_out;
619 #endif
621 if (!(*codecsp = realloc(*codecsp,
622 sizeof(codecs_t) * (*nr_codecsp + 2)))) {
623 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't realloc '*codecsp': %s\n", strerror(errno));
624 goto err_out;
626 codec=*codecsp + *nr_codecsp;
627 ++*nr_codecsp;
628 memset(codec,0,sizeof(codecs_t));
629 memset(codec->fourcc, 0xff, sizeof(codec->fourcc));
630 memset(codec->outfmt, 0xff, sizeof(codec->outfmt));
631 memset(codec->infmt, 0xff, sizeof(codec->infmt));
633 if (get_token(1, 1) < 0)
634 goto err_out_parse_error;
635 for (i = 0; i < *nr_codecsp - 1; i++) {
636 if(( (*codecsp)[i].name!=NULL) &&
637 (!strcmp(token[0], (*codecsp)[i].name)) ) {
638 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Codec name '%s' isn't unique.", token[0]);
639 goto err_out_print_linenum;
642 if (!(codec->name = strdup(token[0]))) {
643 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'name': %s\n", strerror(errno));
644 goto err_out;
646 } else if (!strcmp(token[0], "info")) {
647 if (codec->info || get_token(1, 1) < 0)
648 goto err_out_parse_error;
649 if (!(codec->info = strdup(token[0]))) {
650 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'info': %s\n", strerror(errno));
651 goto err_out;
653 } else if (!strcmp(token[0], "comment")) {
654 if (get_token(1, 1) < 0)
655 goto err_out_parse_error;
656 add_comment(token[0], &codec->comment);
657 } else if (!strcmp(token[0], "fourcc")) {
658 if (get_token(1, 2) < 0)
659 goto err_out_parse_error;
660 if (!add_to_fourcc(token[0], token[1],
661 codec->fourcc,
662 codec->fourccmap))
663 goto err_out_print_linenum;
664 } else if (!strcmp(token[0], "format")) {
665 if (get_token(1, 2) < 0)
666 goto err_out_parse_error;
667 if (!add_to_format(token[0], token[1],
668 codec->fourcc,codec->fourccmap))
669 goto err_out_print_linenum;
670 } else if (!strcmp(token[0], "driver")) {
671 if (get_token(1, 1) < 0)
672 goto err_out_parse_error;
673 if (!(codec->drv = strdup(token[0]))) {
674 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'driver': %s\n", strerror(errno));
675 goto err_out;
677 } else if (!strcmp(token[0], "dll")) {
678 if (get_token(1, 1) < 0)
679 goto err_out_parse_error;
680 if (!(codec->dll = strdup(token[0]))) {
681 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'dll': %s", strerror(errno));
682 goto err_out;
684 } else if (!strcmp(token[0], "guid")) {
685 if (get_token(11, 11) < 0)
686 goto err_out_parse_error;
687 codec->guid.f1=strtoul(token[0],&endptr,0);
688 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
689 *endptr != '\0')
690 goto err_out_parse_error;
691 codec->guid.f2=strtoul(token[1],&endptr,0);
692 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
693 *endptr != '\0')
694 goto err_out_parse_error;
695 codec->guid.f3=strtoul(token[2],&endptr,0);
696 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
697 *endptr != '\0')
698 goto err_out_parse_error;
699 for (i = 0; i < 8; i++) {
700 codec->guid.f4[i]=strtoul(token[i + 3],&endptr,0);
701 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
702 *endptr != '\0')
703 goto err_out_parse_error;
705 } else if (!strcmp(token[0], "out")) {
706 if (get_token(1, 2) < 0)
707 goto err_out_parse_error;
708 if (!add_to_inout(token[0], token[1], codec->outfmt,
709 codec->outflags))
710 goto err_out_print_linenum;
711 } else if (!strcmp(token[0], "in")) {
712 if (get_token(1, 2) < 0)
713 goto err_out_parse_error;
714 if (!add_to_inout(token[0], token[1], codec->infmt,
715 codec->inflags))
716 goto err_out_print_linenum;
717 } else if (!strcmp(token[0], "flags")) {
718 if (get_token(1, 1) < 0)
719 goto err_out_parse_error;
720 if (!strcmp(token[0], "seekable"))
721 codec->flags |= CODECS_FLAG_SEEKABLE;
722 else
723 if (!strcmp(token[0], "align16"))
724 codec->flags |= CODECS_FLAG_ALIGN16;
725 else
726 goto err_out_parse_error;
727 } else if (!strcmp(token[0], "status")) {
728 if (get_token(1, 1) < 0)
729 goto err_out_parse_error;
730 if (!strcasecmp(token[0], "working"))
731 codec->status = CODECS_STATUS_WORKING;
732 else if (!strcasecmp(token[0], "crashing"))
733 codec->status = CODECS_STATUS_NOT_WORKING;
734 else if (!strcasecmp(token[0], "untested"))
735 codec->status = CODECS_STATUS_UNTESTED;
736 else if (!strcasecmp(token[0], "buggy"))
737 codec->status = CODECS_STATUS_PROBLEMS;
738 else
739 goto err_out_parse_error;
740 } else if (!strcmp(token[0], "cpuflags")) {
741 if (get_token(1, 1) < 0)
742 goto err_out_parse_error;
743 if (!(codec->cpuflags = get_cpuflags(token[0])))
744 goto err_out_parse_error;
745 } else
746 goto err_out_parse_error;
748 if (!validate_codec(codec, codec_type))
749 goto err_out_not_valid;
750 mp_tmsg(MSGT_CODECCFG,MSGL_INFO,"%d audio & %d video codecs\n", nr_acodecs, nr_vcodecs);
751 if(video_codecs) video_codecs[nr_vcodecs].name = NULL;
752 if(audio_codecs) audio_codecs[nr_acodecs].name = NULL;
753 out:
754 free(line);
755 line=NULL;
756 fclose(fp);
757 return 1;
759 err_out_parse_error:
760 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
761 err_out_print_linenum:
762 PRINT_LINENUM;
763 err_out:
764 codecs_uninit_free();
766 free(line);
767 line=NULL;
768 line_num = 0;
769 fclose(fp);
770 return 0;
771 err_out_not_valid:
772 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Codec is not defined correctly.");
773 goto err_out_print_linenum;
774 err_out_release_num:
775 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"This codecs.conf is too old and incompatible with this MPlayer release!");
776 goto err_out_print_linenum;
779 static void codecs_free(codecs_t* codecs,int count) {
780 int i;
781 for ( i = 0; i < count; i++)
782 if ( codecs[i].name ) {
783 if( codecs[i].name )
784 free(codecs[i].name);
785 if( codecs[i].info )
786 free(codecs[i].info);
787 if( codecs[i].comment )
788 free(codecs[i].comment);
789 if( codecs[i].dll )
790 free(codecs[i].dll);
791 if( codecs[i].drv )
792 free(codecs[i].drv);
794 if (codecs)
795 free(codecs);
798 void codecs_uninit_free(void) {
799 if (video_codecs)
800 codecs_free(video_codecs,nr_vcodecs);
801 video_codecs=NULL;
802 if (audio_codecs)
803 codecs_free(audio_codecs,nr_acodecs);
804 audio_codecs=NULL;
807 codecs_t *find_audio_codec(unsigned int fourcc, unsigned int *fourccmap,
808 codecs_t *start, int force)
810 return find_codec(fourcc, fourccmap, start, 1, force);
813 codecs_t *find_video_codec(unsigned int fourcc, unsigned int *fourccmap,
814 codecs_t *start, int force)
816 return find_codec(fourcc, fourccmap, start, 0, force);
819 codecs_t* find_codec(unsigned int fourcc,unsigned int *fourccmap,
820 codecs_t *start, int audioflag, int force)
822 int i, j;
823 codecs_t *c;
825 #if 0
826 if (start) {
827 for (/* NOTHING */; start->name; start++) {
828 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
829 if (start->fourcc[j] == fourcc) {
830 if (fourccmap)
831 *fourccmap = start->fourccmap[j];
832 return start;
836 } else
837 #endif
839 if (audioflag) {
840 i = nr_acodecs;
841 c = audio_codecs;
842 } else {
843 i = nr_vcodecs;
844 c = video_codecs;
846 if(!i) return NULL;
847 for (/* NOTHING */; i--; c++) {
848 if(start && c<=start) continue;
849 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
850 // FIXME: do NOT hardwire 'null' name here:
851 if (c->fourcc[j]==fourcc || !strcmp(c->drv,"null")) {
852 if (fourccmap)
853 *fourccmap = c->fourccmap[j];
854 return c;
857 if (force) return c;
860 return NULL;
863 void stringset_init(stringset_t *set) {
864 *set = calloc(1, sizeof(char *));
867 void stringset_free(stringset_t *set) {
868 int count = 0;
869 while ((*set)[count]) free((*set)[count++]);
870 free(*set);
871 *set = NULL;
874 void stringset_add(stringset_t *set, const char *str) {
875 int count = 0;
876 while ((*set)[count]) count++;
877 count++;
878 *set = realloc(*set, sizeof(char *) * (count + 1));
879 (*set)[count - 1] = strdup(str);
880 (*set)[count] = NULL;
883 int stringset_test(stringset_t *set, const char *str) {
884 stringset_t s;
885 for (s = *set; *s; s++)
886 if (strcmp(*s, str) == 0)
887 return 1;
888 return 0;
891 void list_codecs(int audioflag){
892 int i;
893 codecs_t *c;
895 if (audioflag) {
896 i = nr_acodecs;
897 c = audio_codecs;
898 mp_msg(MSGT_CODECCFG,MSGL_INFO,"ac: afm: status: info: [lib/dll]\n");
899 } else {
900 i = nr_vcodecs;
901 c = video_codecs;
902 mp_msg(MSGT_CODECCFG,MSGL_INFO,"vc: vfm: status: info: [lib/dll]\n");
904 if(!i) return;
905 for (/* NOTHING */; i--; c++) {
906 char* s="unknown ";
907 switch(c->status){
908 case CODECS_STATUS_WORKING: s="working ";break;
909 case CODECS_STATUS_PROBLEMS: s="problems";break;
910 case CODECS_STATUS_NOT_WORKING: s="crashing";break;
911 case CODECS_STATUS_UNTESTED: s="untested";break;
913 if(c->dll)
914 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s [%s]\n",c->name,c->drv,s,c->info,c->dll);
915 else
916 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s\n",c->name,c->drv,s,c->info);
924 #ifdef CODECS2HTML
925 void wrapline(FILE *f2,char *s){
926 int c;
927 if(!s){
928 fprintf(f2,"-");
929 return;
931 while((c=*s++)){
932 if(c==',') fprintf(f2,"<br>"); else fputc(c,f2);
936 void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
937 int c,d;
938 while((c=fgetc(f1))>=0){
939 if(c!='%'){
940 fputc(c,f2);
941 continue;
943 d=fgetc(f1);
945 switch(d){
946 case '.':
947 return; // end of section
948 case 'n':
949 wrapline(f2,codec->name); break;
950 case 'i':
951 wrapline(f2,codec->info); break;
952 case 'c':
953 wrapline(f2,codec->comment); break;
954 case 'd':
955 wrapline(f2,codec->dll); break;
956 case 'D':
957 fprintf(f2,"%c",!strcmp(codec->drv,"dshow")?'+':'-'); break;
958 case 'F':
959 for(d=0;d<CODECS_MAX_FOURCC;d++)
960 if(!d || codec->fourcc[d]!=0xFFFFFFFF)
961 fprintf(f2,"%s%.4s",d?"<br>":"",(codec->fourcc[d]==0xFFFFFFFF || codec->fourcc[d]<0x20202020)?!d?"-":"":(char*) &codec->fourcc[d]);
962 break;
963 case 'f':
964 for(d=0;d<CODECS_MAX_FOURCC;d++)
965 if(codec->fourcc[d]!=0xFFFFFFFF)
966 fprintf(f2,"%s0x%X",d?"<br>":"",codec->fourcc[d]);
967 break;
968 case 'Y':
969 for(d=0;d<CODECS_MAX_OUTFMT;d++)
970 if(codec->outfmt[d]!=0xFFFFFFFF){
971 for (c=0; fmt_table[c].name; c++)
972 if(fmt_table[c].num==codec->outfmt[d]) break;
973 if(fmt_table[c].name)
974 fprintf(f2,"%s%s",d?"<br>":"",fmt_table[c].name);
976 break;
977 default:
978 fputc(c,f2);
979 fputc(d,f2);
985 void skiphtml(FILE *f1){
986 int c,d;
987 while((c=fgetc(f1))>=0){
988 if(c!='%'){
989 continue;
991 d=fgetc(f1);
992 if(d=='.') return; // end of section
996 static void print_int_array(const unsigned int* a, int size)
998 printf("{ ");
999 while (size--)
1000 if(abs(*a)<256)
1001 printf("%d%s", *a++, size?", ":"");
1002 else
1003 printf("0x%X%s", *a++, size?", ":"");
1004 printf(" }");
1007 static void print_char_array(const unsigned char* a, int size)
1009 printf("{ ");
1010 while (size--)
1011 if((*a)<10)
1012 printf("%d%s", *a++, size?", ":"");
1013 else
1014 printf("0x%02x%s", *a++, size?", ":"");
1015 printf(" }");
1018 static void print_string(const char* s)
1020 if (!s) printf("NULL");
1021 else printf("\"%s\"", s);
1024 int main(int argc, char* argv[])
1026 codecs_t *cl;
1027 FILE *f1;
1028 FILE *f2;
1029 int c,d,i;
1030 int pos;
1031 int section=-1;
1032 int nr_codecs;
1033 int win32=-1;
1034 int dshow=-1;
1035 int win32ex=-1;
1038 * Take path to codecs.conf from command line, or fall back on
1039 * etc/codecs.conf
1041 if (!(nr_codecs = parse_codec_cfg((argc>1)?argv[1]:"etc/codecs.conf")))
1042 exit(1);
1044 if (argc > 1) {
1045 int i, j;
1046 const char* nm[2];
1047 codecs_t* cod[2];
1048 int nr[2];
1050 nm[0] = "builtin_video_codecs";
1051 cod[0] = video_codecs;
1052 nr[0] = nr_vcodecs;
1054 nm[1] = "builtin_audio_codecs";
1055 cod[1] = audio_codecs;
1056 nr[1] = nr_acodecs;
1058 printf("/* GENERATED FROM %s, DO NOT EDIT! */\n\n",argv[1]);
1059 printf("#include <stddef.h>\n");
1060 printf("#include \"codec-cfg.h\"\n\n");
1062 for (i=0; i<2; i++) {
1063 printf("const codecs_t %s[] = {\n", nm[i]);
1064 for (j = 0; j < nr[i]; j++) {
1065 printf("{");
1067 print_int_array(cod[i][j].fourcc, CODECS_MAX_FOURCC);
1068 printf(", /* fourcc */\n");
1070 print_int_array(cod[i][j].fourccmap, CODECS_MAX_FOURCC);
1071 printf(", /* fourccmap */\n");
1073 print_int_array(cod[i][j].outfmt, CODECS_MAX_OUTFMT);
1074 printf(", /* outfmt */\n");
1076 print_char_array(cod[i][j].outflags, CODECS_MAX_OUTFMT);
1077 printf(", /* outflags */\n");
1079 print_int_array(cod[i][j].infmt, CODECS_MAX_INFMT);
1080 printf(", /* infmt */\n");
1082 print_char_array(cod[i][j].inflags, CODECS_MAX_INFMT);
1083 printf(", /* inflags */\n");
1085 print_string(cod[i][j].name); printf(", /* name */\n");
1086 print_string(cod[i][j].info); printf(", /* info */\n");
1087 print_string(cod[i][j].comment); printf(", /* comment */\n");
1088 print_string(cod[i][j].dll); printf(", /* dll */\n");
1089 print_string(cod[i][j].drv); printf(", /* drv */\n");
1091 printf("{ 0x%08lx, %hu, %hu,",
1092 cod[i][j].guid.f1,
1093 cod[i][j].guid.f2,
1094 cod[i][j].guid.f3);
1095 print_char_array(cod[i][j].guid.f4, sizeof(cod[i][j].guid.f4));
1096 printf(" }, /* GUID */\n");
1097 printf("%hd /* flags */, %hd /* status */, %hd /* cpuflags */ }\n",
1098 cod[i][j].flags,
1099 cod[i][j].status,
1100 cod[i][j].cpuflags);
1101 if (j < nr[i]) printf(",\n");
1103 printf("};\n\n");
1105 exit(0);
1108 f1=fopen("DOCS/tech/codecs-in.html","rb"); if(!f1) exit(1);
1109 f2=fopen("DOCS/codecs-status.html","wb"); if(!f2) exit(1);
1111 while((c=fgetc(f1))>=0){
1112 if(c!='%'){
1113 fputc(c,f2);
1114 continue;
1116 d=fgetc(f1);
1117 if(d>='0' && d<='9'){
1118 // begin section
1119 section=d-'0';
1120 //printf("BEGIN %d\n",section);
1121 if(section>=5){
1122 // audio
1123 cl = audio_codecs;
1124 nr_codecs = nr_acodecs;
1125 dshow=7;win32=4;
1126 } else {
1127 // video
1128 cl = video_codecs;
1129 nr_codecs = nr_vcodecs;
1130 dshow=4;win32=2;win32ex=6;
1132 pos=ftell(f1);
1133 for(i=0;i<nr_codecs;i++){
1134 fseek(f1,pos,SEEK_SET);
1135 switch(section){
1136 case 0:
1137 case 5:
1138 if(cl[i].status==CODECS_STATUS_WORKING)
1139 // if(!(!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1140 parsehtml(f1,f2,&cl[i],section,dshow);
1141 break;
1142 #if 0
1143 case 1:
1144 case 6:
1145 if(cl[i].status==CODECS_STATUS_WORKING)
1146 if((!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1147 parsehtml(f1,f2,&cl[i],section,dshow);
1148 break;
1149 #endif
1150 case 2:
1151 case 7:
1152 if(cl[i].status==CODECS_STATUS_PROBLEMS)
1153 parsehtml(f1,f2,&cl[i],section,dshow);
1154 break;
1155 case 3:
1156 case 8:
1157 if(cl[i].status==CODECS_STATUS_NOT_WORKING)
1158 parsehtml(f1,f2,&cl[i],section,dshow);
1159 break;
1160 case 4:
1161 case 9:
1162 if(cl[i].status==CODECS_STATUS_UNTESTED)
1163 parsehtml(f1,f2,&cl[i],section,dshow);
1164 break;
1165 default:
1166 printf("Warning! unimplemented section: %d\n",section);
1169 fseek(f1,pos,SEEK_SET);
1170 skiphtml(f1);
1171 //void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
1173 continue;
1175 fputc(c,f2);
1176 fputc(d,f2);
1179 fclose(f2);
1180 fclose(f1);
1181 return 0;
1184 #endif
1186 #ifdef TESTING
1187 int main(void)
1189 codecs_t *c;
1190 int i,j, nr_codecs, state;
1192 if (!(parse_codec_cfg("etc/codecs.conf")))
1193 return 0;
1194 if (!video_codecs)
1195 printf("no videoconfig.\n");
1196 if (!audio_codecs)
1197 printf("no audioconfig.\n");
1199 printf("videocodecs:\n");
1200 c = video_codecs;
1201 nr_codecs = nr_vcodecs;
1202 state = 0;
1203 next:
1204 if (c) {
1205 printf("number of %scodecs: %d\n", state==0?"video":"audio",
1206 nr_codecs);
1207 for(i=0;i<nr_codecs;i++, c++){
1208 printf("\n============== %scodec %02d ===============\n",
1209 state==0?"video":"audio",i);
1210 printf("name='%s'\n",c->name);
1211 printf("info='%s'\n",c->info);
1212 printf("comment='%s'\n",c->comment);
1213 printf("dll='%s'\n",c->dll);
1214 /* printf("flags=%X driver=%d status=%d cpuflags=%d\n",
1215 c->flags, c->driver, c->status, c->cpuflags); */
1216 printf("flags=%X status=%d cpuflags=%d\n",
1217 c->flags, c->status, c->cpuflags);
1219 for(j=0;j<CODECS_MAX_FOURCC;j++){
1220 if(c->fourcc[j]!=0xFFFFFFFF){
1221 printf("fourcc %02d: %08X (%.4s) ===> %08X (%.4s)\n",j,c->fourcc[j],(char *) &c->fourcc[j],c->fourccmap[j],(char *) &c->fourccmap[j]);
1225 for(j=0;j<CODECS_MAX_OUTFMT;j++){
1226 if(c->outfmt[j]!=0xFFFFFFFF){
1227 printf("outfmt %02d: %08X (%.4s) flags: %d\n",j,c->outfmt[j],(char *) &c->outfmt[j],c->outflags[j]);
1231 for(j=0;j<CODECS_MAX_INFMT;j++){
1232 if(c->infmt[j]!=0xFFFFFFFF){
1233 printf("infmt %02d: %08X (%.4s) flags: %d\n",j,c->infmt[j],(char *) &c->infmt[j],c->inflags[j]);
1237 printf("GUID: %08lX %04X %04X",c->guid.f1,c->guid.f2,c->guid.f3);
1238 for(j=0;j<8;j++) printf(" %02X",c->guid.f4[j]);
1239 printf("\n");
1244 if (!state) {
1245 printf("audiocodecs:\n");
1246 c = audio_codecs;
1247 nr_codecs = nr_acodecs;
1248 state = 1;
1249 goto next;
1251 return 0;
1254 #endif