Add work-around for muxer bug where idx1 offset is from 0, not "movi"

location
This commit is contained in:
Dustin 2022-01-31 04:48:57 -07:00
parent 0ff238df99
commit 9bd93ad98e
3 changed files with 20 additions and 7 deletions

View File

@ -399,6 +399,14 @@ public class AviExtractor implements Extractor {
w("No video track found"); w("No video track found");
return; return;
} }
if (remaining < 16) {
output.seekMap(new SeekMap.Unseekable(getDuration()));
w("Index too short");
return;
}
final ByteBuffer firstEntry = AviExtractor.allocate(16);
input.peekFully(firstEntry.array(), 0, 16);
final int videoId = videoTrack.id; final int videoId = videoTrack.id;
final ByteBuffer indexByteBuffer = allocate(Math.min(remaining, 64 * 1024)); final ByteBuffer indexByteBuffer = allocate(Math.min(remaining, 64 * 1024));
final byte[] bytes = indexByteBuffer.array(); final byte[] bytes = indexByteBuffer.array();
@ -466,8 +474,10 @@ public class AviExtractor implements Extractor {
videoTrack.setKeyFrames(seekIndexes[videoId].getArray()); videoTrack.setKeyFrames(seekIndexes[videoId].getArray());
} }
//Work-around a bug where the offset is from the start of the file, not "movi"
final long seekOffset = firstEntry.getInt(8) > moviOffset ? 0L : moviOffset;
final AviSeekMap seekMap = new AviSeekMap(videoId, videoTrack.clock.durationUs, videoTrack.chunks, final AviSeekMap seekMap = new AviSeekMap(videoId, videoTrack.clock.durationUs, videoTrack.chunks,
keyFrameOffsetsDiv2.getArray(), seekIndexes, moviOffset); keyFrameOffsetsDiv2.getArray(), seekIndexes, seekOffset);
i("Video chunks=" + videoTrack.chunks + " us=" + seekMap.getDurationUs()); i("Video chunks=" + videoTrack.chunks + " us=" + seekMap.getDurationUs());

View File

@ -14,10 +14,13 @@ public class AviSeekMap implements SeekMap {
final int[] keyFrameOffsetsDiv2; final int[] keyFrameOffsetsDiv2;
//Seek chunk indexes by streamId //Seek chunk indexes by streamId
final int[][] seekIndexes; final int[][] seekIndexes;
final long moviOffset; /**
* Usually the same as moviOffset, but sometimes 0 (muxer bug)
*/
final long seekOffset;
public AviSeekMap(int videoId, long usDuration, int videoChunks, int[] keyFrameOffsetsDiv2, public AviSeekMap(int videoId, long usDuration, int videoChunks, int[] keyFrameOffsetsDiv2,
UnboundedIntArray[] seekIndexes, long moviOffset) { UnboundedIntArray[] seekIndexes, long seekOffset) {
this.videoId = videoId; this.videoId = videoId;
this.videoUsPerChunk = usDuration / videoChunks; this.videoUsPerChunk = usDuration / videoChunks;
this.duration = usDuration; this.duration = usDuration;
@ -26,7 +29,7 @@ public class AviSeekMap implements SeekMap {
for (int i=0;i<seekIndexes.length;i++) { for (int i=0;i<seekIndexes.length;i++) {
this.seekIndexes[i] = seekIndexes[i].getArray(); this.seekIndexes[i] = seekIndexes[i].getArray();
} }
this.moviOffset = moviOffset; this.seekOffset = seekOffset;
} }
@Override @Override
@ -56,7 +59,7 @@ public class AviSeekMap implements SeekMap {
private SeekPoint getSeekPoint(int index) { private SeekPoint getSeekPoint(int index) {
long offset = keyFrameOffsetsDiv2[index] * 2L; long offset = keyFrameOffsetsDiv2[index] * 2L;
final long outUs = seekIndexes[videoId][index] * videoUsPerChunk; final long outUs = seekIndexes[videoId][index] * videoUsPerChunk;
final long position = offset + moviOffset; final long position = offset + seekOffset;
return new SeekPoint(outUs, position); return new SeekPoint(outUs, position);
} }
@ -78,7 +81,7 @@ public class AviSeekMap implements SeekMap {
} }
public void setFrames(final long position, final long timeUs, final AviTrack[] aviTracks) { public void setFrames(final long position, final long timeUs, final AviTrack[] aviTracks) {
final int index = Arrays.binarySearch(keyFrameOffsetsDiv2, (int)((position - moviOffset) / 2)); final int index = Arrays.binarySearch(keyFrameOffsetsDiv2, (int)((position - seekOffset) / 2));
if (index < 0) { if (index < 0) {
throw new IllegalArgumentException("Position: " + position); throw new IllegalArgumentException("Position: " + position);

View File

@ -9,7 +9,7 @@ public class AviSeekMapTest {
@Test @Test
public void setFrames_givenExactSeekPointMatch() { public void setFrames_givenExactSeekPointMatch() {
final AviSeekMap aviSeekMap = DataHelper.getAviSeekMap(); final AviSeekMap aviSeekMap = DataHelper.getAviSeekMap();
final long position = aviSeekMap.keyFrameOffsetsDiv2[1] * 2L + aviSeekMap.moviOffset; final long position = aviSeekMap.keyFrameOffsetsDiv2[1] * 2L + aviSeekMap.seekOffset;
final int secs = 4; final int secs = 4;
final AviTrack[] aviTracks = new AviTrack[]{DataHelper.getVideoAviTrack(secs), final AviTrack[] aviTracks = new AviTrack[]{DataHelper.getVideoAviTrack(secs),
DataHelper.getAudioAviTrack(secs)}; DataHelper.getAudioAviTrack(secs)};