Update MPlayer sources
[mplayer/kovensky.git] / codec-cfg.c
blob39a2f59a09c364941447032fcc6b1ce259924712
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
722 if (!strcmp(token[0], "align16"))
723 codec->flags |= CODECS_FLAG_ALIGN16;
724 else
725 goto err_out_parse_error;
726 } else if (!strcmp(token[0], "status")) {
727 if (get_token(1, 1) < 0)
728 goto err_out_parse_error;
729 if (!strcasecmp(token[0], "working"))
730 codec->status = CODECS_STATUS_WORKING;
731 else if (!strcasecmp(token[0], "crashing"))
732 codec->status = CODECS_STATUS_NOT_WORKING;
733 else if (!strcasecmp(token[0], "untested"))
734 codec->status = CODECS_STATUS_UNTESTED;
735 else if (!strcasecmp(token[0], "buggy"))
736 codec->status = CODECS_STATUS_PROBLEMS;
737 else
738 goto err_out_parse_error;
739 } else if (!strcmp(token[0], "cpuflags")) {
740 if (get_token(1, 1) < 0)
741 goto err_out_parse_error;
742 if (!(codec->cpuflags = get_cpuflags(token[0])))
743 goto err_out_parse_error;
744 } else
745 goto err_out_parse_error;
747 if (!validate_codec(codec, codec_type))
748 goto err_out_not_valid;
749 mp_tmsg(MSGT_CODECCFG,MSGL_INFO,"%d audio & %d video codecs\n", nr_acodecs, nr_vcodecs);
750 if(video_codecs) video_codecs[nr_vcodecs].name = NULL;
751 if(audio_codecs) audio_codecs[nr_acodecs].name = NULL;
752 out:
753 free(line);
754 line=NULL;
755 fclose(fp);
756 return 1;
758 err_out_parse_error:
759 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
760 err_out_print_linenum:
761 PRINT_LINENUM;
762 err_out:
763 codecs_uninit_free();
765 free(line);
766 line=NULL;
767 line_num = 0;
768 fclose(fp);
769 return 0;
770 err_out_not_valid:
771 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Codec is not defined correctly.");
772 goto err_out_print_linenum;
773 err_out_release_num:
774 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"This codecs.conf is too old and incompatible with this MPlayer release!");
775 goto err_out_print_linenum;
778 static void codecs_free(codecs_t* codecs,int count) {
779 int i;
780 for ( i = 0; i < count; i++)
781 if ( codecs[i].name ) {
782 if( codecs[i].name )
783 free(codecs[i].name);
784 if( codecs[i].info )
785 free(codecs[i].info);
786 if( codecs[i].comment )
787 free(codecs[i].comment);
788 if( codecs[i].dll )
789 free(codecs[i].dll);
790 if( codecs[i].drv )
791 free(codecs[i].drv);
793 if (codecs)
794 free(codecs);
797 void codecs_uninit_free(void) {
798 if (video_codecs)
799 codecs_free(video_codecs,nr_vcodecs);
800 video_codecs=NULL;
801 if (audio_codecs)
802 codecs_free(audio_codecs,nr_acodecs);
803 audio_codecs=NULL;
806 codecs_t *find_audio_codec(unsigned int fourcc, unsigned int *fourccmap,
807 codecs_t *start, int force)
809 return find_codec(fourcc, fourccmap, start, 1, force);
812 codecs_t *find_video_codec(unsigned int fourcc, unsigned int *fourccmap,
813 codecs_t *start, int force)
815 return find_codec(fourcc, fourccmap, start, 0, force);
818 codecs_t* find_codec(unsigned int fourcc,unsigned int *fourccmap,
819 codecs_t *start, int audioflag, int force)
821 int i, j;
822 codecs_t *c;
824 #if 0
825 if (start) {
826 for (/* NOTHING */; start->name; start++) {
827 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
828 if (start->fourcc[j] == fourcc) {
829 if (fourccmap)
830 *fourccmap = start->fourccmap[j];
831 return start;
835 } else
836 #endif
838 if (audioflag) {
839 i = nr_acodecs;
840 c = audio_codecs;
841 } else {
842 i = nr_vcodecs;
843 c = video_codecs;
845 if(!i) return NULL;
846 for (/* NOTHING */; i--; c++) {
847 if(start && c<=start) continue;
848 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
849 // FIXME: do NOT hardwire 'null' name here:
850 if (c->fourcc[j]==fourcc || !strcmp(c->drv,"null")) {
851 if (fourccmap)
852 *fourccmap = c->fourccmap[j];
853 return c;
856 if (force) return c;
859 return NULL;
862 void stringset_init(stringset_t *set) {
863 *set = calloc(1, sizeof(char *));
866 void stringset_free(stringset_t *set) {
867 int count = 0;
868 while ((*set)[count]) free((*set)[count++]);
869 free(*set);
870 *set = NULL;
873 void stringset_add(stringset_t *set, const char *str) {
874 int count = 0;
875 while ((*set)[count]) count++;
876 count++;
877 *set = realloc(*set, sizeof(char *) * (count + 1));
878 (*set)[count - 1] = strdup(str);
879 (*set)[count] = NULL;
882 int stringset_test(stringset_t *set, const char *str) {
883 stringset_t s;
884 for (s = *set; *s; s++)
885 if (strcmp(*s, str) == 0)
886 return 1;
887 return 0;
890 void list_codecs(int audioflag){
891 int i;
892 codecs_t *c;
894 if (audioflag) {
895 i = nr_acodecs;
896 c = audio_codecs;
897 mp_msg(MSGT_CODECCFG,MSGL_INFO,"ac: afm: status: info: [lib/dll]\n");
898 } else {
899 i = nr_vcodecs;
900 c = video_codecs;
901 mp_msg(MSGT_CODECCFG,MSGL_INFO,"vc: vfm: status: info: [lib/dll]\n");
903 if(!i) return;
904 for (/* NOTHING */; i--; c++) {
905 char* s="unknown ";
906 switch(c->status){
907 case CODECS_STATUS_WORKING: s="working ";break;
908 case CODECS_STATUS_PROBLEMS: s="problems";break;
909 case CODECS_STATUS_NOT_WORKING: s="crashing";break;
910 case CODECS_STATUS_UNTESTED: s="untested";break;
912 if(c->dll)
913 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s [%s]\n",c->name,c->drv,s,c->info,c->dll);
914 else
915 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s\n",c->name,c->drv,s,c->info);
923 #ifdef CODECS2HTML
924 void wrapline(FILE *f2,char *s){
925 int c;
926 if(!s){
927 fprintf(f2,"-");
928 return;
930 while((c=*s++)){
931 if(c==',') fprintf(f2,"<br>"); else fputc(c,f2);
935 void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
936 int c,d;
937 while((c=fgetc(f1))>=0){
938 if(c!='%'){
939 fputc(c,f2);
940 continue;
942 d=fgetc(f1);
944 switch(d){
945 case '.':
946 return; // end of section
947 case 'n':
948 wrapline(f2,codec->name); break;
949 case 'i':
950 wrapline(f2,codec->info); break;
951 case 'c':
952 wrapline(f2,codec->comment); break;
953 case 'd':
954 wrapline(f2,codec->dll); break;
955 case 'D':
956 fprintf(f2,"%c",!strcmp(codec->drv,"dshow")?'+':'-'); break;
957 case 'F':
958 for(d=0;d<CODECS_MAX_FOURCC;d++)
959 if(!d || codec->fourcc[d]!=0xFFFFFFFF)
960 fprintf(f2,"%s%.4s",d?"<br>":"",(codec->fourcc[d]==0xFFFFFFFF || codec->fourcc[d]<0x20202020)?!d?"-":"":(char*) &codec->fourcc[d]);
961 break;
962 case 'f':
963 for(d=0;d<CODECS_MAX_FOURCC;d++)
964 if(codec->fourcc[d]!=0xFFFFFFFF)
965 fprintf(f2,"%s0x%X",d?"<br>":"",codec->fourcc[d]);
966 break;
967 case 'Y':
968 for(d=0;d<CODECS_MAX_OUTFMT;d++)
969 if(codec->outfmt[d]!=0xFFFFFFFF){
970 for (c=0; fmt_table[c].name; c++)
971 if(fmt_table[c].num==codec->outfmt[d]) break;
972 if(fmt_table[c].name)
973 fprintf(f2,"%s%s",d?"<br>":"",fmt_table[c].name);
975 break;
976 default:
977 fputc(c,f2);
978 fputc(d,f2);
984 void skiphtml(FILE *f1){
985 int c,d;
986 while((c=fgetc(f1))>=0){
987 if(c!='%'){
988 continue;
990 d=fgetc(f1);
991 if(d=='.') return; // end of section
995 static void print_int_array(const unsigned int* a, int size)
997 printf("{ ");
998 while (size--)
999 if(abs(*a)<256)
1000 printf("%d%s", *a++, size?", ":"");
1001 else
1002 printf("0x%X%s", *a++, size?", ":"");
1003 printf(" }");
1006 static void print_char_array(const unsigned char* a, int size)
1008 printf("{ ");
1009 while (size--)
1010 if((*a)<10)
1011 printf("%d%s", *a++, size?", ":"");
1012 else
1013 printf("0x%02x%s", *a++, size?", ":"");
1014 printf(" }");
1017 static void print_string(const char* s)
1019 if (!s) printf("NULL");
1020 else printf("\"%s\"", s);
1023 int main(int argc, char* argv[])
1025 codecs_t *cl;
1026 FILE *f1;
1027 FILE *f2;
1028 int c,d,i;
1029 int pos;
1030 int section=-1;
1031 int nr_codecs;
1032 int win32=-1;
1033 int dshow=-1;
1034 int win32ex=-1;
1037 * Take path to codecs.conf from command line, or fall back on
1038 * etc/codecs.conf
1040 if (!(nr_codecs = parse_codec_cfg((argc>1)?argv[1]:"etc/codecs.conf")))
1041 exit(1);
1043 if (argc > 1) {
1044 int i, j;
1045 const char* nm[2];
1046 codecs_t* cod[2];
1047 int nr[2];
1049 nm[0] = "builtin_video_codecs";
1050 cod[0] = video_codecs;
1051 nr[0] = nr_vcodecs;
1053 nm[1] = "builtin_audio_codecs";
1054 cod[1] = audio_codecs;
1055 nr[1] = nr_acodecs;
1057 printf("/* GENERATED FROM %s, DO NOT EDIT! */\n\n",argv[1]);
1058 printf("#include <stddef.h>\n");
1059 printf("#include \"codec-cfg.h\"\n\n");
1061 for (i=0; i<2; i++) {
1062 printf("const codecs_t %s[] = {\n", nm[i]);
1063 for (j = 0; j < nr[i]; j++) {
1064 printf("{");
1066 print_int_array(cod[i][j].fourcc, CODECS_MAX_FOURCC);
1067 printf(", /* fourcc */\n");
1069 print_int_array(cod[i][j].fourccmap, CODECS_MAX_FOURCC);
1070 printf(", /* fourccmap */\n");
1072 print_int_array(cod[i][j].outfmt, CODECS_MAX_OUTFMT);
1073 printf(", /* outfmt */\n");
1075 print_char_array(cod[i][j].outflags, CODECS_MAX_OUTFMT);
1076 printf(", /* outflags */\n");
1078 print_int_array(cod[i][j].infmt, CODECS_MAX_INFMT);
1079 printf(", /* infmt */\n");
1081 print_char_array(cod[i][j].inflags, CODECS_MAX_INFMT);
1082 printf(", /* inflags */\n");
1084 print_string(cod[i][j].name); printf(", /* name */\n");
1085 print_string(cod[i][j].info); printf(", /* info */\n");
1086 print_string(cod[i][j].comment); printf(", /* comment */\n");
1087 print_string(cod[i][j].dll); printf(", /* dll */\n");
1088 print_string(cod[i][j].drv); printf(", /* drv */\n");
1090 printf("{ 0x%08lx, %hu, %hu,",
1091 cod[i][j].guid.f1,
1092 cod[i][j].guid.f2,
1093 cod[i][j].guid.f3);
1094 print_char_array(cod[i][j].guid.f4, sizeof(cod[i][j].guid.f4));
1095 printf(" }, /* GUID */\n");
1096 printf("%hd /* flags */, %hd /* status */, %hd /* cpuflags */ }\n",
1097 cod[i][j].flags,
1098 cod[i][j].status,
1099 cod[i][j].cpuflags);
1100 if (j < nr[i]) printf(",\n");
1102 printf("};\n\n");
1104 exit(0);
1107 f1=fopen("DOCS/tech/codecs-in.html","rb"); if(!f1) exit(1);
1108 f2=fopen("DOCS/codecs-status.html","wb"); if(!f2) exit(1);
1110 while((c=fgetc(f1))>=0){
1111 if(c!='%'){
1112 fputc(c,f2);
1113 continue;
1115 d=fgetc(f1);
1116 if(d>='0' && d<='9'){
1117 // begin section
1118 section=d-'0';
1119 //printf("BEGIN %d\n",section);
1120 if(section>=5){
1121 // audio
1122 cl = audio_codecs;
1123 nr_codecs = nr_acodecs;
1124 dshow=7;win32=4;
1125 } else {
1126 // video
1127 cl = video_codecs;
1128 nr_codecs = nr_vcodecs;
1129 dshow=4;win32=2;win32ex=6;
1131 pos=ftell(f1);
1132 for(i=0;i<nr_codecs;i++){
1133 fseek(f1,pos,SEEK_SET);
1134 switch(section){
1135 case 0:
1136 case 5:
1137 if(cl[i].status==CODECS_STATUS_WORKING)
1138 // if(!(!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1139 parsehtml(f1,f2,&cl[i],section,dshow);
1140 break;
1141 #if 0
1142 case 1:
1143 case 6:
1144 if(cl[i].status==CODECS_STATUS_WORKING)
1145 if((!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1146 parsehtml(f1,f2,&cl[i],section,dshow);
1147 break;
1148 #endif
1149 case 2:
1150 case 7:
1151 if(cl[i].status==CODECS_STATUS_PROBLEMS)
1152 parsehtml(f1,f2,&cl[i],section,dshow);
1153 break;
1154 case 3:
1155 case 8:
1156 if(cl[i].status==CODECS_STATUS_NOT_WORKING)
1157 parsehtml(f1,f2,&cl[i],section,dshow);
1158 break;
1159 case 4:
1160 case 9:
1161 if(cl[i].status==CODECS_STATUS_UNTESTED)
1162 parsehtml(f1,f2,&cl[i],section,dshow);
1163 break;
1164 default:
1165 printf("Warning! unimplemented section: %d\n",section);
1168 fseek(f1,pos,SEEK_SET);
1169 skiphtml(f1);
1170 //void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
1172 continue;
1174 fputc(c,f2);
1175 fputc(d,f2);
1178 fclose(f2);
1179 fclose(f1);
1180 return 0;
1183 #endif
1185 #ifdef TESTING
1186 int main(void)
1188 codecs_t *c;
1189 int i,j, nr_codecs, state;
1191 if (!(parse_codec_cfg("etc/codecs.conf")))
1192 return 0;
1193 if (!video_codecs)
1194 printf("no videoconfig.\n");
1195 if (!audio_codecs)
1196 printf("no audioconfig.\n");
1198 printf("videocodecs:\n");
1199 c = video_codecs;
1200 nr_codecs = nr_vcodecs;
1201 state = 0;
1202 next:
1203 if (c) {
1204 printf("number of %scodecs: %d\n", state==0?"video":"audio",
1205 nr_codecs);
1206 for(i=0;i<nr_codecs;i++, c++){
1207 printf("\n============== %scodec %02d ===============\n",
1208 state==0?"video":"audio",i);
1209 printf("name='%s'\n",c->name);
1210 printf("info='%s'\n",c->info);
1211 printf("comment='%s'\n",c->comment);
1212 printf("dll='%s'\n",c->dll);
1213 /* printf("flags=%X driver=%d status=%d cpuflags=%d\n",
1214 c->flags, c->driver, c->status, c->cpuflags); */
1215 printf("flags=%X status=%d cpuflags=%d\n",
1216 c->flags, c->status, c->cpuflags);
1218 for(j=0;j<CODECS_MAX_FOURCC;j++){
1219 if(c->fourcc[j]!=0xFFFFFFFF){
1220 printf("fourcc %02d: %08X (%.4s) ===> %08X (%.4s)\n",j,c->fourcc[j],(char *) &c->fourcc[j],c->fourccmap[j],(char *) &c->fourccmap[j]);
1224 for(j=0;j<CODECS_MAX_OUTFMT;j++){
1225 if(c->outfmt[j]!=0xFFFFFFFF){
1226 printf("outfmt %02d: %08X (%.4s) flags: %d\n",j,c->outfmt[j],(char *) &c->outfmt[j],c->outflags[j]);
1230 for(j=0;j<CODECS_MAX_INFMT;j++){
1231 if(c->infmt[j]!=0xFFFFFFFF){
1232 printf("infmt %02d: %08X (%.4s) flags: %d\n",j,c->infmt[j],(char *) &c->infmt[j],c->inflags[j]);
1236 printf("GUID: %08lX %04X %04X",c->guid.f1,c->guid.f2,c->guid.f3);
1237 for(j=0;j<8;j++) printf(" %02X",c->guid.f4[j]);
1238 printf("\n");
1243 if (!state) {
1244 printf("audiocodecs:\n");
1245 c = audio_codecs;
1246 nr_codecs = nr_acodecs;
1247 state = 1;
1248 goto next;
1250 return 0;
1253 #endif