Document that and why deinterlacing is not working
[mplayer/glamo.git] / codec-cfg.c
blobbb09f109fdb1968f568a38568b81d7dd8e2f4131
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 struct {
142 const char *name;
143 const unsigned int num;
144 } fmt_table[] = {
145 {"YV12", IMGFMT_YV12},
146 {"I420", IMGFMT_I420},
147 {"IYUV", IMGFMT_IYUV},
148 {"NV12", IMGFMT_NV12},
149 {"NV21", IMGFMT_NV21},
150 {"YVU9", IMGFMT_YVU9},
151 {"IF09", IMGFMT_IF09},
152 {"444P", IMGFMT_444P},
153 {"422P", IMGFMT_422P},
154 {"411P", IMGFMT_411P},
155 {"Y800", IMGFMT_Y800},
156 {"Y8", IMGFMT_Y8},
158 {"YUY2", IMGFMT_YUY2},
159 {"UYVY", IMGFMT_UYVY},
160 {"YVYU", IMGFMT_YVYU},
162 {"RGB4", IMGFMT_RGB|4},
163 {"RGB8", IMGFMT_RGB|8},
164 {"RGB15", IMGFMT_RGB|15},
165 {"RGB16", IMGFMT_RGB|16},
166 {"RGB24", IMGFMT_RGB|24},
167 {"RGB32", IMGFMT_RGB|32},
168 {"BGR4", IMGFMT_BGR|4},
169 {"BGR8", IMGFMT_BGR|8},
170 {"BGR15", IMGFMT_BGR|15},
171 {"BGR16", IMGFMT_BGR|16},
172 {"BGR24", IMGFMT_BGR|24},
173 {"BGR32", IMGFMT_BGR|32},
174 {"RGB1", IMGFMT_RGB|1},
175 {"BGR1", IMGFMT_BGR|1},
177 {"MPES", IMGFMT_MPEGPES},
178 {"ZRMJPEGNI", IMGFMT_ZRMJPEGNI},
179 {"ZRMJPEGIT", IMGFMT_ZRMJPEGIT},
180 {"ZRMJPEGIB", IMGFMT_ZRMJPEGIB},
182 {"IDCT_MPEG2",IMGFMT_XVMC_IDCT_MPEG2},
183 {"MOCO_MPEG2",IMGFMT_XVMC_MOCO_MPEG2},
185 {"VDPAU_MPEG1",IMGFMT_VDPAU_MPEG1},
186 {"VDPAU_MPEG2",IMGFMT_VDPAU_MPEG2},
187 {"VDPAU_H264",IMGFMT_VDPAU_H264},
188 {"VDPAU_WMV3",IMGFMT_VDPAU_WMV3},
189 {"VDPAU_VC1",IMGFMT_VDPAU_VC1},
191 {NULL, 0}
195 static int add_to_inout(char *sfmt, char *sflags, unsigned int *outfmt,
196 unsigned char *outflags)
199 static char *flagstr[] = {
200 "flip",
201 "noflip",
202 "yuvhack",
203 "query",
204 "static",
205 NULL
208 int i, j, freeslots;
209 unsigned char flags;
211 for (i = 0; i < CODECS_MAX_OUTFMT && outfmt[i] != 0xffffffff; i++)
212 /* NOTHING */;
213 freeslots = CODECS_MAX_OUTFMT - i;
214 if (!freeslots)
215 goto err_out_too_many;
217 flags = 0;
218 if(sflags) {
219 do {
220 for (j = 0; flagstr[j] != NULL; j++)
221 if (!strncmp(sflags, flagstr[j],
222 strlen(flagstr[j])))
223 break;
224 if (flagstr[j] == NULL)
225 goto err_out_parse_error;
226 flags|=(1<<j);
227 sflags+=strlen(flagstr[j]);
228 } while (*(sflags++) == ',');
230 if (*(--sflags) != '\0')
231 goto err_out_parse_error;
234 do {
235 for (j = 0; fmt_table[j].name != NULL; j++)
236 if (!strncmp(sfmt, fmt_table[j].name, strlen(fmt_table[j].name)))
237 break;
238 if (fmt_table[j].name == NULL)
239 goto err_out_parse_error;
240 outfmt[i] = fmt_table[j].num;
241 outflags[i] = flags;
242 ++i;
243 sfmt+=strlen(fmt_table[j].name);
244 } while ((*(sfmt++) == ',') && --freeslots);
246 if (!freeslots)
247 goto err_out_too_many;
249 if (*(--sfmt) != '\0')
250 goto err_out_parse_error;
252 return 1;
253 err_out_too_many:
254 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_TooManyOut);
255 return 0;
256 err_out_parse_error:
257 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseError);
258 return 0;
261 #if 0
262 static short get_driver(char *s,int audioflag)
264 static char *audiodrv[] = {
265 "null",
266 "mp3lib",
267 "pcm",
268 "libac3",
269 "acm",
270 "alaw",
271 "msgsm",
272 "dshow",
273 "dvdpcm",
274 "hwac3",
275 "libvorbis",
276 "ffmpeg",
277 "libmad",
278 "msadpcm",
279 "liba52",
280 "g72x",
281 "imaadpcm",
282 "dk4adpcm",
283 "dk3adpcm",
284 "roqaudio",
285 "faad",
286 "realaud",
287 "libdv",
288 NULL
290 static char *videodrv[] = {
291 "null",
292 "libmpeg2",
293 "vfw",
294 "dshow",
295 "ffmpeg",
296 "vfwex",
297 "raw",
298 "msrle",
299 "xanim",
300 "msvidc",
301 "fli",
302 "cinepak",
303 "qtrle",
304 "nuv",
305 "cyuv",
306 "qtsmc",
307 "ducktm1",
308 "roqvideo",
309 "qtrpza",
310 "mpng",
311 "ijpg",
312 "zlib",
313 "mpegpes",
314 "zrmjpeg",
315 "realvid",
316 "xvid",
317 "libdv",
318 NULL
320 char **drv=audioflag?audiodrv:videodrv;
321 int i;
323 for(i=0;drv[i];i++) if(!strcmp(s,drv[i])) return i;
325 return -1;
327 #endif
329 static int validate_codec(codecs_t *c, int type)
331 unsigned int i;
332 char *tmp_name = c->name;
334 for (i = 0; i < strlen(tmp_name) && isalnum(tmp_name[i]); i++)
335 /* NOTHING */;
337 if (i < strlen(tmp_name)) {
338 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_InvalidCodecName, c->name);
339 return 0;
342 if (!c->info)
343 c->info = strdup(c->name);
345 #if 0
346 if (c->fourcc[0] == 0xffffffff) {
347 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecLacksFourcc, c->name);
348 return 0;
350 #endif
352 if (!c->drv) {
353 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecLacksDriver, c->name);
354 return 0;
357 #if 0
358 #warning codec->driver == 4;... <- this should not be put in here...
359 #warning Where are they defined ????????????
360 if (!c->dll && (c->driver == 4 ||
361 (c->driver == 2 && type == TYPE_VIDEO))) {
362 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecNeedsDLL, c->name);
363 return 0;
365 #warning Can guid.f1 be 0? How does one know that it was not given?
366 // if (!(codec->flags & CODECS_FLAG_AUDIO) && codec->driver == 4)
368 if (type == TYPE_VIDEO)
369 if (c->outfmt[0] == 0xffffffff) {
370 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecNeedsOutfmt, c->name);
371 return 0;
373 #endif
374 return 1;
377 static int add_comment(char *s, char **d)
379 int pos;
381 if (!*d)
382 pos = 0;
383 else {
384 pos = strlen(*d);
385 (*d)[pos++] = '\n';
387 if (!(*d = realloc(*d, pos + strlen(s) + 1))) {
388 mp_msg(MSGT_CODECCFG,MSGL_FATAL,MSGTR_CantAllocateComment);
389 return 0;
391 strcpy(*d + pos, s);
392 return 1;
395 static short get_cpuflags(char *s)
397 static char *flagstr[] = {
398 "mmx",
399 "sse",
400 "3dnow",
401 NULL
403 int i;
404 short flags = 0;
406 do {
407 for (i = 0; flagstr[i]; i++)
408 if (!strncmp(s, flagstr[i], strlen(flagstr[i])))
409 break;
410 if (!flagstr[i])
411 goto err_out_parse_error;
412 flags |= 1<<i;
413 s += strlen(flagstr[i]);
414 } while (*(s++) == ',');
416 if (*(--s) != '\0')
417 goto err_out_parse_error;
419 return flags;
420 err_out_parse_error:
421 return 0;
424 static FILE *fp;
425 static int line_num = 0;
426 static char *line;
427 static char *token[MAX_NR_TOKEN];
428 static int read_nextline = 1;
430 static int get_token(int min, int max)
432 static int line_pos;
433 int i;
434 char c;
436 if (max >= MAX_NR_TOKEN) {
437 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_GetTokenMaxNotLessThanMAX_NR_TOKEN);
438 goto out_eof;
441 memset(token, 0x00, sizeof(*token) * max);
443 if (read_nextline) {
444 if (!fgets(line, MAX_LINE_LEN, fp))
445 goto out_eof;
446 line_pos = 0;
447 ++line_num;
448 read_nextline = 0;
450 for (i = 0; i < max; i++) {
451 while (isspace(line[line_pos]))
452 ++line_pos;
453 if (line[line_pos] == '\0' || line[line_pos] == '#' ||
454 line[line_pos] == ';') {
455 read_nextline = 1;
456 if (i >= min)
457 goto out_ok;
458 goto out_eol;
460 token[i] = line + line_pos;
461 c = line[line_pos];
462 if (c == '"' || c == '\'') {
463 token[i]++;
464 while (line[++line_pos] != c && line[line_pos])
465 /* NOTHING */;
466 } else {
467 for (/* NOTHING */; !isspace(line[line_pos]) &&
468 line[line_pos]; line_pos++)
469 /* NOTHING */;
471 if (!line[line_pos]) {
472 read_nextline = 1;
473 if (i >= min - 1)
474 goto out_ok;
475 goto out_eol;
477 line[line_pos] = '\0';
478 line_pos++;
480 out_ok:
481 return i;
482 out_eof:
483 read_nextline = 1;
484 return RET_EOF;
485 out_eol:
486 return RET_EOL;
489 static codecs_t *video_codecs=NULL;
490 static codecs_t *audio_codecs=NULL;
491 static int nr_vcodecs = 0;
492 static int nr_acodecs = 0;
494 int parse_codec_cfg(const char *cfgfile)
496 codecs_t *codec = NULL; // current codec
497 codecs_t **codecsp = NULL;// points to audio_codecs or to video_codecs
498 char *endptr; // strtoul()...
499 int *nr_codecsp;
500 int codec_type; /* TYPE_VIDEO/TYPE_AUDIO */
501 int tmp, i;
503 // in case we call it a second time
504 codecs_uninit_free();
506 nr_vcodecs = 0;
507 nr_acodecs = 0;
509 if(cfgfile==NULL) {
510 #ifdef CODECS2HTML
511 return 0;
512 #else
513 video_codecs = builtin_video_codecs;
514 audio_codecs = builtin_audio_codecs;
515 nr_vcodecs = sizeof(builtin_video_codecs)/sizeof(codecs_t);
516 nr_acodecs = sizeof(builtin_audio_codecs)/sizeof(codecs_t);
517 return 1;
518 #endif
521 mp_msg(MSGT_CODECCFG,MSGL_V,MSGTR_ReadingFile, cfgfile);
523 if ((fp = fopen(cfgfile, "r")) == NULL) {
524 mp_msg(MSGT_CODECCFG,MSGL_V,MSGTR_CantOpenFileError, cfgfile, strerror(errno));
525 return 0;
528 if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) {
529 mp_msg(MSGT_CODECCFG,MSGL_FATAL,MSGTR_CantGetMemoryForLine, strerror(errno));
530 return 0;
532 read_nextline = 1;
535 * this only catches release lines at the start of
536 * codecs.conf, before audiocodecs and videocodecs.
538 while ((tmp = get_token(1, 1)) == RET_EOL)
539 /* NOTHING */;
540 if (tmp == RET_EOF)
541 goto out;
542 if (!strcmp(token[0], "release")) {
543 if (get_token(1, 2) < 0)
544 goto err_out_parse_error;
545 tmp = atoi(token[0]);
546 if (tmp < CODEC_CFG_MIN)
547 goto err_out_release_num;
548 while ((tmp = get_token(1, 1)) == RET_EOL)
549 /* NOTHING */;
550 if (tmp == RET_EOF)
551 goto out;
552 } else
553 goto err_out_release_num;
556 * check if the next block starts with 'audiocodec' or
557 * with 'videocodec'
559 if (!strcmp(token[0], "audiocodec") || !strcmp(token[0], "videocodec"))
560 goto loop_enter;
561 goto err_out_parse_error;
563 while ((tmp = get_token(1, 1)) != RET_EOF) {
564 if (tmp == RET_EOL)
565 continue;
566 if (!strcmp(token[0], "audiocodec") ||
567 !strcmp(token[0], "videocodec")) {
568 if (!validate_codec(codec, codec_type))
569 goto err_out_not_valid;
570 loop_enter:
571 if (*token[0] == 'v') {
572 codec_type = TYPE_VIDEO;
573 nr_codecsp = &nr_vcodecs;
574 codecsp = &video_codecs;
575 } else if (*token[0] == 'a') {
576 codec_type = TYPE_AUDIO;
577 nr_codecsp = &nr_acodecs;
578 codecsp = &audio_codecs;
579 #ifdef DEBUG
580 } else {
581 mp_msg(MSGT_CODECCFG,MSGL_ERR,"picsba\n");
582 goto err_out;
583 #endif
585 if (!(*codecsp = realloc(*codecsp,
586 sizeof(codecs_t) * (*nr_codecsp + 2)))) {
587 mp_msg(MSGT_CODECCFG,MSGL_FATAL,MSGTR_CantReallocCodecsp, strerror(errno));
588 goto err_out;
590 codec=*codecsp + *nr_codecsp;
591 ++*nr_codecsp;
592 memset(codec,0,sizeof(codecs_t));
593 memset(codec->fourcc, 0xff, sizeof(codec->fourcc));
594 memset(codec->outfmt, 0xff, sizeof(codec->outfmt));
595 memset(codec->infmt, 0xff, sizeof(codec->infmt));
597 if (get_token(1, 1) < 0)
598 goto err_out_parse_error;
599 for (i = 0; i < *nr_codecsp - 1; i++) {
600 if(( (*codecsp)[i].name!=NULL) &&
601 (!strcmp(token[0], (*codecsp)[i].name)) ) {
602 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecNameNotUnique, token[0]);
603 goto err_out_print_linenum;
606 if (!(codec->name = strdup(token[0]))) {
607 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupName, strerror(errno));
608 goto err_out;
610 } else if (!strcmp(token[0], "info")) {
611 if (codec->info || get_token(1, 1) < 0)
612 goto err_out_parse_error;
613 if (!(codec->info = strdup(token[0]))) {
614 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupInfo, strerror(errno));
615 goto err_out;
617 } else if (!strcmp(token[0], "comment")) {
618 if (get_token(1, 1) < 0)
619 goto err_out_parse_error;
620 add_comment(token[0], &codec->comment);
621 } else if (!strcmp(token[0], "fourcc")) {
622 if (get_token(1, 2) < 0)
623 goto err_out_parse_error;
624 if (!add_to_fourcc(token[0], token[1],
625 codec->fourcc,
626 codec->fourccmap))
627 goto err_out_print_linenum;
628 } else if (!strcmp(token[0], "format")) {
629 if (get_token(1, 2) < 0)
630 goto err_out_parse_error;
631 if (!add_to_format(token[0], token[1],
632 codec->fourcc,codec->fourccmap))
633 goto err_out_print_linenum;
634 } else if (!strcmp(token[0], "driver")) {
635 if (get_token(1, 1) < 0)
636 goto err_out_parse_error;
637 if (!(codec->drv = strdup(token[0]))) {
638 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupDriver, strerror(errno));
639 goto err_out;
641 } else if (!strcmp(token[0], "dll")) {
642 if (get_token(1, 1) < 0)
643 goto err_out_parse_error;
644 if (!(codec->dll = strdup(token[0]))) {
645 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupDLL, strerror(errno));
646 goto err_out;
648 } else if (!strcmp(token[0], "guid")) {
649 if (get_token(11, 11) < 0)
650 goto err_out_parse_error;
651 codec->guid.f1=strtoul(token[0],&endptr,0);
652 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
653 *endptr != '\0')
654 goto err_out_parse_error;
655 codec->guid.f2=strtoul(token[1],&endptr,0);
656 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
657 *endptr != '\0')
658 goto err_out_parse_error;
659 codec->guid.f3=strtoul(token[2],&endptr,0);
660 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
661 *endptr != '\0')
662 goto err_out_parse_error;
663 for (i = 0; i < 8; i++) {
664 codec->guid.f4[i]=strtoul(token[i + 3],&endptr,0);
665 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
666 *endptr != '\0')
667 goto err_out_parse_error;
669 } else if (!strcmp(token[0], "out")) {
670 if (get_token(1, 2) < 0)
671 goto err_out_parse_error;
672 if (!add_to_inout(token[0], token[1], codec->outfmt,
673 codec->outflags))
674 goto err_out_print_linenum;
675 } else if (!strcmp(token[0], "in")) {
676 if (get_token(1, 2) < 0)
677 goto err_out_parse_error;
678 if (!add_to_inout(token[0], token[1], codec->infmt,
679 codec->inflags))
680 goto err_out_print_linenum;
681 } else if (!strcmp(token[0], "flags")) {
682 if (get_token(1, 1) < 0)
683 goto err_out_parse_error;
684 if (!strcmp(token[0], "seekable"))
685 codec->flags |= CODECS_FLAG_SEEKABLE;
686 else
687 if (!strcmp(token[0], "align16"))
688 codec->flags |= CODECS_FLAG_ALIGN16;
689 else
690 goto err_out_parse_error;
691 } else if (!strcmp(token[0], "status")) {
692 if (get_token(1, 1) < 0)
693 goto err_out_parse_error;
694 if (!strcasecmp(token[0], "working"))
695 codec->status = CODECS_STATUS_WORKING;
696 else if (!strcasecmp(token[0], "crashing"))
697 codec->status = CODECS_STATUS_NOT_WORKING;
698 else if (!strcasecmp(token[0], "untested"))
699 codec->status = CODECS_STATUS_UNTESTED;
700 else if (!strcasecmp(token[0], "buggy"))
701 codec->status = CODECS_STATUS_PROBLEMS;
702 else
703 goto err_out_parse_error;
704 } else if (!strcmp(token[0], "cpuflags")) {
705 if (get_token(1, 1) < 0)
706 goto err_out_parse_error;
707 if (!(codec->cpuflags = get_cpuflags(token[0])))
708 goto err_out_parse_error;
709 } else
710 goto err_out_parse_error;
712 if (!validate_codec(codec, codec_type))
713 goto err_out_not_valid;
714 mp_msg(MSGT_CODECCFG,MSGL_INFO,MSGTR_AudioVideoCodecTotals, nr_acodecs, nr_vcodecs);
715 if(video_codecs) video_codecs[nr_vcodecs].name = NULL;
716 if(audio_codecs) audio_codecs[nr_acodecs].name = NULL;
717 out:
718 free(line);
719 line=NULL;
720 fclose(fp);
721 return 1;
723 err_out_parse_error:
724 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseError);
725 err_out_print_linenum:
726 PRINT_LINENUM;
727 err_out:
728 codecs_uninit_free();
730 free(line);
731 line=NULL;
732 line_num = 0;
733 fclose(fp);
734 return 0;
735 err_out_not_valid:
736 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecDefinitionIncorrect);
737 goto err_out_print_linenum;
738 err_out_release_num:
739 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_OutdatedCodecsConf);
740 goto err_out_print_linenum;
743 static void codecs_free(codecs_t* codecs,int count) {
744 int i;
745 for ( i = 0; i < count; i++)
746 if ( codecs[i].name ) {
747 if( codecs[i].name )
748 free(codecs[i].name);
749 if( codecs[i].info )
750 free(codecs[i].info);
751 if( codecs[i].comment )
752 free(codecs[i].comment);
753 if( codecs[i].dll )
754 free(codecs[i].dll);
755 if( codecs[i].drv )
756 free(codecs[i].drv);
758 if (codecs)
759 free(codecs);
762 void codecs_uninit_free(void) {
763 if (video_codecs)
764 codecs_free(video_codecs,nr_vcodecs);
765 video_codecs=NULL;
766 if (audio_codecs)
767 codecs_free(audio_codecs,nr_acodecs);
768 audio_codecs=NULL;
771 codecs_t *find_audio_codec(unsigned int fourcc, unsigned int *fourccmap,
772 codecs_t *start, int force)
774 return find_codec(fourcc, fourccmap, start, 1, force);
777 codecs_t *find_video_codec(unsigned int fourcc, unsigned int *fourccmap,
778 codecs_t *start, int force)
780 return find_codec(fourcc, fourccmap, start, 0, force);
783 codecs_t* find_codec(unsigned int fourcc,unsigned int *fourccmap,
784 codecs_t *start, int audioflag, int force)
786 int i, j;
787 codecs_t *c;
789 #if 0
790 if (start) {
791 for (/* NOTHING */; start->name; start++) {
792 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
793 if (start->fourcc[j] == fourcc) {
794 if (fourccmap)
795 *fourccmap = start->fourccmap[j];
796 return start;
800 } else
801 #endif
803 if (audioflag) {
804 i = nr_acodecs;
805 c = audio_codecs;
806 } else {
807 i = nr_vcodecs;
808 c = video_codecs;
810 if(!i) return NULL;
811 for (/* NOTHING */; i--; c++) {
812 if(start && c<=start) continue;
813 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
814 // FIXME: do NOT hardwire 'null' name here:
815 if (c->fourcc[j]==fourcc || !strcmp(c->drv,"null")) {
816 if (fourccmap)
817 *fourccmap = c->fourccmap[j];
818 return c;
821 if (force) return c;
824 return NULL;
827 void stringset_init(stringset_t *set) {
828 *set = calloc(1, sizeof(char *));
831 void stringset_free(stringset_t *set) {
832 int count = 0;
833 while ((*set)[count]) free((*set)[count++]);
834 free(*set);
835 *set = NULL;
838 void stringset_add(stringset_t *set, const char *str) {
839 int count = 0;
840 while ((*set)[count]) count++;
841 count++;
842 *set = realloc(*set, sizeof(char *) * (count + 1));
843 (*set)[count - 1] = strdup(str);
844 (*set)[count] = NULL;
847 int stringset_test(stringset_t *set, const char *str) {
848 stringset_t s;
849 for (s = *set; *s; s++)
850 if (strcmp(*s, str) == 0)
851 return 1;
852 return 0;
855 void list_codecs(int audioflag){
856 int i;
857 codecs_t *c;
859 if (audioflag) {
860 i = nr_acodecs;
861 c = audio_codecs;
862 mp_msg(MSGT_CODECCFG,MSGL_INFO,"ac: afm: status: info: [lib/dll]\n");
863 } else {
864 i = nr_vcodecs;
865 c = video_codecs;
866 mp_msg(MSGT_CODECCFG,MSGL_INFO,"vc: vfm: status: info: [lib/dll]\n");
868 if(!i) return;
869 for (/* NOTHING */; i--; c++) {
870 char* s="unknown ";
871 switch(c->status){
872 case CODECS_STATUS_WORKING: s="working ";break;
873 case CODECS_STATUS_PROBLEMS: s="problems";break;
874 case CODECS_STATUS_NOT_WORKING: s="crashing";break;
875 case CODECS_STATUS_UNTESTED: s="untested";break;
877 if(c->dll)
878 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s [%s]\n",c->name,c->drv,s,c->info,c->dll);
879 else
880 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s\n",c->name,c->drv,s,c->info);
888 #ifdef CODECS2HTML
890 * Fake out GUI references when building the codecs2html utility.
892 #ifdef CONFIG_GUI
893 void gtkMessageBox( int type,char * str ) { return; }
894 int use_gui = 0;
895 #endif
897 void wrapline(FILE *f2,char *s){
898 int c;
899 if(!s){
900 fprintf(f2,"-");
901 return;
903 while((c=*s++)){
904 if(c==',') fprintf(f2,"<br>"); else fputc(c,f2);
908 void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
909 int c,d;
910 while((c=fgetc(f1))>=0){
911 if(c!='%'){
912 fputc(c,f2);
913 continue;
915 d=fgetc(f1);
917 switch(d){
918 case '.':
919 return; // end of section
920 case 'n':
921 wrapline(f2,codec->name); break;
922 case 'i':
923 wrapline(f2,codec->info); break;
924 case 'c':
925 wrapline(f2,codec->comment); break;
926 case 'd':
927 wrapline(f2,codec->dll); break;
928 case 'D':
929 fprintf(f2,"%c",!strcmp(codec->drv,"dshow")?'+':'-'); break;
930 case 'F':
931 for(d=0;d<CODECS_MAX_FOURCC;d++)
932 if(!d || codec->fourcc[d]!=0xFFFFFFFF)
933 fprintf(f2,"%s%.4s",d?"<br>":"",(codec->fourcc[d]==0xFFFFFFFF || codec->fourcc[d]<0x20202020)?!d?"-":"":(char*) &codec->fourcc[d]);
934 break;
935 case 'f':
936 for(d=0;d<CODECS_MAX_FOURCC;d++)
937 if(codec->fourcc[d]!=0xFFFFFFFF)
938 fprintf(f2,"%s0x%X",d?"<br>":"",codec->fourcc[d]);
939 break;
940 case 'Y':
941 for(d=0;d<CODECS_MAX_OUTFMT;d++)
942 if(codec->outfmt[d]!=0xFFFFFFFF){
943 for (c=0; fmt_table[c].name; c++)
944 if(fmt_table[c].num==codec->outfmt[d]) break;
945 if(fmt_table[c].name)
946 fprintf(f2,"%s%s",d?"<br>":"",fmt_table[c].name);
948 break;
949 default:
950 fputc(c,f2);
951 fputc(d,f2);
957 void skiphtml(FILE *f1){
958 int c,d;
959 while((c=fgetc(f1))>=0){
960 if(c!='%'){
961 continue;
963 d=fgetc(f1);
964 if(d=='.') return; // end of section
968 static void print_int_array(const int* a, int size)
970 printf("{ ");
971 while (size--)
972 if(abs(*a)<256)
973 printf("%d%s", *a++, size?", ":"");
974 else
975 printf("0x%X%s", *a++, size?", ":"");
976 printf(" }");
979 static void print_char_array(const unsigned char* a, int size)
981 printf("{ ");
982 while (size--)
983 if((*a)<10)
984 printf("%d%s", *a++, size?", ":"");
985 else
986 printf("0x%02x%s", *a++, size?", ":"");
987 printf(" }");
990 static void print_string(const char* s)
992 if (!s) printf("NULL");
993 else printf("\"%s\"", s);
996 int main(int argc, char* argv[])
998 codecs_t *cl;
999 FILE *f1;
1000 FILE *f2;
1001 int c,d,i;
1002 int pos;
1003 int section=-1;
1004 int nr_codecs;
1005 int win32=-1;
1006 int dshow=-1;
1007 int win32ex=-1;
1010 * Take path to codecs.conf from command line, or fall back on
1011 * etc/codecs.conf
1013 if (!(nr_codecs = parse_codec_cfg((argc>1)?argv[1]:"etc/codecs.conf")))
1014 exit(1);
1016 if (argc > 1) {
1017 int i, j;
1018 const char* nm[2];
1019 codecs_t* cod[2];
1020 int nr[2];
1022 nm[0] = "builtin_video_codecs";
1023 cod[0] = video_codecs;
1024 nr[0] = nr_vcodecs;
1026 nm[1] = "builtin_audio_codecs";
1027 cod[1] = audio_codecs;
1028 nr[1] = nr_acodecs;
1030 printf("/* GENERATED FROM %s, DO NOT EDIT! */\n\n",argv[1]);
1031 printf("#include <stddef.h>\n",argv[1]);
1032 printf("#include \"codec-cfg.h\"\n\n",argv[1]);
1034 for (i=0; i<2; i++) {
1035 printf("const codecs_t %s[] = {\n", nm[i]);
1036 for (j = 0; j < nr[i]; j++) {
1037 printf("{");
1039 print_int_array(cod[i][j].fourcc, CODECS_MAX_FOURCC);
1040 printf(", /* fourcc */\n");
1042 print_int_array(cod[i][j].fourccmap, CODECS_MAX_FOURCC);
1043 printf(", /* fourccmap */\n");
1045 print_int_array(cod[i][j].outfmt, CODECS_MAX_OUTFMT);
1046 printf(", /* outfmt */\n");
1048 print_char_array(cod[i][j].outflags, CODECS_MAX_OUTFMT);
1049 printf(", /* outflags */\n");
1051 print_int_array(cod[i][j].infmt, CODECS_MAX_INFMT);
1052 printf(", /* infmt */\n");
1054 print_char_array(cod[i][j].inflags, CODECS_MAX_INFMT);
1055 printf(", /* inflags */\n");
1057 print_string(cod[i][j].name); printf(", /* name */\n");
1058 print_string(cod[i][j].info); printf(", /* info */\n");
1059 print_string(cod[i][j].comment); printf(", /* comment */\n");
1060 print_string(cod[i][j].dll); printf(", /* dll */\n");
1061 print_string(cod[i][j].drv); printf(", /* drv */\n");
1063 printf("{ 0x%08lx, %hu, %hu,",
1064 cod[i][j].guid.f1,
1065 cod[i][j].guid.f2,
1066 cod[i][j].guid.f3);
1067 print_char_array(cod[i][j].guid.f4, sizeof(cod[i][j].guid.f4));
1068 printf(" }, /* GUID */\n");
1069 printf("%hd /* flags */, %hd /* status */, %hd /* cpuflags */ }\n",
1070 cod[i][j].flags,
1071 cod[i][j].status,
1072 cod[i][j].cpuflags);
1073 if (j < nr[i]) printf(",\n");
1075 printf("};\n\n");
1077 exit(0);
1080 f1=fopen("DOCS/tech/codecs-in.html","rb"); if(!f1) exit(1);
1081 f2=fopen("DOCS/codecs-status.html","wb"); if(!f2) exit(1);
1083 while((c=fgetc(f1))>=0){
1084 if(c!='%'){
1085 fputc(c,f2);
1086 continue;
1088 d=fgetc(f1);
1089 if(d>='0' && d<='9'){
1090 // begin section
1091 section=d-'0';
1092 //printf("BEGIN %d\n",section);
1093 if(section>=5){
1094 // audio
1095 cl = audio_codecs;
1096 nr_codecs = nr_acodecs;
1097 dshow=7;win32=4;
1098 } else {
1099 // video
1100 cl = video_codecs;
1101 nr_codecs = nr_vcodecs;
1102 dshow=4;win32=2;win32ex=6;
1104 pos=ftell(f1);
1105 for(i=0;i<nr_codecs;i++){
1106 fseek(f1,pos,SEEK_SET);
1107 switch(section){
1108 case 0:
1109 case 5:
1110 if(cl[i].status==CODECS_STATUS_WORKING)
1111 // if(!(!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1112 parsehtml(f1,f2,&cl[i],section,dshow);
1113 break;
1114 #if 0
1115 case 1:
1116 case 6:
1117 if(cl[i].status==CODECS_STATUS_WORKING)
1118 if((!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1119 parsehtml(f1,f2,&cl[i],section,dshow);
1120 break;
1121 #endif
1122 case 2:
1123 case 7:
1124 if(cl[i].status==CODECS_STATUS_PROBLEMS)
1125 parsehtml(f1,f2,&cl[i],section,dshow);
1126 break;
1127 case 3:
1128 case 8:
1129 if(cl[i].status==CODECS_STATUS_NOT_WORKING)
1130 parsehtml(f1,f2,&cl[i],section,dshow);
1131 break;
1132 case 4:
1133 case 9:
1134 if(cl[i].status==CODECS_STATUS_UNTESTED)
1135 parsehtml(f1,f2,&cl[i],section,dshow);
1136 break;
1137 default:
1138 printf("Warning! unimplemented section: %d\n",section);
1141 fseek(f1,pos,SEEK_SET);
1142 skiphtml(f1);
1143 //void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
1145 continue;
1147 fputc(c,f2);
1148 fputc(d,f2);
1151 fclose(f2);
1152 fclose(f1);
1153 return 0;
1156 #endif
1158 #ifdef TESTING
1159 int main(void)
1161 codecs_t *c;
1162 int i,j, nr_codecs, state;
1164 if (!(parse_codec_cfg("etc/codecs.conf")))
1165 return 0;
1166 if (!video_codecs)
1167 printf("no videoconfig.\n");
1168 if (!audio_codecs)
1169 printf("no audioconfig.\n");
1171 printf("videocodecs:\n");
1172 c = video_codecs;
1173 nr_codecs = nr_vcodecs;
1174 state = 0;
1175 next:
1176 if (c) {
1177 printf("number of %scodecs: %d\n", state==0?"video":"audio",
1178 nr_codecs);
1179 for(i=0;i<nr_codecs;i++, c++){
1180 printf("\n============== %scodec %02d ===============\n",
1181 state==0?"video":"audio",i);
1182 printf("name='%s'\n",c->name);
1183 printf("info='%s'\n",c->info);
1184 printf("comment='%s'\n",c->comment);
1185 printf("dll='%s'\n",c->dll);
1186 /* printf("flags=%X driver=%d status=%d cpuflags=%d\n",
1187 c->flags, c->driver, c->status, c->cpuflags); */
1188 printf("flags=%X status=%d cpuflags=%d\n",
1189 c->flags, c->status, c->cpuflags);
1191 for(j=0;j<CODECS_MAX_FOURCC;j++){
1192 if(c->fourcc[j]!=0xFFFFFFFF){
1193 printf("fourcc %02d: %08X (%.4s) ===> %08X (%.4s)\n",j,c->fourcc[j],(char *) &c->fourcc[j],c->fourccmap[j],(char *) &c->fourccmap[j]);
1197 for(j=0;j<CODECS_MAX_OUTFMT;j++){
1198 if(c->outfmt[j]!=0xFFFFFFFF){
1199 printf("outfmt %02d: %08X (%.4s) flags: %d\n",j,c->outfmt[j],(char *) &c->outfmt[j],c->outflags[j]);
1203 for(j=0;j<CODECS_MAX_INFMT;j++){
1204 if(c->infmt[j]!=0xFFFFFFFF){
1205 printf("infmt %02d: %08X (%.4s) flags: %d\n",j,c->infmt[j],(char *) &c->infmt[j],c->inflags[j]);
1209 printf("GUID: %08lX %04X %04X",c->guid.f1,c->guid.f2,c->guid.f3);
1210 for(j=0;j<8;j++) printf(" %02X",c->guid.f4[j]);
1211 printf("\n");
1216 if (!state) {
1217 printf("audiocodecs:\n");
1218 c = audio_codecs;
1219 nr_codecs = nr_acodecs;
1220 state = 1;
1221 goto next;
1223 return 0;
1226 #endif