History

Merge remote-tracking branch 'tjoppen/opatom_demuxing_and_seeking'

* tjoppen/opatom_demuxing_and_seeking: mxfdec: Index table driven demuxing and seeking mxfdec: Compute packet offsets properly mxfdec: Use MaterialPackage - Track - TrackID instead of the system_item hack mxfdec: Parse more values in PartitionPack mxfdec: Parse TemporalOffsets mxfdec: av_dlog():ify 'no corresponding source package found' mxfdec: Compute essence container offsets and lengths into mxf->partitions mxfdec: Make mxf->partitions sorted by offset mxfdec: Parse ThisPartition mxfdec: Speed up metadata and index parsing mxfdec: Make sure DataDefinition is consistent between material track and source track mxfdec: Add EssenceContainer UL found in 0001GL00.MXF.A1.mxf_opatom.mxf

Michael Niedermayer committed 14 years ago

Commit 4ab495b2 parents 74436ad ddcf3e02 files · +419 −87Browse files

Unified · Split

2 files
  1. libavformat/mxfdec.c +401 −64
  2. tests/ref/seek/lavf_mxf +18 −23
libavformat/mxfdec.c+401−64
@@ -69,6 +69,7 @@ typedef enum { · 68 unmodified lines
69 OP3b,69 OP3b,
70 OP3c,70 OP3c,
71 OPAtom,71 OPAtom,
72 OPSONYOpt, /* FATE sample, violates the spec in places */
72} MXFOP;73} MXFOP;
73 74
74typedef struct {75typedef struct {
@@ -78,6 +79,13 @@ typedef struct { · 3 unmodified lines
78 uint64_t previous_partition;79 uint64_t previous_partition;
79 int index_sid;80 int index_sid;
80 int body_sid;81 int body_sid;
82 int64_t this_partition;
83 int64_t essence_offset; /* absolute offset of essence */
84 int64_t essence_length;
85 int32_t kag_size;
86 int64_t header_byte_count;
87 int64_t index_byte_count;
88 int pack_length;
81} MXFPartition;89} MXFPartition;
82 90
83typedef struct {91typedef struct {
@@ -147,6 +155,7 @@ typedef struct { · 63 unmodified lines
147 int *slice;155 int *slice;
148 int *element_delta;156 int *element_delta;
149 int nb_delta_entries;157 int nb_delta_entries;
158 int8_t *temporal_offset_entries;
150 int *flag_entries;159 int *flag_entries;
151 uint64_t *stream_offset_entries;160 uint64_t *stream_offset_entries;
152 uint32_t **slice_offset_entries;161 uint32_t **slice_offset_entries;
@@ -181,12 +190,16 @@ typedef struct { · 28 unmodified lines
181 uint8_t *local_tags;190 uint8_t *local_tags;
182 int local_tags_count;191 int local_tags_count;
183 uint64_t footer_partition;192 uint64_t footer_partition;
184 int system_item;
185 int64_t essence_offset;
186 int first_essence_kl_length;
187 int64_t first_essence_length;
188 KLVPacket current_klv_data;193 KLVPacket current_klv_data;
189 int current_klv_index;194 int current_klv_index;
195 int run_in;
196 MXFPartition *current_partition;
197 int parsing_backward;
198 int64_t last_forward_tell;
199 int last_forward_partition;
200 int current_edit_unit;
201 int current_stream;
202 int d10;
190} MXFContext;203} MXFContext;
191 204
192enum MXFWrappingScheme {205enum MXFWrappingScheme {
@@ -194,7 +207,8 @@ enum MXFWrappingScheme { · 1 unmodified line
194 Clip,207 Clip,
195};208};
196 209
197typedef int MXFMetadataReadFunc(void *arg, AVIOContext *pb, int tag, int size, UID uid);210/* NOTE: klv_offset is not set (-1) for local keys */
211typedef int MXFMetadataReadFunc(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset);
198 212
199typedef struct {213typedef struct {
200 const UID key;214 const UID key;
@@ -361,7 +375,7 @@ static int mxf_decrypt_triplet(AVFormatContext *s, AVPacket *pkt, KLVPacket *klv · 160 unmodified lines
361 return 0;375 return 0;
362}376}
363 377
364static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt)378static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt)
365{379{
366 KLVPacket klv;380 KLVPacket klv;
367 381
@@ -407,7 +421,66 @@ static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) · 39 unmodified lines
407 return AVERROR_EOF;421 return AVERROR_EOF;
408}422}
409 423
410static int mxf_read_primer_pack(void *arg, AVIOContext *pb, int tag, int size, UID uid)424static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt)
425{
426 MXFContext *mxf = s->priv_data;
427 AVIndexEntry *e;
428 int ret;
429 int64_t ret64;
430 KLVPacket klv;
431 AVStream *st;
432
433 /* TODO: better logic for this?
434 * only files that lack all index segments prior to the essence need this */
435 if (!s->pb->seekable && mxf->op != OPAtom || mxf->d10)
436 return mxf_read_packet_old(s, pkt);
437
438 if (mxf->current_stream >= s->nb_streams) {
439 mxf->current_edit_unit++;
440 mxf->current_stream = 0;
441 }
442
443 st = s->streams[mxf->current_stream];
444
445 if (mxf->current_edit_unit >= st->nb_index_entries)
446 return AVERROR_EOF;
447
448 e = &st->index_entries[mxf->current_edit_unit];
449
450 if ((ret64 = avio_seek(s->pb, e->pos, SEEK_SET)) < 0)
451 return ret64;
452
453 if (mxf->op == OPAtom) {
454 /* OPAtom - no KL, just essence */
455 if ((ret = av_get_packet(s->pb, pkt, e->size)) != e->size)
456 return ret < 0 ? ret : AVERROR_EOF;
457 } else {
458 /* read KL, read L bytes of essence */
459 if ((ret = klv_read_packet(&klv, s->pb)) < 0)
460 return ret;
461
462 /* untested, but looks OK */
463 if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) {
464 int res = mxf_decrypt_triplet(s, pkt, &klv);
465 if (res < 0) {
466 av_log(s, AV_LOG_ERROR, "invalid encoded triplet\n");
467 return -1;
468 }
469 return 0;
470 }
471
472 if ((ret = av_get_packet(s->pb, pkt, klv.length)) != klv.length)
473 return ret < 0 ? ret : AVERROR_EOF;
474
475 pkt->pos = e->pos;
476 }
477
478 pkt->stream_index = mxf->current_stream++;
479
480 return 0;
481}
482
483static int mxf_read_primer_pack(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
411{484{
412 MXFContext *mxf = arg;485 MXFContext *mxf = arg;
413 int item_num = avio_rb32(pb);486 int item_num = avio_rb32(pb);
@@ -427,7 +500,7 @@ static int mxf_read_primer_pack(void *arg, AVIOContext *pb, int tag, int size, U · 13 unmodified lines
427 return 0;500 return 0;
428}501}
429 502
430static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size, UID uid)503static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
431{504{
432 MXFContext *mxf = arg;505 MXFContext *mxf = arg;
433 MXFPartition *partition;506 MXFPartition *partition;
@@ -441,7 +514,21 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size · 7 unmodified lines
441 if (!mxf->partitions)514 if (!mxf->partitions)
442 return AVERROR(ENOMEM);515 return AVERROR(ENOMEM);
443 516
444 partition = &mxf->partitions[mxf->partitions_count++];517 if (mxf->parsing_backward) {
518 /* insert the new partition pack in the middle
519 * this makes the entries in mxf->partitions sorted by offset */
520 memmove(&mxf->partitions[mxf->last_forward_partition+1],
521 &mxf->partitions[mxf->last_forward_partition],
522 (mxf->partitions_count - mxf->last_forward_partition)*sizeof(*mxf->partitions));
523 partition = mxf->current_partition = &mxf->partitions[mxf->last_forward_partition];
524 } else {
525 mxf->last_forward_partition++;
526 partition = mxf->current_partition = &mxf->partitions[mxf->partitions_count];
527 }
528
529 memset(partition, 0, sizeof(*partition));
530 mxf->partitions_count++;
531 partition->pack_length = avio_tell(pb) - klv_offset + size;
445 532
446 switch(uid[13]) {533 switch(uid[13]) {
447 case 2:534 case 2:
@@ -461,10 +548,13 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size · 13 unmodified lines
461 /* consider both footers to be closed (there is only Footer and CompleteFooter) */548 /* consider both footers to be closed (there is only Footer and CompleteFooter) */
462 partition->closed = partition->type == Footer || !(uid[14] & 1);549 partition->closed = partition->type == Footer || !(uid[14] & 1);
463 partition->complete = uid[14] > 2;550 partition->complete = uid[14] > 2;
464 avio_skip(pb, 16);551 avio_skip(pb, 4);
552 partition->kag_size = avio_rb32(pb);
553 partition->this_partition = avio_rb64(pb);
465 partition->previous_partition = avio_rb64(pb);554 partition->previous_partition = avio_rb64(pb);
466 footer_partition = avio_rb64(pb);555 footer_partition = avio_rb64(pb);
467 avio_skip(pb, 16);556 partition->header_byte_count = avio_rb64(pb);
557 partition->index_byte_count = avio_rb64(pb);
468 partition->index_sid = avio_rb32(pb);558 partition->index_sid = avio_rb32(pb);
469 avio_skip(pb, 8);559 avio_skip(pb, 8);
470 partition->body_sid = avio_rb32(pb);560 partition->body_sid = avio_rb32(pb);
@@ -480,8 +570,9 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size · 9 unmodified lines
480 }570 }
481 }571 }
482 572
483 av_dlog(mxf->fc, "PartitionPack: PreviousPartition = 0x%lx, "573 av_dlog(mxf->fc, "PartitionPack: ThisPartition = 0x%lx, PreviousPartition = 0x%lx, "
484 "FooterPartition = 0x%lx, IndexSID = %i, BodySID = %i\n",574 "FooterPartition = 0x%lx, IndexSID = %i, BodySID = %i\n",
575 partition->this_partition,
485 partition->previous_partition, footer_partition,576 partition->previous_partition, footer_partition,
486 partition->index_sid, partition->body_sid);577 partition->index_sid, partition->body_sid);
487 578
@@ -495,8 +586,22 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size · 7 unmodified lines
495 else if (op[12] == 3 && op[13] == 2) mxf->op = OP3b;586 else if (op[12] == 3 && op[13] == 2) mxf->op = OP3b;
496 else if (op[12] == 3 && op[13] == 3) mxf->op = OP3c;587 else if (op[12] == 3 && op[13] == 3) mxf->op = OP3c;
497 else if (op[12] == 0x10) mxf->op = OPAtom;588 else if (op[12] == 0x10) mxf->op = OPAtom;
498 else589 else if (op[12] == 64&& op[13] == 1) mxf->op = OPSONYOpt;
499 av_log(mxf->fc, AV_LOG_ERROR, "unknown operational pattern: %02xh %02xh\n", op[12], op[13]);590 else {
591 av_log(mxf->fc, AV_LOG_ERROR, "unknown operational pattern: %02xh %02xh - guessing OP1a\n", op[12], op[13]);
592 mxf->op = OP1a;
593 }
594
595 if (partition->kag_size <= 0 || partition->kag_size > (1 << 20)) {
596 av_log(mxf->fc, AV_LOG_WARNING, "invalid KAGSize %i - guessing ", partition->kag_size);
597
598 if (mxf->op == OPSONYOpt)
599 partition->kag_size = 512;
600 else
601 partition->kag_size = 1;
602
603 av_log(mxf->fc, AV_LOG_WARNING, "%i\n", partition->kag_size);
604 }
500 605
501 return 0;606 return 0;
502}607}
@@ -513,7 +618,7 @@ static int mxf_add_metadata_set(MXFContext *mxf, void *metadata_set) · 10 unmodified lines
513 return 0;618 return 0;
514}619}
515 620
516static int mxf_read_cryptographic_context(void *arg, AVIOContext *pb, int tag, int size, UID uid)621static int mxf_read_cryptographic_context(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
517{622{
518 MXFCryptoContext *cryptocontext = arg;623 MXFCryptoContext *cryptocontext = arg;
519 if (size != 16)624 if (size != 16)
@@ -523,7 +628,7 @@ static int mxf_read_cryptographic_context(void *arg, AVIOContext *pb, int tag, i · 3 unmodified lines
523 return 0;628 return 0;
524}629}
525 630
526static int mxf_read_content_storage(void *arg, AVIOContext *pb, int tag, int size, UID uid)631static int mxf_read_content_storage(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
527{632{
528 MXFContext *mxf = arg;633 MXFContext *mxf = arg;
529 switch (tag) {634 switch (tag) {
@@ -541,7 +646,7 @@ static int mxf_read_content_storage(void *arg, AVIOContext *pb, int tag, int siz · 11 unmodified lines
541 return 0;646 return 0;
542}647}
543 648
544static int mxf_read_source_clip(void *arg, AVIOContext *pb, int tag, int size, UID uid)649static int mxf_read_source_clip(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
545{650{
546 MXFStructuralComponent *source_clip = arg;651 MXFStructuralComponent *source_clip = arg;
547 switch(tag) {652 switch(tag) {
@@ -563,7 +668,7 @@ static int mxf_read_source_clip(void *arg, AVIOContext *pb, int tag, int size, U · 15 unmodified lines
563 return 0;668 return 0;
564}669}
565 670
566static int mxf_read_material_package(void *arg, AVIOContext *pb, int tag, int size, UID uid)671static int mxf_read_material_package(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
567{672{
568 MXFPackage *package = arg;673 MXFPackage *package = arg;
569 switch(tag) {674 switch(tag) {
@@ -581,7 +686,7 @@ static int mxf_read_material_package(void *arg, AVIOContext *pb, int tag, int si · 11 unmodified lines
581 return 0;686 return 0;
582}687}
583 688
584static int mxf_read_track(void *arg, AVIOContext *pb, int tag, int size, UID uid)689static int mxf_read_track(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
585{690{
586 MXFTrack *track = arg;691 MXFTrack *track = arg;
587 switch(tag) {692 switch(tag) {
@@ -602,7 +707,7 @@ static int mxf_read_track(void *arg, AVIOContext *pb, int tag, int size, UID uid · 14 unmodified lines
602 return 0;707 return 0;
603}708}
604 709
605static int mxf_read_sequence(void *arg, AVIOContext *pb, int tag, int size, UID uid)710static int mxf_read_sequence(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
606{711{
607 MXFSequence *sequence = arg;712 MXFSequence *sequence = arg;
608 switch(tag) {713 switch(tag) {
@@ -626,7 +731,7 @@ static int mxf_read_sequence(void *arg, AVIOContext *pb, int tag, int size, UID · 17 unmodified lines
626 return 0;731 return 0;
627}732}
628 733
629static int mxf_read_source_package(void *arg, AVIOContext *pb, int tag, int size, UID uid)734static int mxf_read_source_package(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
630{735{
631 MXFPackage *package = arg;736 MXFPackage *package = arg;
632 switch(tag) {737 switch(tag) {
@@ -678,7 +783,8 @@ static int mxf_read_index_entry_array(AVIOContext *pb, MXFIndexTableSegment *seg · 45 unmodified lines
678 segment->nb_index_entries = avio_rb32(pb);783 segment->nb_index_entries = avio_rb32(pb);
679 length = avio_rb32(pb);784 length = avio_rb32(pb);
680 785
681 if (!(segment->flag_entries = av_calloc(segment->nb_index_entries, sizeof(*segment->flag_entries))) ||786 if (!(segment->temporal_offset_entries=av_calloc(segment->nb_index_entries, sizeof(*segment->temporal_offset_entries))) ||
787 !(segment->flag_entries = av_calloc(segment->nb_index_entries, sizeof(*segment->flag_entries))) ||
682 !(segment->stream_offset_entries = av_calloc(segment->nb_index_entries, sizeof(*segment->stream_offset_entries))))788 !(segment->stream_offset_entries = av_calloc(segment->nb_index_entries, sizeof(*segment->stream_offset_entries))))
683 return AVERROR(ENOMEM);789 return AVERROR(ENOMEM);
684 790
@@ -687,7 +793,8 @@ static int mxf_read_index_entry_array(AVIOContext *pb, MXFIndexTableSegment *seg · 2 unmodified lines
687 return AVERROR(ENOMEM);793 return AVERROR(ENOMEM);
688 794
689 for (i = 0; i < segment->nb_index_entries; i++) {795 for (i = 0; i < segment->nb_index_entries; i++) {
690 avio_rb16(pb); /* TemporalOffset and KeyFrameOffset */796 segment->temporal_offset_entries[i] = avio_r8(pb);
797 avio_r8(pb); /* KeyFrameOffset */
691 segment->flag_entries[i] = avio_r8(pb);798 segment->flag_entries[i] = avio_r8(pb);
692 segment->stream_offset_entries[i] = avio_rb64(pb);799 segment->stream_offset_entries[i] = avio_rb64(pb);
693 if (segment->slice_count) {800 if (segment->slice_count) {
@@ -703,7 +810,7 @@ static int mxf_read_index_entry_array(AVIOContext *pb, MXFIndexTableSegment *seg · 9 unmodified lines
703 return 0;810 return 0;
704}811}
705 812
706static int mxf_read_index_table_segment(void *arg, AVIOContext *pb, int tag, int size, UID uid)813static int mxf_read_index_table_segment(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
707{814{
708 MXFIndexTableSegment *segment = arg;815 MXFIndexTableSegment *segment = arg;
709 switch(tag) {816 switch(tag) {
@@ -766,7 +873,7 @@ static void mxf_read_pixel_layout(AVIOContext *pb, MXFDescriptor *descriptor) · 56 unmodified lines
766 ff_mxf_decode_pixel_layout(layout, &descriptor->pix_fmt);873 ff_mxf_decode_pixel_layout(layout, &descriptor->pix_fmt);
767}874}
768 875
769static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int size, UID uid)876static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
770{877{
771 MXFDescriptor *descriptor = arg;878 MXFDescriptor *descriptor = arg;
772 switch(tag) {879 switch(tag) {
@@ -876,9 +983,12 @@ static const MXFCodecUL mxf_essence_container_uls[] = { · 103 unmodified lines
876 { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x06,0x01,0x00 }, 14, CODEC_ID_PCM_S16LE }, /* BWF Frame wrapped */983 { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x06,0x01,0x00 }, 14, CODEC_ID_PCM_S16LE }, /* BWF Frame wrapped */
877 { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x03,0x01,0x02,0x04,0x40,0x01 }, 14, CODEC_ID_MP2 }, /* MPEG-ES Frame wrapped, 0x40 ??? stream id */984 { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x03,0x01,0x02,0x04,0x40,0x01 }, 14, CODEC_ID_MP2 }, /* MPEG-ES Frame wrapped, 0x40 ??? stream id */
878 { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x01,0x01,0x01 }, 14, CODEC_ID_PCM_S16LE }, /* D-10 Mapping 50Mbps PAL Extended Template */985 { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x01,0x01,0x01 }, 14, CODEC_ID_PCM_S16LE }, /* D-10 Mapping 50Mbps PAL Extended Template */
986 { { 0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0xFF,0x4B,0x46,0x41,0x41,0x00,0x0D,0x4D,0x4F }, 14, CODEC_ID_PCM_S16LE }, /* 0001GL00.MXF.A1.mxf_opatom.mxf */
879 { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, CODEC_ID_NONE },987 { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, CODEC_ID_NONE },
880};988};
881 989
990static UID mxf_d10_ul = { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x01,0x01,0x01 };
991
882static int mxf_get_sorted_table_segments(MXFContext *mxf, int *nb_sorted_segments, MXFIndexTableSegment ***sorted_segments)992static int mxf_get_sorted_table_segments(MXFContext *mxf, int *nb_sorted_segments, MXFIndexTableSegment ***sorted_segments)
883{993{
884 int i, j, nb_segments = 0;994 int i, j, nb_segments = 0;
@@ -936,28 +1046,53 @@ static int mxf_get_sorted_table_segments(MXFContext *mxf, int *nb_sorted_segment · 51 unmodified lines
936 return 0;1046 return 0;
937}1047}
938 1048
939static int mxf_parse_index(MXFContext *mxf, int i, AVStream *st)1049/**
1050 * Computes the absolute file offset of the given essence container offset
1051 */
1052static int mxf_absolute_bodysid_offset(MXFContext *mxf, int body_sid, int64_t offset, int64_t *offset_out)
1053{
1054 int x;
1055 int64_t offset_in = offset; /* for logging */
1056
1057 for (x = 0; x < mxf->partitions_count; x++) {
1058 MXFPartition *p = &mxf->partitions[x];
1059
1060 if (p->body_sid != body_sid)
1061 continue;
1062
1063 if (offset < p->essence_length || !p->essence_length) {
1064 *offset_out = p->essence_offset + offset;
1065 return 0;
1066 }
1067
1068 offset -= p->essence_length;
1069 }
1070
1071 av_log(mxf->fc, AV_LOG_ERROR, "failed to find absolute offset of %lx in BodySID %i - partial file?\n",
1072 offset_in, body_sid);
1073
1074 return AVERROR_INVALIDDATA;
1075}
1076
1077static int mxf_parse_index(MXFContext *mxf, int track_id, AVStream *st)
940{1078{
941 int64_t accumulated_offset = 0;
942 int j, k, ret, nb_sorted_segments;1079 int j, k, ret, nb_sorted_segments;
943 MXFIndexTableSegment **sorted_segments;1080 MXFIndexTableSegment **sorted_segments;
1081 int n_delta = track_id - 1; /* TrackID = 1-based stream index */
1082
1083 if (track_id < 1) {
1084 av_log(mxf->fc, AV_LOG_ERROR, "TrackID not positive: %i\n", track_id);
1085 return AVERROR_INVALIDDATA;
1086 }
944 1087
945 if ((ret = mxf_get_sorted_table_segments(mxf, &nb_sorted_segments, &sorted_segments)))1088 if ((ret = mxf_get_sorted_table_segments(mxf, &nb_sorted_segments, &sorted_segments)))
946 return ret;1089 return ret;
947 1090
948 for (j = 0; j < nb_sorted_segments; j++) {1091 for (j = 0; j < nb_sorted_segments; j++) {
949 int n_delta = i;
950 int duration, sample_duration = 1, last_sample_size = 0;1092 int duration, sample_duration = 1, last_sample_size = 0;
951 int64_t segment_size;1093 int64_t segment_size;
952 MXFIndexTableSegment *tableseg = sorted_segments[j];1094 MXFIndexTableSegment *tableseg = sorted_segments[j];
953 1095
954 /* reset accumulated_offset on BodySID change */
955 if (j > 0 && tableseg->body_sid != sorted_segments[j-1]->body_sid)
956 accumulated_offset = 0;
957
958 /* HACK: How to correctly link between streams and slices? */
959 if (i < mxf->system_item + st->index)
960 n_delta++;
961 if (n_delta >= tableseg->nb_delta_entries && st->index != 0)1096 if (n_delta >= tableseg->nb_delta_entries && st->index != 0)
962 continue;1097 continue;
963 duration = tableseg->index_duration > 0 ? tableseg->index_duration :1098 duration = tableseg->index_duration > 0 ? tableseg->index_duration :
@@ -1003,7 +1138,7 @@ static int mxf_parse_index(MXFContext *mxf, int i, AVStream *st) · 39 unmodified lines
1003 size = 0;1138 size = 0;
1004 flags = !(tableseg->flag_entries[k] & 0x30) ? AVINDEX_KEYFRAME : 0;1139 flags = !(tableseg->flag_entries[k] & 0x30) ? AVINDEX_KEYFRAME : 0;
1005 } else {1140 } else {
1006 pos = (int64_t)k * tableseg->edit_unit_byte_count + accumulated_offset;1141 pos = (int64_t)(tableseg->index_start_position + k) * tableseg->edit_unit_byte_count;
1007 if (n_delta < tableseg->nb_delta_entries - 1)1142 if (n_delta < tableseg->nb_delta_entries - 1)
1008 size = tableseg->element_delta[n_delta+1] - tableseg->element_delta[n_delta];1143 size = tableseg->element_delta[n_delta+1] - tableseg->element_delta[n_delta];
1009 else {1144 else {
@@ -1020,18 +1155,17 @@ static int mxf_parse_index(MXFContext *mxf, int i, AVStream *st) · 10 unmodified lines
1020 flags = AVINDEX_KEYFRAME;1155 flags = AVINDEX_KEYFRAME;
1021 }1156 }
1022 1157
1023 if (k > 0 && pos < mxf->first_essence_length && accumulated_offset == 0)1158 if (mxf_absolute_bodysid_offset(mxf, tableseg->body_sid, pos, &pos) < 0) {
1024 pos += mxf->first_essence_kl_length;1159 /* probably partial file - no point going further for this stream */
1025 1160 break;
1026 pos += mxf->essence_offset;1161 }
1027 1162
1028 av_dlog(mxf->fc, "Stream %d IndexEntry %d n_Delta %d Offset %"PRIx64" Timestamp %"PRId64"\n",1163 av_dlog(mxf->fc, "Stream %d IndexEntry %d TrackID %d Offset %"PRIx64" Timestamp %"PRId64"\n",
1029 st->index, st->nb_index_entries, n_delta, pos, sample_duration * st->nb_index_entries);1164 st->index, st->nb_index_entries, track_id, pos, sample_duration * st->nb_index_entries);
1030 1165
1031 if ((ret = av_add_index_entry(st, pos, sample_duration * st->nb_index_entries, size, 0, flags)) < 0)1166 if ((ret = av_add_index_entry(st, pos, sample_duration * st->nb_index_entries, size, 0, flags)) < 0)
1032 return ret;1167 return ret;
1033 }1168 }
1034 accumulated_offset += segment_size;
1035 }1169 }
1036 1170
1037 av_free(sorted_segments);1171 av_free(sorted_segments);
@@ -1095,7 +1229,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) · 57 unmodified lines
1095 }1229 }
1096 }1230 }
1097 if (!source_package) {1231 if (!source_package) {
1098 av_log(mxf->fc, AV_LOG_ERROR, "material track %d: no corresponding source package found\n", material_track->track_id);1232 av_dlog(mxf->fc, "material track %d: no corresponding source package found\n", material_track->track_id);
1099 break;1233 break;
1100 }1234 }
1101 for (k = 0; k < source_package->tracks_count; k++) {1235 for (k = 0; k < source_package->tracks_count; k++) {
@@ -1116,6 +1250,18 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) · 14 unmodified lines
1116 if (!source_track)1250 if (!source_track)
1117 continue;1251 continue;
1118 1252
1253 if (!(source_track->sequence = mxf_resolve_strong_ref(mxf, &source_track->sequence_ref, Sequence))) {
1254 av_log(mxf->fc, AV_LOG_ERROR, "could not resolve source track sequence strong ref\n");
1255 return -1;
1256 }
1257
1258 /* 0001GL00.MXF.A1.mxf_opatom.mxf has the same SourcePackageID as 0001GL.MXF.V1.mxf_opatom.mxf
1259 * This would result in both files appearing to have two streams. Work around this by sanity checking DataDefinition */
1260 if (memcmp(material_track->sequence->data_definition_ul, source_track->sequence->data_definition_ul, 16)) {
1261 av_log(mxf->fc, AV_LOG_ERROR, "material track %d: DataDefinition mismatch\n", material_track->track_id);
1262 continue;
1263 }
1264
1119 st = avformat_new_stream(mxf->fc, NULL);1265 st = avformat_new_stream(mxf->fc, NULL);
1120 if (!st) {1266 if (!st) {
1121 av_log(mxf->fc, AV_LOG_ERROR, "could not allocate stream\n");1267 av_log(mxf->fc, AV_LOG_ERROR, "could not allocate stream\n");
@@ -1129,11 +1275,6 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) · 7 unmodified lines
1129 st->start_time = component->start_position;1275 st->start_time = component->start_position;
1130 avpriv_set_pts_info(st, 64, material_track->edit_rate.num, material_track->edit_rate.den);1276 avpriv_set_pts_info(st, 64, material_track->edit_rate.num, material_track->edit_rate.den);
1131 1277
1132 if (!(source_track->sequence = mxf_resolve_strong_ref(mxf, &source_track->sequence_ref, Sequence))) {
1133 av_log(mxf->fc, AV_LOG_ERROR, "could not resolve source track sequence strong ref\n");
1134 return -1;
1135 }
1136
1137 PRINT_KEY(mxf->fc, "data definition ul", source_track->sequence->data_definition_ul);1278 PRINT_KEY(mxf->fc, "data definition ul", source_track->sequence->data_definition_ul);
1138 codec_ul = mxf_get_codec_ul(ff_mxf_data_definition_uls, &source_track->sequence->data_definition_ul);1279 codec_ul = mxf_get_codec_ul(ff_mxf_data_definition_uls, &source_track->sequence->data_definition_ul);
1139 st->codec->codec_type = codec_ul->id;1280 st->codec->codec_type = codec_ul->id;
@@ -1175,6 +1316,11 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) · 35 unmodified lines
1175 }1316 }
1176 }1317 }
1177 }1318 }
1319
1320 /* HACK: revert to the old demuxing/seeking scode for D-10 for now */
1321 if (mxf_match_uid(essence_container_ul, mxf_d10_ul, 14))
1322 mxf->d10 = 1;
1323
1178 /* TODO: drop PictureEssenceCoding and SoundEssenceCompression, only check EssenceContainer */1324 /* TODO: drop PictureEssenceCoding and SoundEssenceCompression, only check EssenceContainer */
1179 codec_ul = mxf_get_codec_ul(ff_mxf_codec_uls, &descriptor->essence_codec_ul);1325 codec_ul = mxf_get_codec_ul(ff_mxf_codec_uls, &descriptor->essence_codec_ul);
1180 st->codec->codec_id = codec_ul->id;1326 st->codec->codec_id = codec_ul->id;
@@ -1214,11 +1360,11 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) · 33 unmodified lines
1214 }1360 }
1215 }1361 }
1216 if (st->codec->codec_type != AVMEDIA_TYPE_DATA && (*essence_container_ul)[15] > 0x01) {1362 if (st->codec->codec_type != AVMEDIA_TYPE_DATA && (*essence_container_ul)[15] > 0x01) {
1217 av_log(mxf->fc, AV_LOG_WARNING, "only frame wrapped mappings are correctly supported\n");1363 /* TODO: decode timestamps */
1218 st->need_parsing = AVSTREAM_PARSE_FULL;1364 st->need_parsing = AVSTREAM_PARSE_TIMESTAMPS;
1219 }1365 }
1220 1366
1221 if ((ret = mxf_parse_index(mxf, i, st)))1367 if ((ret = mxf_parse_index(mxf, material_track->track_id, st)))
1222 return ret;1368 return ret;
1223 }1369 }
1224 return 0;1370 return 0;
@@ -1287,7 +1433,7 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadF · 62 unmodified lines
1287 }1433 }
1288 if (ctx_size && tag == 0x3C0A)1434 if (ctx_size && tag == 0x3C0A)
1289 avio_read(pb, ctx->uid, 16);1435 avio_read(pb, ctx->uid, 16);
1290 else if (read_child(ctx, pb, tag, size, uid) < 0)1436 else if (read_child(ctx, pb, tag, size, uid, -1) < 0)
1291 return -1;1437 return -1;
1292 1438
1293 avio_seek(pb, next, SEEK_SET);1439 avio_seek(pb, next, SEEK_SET);
@@ -1296,10 +1442,129 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadF · 2 unmodified lines
1296 return ctx_size ? mxf_add_metadata_set(mxf, ctx) : 0;1442 return ctx_size ? mxf_add_metadata_set(mxf, ctx) : 0;
1297}1443}
1298 1444
1445/**
1446 * Seeks to the previous partition, if possible
1447 * @return <= 0 if we should stop parsing, > 0 if we should keep going
1448 */
1449static int mxf_seek_to_previous_partition(MXFContext *mxf)
1450{
1451 AVIOContext *pb = mxf->fc->pb;
1452
1453 if (!mxf->current_partition ||
1454 mxf->run_in + mxf->current_partition->previous_partition <= mxf->last_forward_tell)
1455 return 0; /* we've parsed all partitions */
1456
1457 /* seek to previous partition */
1458 avio_seek(pb, mxf->run_in + mxf->current_partition->previous_partition, SEEK_SET);
1459 mxf->current_partition = NULL;
1460
1461 av_dlog(mxf->fc, "seeking to previous partition\n");
1462
1463 return 1;
1464}
1465
1466/**
1467 * Called when essence is encountered
1468 * @return <= 0 if we should stop parsing, > 0 if we should keep going
1469 */
1470static int mxf_parse_handle_essence(MXFContext *mxf)
1471{
1472 AVIOContext *pb = mxf->fc->pb;
1473 int64_t ret;
1474
1475 if (!mxf->current_partition) {
1476 av_log(mxf->fc, AV_LOG_ERROR, "found essence prior to PartitionPack\n");
1477 return AVERROR_INVALIDDATA;
1478 }
1479
1480 if (mxf->parsing_backward) {
1481 return mxf_seek_to_previous_partition(mxf);
1482 } else {
1483 if (!mxf->footer_partition) {
1484 av_dlog(mxf->fc, "no footer\n");
1485 return 0;
1486 }
1487
1488 av_dlog(mxf->fc, "seeking to footer\n");
1489
1490 /* remember where we were so we don't end up seeking further back than this */
1491 mxf->last_forward_tell = avio_tell(pb);
1492
1493 if (!pb->seekable) {
1494 av_log(mxf->fc, AV_LOG_INFO, "file is not seekable - not parsing footer\n");
1495 return -1;
1496 }
1497
1498 /* seek to footer partition and parse backward */
1499 if ((ret = avio_seek(pb, mxf->run_in + mxf->footer_partition, SEEK_SET)) < 0) {
1500 av_log(mxf->fc, AV_LOG_ERROR, "failed to seek to footer @ 0x%"PRIx64" (%"PRId64") - partial file?\n",
1501 mxf->run_in + mxf->footer_partition, ret);
1502 return ret;
1503 }
1504
1505 mxf->current_partition = NULL;
1506 mxf->parsing_backward = 1;
1507 }
1508
1509 return 1;
1510}
1511
1512/**
1513 * Called when the next partition or EOF is encountered
1514 * @return <= 0 if we should stop parsing, > 0 if we should keep going
1515 */
1516static int mxf_parse_handle_partition_or_eof(MXFContext *mxf)
1517{
1518 return mxf->parsing_backward ? mxf_seek_to_previous_partition(mxf) : 1;
1519}
1520
1521/**
1522 * Figures out the proper offset and length of the essence container in each partition
1523 */
1524static void mxf_compute_essence_containers(MXFContext *mxf)
1525{
1526 int x;
1527
1528 /* everything is already correct */
1529 if (mxf->op == OPAtom)
1530 return;
1531
1532 for (x = 0; x < mxf->partitions_count; x++) {
1533 MXFPartition *p = &mxf->partitions[x];
1534
1535 if (!p->body_sid)
1536 continue; /* BodySID == 0 -> no essence */
1537
1538 if (x >= mxf->partitions_count - 1)
1539 break; /* last partition - can't compute length (and we don't need to) */
1540
1541 /* essence container spans to the next partition */
1542 p->essence_length = mxf->partitions[x+1].this_partition - p->essence_offset;
1543
1544 if (p->essence_length < 0) {
1545 /* next ThisPartition < essence_offset */
1546 p->essence_length = 0;
1547 av_log(mxf->fc, AV_LOG_ERROR, "partition %i: bad ThisPartition = %lx\n",
1548 x+1, mxf->partitions[x+1].this_partition);
1549 }
1550 }
1551}
1552
1553static int64_t round_to_kag(int64_t position, int kag_size)
1554{
1555 /* TODO: account for run-in? the spec isn't clear whether KAG should account for it */
1556 /* NOTE: kag_size may be any integer between 1 - 2^10 */
1557 int64_t ret = (position / kag_size) * kag_size;
1558 return ret == position ? ret : ret + kag_size;
1559}
1560
1299static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap)1561static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap)
1300{1562{
1301 MXFContext *mxf = s->priv_data;1563 MXFContext *mxf = s->priv_data;
1302 KLVPacket klv;1564 KLVPacket klv;
1565 int64_t essence_offset = 0;
1566
1567 mxf->last_forward_tell = INT64_MAX;
1303 1568
1304 if (!mxf_read_sync(s->pb, mxf_header_partition_pack_key, 14)) {1569 if (!mxf_read_sync(s->pb, mxf_header_partition_pack_key, 14)) {
1305 av_log(s, AV_LOG_ERROR, "could not find header partition pack key\n");1570 av_log(s, AV_LOG_ERROR, "could not find header partition pack key\n");
@@ -1307,23 +1572,60 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) · 1 unmodified line
1307 }1572 }
1308 avio_seek(s->pb, -14, SEEK_CUR);1573 avio_seek(s->pb, -14, SEEK_CUR);
1309 mxf->fc = s;1574 mxf->fc = s;
1575 mxf->run_in = avio_tell(s->pb);
1576
1310 while (!url_feof(s->pb)) {1577 while (!url_feof(s->pb)) {
1311 const MXFMetadataReadTableEntry *metadata;1578 const MXFMetadataReadTableEntry *metadata;
1312 1579
1313 if (klv_read_packet(&klv, s->pb) < 0)1580 if (klv_read_packet(&klv, s->pb) < 0) {
1314 return -1;1581 /* EOF - seek to previous partition or stop */
1582 if(mxf_parse_handle_partition_or_eof(mxf) <= 0)
1583 break;
1584 else
1585 continue;
1586 }
1587
1315 PRINT_KEY(s, "read header", klv.key);1588 PRINT_KEY(s, "read header", klv.key);
1316 av_dlog(s, "size %"PRIu64" offset %#"PRIx64"\n", klv.length, klv.offset);1589 av_dlog(s, "size %"PRIu64" offset %#"PRIx64"\n", klv.length, klv.offset);
1317 if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key) ||1590 if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key) ||
1318 IS_KLV_KEY(klv.key, mxf_essence_element_key)) {1591 IS_KLV_KEY(klv.key, mxf_essence_element_key) ||
1319 /* FIXME avoid seek */1592 IS_KLV_KEY(klv.key, mxf_system_item_key)) {
1320 avio_seek(s->pb, klv.offset, SEEK_SET);1593 if (!mxf->current_partition->essence_offset) {
1321 break;1594 /* for OP1a we compute essence_offset
1322 }1595 * for OPAtom we point essence_offset after the KL (usually op1a_essence_offset + 20 or 25)
1323 if (IS_KLV_KEY(klv.key, mxf_system_item_key)) {1596 * TODO: for OP1a we could eliminate this entire if statement, always stopping parsing at op1a_essence_offset
1324 mxf->system_item = 1;1597 * for OPAtom we still need the actual essence_offset though (the KL's length can vary)
1325 avio_skip(s->pb, klv.length);1598 */
1599 int64_t op1a_essence_offset =
1600 round_to_kag(mxf->current_partition->this_partition +
1601 mxf->current_partition->pack_length, mxf->current_partition->kag_size) +
1602 round_to_kag(mxf->current_partition->header_byte_count, mxf->current_partition->kag_size) +
1603 round_to_kag(mxf->current_partition->index_byte_count, mxf->current_partition->kag_size);
1604
1605 if (mxf->op == OPAtom) {
1606 /* point essence_offset to the actual data
1607 * OPAtom has all the essence in one big KLV
1608 */
1609 mxf->current_partition->essence_offset = avio_tell(s->pb);
1610 mxf->current_partition->essence_length = klv.length;
1611 } else {
1612 /* NOTE: op1a_essence_offset may be less than to klv.offset (C0023S01.mxf) */
1613 mxf->current_partition->essence_offset = op1a_essence_offset;
1614 }
1615 }
1616
1617 if (!essence_offset)
1618 essence_offset = klv.offset;
1619
1620 /* seek to footer, previous partition or stop */
1621 if (mxf_parse_handle_essence(mxf) <= 0)
1622 break;
1326 continue;1623 continue;
1624 } else if (!memcmp(klv.key, mxf_header_partition_pack_key, 13) &&
1625 klv.key[13] >= 2 && klv.key[13] <= 4 && mxf->current_partition) {
1626 /* next partition pack - keep going, seek to previous partition or stop */
1627 if(mxf_parse_handle_partition_or_eof(mxf) <= 0)
1628 break;
1327 }1629 }
1328 1630
1329 for (metadata = mxf_metadata_read_table; metadata->read; metadata++) {1631 for (metadata = mxf_metadata_read_table; metadata->read; metadata++) {
@@ -1333,7 +1635,7 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) · 3 unmodified lines
1333 res = mxf_read_local_tags(mxf, &klv, metadata->read, metadata->ctx_size, metadata->type);1635 res = mxf_read_local_tags(mxf, &klv, metadata->read, metadata->ctx_size, metadata->type);
1334 } else {1636 } else {
1335 uint64_t next = avio_tell(s->pb) + klv.length;1637 uint64_t next = avio_tell(s->pb) + klv.length;
1336 res = metadata->read(mxf, s->pb, 0, 0, klv.key);1638 res = metadata->read(mxf, s->pb, 0, klv.length, klv.key, klv.offset);
1337 avio_seek(s->pb, next, SEEK_SET);1639 avio_seek(s->pb, next, SEEK_SET);
1338 }1640 }
1339 if (res < 0) {1641 if (res < 0) {
@@ -1346,6 +1648,15 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) · 6 unmodified lines
1346 if (!metadata->read)1648 if (!metadata->read)
1347 avio_skip(s->pb, klv.length);1649 avio_skip(s->pb, klv.length);
1348 }1650 }
1651 /* FIXME avoid seek */
1652 if (!essence_offset) {
1653 av_log(s, AV_LOG_ERROR, "no essence\n");
1654 return AVERROR_INVALIDDATA;
1655 }
1656 avio_seek(s->pb, essence_offset, SEEK_SET);
1657
1658 mxf_compute_essence_containers(mxf);
1659
1349 return mxf_parse_structural_metadata(mxf);1660 return mxf_parse_structural_metadata(mxf);
1350}1661}
1351 1662
@@ -1378,6 +1689,7 @@ static int mxf_read_close(AVFormatContext *s) · 26 unmodified lines
1378 av_freep(&seg->slice_offset_entries[j]);1689 av_freep(&seg->slice_offset_entries[j]);
1379 av_freep(&seg->slice);1690 av_freep(&seg->slice);
1380 av_freep(&seg->element_delta);1691 av_freep(&seg->element_delta);
1692 av_freep(&seg->temporal_offset_entries);
1381 av_freep(&seg->flag_entries);1693 av_freep(&seg->flag_entries);
1382 av_freep(&seg->stream_offset_entries);1694 av_freep(&seg->stream_offset_entries);
1383 av_freep(&seg->slice_offset_entries);1695 av_freep(&seg->slice_offset_entries);
@@ -1416,7 +1728,11 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti · 32 unmodified lines
1416{1728{
1417 AVStream *st = s->streams[stream_index];1729 AVStream *st = s->streams[stream_index];
1418 int64_t seconds;1730 int64_t seconds;
1731 MXFContext* mxf = s->priv_data;
1732 int64_t seekpos;
1733 int index;
1419 1734
1735 if (mxf->d10) {
1420 if (!s->bit_rate)1736 if (!s->bit_rate)
1421 return -1;1737 return -1;
1422 if (sample_time < 0)1738 if (sample_time < 0)
@@ -1425,6 +1741,27 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti · 2 unmodified lines
1425 if (avio_seek(s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET) < 0)1741 if (avio_seek(s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET) < 0)
1426 return -1;1742 return -1;
1427 ff_update_cur_dts(s, st, sample_time);1743 ff_update_cur_dts(s, st, sample_time);
1744 } else {
1745 if (st->nb_index_entries <= 0)
1746 return -1;
1747
1748 index = av_index_search_timestamp(st, sample_time, flags);
1749
1750 av_dlog(s, "stream %d, timestamp %"PRId64", sample %d\n", st->index, sample_time, index);
1751
1752 if (index < 0) {
1753 if (sample_time < st->index_entries[0].timestamp)
1754 index = 0;
1755 else
1756 return -1;
1757 }
1758
1759 seekpos = st->index_entries[index].pos;
1760 av_update_cur_dts(s, st, st->index_entries[index].timestamp);
1761 mxf->current_edit_unit = st->index_entries[index].timestamp;
1762 mxf->current_stream = 0;
1763 avio_seek(s->pb, seekpos, SEEK_SET);
1764 }
1428 return 0;1765 return 0;
1429}1766}
1430 1767
tests/ref/seek/lavf_mxf+18−23
@@ -2,52 +2,47 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801 · 1 unmodified line
2ret: 0 st:-1 flags:0 ts:-1.0000002ret: 0 st:-1 flags:0 ts:-1.000000
3ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 248013ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801
4ret: 0 st:-1 flags:1 ts: 1.8941674ret: 0 st:-1 flags:1 ts: 1.894167
5ret:-15ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712
6ret: 0 st: 0 flags:0 ts: 0.8000006ret: 0 st: 0 flags:0 ts: 0.800000
7ret:-17ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712
8ret: 0 st: 0 flags:1 ts:-0.3200008ret: 0 st: 0 flags:1 ts:-0.320000
9ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 248019ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801
10ret: 0 st: 1 flags:0 ts: 2.56000010ret:-1 st: 1 flags:0 ts: 2.560000
11ret:-1
12ret: 0 st: 1 flags:1 ts: 1.48000011ret: 0 st: 1 flags:1 ts: 1.480000
13ret:-112ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712
14ret: 0 st:-1 flags:0 ts: 0.36500213ret: 0 st:-1 flags:0 ts: 0.365002
15ret: 0 st: 0 flags:1 dts: 0.360000 pts: NOPTS pos: 6144 size: 2480114ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 211968 size: 24787
16ret: 0 st:-1 flags:1 ts:-0.74083115ret: 0 st:-1 flags:1 ts:-0.740831
17ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 2480116ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801
18ret: 0 st: 0 flags:0 ts: 2.16000017ret:-1 st: 0 flags:0 ts: 2.160000
19ret:-1
20ret: 0 st: 0 flags:1 ts: 1.04000018ret: 0 st: 0 flags:1 ts: 1.040000
21ret:-119ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712
22ret: 0 st: 1 flags:0 ts:-0.04000020ret: 0 st: 1 flags:0 ts:-0.040000
23ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 2480121ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801
24ret: 0 st: 1 flags:1 ts: 2.84000022ret: 0 st: 1 flags:1 ts: 2.840000
25ret:-123ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712
26ret: 0 st:-1 flags:0 ts: 1.73000424ret:-1 st:-1 flags:0 ts: 1.730004
27ret:-1
28ret: 0 st:-1 flags:1 ts: 0.62417125ret: 0 st:-1 flags:1 ts: 0.624171
29ret:-126ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 211968 size: 24787
30ret: 0 st: 0 flags:0 ts:-0.48000027ret: 0 st: 0 flags:0 ts:-0.480000
31ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 2480128ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801
32ret: 0 st: 0 flags:1 ts: 2.40000029ret: 0 st: 0 flags:1 ts: 2.400000
33ret:-130ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712
34ret: 0 st: 1 flags:0 ts: 1.32000031ret:-1 st: 1 flags:0 ts: 1.320000
35ret:-1
36ret: 0 st: 1 flags:1 ts: 0.20000032ret: 0 st: 1 flags:1 ts: 0.200000
37ret: 0 st: 0 flags:1 dts: 0.200000 pts: NOPTS pos: 6144 size: 2480133ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801
38ret: 0 st:-1 flags:0 ts:-0.90499434ret: 0 st:-1 flags:0 ts:-0.904994
39ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 2480135ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801
40ret: 0 st:-1 flags:1 ts: 1.98917336ret: 0 st:-1 flags:1 ts: 1.989173
41ret:-137ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712
42ret: 0 st: 0 flags:0 ts: 0.88000038ret: 0 st: 0 flags:0 ts: 0.880000
43ret:-139ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712
44ret: 0 st: 0 flags:1 ts:-0.24000040ret: 0 st: 0 flags:1 ts:-0.240000
45ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 2480141ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801
46ret: 0 st: 1 flags:0 ts: 2.68000042ret:-1 st: 1 flags:0 ts: 2.680000
47ret:-1
48ret: 0 st: 1 flags:1 ts: 1.56000043ret: 0 st: 1 flags:1 ts: 1.560000
49ret:-144ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712
50ret: 0 st:-1 flags:0 ts: 0.46000845ret: 0 st:-1 flags:0 ts: 0.460008
51ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 6144 size: 2480146ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 460800 size: 24712
52ret: 0 st:-1 flags:1 ts:-0.64582547ret: 0 st:-1 flags:1 ts:-0.645825
53ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 2480148ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 6144 size: 24801

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t