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;
/* timescale in the file */
int64_t time_scale;
- /* position (time, ns) */
- int64_t pos;
-
/* num_streams is the number of streams that av_new_stream() was called
* for ( = that are available to the calling program). */
int num_tracks, num_streams;
/* 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,
/* The index for seeking. */
int num_indexes;
MatroskaDemuxIndex *index;
+
+ /* What to skip before effectively reading a packet. */
+ int skip_to_keyframe;
+ AVStream *skip_to_stream;
} MatroskaDemuxContext;
/*
return 0;
}
+
+static int
+matroska_find_track_by_num (MatroskaDemuxContext *matroska,
+ int num)
+{
+ int i;
+
+ for (i = 0; i < matroska->num_tracks; i++)
+ if (matroska->tracks[i]->num == num)
+ return i;
+
+ return -1;
+}
+
+
/*
* Put one packet in an application-supplied AVPacket struct.
* Returns 0 on success or -1 on failure.
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...
int len_mask = 0x80, size = 1, n = 1;
uint8_t probe_data[] = { 'm', 'a', 't', 'r', 'o', 's', 'k', 'a' };
- if (p->buf_size < 5)
- return 0;
-
/* ebml header? */
if ((p->buf[0] << 24 | p->buf[1] << 16 |
p->buf[2] << 8 | p->buf[3]) != EBML_ID_HEADER)
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;
}
if ((res = ebml_read_uint(matroska,
&id, &num)) < 0)
break;
- idx.pos = num;
+ idx.pos = num+matroska->segment_start;
break;
}
}
- else if (codec_id == CODEC_ID_MPEG1VIDEO ||
- codec_id == CODEC_ID_MPEG2VIDEO ||
- codec_id == CODEC_ID_MPEG4 ||
- codec_id == CODEC_ID_MSMPEG4V3 ||
- codec_id == CODEC_ID_H264) {
- track->flags |= MATROSKA_TRACK_REORDER;
- }
-
else if (codec_id == CODEC_ID_AAC && !track->codec_priv_size) {
MatroskaAudioTrack *audiotrack = (MatroskaAudioTrack *) track;
int profile = matroska_aac_profile(track->codec_id);
} else {
extradata_size = 2;
}
+ track->default_duration = 1024*1000 / audiotrack->internal_samplerate;
}
else if (codec_id == CODEC_ID_TTA) {
av_set_pts_info(st, 64, matroska->time_scale, 1000*1000*1000); /* 64 bit pts in ns */
st->codec->codec_id = codec_id;
+ st->start_time = 0;
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 = AVSTREAM_PARSE_HEADERS;
} else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) {
MatroskaAudioTrack *audiotrack = (MatroskaAudioTrack *)track;
res = 0;
}
- return res;
-}
-
-static int
-matroska_find_track_by_num (MatroskaDemuxContext *matroska,
- int num)
-{
- int i;
-
- for (i = 0; i < matroska->num_tracks; i++)
- if (matroska->tracks[i]->num == num)
- return i;
+ if (matroska->index_parsed) {
+ int i, track, stream;
+ for (i=0; i<matroska->num_indexes; i++) {
+ MatroskaDemuxIndex *idx = &matroska->index[i];
+ track = matroska_find_track_by_num(matroska, idx->track);
+ stream = matroska->tracks[track]->stream_index;
+ av_add_index_entry(matroska->ctx->streams[stream],
+ idx->pos, idx->time/matroska->time_scale,
+ 0, 0, AVINDEX_KEYFRAME);
+ }
+ }
- return -1;
+ return res;
}
static inline int
static int
matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size,
- int64_t pos, uint64_t cluster_time,
- int is_keyframe, int is_bframe,
- int *ptrack, AVPacket **ppkt)
+ int64_t pos, uint64_t cluster_time, uint64_t duration,
+ int is_keyframe, int is_bframe)
{
int res = 0;
int track;
+ AVStream *st;
AVPacket *pkt;
uint8_t *origdata = data;
int16_t block_time;
/* 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(matroska->ctx->streams[ matroska->tracks[track]->stream_index ]->discard >= AVDISCARD_ALL){
+ st = matroska->ctx->streams[matroska->tracks[track]->stream_index];
+ if (st->discard >= AVDISCARD_ALL) {
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];
size -= 1;
if (is_keyframe == -1)
is_keyframe = flags & 1 ? PKT_FLAG_KEY : 0;
+
+ if (matroska->skip_to_keyframe) {
+ if (!is_keyframe || st != matroska->skip_to_stream)
+ return res;
+ matroska->skip_to_keyframe = 0;
+ }
+
switch ((flags & 0x06) >> 1) {
case 0x0: /* no lacing */
laces = 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;
- }
- /* 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;
- 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;
case MATROSKA_ID_BLOCKDURATION: {
if ((res = ebml_read_uint(matroska, &id, &duration)) < 0)
break;
+ duration /= matroska->time_scale;
break;
}
if (size > 0)
res = matroska_parse_block(matroska, data, size, pos, cluster_time,
- is_keyframe, is_bframe, &track, &pkt);
-
- 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;
- }
+ duration, is_keyframe, is_bframe);
return res;
}
res = ebml_read_binary(matroska, &id, &data, &size);
if (res == 0)
res = matroska_parse_block(matroska, data, size, pos,
- cluster_time, -1,0, NULL, NULL);
+ cluster_time, AV_NOPTS_VALUE,
+ -1, 0);
break;
default:
return 0;
}
+static int
+matroska_read_seek (AVFormatContext *s, int stream_index, int64_t timestamp,
+ int flags)
+{
+ MatroskaDemuxContext *matroska = s->priv_data;
+ AVStream *st = s->streams[stream_index];
+ int index;
+
+ /* find index entry */
+ index = av_index_search_timestamp(st, timestamp, flags);
+ if (index < 0)
+ return 0;
+
+ /* do the seek */
+ url_fseek(&s->pb, st->index_entries[index].pos, SEEK_SET);
+ matroska->skip_to_keyframe = !(flags & AVSEEK_FLAG_ANY);
+ matroska->skip_to_stream = st;
+ matroska->num_packets = 0;
+ matroska->peek_id = 0;
+ return 0;
+}
+
static int
matroska_read_close (AVFormatContext *s)
{
}
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];
matroska_read_header,
matroska_read_packet,
matroska_read_close,
+ matroska_read_seek,
};