MATROSKA_TRACK_DEFAULT = (1<<1),
MATROSKA_TRACK_LACING = (1<<2),
MATROSKA_TRACK_REAL_V = (1<<4),
+ MATROSKA_TRACK_REORDER = (1<<8),
MATROSKA_TRACK_SHIFT = (1<<16)
} MatroskaTrackFlags;
{"V_REAL/RV20" , CODEC_ID_RV20},
{"V_REAL/RV30" , CODEC_ID_RV30},
{"V_REAL/RV40" , CODEC_ID_RV40},
+ {"V_THEORA" , CODEC_ID_THEORA},
/* TODO: Real/Quicktime */
// {"A_MS/ACM" , CODEC_ID_NONE},
unsigned char *codec_priv;
int codec_priv_size;
- int64_t default_duration;
+ uint64_t default_duration;
MatroskaTrackFlags flags;
} MatroskaTrack;
/* The packet queue. */
AVPacket **packets;
int num_packets;
+ /* Second packet queue used to reorder pts of some video track. */
+ AVPacket **packets_reorder;
+ int num_packets_reorder;
+ uint64_t reorder_max_pts;
/* have we already parse metadata/cues/clusters? */
int metadata_parsed,
matroska->num_packets++;
}
+/*
+ * Put a packet into our internal reordering queue. Will be moved to the
+ * main packet queue when enough packets are available to reorder pts.
+ */
+
+static void
+matroska_queue_packet_reordered (MatroskaDemuxContext *matroska,
+ AVPacket *pkt,
+ int is_bframe)
+{
+ if (matroska->num_packets_reorder && !is_bframe
+ && pkt->pts > matroska->reorder_max_pts) {
+ /* reorder pts */
+ int i, j, k = 1;
+ for (j=matroska->num_packets_reorder-1; j && k; j--) {
+ k = 0;
+ for (i=0; i<j; i++) {
+ if (matroska->packets_reorder[i]->pts > matroska->packets_reorder[i+1]->pts) {
+ FFSWAP(uint64_t, matroska->packets_reorder[i]->pts, matroska->packets_reorder[i+1]->pts);
+ k = 1;
+ }
+ }
+ }
+ /* then really queue the packets */
+ for (i=0; i<matroska->num_packets_reorder; i++)
+ matroska_queue_packet (matroska, matroska->packets_reorder[i]);
+ matroska->num_packets_reorder = 0;
+ }
+ matroska->packets_reorder =
+ av_realloc(matroska->packets_reorder,
+ (matroska->num_packets_reorder + 1) * sizeof(AVPacket *));
+ matroska->packets_reorder[matroska->num_packets_reorder++] = pkt;
+ if (pkt->pts > matroska->reorder_max_pts)
+ matroska->reorder_max_pts = pkt->pts;
+}
+
+
/*
* Autodetecting...
*/
if ((res = ebml_read_uint (matroska, &id,
&num)) < 0)
break;
- track->default_duration = num;
+ track->default_duration = num/matroska->time_scale;
break;
}
if ((res = ebml_read_float(matroska, &id,
&num)) < 0)
break;
- track->default_duration = 1000000000 * (1. / num);
+ track->default_duration = 1000000000/(matroska->time_scale*num);
break;
}
uint64_t num;
if ((res = ebml_read_uint(matroska, &id, &num)) < 0)
break;
- track->default_duration = num;
+ track->default_duration = num / matroska->time_scale;
break;
}
} else {
extradata_size = 2;
}
+ track->default_duration = 1024*1000 / audiotrack->internal_samplerate;
}
else if (codec_id == CODEC_ID_TTA) {
if (track->default_duration)
av_reduce(&st->codec->time_base.num, &st->codec->time_base.den,
- track->default_duration, 1000000000, 30000);
+ track->default_duration, 1000, 30000);
if(extradata){
st->codec->extradata = extradata;
st->codec->height * videotrack->display_width,
st->codec-> width * videotrack->display_height,
255);
+ st->need_parsing = 2;
} else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) {
MatroskaAudioTrack *audiotrack = (MatroskaAudioTrack *)track;
}
static int
-matroska_parse_block(MatroskaDemuxContext *matroska, uint64_t cluster_time,
- int is_keyframe, int *ptrack, AVPacket **ppkt)
+matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size,
+ int64_t pos, uint64_t cluster_time, uint64_t duration,
+ int is_keyframe, int is_bframe)
{
- int res;
- uint32_t id;
+ int res = 0;
int track;
AVPacket *pkt;
- uint8_t *data, *origdata;
- int size;
+ uint8_t *origdata = data;
int16_t block_time;
uint32_t *lace_size = NULL;
int n, flags, laces = 0;
uint64_t num;
- int64_t pos= url_ftell(&matroska->ctx->pb);
-
- if ((res = ebml_read_binary(matroska, &id, &data, &size)) < 0)
- return res;
- origdata = data;
/* first byte(s): tracknum */
if ((n = matroska_ebmlnum_uint(data, size, &num)) < 0) {
/* fetch track from num */
track = matroska_find_track_by_num(matroska, num);
- if (ptrack) *ptrack = track;
if (size <= 3 || track < 0 || track >= matroska->num_tracks) {
av_log(matroska->ctx, AV_LOG_INFO,
"Invalid stream %d or size %u\n", track, size);
av_free(origdata);
return res;
}
+ if (duration == AV_NOPTS_VALUE)
+ duration = matroska->tracks[track]->default_duration;
/* block_time (relative to cluster time) */
block_time = (data[0] << 8) | data[1];
if (res == 0) {
int real_v = matroska->tracks[track]->flags & MATROSKA_TRACK_REAL_V;
+ uint64_t timecode = AV_NOPTS_VALUE;
+
+ if (cluster_time != (uint64_t)-1 && cluster_time + block_time >= 0)
+ timecode = cluster_time + block_time;
+
for (n = 0; n < laces; n++) {
- uint64_t timecode = AV_NOPTS_VALUE;
int slice, slices = 1;
if (real_v) {
slices = *data++ + 1;
lace_size[n]--;
}
- if (cluster_time != (uint64_t)-1 && n == 0) {
- if (cluster_time + block_time >= 0)
- timecode = (cluster_time + block_time) * matroska->time_scale;
- }
- /* FIXME: duration */
for (slice=0; slice<slices; slice++) {
int slice_size, slice_offset = 0;
else
slice_size = rv_offset(data, slice+1, slices) - slice_offset;
pkt = av_mallocz(sizeof(AVPacket));
- if (ppkt) *ppkt = pkt;
/* XXX: prevent data copy... */
if (av_new_packet(pkt, slice_size) < 0) {
res = AVERROR_NOMEM;
pkt->pts = timecode;
pkt->pos = pos;
+ pkt->duration = duration;
- matroska_queue_packet(matroska, pkt);
+ if (matroska->tracks[track]->flags & MATROSKA_TRACK_REORDER)
+ matroska_queue_packet_reordered(matroska, pkt, is_bframe);
+ else
+ matroska_queue_packet(matroska, pkt);
+
+ if (timecode != AV_NOPTS_VALUE)
+ timecode = duration ? timecode + duration : AV_NOPTS_VALUE;
}
data += lace_size[n];
}
{
int res = 0;
uint32_t id;
- AVPacket *pkt = NULL;
+ int is_bframe = 0;
int is_keyframe = PKT_FLAG_KEY, last_num_packets = matroska->num_packets;
uint64_t duration = AV_NOPTS_VALUE;
- int track = -1;
+ uint8_t *data;
+ int size = 0;
+ int64_t pos = 0;
av_log(matroska->ctx, AV_LOG_DEBUG, "parsing blockgroup...\n");
* of the harder things, so this code is a bit complicated.
* See http://www.matroska.org/ for documentation. */
case MATROSKA_ID_BLOCK: {
- res = matroska_parse_block(matroska, cluster_time,
- is_keyframe, &track, &pkt);
+ pos = url_ftell(&matroska->ctx->pb);
+ res = ebml_read_binary(matroska, &id, &data, &size);
break;
}
case MATROSKA_ID_BLOCKDURATION: {
if ((res = ebml_read_uint(matroska, &id, &duration)) < 0)
break;
+ duration /= matroska->time_scale;
break;
}
- case MATROSKA_ID_BLOCKREFERENCE:
+ case MATROSKA_ID_BLOCKREFERENCE: {
+ int64_t num;
/* We've found a reference, so not even the first frame in
* the lace is a key frame. */
is_keyframe = 0;
if (last_num_packets != matroska->num_packets)
matroska->packets[last_num_packets]->flags = 0;
- res = ebml_read_skip(matroska);
+ if ((res = ebml_read_sint(matroska, &id, &num)) < 0)
+ break;
+ if (num > 0)
+ is_bframe = 1;
break;
+ }
default:
av_log(matroska->ctx, AV_LOG_INFO,
}
}
- if (pkt)
- {
- if (duration != AV_NOPTS_VALUE)
- pkt->duration = duration;
- else if (track >= 0 && track < matroska->num_tracks)
- pkt->duration = matroska->tracks[track]->default_duration / matroska->time_scale;
- }
+ if (res)
+ return res;
+
+ if (size > 0)
+ res = matroska_parse_block(matroska, data, size, pos, cluster_time,
+ duration, is_keyframe, is_bframe);
return res;
}
int res = 0;
uint32_t id;
uint64_t cluster_time = 0;
+ uint8_t *data;
+ int64_t pos;
+ int size;
av_log(matroska->ctx, AV_LOG_DEBUG,
"parsing cluster at %"PRId64"\n", url_ftell(&matroska->ctx->pb));
break;
case MATROSKA_ID_SIMPLEBLOCK:
- matroska_parse_block(matroska, cluster_time, -1, NULL, NULL);
+ pos = url_ftell(&matroska->ctx->pb);
+ res = ebml_read_binary(matroska, &id, &data, &size);
+ if (res == 0)
+ res = matroska_parse_block(matroska, data, size, pos,
+ cluster_time, AV_NOPTS_VALUE,
+ -1, 0);
break;
default:
int res = 0;
uint32_t id;
- /* Do we still have a packet queued? */
- if (matroska_deliver_packet(matroska, pkt) == 0)
- return 0;
+ /* Read stream until we have a packet queued. */
+ while (matroska_deliver_packet(matroska, pkt)) {
- /* Have we already reached the end? */
- if (matroska->done)
- return AVERROR_IO;
+ /* Have we already reached the end? */
+ if (matroska->done)
+ return AVERROR_IO;
- while (res == 0) {
- if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
- res = AVERROR_IO;
- break;
- } else if (matroska->level_up) {
- matroska->level_up--;
- break;
- }
+ while (res == 0) {
+ if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
+ return AVERROR_IO;
+ } else if (matroska->level_up) {
+ matroska->level_up--;
+ break;
+ }
- switch (id) {
- case MATROSKA_ID_CLUSTER:
- if ((res = ebml_read_master(matroska, &id)) < 0)
+ switch (id) {
+ case MATROSKA_ID_CLUSTER:
+ if ((res = ebml_read_master(matroska, &id)) < 0)
+ break;
+ if ((res = matroska_parse_cluster(matroska)) == 0)
+ res = 1; /* Parsed one cluster, let's get out. */
break;
- if ((res = matroska_parse_cluster(matroska)) == 0)
- res = 1; /* Parsed one cluster, let's get out. */
- break;
- default:
- case EBML_ID_VOID:
- res = ebml_read_skip(matroska);
+ default:
+ case EBML_ID_VOID:
+ res = ebml_read_skip(matroska);
+ break;
+ }
+
+ if (matroska->level_up) {
+ matroska->level_up--;
break;
+ }
}
- if (matroska->level_up) {
- matroska->level_up--;
- break;
- }
+ if (res == -1)
+ matroska->done = 1;
}
- if (res == -1)
- matroska->done = 1;
-
- return matroska_deliver_packet(matroska, pkt);
+ return 0;
}
static int
}
av_free(matroska->packets);
}
+ if (matroska->packets_reorder) {
+ for (n = 0; n < matroska->num_packets_reorder; n++) {
+ av_free_packet(matroska->packets_reorder[n]);
+ av_free(matroska->packets_reorder[n]);
+ }
+ av_free(matroska->packets_reorder);
+ }
for (n = 0; n < matroska->num_tracks; n++) {
MatroskaTrack *track = matroska->tracks[n];