|
|
|
@ -594,6 +594,24 @@ static int ebml_read_ascii(ByteIOContext *pb, int size, char **str) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Read the next element as binary data. |
|
|
|
|
* 0 is success, < 0 is failure. |
|
|
|
|
*/ |
|
|
|
|
static int ebml_read_binary(ByteIOContext *pb, int length, EbmlBin *bin) |
|
|
|
|
{ |
|
|
|
|
av_free(bin->data); |
|
|
|
|
if (!(bin->data = av_malloc(length))) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
|
|
bin->size = length; |
|
|
|
|
bin->pos = url_ftell(pb); |
|
|
|
|
if (get_buffer(pb, bin->data, length) != length) |
|
|
|
|
return AVERROR(EIO); |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Read the next element, but only the header. The contents |
|
|
|
|
* are supposed to be sub-elements which can be read separately. |
|
|
|
@ -617,24 +635,6 @@ static int ebml_read_master(MatroskaDemuxContext *matroska, int length) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Read the next element as binary data. |
|
|
|
|
* 0 is success, < 0 is failure. |
|
|
|
|
*/ |
|
|
|
|
static int ebml_read_binary(ByteIOContext *pb, int length, EbmlBin *bin) |
|
|
|
|
{ |
|
|
|
|
av_free(bin->data); |
|
|
|
|
if (!(bin->data = av_malloc(length))) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
|
|
bin->size = length; |
|
|
|
|
bin->pos = url_ftell(pb); |
|
|
|
|
if (get_buffer(pb, bin->data, length) != length) |
|
|
|
|
return AVERROR(EIO); |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Read signed/unsigned "EBML" numbers. |
|
|
|
|
* Return: number of bytes processed, < 0 on error. |
|
|
|
@ -696,124 +696,54 @@ static int matroska_ebmlnum_sint(uint8_t *data, uint32_t size, int64_t *num) |
|
|
|
|
return res; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int ebml_parse_elem(MatroskaDemuxContext *matroska, |
|
|
|
|
EbmlSyntax *syntax, void *data); |
|
|
|
|
|
|
|
|
|
static MatroskaTrack *matroska_find_track_by_num(MatroskaDemuxContext *matroska, |
|
|
|
|
int num) |
|
|
|
|
static int ebml_parse_id(MatroskaDemuxContext *matroska, EbmlSyntax *syntax, |
|
|
|
|
uint32_t id, void *data) |
|
|
|
|
{ |
|
|
|
|
MatroskaTrack *tracks = matroska->tracks.elem; |
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
for (i=0; i < matroska->tracks.nb_elem; i++) |
|
|
|
|
if (tracks[i].num == num) |
|
|
|
|
return &tracks[i]; |
|
|
|
|
|
|
|
|
|
av_log(matroska->ctx, AV_LOG_ERROR, "Invalid track number %d\n", num); |
|
|
|
|
return NULL; |
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Put one packet in an application-supplied AVPacket struct. |
|
|
|
|
* Returns 0 on success or -1 on failure. |
|
|
|
|
*/ |
|
|
|
|
static int matroska_deliver_packet(MatroskaDemuxContext *matroska, |
|
|
|
|
AVPacket *pkt) |
|
|
|
|
static int ebml_parse(MatroskaDemuxContext *matroska, EbmlSyntax *syntax, |
|
|
|
|
void *data) |
|
|
|
|
{ |
|
|
|
|
if (matroska->num_packets > 0) { |
|
|
|
|
memcpy(pkt, matroska->packets[0], sizeof(AVPacket)); |
|
|
|
|
av_free(matroska->packets[0]); |
|
|
|
|
if (matroska->num_packets > 1) { |
|
|
|
|
memmove(&matroska->packets[0], &matroska->packets[1], |
|
|
|
|
(matroska->num_packets - 1) * sizeof(AVPacket *)); |
|
|
|
|
matroska->packets = |
|
|
|
|
av_realloc(matroska->packets, (matroska->num_packets - 1) * |
|
|
|
|
sizeof(AVPacket *)); |
|
|
|
|
} else { |
|
|
|
|
av_freep(&matroska->packets); |
|
|
|
|
} |
|
|
|
|
matroska->num_packets--; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return -1; |
|
|
|
|
uint32_t id; |
|
|
|
|
int res = ebml_read_element_id(matroska, &id); |
|
|
|
|
return res < 0 ? res : ebml_parse_id(matroska, syntax, id, data); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Put a packet into our internal queue. Will be delivered to the |
|
|
|
|
* user/application during the next get_packet() call. |
|
|
|
|
*/ |
|
|
|
|
static void matroska_queue_packet(MatroskaDemuxContext *matroska, AVPacket *pkt) |
|
|
|
|
static int ebml_parse_nest(MatroskaDemuxContext *matroska, EbmlSyntax *syntax, |
|
|
|
|
void *data) |
|
|
|
|
{ |
|
|
|
|
matroska->packets = |
|
|
|
|
av_realloc(matroska->packets, (matroska->num_packets + 1) * |
|
|
|
|
sizeof(AVPacket *)); |
|
|
|
|
matroska->packets[matroska->num_packets] = pkt; |
|
|
|
|
matroska->num_packets++; |
|
|
|
|
} |
|
|
|
|
int i, res = 0; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Free all packets in our internal queue. |
|
|
|
|
*/ |
|
|
|
|
static void matroska_clear_queue(MatroskaDemuxContext *matroska) |
|
|
|
|
{ |
|
|
|
|
if (matroska->packets) { |
|
|
|
|
int n; |
|
|
|
|
for (n = 0; n < matroska->num_packets; n++) { |
|
|
|
|
av_free_packet(matroska->packets[n]); |
|
|
|
|
av_free(matroska->packets[n]); |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
av_free(matroska->packets); |
|
|
|
|
matroska->packets = NULL; |
|
|
|
|
matroska->num_packets = 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Autodetecting... |
|
|
|
|
*/ |
|
|
|
|
static int matroska_probe(AVProbeData *p) |
|
|
|
|
{ |
|
|
|
|
uint64_t total = 0; |
|
|
|
|
int len_mask = 0x80, size = 1, n = 1; |
|
|
|
|
char probe_data[] = "matroska"; |
|
|
|
|
|
|
|
|
|
/* ebml header? */ |
|
|
|
|
if (AV_RB32(p->buf) != EBML_ID_HEADER) |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
/* length of header */ |
|
|
|
|
total = p->buf[4]; |
|
|
|
|
while (size <= 8 && !(total & len_mask)) { |
|
|
|
|
size++; |
|
|
|
|
len_mask >>= 1; |
|
|
|
|
} |
|
|
|
|
if (size > 8) |
|
|
|
|
return 0; |
|
|
|
|
total &= (len_mask - 1); |
|
|
|
|
while (n < size) |
|
|
|
|
total = (total << 8) | p->buf[4 + n++]; |
|
|
|
|
|
|
|
|
|
/* does the probe data contain the whole header? */ |
|
|
|
|
if (p->buf_size < 4 + size + total) |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
/* the header must contain the document type 'matroska'. For now,
|
|
|
|
|
* we don't parse the whole header but simply check for the |
|
|
|
|
* availability of that array of characters inside the header. |
|
|
|
|
* Not fully fool-proof, but good enough. */ |
|
|
|
|
for (n = 4+size; n <= 4+size+total-(sizeof(probe_data)-1); n++) |
|
|
|
|
if (!memcmp(p->buf+n, probe_data, sizeof(probe_data)-1)) |
|
|
|
|
return AVPROBE_SCORE_MAX; |
|
|
|
|
while (!res && !ebml_level_end(matroska)) |
|
|
|
|
res = ebml_parse(matroska, syntax, data); |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
return res; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int ebml_parse_id(MatroskaDemuxContext *matroska, EbmlSyntax *syntax, |
|
|
|
|
uint32_t id, void *data); |
|
|
|
|
static int ebml_parse_nest(MatroskaDemuxContext *matroska, EbmlSyntax *syntax, |
|
|
|
|
void *data); |
|
|
|
|
|
|
|
|
|
static int ebml_parse_elem(MatroskaDemuxContext *matroska, |
|
|
|
|
EbmlSyntax *syntax, void *data) |
|
|
|
|
{ |
|
|
|
@ -857,51 +787,6 @@ static int ebml_parse_elem(MatroskaDemuxContext *matroska, |
|
|
|
|
return res; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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 id; |
|
|
|
|
int res = ebml_read_element_id(matroska, &id); |
|
|
|
|
return res < 0 ? res : ebml_parse_id(matroska, syntax, id, data); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int ebml_parse_nest(MatroskaDemuxContext *matroska, EbmlSyntax *syntax, |
|
|
|
|
void *data) |
|
|
|
|
{ |
|
|
|
|
int i, res = 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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
while (!res && !ebml_level_end(matroska)) |
|
|
|
|
res = ebml_parse(matroska, syntax, data); |
|
|
|
|
|
|
|
|
|
return res; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void ebml_free(EbmlSyntax *syntax, void *data) |
|
|
|
|
{ |
|
|
|
|
int i, j; |
|
|
|
@ -925,6 +810,61 @@ static void ebml_free(EbmlSyntax *syntax, void *data) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Autodetecting... |
|
|
|
|
*/ |
|
|
|
|
static int matroska_probe(AVProbeData *p) |
|
|
|
|
{ |
|
|
|
|
uint64_t total = 0; |
|
|
|
|
int len_mask = 0x80, size = 1, n = 1; |
|
|
|
|
char probe_data[] = "matroska"; |
|
|
|
|
|
|
|
|
|
/* ebml header? */ |
|
|
|
|
if (AV_RB32(p->buf) != EBML_ID_HEADER) |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
/* length of header */ |
|
|
|
|
total = p->buf[4]; |
|
|
|
|
while (size <= 8 && !(total & len_mask)) { |
|
|
|
|
size++; |
|
|
|
|
len_mask >>= 1; |
|
|
|
|
} |
|
|
|
|
if (size > 8) |
|
|
|
|
return 0; |
|
|
|
|
total &= (len_mask - 1); |
|
|
|
|
while (n < size) |
|
|
|
|
total = (total << 8) | p->buf[4 + n++]; |
|
|
|
|
|
|
|
|
|
/* does the probe data contain the whole header? */ |
|
|
|
|
if (p->buf_size < 4 + size + total) |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
/* the header must contain the document type 'matroska'. For now,
|
|
|
|
|
* we don't parse the whole header but simply check for the |
|
|
|
|
* availability of that array of characters inside the header. |
|
|
|
|
* Not fully fool-proof, but good enough. */ |
|
|
|
|
for (n = 4+size; n <= 4+size+total-(sizeof(probe_data)-1); n++) |
|
|
|
|
if (!memcmp(p->buf+n, probe_data, sizeof(probe_data)-1)) |
|
|
|
|
return AVPROBE_SCORE_MAX; |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static MatroskaTrack *matroska_find_track_by_num(MatroskaDemuxContext *matroska, |
|
|
|
|
int num) |
|
|
|
|
{ |
|
|
|
|
MatroskaTrack *tracks = matroska->tracks.elem; |
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
for (i=0; i < matroska->tracks.nb_elem; i++) |
|
|
|
|
if (tracks[i].num == num) |
|
|
|
|
return &tracks[i]; |
|
|
|
|
|
|
|
|
|
av_log(matroska->ctx, AV_LOG_ERROR, "Invalid track number %d\n", num); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int matroska_decode_buffer(uint8_t** buf, int* buf_size, |
|
|
|
|
MatroskaTrack *track) |
|
|
|
|
{ |
|
|
|
@ -1378,6 +1318,62 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Put a packet into our internal queue. Will be delivered to the |
|
|
|
|
* user/application during the next get_packet() call. |
|
|
|
|
*/ |
|
|
|
|
static void matroska_queue_packet(MatroskaDemuxContext *matroska, AVPacket *pkt) |
|
|
|
|
{ |
|
|
|
|
matroska->packets = |
|
|
|
|
av_realloc(matroska->packets, (matroska->num_packets + 1) * |
|
|
|
|
sizeof(AVPacket *)); |
|
|
|
|
matroska->packets[matroska->num_packets] = pkt; |
|
|
|
|
matroska->num_packets++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Put one packet in an application-supplied AVPacket struct. |
|
|
|
|
* Returns 0 on success or -1 on failure. |
|
|
|
|
*/ |
|
|
|
|
static int matroska_deliver_packet(MatroskaDemuxContext *matroska, |
|
|
|
|
AVPacket *pkt) |
|
|
|
|
{ |
|
|
|
|
if (matroska->num_packets > 0) { |
|
|
|
|
memcpy(pkt, matroska->packets[0], sizeof(AVPacket)); |
|
|
|
|
av_free(matroska->packets[0]); |
|
|
|
|
if (matroska->num_packets > 1) { |
|
|
|
|
memmove(&matroska->packets[0], &matroska->packets[1], |
|
|
|
|
(matroska->num_packets - 1) * sizeof(AVPacket *)); |
|
|
|
|
matroska->packets = |
|
|
|
|
av_realloc(matroska->packets, (matroska->num_packets - 1) * |
|
|
|
|
sizeof(AVPacket *)); |
|
|
|
|
} else { |
|
|
|
|
av_freep(&matroska->packets); |
|
|
|
|
} |
|
|
|
|
matroska->num_packets--; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Free all packets in our internal queue. |
|
|
|
|
*/ |
|
|
|
|
static void matroska_clear_queue(MatroskaDemuxContext *matroska) |
|
|
|
|
{ |
|
|
|
|
if (matroska->packets) { |
|
|
|
|
int n; |
|
|
|
|
for (n = 0; n < matroska->num_packets; n++) { |
|
|
|
|
av_free_packet(matroska->packets[n]); |
|
|
|
|
av_free(matroska->packets[n]); |
|
|
|
|
} |
|
|
|
|
av_free(matroska->packets); |
|
|
|
|
matroska->packets = NULL; |
|
|
|
|
matroska->num_packets = 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, |
|
|
|
|
int size, int64_t pos, uint64_t cluster_time, |
|
|
|
|
uint64_t duration, int is_keyframe) |
|
|
|
|