matroskadec: add an ebml generic parser

Originally committed as revision 14552 to svn://svn.ffmpeg.org/ffmpeg/trunk
pull/126/head
Aurelien Jacobs 17 years ago
parent 6e35ae2a74
commit 789ed100d7
  1. 163
      libavformat/matroskadec.c

@ -44,6 +44,42 @@
#include <bzlib.h>
#endif
typedef enum {
EBML_NONE,
EBML_UINT,
EBML_FLOAT,
EBML_STR,
EBML_UTF8,
EBML_BIN,
EBML_NEST,
EBML_PASS,
EBML_STOP,
} EbmlType;
typedef const struct EbmlSyntax {
uint32_t id;
EbmlType type;
int list_elem_size;
int data_offset;
union {
uint64_t u;
double f;
const char *s;
const struct EbmlSyntax *n;
} def;
} EbmlSyntax;
typedef struct {
int nb_elem;
void *elem;
} EbmlList;
typedef struct {
int size;
uint8_t *data;
int64_t pos;
} EbmlBin;
typedef struct Track {
MatroskaTrackType type;
@ -906,6 +942,133 @@ matroska_probe (AVProbeData *p)
* From here on, it's all XML-style DTD stuff... Needs no comments.
*/
static int ebml_parse(MatroskaDemuxContext *matroska, EbmlSyntax *syntax,
void *data, uint32_t expected_id, int once);
static int ebml_parse_elem(MatroskaDemuxContext *matroska,
EbmlSyntax *syntax, void *data)
{
uint32_t id = syntax->id;
EbmlBin *bin;
int res;
data = (char *)data + syntax->data_offset;
if (syntax->list_elem_size) {
EbmlList *list = data;
list->elem = av_realloc(list->elem, (list->nb_elem+1)*syntax->list_elem_size);
data = (char*)list->elem + list->nb_elem*syntax->list_elem_size;
memset(data, 0, syntax->list_elem_size);
list->nb_elem++;
}
bin = data;
switch (syntax->type) {
case EBML_UINT: return ebml_read_uint (matroska, &id, data);
case EBML_FLOAT: return ebml_read_float(matroska, &id, data);
case EBML_STR:
case EBML_UTF8: av_free(*(char **)data);
return ebml_read_ascii(matroska, &id, data);
case EBML_BIN: av_free(bin->data);
bin->pos = url_ftell(matroska->ctx->pb);
return ebml_read_binary(matroska, &id, &bin->data,
&bin->size);
case EBML_NEST: if ((res=ebml_read_master(matroska, &id)) < 0)
return res;
if (id == MATROSKA_ID_SEGMENT)
matroska->segment_start = url_ftell(matroska->ctx->pb);
return ebml_parse(matroska, syntax->def.n, data, 0, 0);
case EBML_PASS: return ebml_parse(matroska, syntax->def.n, data, 0, 1);
case EBML_STOP: *(int *)data = 1; return 1;
default: return ebml_read_skip(matroska);
}
}
static int ebml_parse_id(MatroskaDemuxContext *matroska, EbmlSyntax *syntax,
uint32_t id, void *data)
{
int i;
for (i=0; syntax[i].id; i++)
if (id == syntax[i].id)
break;
if (!syntax[i].id)
av_log(matroska->ctx, AV_LOG_INFO, "Unknown entry 0x%X\n", id);
return ebml_parse_elem(matroska, &syntax[i], data);
}
static int ebml_parse(MatroskaDemuxContext *matroska, EbmlSyntax *syntax,
void *data, uint32_t expected_id, int once)
{
int i, res = 0;
uint32_t id = 0;
for (i=0; syntax[i].id; i++)
switch (syntax[i].type) {
case EBML_UINT:
*(uint64_t *)((char *)data+syntax[i].data_offset) = syntax[i].def.u;
break;
case EBML_FLOAT:
*(double *)((char *)data+syntax[i].data_offset) = syntax[i].def.f;
break;
case EBML_STR:
case EBML_UTF8:
*(char **)((char *)data+syntax[i].data_offset) = av_strdup(syntax[i].def.s);
break;
}
if (expected_id) {
res = ebml_read_master(matroska, &id);
if (id != expected_id)
return AVERROR_INVALIDDATA;
if (id == MATROSKA_ID_SEGMENT)
matroska->segment_start = url_ftell(matroska->ctx->pb);
}
while (!res) {
if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
res = AVERROR(EIO);
break;
} else if (matroska->level_up) {
matroska->level_up--;
break;
}
res = ebml_parse_id(matroska, syntax, id, data);
if (once)
break;
if (matroska->level_up) {
matroska->level_up--;
break;
}
}
return res;
}
static void ebml_free(EbmlSyntax *syntax, void *data)
{
int i, j;
for (i=0; syntax[i].id; i++) {
void *data_off = (char *)data + syntax[i].data_offset;
switch (syntax[i].type) {
case EBML_STR:
case EBML_UTF8: av_freep(data_off); break;
case EBML_BIN: av_freep(&((EbmlBin *)data_off)->data); break;
case EBML_NEST:
if (syntax[i].list_elem_size) {
EbmlList *list = data_off;
char *ptr = list->elem;
for (j=0; j<list->nb_elem; j++, ptr+=syntax[i].list_elem_size)
ebml_free(syntax[i].def.n, ptr);
av_free(list->elem);
} else
ebml_free(syntax[i].def.n, data_off);
default: break;
}
}
}
static int
matroska_parse_info (MatroskaDemuxContext *matroska)
{

Loading…
Cancel
Save