summaryrefslogtreecommitdiff
path: root/libavformat/matroskadec.c
diff options
context:
space:
mode:
authorAurelien Jacobs <aurel@gnuage.org>2008-08-05 00:40:00 +0000
committerAurelien Jacobs <aurel@gnuage.org>2008-08-05 00:40:00 +0000
commit789ed100d74d230bae5a2b084221cca9c8bc2bcb (patch)
tree39755fc26129a0d948c0f214c65e6c65904f7229 /libavformat/matroskadec.c
parent6e35ae2a7415361a56ce5c3f892e771af7fbe62c (diff)
matroskadec: add an ebml generic parser
Originally committed as revision 14552 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavformat/matroskadec.c')
-rw-r--r--libavformat/matroskadec.c163
1 files changed, 163 insertions, 0 deletions
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index f2d4e3c3c8..6a1aeb2794 100644
--- a/libavformat/matroskadec.c
+++ b/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)
{