codecs_conf: Add FFmpeg VP8 decoder
[mplayer/glamo.git] / codec-cfg.c
blobeffc775d4c2e903380edf1b2b31b622a5b46d015
1 /*
2 * codec.conf parser
4 * to compile test application:
5 * cc -I. -DTESTING -o codec-cfg-test codec-cfg.c mp_msg.o osdep/getch2.o -ltermcap
6 * to compile CODECS2HTML:
7 * gcc -DCODECS2HTML -o codecs2html codec-cfg.c mp_msg.o
9 * TODO: implement informat in CODECS2HTML too
11 * Copyright (C) 2001 Szabolcs Berecz <szabi@inf.elte.hu>
13 * This file is part of MPlayer.
15 * MPlayer is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * MPlayer is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License along
26 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #define DEBUG
32 //disable asserts
33 #define NDEBUG
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <errno.h>
40 #include <ctype.h>
41 #include <assert.h>
42 #include <string.h>
43 #include <stdint.h>
45 #include "config.h"
46 #include "mp_msg.h"
47 #ifdef CODECS2HTML
48 #define mp_tmsg mp_msg
49 #ifdef __GNUC__
50 #define mp_msg(t, l, m, args...) fprintf(stderr, m, ##args)
51 #else
52 #define mp_msg(t, l, ...) fprintf(stderr, __VA_ARGS__)
53 #endif
54 #endif
57 #include "libmpcodecs/img_format.h"
58 #include "codec-cfg.h"
60 #ifdef CODECS2HTML
61 #define CODEC_CFG_MIN 20100000
62 #else
63 #include "codecs.conf.h"
64 #endif
66 #define mmioFOURCC( ch0, ch1, ch2, ch3 ) \
67 ( (uint32_t)(uint8_t)(ch0) | ( (uint32_t)(uint8_t)(ch1) << 8 ) | \
68 ( (uint32_t)(uint8_t)(ch2) << 16 ) | ( (uint32_t)(uint8_t)(ch3) << 24 ) )
70 #define PRINT_LINENUM mp_msg(MSGT_CODECCFG,MSGL_ERR," at line %d\n", line_num)
72 #define MAX_NR_TOKEN 16
74 #define MAX_LINE_LEN 1000
76 #define RET_EOF -1
77 #define RET_EOL -2
79 #define TYPE_VIDEO 0
80 #define TYPE_AUDIO 1
82 static int codecs_conf_release;
83 char * codecs_file = NULL;
85 static int add_to_fourcc(char *s, char *alias, unsigned int *fourcc,
86 unsigned int *map)
88 int i, j, freeslots;
89 unsigned int tmp;
91 /* find first unused slot */
92 for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++)
93 /* NOTHING */;
94 freeslots = CODECS_MAX_FOURCC - i;
95 if (!freeslots)
96 goto err_out_too_many;
98 do {
99 tmp = mmioFOURCC(s[0], s[1], s[2], s[3]);
100 for (j = 0; j < i; j++)
101 if (tmp == fourcc[j])
102 goto err_out_duplicated;
103 fourcc[i] = tmp;
104 map[i] = alias ? mmioFOURCC(alias[0], alias[1], alias[2], alias[3]) : tmp;
105 s += 4;
106 i++;
107 } while ((*(s++) == ',') && --freeslots);
109 if (!freeslots)
110 goto err_out_too_many;
111 if (*(--s) != '\0')
112 goto err_out_parse_error;
113 return 1;
114 err_out_duplicated:
115 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"duplicated FourCC");
116 return 0;
117 err_out_too_many:
118 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"too many FourCCs/formats...");
119 return 0;
120 err_out_parse_error:
121 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
122 return 0;
125 static int add_to_format(char *s, char *alias,unsigned int *fourcc, unsigned int *fourccmap)
127 int i, j;
128 char *endptr;
130 /* find first unused slot */
131 for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++)
132 /* NOTHING */;
133 if (i == CODECS_MAX_FOURCC) {
134 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"too many FourCCs/formats...");
135 return 0;
138 fourcc[i]=strtoul(s,&endptr,0);
139 if (*endptr != '\0') {
140 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error (format ID not a number?)");
141 return 0;
144 if(alias){
145 fourccmap[i]=strtoul(alias,&endptr,0);
146 if (*endptr != '\0') {
147 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error (format ID alias not a number?)");
148 return 0;
150 } else
151 fourccmap[i]=fourcc[i];
153 for (j = 0; j < i; j++)
154 if (fourcc[j] == fourcc[i]) {
155 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"duplicated format ID");
156 return 0;
159 return 1;
162 static const struct {
163 const char *name;
164 const unsigned int num;
165 } fmt_table[] = {
166 // note: due to parser deficiencies/simplicity, if one format
167 // name matches the beginning of another, the longer one _must_
168 // come first in this list.
169 {"YV12", IMGFMT_YV12},
170 {"I420", IMGFMT_I420},
171 {"IYUV", IMGFMT_IYUV},
172 {"NV12", IMGFMT_NV12},
173 {"NV21", IMGFMT_NV21},
174 {"YVU9", IMGFMT_YVU9},
175 {"IF09", IMGFMT_IF09},
176 {"444P16LE", IMGFMT_444P16_LE},
177 {"444P16BE", IMGFMT_444P16_BE},
178 {"422P16LE", IMGFMT_422P16_LE},
179 {"422P16BE", IMGFMT_422P16_BE},
180 {"420P16LE", IMGFMT_420P16_LE},
181 {"420P16BE", IMGFMT_420P16_BE},
182 {"444P16", IMGFMT_444P16},
183 {"422P16", IMGFMT_422P16},
184 {"420P16", IMGFMT_420P16},
185 {"420A", IMGFMT_420A},
186 {"444P", IMGFMT_444P},
187 {"422P", IMGFMT_422P},
188 {"411P", IMGFMT_411P},
189 {"440P", IMGFMT_440P},
190 {"Y800", IMGFMT_Y800},
191 {"Y8", IMGFMT_Y8},
193 {"YUY2", IMGFMT_YUY2},
194 {"UYVY", IMGFMT_UYVY},
195 {"YVYU", IMGFMT_YVYU},
197 {"RGB48LE", IMGFMT_RGB48LE},
198 {"RGB48BE", IMGFMT_RGB48BE},
199 {"RGB4", IMGFMT_RGB4},
200 {"RGB8", IMGFMT_RGB8},
201 {"RGB15", IMGFMT_RGB15},
202 {"RGB16", IMGFMT_RGB16},
203 {"RGB24", IMGFMT_RGB24},
204 {"RGB32", IMGFMT_RGB32},
205 {"BGR4", IMGFMT_BGR4},
206 {"BGR8", IMGFMT_BGR8},
207 {"BGR15", IMGFMT_BGR15},
208 {"BGR16", IMGFMT_BGR16},
209 {"BGR24", IMGFMT_BGR24},
210 {"BGR32", IMGFMT_BGR32},
211 {"RGB1", IMGFMT_RGB1},
212 {"BGR1", IMGFMT_BGR1},
214 {"MPES", IMGFMT_MPEGPES},
215 {"ZRMJPEGNI", IMGFMT_ZRMJPEGNI},
216 {"ZRMJPEGIT", IMGFMT_ZRMJPEGIT},
217 {"ZRMJPEGIB", IMGFMT_ZRMJPEGIB},
219 {"IDCT_MPEG2",IMGFMT_XVMC_IDCT_MPEG2},
220 {"MOCO_MPEG2",IMGFMT_XVMC_MOCO_MPEG2},
222 {"VDPAU_MPEG1",IMGFMT_VDPAU_MPEG1},
223 {"VDPAU_MPEG2",IMGFMT_VDPAU_MPEG2},
224 {"VDPAU_H264",IMGFMT_VDPAU_H264},
225 {"VDPAU_WMV3",IMGFMT_VDPAU_WMV3},
226 {"VDPAU_VC1",IMGFMT_VDPAU_VC1},
227 {"VDPAU_MPEG4",IMGFMT_VDPAU_MPEG4},
229 {NULL, 0}
233 static int add_to_inout(char *sfmt, char *sflags, unsigned int *outfmt,
234 unsigned char *outflags)
237 static char *flagstr[] = {
238 "flip",
239 "noflip",
240 "yuvhack",
241 "query",
242 "static",
243 NULL
246 int i, j, freeslots;
247 unsigned char flags;
249 for (i = 0; i < CODECS_MAX_OUTFMT && outfmt[i] != 0xffffffff; i++)
250 /* NOTHING */;
251 freeslots = CODECS_MAX_OUTFMT - i;
252 if (!freeslots)
253 goto err_out_too_many;
255 flags = 0;
256 if(sflags) {
257 do {
258 for (j = 0; flagstr[j] != NULL; j++)
259 if (!strncmp(sflags, flagstr[j],
260 strlen(flagstr[j])))
261 break;
262 if (flagstr[j] == NULL)
263 goto err_out_parse_error;
264 flags|=(1<<j);
265 sflags+=strlen(flagstr[j]);
266 } while (*(sflags++) == ',');
268 if (*(--sflags) != '\0')
269 goto err_out_parse_error;
272 do {
273 for (j = 0; fmt_table[j].name != NULL; j++)
274 if (!strncmp(sfmt, fmt_table[j].name, strlen(fmt_table[j].name)))
275 break;
276 if (fmt_table[j].name == NULL)
277 goto err_out_parse_error;
278 outfmt[i] = fmt_table[j].num;
279 outflags[i] = flags;
280 ++i;
281 sfmt+=strlen(fmt_table[j].name);
282 } while ((*(sfmt++) == ',') && --freeslots);
284 if (!freeslots)
285 goto err_out_too_many;
287 if (*(--sfmt) != '\0')
288 goto err_out_parse_error;
290 return 1;
291 err_out_too_many:
292 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"too many out...");
293 return 0;
294 err_out_parse_error:
295 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
296 return 0;
299 #if 0
300 static short get_driver(char *s,int audioflag)
302 static char *audiodrv[] = {
303 "null",
304 "mp3lib",
305 "pcm",
306 "libac3",
307 "acm",
308 "alaw",
309 "msgsm",
310 "dshow",
311 "dvdpcm",
312 "hwac3",
313 "libvorbis",
314 "ffmpeg",
315 "libmad",
316 "msadpcm",
317 "liba52",
318 "g72x",
319 "imaadpcm",
320 "dk4adpcm",
321 "dk3adpcm",
322 "roqaudio",
323 "faad",
324 "realaud",
325 "libdv",
326 NULL
328 static char *videodrv[] = {
329 "null",
330 "libmpeg2",
331 "vfw",
332 "dshow",
333 "ffmpeg",
334 "vfwex",
335 "raw",
336 "msrle",
337 "xanim",
338 "msvidc",
339 "fli",
340 "cinepak",
341 "qtrle",
342 "nuv",
343 "cyuv",
344 "qtsmc",
345 "ducktm1",
346 "roqvideo",
347 "qtrpza",
348 "mpng",
349 "ijpg",
350 "zlib",
351 "mpegpes",
352 "zrmjpeg",
353 "realvid",
354 "xvid",
355 "libdv",
356 NULL
358 char **drv=audioflag?audiodrv:videodrv;
359 int i;
361 for(i=0;drv[i];i++) if(!strcmp(s,drv[i])) return i;
363 return -1;
365 #endif
367 static int validate_codec(codecs_t *c, int type)
369 unsigned int i;
370 char *tmp_name = c->name;
372 for (i = 0; i < strlen(tmp_name) && isalnum(tmp_name[i]); i++)
373 /* NOTHING */;
375 if (i < strlen(tmp_name)) {
376 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) name is not valid!\n", c->name);
377 return 0;
380 if (!c->info)
381 c->info = strdup(c->name);
383 #if 0
384 if (c->fourcc[0] == 0xffffffff) {
385 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) does not have FourCC/format!\n", c->name);
386 return 0;
388 #endif
390 if (!c->drv) {
391 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) does not have a driver!\n", c->name);
392 return 0;
395 #if 0
396 #warning codec->driver == 4;... <- this should not be put in here...
397 #warning Where are they defined ????????????
398 if (!c->dll && (c->driver == 4 ||
399 (c->driver == 2 && type == TYPE_VIDEO))) {
400 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) needs a 'dll'!\n", c->name);
401 return 0;
403 #warning Can guid.f1 be 0? How does one know that it was not given?
404 // if (!(codec->flags & CODECS_FLAG_AUDIO) && codec->driver == 4)
406 if (type == TYPE_VIDEO)
407 if (c->outfmt[0] == 0xffffffff) {
408 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) needs an 'outfmt'!\n", c->name);
409 return 0;
411 #endif
412 return 1;
415 static int add_comment(char *s, char **d)
417 int pos;
419 if (!*d)
420 pos = 0;
421 else {
422 pos = strlen(*d);
423 (*d)[pos++] = '\n';
425 if (!(*d = realloc(*d, pos + strlen(s) + 1))) {
426 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't allocate memory for comment. ");
427 return 0;
429 strcpy(*d + pos, s);
430 return 1;
433 static short get_cpuflags(char *s)
435 static char *flagstr[] = {
436 "mmx",
437 "sse",
438 "3dnow",
439 NULL
441 int i;
442 short flags = 0;
444 do {
445 for (i = 0; flagstr[i]; i++)
446 if (!strncmp(s, flagstr[i], strlen(flagstr[i])))
447 break;
448 if (!flagstr[i])
449 goto err_out_parse_error;
450 flags |= 1<<i;
451 s += strlen(flagstr[i]);
452 } while (*(s++) == ',');
454 if (*(--s) != '\0')
455 goto err_out_parse_error;
457 return flags;
458 err_out_parse_error:
459 return 0;
462 static FILE *fp;
463 static int line_num = 0;
464 static char *line;
465 static char *token[MAX_NR_TOKEN];
466 static int read_nextline = 1;
468 static int get_token(int min, int max)
470 static int line_pos;
471 int i;
472 char c;
474 if (max >= MAX_NR_TOKEN) {
475 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"get_token(): max >= MAX_MR_TOKEN!");
476 goto out_eof;
479 memset(token, 0x00, sizeof(*token) * max);
481 if (read_nextline) {
482 if (!fgets(line, MAX_LINE_LEN, fp))
483 goto out_eof;
484 line_pos = 0;
485 ++line_num;
486 read_nextline = 0;
488 for (i = 0; i < max; i++) {
489 while (isspace(line[line_pos]))
490 ++line_pos;
491 if (line[line_pos] == '\0' || line[line_pos] == '#' ||
492 line[line_pos] == ';') {
493 read_nextline = 1;
494 if (i >= min)
495 goto out_ok;
496 goto out_eol;
498 token[i] = line + line_pos;
499 c = line[line_pos];
500 if (c == '"' || c == '\'') {
501 token[i]++;
502 while (line[++line_pos] != c && line[line_pos])
503 /* NOTHING */;
504 } else {
505 for (/* NOTHING */; !isspace(line[line_pos]) &&
506 line[line_pos]; line_pos++)
507 /* NOTHING */;
509 if (!line[line_pos]) {
510 read_nextline = 1;
511 if (i >= min - 1)
512 goto out_ok;
513 goto out_eol;
515 line[line_pos] = '\0';
516 line_pos++;
518 out_ok:
519 return i;
520 out_eof:
521 read_nextline = 1;
522 return RET_EOF;
523 out_eol:
524 return RET_EOL;
527 static codecs_t *video_codecs=NULL;
528 static codecs_t *audio_codecs=NULL;
529 static int nr_vcodecs = 0;
530 static int nr_acodecs = 0;
532 int parse_codec_cfg(const char *cfgfile)
534 codecs_t *codec = NULL; // current codec
535 codecs_t **codecsp = NULL;// points to audio_codecs or to video_codecs
536 char *endptr; // strtoul()...
537 int *nr_codecsp;
538 int codec_type; /* TYPE_VIDEO/TYPE_AUDIO */
539 int tmp, i;
541 // in case we call it a second time
542 codecs_uninit_free();
544 nr_vcodecs = 0;
545 nr_acodecs = 0;
547 if(cfgfile==NULL) {
548 #ifdef CODECS2HTML
549 return 0;
550 #else
551 video_codecs = builtin_video_codecs;
552 audio_codecs = builtin_audio_codecs;
553 nr_vcodecs = sizeof(builtin_video_codecs)/sizeof(codecs_t);
554 nr_acodecs = sizeof(builtin_audio_codecs)/sizeof(codecs_t);
555 return 1;
556 #endif
559 mp_tmsg(MSGT_CODECCFG,MSGL_V,"Reading %s: ", cfgfile);
561 if ((fp = fopen(cfgfile, "r")) == NULL) {
562 mp_tmsg(MSGT_CODECCFG,MSGL_V,"Can't open '%s': %s\n", cfgfile, strerror(errno));
563 return 0;
566 if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) {
567 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't get memory for 'line': %s\n", strerror(errno));
568 return 0;
570 read_nextline = 1;
573 * this only catches release lines at the start of
574 * codecs.conf, before audiocodecs and videocodecs.
576 while ((tmp = get_token(1, 1)) == RET_EOL)
577 /* NOTHING */;
578 if (tmp == RET_EOF)
579 goto out;
580 if (!strcmp(token[0], "release")) {
581 if (get_token(1, 2) < 0)
582 goto err_out_parse_error;
583 tmp = atoi(token[0]);
584 if (tmp < CODEC_CFG_MIN)
585 goto err_out_release_num;
586 codecs_conf_release = tmp;
587 while ((tmp = get_token(1, 1)) == RET_EOL)
588 /* NOTHING */;
589 if (tmp == RET_EOF)
590 goto out;
591 } else
592 goto err_out_release_num;
595 * check if the next block starts with 'audiocodec' or
596 * with 'videocodec'
598 if (!strcmp(token[0], "audiocodec") || !strcmp(token[0], "videocodec"))
599 goto loop_enter;
600 goto err_out_parse_error;
602 while ((tmp = get_token(1, 1)) != RET_EOF) {
603 if (tmp == RET_EOL)
604 continue;
605 if (!strcmp(token[0], "audiocodec") ||
606 !strcmp(token[0], "videocodec")) {
607 if (!validate_codec(codec, codec_type))
608 goto err_out_not_valid;
609 loop_enter:
610 if (*token[0] == 'v') {
611 codec_type = TYPE_VIDEO;
612 nr_codecsp = &nr_vcodecs;
613 codecsp = &video_codecs;
614 } else if (*token[0] == 'a') {
615 codec_type = TYPE_AUDIO;
616 nr_codecsp = &nr_acodecs;
617 codecsp = &audio_codecs;
618 #ifdef DEBUG
619 } else {
620 mp_msg(MSGT_CODECCFG,MSGL_ERR,"picsba\n");
621 goto err_out;
622 #endif
624 if (!(*codecsp = realloc(*codecsp,
625 sizeof(codecs_t) * (*nr_codecsp + 2)))) {
626 mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't realloc '*codecsp': %s\n", strerror(errno));
627 goto err_out;
629 codec=*codecsp + *nr_codecsp;
630 ++*nr_codecsp;
631 memset(codec,0,sizeof(codecs_t));
632 memset(codec->fourcc, 0xff, sizeof(codec->fourcc));
633 memset(codec->outfmt, 0xff, sizeof(codec->outfmt));
634 memset(codec->infmt, 0xff, sizeof(codec->infmt));
636 if (get_token(1, 1) < 0)
637 goto err_out_parse_error;
638 for (i = 0; i < *nr_codecsp - 1; i++) {
639 if(( (*codecsp)[i].name!=NULL) &&
640 (!strcmp(token[0], (*codecsp)[i].name)) ) {
641 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Codec name '%s' isn't unique.", token[0]);
642 goto err_out_print_linenum;
645 if (!(codec->name = strdup(token[0]))) {
646 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'name': %s\n", strerror(errno));
647 goto err_out;
649 } else if (!strcmp(token[0], "info")) {
650 if (codec->info || get_token(1, 1) < 0)
651 goto err_out_parse_error;
652 if (!(codec->info = strdup(token[0]))) {
653 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'info': %s\n", strerror(errno));
654 goto err_out;
656 } else if (!strcmp(token[0], "comment")) {
657 if (get_token(1, 1) < 0)
658 goto err_out_parse_error;
659 add_comment(token[0], &codec->comment);
660 } else if (!strcmp(token[0], "fourcc")) {
661 if (get_token(1, 2) < 0)
662 goto err_out_parse_error;
663 if (!add_to_fourcc(token[0], token[1],
664 codec->fourcc,
665 codec->fourccmap))
666 goto err_out_print_linenum;
667 } else if (!strcmp(token[0], "format")) {
668 if (get_token(1, 2) < 0)
669 goto err_out_parse_error;
670 if (!add_to_format(token[0], token[1],
671 codec->fourcc,codec->fourccmap))
672 goto err_out_print_linenum;
673 } else if (!strcmp(token[0], "driver")) {
674 if (get_token(1, 1) < 0)
675 goto err_out_parse_error;
676 if (!(codec->drv = strdup(token[0]))) {
677 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'driver': %s\n", strerror(errno));
678 goto err_out;
680 } else if (!strcmp(token[0], "dll")) {
681 if (get_token(1, 1) < 0)
682 goto err_out_parse_error;
683 if (!(codec->dll = strdup(token[0]))) {
684 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Can't strdup -> 'dll': %s", strerror(errno));
685 goto err_out;
687 } else if (!strcmp(token[0], "guid")) {
688 if (get_token(11, 11) < 0)
689 goto err_out_parse_error;
690 codec->guid.f1=strtoul(token[0],&endptr,0);
691 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
692 *endptr != '\0')
693 goto err_out_parse_error;
694 codec->guid.f2=strtoul(token[1],&endptr,0);
695 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
696 *endptr != '\0')
697 goto err_out_parse_error;
698 codec->guid.f3=strtoul(token[2],&endptr,0);
699 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
700 *endptr != '\0')
701 goto err_out_parse_error;
702 for (i = 0; i < 8; i++) {
703 codec->guid.f4[i]=strtoul(token[i + 3],&endptr,0);
704 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
705 *endptr != '\0')
706 goto err_out_parse_error;
708 } else if (!strcmp(token[0], "out")) {
709 if (get_token(1, 2) < 0)
710 goto err_out_parse_error;
711 if (!add_to_inout(token[0], token[1], codec->outfmt,
712 codec->outflags))
713 goto err_out_print_linenum;
714 } else if (!strcmp(token[0], "in")) {
715 if (get_token(1, 2) < 0)
716 goto err_out_parse_error;
717 if (!add_to_inout(token[0], token[1], codec->infmt,
718 codec->inflags))
719 goto err_out_print_linenum;
720 } else if (!strcmp(token[0], "flags")) {
721 if (get_token(1, 1) < 0)
722 goto err_out_parse_error;
723 if (!strcmp(token[0], "seekable"))
724 codec->flags |= CODECS_FLAG_SEEKABLE;
725 else if (!strcmp(token[0], "align16"))
726 codec->flags |= CODECS_FLAG_ALIGN16;
727 else
728 goto err_out_parse_error;
729 } else if (!strcmp(token[0], "status")) {
730 if (get_token(1, 1) < 0)
731 goto err_out_parse_error;
732 if (!strcasecmp(token[0], "working"))
733 codec->status = CODECS_STATUS_WORKING;
734 else if (!strcasecmp(token[0], "crashing"))
735 codec->status = CODECS_STATUS_NOT_WORKING;
736 else if (!strcasecmp(token[0], "untested"))
737 codec->status = CODECS_STATUS_UNTESTED;
738 else if (!strcasecmp(token[0], "buggy"))
739 codec->status = CODECS_STATUS_PROBLEMS;
740 else
741 goto err_out_parse_error;
742 } else if (!strcmp(token[0], "cpuflags")) {
743 if (get_token(1, 1) < 0)
744 goto err_out_parse_error;
745 if (!(codec->cpuflags = get_cpuflags(token[0])))
746 goto err_out_parse_error;
747 } else
748 goto err_out_parse_error;
750 if (!validate_codec(codec, codec_type))
751 goto err_out_not_valid;
752 mp_tmsg(MSGT_CODECCFG,MSGL_INFO,"%d audio & %d video codecs\n", nr_acodecs, nr_vcodecs);
753 if(video_codecs) video_codecs[nr_vcodecs].name = NULL;
754 if(audio_codecs) audio_codecs[nr_acodecs].name = NULL;
755 out:
756 free(line);
757 line=NULL;
758 fclose(fp);
759 return 1;
761 err_out_parse_error:
762 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error");
763 err_out_print_linenum:
764 PRINT_LINENUM;
765 err_out:
766 codecs_uninit_free();
768 free(line);
769 line=NULL;
770 line_num = 0;
771 fclose(fp);
772 return 0;
773 err_out_not_valid:
774 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"Codec is not defined correctly.");
775 goto err_out_print_linenum;
776 err_out_release_num:
777 mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"This codecs.conf is too old and incompatible with this MPlayer release!");
778 goto err_out_print_linenum;
781 static void codecs_free(codecs_t* codecs,int count) {
782 int i;
783 for ( i = 0; i < count; i++)
784 if ( codecs[i].name ) {
785 if( codecs[i].name )
786 free(codecs[i].name);
787 if( codecs[i].info )
788 free(codecs[i].info);
789 if( codecs[i].comment )
790 free(codecs[i].comment);
791 if( codecs[i].dll )
792 free(codecs[i].dll);
793 if( codecs[i].drv )
794 free(codecs[i].drv);
796 if (codecs)
797 free(codecs);
800 void codecs_uninit_free(void) {
801 if (video_codecs)
802 codecs_free(video_codecs,nr_vcodecs);
803 video_codecs=NULL;
804 if (audio_codecs)
805 codecs_free(audio_codecs,nr_acodecs);
806 audio_codecs=NULL;
809 codecs_t *find_audio_codec(unsigned int fourcc, unsigned int *fourccmap,
810 codecs_t *start, int force)
812 return find_codec(fourcc, fourccmap, start, 1, force);
815 codecs_t *find_video_codec(unsigned int fourcc, unsigned int *fourccmap,
816 codecs_t *start, int force)
818 return find_codec(fourcc, fourccmap, start, 0, force);
821 codecs_t* find_codec(unsigned int fourcc,unsigned int *fourccmap,
822 codecs_t *start, int audioflag, int force)
824 int i, j;
825 codecs_t *c;
827 #if 0
828 if (start) {
829 for (/* NOTHING */; start->name; start++) {
830 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
831 if (start->fourcc[j] == fourcc) {
832 if (fourccmap)
833 *fourccmap = start->fourccmap[j];
834 return start;
838 } else
839 #endif
841 if (audioflag) {
842 i = nr_acodecs;
843 c = audio_codecs;
844 } else {
845 i = nr_vcodecs;
846 c = video_codecs;
848 if(!i) return NULL;
849 for (/* NOTHING */; i--; c++) {
850 if(start && c<=start) continue;
851 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
852 // FIXME: do NOT hardwire 'null' name here:
853 if (c->fourcc[j]==fourcc || !strcmp(c->drv,"null")) {
854 if (fourccmap)
855 *fourccmap = c->fourccmap[j];
856 return c;
859 if (force) return c;
862 return NULL;
865 void stringset_init(stringset_t *set) {
866 *set = calloc(1, sizeof(char *));
869 void stringset_free(stringset_t *set) {
870 int count = 0;
871 while ((*set)[count]) free((*set)[count++]);
872 free(*set);
873 *set = NULL;
876 void stringset_add(stringset_t *set, const char *str) {
877 int count = 0;
878 while ((*set)[count]) count++;
879 count++;
880 *set = realloc(*set, sizeof(char *) * (count + 1));
881 (*set)[count - 1] = strdup(str);
882 (*set)[count] = NULL;
885 int stringset_test(stringset_t *set, const char *str) {
886 stringset_t s;
887 for (s = *set; *s; s++)
888 if (strcmp(*s, str) == 0)
889 return 1;
890 return 0;
893 void list_codecs(int audioflag){
894 int i;
895 codecs_t *c;
897 if (audioflag) {
898 i = nr_acodecs;
899 c = audio_codecs;
900 mp_msg(MSGT_CODECCFG,MSGL_INFO,"ac: afm: status: info: [lib/dll]\n");
901 } else {
902 i = nr_vcodecs;
903 c = video_codecs;
904 mp_msg(MSGT_CODECCFG,MSGL_INFO,"vc: vfm: status: info: [lib/dll]\n");
906 if(!i) return;
907 for (/* NOTHING */; i--; c++) {
908 char* s="unknown ";
909 switch(c->status){
910 case CODECS_STATUS_WORKING: s="working ";break;
911 case CODECS_STATUS_PROBLEMS: s="problems";break;
912 case CODECS_STATUS_NOT_WORKING: s="crashing";break;
913 case CODECS_STATUS_UNTESTED: s="untested";break;
915 if(c->dll)
916 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s [%s]\n",c->name,c->drv,s,c->info,c->dll);
917 else
918 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s\n",c->name,c->drv,s,c->info);
923 #ifdef CODECS2HTML
924 static 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 static void parsehtml(FILE *f1,FILE *f2,codecs_t *codec){
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);
983 void skiphtml(FILE *f1){
984 int c,d;
985 while((c=fgetc(f1))>=0){
986 if(c!='%'){
987 continue;
989 d=fgetc(f1);
990 if(d=='.') return; // end of section
994 static void print_int_array(const unsigned int* a, int size)
996 printf("{ ");
997 while (size--)
998 if(abs(*a)<256)
999 printf("%d%s", *a++, size?", ":"");
1000 else
1001 printf("0x%X%s", *a++, size?", ":"");
1002 printf(" }");
1005 static void print_char_array(const unsigned char* a, int size)
1007 printf("{ ");
1008 while (size--)
1009 if((*a)<10)
1010 printf("%d%s", *a++, size?", ":"");
1011 else
1012 printf("0x%02x%s", *a++, size?", ":"");
1013 printf(" }");
1016 static void print_string(const char* s)
1018 if (!s) printf("NULL");
1019 else printf("\"%s\"", s);
1022 int main(int argc, char* argv[])
1024 codecs_t *cl;
1025 FILE *f1;
1026 FILE *f2;
1027 int c,d,i;
1028 int pos;
1029 int section=-1;
1030 int nr_codecs;
1031 int win32=-1;
1032 int dshow=-1;
1033 int win32ex=-1;
1036 * Take path to codecs.conf from command line, or fall back on
1037 * etc/codecs.conf
1039 if (!(nr_codecs = parse_codec_cfg((argc>1)?argv[1]:"etc/codecs.conf")))
1040 exit(1);
1041 if (codecs_conf_release < CODEC_CFG_MIN)
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");
1061 printf("#define CODEC_CFG_MIN %i\n\n", codecs_conf_release);
1063 for (i=0; i<2; i++) {
1064 printf("const codecs_t %s[] = {\n", nm[i]);
1065 for (j = 0; j < nr[i]; j++) {
1066 printf("{");
1068 print_int_array(cod[i][j].fourcc, CODECS_MAX_FOURCC);
1069 printf(", /* fourcc */\n");
1071 print_int_array(cod[i][j].fourccmap, CODECS_MAX_FOURCC);
1072 printf(", /* fourccmap */\n");
1074 print_int_array(cod[i][j].outfmt, CODECS_MAX_OUTFMT);
1075 printf(", /* outfmt */\n");
1077 print_char_array(cod[i][j].outflags, CODECS_MAX_OUTFMT);
1078 printf(", /* outflags */\n");
1080 print_int_array(cod[i][j].infmt, CODECS_MAX_INFMT);
1081 printf(", /* infmt */\n");
1083 print_char_array(cod[i][j].inflags, CODECS_MAX_INFMT);
1084 printf(", /* inflags */\n");
1086 print_string(cod[i][j].name); printf(", /* name */\n");
1087 print_string(cod[i][j].info); printf(", /* info */\n");
1088 print_string(cod[i][j].comment); printf(", /* comment */\n");
1089 print_string(cod[i][j].dll); printf(", /* dll */\n");
1090 print_string(cod[i][j].drv); printf(", /* drv */\n");
1092 printf("{ 0x%08lx, %hu, %hu,",
1093 cod[i][j].guid.f1,
1094 cod[i][j].guid.f2,
1095 cod[i][j].guid.f3);
1096 print_char_array(cod[i][j].guid.f4, sizeof(cod[i][j].guid.f4));
1097 printf(" }, /* GUID */\n");
1098 printf("%hd /* flags */, %hd /* status */, %hd /* cpuflags */ }\n",
1099 cod[i][j].flags,
1100 cod[i][j].status,
1101 cod[i][j].cpuflags);
1102 if (j < nr[i]) printf(",\n");
1104 printf("};\n\n");
1106 exit(0);
1109 f1=fopen("DOCS/tech/codecs-in.html","rb"); if(!f1) exit(1);
1110 f2=fopen("DOCS/codecs-status.html","wb"); if(!f2) exit(1);
1112 while((c=fgetc(f1))>=0){
1113 if(c!='%'){
1114 fputc(c,f2);
1115 continue;
1117 d=fgetc(f1);
1118 if(d>='0' && d<='9'){
1119 // begin section
1120 section=d-'0';
1121 //printf("BEGIN %d\n",section);
1122 if(section>=5){
1123 // audio
1124 cl = audio_codecs;
1125 nr_codecs = nr_acodecs;
1126 dshow=7;win32=4;
1127 } else {
1128 // video
1129 cl = video_codecs;
1130 nr_codecs = nr_vcodecs;
1131 dshow=4;win32=2;win32ex=6;
1133 pos=ftell(f1);
1134 for(i=0;i<nr_codecs;i++){
1135 fseek(f1,pos,SEEK_SET);
1136 switch(section){
1137 case 0:
1138 case 5:
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]);
1142 break;
1143 #if 0
1144 case 1:
1145 case 6:
1146 if(cl[i].status==CODECS_STATUS_WORKING)
1147 if((!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1148 parsehtml(f1,f2,&cl[i]);
1149 break;
1150 #endif
1151 case 2:
1152 case 7:
1153 if(cl[i].status==CODECS_STATUS_PROBLEMS)
1154 parsehtml(f1,f2,&cl[i]);
1155 break;
1156 case 3:
1157 case 8:
1158 if(cl[i].status==CODECS_STATUS_NOT_WORKING)
1159 parsehtml(f1,f2,&cl[i]);
1160 break;
1161 case 4:
1162 case 9:
1163 if(cl[i].status==CODECS_STATUS_UNTESTED)
1164 parsehtml(f1,f2,&cl[i]);
1165 break;
1166 default:
1167 printf("Warning! unimplemented section: %d\n",section);
1170 fseek(f1,pos,SEEK_SET);
1171 skiphtml(f1);
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