X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmatroska.c;h=591530490c1496d5b7bb65fa4990b781770ea231;hb=9a0ddd09e737545711e209591bc95891e3615543;hp=47b99ee7455ae33a8b77224ab69b832066de51f2;hpb=12f3278dc50273c39c35ea5c154862268b4208bb;p=ffmpeg diff --git a/libavformat/matroska.c b/libavformat/matroska.c index 47b99ee7455..591530490c1 100644 --- a/libavformat/matroska.c +++ b/libavformat/matroska.c @@ -178,6 +178,7 @@ typedef enum { 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; @@ -212,6 +213,7 @@ static CodecTags codec_tags[]={ {"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}, @@ -253,7 +255,7 @@ typedef struct Track { unsigned char *codec_priv; int codec_priv_size; - int64_t default_duration; + uint64_t default_duration; MatroskaTrackFlags flags; } MatroskaTrack; @@ -336,6 +338,10 @@ typedef struct MatroskaDemuxContext { /* 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, @@ -1020,6 +1026,43 @@ matroska_queue_packet (MatroskaDemuxContext *matroska, 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; ipackets_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; inum_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... */ @@ -1265,7 +1308,7 @@ matroska_add_stream (MatroskaDemuxContext *matroska) if ((res = ebml_read_uint (matroska, &id, &num)) < 0) break; - track->default_duration = num; + track->default_duration = num/matroska->time_scale; break; } @@ -1275,7 +1318,7 @@ matroska_add_stream (MatroskaDemuxContext *matroska) 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; } @@ -1578,7 +1621,7 @@ matroska_add_stream (MatroskaDemuxContext *matroska) 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; } @@ -2263,6 +2306,7 @@ matroska_read_header (AVFormatContext *s, } else { extradata_size = 2; } + track->default_duration = 1024*1000 / audiotrack->internal_samplerate; } else if (codec_id == CODEC_ID_TTA) { @@ -2307,7 +2351,7 @@ matroska_read_header (AVFormatContext *s, 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; @@ -2337,6 +2381,7 @@ matroska_read_header (AVFormatContext *s, 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; @@ -2375,24 +2420,18 @@ rv_offset(uint8_t *data, int slice, int slices) } 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) { @@ -2405,7 +2444,6 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint64_t cluster_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); @@ -2416,6 +2454,8 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint64_t cluster_time, 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]; @@ -2507,19 +2547,18 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint64_t cluster_time, 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; slicepts = 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]; } @@ -2563,10 +2608,12 @@ matroska_parse_blockgroup (MatroskaDemuxContext *matroska, { 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"); @@ -2584,25 +2631,31 @@ matroska_parse_blockgroup (MatroskaDemuxContext *matroska, * 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, @@ -2620,13 +2673,12 @@ matroska_parse_blockgroup (MatroskaDemuxContext *matroska, } } - 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; } @@ -2637,6 +2689,9 @@ matroska_parse_cluster (MatroskaDemuxContext *matroska) 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)); @@ -2668,7 +2723,12 @@ matroska_parse_cluster (MatroskaDemuxContext *matroska) 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: @@ -2757,6 +2817,13 @@ 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];