core: Improve handling of bad timestamps
[mplayer.git] / codec-cfg.c
blob5e7847db403ac2dd401c39f1acd081c401397a24
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>
27 #include <stdint.h>
29 #include "config.h"
30 #include "mp_msg.h"
31 #ifdef CODECS2HTML
32 #ifdef __GNUC__
33 #define mp_msg(t, l, m, args...) fprintf(stderr, m, ##args)
34 #else
35 #define mp_msg(t, l, ...) fprintf(stderr, __VA_ARGS__)
36 #endif
37 #endif
39 #include "help_mp.h"
41 #include "libmpcodecs/img_format.h"
42 #include "codec-cfg.h"
44 #ifndef CODECS2HTML
45 #include "codecs.conf.h"
46 #endif
48 #define mmioFOURCC( ch0, ch1, ch2, ch3 ) \
49 ( (uint32_t)(uint8_t)(ch0) | ( (uint32_t)(uint8_t)(ch1) << 8 ) | \
50 ( (uint32_t)(uint8_t)(ch2) << 16 ) | ( (uint32_t)(uint8_t)(ch3) << 24 ) )
52 #define PRINT_LINENUM mp_msg(MSGT_CODECCFG,MSGL_ERR," at line %d\n", line_num)
54 #define MAX_NR_TOKEN 16
56 #define MAX_LINE_LEN 1000
58 #define RET_EOF -1
59 #define RET_EOL -2
61 #define TYPE_VIDEO 0
62 #define TYPE_AUDIO 1
64 char * codecs_file = NULL;
66 static int add_to_fourcc(char *s, char *alias, unsigned int *fourcc,
67 unsigned int *map)
69 int i, j, freeslots;
70 unsigned int tmp;
72 /* find first unused slot */
73 for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++)
74 /* NOTHING */;
75 freeslots = CODECS_MAX_FOURCC - i;
76 if (!freeslots)
77 goto err_out_too_many;
79 do {
80 tmp = mmioFOURCC(s[0], s[1], s[2], s[3]);
81 for (j = 0; j < i; j++)
82 if (tmp == fourcc[j])
83 goto err_out_duplicated;
84 fourcc[i] = tmp;
85 map[i] = alias ? mmioFOURCC(alias[0], alias[1], alias[2], alias[3]) : tmp;
86 s += 4;
87 i++;
88 } while ((*(s++) == ',') && --freeslots);
90 if (!freeslots)
91 goto err_out_too_many;
92 if (*(--s) != '\0')
93 goto err_out_parse_error;
94 return 1;
95 err_out_duplicated:
96 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_DuplicateFourcc);
97 return 0;
98 err_out_too_many:
99 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_TooManyFourccs);
100 return 0;
101 err_out_parse_error:
102 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseError);
103 return 0;
106 static int add_to_format(char *s, char *alias,unsigned int *fourcc, unsigned int *fourccmap)
108 int i, j;
109 char *endptr;
111 /* find first unused slot */
112 for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++)
113 /* NOTHING */;
114 if (i == CODECS_MAX_FOURCC) {
115 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_TooManyFourccs);
116 return 0;
119 fourcc[i]=strtoul(s,&endptr,0);
120 if (*endptr != '\0') {
121 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseErrorFIDNotNumber);
122 return 0;
125 if(alias){
126 fourccmap[i]=strtoul(alias,&endptr,0);
127 if (*endptr != '\0') {
128 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseErrorFIDAliasNotNumber);
129 return 0;
131 } else
132 fourccmap[i]=fourcc[i];
134 for (j = 0; j < i; j++)
135 if (fourcc[j] == fourcc[i]) {
136 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_DuplicateFID);
137 return 0;
140 return 1;
143 static struct {
144 const char *name;
145 const unsigned int num;
146 } fmt_table[] = {
147 {"YV12", IMGFMT_YV12},
148 {"I420", IMGFMT_I420},
149 {"IYUV", IMGFMT_IYUV},
150 {"NV12", IMGFMT_NV12},
151 {"NV21", IMGFMT_NV21},
152 {"YVU9", IMGFMT_YVU9},
153 {"IF09", IMGFMT_IF09},
154 {"444P", IMGFMT_444P},
155 {"422P", IMGFMT_422P},
156 {"411P", IMGFMT_411P},
157 {"Y800", IMGFMT_Y800},
158 {"Y8", IMGFMT_Y8},
160 {"YUY2", IMGFMT_YUY2},
161 {"UYVY", IMGFMT_UYVY},
162 {"YVYU", IMGFMT_YVYU},
164 {"RGB4", IMGFMT_RGB|4},
165 {"RGB8", IMGFMT_RGB|8},
166 {"RGB15", IMGFMT_RGB|15},
167 {"RGB16", IMGFMT_RGB|16},
168 {"RGB24", IMGFMT_RGB|24},
169 {"RGB32", IMGFMT_RGB|32},
170 {"BGR4", IMGFMT_BGR|4},
171 {"BGR8", IMGFMT_BGR|8},
172 {"BGR15", IMGFMT_BGR|15},
173 {"BGR16", IMGFMT_BGR|16},
174 {"BGR24", IMGFMT_BGR|24},
175 {"BGR32", IMGFMT_BGR|32},
176 {"RGB1", IMGFMT_RGB|1},
177 {"BGR1", IMGFMT_BGR|1},
179 {"MPES", IMGFMT_MPEGPES},
180 {"ZRMJPEGNI", IMGFMT_ZRMJPEGNI},
181 {"ZRMJPEGIT", IMGFMT_ZRMJPEGIT},
182 {"ZRMJPEGIB", IMGFMT_ZRMJPEGIB},
184 {"IDCT_MPEG2",IMGFMT_XVMC_IDCT_MPEG2},
185 {"MOCO_MPEG2",IMGFMT_XVMC_MOCO_MPEG2},
187 {NULL, 0}
191 static int add_to_inout(char *sfmt, char *sflags, unsigned int *outfmt,
192 unsigned char *outflags)
195 static char *flagstr[] = {
196 "flip",
197 "noflip",
198 "yuvhack",
199 "query",
200 "static",
201 NULL
204 int i, j, freeslots;
205 unsigned char flags;
207 for (i = 0; i < CODECS_MAX_OUTFMT && outfmt[i] != 0xffffffff; i++)
208 /* NOTHING */;
209 freeslots = CODECS_MAX_OUTFMT - i;
210 if (!freeslots)
211 goto err_out_too_many;
213 flags = 0;
214 if(sflags) {
215 do {
216 for (j = 0; flagstr[j] != NULL; j++)
217 if (!strncmp(sflags, flagstr[j],
218 strlen(flagstr[j])))
219 break;
220 if (flagstr[j] == NULL)
221 goto err_out_parse_error;
222 flags|=(1<<j);
223 sflags+=strlen(flagstr[j]);
224 } while (*(sflags++) == ',');
226 if (*(--sflags) != '\0')
227 goto err_out_parse_error;
230 do {
231 for (j = 0; fmt_table[j].name != NULL; j++)
232 if (!strncmp(sfmt, fmt_table[j].name, strlen(fmt_table[j].name)))
233 break;
234 if (fmt_table[j].name == NULL)
235 goto err_out_parse_error;
236 outfmt[i] = fmt_table[j].num;
237 outflags[i] = flags;
238 ++i;
239 sfmt+=strlen(fmt_table[j].name);
240 } while ((*(sfmt++) == ',') && --freeslots);
242 if (!freeslots)
243 goto err_out_too_many;
245 if (*(--sfmt) != '\0')
246 goto err_out_parse_error;
248 return 1;
249 err_out_too_many:
250 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_TooManyOut);
251 return 0;
252 err_out_parse_error:
253 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseError);
254 return 0;
257 #if 0
258 static short get_driver(char *s,int audioflag)
260 static char *audiodrv[] = {
261 "null",
262 "mp3lib",
263 "pcm",
264 "libac3",
265 "acm",
266 "alaw",
267 "msgsm",
268 "dshow",
269 "dvdpcm",
270 "hwac3",
271 "libvorbis",
272 "ffmpeg",
273 "libmad",
274 "msadpcm",
275 "liba52",
276 "g72x",
277 "imaadpcm",
278 "dk4adpcm",
279 "dk3adpcm",
280 "roqaudio",
281 "faad",
282 "realaud",
283 "libdv",
284 NULL
286 static char *videodrv[] = {
287 "null",
288 "libmpeg2",
289 "vfw",
290 "dshow",
291 "ffmpeg",
292 "vfwex",
293 "raw",
294 "msrle",
295 "xanim",
296 "msvidc",
297 "fli",
298 "cinepak",
299 "qtrle",
300 "nuv",
301 "cyuv",
302 "qtsmc",
303 "ducktm1",
304 "roqvideo",
305 "qtrpza",
306 "mpng",
307 "ijpg",
308 "zlib",
309 "mpegpes",
310 "zrmjpeg",
311 "realvid",
312 "xvid",
313 "libdv",
314 NULL
316 char **drv=audioflag?audiodrv:videodrv;
317 int i;
319 for(i=0;drv[i];i++) if(!strcmp(s,drv[i])) return i;
321 return -1;
323 #endif
325 static int validate_codec(codecs_t *c, int type)
327 unsigned int i;
328 char *tmp_name = c->name;
330 for (i = 0; i < strlen(tmp_name) && isalnum(tmp_name[i]); i++)
331 /* NOTHING */;
333 if (i < strlen(tmp_name)) {
334 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_InvalidCodecName, c->name);
335 return 0;
338 if (!c->info)
339 c->info = strdup(c->name);
341 #if 0
342 if (c->fourcc[0] == 0xffffffff) {
343 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecLacksFourcc, c->name);
344 return 0;
346 #endif
348 if (!c->drv) {
349 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecLacksDriver, c->name);
350 return 0;
353 #if 0
354 #warning codec->driver == 4;... <- this should not be put in here...
355 #warning Where are they defined ????????????
356 if (!c->dll && (c->driver == 4 ||
357 (c->driver == 2 && type == TYPE_VIDEO))) {
358 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecNeedsDLL, c->name);
359 return 0;
361 #warning Can guid.f1 be 0? How does one know that it was not given?
362 // if (!(codec->flags & CODECS_FLAG_AUDIO) && codec->driver == 4)
364 if (type == TYPE_VIDEO)
365 if (c->outfmt[0] == 0xffffffff) {
366 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecNeedsOutfmt, c->name);
367 return 0;
369 #endif
370 return 1;
373 static int add_comment(char *s, char **d)
375 int pos;
377 if (!*d)
378 pos = 0;
379 else {
380 pos = strlen(*d);
381 (*d)[pos++] = '\n';
383 if (!(*d = realloc(*d, pos + strlen(s) + 1))) {
384 mp_msg(MSGT_CODECCFG,MSGL_FATAL,MSGTR_CantAllocateComment);
385 return 0;
387 strcpy(*d + pos, s);
388 return 1;
391 static short get_cpuflags(char *s)
393 static char *flagstr[] = {
394 "mmx",
395 "sse",
396 "3dnow",
397 NULL
399 int i;
400 short flags = 0;
402 do {
403 for (i = 0; flagstr[i]; i++)
404 if (!strncmp(s, flagstr[i], strlen(flagstr[i])))
405 break;
406 if (!flagstr[i])
407 goto err_out_parse_error;
408 flags |= 1<<i;
409 s += strlen(flagstr[i]);
410 } while (*(s++) == ',');
412 if (*(--s) != '\0')
413 goto err_out_parse_error;
415 return flags;
416 err_out_parse_error:
417 return 0;
420 static FILE *fp;
421 static int line_num = 0;
422 static char *line;
423 static char *token[MAX_NR_TOKEN];
424 static int read_nextline = 1;
426 static int get_token(int min, int max)
428 static int line_pos;
429 int i;
430 char c;
432 if (max >= MAX_NR_TOKEN) {
433 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_GetTokenMaxNotLessThanMAX_NR_TOKEN);
434 goto out_eof;
437 memset(token, 0x00, sizeof(*token) * max);
439 if (read_nextline) {
440 if (!fgets(line, MAX_LINE_LEN, fp))
441 goto out_eof;
442 line_pos = 0;
443 ++line_num;
444 read_nextline = 0;
446 for (i = 0; i < max; i++) {
447 while (isspace(line[line_pos]))
448 ++line_pos;
449 if (line[line_pos] == '\0' || line[line_pos] == '#' ||
450 line[line_pos] == ';') {
451 read_nextline = 1;
452 if (i >= min)
453 goto out_ok;
454 goto out_eol;
456 token[i] = line + line_pos;
457 c = line[line_pos];
458 if (c == '"' || c == '\'') {
459 token[i]++;
460 while (line[++line_pos] != c && line[line_pos])
461 /* NOTHING */;
462 } else {
463 for (/* NOTHING */; !isspace(line[line_pos]) &&
464 line[line_pos]; line_pos++)
465 /* NOTHING */;
467 if (!line[line_pos]) {
468 read_nextline = 1;
469 if (i >= min - 1)
470 goto out_ok;
471 goto out_eol;
473 line[line_pos] = '\0';
474 line_pos++;
476 out_ok:
477 return i;
478 out_eof:
479 read_nextline = 1;
480 return RET_EOF;
481 out_eol:
482 return RET_EOL;
485 static codecs_t *video_codecs=NULL;
486 static codecs_t *audio_codecs=NULL;
487 static int nr_vcodecs = 0;
488 static int nr_acodecs = 0;
490 int parse_codec_cfg(const char *cfgfile)
492 codecs_t *codec = NULL; // current codec
493 codecs_t **codecsp = NULL;// points to audio_codecs or to video_codecs
494 char *endptr; // strtoul()...
495 int *nr_codecsp;
496 int codec_type; /* TYPE_VIDEO/TYPE_AUDIO */
497 int tmp, i;
499 // in case we call it a second time
500 codecs_uninit_free();
502 nr_vcodecs = 0;
503 nr_acodecs = 0;
505 if(cfgfile==NULL) {
506 #ifdef CODECS2HTML
507 return 0;
508 #else
509 video_codecs = builtin_video_codecs;
510 audio_codecs = builtin_audio_codecs;
511 nr_vcodecs = sizeof(builtin_video_codecs)/sizeof(codecs_t);
512 nr_acodecs = sizeof(builtin_audio_codecs)/sizeof(codecs_t);
513 return 1;
514 #endif
517 mp_msg(MSGT_CODECCFG,MSGL_V,MSGTR_ReadingFile, cfgfile);
519 if ((fp = fopen(cfgfile, "r")) == NULL) {
520 mp_msg(MSGT_CODECCFG,MSGL_V,MSGTR_CantOpenFileError, cfgfile, strerror(errno));
521 return 0;
524 if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) {
525 mp_msg(MSGT_CODECCFG,MSGL_FATAL,MSGTR_CantGetMemoryForLine, strerror(errno));
526 return 0;
528 read_nextline = 1;
531 * this only catches release lines at the start of
532 * codecs.conf, before audiocodecs and videocodecs.
534 while ((tmp = get_token(1, 1)) == RET_EOL)
535 /* NOTHING */;
536 if (tmp == RET_EOF)
537 goto out;
538 if (!strcmp(token[0], "release")) {
539 if (get_token(1, 2) < 0)
540 goto err_out_parse_error;
541 tmp = atoi(token[0]);
542 if (tmp < CODEC_CFG_MIN)
543 goto err_out_release_num;
544 while ((tmp = get_token(1, 1)) == RET_EOL)
545 /* NOTHING */;
546 if (tmp == RET_EOF)
547 goto out;
548 } else
549 goto err_out_release_num;
552 * check if the next block starts with 'audiocodec' or
553 * with 'videocodec'
555 if (!strcmp(token[0], "audiocodec") || !strcmp(token[0], "videocodec"))
556 goto loop_enter;
557 goto err_out_parse_error;
559 while ((tmp = get_token(1, 1)) != RET_EOF) {
560 if (tmp == RET_EOL)
561 continue;
562 if (!strcmp(token[0], "audiocodec") ||
563 !strcmp(token[0], "videocodec")) {
564 if (!validate_codec(codec, codec_type))
565 goto err_out_not_valid;
566 loop_enter:
567 if (*token[0] == 'v') {
568 codec_type = TYPE_VIDEO;
569 nr_codecsp = &nr_vcodecs;
570 codecsp = &video_codecs;
571 } else if (*token[0] == 'a') {
572 codec_type = TYPE_AUDIO;
573 nr_codecsp = &nr_acodecs;
574 codecsp = &audio_codecs;
575 #ifdef DEBUG
576 } else {
577 mp_msg(MSGT_CODECCFG,MSGL_ERR,"picsba\n");
578 goto err_out;
579 #endif
581 if (!(*codecsp = realloc(*codecsp,
582 sizeof(codecs_t) * (*nr_codecsp + 2)))) {
583 mp_msg(MSGT_CODECCFG,MSGL_FATAL,MSGTR_CantReallocCodecsp, strerror(errno));
584 goto err_out;
586 codec=*codecsp + *nr_codecsp;
587 ++*nr_codecsp;
588 memset(codec,0,sizeof(codecs_t));
589 memset(codec->fourcc, 0xff, sizeof(codec->fourcc));
590 memset(codec->outfmt, 0xff, sizeof(codec->outfmt));
591 memset(codec->infmt, 0xff, sizeof(codec->infmt));
593 if (get_token(1, 1) < 0)
594 goto err_out_parse_error;
595 for (i = 0; i < *nr_codecsp - 1; i++) {
596 if(( (*codecsp)[i].name!=NULL) &&
597 (!strcmp(token[0], (*codecsp)[i].name)) ) {
598 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecNameNotUnique, token[0]);
599 goto err_out_print_linenum;
602 if (!(codec->name = strdup(token[0]))) {
603 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupName, strerror(errno));
604 goto err_out;
606 } else if (!strcmp(token[0], "info")) {
607 if (codec->info || get_token(1, 1) < 0)
608 goto err_out_parse_error;
609 if (!(codec->info = strdup(token[0]))) {
610 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupInfo, strerror(errno));
611 goto err_out;
613 } else if (!strcmp(token[0], "comment")) {
614 if (get_token(1, 1) < 0)
615 goto err_out_parse_error;
616 add_comment(token[0], &codec->comment);
617 } else if (!strcmp(token[0], "fourcc")) {
618 if (get_token(1, 2) < 0)
619 goto err_out_parse_error;
620 if (!add_to_fourcc(token[0], token[1],
621 codec->fourcc,
622 codec->fourccmap))
623 goto err_out_print_linenum;
624 } else if (!strcmp(token[0], "format")) {
625 if (get_token(1, 2) < 0)
626 goto err_out_parse_error;
627 if (!add_to_format(token[0], token[1],
628 codec->fourcc,codec->fourccmap))
629 goto err_out_print_linenum;
630 } else if (!strcmp(token[0], "driver")) {
631 if (get_token(1, 1) < 0)
632 goto err_out_parse_error;
633 if (!(codec->drv = strdup(token[0]))) {
634 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupDriver, strerror(errno));
635 goto err_out;
637 } else if (!strcmp(token[0], "dll")) {
638 if (get_token(1, 1) < 0)
639 goto err_out_parse_error;
640 if (!(codec->dll = strdup(token[0]))) {
641 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CantStrdupDLL, strerror(errno));
642 goto err_out;
644 } else if (!strcmp(token[0], "guid")) {
645 if (get_token(11, 11) < 0)
646 goto err_out_parse_error;
647 codec->guid.f1=strtoul(token[0],&endptr,0);
648 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
649 *endptr != '\0')
650 goto err_out_parse_error;
651 codec->guid.f2=strtoul(token[1],&endptr,0);
652 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
653 *endptr != '\0')
654 goto err_out_parse_error;
655 codec->guid.f3=strtoul(token[2],&endptr,0);
656 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
657 *endptr != '\0')
658 goto err_out_parse_error;
659 for (i = 0; i < 8; i++) {
660 codec->guid.f4[i]=strtoul(token[i + 3],&endptr,0);
661 if ((*endptr != ',' || *(endptr + 1) != '\0') &&
662 *endptr != '\0')
663 goto err_out_parse_error;
665 } else if (!strcmp(token[0], "out")) {
666 if (get_token(1, 2) < 0)
667 goto err_out_parse_error;
668 if (!add_to_inout(token[0], token[1], codec->outfmt,
669 codec->outflags))
670 goto err_out_print_linenum;
671 } else if (!strcmp(token[0], "in")) {
672 if (get_token(1, 2) < 0)
673 goto err_out_parse_error;
674 if (!add_to_inout(token[0], token[1], codec->infmt,
675 codec->inflags))
676 goto err_out_print_linenum;
677 } else if (!strcmp(token[0], "flags")) {
678 if (get_token(1, 1) < 0)
679 goto err_out_parse_error;
680 if (!strcmp(token[0], "seekable"))
681 codec->flags |= CODECS_FLAG_SEEKABLE;
682 else
683 if (!strcmp(token[0], "align16"))
684 codec->flags |= CODECS_FLAG_ALIGN16;
685 else
686 goto err_out_parse_error;
687 } else if (!strcmp(token[0], "status")) {
688 if (get_token(1, 1) < 0)
689 goto err_out_parse_error;
690 if (!strcasecmp(token[0], "working"))
691 codec->status = CODECS_STATUS_WORKING;
692 else if (!strcasecmp(token[0], "crashing"))
693 codec->status = CODECS_STATUS_NOT_WORKING;
694 else if (!strcasecmp(token[0], "untested"))
695 codec->status = CODECS_STATUS_UNTESTED;
696 else if (!strcasecmp(token[0], "buggy"))
697 codec->status = CODECS_STATUS_PROBLEMS;
698 else
699 goto err_out_parse_error;
700 } else if (!strcmp(token[0], "cpuflags")) {
701 if (get_token(1, 1) < 0)
702 goto err_out_parse_error;
703 if (!(codec->cpuflags = get_cpuflags(token[0])))
704 goto err_out_parse_error;
705 } else
706 goto err_out_parse_error;
708 if (!validate_codec(codec, codec_type))
709 goto err_out_not_valid;
710 mp_msg(MSGT_CODECCFG,MSGL_INFO,MSGTR_AudioVideoCodecTotals, nr_acodecs, nr_vcodecs);
711 if(video_codecs) video_codecs[nr_vcodecs].name = NULL;
712 if(audio_codecs) audio_codecs[nr_acodecs].name = NULL;
713 out:
714 free(line);
715 line=NULL;
716 fclose(fp);
717 return 1;
719 err_out_parse_error:
720 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_ParseError);
721 err_out_print_linenum:
722 PRINT_LINENUM;
723 err_out:
724 codecs_uninit_free();
726 free(line);
727 line=NULL;
728 line_num = 0;
729 fclose(fp);
730 return 0;
731 err_out_not_valid:
732 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_CodecDefinitionIncorrect);
733 goto err_out_print_linenum;
734 err_out_release_num:
735 mp_msg(MSGT_CODECCFG,MSGL_ERR,MSGTR_OutdatedCodecsConf);
736 goto err_out_print_linenum;
739 static void codecs_free(codecs_t* codecs,int count) {
740 int i;
741 for ( i = 0; i < count; i++)
742 if ( codecs[i].name ) {
743 if( codecs[i].name )
744 free(codecs[i].name);
745 if( codecs[i].info )
746 free(codecs[i].info);
747 if( codecs[i].comment )
748 free(codecs[i].comment);
749 if( codecs[i].dll )
750 free(codecs[i].dll);
751 if( codecs[i].drv )
752 free(codecs[i].drv);
754 if (codecs)
755 free(codecs);
758 void codecs_uninit_free(void) {
759 if (video_codecs)
760 codecs_free(video_codecs,nr_vcodecs);
761 video_codecs=NULL;
762 if (audio_codecs)
763 codecs_free(audio_codecs,nr_acodecs);
764 audio_codecs=NULL;
767 codecs_t *find_audio_codec(unsigned int fourcc, unsigned int *fourccmap,
768 codecs_t *start, int force)
770 return find_codec(fourcc, fourccmap, start, 1, force);
773 codecs_t *find_video_codec(unsigned int fourcc, unsigned int *fourccmap,
774 codecs_t *start, int force)
776 return find_codec(fourcc, fourccmap, start, 0, force);
779 codecs_t* find_codec(unsigned int fourcc,unsigned int *fourccmap,
780 codecs_t *start, int audioflag, int force)
782 int i, j;
783 codecs_t *c;
785 #if 0
786 if (start) {
787 for (/* NOTHING */; start->name; start++) {
788 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
789 if (start->fourcc[j] == fourcc) {
790 if (fourccmap)
791 *fourccmap = start->fourccmap[j];
792 return start;
796 } else
797 #endif
799 if (audioflag) {
800 i = nr_acodecs;
801 c = audio_codecs;
802 } else {
803 i = nr_vcodecs;
804 c = video_codecs;
806 if(!i) return NULL;
807 for (/* NOTHING */; i--; c++) {
808 if(start && c<=start) continue;
809 for (j = 0; j < CODECS_MAX_FOURCC; j++) {
810 // FIXME: do NOT hardwire 'null' name here:
811 if (c->fourcc[j]==fourcc || !strcmp(c->drv,"null")) {
812 if (fourccmap)
813 *fourccmap = c->fourccmap[j];
814 return c;
817 if (force) return c;
820 return NULL;
823 void stringset_init(stringset_t *set) {
824 *set = calloc(1, sizeof(char *));
827 void stringset_free(stringset_t *set) {
828 int count = 0;
829 while ((*set)[count]) free((*set)[count++]);
830 free(*set);
831 *set = NULL;
834 void stringset_add(stringset_t *set, const char *str) {
835 int count = 0;
836 while ((*set)[count]) count++;
837 count++;
838 *set = realloc(*set, sizeof(char *) * (count + 1));
839 (*set)[count - 1] = strdup(str);
840 (*set)[count] = NULL;
843 int stringset_test(stringset_t *set, const char *str) {
844 stringset_t s;
845 for (s = *set; *s; s++)
846 if (strcmp(*s, str) == 0)
847 return 1;
848 return 0;
851 void list_codecs(int audioflag){
852 int i;
853 codecs_t *c;
855 if (audioflag) {
856 i = nr_acodecs;
857 c = audio_codecs;
858 mp_msg(MSGT_CODECCFG,MSGL_INFO,"ac: afm: status: info: [lib/dll]\n");
859 } else {
860 i = nr_vcodecs;
861 c = video_codecs;
862 mp_msg(MSGT_CODECCFG,MSGL_INFO,"vc: vfm: status: info: [lib/dll]\n");
864 if(!i) return;
865 for (/* NOTHING */; i--; c++) {
866 char* s="unknown ";
867 switch(c->status){
868 case CODECS_STATUS_WORKING: s="working ";break;
869 case CODECS_STATUS_PROBLEMS: s="problems";break;
870 case CODECS_STATUS_NOT_WORKING: s="crashing";break;
871 case CODECS_STATUS_UNTESTED: s="untested";break;
873 if(c->dll)
874 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s [%s]\n",c->name,c->drv,s,c->info,c->dll);
875 else
876 mp_msg(MSGT_CODECCFG,MSGL_INFO,"%-11s %-9s %s %s\n",c->name,c->drv,s,c->info);
884 #ifdef CODECS2HTML
886 * Fake out GUI references when building the codecs2html utility.
888 #ifdef CONFIG_GUI
889 void gtkMessageBox( int type,char * str ) { return; }
890 int use_gui = 0;
891 #endif
893 void wrapline(FILE *f2,char *s){
894 int c;
895 if(!s){
896 fprintf(f2,"-");
897 return;
899 while((c=*s++)){
900 if(c==',') fprintf(f2,"<br>"); else fputc(c,f2);
904 void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
905 int c,d;
906 while((c=fgetc(f1))>=0){
907 if(c!='%'){
908 fputc(c,f2);
909 continue;
911 d=fgetc(f1);
913 switch(d){
914 case '.':
915 return; // end of section
916 case 'n':
917 wrapline(f2,codec->name); break;
918 case 'i':
919 wrapline(f2,codec->info); break;
920 case 'c':
921 wrapline(f2,codec->comment); break;
922 case 'd':
923 wrapline(f2,codec->dll); break;
924 case 'D':
925 fprintf(f2,"%c",!strcmp(codec->drv,"dshow")?'+':'-'); break;
926 case 'F':
927 for(d=0;d<CODECS_MAX_FOURCC;d++)
928 if(!d || codec->fourcc[d]!=0xFFFFFFFF)
929 fprintf(f2,"%s%.4s",d?"<br>":"",(codec->fourcc[d]==0xFFFFFFFF || codec->fourcc[d]<0x20202020)?!d?"-":"":(char*) &codec->fourcc[d]);
930 break;
931 case 'f':
932 for(d=0;d<CODECS_MAX_FOURCC;d++)
933 if(codec->fourcc[d]!=0xFFFFFFFF)
934 fprintf(f2,"%s0x%X",d?"<br>":"",codec->fourcc[d]);
935 break;
936 case 'Y':
937 for(d=0;d<CODECS_MAX_OUTFMT;d++)
938 if(codec->outfmt[d]!=0xFFFFFFFF){
939 for (c=0; fmt_table[c].name; c++)
940 if(fmt_table[c].num==codec->outfmt[d]) break;
941 if(fmt_table[c].name)
942 fprintf(f2,"%s%s",d?"<br>":"",fmt_table[c].name);
944 break;
945 default:
946 fputc(c,f2);
947 fputc(d,f2);
953 void skiphtml(FILE *f1){
954 int c,d;
955 while((c=fgetc(f1))>=0){
956 if(c!='%'){
957 continue;
959 d=fgetc(f1);
960 if(d=='.') return; // end of section
964 static void print_int_array(const int* a, int size)
966 printf("{ ");
967 while (size--)
968 if(abs(*a)<256)
969 printf("%d%s", *a++, size?", ":"");
970 else
971 printf("0x%X%s", *a++, size?", ":"");
972 printf(" }");
975 static void print_char_array(const unsigned char* a, int size)
977 printf("{ ");
978 while (size--)
979 if((*a)<10)
980 printf("%d%s", *a++, size?", ":"");
981 else
982 printf("0x%02x%s", *a++, size?", ":"");
983 printf(" }");
986 static void print_string(const char* s)
988 if (!s) printf("NULL");
989 else printf("\"%s\"", s);
992 int main(int argc, char* argv[])
994 codecs_t *cl;
995 FILE *f1;
996 FILE *f2;
997 int c,d,i;
998 int pos;
999 int section=-1;
1000 int nr_codecs;
1001 int win32=-1;
1002 int dshow=-1;
1003 int win32ex=-1;
1006 * Take path to codecs.conf from command line, or fall back on
1007 * etc/codecs.conf
1009 if (!(nr_codecs = parse_codec_cfg((argc>1)?argv[1]:"etc/codecs.conf")))
1010 exit(1);
1012 if (argc > 1) {
1013 int i, j;
1014 const char* nm[2];
1015 codecs_t* cod[2];
1016 int nr[2];
1018 nm[0] = "builtin_video_codecs";
1019 cod[0] = video_codecs;
1020 nr[0] = nr_vcodecs;
1022 nm[1] = "builtin_audio_codecs";
1023 cod[1] = audio_codecs;
1024 nr[1] = nr_acodecs;
1026 printf("/* GENERATED FROM %s, DO NOT EDIT! */\n\n",argv[1]);
1027 printf("#include <stddef.h>\n",argv[1]);
1028 printf("#include \"codec-cfg.h\"\n\n",argv[1]);
1030 for (i=0; i<2; i++) {
1031 printf("const codecs_t %s[] = {\n", nm[i]);
1032 for (j = 0; j < nr[i]; j++) {
1033 printf("{");
1035 print_int_array(cod[i][j].fourcc, CODECS_MAX_FOURCC);
1036 printf(", /* fourcc */\n");
1038 print_int_array(cod[i][j].fourccmap, CODECS_MAX_FOURCC);
1039 printf(", /* fourccmap */\n");
1041 print_int_array(cod[i][j].outfmt, CODECS_MAX_OUTFMT);
1042 printf(", /* outfmt */\n");
1044 print_char_array(cod[i][j].outflags, CODECS_MAX_OUTFMT);
1045 printf(", /* outflags */\n");
1047 print_int_array(cod[i][j].infmt, CODECS_MAX_INFMT);
1048 printf(", /* infmt */\n");
1050 print_char_array(cod[i][j].inflags, CODECS_MAX_INFMT);
1051 printf(", /* inflags */\n");
1053 print_string(cod[i][j].name); printf(", /* name */\n");
1054 print_string(cod[i][j].info); printf(", /* info */\n");
1055 print_string(cod[i][j].comment); printf(", /* comment */\n");
1056 print_string(cod[i][j].dll); printf(", /* dll */\n");
1057 print_string(cod[i][j].drv); printf(", /* drv */\n");
1059 printf("{ 0x%08lx, %hu, %hu,",
1060 cod[i][j].guid.f1,
1061 cod[i][j].guid.f2,
1062 cod[i][j].guid.f3);
1063 print_char_array(cod[i][j].guid.f4, sizeof(cod[i][j].guid.f4));
1064 printf(" }, /* GUID */\n");
1065 printf("%hd /* flags */, %hd /* status */, %hd /* cpuflags */ }\n",
1066 cod[i][j].flags,
1067 cod[i][j].status,
1068 cod[i][j].cpuflags);
1069 if (j < nr[i]) printf(",\n");
1071 printf("};\n\n");
1073 exit(0);
1076 f1=fopen("DOCS/tech/codecs-in.html","rb"); if(!f1) exit(1);
1077 f2=fopen("DOCS/codecs-status.html","wb"); if(!f2) exit(1);
1079 while((c=fgetc(f1))>=0){
1080 if(c!='%'){
1081 fputc(c,f2);
1082 continue;
1084 d=fgetc(f1);
1085 if(d>='0' && d<='9'){
1086 // begin section
1087 section=d-'0';
1088 //printf("BEGIN %d\n",section);
1089 if(section>=5){
1090 // audio
1091 cl = audio_codecs;
1092 nr_codecs = nr_acodecs;
1093 dshow=7;win32=4;
1094 } else {
1095 // video
1096 cl = video_codecs;
1097 nr_codecs = nr_vcodecs;
1098 dshow=4;win32=2;win32ex=6;
1100 pos=ftell(f1);
1101 for(i=0;i<nr_codecs;i++){
1102 fseek(f1,pos,SEEK_SET);
1103 switch(section){
1104 case 0:
1105 case 5:
1106 if(cl[i].status==CODECS_STATUS_WORKING)
1107 // if(!(!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1108 parsehtml(f1,f2,&cl[i],section,dshow);
1109 break;
1110 #if 0
1111 case 1:
1112 case 6:
1113 if(cl[i].status==CODECS_STATUS_WORKING)
1114 if((!strcmp(cl[i].drv,"vfw") || !strcmp(cl[i].drv,"dshow") || !strcmp(cl[i].drv,"vfwex") || !strcmp(cl[i].drv,"acm")))
1115 parsehtml(f1,f2,&cl[i],section,dshow);
1116 break;
1117 #endif
1118 case 2:
1119 case 7:
1120 if(cl[i].status==CODECS_STATUS_PROBLEMS)
1121 parsehtml(f1,f2,&cl[i],section,dshow);
1122 break;
1123 case 3:
1124 case 8:
1125 if(cl[i].status==CODECS_STATUS_NOT_WORKING)
1126 parsehtml(f1,f2,&cl[i],section,dshow);
1127 break;
1128 case 4:
1129 case 9:
1130 if(cl[i].status==CODECS_STATUS_UNTESTED)
1131 parsehtml(f1,f2,&cl[i],section,dshow);
1132 break;
1133 default:
1134 printf("Warning! unimplemented section: %d\n",section);
1137 fseek(f1,pos,SEEK_SET);
1138 skiphtml(f1);
1139 //void parsehtml(FILE *f1,FILE *f2,codecs_t *codec,int section,int dshow){
1141 continue;
1143 fputc(c,f2);
1144 fputc(d,f2);
1147 fclose(f2);
1148 fclose(f1);
1149 return 0;
1152 #endif
1154 #ifdef TESTING
1155 int main(void)
1157 codecs_t *c;
1158 int i,j, nr_codecs, state;
1160 if (!(parse_codec_cfg("etc/codecs.conf")))
1161 return 0;
1162 if (!video_codecs)
1163 printf("no videoconfig.\n");
1164 if (!audio_codecs)
1165 printf("no audioconfig.\n");
1167 printf("videocodecs:\n");
1168 c = video_codecs;
1169 nr_codecs = nr_vcodecs;
1170 state = 0;
1171 next:
1172 if (c) {
1173 printf("number of %scodecs: %d\n", state==0?"video":"audio",
1174 nr_codecs);
1175 for(i=0;i<nr_codecs;i++, c++){
1176 printf("\n============== %scodec %02d ===============\n",
1177 state==0?"video":"audio",i);
1178 printf("name='%s'\n",c->name);
1179 printf("info='%s'\n",c->info);
1180 printf("comment='%s'\n",c->comment);
1181 printf("dll='%s'\n",c->dll);
1182 /* printf("flags=%X driver=%d status=%d cpuflags=%d\n",
1183 c->flags, c->driver, c->status, c->cpuflags); */
1184 printf("flags=%X status=%d cpuflags=%d\n",
1185 c->flags, c->status, c->cpuflags);
1187 for(j=0;j<CODECS_MAX_FOURCC;j++){
1188 if(c->fourcc[j]!=0xFFFFFFFF){
1189 printf("fourcc %02d: %08X (%.4s) ===> %08X (%.4s)\n",j,c->fourcc[j],(char *) &c->fourcc[j],c->fourccmap[j],(char *) &c->fourccmap[j]);
1193 for(j=0;j<CODECS_MAX_OUTFMT;j++){
1194 if(c->outfmt[j]!=0xFFFFFFFF){
1195 printf("outfmt %02d: %08X (%.4s) flags: %d\n",j,c->outfmt[j],(char *) &c->outfmt[j],c->outflags[j]);
1199 for(j=0;j<CODECS_MAX_INFMT;j++){
1200 if(c->infmt[j]!=0xFFFFFFFF){
1201 printf("infmt %02d: %08X (%.4s) flags: %d\n",j,c->infmt[j],(char *) &c->infmt[j],c->inflags[j]);
1205 printf("GUID: %08lX %04X %04X",c->guid.f1,c->guid.f2,c->guid.f3);
1206 for(j=0;j<8;j++) printf(" %02X",c->guid.f4[j]);
1207 printf("\n");
1212 if (!state) {
1213 printf("audiocodecs:\n");
1214 c = audio_codecs;
1215 nr_codecs = nr_acodecs;
1216 state = 1;
1217 goto next;
1219 return 0;
1222 #endif