mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-11-26 19:01:44 +02:00
matroskadec: add an ebml generic parser
Originally committed as revision 14552 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
6e35ae2a74
commit
789ed100d7
@ -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…
Reference in New Issue
Block a user