Handle AVI containers with no keyframes in index

If there is no keyframe in the index assume that the first chunk has a
keyframe.

PiperOrigin-RevId: 650915467
This commit is contained in:
andrewlewis 2024-07-10 01:48:05 -07:00 committed by Copybara-Service
parent b145a9b35e
commit dcc3e439e2
2 changed files with 24 additions and 17 deletions

View File

@ -411,10 +411,8 @@ public final class AviExtractor implements Extractor {
// We ignore unknown chunk IDs.
continue;
}
if ((flags & AVIIF_KEYFRAME) == AVIIF_KEYFRAME) {
chunkReader.appendKeyFrameToIndex(offset);
}
chunkReader.incrementIndexChunkCount();
chunkReader.appendIndexChunk(
offset, /* isKeyFrame= */ (flags & AVIIF_KEYFRAME) == AVIIF_KEYFRAME);
}
for (ChunkReader chunkReader : chunkReaders) {
chunkReader.compactIndex();

View File

@ -70,17 +70,18 @@ import java.util.Arrays;
private int indexChunkCount;
private int indexSize;
private long firstIndexChunkOffset;
private long[] keyFrameOffsets;
private int[] keyFrameIndices;
public ChunkReader(
int id,
@C.TrackType int trackType,
long durationnUs,
long durationUs,
int streamHeaderChunkCount,
TrackOutput trackOutput) {
Assertions.checkArgument(trackType == C.TRACK_TYPE_AUDIO || trackType == C.TRACK_TYPE_VIDEO);
this.durationUs = durationnUs;
this.durationUs = durationUs;
this.streamHeaderChunkCount = streamHeaderChunkCount;
this.trackOutput = trackOutput;
@ChunkType
@ -89,18 +90,25 @@ import java.util.Arrays;
chunkId = getChunkIdFourCc(id, chunkType);
alternativeChunkId =
trackType == C.TRACK_TYPE_VIDEO ? getChunkIdFourCc(id, CHUNK_TYPE_VIDEO_UNCOMPRESSED) : -1;
firstIndexChunkOffset = C.INDEX_UNSET;
keyFrameOffsets = new long[INITIAL_INDEX_SIZE];
keyFrameIndices = new int[INITIAL_INDEX_SIZE];
}
public void appendKeyFrameToIndex(long offset) {
if (indexSize == keyFrameIndices.length) {
keyFrameOffsets = Arrays.copyOf(keyFrameOffsets, keyFrameOffsets.length * 3 / 2);
keyFrameIndices = Arrays.copyOf(keyFrameIndices, keyFrameIndices.length * 3 / 2);
public void appendIndexChunk(long offset, boolean isKeyFrame) {
if (firstIndexChunkOffset == C.INDEX_UNSET) {
firstIndexChunkOffset = offset;
}
keyFrameOffsets[indexSize] = offset;
keyFrameIndices[indexSize] = indexChunkCount;
indexSize++;
if (isKeyFrame) {
if (indexSize == keyFrameIndices.length) {
keyFrameOffsets = Arrays.copyOf(keyFrameOffsets, keyFrameOffsets.length * 3 / 2);
keyFrameIndices = Arrays.copyOf(keyFrameIndices, keyFrameIndices.length * 3 / 2);
}
keyFrameOffsets[indexSize] = offset;
keyFrameIndices[indexSize] = indexChunkCount;
indexSize++;
}
indexChunkCount++;
}
public void advanceCurrentChunk() {
@ -115,10 +123,6 @@ import java.util.Arrays;
return getChunkTimestampUs(/* chunkIndex= */ 1);
}
public void incrementIndexChunkCount() {
indexChunkCount++;
}
public void compactIndex() {
keyFrameOffsets = Arrays.copyOf(keyFrameOffsets, indexSize);
keyFrameIndices = Arrays.copyOf(keyFrameIndices, indexSize);
@ -180,6 +184,11 @@ import java.util.Arrays;
}
public SeekMap.SeekPoints getSeekPoints(long timeUs) {
if (indexSize == 0) {
// Return the offset of the first chunk as there are no keyframes in the index.
return new SeekMap.SeekPoints(
new SeekPoint(/* timeUs= */ 0, /* position= */ firstIndexChunkOffset));
}
int targetFrameIndex = (int) (timeUs / getFrameDurationUs());
int keyFrameIndex =
Util.binarySearchFloor(