static int mxf_parse_index(MXFContext *mxf, int track_id, AVStream *st) { int64_t accumulated_offset = 0; int j, k, ret, nb_sorted_segments; MXFIndexTableSegment **sorted_segments; int n_delta = track_id - 1; /* TrackID = 1-based stream index */ if (track_id < 1) { av_log(mxf->fc, AV_LOG_ERROR, "TrackID not positive: %i\n", track_id); return AVERROR_INVALIDDATA; } if ((ret = mxf_get_sorted_table_segments(mxf, &nb_sorted_segments, &sorted_segments))) return ret; for (j = 0; j < nb_sorted_segments; j++) { int duration, sample_duration = 1, last_sample_size = 0; int64_t segment_size; MXFIndexTableSegment *tableseg = sorted_segments[j]; /* reset accumulated_offset on BodySID change */ if (j > 0 && tableseg->body_sid != sorted_segments[j-1]->body_sid) accumulated_offset = 0; if (n_delta >= tableseg->nb_delta_entries && st->index != 0) continue; duration = tableseg->index_duration > 0 ? tableseg->index_duration : st->duration - st->nb_index_entries; segment_size = tableseg->edit_unit_byte_count * duration; /* check small EditUnitByteCount for audio */ if (tableseg->edit_unit_byte_count && tableseg->edit_unit_byte_count < 32 && !tableseg->index_duration) { /* duration might be prime relative to the new sample_duration, * which means we need to handle the last frame differently */ sample_duration = 8192; last_sample_size = (duration % sample_duration) * tableseg->edit_unit_byte_count; tableseg->edit_unit_byte_count *= sample_duration; duration /= sample_duration; if (last_sample_size) duration++; } for (k = 0; k < duration; k++) { int64_t pos; int size, flags = 0; if (k < tableseg->nb_index_entries) { pos = tableseg->stream_offset_entries[k]; if (n_delta < tableseg->nb_delta_entries) { if (n_delta < tableseg->nb_delta_entries - 1) { size = tableseg->slice_offset_entries[k][tableseg->slice[n_delta+1]-1] + tableseg->element_delta[n_delta+1] - tableseg->element_delta[n_delta]; if (tableseg->slice[n_delta] > 0) size -= tableseg->slice_offset_entries[k][tableseg->slice[n_delta]-1]; } else if (k < duration - 1) { size = tableseg->stream_offset_entries[k+1] - tableseg->stream_offset_entries[k] - tableseg->slice_offset_entries[k][tableseg->slice[tableseg->nb_delta_entries-1]-1] - tableseg->element_delta[tableseg->nb_delta_entries-1]; } else size = 0; if (tableseg->slice[n_delta] > 0) pos += tableseg->slice_offset_entries[k][tableseg->slice[n_delta]-1]; pos += tableseg->element_delta[n_delta]; } else size = 0; flags = !(tableseg->flag_entries[k] & 0x30) ? AVINDEX_KEYFRAME : 0; } else { pos = (int64_t)k * tableseg->edit_unit_byte_count + accumulated_offset; if (n_delta < tableseg->nb_delta_entries - 1) size = tableseg->element_delta[n_delta+1] - tableseg->element_delta[n_delta]; else { /* use smaller size for last sample if we should */ if (last_sample_size && k == duration - 1) size = last_sample_size; else size = tableseg->edit_unit_byte_count; if (tableseg->nb_delta_entries) size -= tableseg->element_delta[tableseg->nb_delta_entries-1]; } if (n_delta < tableseg->nb_delta_entries) pos += tableseg->element_delta[n_delta]; flags = AVINDEX_KEYFRAME; } if (mxf_absolute_bodysid_offset(mxf, tableseg->body_sid, pos, &pos) < 0) { /* probably partial file - no point going further for this stream */ break; } av_dlog(mxf->fc, "Stream %d IndexEntry %d TrackID %d Offset %"PRIx64" Timestamp %"PRId64"\n", st->index, st->nb_index_entries, track_id, pos, sample_duration * st->nb_index_entries); if ((ret = av_add_index_entry(st, pos, sample_duration * st->nb_index_entries, size, 0, flags)) < 0) return ret; } accumulated_offset += segment_size; } av_free(sorted_segments); return 0; }