Index: libavformat/matroskadec.c |
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c |
index df54762c5ec279150dbf5482fcae5a2a211a312f..fd569be1874744038866b7a9b7865c210eb5add5 100644 |
--- a/libavformat/matroskadec.c |
+++ b/libavformat/matroskadec.c |
@@ -35,13 +35,17 @@ |
/* For ff_codec_get_id(). */ |
#include "riff.h" |
#include "isom.h" |
+#if CONFIG_SIPR_DECODER |
#include "rm.h" |
+#endif |
#include "matroska.h" |
#include "libavcodec/mpeg4audio.h" |
#include "libavutil/intfloat.h" |
#include "libavutil/intreadwrite.h" |
#include "libavutil/avstring.h" |
+#if HAVE_LZO1X_999_COMPRESS |
#include "libavutil/lzo.h" |
+#endif |
#include "libavutil/dict.h" |
#if CONFIG_ZLIB |
#include <zlib.h> |
@@ -224,6 +228,11 @@ typedef struct { |
} MatroskaLevel; |
typedef struct { |
+ uint64_t timecode; |
+ EbmlList blocks; |
+} MatroskaCluster; |
+ |
+typedef struct { |
AVFormatContext *ctx; |
/* EBML stuff */ |
@@ -258,6 +267,10 @@ typedef struct { |
/* File has a CUES element, but we defer parsing until it is needed. */ |
int cues_parsing_deferred; |
+ |
+ int current_cluster_num_blocks; |
+ int64_t current_cluster_pos; |
+ MatroskaCluster current_cluster; |
} MatroskaDemuxContext; |
typedef struct { |
@@ -267,11 +280,6 @@ typedef struct { |
EbmlBin bin; |
} MatroskaBlock; |
-typedef struct { |
- uint64_t timecode; |
- EbmlList blocks; |
-} MatroskaCluster; |
- |
static EbmlSyntax ebml_header[] = { |
{ EBML_ID_EBMLREADVERSION, EBML_UINT, 0, offsetof(Ebml,version), {.u=EBML_VERSION} }, |
{ EBML_ID_EBMLMAXSIZELENGTH, EBML_UINT, 0, offsetof(Ebml,max_size), {.u=8} }, |
@@ -542,6 +550,38 @@ static EbmlSyntax matroska_clusters[] = { |
{ 0 } |
}; |
+static EbmlSyntax matroska_cluster_incremental_parsing[] = { |
+ { MATROSKA_ID_CLUSTERTIMECODE,EBML_UINT,0, offsetof(MatroskaCluster,timecode) }, |
+ { MATROSKA_ID_BLOCKGROUP, EBML_NEST, sizeof(MatroskaBlock), offsetof(MatroskaCluster,blocks), {.n=matroska_blockgroup} }, |
+ { MATROSKA_ID_SIMPLEBLOCK, EBML_PASS, sizeof(MatroskaBlock), offsetof(MatroskaCluster,blocks), {.n=matroska_blockgroup} }, |
+ { MATROSKA_ID_CLUSTERPOSITION,EBML_NONE }, |
+ { MATROSKA_ID_CLUSTERPREVSIZE,EBML_NONE }, |
+ { MATROSKA_ID_INFO, EBML_NONE }, |
+ { MATROSKA_ID_CUES, EBML_NONE }, |
+ { MATROSKA_ID_TAGS, EBML_NONE }, |
+ { MATROSKA_ID_SEEKHEAD, EBML_NONE }, |
+ { MATROSKA_ID_CLUSTER, EBML_STOP }, |
+ { 0 } |
+}; |
+ |
+static EbmlSyntax matroska_cluster_incremental[] = { |
+ { MATROSKA_ID_CLUSTERTIMECODE,EBML_UINT,0, offsetof(MatroskaCluster,timecode) }, |
+ { MATROSKA_ID_BLOCKGROUP, EBML_STOP }, |
+ { MATROSKA_ID_SIMPLEBLOCK, EBML_STOP }, |
+ { MATROSKA_ID_CLUSTERPOSITION,EBML_NONE }, |
+ { MATROSKA_ID_CLUSTERPREVSIZE,EBML_NONE }, |
+ { 0 } |
+}; |
+ |
+static EbmlSyntax matroska_clusters_incremental[] = { |
+ { MATROSKA_ID_CLUSTER, EBML_NEST, 0, 0, {.n=matroska_cluster_incremental} }, |
+ { MATROSKA_ID_INFO, EBML_NONE }, |
+ { MATROSKA_ID_CUES, EBML_NONE }, |
+ { MATROSKA_ID_TAGS, EBML_NONE }, |
+ { MATROSKA_ID_SEEKHEAD, EBML_NONE }, |
+ { 0 } |
+}; |
+ |
static const char *matroska_doctypes[] = { "matroska", "webm" }; |
/* |
@@ -668,9 +708,10 @@ static int ebml_read_float(AVIOContext *pb, int size, double *num) |
static int ebml_read_ascii(AVIOContext *pb, int size, char **str) |
{ |
av_free(*str); |
+ *str = NULL; |
/* EBML strings are usually not 0-terminated, so we allocate one |
* byte more, read the string and NULL-terminate it ourselves. */ |
- if (!(*str = av_malloc(size + 1))) |
+ if (size < 0 || !(*str = av_malloc(size + 1))) |
return AVERROR(ENOMEM); |
if (avio_read(pb, (uint8_t *) *str, size) != size) { |
av_freep(str); |
@@ -978,6 +1019,7 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size, |
switch (encodings[0].compression.algo) { |
case MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP: |
return encodings[0].compression.settings.size; |
+#if HAVE_LZO1X_999_COMPRESS |
case MATROSKA_TRACK_ENCODING_COMP_LZO: |
do { |
olen = pkt_size *= 3; |
@@ -988,6 +1030,7 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size, |
goto failed; |
pkt_size -= olen; |
break; |
+#endif |
#if CONFIG_ZLIB |
case MATROSKA_TRACK_ENCODING_COMP_ZLIB: { |
z_stream zstream = {0}; |
@@ -1340,6 +1383,7 @@ static int matroska_read_header(AVFormatContext *s) |
"(EBML version %"PRIu64", doctype %s, doc version %"PRIu64")\n", |
ebml.version, ebml.doctype, ebml.doctype_version); |
} |
+ av_dict_set(&s->metadata, "doctype", ebml.doctype, 0); |
for (i = 0; i < FF_ARRAY_ELEMS(matroska_doctypes); i++) |
if (!strcmp(ebml.doctype, matroska_doctypes[i])) |
break; |
@@ -1402,14 +1446,17 @@ static int matroska_read_header(AVFormatContext *s) |
"Multiple combined encodings not supported"); |
} else if (encodings_list->nb_elem == 1) { |
if (encodings[0].type || |
- (encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP && |
+ (encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP |
#if CONFIG_ZLIB |
- encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_ZLIB && |
+ && encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_ZLIB |
#endif |
#if CONFIG_BZLIB |
- encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_BZLIB && |
+ && encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_BZLIB |
+#endif |
+#if HAVE_LZO1X_999_COMPRESS |
+ && encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_LZO |
#endif |
- encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_LZO)) { |
+ )) { |
encodings[0].scope = 0; |
av_log(matroska->ctx, AV_LOG_ERROR, |
"Unsupported encoding type"); |
@@ -1537,11 +1584,13 @@ static int matroska_read_header(AVFormatContext *s) |
st->codec->block_align = track->audio.coded_framesize; |
track->codec_priv.size = 0; |
} else { |
+#if CONFIG_SIPR_DECODER |
if (codec_id == CODEC_ID_SIPR && flavor < 4) { |
const int sipr_bit_rate[4] = { 6504, 8496, 5000, 16000 }; |
track->audio.sub_packet_size = ff_sipr_subpk_size[flavor]; |
st->codec->bit_rate = sipr_bit_rate[flavor]; |
} |
+#endif |
st->codec->block_align = track->audio.sub_packet_size; |
extradata_offset = 78; |
} |
@@ -1621,6 +1670,8 @@ static int matroska_read_header(AVFormatContext *s) |
} else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) { |
st->codec->codec_type = AVMEDIA_TYPE_AUDIO; |
st->codec->sample_rate = track->audio.out_samplerate; |
+ if (st->codec->sample_rate <= 0) |
+ st->codec->sample_rate = 1; |
st->codec->channels = track->audio.channels; |
if (st->codec->codec_id != CODEC_ID_AAC) |
st->need_parsing = AVSTREAM_PARSE_HEADERS; |
@@ -1699,6 +1750,7 @@ static int matroska_deliver_packet(MatroskaDemuxContext *matroska, |
matroska->packets = newpackets; |
} else { |
av_freep(&matroska->packets); |
+ matroska->prev_pkt = NULL; |
} |
matroska->num_packets--; |
return 0; |
@@ -1887,8 +1939,10 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, |
memcpy(track->audio.buf+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), data+x*sps, sps); |
if (++track->audio.sub_packet_cnt >= h) { |
+#if CONFIG_SIPR_DECODER |
if (st->codec->codec_id == CODEC_ID_SIPR) |
ff_rm_reorder_sipr_data(track->audio.buf, h, w); |
+#endif |
track->audio.sub_packet_cnt = 0; |
track->audio.pkt_cnt = h*w / a; |
} |
@@ -2001,17 +2055,71 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska) |
return res; |
} |
+static int matroska_parse_cluster_incremental(MatroskaDemuxContext *matroska) |
+{ |
+ EbmlList *blocks_list; |
+ MatroskaBlock *blocks; |
+ int i, res; |
+ res = ebml_parse(matroska, |
+ matroska_cluster_incremental_parsing, |
+ &matroska->current_cluster); |
+ if (res == 1) { |
+ /* New Cluster */ |
+ if (matroska->current_cluster_pos) |
+ ebml_level_end(matroska); |
+ ebml_free(matroska_cluster, &matroska->current_cluster); |
+ memset(&matroska->current_cluster, 0, sizeof(MatroskaCluster)); |
+ matroska->current_cluster_num_blocks = 0; |
+ matroska->current_cluster_pos = avio_tell(matroska->ctx->pb); |
+ matroska->prev_pkt = NULL; |
+ /* sizeof the ID which was already read */ |
+ if (matroska->current_id) |
+ matroska->current_cluster_pos -= 4; |
+ res = ebml_parse(matroska, |
+ matroska_clusters_incremental, |
+ &matroska->current_cluster); |
+ /* Try parsing the block agiain. */ |
+ if (res == 1) |
+ res = ebml_parse(matroska, |
+ matroska_cluster_incremental_parsing, |
+ &matroska->current_cluster); |
+ } |
+ |
+ if (!res && |
+ matroska->current_cluster_num_blocks < |
+ matroska->current_cluster.blocks.nb_elem) { |
+ blocks_list = &matroska->current_cluster.blocks; |
+ blocks = blocks_list->elem; |
+ |
+ matroska->current_cluster_num_blocks = blocks_list->nb_elem; |
+ i = blocks_list->nb_elem - 1; |
+ if (blocks[i].bin.size > 0 && blocks[i].bin.data) { |
+ int is_keyframe = blocks[i].non_simple ? !blocks[i].reference : -1; |
+ res=matroska_parse_block(matroska, |
+ blocks[i].bin.data, blocks[i].bin.size, |
+ blocks[i].bin.pos, |
+ matroska->current_cluster.timecode, |
+ blocks[i].duration, is_keyframe, |
+ matroska->current_cluster_pos); |
+ } |
+ } |
+ |
+ if (res < 0) matroska->done = 1; |
+ return res; |
+} |
+ |
static int matroska_read_packet(AVFormatContext *s, AVPacket *pkt) |
{ |
MatroskaDemuxContext *matroska = s->priv_data; |
+ int ret = 0; |
- while (matroska_deliver_packet(matroska, pkt)) { |
+ while (!ret && matroska_deliver_packet(matroska, pkt)) { |
if (matroska->done) |
return AVERROR_EOF; |
- matroska_parse_cluster(matroska); |
+ ret = matroska_parse_cluster_incremental(matroska); |
} |
- return 0; |
+ return ret; |
} |
static int matroska_read_seek(AVFormatContext *s, int stream_index, |
@@ -2082,6 +2190,7 @@ static int matroska_read_close(AVFormatContext *s) |
for (n=0; n < matroska->tracks.nb_elem; n++) |
if (tracks[n].type == MATROSKA_TRACK_TYPE_AUDIO) |
av_free(tracks[n].audio.buf); |
+ ebml_free(matroska_cluster, &matroska->current_cluster); |
ebml_free(matroska_segment, matroska); |
return 0; |