Raise LIBASS_VERSION, forgotten in r31293.
[mplayer/glamo.git] / codec-cfg.c
blobeba5aaa877f4b7ee77ca6285e2be61605c4a3331
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>
44 #include "config.h"
45 #include "mp_msg.h"
46 #ifdef CODECS2HTML
47 #ifdef __GNUC__
48 #define mp_msg(t, l, m, args...) fprintf(stderr, m, ##args)
49 #else
50 #define mp_msg(t, l, ...) fprintf(stderr, __VA_ARGS__)
51 #endif
52 #endif
54 #include "help_mp.h"
56 // for mmioFOURCC:
57 #include "libmpdemux/aviheader.h"
59 #include "libmpcodecs/img_format.h"
60 #include "codec-cfg.h"
62 #ifndef CODECS2HTML
63 #include "codecs.conf.h"
64 #endif
66 #define PRINT_LINENUM mp_msg(MSGT_CODECCFG,MSGL_ERR," at line %d\n", line_num)
68 #define MAX_NR_TOKEN 16
70 #define MAX_LINE_LEN 1000
72 #define RET_EOF -1
73 #define RET_EOL -2
75 #define TYPE_VIDEO 0
76 #define TYPE_AUDIO 1
78 char * codecs_file = NULL;
80 static int add_to_fourcc(char *s, char *alias, unsigned int *fourcc,
81 unsigned int *map)
83 int i, j, freeslots;
84 unsigned int tmp;
86 /* find first unused slot */
87 for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++)
88 /* NOTHING */;
89 freeslots = CODECS_MAX_FOURCC - i;
90 if (!freeslots)
91 goto err_out_too_many;
93 do {
94 tmp = mmioFOURCC(s[0], s[1], s[2], s[3]);
95 for (j = 0; j < i; j++)
96 if (tmp == fourcc[j])
97 goto err_out_duplicated;
98 fourcc[i] = tmp;
99 map[i] = alias ? mmioFOURCC(alias[0], alias[1], alias[2], alias[3]) : tmp;
100 s += 4;
101 i++;
102 } while ((*(s++) == ',') && --freeslots);
104 if (!freeslots)
105 goto err_out_too_many;
106 if (*(--s) != '\0')
107 goto err_out_parse_error;
108 return 1;
109 err_out_duplicated:
110 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_DuplicateFourcc);
111 return 0;
112 err_out_too_many:
113 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_TooManyFourccs);
114 return 0;
115 err_out_parse_error:
116 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseError);
117 return 0;
120 static int add_to_format(char *s, char *alias,unsigned int *fourcc, unsigned int *fourccmap)
122 int i, j;
123 char *endptr;
125 /* find first unused slot */
126 for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++)
127 /* NOTHING */;
128 if (i == CODECS_MAX_FOURCC) {
129 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_TooManyFourccs);
130 return 0;
133 fourcc[i]=strtoul(s,&endptr,0);
134 if (*endptr != '\0') {
135 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseErrorFIDNotNumber);
136 return 0;
139 if(alias){
140 fourccmap[i]=strtoul(alias,&endptr,0);
141 if (*endptr != '\0') {
142 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseErrorFIDAliasNotNumber);
143 return 0;
145 } else
146 fourccmap[i]=fourcc[i];
148 for (j = 0; j < i; j++)
149 if (fourcc[j] == fourcc[i]) {
150 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_DuplicateFID);
151 return 0;
154 return 1;
157 static const struct {
158 const char *name;
159 const unsigned int num;
160 } fmt_table[] = {
161 // note: due to parser deficiencies/simplicity, if one format
162 // name matches the beginning of another, the longer one _must_
163 // come first in this list.
164 {"YV12", IMGFMT_YV12},
165 {"I420", IMGFMT_I420},
166 {"IYUV", IMGFMT_IYUV},
167 {"NV12", IMGFMT_NV12},
168 {"NV21", IMGFMT_NV21},
169 {"YVU9", IMGFMT_YVU9},
170 {"IF09", IMGFMT_IF09},
171 {"444P16LE", IMGFMT_444P16_LE},
172 {"444P16BE", IMGFMT_444P16_BE},
173 {"422P16LE", IMGFMT_422P16_LE},
174 {"422P16BE", IMGFMT_422P16_BE},
175 {"420P16LE", IMGFMT_420P16_LE},
176 {"420P16BE", IMGFMT_420P16_BE},
177 {"444P16", IMGFMT_444P16},
178 {"422P16", IMGFMT_422P16},
179 {"420P16", IMGFMT_420P16},
180 {"420A", IMGFMT_420A},
181 {"444P", IMGFMT_444P},
182 {"422P", IMGFMT_422P},
183 {"411P", IMGFMT_411P},
184 {"440P", IMGFMT_440P},
185 {"Y800", IMGFMT_Y800},
186 {"Y8", IMGFMT_Y8},
188 {"YUY2", IMGFMT_YUY2},
189 {"UYVY", IMGFMT_UYVY},
190 {"YVYU", IMGFMT_YVYU},
192 {"RGB48LE", IMGFMT_RGB48LE},
193 {"RGB48BE", IMGFMT_RGB48BE},
194 {"RGB4", IMGFMT_RGB4},
195 {"RGB8", IMGFMT_RGB8},
196 {"RGB15", IMGFMT_RGB15},
197 {"RGB16", IMGFMT_RGB16},
198 {"RGB24", IMGFMT_RGB24},
199 {"RGB32", IMGFMT_RGB32},
200 {"BGR4", IMGFMT_BGR4},
201 {"BGR8", IMGFMT_BGR8},
202 {"BGR15", IMGFMT_BGR15},
203 {"BGR16", IMGFMT_BGR16},
204 {"BGR24", IMGFMT_BGR24},
205 {"BGR32", IMGFMT_BGR32},
206 {"RGB1", IMGFMT_RGB1},
207 {"BGR1", IMGFMT_BGR1},
209 {"MPES", IMGFMT_MPEGPES},
210 {"ZRMJPEGNI", IMGFMT_ZRMJPEGNI},
211 {"ZRMJPEGIT", IMGFMT_ZRMJPEGIT},
212 {"ZRMJPEGIB", IMGFMT_ZRMJPEGIB},
214 {"IDCT_MPEG2",IMGFMT_XVMC_IDCT_MPEG2},
215 {"MOCO_MPEG2",IMGFMT_XVMC_MOCO_MPEG2},
217 {"VDPAU_MPEG1",IMGFMT_VDPAU_MPEG1},
218 {"VDPAU_MPEG2",IMGFMT_VDPAU_MPEG2},
219 {"VDPAU_H264",IMGFMT_VDPAU_H264},
220 {"VDPAU_WMV3",IMGFMT_VDPAU_WMV3},
221 {"VDPAU_VC1",IMGFMT_VDPAU_VC1},
222 {"VDPAU_MPEG4",IMGFMT_VDPAU_MPEG4},
224 {NULL, 0}
228 static int add_to_inout(char *sfmt, char *sflags, unsigned int *outfmt,
229 unsigned char *outflags)
232 static char *flagstr[] = {
233 "flip",
234 "noflip",
235 "yuvhack",
236 "query",
237 "static",
238 NULL
241 int i, j, freeslots;
242 unsigned char flags;
244 for (i = 0; i < CODECS_MAX_OUTFMT && outfmt[i] != 0xffffffff; i++)
245 /* NOTHING */;
246 freeslots = CODECS_MAX_OUTFMT - i;
247 if (!freeslots)
248 goto err_out_too_many;
250 flags = 0;
251 if(sflags) {
252 do {
253 for (j = 0; flagstr[j] != NULL; j++)
254 if (!strncmp(sflags, flagstr[j],
255 strlen(flagstr[j])))
256 break;
257 if (flagstr[j] == NULL)
258 goto err_out_parse_error;
259 flags|=(1<<j);
260 sflags+=strlen(flagstr[j]);
261 } while (*(sflags++) == ',');
263 if (*(--sflags) != '\0')
264 goto err_out_parse_error;
267 do {
268 for (j = 0; fmt_table[j].name != NULL; j++)
269 if (!strncmp(sfmt, fmt_table[j].name, strlen(fmt_table[j].name)))
270 break;
271 if (fmt_table[j].name == NULL)
272 goto err_out_parse_error;
273 outfmt[i] = fmt_table[j].num;
274 outflags[i] = flags;
275 ++i;
276 sfmt+=strlen(fmt_table[j].name);
277 } while ((*(sfmt++) == ',') && --freeslots);
279 if (!freeslots)
280 goto err_out_too_many;
282 if (*(--sfmt) != '\0')
283 goto err_out_parse_error;
285 return 1;
286 err_out_too_many:
287 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_TooManyOut);
288 return 0;
289 err_out_parse_error:
290 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseError);
291 return 0;
294 #if 0
295 static short get_driver(char *s,int audioflag)
297 static char *audiodrv[] = {
298 "null",
299 "mp3lib",
300 "pcm",
301 "libac3",
302 "acm",
303 "alaw",
304 "msgsm",
305 "dshow",
306 "dvdpcm",
307 "hwac3",
308 "libvorbis",
309 "ffmpeg",
310 "libmad",
311 "msadpcm",
312 "liba52",
313 "g72x",
314 "imaadpcm",
315 "dk4adpcm",
316 "dk3adpcm",
317 "roqaudio",
318 "faad",
319 "realaud",
320 "libdv",
321 NULL
323 static char *videodrv[] = {
324 "null",
325 "libmpeg2",
326 "vfw",
327 "dshow",
328 "ffmpeg",
329 "vfwex",
330 "raw",
331 "msrle",
332 "xanim",
333 "msvidc",
334 "fli",
335 "cinepak",
336 "qtrle",
337 "nuv",
338 "cyuv",
339 "qtsmc",
340 "ducktm1",
341 "roqvideo",
342 "qtrpza",
343 "mpng",
344 "ijpg",
345 "zlib",
346 "mpegpes",
347 "zrmjpeg",
348 "realvid",
349 "xvid",
350 "libdv",
351 NULL
353 char **drv=audioflag?audiodrv:videodrv;
354 int i;
356 for(i=0;drv[i];i++) if(!strcmp(s,drv[i])) return i;
358 return -1;
360 #endif
362 static int validate_codec(codecs_t *c, int type)
364 unsigned int i;
365 char *tmp_name = c->name;
367 for (i = 0; i < strlen(tmp_name) && isalnum(tmp_name[i]); i++)
368 /* NOTHING */;
370 if (i < strlen(tmp_name)) {
371 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_InvalidCodecName, c->name);
372 return 0;
375 if (!c->info)
376 c->info = strdup(c->name);
378 #if 0
379 if (c->fourcc[0] == 0xffffffff) {
380 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecLacksFourcc, c->name);
381 return 0;
383 #endif
385 if (!c->drv) {
386 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecLacksDriver, c->name);
387 return 0;
390 #if 0
391 #warning codec->driver == 4;... <- this should not be put in here...
392 #warning Where are they defined ????????????
393 if (!c->dll && (c->driver == 4 ||
394 (c->driver == 2 && type == TYPE_VIDEO))) {
395 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecNeedsDLL, c->name);
396 return 0;
398 #warning Can guid.f1 be 0? How does one know that it was not given?
399 // if (!(codec->flags & CODECS_FLAG_AUDIO) && codec->driver == 4)
401 if (type == TYPE_VIDEO)
402 if (c->outfmt[0] == 0xffffffff) {
403 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecNeedsOutfmt, c->name);
404 return 0;
406 #endif
407 return 1;
410 static int add_comment(char *s, char **d)
412 int pos;
414 if (!*d)
415 pos = 0;
416 else {
417 pos = strlen(*d);
418 (*d)[pos++] = '\n';
420 if (!(*d = realloc(*d, pos + strlen(s) + 1))) {
421 mp_msg(MSGT_CODECCFG,MSGL_FATAL,MSGTR_CantAllocateComment);
422 return 0;
424 strcpy(*d + pos, s);
425 return 1;
428 static short get_cpuflags(char *s)
430 static char *flagstr[] = {
431 "mmx",
432 "sse",
433 "3dnow",
434 NULL
436 int i;
437 short flags = 0;
439 do {
440 for (i = 0; flagstr[i]; i++)
441 if (!strncmp(s, flagstr[i], strlen(flagstr[i])))
442 break;
443 if (!flagstr[i])
444 goto err_out_parse_error;
445 flags |= 1<<i;
446 s += strlen(flagstr[i]);
447 } while (*(s++) == ',');
449 if (*(--s) != '\0')
450 goto err_out_parse_error;
452 return flags;
453 err_out_parse_error:
454 return 0;
457 static FILE *fp;
458 static int line_num = 0;
459 static char *line;
460 static char *token[MAX_NR_TOKEN];
461 static int read_nextline = 1;
463 static int get_token(int min, int max)
465 static int line_pos;
466 int i;
467 char c;
469 if (max >= MAX_NR_TOKEN) {
470 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_GetTokenMaxNotLessThanMAX_NR_TOKEN);
471 goto out_eof;
474 memset(token, 0x00, sizeof(*token) * max);
476 if (read_nextline) {
477 if (!fgets(line, MAX_LINE_LEN, fp))
478 goto out_eof;
479 line_pos = 0;
480 ++line_num;
481 read_nextline = 0;
483 for (i = 0; i < max; i++) {
484 while (isspace(line[line_pos]))
485 ++line_pos;
486 if (line[line_pos] == '\0' || line[line_pos] == '#' ||
487 line[line_pos] == ';') {
488 read_nextline = 1;
489 if (i >= min)
490 goto out_ok;
491 goto out_eol;
493 token[i] = line + line_pos;
494 c = line[line_pos];
495 if (c == '"' || c == '\'') {
496 token[i]++;
497 while (line[++line_pos] != c && line[line_pos])
498 /* NOTHING */;
499 } else {
500 for (/* NOTHING */; !isspace(line[line_pos]) &&
501 line[line_pos]; line_pos++)
502 /* NOTHING */;
504 if (!line[line_pos]) {
505 read_nextline = 1;
506 if (i >= min - 1)
507 goto out_ok;
508 goto out_eol;
510 line[line_pos] = '\0';
511 line_pos++;
513 out_ok:
514 return i;
515 out_eof:
516 read_nextline = 1;
517 return RET_EOF;
518 out_eol:
519 return RET_EOL;
522 static codecs_t *video_codecs=NULL;
523 static codecs_t *audio_codecs=NULL;
524 static int nr_vcodecs = 0;
525 static int nr_acodecs = 0;
527 int parse_codec_cfg(const char *cfgfile)
529 codecs_t *codec = NULL; // current codec
530 codecs_t **codecsp = NULL;// points to audio_codecs or to video_codecs
531 char *endptr; // strtoul()...
532 int *nr_codecsp;
533 int codec_type; /* TYPE_VIDEO/TYPE_AUDIO */
534 int tmp, i;
536 // in case we call it a second time
537 codecs_uninit_free();
539 nr_vcodecs = 0;
540 nr_acodecs = 0;
542 if(cfgfile==NULL) {
543 #ifdef CODECS2HTML
544 return 0;
545 #else
546 video_codecs = builtin_video_codecs;
547 audio_codecs = builtin_audio_codecs;
548 nr_vcodecs = sizeof(builtin_video_codecs)/sizeof(codecs_t);
549 nr_acodecs = sizeof(builtin_audio_codecs)/sizeof(codecs_t);
550 return 1;
551 #endif
554 mp_msg(MSGT_CODECCFG,MSGL_V,MSGTR_ReadingFile, cfgfile);
556 if ((fp = fopen(cfgfile, "r")) == NULL) {
557 mp_msg(MSGT_CODECCFG,MSGL_V,MSGTR_CantOpenFileError, cfgfile, strerror(errno));
558 return 0;
561 if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) {
562 mp_msg(MSGT_CODECCFG,MSGL_FATAL,MSGTR_CantGetMemoryForLine, strerror(errno));
563 return 0;
565 read_nextline = 1;
568 * this only catches release lines at the start of
569 * codecs.conf, before audiocodecs and videocodecs.
571 while ((tmp = get_token(1, 1)) == RET_EOL)
572 /* NOTHING */;
573 if (tmp == RET_EOF)
574 goto out;
575 if (!strcmp(token[0], "release")) {
576 if (get_token(1, 2) < 0)
577 goto err_out_parse_error;
578 tmp = atoi(token[0]);
579 if (tmp < CODEC_CFG_MIN)
580 goto err_out_release_num;
581 while ((tmp = get_token(1, 1)) == RET_EOL)
582 /* NOTHING */;
583 if (tmp == RET_EOF)
584 goto out;
585 } else
586 goto err_out_release_num;
589 * check if the next block starts with 'audiocodec' or
590 * with 'videocodec'
592 if (!strcmp(token[0], "audiocodec") || !strcmp(token[0], "videocodec"))
593 goto loop_enter;
594 goto err_out_parse_error;
596 while ((tmp = get_token(1, 1)) != RET_EOF) {
597 if (tmp == RET_EOL)
598 continue;
599 if (!strcmp(token[0], "audiocodec") ||
600 !strcmp(token[0], "videocodec")) {
601 if (!validate_codec(codec, codec_type))
602 goto err_out_not_valid;
603 loop_enter:
604 if (*token[0] == 'v') {
605 codec_type = TYPE_VIDEO;
606 nr_codecsp = &nr_vcodecs;
607 codecsp = &video_codecs;
608 } else if (*token[0] == 'a') {
609 codec_type = TYPE_AUDIO;
610 nr_codecsp = &nr_acodecs;
611 codecsp = &audio_codecs;
612 #ifdef DEBUG
613 } else {
614 mp_msg(MSGT_CODECCFG,MSGL_ERR,"picsba\n");
615 goto err_out;
616 #endif
618 if (!(*codecsp = realloc(*codecsp,
619 sizeof(codecs_t) * (*nr_codecsp + 2)))) {
620 mp_msg(MSGT_CODECCFG,MSGL_FATAL,MSGTR_CantReallocCodecsp, strerror(errno));
621 goto err_out;
623 codec=*codecsp + *nr_codecsp;
624 ++*nr_codecsp;
625 memset(codec,0,sizeof(codecs_t));
626 memset(codec->fourcc, 0xff, sizeof(codec->fourcc));
627 memset(codec->outfmt, 0xff, sizeof(codec->outfmt));
628 memset(codec->infmt, 0xff, sizeof(codec->infmt));
630 if (get_token(1, 1) < 0)
631 goto err_out_parse_error;
632 for (i = 0; i < *nr_codecsp - 1; i++) {
633 if(( (*codecsp)[i].name!=NULL) &&
634 (!strcmp(token[0], (*codecsp)[i].name)) ) {
635 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecNameNotUnique, token[0]);
636 goto err_out_print_linenum;
639 if (!(codec->name = strdup(token[0]))) {
640 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupName, strerror(errno));
641 goto err_out;
643 } else if (!strcmp(token[0], "info")) {
644 if (codec->info || get_token(1, 1) < 0)
645 goto err_out_parse_error;
646 if (!(codec->info = strdup(token[0]))) {
647 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupInfo, strerror(errno));
648 goto err_out;
650 } else if (!strcmp(token[0], "comment")) {
651 if (get_token(1, 1) < 0)
652 goto err_out_parse_error;
653 add_comment(token[0], &codec->comment);
654 } else if (!strcmp(token[0], "fourcc")) {
655 if (get_token(1, 2) < 0)
656 goto err_out_parse_error;
657 if (!add_to_fourcc(token[0], token[1],
658 codec->fourcc,
659 codec->fourccmap))
660 goto err_out_print_linenum;
661 } else if (!strcmp(token[0], "format")) {
662 if (get_token(1, 2) < 0)
663 goto err_out_parse_error;
664 if (!add_to_format(token[0], token[1],
665 codec->fourcc,codec->fourccmap))
666 goto err_out_print_linenum;
667 } else if (!strcmp(token[0], "driver")) {
668 if (get_token(1, 1) < 0)
669 goto err_out_parse_error;
670 if (!(codec->drv = strdup(token[0]))) {
671 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupDriver, strerror(errno));
672 goto err_out;
674 } else if (!strcmp(token[0], "dll")) {
675 if (get_token(1, 1) < 0)
676 goto err_out_parse_error;
677 if (!(codec->dll = strdup(token[0]))) {
678 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupDLL, strerror(errno));
679 goto err_out;
681 } else if (!strcmp(token[0], "guid")) {
682 if (get_token(11, 11) < 0)
683 goto err_out_parse_error;
684 codec->guid.f1=strtoul(token[0],&endptr,0);
685 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
686 *endptr != '\0')
687 goto err_out_parse_error;
688 codec->guid.f2=strtoul(token[1],&endptr,0);
689 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
690 *endptr != '\0')
691 goto err_out_parse_error;
692 codec->guid.f3=strtoul(token[2],&endptr,0);
693 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
694 *endptr != '\0')
695 goto err_out_parse_error;
696 for (i = 0; i < 8; i++) {
697 codec->guid.f4[i]=strtoul(token[i + 3],&endptr,0);
698 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
699 *endptr != '\0')
700 goto err_out_parse_error;
702 } else if (!strcmp(token[0], "out")) {
703 if (get_token(1, 2) < 0)
704 goto err_out_parse_error;
705 if (!add_to_inout(token[0], token[1], codec->outfmt,
706 codec->outflags))
707 goto err_out_print_linenum;
708 } else if (!strcmp(token[0], "in")) {
709 if (get_token(1, 2) < 0)
710 goto err_out_parse_error;
711 if (!add_to_inout(token[0], token[1], codec->infmt,
712 codec->inflags))
713 goto err_out_print_linenum;
714 } else if (!strcmp(token[0], "flags")) {
715 if (get_token(1, 1) < 0)
716 goto err_out_parse_error;
717 if (!strcmp(token[0], "seekable"))
718 codec->flags |= CODECS_FLAG_SEEKABLE;
719 else
720 if (!strcmp(token[0], "align16"))
721 codec->flags |= CODECS_FLAG_ALIGN16;
722 else
723 goto err_out_parse_error;
724 } else if (!strcmp(token[0], "status")) {
725 if (get_token(1, 1) < 0)
726 goto err_out_parse_error;
727 if (!strcasecmp(token[0], "working"))
728 codec->status = CODECS_STATUS_WORKING;
729 else if (!strcasecmp(token[0], "crashing"))
730 codec->status = CODECS_STATUS_NOT_WORKING;
731 else if (!strcasecmp(token[0], "untested"))
732 codec->status = CODECS_STATUS_UNTESTED;
733 else if (!strcasecmp(token[0], "buggy"))
734 codec->status = CODECS_STATUS_PROBLEMS;
735 else
736 goto err_out_parse_error;
737 } else if (!strcmp(token[0], "cpuflags")) {
738 if (get_token(1, 1) < 0)
739 goto err_out_parse_error;
740 if (!(codec->cpuflags = get_cpuflags(token[0])))
741 goto err_out_parse_error;
742 } else
743 goto err_out_parse_error;
745 if (!validate_codec(codec, codec_type))
746 goto err_out_not_valid;
747 mp_msg(MSGT_CODECCFG,MSGL_INFO,MSGTR_AudioVideoCodecTotals, nr_acodecs, nr_vcodecs);
748 if(video_codecs) video_codecs[nr_vcodecs].name = NULL;
749 if(audio_codecs) audio_codecs[nr_acodecs].name = NULL;
750 out:
751 free(line);
752 line=NULL;
753 fclose(fp);
754 return 1;
756 err_out_parse_error:
757 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseError);
758 err_out_print_linenum:
759 PRINT_LINENUM;
760 err_out:
761 codecs_uninit_free();
763 free(line);
764 line=NULL;
765 line_num = 0;
766 fclose(fp);
767 return 0;
768 err_out_not_valid:
769 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecDefinitionIncorrect);
770 goto err_out_print_linenum;
771 err_out_release_num:
772 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_OutdatedCodecsConf);
773 goto err_out_print_linenum;
776 static void codecs_free(codecs_t* codecs,int count) {
777 int i;
778 for ( i = 0; i < count; i++)
779 if ( codecs[i].name ) {
780 if( codecs[i].name )
781 free(codecs[i].name);
782 if( codecs[i].info )
783 free(codecs[i].info);
784 if( codecs[i].comment )
785 free(codecs[i].comment);
786 if( codecs[i].dll )
787 free(codecs[i].dll);
788 if( codecs[i].drv )
789 free(codecs[i].drv);
791 if (codecs)
792 free(codecs);
795 void codecs_uninit_free(void) {
796 if (video_codecs)
797 codecs_free(video_codecs,nr_vcodecs);
798 video_codecs=NULL;
799 if (audio_codecs)
800 codecs_free(audio_codecs,nr_acodecs);
801 audio_codecs=NULL;
804 codecs_t *find_audio_codec(unsigned int fourcc, unsigned int *fourccmap,
805 codecs_t *start, int force)
807 return find_codec(fourcc, fourccmap, start, 1, force);
810 codecs_t *find_video_codec(unsigned int fourcc, unsigned int *fourccmap,
811 codecs_t *start, int force)
813 return find_codec(fourcc, fourccmap, start, 0, force);
816 codecs_t* find_codec(unsigned int fourcc,unsigned int *fourccmap,
817 codecs_t *start, int audioflag, int force)
819 int i, j;
820 codecs_t *c;
822 #if 0
823 if (start) {
824 for (/* NOTHING */; start->name; start++) {
825 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
826 if (start->fourcc[j] == fourcc) {
827 if (fourccmap)
828 *fourccmap = start->fourccmap[j];
829 return start;
833 } else
834 #endif
836 if (audioflag) {
837 i = nr_acodecs;
838 c = audio_codecs;
839 } else {
840 i = nr_vcodecs;
841 c = video_codecs;
843 if(!i) return NULL;
844 for (/* NOTHING */; i--; c++) {
845 if(start && c<=start) continue;
846 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
847 // FIXME: do NOT hardwire 'null' name here:
848 if (c->fourcc[j]==fourcc || !strcmp(c->drv,"null")) {
849 if (fourccmap)
850 *fourccmap = c->fourccmap[j];
851 return c;
854 if (force) return c;
857 return NULL;
860 void stringset_init(stringset_t *set) {
861 *set = calloc(1, sizeof(char *));
864 void stringset_free(stringset_t *set) {
865 int count = 0;
866 while ((*set)[count]) free((*set)[count++]);
867 free(*set);
868 *set = NULL;
871 void stringset_add(stringset_t *set, const char *str) {
872 int count = 0;
873 while ((*set)[count]) count++;
874 count++;
875 *set = realloc(*set, sizeof(char *) * (count + 1));
876 (*set)[count - 1] = strdup(str);
877 (*set)[count] = NULL;
880 int stringset_test(stringset_t *set, const char *str) {
881 stringset_t s;
882 for (s = *set; *s; s++)
883 if (strcmp(*s, str) == 0)
884 return 1;
885 return 0;
888 void list_codecs(int audioflag){
889 int i;
890 codecs_t *c;
892 if (audioflag) {
893 i = nr_acodecs;
894 c = audio_codecs;
895 mp_msg(MSGT_CODECCFG,MSGL_INFO,"ac: afm: status: info: [lib/dll]\n");
896 } else {
897 i = nr_vcodecs;
898 c = video_codecs;
899 mp_msg(MSGT_CODECCFG,MSGL_INFO,"vc: vfm: status: info: [lib/dll]\n");
901 if(!i) return;
902 for (/* NOTHING */; i--; c++) {
903 char* s="unknown ";
904 switch(c->status){
905 case CODECS_STATUS_WORKING: s="working ";break;
906 case CODECS_STATUS_PROBLEMS: s="problems";break;
907 case CODECS_STATUS_NOT_WORKING: s="crashing";break;
908 case CODECS_STATUS_UNTESTED: s="untested";break;
910 if(c->dll)
911 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s [%s]\n",c->name,c->drv,s,c->info,c->dll);
912 else
913 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s\n",c->name,c->drv,s,c->info);
918 #ifdef CODECS2HTML
919 void wrapline(FILE *f2,char *s){
920 int c;
921 if(!s){
922 fprintf(f2,"-");
923 return;
925 while((c=*s++)){
926 if(c==',') fprintf(f2,"<br>"); else fputc(c,f2);
930 void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
931 int c,d;
932 while((c=fgetc(f1))>=0){
933 if(c!='%'){
934 fputc(c,f2);
935 continue;
937 d=fgetc(f1);
939 switch(d){
940 case '.':
941 return; // end of section
942 case 'n':
943 wrapline(f2,codec->name); break;
944 case 'i':
945 wrapline(f2,codec->info); break;
946 case 'c':
947 wrapline(f2,codec->comment); break;
948 case 'd':
949 wrapline(f2,codec->dll); break;
950 case 'D':
951 fprintf(f2,"%c",!strcmp(codec->drv,"dshow")?'+':'-'); break;
952 case 'F':
953 for(d=0;d<CODECS_MAX_FOURCC;d++)
954 if(!d || codec->fourcc[d]!=0xFFFFFFFF)
955 fprintf(f2,"%s%.4s",d?"<br>":"",(codec->fourcc[d]==0xFFFFFFFF || codec->fourcc[d]<0x20202020)?!d?"-":"":(char*) &codec->fourcc[d]);
956 break;
957 case 'f':
958 for(d=0;d<CODECS_MAX_FOURCC;d++)
959 if(codec->fourcc[d]!=0xFFFFFFFF)
960 fprintf(f2,"%s0x%X",d?"<br>":"",codec->fourcc[d]);
961 break;
962 case 'Y':
963 for(d=0;d<CODECS_MAX_OUTFMT;d++)
964 if(codec->outfmt[d]!=0xFFFFFFFF){
965 for (c=0; fmt_table[c].name; c++)
966 if(fmt_table[c].num==codec->outfmt[d]) break;
967 if(fmt_table[c].name)
968 fprintf(f2,"%s%s",d?"<br>":"",fmt_table[c].name);
970 break;
971 default:
972 fputc(c,f2);
973 fputc(d,f2);
978 void skiphtml(FILE *f1){
979 int c,d;
980 while((c=fgetc(f1))>=0){
981 if(c!='%'){
982 continue;
984 d=fgetc(f1);
985 if(d=='.') return; // end of section
989 static void print_int_array(const unsigned int* a, int size)
991 printf("{ ");
992 while (size--)
993 if(abs(*a)<256)
994 printf("%d%s", *a++, size?", ":"");
995 else
996 printf("0x%X%s", *a++, size?", ":"");
997 printf(" }");
1000 static void print_char_array(const unsigned char* a, int size)
1002 printf("{ ");
1003 while (size--)
1004 if((*a)<10)
1005 printf("%d%s", *a++, size?", ":"");
1006 else
1007 printf("0x%02x%s", *a++, size?", ":"");
1008 printf(" }");
1011 static void print_string(const char* s)
1013 if (!s) printf("NULL");
1014 else printf("\"%s\"", s);
1017 int main(int argc, char* argv[])
1019 codecs_t *cl;
1020 FILE *f1;
1021 FILE *f2;
1022 int c,d,i;
1023 int pos;
1024 int section=-1;
1025 int nr_codecs;
1026 int win32=-1;
1027 int dshow=-1;
1028 int win32ex=-1;
1031 * Take path to codecs.conf from command line, or fall back on
1032 * etc/codecs.conf
1034 if (!(nr_codecs = parse_codec_cfg((argc>1)?argv[1]:"etc/codecs.conf")))
1035 exit(1);
1037 if (argc > 1) {
1038 int i, j;
1039 const char* nm[2];
1040 codecs_t* cod[2];
1041 int nr[2];
1043 nm[0] = "builtin_video_codecs";
1044 cod[0] = video_codecs;
1045 nr[0] = nr_vcodecs;
1047 nm[1] = "builtin_audio_codecs";
1048 cod[1] = audio_codecs;
1049 nr[1] = nr_acodecs;
1051 printf("/* GENERATED FROM %s, DO NOT EDIT! */\n\n",argv[1]);
1052 printf("#include <stddef.h>\n",argv[1]);
1053 printf("#include \"codec-cfg.h\"\n\n",argv[1]);
1055 for (i=0; i<2; i++) {
1056 printf("const codecs_t %s[] = {\n", nm[i]);
1057 for (j = 0; j < nr[i]; j++) {
1058 printf("{");
1060 print_int_array(cod[i][j].fourcc, CODECS_MAX_FOURCC);
1061 printf(", /* fourcc */\n");
1063 print_int_array(cod[i][j].fourccmap, CODECS_MAX_FOURCC);
1064 printf(", /* fourccmap */\n");
1066 print_int_array(cod[i][j].outfmt, CODECS_MAX_OUTFMT);
1067 printf(", /* outfmt */\n");
1069 print_char_array(cod[i][j].outflags, CODECS_MAX_OUTFMT);
1070 printf(", /* outflags */\n");
1072 print_int_array(cod[i][j].infmt, CODECS_MAX_INFMT);
1073 printf(", /* infmt */\n");
1075 print_char_array(cod[i][j].inflags, CODECS_MAX_INFMT);
1076 printf(", /* inflags */\n");
1078 print_string(cod[i][j].name); printf(", /* name */\n");
1079 print_string(cod[i][j].info); printf(", /* info */\n");
1080 print_string(cod[i][j].comment); printf(", /* comment */\n");
1081 print_string(cod[i][j].dll); printf(", /* dll */\n");
1082 print_string(cod[i][j].drv); printf(", /* drv */\n");
1084 printf("{ 0x%08lx, %hu, %hu,",
1085 cod[i][j].guid.f1,
1086 cod[i][j].guid.f2,
1087 cod[i][j].guid.f3);
1088 print_char_array(cod[i][j].guid.f4, sizeof(cod[i][j].guid.f4));
1089 printf(" }, /* GUID */\n");
1090 printf("%hd /* flags */, %hd /* status */, %hd /* cpuflags */ }\n",
1091 cod[i][j].flags,
1092 cod[i][j].status,
1093 cod[i][j].cpuflags);
1094 if (j < nr[i]) printf(",\n");
1096 printf("};\n\n");
1098 exit(0);
1101 f1=fopen("DOCS/tech/codecs-in.html","rb"); if(!f1) exit(1);
1102 f2=fopen("DOCS/codecs-status.html","wb"); if(!f2) exit(1);
1104 while((c=fgetc(f1))>=0){
1105 if(c!='%'){
1106 fputc(c,f2);
1107 continue;
1109 d=fgetc(f1);
1110 if(d>='0' && d<='9'){
1111 // begin section
1112 section=d-'0';
1113 //printf("BEGIN %d\n",section);
1114 if(section>=5){
1115 // audio
1116 cl = audio_codecs;
1117 nr_codecs = nr_acodecs;
1118 dshow=7;win32=4;
1119 } else {
1120 // video
1121 cl = video_codecs;
1122 nr_codecs = nr_vcodecs;
1123 dshow=4;win32=2;win32ex=6;
1125 pos=ftell(f1);
1126 for(i=0;i<nr_codecs;i++){
1127 fseek(f1,pos,SEEK_SET);
1128 switch(section){
1129 case 0:
1130 case 5:
1131 if(cl[i].status==CODECS_STATUS_WORKING)
1132 // if(!(!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1133 parsehtml(f1,f2,&cl[i],section,dshow);
1134 break;
1135 #if 0
1136 case 1:
1137 case 6:
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 #endif
1143 case 2:
1144 case 7:
1145 if(cl[i].status==CODECS_STATUS_PROBLEMS)
1146 parsehtml(f1,f2,&cl[i],section,dshow);
1147 break;
1148 case 3:
1149 case 8:
1150 if(cl[i].status==CODECS_STATUS_NOT_WORKING)
1151 parsehtml(f1,f2,&cl[i],section,dshow);
1152 break;
1153 case 4:
1154 case 9:
1155 if(cl[i].status==CODECS_STATUS_UNTESTED)
1156 parsehtml(f1,f2,&cl[i],section,dshow);
1157 break;
1158 default:
1159 printf("Warning! unimplemented section: %d\n",section);
1162 fseek(f1,pos,SEEK_SET);
1163 skiphtml(f1);
1164 //void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
1166 continue;
1168 fputc(c,f2);
1169 fputc(d,f2);
1172 fclose(f2);
1173 fclose(f1);
1174 return 0;
1177 #endif
1179 #ifdef TESTING
1180 int main(void)
1182 codecs_t *c;
1183 int i,j, nr_codecs, state;
1185 if (!(parse_codec_cfg("etc/codecs.conf")))
1186 return 0;
1187 if (!video_codecs)
1188 printf("no videoconfig.\n");
1189 if (!audio_codecs)
1190 printf("no audioconfig.\n");
1192 printf("videocodecs:\n");
1193 c = video_codecs;
1194 nr_codecs = nr_vcodecs;
1195 state = 0;
1196 next:
1197 if (c) {
1198 printf("number of %scodecs: %d\n", state==0?"video":"audio",
1199 nr_codecs);
1200 for(i=0;i<nr_codecs;i++, c++){
1201 printf("\n============== %scodec %02d ===============\n",
1202 state==0?"video":"audio",i);
1203 printf("name='%s'\n",c->name);
1204 printf("info='%s'\n",c->info);
1205 printf("comment='%s'\n",c->comment);
1206 printf("dll='%s'\n",c->dll);
1207 /* printf("flags=%X driver=%d status=%d cpuflags=%d\n",
1208 c->flags, c->driver, c->status, c->cpuflags); */
1209 printf("flags=%X status=%d cpuflags=%d\n",
1210 c->flags, c->status, c->cpuflags);
1212 for(j=0;j<CODECS_MAX_FOURCC;j++){
1213 if(c->fourcc[j]!=0xFFFFFFFF){
1214 printf("fourcc %02d: %08X (%.4s) ===> %08X (%.4s)\n",j,c->fourcc[j],(char *) &c->fourcc[j],c->fourccmap[j],(char *) &c->fourccmap[j]);
1218 for(j=0;j<CODECS_MAX_OUTFMT;j++){
1219 if(c->outfmt[j]!=0xFFFFFFFF){
1220 printf("outfmt %02d: %08X (%.4s) flags: %d\n",j,c->outfmt[j],(char *) &c->outfmt[j],c->outflags[j]);
1224 for(j=0;j<CODECS_MAX_INFMT;j++){
1225 if(c->infmt[j]!=0xFFFFFFFF){
1226 printf("infmt %02d: %08X (%.4s) flags: %d\n",j,c->infmt[j],(char *) &c->infmt[j],c->inflags[j]);
1230 printf("GUID: %08lX %04X %04X",c->guid.f1,c->guid.f2,c->guid.f3);
1231 for(j=0;j<8;j++) printf(" %02X",c->guid.f4[j]);
1232 printf("\n");
1237 if (!state) {
1238 printf("audiocodecs:\n");
1239 c = audio_codecs;
1240 nr_codecs = nr_acodecs;
1241 state = 1;
1242 goto next;
1244 return 0;
1247 #endif