sync with en/mplayer.1 r29731
[mplayer/greg.git] / codec-cfg.c
blob86424b54c4a74e06b5b6bb4d55c6f6d854b060eb
1 /*
2 * codec.conf parser
3 * by Szabolcs Berecz <szabi@inf.elte.hu>
4 * (C) 2001
6 * to compile test application:
7 * cc -I. -DTESTING -o codec-cfg-test codec-cfg.c mp_msg.o osdep/getch2.o -ltermcap
8 * to compile CODECS2HTML:
9 * gcc -DCODECS2HTML -o codecs2html codec-cfg.c mp_msg.o
11 * TODO: implement informat in CODECS2HTML too
14 #define DEBUG
16 //disable asserts
17 #define NDEBUG
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <ctype.h>
25 #include <assert.h>
26 #include <string.h>
28 #include "config.h"
29 #include "mp_msg.h"
30 #ifdef CODECS2HTML
31 #ifdef __GNUC__
32 #define mp_msg(t, l, m, args...) fprintf(stderr, m, ##args)
33 #else
34 #define mp_msg(t, l, ...) fprintf(stderr, __VA_ARGS__)
35 #endif
36 #endif
38 #include "help_mp.h"
40 // for mmioFOURCC:
41 #include "libmpdemux/aviheader.h"
43 #include "libmpcodecs/img_format.h"
44 #include "codec-cfg.h"
46 #ifndef CODECS2HTML
47 #include "codecs.conf.h"
48 #endif
50 #define PRINT_LINENUM mp_msg(MSGT_CODECCFG,MSGL_ERR," at line %d\n", line_num)
52 #define MAX_NR_TOKEN 16
54 #define MAX_LINE_LEN 1000
56 #define RET_EOF -1
57 #define RET_EOL -2
59 #define TYPE_VIDEO 0
60 #define TYPE_AUDIO 1
62 char * codecs_file = NULL;
64 static int add_to_fourcc(char *s, char *alias, unsigned int *fourcc,
65 unsigned int *map)
67 int i, j, freeslots;
68 unsigned int tmp;
70 /* find first unused slot */
71 for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++)
72 /* NOTHING */;
73 freeslots = CODECS_MAX_FOURCC - i;
74 if (!freeslots)
75 goto err_out_too_many;
77 do {
78 tmp = mmioFOURCC(s[0], s[1], s[2], s[3]);
79 for (j = 0; j < i; j++)
80 if (tmp == fourcc[j])
81 goto err_out_duplicated;
82 fourcc[i] = tmp;
83 map[i] = alias ? mmioFOURCC(alias[0], alias[1], alias[2], alias[3]) : tmp;
84 s += 4;
85 i++;
86 } while ((*(s++) == ',') && --freeslots);
88 if (!freeslots)
89 goto err_out_too_many;
90 if (*(--s) != '\0')
91 goto err_out_parse_error;
92 return 1;
93 err_out_duplicated:
94 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_DuplicateFourcc);
95 return 0;
96 err_out_too_many:
97 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_TooManyFourccs);
98 return 0;
99 err_out_parse_error:
100 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseError);
101 return 0;
104 static int add_to_format(char *s, char *alias,unsigned int *fourcc, unsigned int *fourccmap)
106 int i, j;
107 char *endptr;
109 /* find first unused slot */
110 for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++)
111 /* NOTHING */;
112 if (i == CODECS_MAX_FOURCC) {
113 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_TooManyFourccs);
114 return 0;
117 fourcc[i]=strtoul(s,&endptr,0);
118 if (*endptr != '\0') {
119 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseErrorFIDNotNumber);
120 return 0;
123 if(alias){
124 fourccmap[i]=strtoul(alias,&endptr,0);
125 if (*endptr != '\0') {
126 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseErrorFIDAliasNotNumber);
127 return 0;
129 } else
130 fourccmap[i]=fourcc[i];
132 for (j = 0; j < i; j++)
133 if (fourcc[j] == fourcc[i]) {
134 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_DuplicateFID);
135 return 0;
138 return 1;
141 static const struct {
142 const char *name;
143 const unsigned int num;
144 } fmt_table[] = {
145 // note: due to parser deficiencies/simplicity, if one format
146 // name matches the beginning of another, the longer one _must_
147 // come first in this list.
148 {"YV12", IMGFMT_YV12},
149 {"I420", IMGFMT_I420},
150 {"IYUV", IMGFMT_IYUV},
151 {"NV12", IMGFMT_NV12},
152 {"NV21", IMGFMT_NV21},
153 {"YVU9", IMGFMT_YVU9},
154 {"IF09", IMGFMT_IF09},
155 {"444P", IMGFMT_444P},
156 {"422P", IMGFMT_422P},
157 {"411P", IMGFMT_411P},
158 {"Y800", IMGFMT_Y800},
159 {"Y8", IMGFMT_Y8},
161 {"YUY2", IMGFMT_YUY2},
162 {"UYVY", IMGFMT_UYVY},
163 {"YVYU", IMGFMT_YVYU},
165 {"RGB48LE", IMGFMT_RGB48LE},
166 {"RGB48BE", IMGFMT_RGB48BE},
167 {"RGB4", IMGFMT_RGB4},
168 {"RGB8", IMGFMT_RGB8},
169 {"RGB15", IMGFMT_RGB15},
170 {"RGB16", IMGFMT_RGB16},
171 {"RGB24", IMGFMT_RGB24},
172 {"RGB32", IMGFMT_RGB32},
173 {"BGR4", IMGFMT_BGR4},
174 {"BGR8", IMGFMT_BGR8},
175 {"BGR15", IMGFMT_BGR15},
176 {"BGR16", IMGFMT_BGR16},
177 {"BGR24", IMGFMT_BGR24},
178 {"BGR32", IMGFMT_BGR32},
179 {"RGB1", IMGFMT_RGB1},
180 {"BGR1", IMGFMT_BGR1},
182 {"MPES", IMGFMT_MPEGPES},
183 {"ZRMJPEGNI", IMGFMT_ZRMJPEGNI},
184 {"ZRMJPEGIT", IMGFMT_ZRMJPEGIT},
185 {"ZRMJPEGIB", IMGFMT_ZRMJPEGIB},
187 {"IDCT_MPEG2",IMGFMT_XVMC_IDCT_MPEG2},
188 {"MOCO_MPEG2",IMGFMT_XVMC_MOCO_MPEG2},
190 {"VDPAU_MPEG1",IMGFMT_VDPAU_MPEG1},
191 {"VDPAU_MPEG2",IMGFMT_VDPAU_MPEG2},
192 {"VDPAU_H264",IMGFMT_VDPAU_H264},
193 {"VDPAU_WMV3",IMGFMT_VDPAU_WMV3},
194 {"VDPAU_VC1",IMGFMT_VDPAU_VC1},
196 {NULL, 0}
200 static int add_to_inout(char *sfmt, char *sflags, unsigned int *outfmt,
201 unsigned char *outflags)
204 static char *flagstr[] = {
205 "flip",
206 "noflip",
207 "yuvhack",
208 "query",
209 "static",
210 NULL
213 int i, j, freeslots;
214 unsigned char flags;
216 for (i = 0; i < CODECS_MAX_OUTFMT && outfmt[i] != 0xffffffff; i++)
217 /* NOTHING */;
218 freeslots = CODECS_MAX_OUTFMT - i;
219 if (!freeslots)
220 goto err_out_too_many;
222 flags = 0;
223 if(sflags) {
224 do {
225 for (j = 0; flagstr[j] != NULL; j++)
226 if (!strncmp(sflags, flagstr[j],
227 strlen(flagstr[j])))
228 break;
229 if (flagstr[j] == NULL)
230 goto err_out_parse_error;
231 flags|=(1<<j);
232 sflags+=strlen(flagstr[j]);
233 } while (*(sflags++) == ',');
235 if (*(--sflags) != '\0')
236 goto err_out_parse_error;
239 do {
240 for (j = 0; fmt_table[j].name != NULL; j++)
241 if (!strncmp(sfmt, fmt_table[j].name, strlen(fmt_table[j].name)))
242 break;
243 if (fmt_table[j].name == NULL)
244 goto err_out_parse_error;
245 outfmt[i] = fmt_table[j].num;
246 outflags[i] = flags;
247 ++i;
248 sfmt+=strlen(fmt_table[j].name);
249 } while ((*(sfmt++) == ',') && --freeslots);
251 if (!freeslots)
252 goto err_out_too_many;
254 if (*(--sfmt) != '\0')
255 goto err_out_parse_error;
257 return 1;
258 err_out_too_many:
259 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_TooManyOut);
260 return 0;
261 err_out_parse_error:
262 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseError);
263 return 0;
266 #if 0
267 static short get_driver(char *s,int audioflag)
269 static char *audiodrv[] = {
270 "null",
271 "mp3lib",
272 "pcm",
273 "libac3",
274 "acm",
275 "alaw",
276 "msgsm",
277 "dshow",
278 "dvdpcm",
279 "hwac3",
280 "libvorbis",
281 "ffmpeg",
282 "libmad",
283 "msadpcm",
284 "liba52",
285 "g72x",
286 "imaadpcm",
287 "dk4adpcm",
288 "dk3adpcm",
289 "roqaudio",
290 "faad",
291 "realaud",
292 "libdv",
293 NULL
295 static char *videodrv[] = {
296 "null",
297 "libmpeg2",
298 "vfw",
299 "dshow",
300 "ffmpeg",
301 "vfwex",
302 "raw",
303 "msrle",
304 "xanim",
305 "msvidc",
306 "fli",
307 "cinepak",
308 "qtrle",
309 "nuv",
310 "cyuv",
311 "qtsmc",
312 "ducktm1",
313 "roqvideo",
314 "qtrpza",
315 "mpng",
316 "ijpg",
317 "zlib",
318 "mpegpes",
319 "zrmjpeg",
320 "realvid",
321 "xvid",
322 "libdv",
323 NULL
325 char **drv=audioflag?audiodrv:videodrv;
326 int i;
328 for(i=0;drv[i];i++) if(!strcmp(s,drv[i])) return i;
330 return -1;
332 #endif
334 static int validate_codec(codecs_t *c, int type)
336 unsigned int i;
337 char *tmp_name = c->name;
339 for (i = 0; i < strlen(tmp_name) && isalnum(tmp_name[i]); i++)
340 /* NOTHING */;
342 if (i < strlen(tmp_name)) {
343 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_InvalidCodecName, c->name);
344 return 0;
347 if (!c->info)
348 c->info = strdup(c->name);
350 #if 0
351 if (c->fourcc[0] == 0xffffffff) {
352 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecLacksFourcc, c->name);
353 return 0;
355 #endif
357 if (!c->drv) {
358 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecLacksDriver, c->name);
359 return 0;
362 #if 0
363 #warning codec->driver == 4;... <- this should not be put in here...
364 #warning Where are they defined ????????????
365 if (!c->dll && (c->driver == 4 ||
366 (c->driver == 2 && type == TYPE_VIDEO))) {
367 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecNeedsDLL, c->name);
368 return 0;
370 #warning Can guid.f1 be 0? How does one know that it was not given?
371 // if (!(codec->flags & CODECS_FLAG_AUDIO) && codec->driver == 4)
373 if (type == TYPE_VIDEO)
374 if (c->outfmt[0] == 0xffffffff) {
375 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecNeedsOutfmt, c->name);
376 return 0;
378 #endif
379 return 1;
382 static int add_comment(char *s, char **d)
384 int pos;
386 if (!*d)
387 pos = 0;
388 else {
389 pos = strlen(*d);
390 (*d)[pos++] = '\n';
392 if (!(*d = realloc(*d, pos + strlen(s) + 1))) {
393 mp_msg(MSGT_CODECCFG,MSGL_FATAL,MSGTR_CantAllocateComment);
394 return 0;
396 strcpy(*d + pos, s);
397 return 1;
400 static short get_cpuflags(char *s)
402 static char *flagstr[] = {
403 "mmx",
404 "sse",
405 "3dnow",
406 NULL
408 int i;
409 short flags = 0;
411 do {
412 for (i = 0; flagstr[i]; i++)
413 if (!strncmp(s, flagstr[i], strlen(flagstr[i])))
414 break;
415 if (!flagstr[i])
416 goto err_out_parse_error;
417 flags |= 1<<i;
418 s += strlen(flagstr[i]);
419 } while (*(s++) == ',');
421 if (*(--s) != '\0')
422 goto err_out_parse_error;
424 return flags;
425 err_out_parse_error:
426 return 0;
429 static FILE *fp;
430 static int line_num = 0;
431 static char *line;
432 static char *token[MAX_NR_TOKEN];
433 static int read_nextline = 1;
435 static int get_token(int min, int max)
437 static int line_pos;
438 int i;
439 char c;
441 if (max >= MAX_NR_TOKEN) {
442 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_GetTokenMaxNotLessThanMAX_NR_TOKEN);
443 goto out_eof;
446 memset(token, 0x00, sizeof(*token) * max);
448 if (read_nextline) {
449 if (!fgets(line, MAX_LINE_LEN, fp))
450 goto out_eof;
451 line_pos = 0;
452 ++line_num;
453 read_nextline = 0;
455 for (i = 0; i < max; i++) {
456 while (isspace(line[line_pos]))
457 ++line_pos;
458 if (line[line_pos] == '\0' || line[line_pos] == '#' ||
459 line[line_pos] == ';') {
460 read_nextline = 1;
461 if (i >= min)
462 goto out_ok;
463 goto out_eol;
465 token[i] = line + line_pos;
466 c = line[line_pos];
467 if (c == '"' || c == '\'') {
468 token[i]++;
469 while (line[++line_pos] != c && line[line_pos])
470 /* NOTHING */;
471 } else {
472 for (/* NOTHING */; !isspace(line[line_pos]) &&
473 line[line_pos]; line_pos++)
474 /* NOTHING */;
476 if (!line[line_pos]) {
477 read_nextline = 1;
478 if (i >= min - 1)
479 goto out_ok;
480 goto out_eol;
482 line[line_pos] = '\0';
483 line_pos++;
485 out_ok:
486 return i;
487 out_eof:
488 read_nextline = 1;
489 return RET_EOF;
490 out_eol:
491 return RET_EOL;
494 static codecs_t *video_codecs=NULL;
495 static codecs_t *audio_codecs=NULL;
496 static int nr_vcodecs = 0;
497 static int nr_acodecs = 0;
499 int parse_codec_cfg(const char *cfgfile)
501 codecs_t *codec = NULL; // current codec
502 codecs_t **codecsp = NULL;// points to audio_codecs or to video_codecs
503 char *endptr; // strtoul()...
504 int *nr_codecsp;
505 int codec_type; /* TYPE_VIDEO/TYPE_AUDIO */
506 int tmp, i;
508 // in case we call it a second time
509 codecs_uninit_free();
511 nr_vcodecs = 0;
512 nr_acodecs = 0;
514 if(cfgfile==NULL) {
515 #ifdef CODECS2HTML
516 return 0;
517 #else
518 video_codecs = builtin_video_codecs;
519 audio_codecs = builtin_audio_codecs;
520 nr_vcodecs = sizeof(builtin_video_codecs)/sizeof(codecs_t);
521 nr_acodecs = sizeof(builtin_audio_codecs)/sizeof(codecs_t);
522 return 1;
523 #endif
526 mp_msg(MSGT_CODECCFG,MSGL_V,MSGTR_ReadingFile, cfgfile);
528 if ((fp = fopen(cfgfile, "r")) == NULL) {
529 mp_msg(MSGT_CODECCFG,MSGL_V,MSGTR_CantOpenFileError, cfgfile, strerror(errno));
530 return 0;
533 if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) {
534 mp_msg(MSGT_CODECCFG,MSGL_FATAL,MSGTR_CantGetMemoryForLine, strerror(errno));
535 return 0;
537 read_nextline = 1;
540 * this only catches release lines at the start of
541 * codecs.conf, before audiocodecs and videocodecs.
543 while ((tmp = get_token(1, 1)) == RET_EOL)
544 /* NOTHING */;
545 if (tmp == RET_EOF)
546 goto out;
547 if (!strcmp(token[0], "release")) {
548 if (get_token(1, 2) < 0)
549 goto err_out_parse_error;
550 tmp = atoi(token[0]);
551 if (tmp < CODEC_CFG_MIN)
552 goto err_out_release_num;
553 while ((tmp = get_token(1, 1)) == RET_EOL)
554 /* NOTHING */;
555 if (tmp == RET_EOF)
556 goto out;
557 } else
558 goto err_out_release_num;
561 * check if the next block starts with 'audiocodec' or
562 * with 'videocodec'
564 if (!strcmp(token[0], "audiocodec") || !strcmp(token[0], "videocodec"))
565 goto loop_enter;
566 goto err_out_parse_error;
568 while ((tmp = get_token(1, 1)) != RET_EOF) {
569 if (tmp == RET_EOL)
570 continue;
571 if (!strcmp(token[0], "audiocodec") ||
572 !strcmp(token[0], "videocodec")) {
573 if (!validate_codec(codec, codec_type))
574 goto err_out_not_valid;
575 loop_enter:
576 if (*token[0] == 'v') {
577 codec_type = TYPE_VIDEO;
578 nr_codecsp = &nr_vcodecs;
579 codecsp = &video_codecs;
580 } else if (*token[0] == 'a') {
581 codec_type = TYPE_AUDIO;
582 nr_codecsp = &nr_acodecs;
583 codecsp = &audio_codecs;
584 #ifdef DEBUG
585 } else {
586 mp_msg(MSGT_CODECCFG,MSGL_ERR,"picsba\n");
587 goto err_out;
588 #endif
590 if (!(*codecsp = realloc(*codecsp,
591 sizeof(codecs_t) * (*nr_codecsp + 2)))) {
592 mp_msg(MSGT_CODECCFG,MSGL_FATAL,MSGTR_CantReallocCodecsp, strerror(errno));
593 goto err_out;
595 codec=*codecsp + *nr_codecsp;
596 ++*nr_codecsp;
597 memset(codec,0,sizeof(codecs_t));
598 memset(codec->fourcc, 0xff, sizeof(codec->fourcc));
599 memset(codec->outfmt, 0xff, sizeof(codec->outfmt));
600 memset(codec->infmt, 0xff, sizeof(codec->infmt));
602 if (get_token(1, 1) < 0)
603 goto err_out_parse_error;
604 for (i = 0; i < *nr_codecsp - 1; i++) {
605 if(( (*codecsp)[i].name!=NULL) &&
606 (!strcmp(token[0], (*codecsp)[i].name)) ) {
607 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecNameNotUnique, token[0]);
608 goto err_out_print_linenum;
611 if (!(codec->name = strdup(token[0]))) {
612 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupName, strerror(errno));
613 goto err_out;
615 } else if (!strcmp(token[0], "info")) {
616 if (codec->info || get_token(1, 1) < 0)
617 goto err_out_parse_error;
618 if (!(codec->info = strdup(token[0]))) {
619 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupInfo, strerror(errno));
620 goto err_out;
622 } else if (!strcmp(token[0], "comment")) {
623 if (get_token(1, 1) < 0)
624 goto err_out_parse_error;
625 add_comment(token[0], &codec->comment);
626 } else if (!strcmp(token[0], "fourcc")) {
627 if (get_token(1, 2) < 0)
628 goto err_out_parse_error;
629 if (!add_to_fourcc(token[0], token[1],
630 codec->fourcc,
631 codec->fourccmap))
632 goto err_out_print_linenum;
633 } else if (!strcmp(token[0], "format")) {
634 if (get_token(1, 2) < 0)
635 goto err_out_parse_error;
636 if (!add_to_format(token[0], token[1],
637 codec->fourcc,codec->fourccmap))
638 goto err_out_print_linenum;
639 } else if (!strcmp(token[0], "driver")) {
640 if (get_token(1, 1) < 0)
641 goto err_out_parse_error;
642 if (!(codec->drv = strdup(token[0]))) {
643 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupDriver, strerror(errno));
644 goto err_out;
646 } else if (!strcmp(token[0], "dll")) {
647 if (get_token(1, 1) < 0)
648 goto err_out_parse_error;
649 if (!(codec->dll = strdup(token[0]))) {
650 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupDLL, strerror(errno));
651 goto err_out;
653 } else if (!strcmp(token[0], "guid")) {
654 if (get_token(11, 11) < 0)
655 goto err_out_parse_error;
656 codec->guid.f1=strtoul(token[0],&endptr,0);
657 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
658 *endptr != '\0')
659 goto err_out_parse_error;
660 codec->guid.f2=strtoul(token[1],&endptr,0);
661 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
662 *endptr != '\0')
663 goto err_out_parse_error;
664 codec->guid.f3=strtoul(token[2],&endptr,0);
665 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
666 *endptr != '\0')
667 goto err_out_parse_error;
668 for (i = 0; i < 8; i++) {
669 codec->guid.f4[i]=strtoul(token[i + 3],&endptr,0);
670 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
671 *endptr != '\0')
672 goto err_out_parse_error;
674 } else if (!strcmp(token[0], "out")) {
675 if (get_token(1, 2) < 0)
676 goto err_out_parse_error;
677 if (!add_to_inout(token[0], token[1], codec->outfmt,
678 codec->outflags))
679 goto err_out_print_linenum;
680 } else if (!strcmp(token[0], "in")) {
681 if (get_token(1, 2) < 0)
682 goto err_out_parse_error;
683 if (!add_to_inout(token[0], token[1], codec->infmt,
684 codec->inflags))
685 goto err_out_print_linenum;
686 } else if (!strcmp(token[0], "flags")) {
687 if (get_token(1, 1) < 0)
688 goto err_out_parse_error;
689 if (!strcmp(token[0], "seekable"))
690 codec->flags |= CODECS_FLAG_SEEKABLE;
691 else
692 if (!strcmp(token[0], "align16"))
693 codec->flags |= CODECS_FLAG_ALIGN16;
694 else
695 goto err_out_parse_error;
696 } else if (!strcmp(token[0], "status")) {
697 if (get_token(1, 1) < 0)
698 goto err_out_parse_error;
699 if (!strcasecmp(token[0], "working"))
700 codec->status = CODECS_STATUS_WORKING;
701 else if (!strcasecmp(token[0], "crashing"))
702 codec->status = CODECS_STATUS_NOT_WORKING;
703 else if (!strcasecmp(token[0], "untested"))
704 codec->status = CODECS_STATUS_UNTESTED;
705 else if (!strcasecmp(token[0], "buggy"))
706 codec->status = CODECS_STATUS_PROBLEMS;
707 else
708 goto err_out_parse_error;
709 } else if (!strcmp(token[0], "cpuflags")) {
710 if (get_token(1, 1) < 0)
711 goto err_out_parse_error;
712 if (!(codec->cpuflags = get_cpuflags(token[0])))
713 goto err_out_parse_error;
714 } else
715 goto err_out_parse_error;
717 if (!validate_codec(codec, codec_type))
718 goto err_out_not_valid;
719 mp_msg(MSGT_CODECCFG,MSGL_INFO,MSGTR_AudioVideoCodecTotals, nr_acodecs, nr_vcodecs);
720 if(video_codecs) video_codecs[nr_vcodecs].name = NULL;
721 if(audio_codecs) audio_codecs[nr_acodecs].name = NULL;
722 out:
723 free(line);
724 line=NULL;
725 fclose(fp);
726 return 1;
728 err_out_parse_error:
729 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseError);
730 err_out_print_linenum:
731 PRINT_LINENUM;
732 err_out:
733 codecs_uninit_free();
735 free(line);
736 line=NULL;
737 line_num = 0;
738 fclose(fp);
739 return 0;
740 err_out_not_valid:
741 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecDefinitionIncorrect);
742 goto err_out_print_linenum;
743 err_out_release_num:
744 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_OutdatedCodecsConf);
745 goto err_out_print_linenum;
748 static void codecs_free(codecs_t* codecs,int count) {
749 int i;
750 for ( i = 0; i < count; i++)
751 if ( codecs[i].name ) {
752 if( codecs[i].name )
753 free(codecs[i].name);
754 if( codecs[i].info )
755 free(codecs[i].info);
756 if( codecs[i].comment )
757 free(codecs[i].comment);
758 if( codecs[i].dll )
759 free(codecs[i].dll);
760 if( codecs[i].drv )
761 free(codecs[i].drv);
763 if (codecs)
764 free(codecs);
767 void codecs_uninit_free(void) {
768 if (video_codecs)
769 codecs_free(video_codecs,nr_vcodecs);
770 video_codecs=NULL;
771 if (audio_codecs)
772 codecs_free(audio_codecs,nr_acodecs);
773 audio_codecs=NULL;
776 codecs_t *find_audio_codec(unsigned int fourcc, unsigned int *fourccmap,
777 codecs_t *start, int force)
779 return find_codec(fourcc, fourccmap, start, 1, force);
782 codecs_t *find_video_codec(unsigned int fourcc, unsigned int *fourccmap,
783 codecs_t *start, int force)
785 return find_codec(fourcc, fourccmap, start, 0, force);
788 codecs_t* find_codec(unsigned int fourcc,unsigned int *fourccmap,
789 codecs_t *start, int audioflag, int force)
791 int i, j;
792 codecs_t *c;
794 #if 0
795 if (start) {
796 for (/* NOTHING */; start->name; start++) {
797 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
798 if (start->fourcc[j] == fourcc) {
799 if (fourccmap)
800 *fourccmap = start->fourccmap[j];
801 return start;
805 } else
806 #endif
808 if (audioflag) {
809 i = nr_acodecs;
810 c = audio_codecs;
811 } else {
812 i = nr_vcodecs;
813 c = video_codecs;
815 if(!i) return NULL;
816 for (/* NOTHING */; i--; c++) {
817 if(start && c<=start) continue;
818 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
819 // FIXME: do NOT hardwire 'null' name here:
820 if (c->fourcc[j]==fourcc || !strcmp(c->drv,"null")) {
821 if (fourccmap)
822 *fourccmap = c->fourccmap[j];
823 return c;
826 if (force) return c;
829 return NULL;
832 void stringset_init(stringset_t *set) {
833 *set = calloc(1, sizeof(char *));
836 void stringset_free(stringset_t *set) {
837 int count = 0;
838 while ((*set)[count]) free((*set)[count++]);
839 free(*set);
840 *set = NULL;
843 void stringset_add(stringset_t *set, const char *str) {
844 int count = 0;
845 while ((*set)[count]) count++;
846 count++;
847 *set = realloc(*set, sizeof(char *) * (count + 1));
848 (*set)[count - 1] = strdup(str);
849 (*set)[count] = NULL;
852 int stringset_test(stringset_t *set, const char *str) {
853 stringset_t s;
854 for (s = *set; *s; s++)
855 if (strcmp(*s, str) == 0)
856 return 1;
857 return 0;
860 void list_codecs(int audioflag){
861 int i;
862 codecs_t *c;
864 if (audioflag) {
865 i = nr_acodecs;
866 c = audio_codecs;
867 mp_msg(MSGT_CODECCFG,MSGL_INFO,"ac: afm: status: info: [lib/dll]\n");
868 } else {
869 i = nr_vcodecs;
870 c = video_codecs;
871 mp_msg(MSGT_CODECCFG,MSGL_INFO,"vc: vfm: status: info: [lib/dll]\n");
873 if(!i) return;
874 for (/* NOTHING */; i--; c++) {
875 char* s="unknown ";
876 switch(c->status){
877 case CODECS_STATUS_WORKING: s="working ";break;
878 case CODECS_STATUS_PROBLEMS: s="problems";break;
879 case CODECS_STATUS_NOT_WORKING: s="crashing";break;
880 case CODECS_STATUS_UNTESTED: s="untested";break;
882 if(c->dll)
883 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s [%s]\n",c->name,c->drv,s,c->info,c->dll);
884 else
885 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s\n",c->name,c->drv,s,c->info);
893 #ifdef CODECS2HTML
894 void wrapline(FILE *f2,char *s){
895 int c;
896 if(!s){
897 fprintf(f2,"-");
898 return;
900 while((c=*s++)){
901 if(c==',') fprintf(f2,"<br>"); else fputc(c,f2);
905 void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
906 int c,d;
907 while((c=fgetc(f1))>=0){
908 if(c!='%'){
909 fputc(c,f2);
910 continue;
912 d=fgetc(f1);
914 switch(d){
915 case '.':
916 return; // end of section
917 case 'n':
918 wrapline(f2,codec->name); break;
919 case 'i':
920 wrapline(f2,codec->info); break;
921 case 'c':
922 wrapline(f2,codec->comment); break;
923 case 'd':
924 wrapline(f2,codec->dll); break;
925 case 'D':
926 fprintf(f2,"%c",!strcmp(codec->drv,"dshow")?'+':'-'); break;
927 case 'F':
928 for(d=0;d<CODECS_MAX_FOURCC;d++)
929 if(!d || codec->fourcc[d]!=0xFFFFFFFF)
930 fprintf(f2,"%s%.4s",d?"<br>":"",(codec->fourcc[d]==0xFFFFFFFF || codec->fourcc[d]<0x20202020)?!d?"-":"":(char*) &codec->fourcc[d]);
931 break;
932 case 'f':
933 for(d=0;d<CODECS_MAX_FOURCC;d++)
934 if(codec->fourcc[d]!=0xFFFFFFFF)
935 fprintf(f2,"%s0x%X",d?"<br>":"",codec->fourcc[d]);
936 break;
937 case 'Y':
938 for(d=0;d<CODECS_MAX_OUTFMT;d++)
939 if(codec->outfmt[d]!=0xFFFFFFFF){
940 for (c=0; fmt_table[c].name; c++)
941 if(fmt_table[c].num==codec->outfmt[d]) break;
942 if(fmt_table[c].name)
943 fprintf(f2,"%s%s",d?"<br>":"",fmt_table[c].name);
945 break;
946 default:
947 fputc(c,f2);
948 fputc(d,f2);
954 void skiphtml(FILE *f1){
955 int c,d;
956 while((c=fgetc(f1))>=0){
957 if(c!='%'){
958 continue;
960 d=fgetc(f1);
961 if(d=='.') return; // end of section
965 static void print_int_array(const unsigned int* a, int size)
967 printf("{ ");
968 while (size--)
969 if(abs(*a)<256)
970 printf("%d%s", *a++, size?", ":"");
971 else
972 printf("0x%X%s", *a++, size?", ":"");
973 printf(" }");
976 static void print_char_array(const unsigned char* a, int size)
978 printf("{ ");
979 while (size--)
980 if((*a)<10)
981 printf("%d%s", *a++, size?", ":"");
982 else
983 printf("0x%02x%s", *a++, size?", ":"");
984 printf(" }");
987 static void print_string(const char* s)
989 if (!s) printf("NULL");
990 else printf("\"%s\"", s);
993 int main(int argc, char* argv[])
995 codecs_t *cl;
996 FILE *f1;
997 FILE *f2;
998 int c,d,i;
999 int pos;
1000 int section=-1;
1001 int nr_codecs;
1002 int win32=-1;
1003 int dshow=-1;
1004 int win32ex=-1;
1007 * Take path to codecs.conf from command line, or fall back on
1008 * etc/codecs.conf
1010 if (!(nr_codecs = parse_codec_cfg((argc>1)?argv[1]:"etc/codecs.conf")))
1011 exit(1);
1013 if (argc > 1) {
1014 int i, j;
1015 const char* nm[2];
1016 codecs_t* cod[2];
1017 int nr[2];
1019 nm[0] = "builtin_video_codecs";
1020 cod[0] = video_codecs;
1021 nr[0] = nr_vcodecs;
1023 nm[1] = "builtin_audio_codecs";
1024 cod[1] = audio_codecs;
1025 nr[1] = nr_acodecs;
1027 printf("/* GENERATED FROM %s, DO NOT EDIT! */\n\n",argv[1]);
1028 printf("#include <stddef.h>\n",argv[1]);
1029 printf("#include \"codec-cfg.h\"\n\n",argv[1]);
1031 for (i=0; i<2; i++) {
1032 printf("const codecs_t %s[] = {\n", nm[i]);
1033 for (j = 0; j < nr[i]; j++) {
1034 printf("{");
1036 print_int_array(cod[i][j].fourcc, CODECS_MAX_FOURCC);
1037 printf(", /* fourcc */\n");
1039 print_int_array(cod[i][j].fourccmap, CODECS_MAX_FOURCC);
1040 printf(", /* fourccmap */\n");
1042 print_int_array(cod[i][j].outfmt, CODECS_MAX_OUTFMT);
1043 printf(", /* outfmt */\n");
1045 print_char_array(cod[i][j].outflags, CODECS_MAX_OUTFMT);
1046 printf(", /* outflags */\n");
1048 print_int_array(cod[i][j].infmt, CODECS_MAX_INFMT);
1049 printf(", /* infmt */\n");
1051 print_char_array(cod[i][j].inflags, CODECS_MAX_INFMT);
1052 printf(", /* inflags */\n");
1054 print_string(cod[i][j].name); printf(", /* name */\n");
1055 print_string(cod[i][j].info); printf(", /* info */\n");
1056 print_string(cod[i][j].comment); printf(", /* comment */\n");
1057 print_string(cod[i][j].dll); printf(", /* dll */\n");
1058 print_string(cod[i][j].drv); printf(", /* drv */\n");
1060 printf("{ 0x%08lx, %hu, %hu,",
1061 cod[i][j].guid.f1,
1062 cod[i][j].guid.f2,
1063 cod[i][j].guid.f3);
1064 print_char_array(cod[i][j].guid.f4, sizeof(cod[i][j].guid.f4));
1065 printf(" }, /* GUID */\n");
1066 printf("%hd /* flags */, %hd /* status */, %hd /* cpuflags */ }\n",
1067 cod[i][j].flags,
1068 cod[i][j].status,
1069 cod[i][j].cpuflags);
1070 if (j < nr[i]) printf(",\n");
1072 printf("};\n\n");
1074 exit(0);
1077 f1=fopen("DOCS/tech/codecs-in.html","rb"); if(!f1) exit(1);
1078 f2=fopen("DOCS/codecs-status.html","wb"); if(!f2) exit(1);
1080 while((c=fgetc(f1))>=0){
1081 if(c!='%'){
1082 fputc(c,f2);
1083 continue;
1085 d=fgetc(f1);
1086 if(d>='0' && d<='9'){
1087 // begin section
1088 section=d-'0';
1089 //printf("BEGIN %d\n",section);
1090 if(section>=5){
1091 // audio
1092 cl = audio_codecs;
1093 nr_codecs = nr_acodecs;
1094 dshow=7;win32=4;
1095 } else {
1096 // video
1097 cl = video_codecs;
1098 nr_codecs = nr_vcodecs;
1099 dshow=4;win32=2;win32ex=6;
1101 pos=ftell(f1);
1102 for(i=0;i<nr_codecs;i++){
1103 fseek(f1,pos,SEEK_SET);
1104 switch(section){
1105 case 0:
1106 case 5:
1107 if(cl[i].status==CODECS_STATUS_WORKING)
1108 // if(!(!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1109 parsehtml(f1,f2,&cl[i],section,dshow);
1110 break;
1111 #if 0
1112 case 1:
1113 case 6:
1114 if(cl[i].status==CODECS_STATUS_WORKING)
1115 if((!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1116 parsehtml(f1,f2,&cl[i],section,dshow);
1117 break;
1118 #endif
1119 case 2:
1120 case 7:
1121 if(cl[i].status==CODECS_STATUS_PROBLEMS)
1122 parsehtml(f1,f2,&cl[i],section,dshow);
1123 break;
1124 case 3:
1125 case 8:
1126 if(cl[i].status==CODECS_STATUS_NOT_WORKING)
1127 parsehtml(f1,f2,&cl[i],section,dshow);
1128 break;
1129 case 4:
1130 case 9:
1131 if(cl[i].status==CODECS_STATUS_UNTESTED)
1132 parsehtml(f1,f2,&cl[i],section,dshow);
1133 break;
1134 default:
1135 printf("Warning! unimplemented section: %d\n",section);
1138 fseek(f1,pos,SEEK_SET);
1139 skiphtml(f1);
1140 //void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
1142 continue;
1144 fputc(c,f2);
1145 fputc(d,f2);
1148 fclose(f2);
1149 fclose(f1);
1150 return 0;
1153 #endif
1155 #ifdef TESTING
1156 int main(void)
1158 codecs_t *c;
1159 int i,j, nr_codecs, state;
1161 if (!(parse_codec_cfg("etc/codecs.conf")))
1162 return 0;
1163 if (!video_codecs)
1164 printf("no videoconfig.\n");
1165 if (!audio_codecs)
1166 printf("no audioconfig.\n");
1168 printf("videocodecs:\n");
1169 c = video_codecs;
1170 nr_codecs = nr_vcodecs;
1171 state = 0;
1172 next:
1173 if (c) {
1174 printf("number of %scodecs: %d\n", state==0?"video":"audio",
1175 nr_codecs);
1176 for(i=0;i<nr_codecs;i++, c++){
1177 printf("\n============== %scodec %02d ===============\n",
1178 state==0?"video":"audio",i);
1179 printf("name='%s'\n",c->name);
1180 printf("info='%s'\n",c->info);
1181 printf("comment='%s'\n",c->comment);
1182 printf("dll='%s'\n",c->dll);
1183 /* printf("flags=%X driver=%d status=%d cpuflags=%d\n",
1184 c->flags, c->driver, c->status, c->cpuflags); */
1185 printf("flags=%X status=%d cpuflags=%d\n",
1186 c->flags, c->status, c->cpuflags);
1188 for(j=0;j<CODECS_MAX_FOURCC;j++){
1189 if(c->fourcc[j]!=0xFFFFFFFF){
1190 printf("fourcc %02d: %08X (%.4s) ===> %08X (%.4s)\n",j,c->fourcc[j],(char *) &c->fourcc[j],c->fourccmap[j],(char *) &c->fourccmap[j]);
1194 for(j=0;j<CODECS_MAX_OUTFMT;j++){
1195 if(c->outfmt[j]!=0xFFFFFFFF){
1196 printf("outfmt %02d: %08X (%.4s) flags: %d\n",j,c->outfmt[j],(char *) &c->outfmt[j],c->outflags[j]);
1200 for(j=0;j<CODECS_MAX_INFMT;j++){
1201 if(c->infmt[j]!=0xFFFFFFFF){
1202 printf("infmt %02d: %08X (%.4s) flags: %d\n",j,c->infmt[j],(char *) &c->infmt[j],c->inflags[j]);
1206 printf("GUID: %08lX %04X %04X",c->guid.f1,c->guid.f2,c->guid.f3);
1207 for(j=0;j<8;j++) printf(" %02X",c->guid.f4[j]);
1208 printf("\n");
1213 if (!state) {
1214 printf("audiocodecs:\n");
1215 c = audio_codecs;
1216 nr_codecs = nr_acodecs;
1217 state = 1;
1218 goto next;
1220 return 0;
1223 #endif