diff options
author | Tomas Härdin <tomas.hardin@codemill.se> | 2011-12-08 20:28:49 +0100 |
---|---|---|
committer | Tomas Härdin <tomas.hardin@codemill.se> | 2011-12-08 20:28:49 +0100 |
commit | ddcf3e0535191a776728d0ecabc71c6dddf05dd1 (patch) | |
tree | 73144e4c52c17189de954f66ff1d9348bb32a091 /libavformat | |
parent | 5e67e3eac2fed771ef7363face3ff4691dd4ff2d (diff) | |
download | ffmpeg-ddcf3e0535191a776728d0ecabc71c6dddf05dd1.tar.gz |
mxfdec: Index table driven demuxing and seeking
This adds OPAtom support and proper seeking.
D-10 and non-seekable OP1a streams still use the old demuxing/seeking code.
Diffstat (limited to 'libavformat')
-rw-r--r-- | libavformat/mxfdec.c | 100 |
1 files changed, 97 insertions, 3 deletions
diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 37245df474..47717c6db5 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -197,6 +197,9 @@ typedef struct { int parsing_backward; int64_t last_forward_tell; int last_forward_partition; + int current_edit_unit; + int current_stream; + int d10; } MXFContext; enum MXFWrappingScheme { @@ -372,7 +375,7 @@ static int mxf_decrypt_triplet(AVFormatContext *s, AVPacket *pkt, KLVPacket *klv return 0; } -static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) +static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) { KLVPacket klv; @@ -418,6 +421,65 @@ static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) return AVERROR_EOF; } +static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + MXFContext *mxf = s->priv_data; + AVIndexEntry *e; + int ret; + int64_t ret64; + KLVPacket klv; + AVStream *st; + + /* TODO: better logic for this? + * only files that lack all index segments prior to the essence need this */ + if (!s->pb->seekable && mxf->op != OPAtom || mxf->d10) + return mxf_read_packet_old(s, pkt); + + if (mxf->current_stream >= s->nb_streams) { + mxf->current_edit_unit++; + mxf->current_stream = 0; + } + + st = s->streams[mxf->current_stream]; + + if (mxf->current_edit_unit >= st->nb_index_entries) + return AVERROR_EOF; + + e = &st->index_entries[mxf->current_edit_unit]; + + if ((ret64 = avio_seek(s->pb, e->pos, SEEK_SET)) < 0) + return ret64; + + if (mxf->op == OPAtom) { + /* OPAtom - no KL, just essence */ + if ((ret = av_get_packet(s->pb, pkt, e->size)) != e->size) + return ret < 0 ? ret : AVERROR_EOF; + } else { + /* read KL, read L bytes of essence */ + if ((ret = klv_read_packet(&klv, s->pb)) < 0) + return ret; + + /* untested, but looks OK */ + if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) { + int res = mxf_decrypt_triplet(s, pkt, &klv); + if (res < 0) { + av_log(s, AV_LOG_ERROR, "invalid encoded triplet\n"); + return -1; + } + return 0; + } + + if ((ret = av_get_packet(s->pb, pkt, klv.length)) != klv.length) + return ret < 0 ? ret : AVERROR_EOF; + + pkt->pos = e->pos; + } + + pkt->stream_index = mxf->current_stream++; + + return 0; +} + static int mxf_read_primer_pack(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset) { MXFContext *mxf = arg; @@ -925,6 +987,8 @@ static const MXFCodecUL mxf_essence_container_uls[] = { { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, CODEC_ID_NONE }, }; +static UID mxf_d10_ul = { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x01,0x01,0x01 }; + static int mxf_get_sorted_table_segments(MXFContext *mxf, int *nb_sorted_segments, MXFIndexTableSegment ***sorted_segments) { int i, j, nb_segments = 0; @@ -1252,6 +1316,11 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) } } } + + /* HACK: revert to the old demuxing/seeking scode for D-10 for now */ + if (mxf_match_uid(essence_container_ul, mxf_d10_ul, 14)) + mxf->d10 = 1; + /* TODO: drop PictureEssenceCoding and SoundEssenceCompression, only check EssenceContainer */ codec_ul = mxf_get_codec_ul(ff_mxf_codec_uls, &descriptor->essence_codec_ul); st->codec->codec_id = codec_ul->id; @@ -1291,8 +1360,8 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) } } if (st->codec->codec_type != AVMEDIA_TYPE_DATA && (*essence_container_ul)[15] > 0x01) { - av_log(mxf->fc, AV_LOG_WARNING, "only frame wrapped mappings are correctly supported\n"); - st->need_parsing = AVSTREAM_PARSE_FULL; + /* TODO: decode timestamps */ + st->need_parsing = AVSTREAM_PARSE_TIMESTAMPS; } if ((ret = mxf_parse_index(mxf, material_track->track_id, st))) @@ -1659,7 +1728,11 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti { AVStream *st = s->streams[stream_index]; int64_t seconds; + MXFContext* mxf = s->priv_data; + int64_t seekpos; + int index; + if (mxf->d10) { if (!s->bit_rate) return -1; if (sample_time < 0) @@ -1668,6 +1741,27 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti if (avio_seek(s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET) < 0) return -1; ff_update_cur_dts(s, st, sample_time); + } else { + if (st->nb_index_entries <= 0) + return -1; + + index = av_index_search_timestamp(st, sample_time, flags); + + av_dlog(s, "stream %d, timestamp %"PRId64", sample %d\n", st->index, sample_time, index); + + if (index < 0) { + if (sample_time < st->index_entries[0].timestamp) + index = 0; + else + return -1; + } + + seekpos = st->index_entries[index].pos; + av_update_cur_dts(s, st, st->index_entries[index].timestamp); + mxf->current_edit_unit = st->index_entries[index].timestamp; + mxf->current_stream = 0; + avio_seek(s->pb, seekpos, SEEK_SET); + } return 0; } |