4 * Copyright (C) 2001 Szabolcs Berecz <szabi@inf.elte.hu>
6 * This file is part of MPlayer.
8 * MPlayer is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * MPlayer is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
35 #include "libmpcodecs/img_format.h"
36 #include "codec-cfg.h"
38 #include "stream/stream.h"
41 static const char embedded_file
[] =
42 #include "codecs.conf.h"
44 static const struct bstr builtin_codecs_conf
= {
45 .start
= (char *)embedded_file
, .len
= sizeof(embedded_file
) - 1
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
62 static int codecs_conf_release
;
63 char * codecs_file
= NULL
;
65 static int add_to_fourcc(char *s
, char *alias
, unsigned int *fourcc
,
71 /* find first unused slot */
72 for (i
= 0; i
< CODECS_MAX_FOURCC
&& fourcc
[i
] != 0xffffffff; i
++)
74 freeslots
= CODECS_MAX_FOURCC
- i
;
76 goto err_out_too_many
;
80 goto err_out_parse_error
;
81 tmp
= mmioFOURCC(s
[0], s
[1], s
[2], s
[3]);
82 for (j
= 0; j
< i
; j
++)
84 goto err_out_duplicated
;
86 map
[i
] = alias
? mmioFOURCC(alias
[0], alias
[1], alias
[2], alias
[3]) : tmp
;
89 } while ((*(s
++) == ',') && --freeslots
);
92 goto err_out_too_many
;
94 goto err_out_parse_error
;
97 mp_tmsg(MSGT_CODECCFG
,MSGL_ERR
,"duplicated FourCC");
100 mp_tmsg(MSGT_CODECCFG
,MSGL_ERR
,"too many FourCCs/formats...");
103 mp_tmsg(MSGT_CODECCFG
,MSGL_ERR
,"parse error");
107 static int add_to_format(char *s
, char *alias
,unsigned int *fourcc
, unsigned int *fourccmap
)
112 /* find first unused slot */
113 for (i
= 0; i
< CODECS_MAX_FOURCC
&& fourcc
[i
] != 0xffffffff; i
++)
115 if (i
== CODECS_MAX_FOURCC
) {
116 mp_tmsg(MSGT_CODECCFG
,MSGL_ERR
,"too many FourCCs/formats...");
120 fourcc
[i
]=strtoul(s
,&endptr
,0);
121 if (*endptr
!= '\0') {
122 mp_tmsg(MSGT_CODECCFG
,MSGL_ERR
,"parse error (format ID not a number?)");
127 fourccmap
[i
]=strtoul(alias
,&endptr
,0);
128 if (*endptr
!= '\0') {
129 mp_tmsg(MSGT_CODECCFG
,MSGL_ERR
,"parse error (format ID alias not a number?)");
133 fourccmap
[i
]=fourcc
[i
];
135 for (j
= 0; j
< i
; j
++)
136 if (fourcc
[j
] == fourcc
[i
]) {
137 mp_tmsg(MSGT_CODECCFG
,MSGL_ERR
,"duplicated format ID");
144 static int add_to_inout(char *sfmt
, char *sflags
, unsigned int *outfmt
,
145 unsigned char *outflags
)
148 static char *flagstr
[] = {
160 for (i
= 0; i
< CODECS_MAX_OUTFMT
&& outfmt
[i
] != 0xffffffff; i
++)
162 freeslots
= CODECS_MAX_OUTFMT
- i
;
164 goto err_out_too_many
;
169 for (j
= 0; flagstr
[j
] != NULL
; j
++)
170 if (!strncmp(sflags
, flagstr
[j
],
173 if (flagstr
[j
] == NULL
)
174 goto err_out_parse_error
;
176 sflags
+=strlen(flagstr
[j
]);
177 } while (*(sflags
++) == ',');
179 if (*(--sflags
) != '\0')
180 goto err_out_parse_error
;
184 for (j
= 0; isalnum(sfmt
[j
]) || sfmt
[j
] == '_'; j
++);
185 unsigned int fmt
= imgfmt_parse((struct bstr
){sfmt
, j
}, true);
187 goto err_out_parse_error
;
192 } while ((*(sfmt
++) == ',') && --freeslots
);
195 goto err_out_too_many
;
197 if (*(--sfmt
) != '\0')
198 goto err_out_parse_error
;
202 mp_tmsg(MSGT_CODECCFG
,MSGL_ERR
,"too many out...");
205 mp_tmsg(MSGT_CODECCFG
,MSGL_ERR
,"parse error");
209 static int validate_codec(codecs_t
*c
, int type
)
212 char *tmp_name
= c
->name
;
214 for (i
= 0; i
< strlen(tmp_name
) && isalnum(tmp_name
[i
]); i
++)
217 if (i
< strlen(tmp_name
)) {
218 mp_tmsg(MSGT_CODECCFG
,MSGL_ERR
,"\ncodec(%s) name is not valid!\n", c
->name
);
223 c
->info
= strdup(c
->name
);
226 mp_tmsg(MSGT_CODECCFG
,MSGL_ERR
,"\ncodec(%s) does not have a driver!\n", c
->name
);
233 static int add_comment(char *s
, char **d
)
243 if (!(*d
= realloc(*d
, pos
+ strlen(s
) + 1))) {
244 mp_tmsg(MSGT_CODECCFG
,MSGL_FATAL
,"Can't allocate memory for comment. ");
251 static struct bstr filetext
;
252 static int line_num
= 0;
254 static char *token
[MAX_NR_TOKEN
];
255 static int read_nextline
= 1;
257 static int get_token(int min
, int max
)
263 if (max
>= MAX_NR_TOKEN
) {
264 mp_tmsg(MSGT_CODECCFG
,MSGL_ERR
,"get_token(): max >= MAX_MR_TOKEN!");
268 memset(token
, 0x00, sizeof(*token
) * max
);
273 struct bstr nextline
= bstr_getline(filetext
, &filetext
);
274 line
= nextline
.start
;
275 line
[nextline
.len
- 1] = 0;
280 for (i
= 0; i
< max
; i
++) {
281 while (isspace(line
[line_pos
]))
283 if (line
[line_pos
] == '\0' || line
[line_pos
] == '#' ||
284 line
[line_pos
] == ';') {
290 token
[i
] = line
+ line_pos
;
292 if (c
== '"' || c
== '\'') {
294 while (line
[++line_pos
] != c
&& line
[line_pos
])
297 for (/* NOTHING */; !isspace(line
[line_pos
]) &&
298 line
[line_pos
]; line_pos
++)
301 if (!line
[line_pos
]) {
307 line
[line_pos
] = '\0';
319 static codecs_t
*video_codecs
=NULL
;
320 static codecs_t
*audio_codecs
=NULL
;
321 static int nr_vcodecs
= 0;
322 static int nr_acodecs
= 0;
324 int parse_codec_cfg(const char *cfgfile
)
326 codecs_t
*codec
= NULL
; // current codec
327 codecs_t
**codecsp
= NULL
;// points to audio_codecs or to video_codecs
328 char *endptr
; // strtoul()...
330 int codec_type
; /* TYPE_VIDEO/TYPE_AUDIO */
334 for (struct bstr s
= builtin_codecs_conf
; ; bstr_getline(s
, &s
)) {
337 if (bstr_eatstart0(&s
, "release ")) {
338 codec_cfg_min
= atoi(s
.start
);
343 // in case we call it a second time
344 codecs_uninit_free();
350 // Avoid printing errors from open_stream when trying optional files
351 if (!mp_path_exists(cfgfile
)) {
352 mp_tmsg(MSGT_CODECCFG
, MSGL_V
,
353 "No optional codecs config file: %s\n", cfgfile
);
356 mp_msg(MSGT_CODECCFG
, MSGL_V
, "Reading codec config file: %s\n",
358 struct stream
*s
= open_stream(cfgfile
, NULL
, NULL
);
361 filetext
= stream_read_complete(s
, NULL
, 10000000, 1);
366 // Parsing modifies the data
367 filetext
= bstrdup(NULL
, builtin_codecs_conf
);
368 void *tmpmem
= filetext
.start
;
373 * this only catches release lines at the start of
374 * codecs.conf, before audiocodecs and videocodecs.
376 while ((tmp
= get_token(1, 1)) == RET_EOL
)
380 if (!strcmp(token
[0], "release")) {
381 if (get_token(1, 2) < 0)
382 goto err_out_parse_error
;
383 tmp
= atoi(token
[0]);
384 if (tmp
< codec_cfg_min
)
385 goto err_out_release_num
;
386 codecs_conf_release
= tmp
;
387 while ((tmp
= get_token(1, 1)) == RET_EOL
)
392 goto err_out_release_num
;
395 * check if the next block starts with 'audiocodec' or
398 if (!strcmp(token
[0], "audiocodec") || !strcmp(token
[0], "videocodec"))
400 goto err_out_parse_error
;
402 while ((tmp
= get_token(1, 1)) != RET_EOF
) {
405 if (!strcmp(token
[0], "audiocodec") ||
406 !strcmp(token
[0], "videocodec")) {
407 if (!validate_codec(codec
, codec_type
))
408 goto err_out_not_valid
;
410 if (*token
[0] == 'v') {
411 codec_type
= TYPE_VIDEO
;
412 nr_codecsp
= &nr_vcodecs
;
413 codecsp
= &video_codecs
;
415 assert(*token
[0] == 'a');
416 codec_type
= TYPE_AUDIO
;
417 nr_codecsp
= &nr_acodecs
;
418 codecsp
= &audio_codecs
;
420 if (!(*codecsp
= realloc(*codecsp
,
421 sizeof(codecs_t
) * (*nr_codecsp
+ 2)))) {
422 mp_tmsg(MSGT_CODECCFG
,MSGL_FATAL
,"Can't realloc '*codecsp': %s\n", strerror(errno
));
425 codec
=*codecsp
+ *nr_codecsp
;
427 memset(codec
,0,sizeof(codecs_t
));
428 memset(codec
->fourcc
, 0xff, sizeof(codec
->fourcc
));
429 memset(codec
->outfmt
, 0xff, sizeof(codec
->outfmt
));
430 memset(codec
->infmt
, 0xff, sizeof(codec
->infmt
));
432 if (get_token(1, 1) < 0)
433 goto err_out_parse_error
;
434 for (i
= 0; i
< *nr_codecsp
- 1; i
++) {
435 if(( (*codecsp
)[i
].name
!=NULL
) &&
436 (!strcmp(token
[0], (*codecsp
)[i
].name
)) ) {
437 mp_tmsg(MSGT_CODECCFG
,MSGL_ERR
,"Codec name '%s' isn't unique.", token
[0]);
438 goto err_out_print_linenum
;
441 if (!(codec
->name
= strdup(token
[0]))) {
442 mp_tmsg(MSGT_CODECCFG
,MSGL_ERR
,"Can't strdup -> 'name': %s\n", strerror(errno
));
445 } else if (!strcmp(token
[0], "info")) {
446 if (codec
->info
|| get_token(1, 1) < 0)
447 goto err_out_parse_error
;
448 if (!(codec
->info
= strdup(token
[0]))) {
449 mp_tmsg(MSGT_CODECCFG
,MSGL_ERR
,"Can't strdup -> 'info': %s\n", strerror(errno
));
452 } else if (!strcmp(token
[0], "comment")) {
453 if (get_token(1, 1) < 0)
454 goto err_out_parse_error
;
455 add_comment(token
[0], &codec
->comment
);
456 } else if (!strcmp(token
[0], "fourcc")) {
457 if (get_token(1, 2) < 0)
458 goto err_out_parse_error
;
459 if (!add_to_fourcc(token
[0], token
[1],
462 goto err_out_print_linenum
;
463 } else if (!strcmp(token
[0], "format")) {
464 if (get_token(1, 2) < 0)
465 goto err_out_parse_error
;
466 if (!add_to_format(token
[0], token
[1],
467 codec
->fourcc
,codec
->fourccmap
))
468 goto err_out_print_linenum
;
469 } else if (!strcmp(token
[0], "driver")) {
470 if (get_token(1, 1) < 0)
471 goto err_out_parse_error
;
472 if (!(codec
->drv
= strdup(token
[0]))) {
473 mp_tmsg(MSGT_CODECCFG
,MSGL_ERR
,"Can't strdup -> 'driver': %s\n", strerror(errno
));
476 } else if (!strcmp(token
[0], "dll")) {
477 if (get_token(1, 1) < 0)
478 goto err_out_parse_error
;
479 if (!(codec
->dll
= strdup(token
[0]))) {
480 mp_tmsg(MSGT_CODECCFG
,MSGL_ERR
,"Can't strdup -> 'dll': %s", strerror(errno
));
483 } else if (!strcmp(token
[0], "guid")) {
484 if (get_token(11, 11) < 0)
485 goto err_out_parse_error
;
486 codec
->guid
.f1
=strtoul(token
[0],&endptr
,0);
487 if ((*endptr
!= ',' || *(endptr
+ 1) != '\0') &&
489 goto err_out_parse_error
;
490 codec
->guid
.f2
=strtoul(token
[1],&endptr
,0);
491 if ((*endptr
!= ',' || *(endptr
+ 1) != '\0') &&
493 goto err_out_parse_error
;
494 codec
->guid
.f3
=strtoul(token
[2],&endptr
,0);
495 if ((*endptr
!= ',' || *(endptr
+ 1) != '\0') &&
497 goto err_out_parse_error
;
498 for (i
= 0; i
< 8; i
++) {
499 codec
->guid
.f4
[i
]=strtoul(token
[i
+ 3],&endptr
,0);
500 if ((*endptr
!= ',' || *(endptr
+ 1) != '\0') &&
502 goto err_out_parse_error
;
504 } else if (!strcmp(token
[0], "out")) {
505 if (get_token(1, 2) < 0)
506 goto err_out_parse_error
;
507 if (!add_to_inout(token
[0], token
[1], codec
->outfmt
,
509 goto err_out_print_linenum
;
510 } else if (!strcmp(token
[0], "in")) {
511 if (get_token(1, 2) < 0)
512 goto err_out_parse_error
;
513 if (!add_to_inout(token
[0], token
[1], codec
->infmt
,
515 goto err_out_print_linenum
;
516 } else if (!strcmp(token
[0], "flags")) {
517 if (get_token(1, 1) < 0)
518 goto err_out_parse_error
;
519 if (!strcmp(token
[0], "seekable"))
520 codec
->flags
|= CODECS_FLAG_SEEKABLE
;
521 else if (!strcmp(token
[0], "align16"))
522 codec
->flags
|= CODECS_FLAG_ALIGN16
;
524 goto err_out_parse_error
;
525 } else if (!strcmp(token
[0], "status")) {
526 if (get_token(1, 1) < 0)
527 goto err_out_parse_error
;
528 if (!strcasecmp(token
[0], "working"))
529 codec
->status
= CODECS_STATUS_WORKING
;
530 else if (!strcasecmp(token
[0], "crashing"))
531 codec
->status
= CODECS_STATUS_NOT_WORKING
;
532 else if (!strcasecmp(token
[0], "untested"))
533 codec
->status
= CODECS_STATUS_UNTESTED
;
534 else if (!strcasecmp(token
[0], "buggy"))
535 codec
->status
= CODECS_STATUS_PROBLEMS
;
537 goto err_out_parse_error
;
538 } else if (!strcmp(token
[0], "anyinput")) {
539 codec
->anyinput
= true;
541 goto err_out_parse_error
;
543 if (!validate_codec(codec
, codec_type
))
544 goto err_out_not_valid
;
545 mp_tmsg(MSGT_CODECCFG
, MSGL_V
, "%d audio & %d video codecs\n", nr_acodecs
,
547 if(video_codecs
) video_codecs
[nr_vcodecs
].name
= NULL
;
548 if(audio_codecs
) audio_codecs
[nr_acodecs
].name
= NULL
;
555 mp_tmsg(MSGT_CODECCFG
,MSGL_ERR
,"parse error");
556 err_out_print_linenum
:
559 codecs_uninit_free();
566 mp_tmsg(MSGT_CODECCFG
,MSGL_ERR
,"Codec is not defined correctly.");
567 goto err_out_print_linenum
;
569 mp_tmsg(MSGT_CODECCFG
,MSGL_ERR
,"This codecs.conf is too old and incompatible with this MPlayer release!");
570 goto err_out_print_linenum
;
573 static void codecs_free(codecs_t
* codecs
,int count
) {
575 for ( i
= 0; i
< count
; i
++)
576 if ( codecs
[i
].name
) {
577 free(codecs
[i
].name
);
578 free(codecs
[i
].info
);
579 free(codecs
[i
].comment
);
586 void codecs_uninit_free(void) {
588 codecs_free(video_codecs
,nr_vcodecs
);
591 codecs_free(audio_codecs
,nr_acodecs
);
595 codecs_t
*find_audio_codec(unsigned int fourcc
, unsigned int *fourccmap
,
596 codecs_t
*start
, int force
)
598 return find_codec(fourcc
, fourccmap
, start
, 1, force
);
601 codecs_t
*find_video_codec(unsigned int fourcc
, unsigned int *fourccmap
,
602 codecs_t
*start
, int force
)
604 return find_codec(fourcc
, fourccmap
, start
, 0, force
);
607 struct codecs
*find_codec(unsigned int fourcc
, unsigned int *fourccmap
,
608 codecs_t
*start
, int audioflag
, int force
)
610 struct codecs
*c
, *end
;
614 end
= c
+ nr_acodecs
;
617 end
= c
+ nr_vcodecs
;
620 c
= start
+ 1; // actually starts from the next one after the given one
621 for (; c
< end
; c
++) {
622 for (int j
= 0; j
< CODECS_MAX_FOURCC
; j
++) {
623 if (c
->fourcc
[j
] == -1)
625 if (c
->fourcc
[j
] == fourcc
) {
627 *fourccmap
= c
->fourccmap
[j
];
631 if (c
->anyinput
|| force
)
637 void stringset_init(stringset_t
*set
) {
638 *set
= calloc(1, sizeof(char *));
641 void stringset_free(stringset_t
*set
) {
643 while ((*set
)[count
]) free((*set
)[count
++]);
648 void stringset_add(stringset_t
*set
, const char *str
) {
650 while ((*set
)[count
]) count
++;
652 *set
= realloc(*set
, sizeof(char *) * (count
+ 1));
653 (*set
)[count
- 1] = strdup(str
);
654 (*set
)[count
] = NULL
;
657 int stringset_test(stringset_t
*set
, const char *str
) {
659 for (s
= *set
; *s
; s
++)
660 if (strcmp(*s
, str
) == 0)
665 void list_codecs(int audioflag
){
672 mp_msg(MSGT_CODECCFG
,MSGL_INFO
,"ac: afm: status: info: [lib/dll]\n");
676 mp_msg(MSGT_CODECCFG
,MSGL_INFO
,"vc: vfm: status: info: [lib/dll]\n");
679 for (/* NOTHING */; i
--; c
++) {
682 case CODECS_STATUS_WORKING
: s
="working ";break;
683 case CODECS_STATUS_PROBLEMS
: s
="problems";break;
684 case CODECS_STATUS_NOT_WORKING
: s
="crashing";break;
685 case CODECS_STATUS_UNTESTED
: s
="untested";break;
688 mp_msg(MSGT_CODECCFG
,MSGL_INFO
,"%-11s %-9s %s %s [%s]\n",c
->name
,c
->drv
,s
,c
->info
,c
->dll
);
690 mp_msg(MSGT_CODECCFG
,MSGL_INFO
,"%-11s %-9s %s %s\n",c
->name
,c
->drv
,s
,c
->info
);