X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmatroskadec.c;h=3a2209f31863c036b3504abd4e64c2d983905e76;hb=88297e80aa005afc4ebdfb4ab68e38a114439905;hp=363b1f2c917dece567a59f6ba616b9cd32d64620;hpb=5358a81f9c99f915ec5de8f813ee30f0db608eee;p=ffmpeg diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index 363b1f2c917..3a2209f3186 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -20,7 +20,7 @@ */ /** - * @file matroskadec.c + * @file libavformat/matroskadec.c * Matroska file demuxer * by Ronald Bultje * with a little help from Moritz Bunkus @@ -36,12 +36,13 @@ #include "matroska.h" #include "libavcodec/mpeg4audio.h" #include "libavutil/intfloat_readwrite.h" +#include "libavutil/intreadwrite.h" #include "libavutil/avstring.h" #include "libavutil/lzo.h" -#ifdef CONFIG_ZLIB +#if CONFIG_ZLIB #include #endif -#ifdef CONFIG_BZLIB +#if CONFIG_BZLIB #include #endif @@ -139,7 +140,6 @@ typedef struct { EbmlList encodings; AVStream *stream; - int64_t first_timecode; int64_t end_timecode; } MatroskaTrack; @@ -201,11 +201,12 @@ typedef struct { EbmlList seekhead; /* byte position of the segment inside the stream */ - offset_t segment_start; + int64_t segment_start; /* the packet queue */ AVPacket **packets; int num_packets; + AVPacket *prev_pkt; int done; int has_cluster_id; @@ -226,8 +227,6 @@ typedef struct { EbmlList blocks; } MatroskaCluster; -#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x)) - 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} }, @@ -495,7 +494,7 @@ const struct { static int ebml_level_end(MatroskaDemuxContext *matroska) { ByteIOContext *pb = matroska->ctx->pb; - offset_t pos = url_ftell(pb); + int64_t pos = url_ftell(pb); if (matroska->num_levels > 0) { MatroskaLevel *level = &matroska->levels[matroska->num_levels - 1]; @@ -527,7 +526,7 @@ static int ebml_read_num(MatroskaDemuxContext *matroska, ByteIOContext *pb, if (!(total = get_byte(pb))) { /* we might encounter EOS here */ if (!url_feof(pb)) { - offset_t pos = url_ftell(pb); + int64_t pos = url_ftell(pb); av_log(matroska->ctx, AV_LOG_ERROR, "Read error at pos. %"PRIu64" (0x%"PRIx64")\n", pos, pos); @@ -541,7 +540,7 @@ static int ebml_read_num(MatroskaDemuxContext *matroska, ByteIOContext *pb, len_mask >>= 1; } if (read > max_size) { - offset_t pos = url_ftell(pb) - 1; + int64_t pos = url_ftell(pb) - 1; av_log(matroska->ctx, AV_LOG_ERROR, "Invalid EBML number size tag 0x%02x at pos %"PRIu64" (0x%"PRIx64")\n", (uint8_t) total, pos, pos); @@ -872,15 +871,14 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size, case MATROSKA_TRACK_ENCODING_COMP_LZO: do { olen = pkt_size *= 3; - pkt_data = av_realloc(pkt_data, - pkt_size+LZO_OUTPUT_PADDING); - result = lzo1x_decode(pkt_data, &olen, data, &isize); - } while (result==LZO_OUTPUT_FULL && pkt_size<10000000); + pkt_data = av_realloc(pkt_data, pkt_size+AV_LZO_OUTPUT_PADDING); + result = av_lzo1x_decode(pkt_data, &olen, data, &isize); + } while (result==AV_LZO_OUTPUT_FULL && pkt_size<10000000); if (result) goto failed; pkt_size -= olen; break; -#ifdef CONFIG_ZLIB +#if CONFIG_ZLIB case MATROSKA_TRACK_ENCODING_COMP_ZLIB: { z_stream zstream = {0}; if (inflateInit(&zstream) != Z_OK) @@ -901,7 +899,7 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size, break; } #endif -#ifdef CONFIG_BZLIB +#if CONFIG_BZLIB case MATROSKA_TRACK_ENCODING_COMP_BZLIB: { bz_stream bzstream = {0}; if (BZ2_bzDecompressInit(&bzstream, 0, 0) != BZ_OK) @@ -935,7 +933,7 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size, } static void matroska_fix_ass_packet(MatroskaDemuxContext *matroska, - AVPacket *pkt) + AVPacket *pkt, uint64_t display_duration) { char *line, *layer, *ptr = pkt->data, *end = ptr+pkt->size; for (; *ptr!=',' && ptrpts + pkt->convergence_duration; + int64_t end_pts = pkt->pts + display_duration; int sc = matroska->time_scale * pkt->pts / 10000000; int ec = matroska->time_scale * end_pts / 10000000; int sh, sm, ss, eh, em, es, len; @@ -957,7 +955,7 @@ static void matroska_fix_ass_packet(MatroskaDemuxContext *matroska, len = 50 + end-ptr + FF_INPUT_BUFFER_PADDING_SIZE; if (!(line = av_malloc(len))) return; - snprintf(line,len,"Dialogue: %s,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s", + snprintf(line,len,"Dialogue: %s,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s\r\n", layer, sh, sm, ss, sc, eh, em, es, ec, ptr); av_free(pkt->data); pkt->data = line; @@ -965,13 +963,22 @@ static void matroska_fix_ass_packet(MatroskaDemuxContext *matroska, } } +static void matroska_merge_packets(AVPacket *out, AVPacket *in) +{ + out->data = av_realloc(out->data, out->size+in->size); + memcpy(out->data+out->size, in->data, in->size); + out->size += in->size; + av_destruct_packet(in); + av_free(in); +} + static void matroska_convert_tags(AVFormatContext *s, EbmlList *list) { MatroskaTag *tags = list->elem; int i, j; for (i=0; i < list->nb_elem; i++) { - for (j=0; j < ARRAY_SIZE(metadata); j++){ + for (j=0; j < FF_ARRAY_ELEMS(metadata); j++){ if (!strcmp(tags[i].name, metadata[j].name)) { int *ptr = (int *)((char *)s + metadata[j].offset); if (*ptr) continue; @@ -991,12 +998,12 @@ static void matroska_execute_seekhead(MatroskaDemuxContext *matroska) EbmlList *seekhead_list = &matroska->seekhead; MatroskaSeekhead *seekhead = seekhead_list->elem; uint32_t level_up = matroska->level_up; - offset_t before_pos = url_ftell(matroska->ctx->pb); + int64_t before_pos = url_ftell(matroska->ctx->pb); MatroskaLevel level; int i; for (i=0; inb_elem; i++) { - offset_t offset = seekhead[i].pos + matroska->segment_start; + int64_t offset = seekhead[i].pos + matroska->segment_start; if (seekhead[i].pos <= before_pos || seekhead[i].id == MATROSKA_ID_SEEKHEAD @@ -1041,7 +1048,7 @@ static int matroska_aac_profile(char *codec_id) static const char * const aac_profiles[] = { "MAIN", "LC", "SSR" }; int profile; - for (profile=0; profiletype != MATROSKA_TRACK_TYPE_VIDEO && @@ -1138,10 +1148,10 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) } else if (encodings_list->nb_elem == 1) { if (encodings[0].type || (encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP && -#ifdef CONFIG_ZLIB +#if CONFIG_ZLIB encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_ZLIB && #endif -#ifdef CONFIG_BZLIB +#if CONFIG_BZLIB encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_BZLIB && #endif encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_LZO)) { @@ -1182,7 +1192,6 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) st = track->stream = av_new_stream(s, 0); if (st == NULL) return AVERROR(ENOMEM); - track->first_timecode = AV_NOPTS_VALUE; if (!strcmp(track->codec_id, "V_MS/VFW/FOURCC") && track->codec_priv.size >= 40 @@ -1192,8 +1201,12 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) } else if (!strcmp(track->codec_id, "A_MS/ACM") && track->codec_priv.size >= 18 && track->codec_priv.data != NULL) { - uint16_t tag = AV_RL16(track->codec_priv.data); - codec_id = codec_get_id(codec_wav_tags, tag); + init_put_byte(&b, track->codec_priv.data, track->codec_priv.size, + URL_RDONLY, NULL, NULL, NULL, NULL); + get_wav_header(&b, st->codec, track->codec_priv.size); + codec_id = st->codec->codec_id; + extradata_offset = 18; + track->codec_priv.size -= extradata_offset; } else if (!strcmp(track->codec_id, "V_QUICKTIME") && (track->codec_priv.size >= 86) && (track->codec_priv.data != NULL)) { @@ -1230,7 +1243,6 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) } else extradata_size = 2; } else if (codec_id == CODEC_ID_TTA) { - ByteIOContext b; extradata_size = 30; extradata = av_mallocz(extradata_size); if (extradata == NULL) @@ -1252,8 +1264,6 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) track->audio.channels = 1; } else if (codec_id == CODEC_ID_RA_288 || codec_id == CODEC_ID_COOK || codec_id == CODEC_ID_ATRAC3) { - ByteIOContext b; - init_put_byte(&b, track->codec_priv.data,track->codec_priv.size, 0, NULL, NULL, NULL, NULL); url_fskip(&b, 24); @@ -1297,7 +1307,8 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) st->codec->extradata = extradata; st->codec->extradata_size = extradata_size; } else if(track->codec_priv.data && track->codec_priv.size > 0){ - st->codec->extradata = av_malloc(track->codec_priv.size); + st->codec->extradata = av_mallocz(track->codec_priv.size + + FF_INPUT_BUFFER_PADDING_SIZE); if(st->codec->extradata == NULL) return AVERROR(ENOMEM); st->codec->extradata_size = track->codec_priv.size; @@ -1356,13 +1367,21 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) chapters = chapters_list->elem; for (i=0; inb_elem; i++) - if (chapters[i].start != AV_NOPTS_VALUE && chapters[i].uid) + if (chapters[i].start != AV_NOPTS_VALUE && chapters[i].uid + && (max_start==0 || chapters[i].start > max_start)) { ff_new_chapter(s, chapters[i].uid, (AVRational){1, 1000000000}, chapters[i].start, chapters[i].end, chapters[i].title); + max_start = chapters[i].start; + } index_list = &matroska->index; index = index_list->elem; + if (index_list->nb_elem + && index[0].time > 100000000000000/matroska->time_scale) { + av_log(matroska->ctx, AV_LOG_WARNING, "Working around broken index.\n"); + index_scale = matroska->time_scale; + } for (i=0; inb_elem; i++) { EbmlList *pos_list = &index[i].pos; MatroskaIndexPos *pos = pos_list->elem; @@ -1372,7 +1391,8 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) if (track && track->stream) av_add_index_entry(track->stream, pos[j].pos + matroska->segment_start, - index[i].time, 0, 0, AVINDEX_KEYFRAME); + index[i].time/index_scale, 0, 0, + AVINDEX_KEYFRAME); } } @@ -1468,11 +1488,8 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE && timecode < track->end_timecode) is_keyframe = 0; /* overlapping subtitles are not key frame */ - if (is_keyframe) { + if (is_keyframe) av_add_index_entry(st, cluster_pos, timecode, 0,0,AVINDEX_KEYFRAME); - if (track->first_timecode == AV_NOPTS_VALUE) - track->first_timecode = timecode; - } track->end_timecode = FFMAX(track->end_timecode, timecode+duration); } @@ -1626,15 +1643,23 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, pkt->pts = timecode; pkt->pos = pos; - if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE) + if (st->codec->codec_id == CODEC_ID_TEXT) pkt->convergence_duration = duration; - else + else if (track->type != MATROSKA_TRACK_TYPE_SUBTITLE) pkt->duration = duration; if (st->codec->codec_id == CODEC_ID_SSA) - matroska_fix_ass_packet(matroska, pkt); - - dynarray_add(&matroska->packets, &matroska->num_packets, pkt); + matroska_fix_ass_packet(matroska, pkt, duration); + + if (matroska->prev_pkt && + timecode != AV_NOPTS_VALUE && + matroska->prev_pkt->pts == timecode && + matroska->prev_pkt->stream_index == st->index) + matroska_merge_packets(matroska->prev_pkt, pkt); + else { + dynarray_add(&matroska->packets,&matroska->num_packets,pkt); + matroska->prev_pkt = pkt; + } } if (timecode != AV_NOPTS_VALUE) @@ -1653,7 +1678,8 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska) EbmlList *blocks_list; MatroskaBlock *blocks; int i, res; - offset_t pos = url_ftell(matroska->ctx->pb); + int64_t pos = url_ftell(matroska->ctx->pb); + matroska->prev_pkt = NULL; if (matroska->has_cluster_id){ /* For the first cluster we parse, its ID was already read as part of matroska_read_header(), so don't read it again */ @@ -1697,19 +1723,13 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index, MatroskaTrack *tracks = matroska->tracks.elem; AVStream *st = s->streams[stream_index]; int i, index, index_sub, index_min; - int64_t first_timecode = 0; - - for (i=0; i < matroska->tracks.nb_elem; i++) - if (tracks[i].stream->index == stream_index && - tracks[i].first_timecode != AV_NOPTS_VALUE) - first_timecode = tracks[i].first_timecode; - if (timestamp < first_timecode) - timestamp = first_timecode; + if (!st->nb_index_entries) + return 0; + timestamp = FFMAX(timestamp, st->index_entries[0].timestamp); if ((index = av_index_search_timestamp(st, timestamp, flags)) < 0) { - if (st->nb_index_entries) - url_fseek(s->pb, st->index_entries[st->nb_index_entries-1].pos, SEEK_SET); + url_fseek(s->pb, st->index_entries[st->nb_index_entries-1].pos, SEEK_SET); while ((index = av_index_search_timestamp(st, timestamp, flags)) < 0) { matroska_clear_queue(matroska); if (matroska_parse_cluster(matroska) < 0)