More AviExtractor tests

This commit is contained in:
Dustin 2022-01-29 14:51:03 -07:00
parent 66c240f1bd
commit 432ff5ea70
5 changed files with 191 additions and 6 deletions

View file

@ -351,7 +351,8 @@ public class AviExtractor implements Extractor {
return RESULT_SEEK;
}
private AviTrack getVideoTrack() {
@VisibleForTesting
AviTrack getVideoTrack() {
for (@Nullable AviTrack aviTrack : aviTracks) {
if (aviTrack != null && aviTrack.isVideo()) {
return aviTrack;
@ -510,7 +511,7 @@ public class AviExtractor implements Extractor {
final AviTrack aviTrack = getAviTrack(chunkId);
if (aviTrack == null) {
seekPosition.position = alignPosition(input.getPosition() + size);
Log.w(TAG, "Unknown tag=" + toString(chunkId) + " pos=" + (input.getPosition() - 8)
w("Unknown tag=" + toString(chunkId) + " pos=" + (input.getPosition() - 8)
+ " size=" + size + " moviEnd=" + moviEnd);
return RESULT_SEEK;
}
@ -590,6 +591,27 @@ public class AviExtractor implements Extractor {
this.aviTracks = aviTracks;
}
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
void setAviHeader(final AviHeaderBox aviHeaderBox) {
aviHeader = aviHeaderBox;
}
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
void setMovi(final int offset, final int end) {
moviOffset = offset;
moviEnd = end;
}
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
AviTrack getChunkHandler() {
return chunkHandler;
}
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
void setChunkHandler(final AviTrack aviTrack) {
chunkHandler = aviTrack;
}
private static void w(String message) {
try {
Log.w(TAG, message);

View file

@ -1,5 +1,6 @@
package com.google.android.exoplayer2.extractor.avi;
import androidx.annotation.VisibleForTesting;
import java.nio.ByteBuffer;
public class AviHeaderBox extends ResidentBox {
@ -49,4 +50,9 @@ public class AviHeaderBox extends ResidentBox {
// 28 - dwSuggestedBufferSize
// 32 - dwWidth
// 36 - dwHeight
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
void setFlags(int flags) {
byteBuffer.putInt(12, flags);
}
}

View file

@ -1,10 +1,14 @@
package com.google.android.exoplayer2.extractor.avi;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.extractor.Extractor;
import com.google.android.exoplayer2.extractor.ExtractorInput;
import com.google.android.exoplayer2.extractor.PositionHolder;
import com.google.android.exoplayer2.extractor.SeekMap;
import com.google.android.exoplayer2.testutil.FakeExtractorInput;
import com.google.android.exoplayer2.testutil.FakeExtractorOutput;
import com.google.android.exoplayer2.testutil.FakeTrackOutput;
import com.google.android.exoplayer2.util.MimeTypes;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.junit.Assert;
@ -296,4 +300,153 @@ public class AviExtractorTest {
Assert.assertTrue(listBox.getChildren().get(0) instanceof AviHeaderBox);
}
@Test
public void findMovi_givenMoviListAndIndex() throws IOException {
final AviExtractor aviExtractor = new AviExtractor();
aviExtractor.setAviHeader(DataHelper.createAviHeaderBox());
final FakeExtractorOutput fakeExtractorOutput = new FakeExtractorOutput();
aviExtractor.init(fakeExtractorOutput);
ByteBuffer byteBuffer = AviExtractor.allocate(12);
byteBuffer.putInt(ListBox.LIST);
byteBuffer.putInt(64*1024);
byteBuffer.putInt(AviExtractor.MOVI);
final ExtractorInput input = new FakeExtractorInput.Builder().setData(byteBuffer.array()).build();
aviExtractor.findMovi(input, new PositionHolder());
Assert.assertEquals(aviExtractor.state, AviExtractor.STATE_READ_IDX1);
}
@Test
public void findMovi_givenMoviListAndNoIndex() throws IOException {
final AviExtractor aviExtractor = new AviExtractor();
final AviHeaderBox aviHeaderBox = DataHelper.createAviHeaderBox();
aviHeaderBox.setFlags(0);
aviExtractor.setAviHeader(aviHeaderBox);
final FakeExtractorOutput fakeExtractorOutput = new FakeExtractorOutput();
aviExtractor.init(fakeExtractorOutput);
ByteBuffer byteBuffer = AviExtractor.allocate(12);
byteBuffer.putInt(ListBox.LIST);
byteBuffer.putInt(64*1024);
byteBuffer.putInt(AviExtractor.MOVI);
final ExtractorInput input = new FakeExtractorInput.Builder().setData(byteBuffer.array()).build();
aviExtractor.state = AviExtractor.STATE_FIND_MOVI;
aviExtractor.read(input, new PositionHolder());
Assert.assertEquals(aviExtractor.state, AviExtractor.STATE_READ_TRACKS);
Assert.assertTrue(fakeExtractorOutput.seekMap instanceof SeekMap.Unseekable);
}
@Test
public void findMovi_givenJunk() throws IOException {
final AviExtractor aviExtractor = new AviExtractor();
aviExtractor.setAviHeader(DataHelper.createAviHeaderBox());
final FakeExtractorOutput fakeExtractorOutput = new FakeExtractorOutput();
aviExtractor.init(fakeExtractorOutput);
ByteBuffer byteBuffer = AviExtractor.allocate(12);
byteBuffer.putInt(AviExtractor.JUNK);
byteBuffer.putInt(64*1024);
final ExtractorInput input = new FakeExtractorInput.Builder().setData(byteBuffer.array()).build();
final PositionHolder positionHolder = new PositionHolder();
aviExtractor.findMovi(input, positionHolder);
Assert.assertEquals(64 * 1024 + 8, positionHolder.position);
}
private AviExtractor setupReadSamples() {
final AviExtractor aviExtractor = new AviExtractor();
aviExtractor.setAviHeader(DataHelper.createAviHeaderBox());
final FakeExtractorOutput fakeExtractorOutput = new FakeExtractorOutput();
aviExtractor.init(fakeExtractorOutput);
final AviTrack aviTrack = DataHelper.getVideoAviTrack(9);
aviExtractor.setAviTracks(new AviTrack[]{aviTrack});
final Format format = new Format.Builder().setSampleMimeType(MimeTypes.VIDEO_MP4V).build();
aviTrack.trackOutput.format(format);
aviExtractor.state = AviExtractor.STATE_READ_SAMPLES;
aviExtractor.setMovi(DataHelper.MOVI_OFFSET, 128*1024);
return aviExtractor;
}
@Test
public void readSamples_givenAtEndOfInput() throws IOException {
AviExtractor aviExtractor = setupReadSamples();
aviExtractor.setMovi(0, 0);
final AviTrack aviTrack = aviExtractor.getVideoTrack();
final ByteBuffer byteBuffer = AviExtractor.allocate(32);
byteBuffer.putInt(aviTrack.chunkId);
byteBuffer.putInt(24);
final ExtractorInput input = new FakeExtractorInput.Builder().setData(byteBuffer.array()).build();
Assert.assertEquals(Extractor.RESULT_END_OF_INPUT, aviExtractor.read(input, new PositionHolder()));
}
@Test
public void readSamples_completeChunk() throws IOException {
AviExtractor aviExtractor = setupReadSamples();
final AviTrack aviTrack = aviExtractor.getVideoTrack();
final ByteBuffer byteBuffer = AviExtractor.allocate(32);
byteBuffer.putInt(aviTrack.chunkId);
byteBuffer.putInt(24);
final ExtractorInput input = new FakeExtractorInput.Builder().setData(byteBuffer.array())
.build();
Assert.assertEquals(Extractor.RESULT_CONTINUE, aviExtractor.read(input, new PositionHolder()));
final FakeTrackOutput fakeTrackOutput = (FakeTrackOutput) aviTrack.trackOutput;
Assert.assertEquals(24, fakeTrackOutput.getSampleData(0).length);
}
@Test
public void readSamples_fragmentedChunk() throws IOException {
AviExtractor aviExtractor = setupReadSamples();
final AviTrack aviTrack = aviExtractor.getVideoTrack();
final int size = 24 + 16;
final ByteBuffer byteBuffer = AviExtractor.allocate(32);
byteBuffer.putInt(aviTrack.chunkId);
byteBuffer.putInt(size);
final ExtractorInput chunk0 = new FakeExtractorInput.Builder().setData(byteBuffer.array())
.build();
Assert.assertEquals(Extractor.RESULT_CONTINUE, aviExtractor.read(chunk0, new PositionHolder()));
final ExtractorInput chunk1 = new FakeExtractorInput.Builder().setData(new byte[16])
.build();
Assert.assertEquals(Extractor.RESULT_CONTINUE, aviExtractor.read(chunk1, new PositionHolder()));
final FakeTrackOutput fakeTrackOutput = (FakeTrackOutput) aviTrack.trackOutput;
Assert.assertEquals(size, fakeTrackOutput.getSampleData(0).length);
}
@Test
public void seek_givenPosition0() throws IOException {
final AviExtractor aviExtractor = setupReadSamples();
final AviTrack aviTrack = aviExtractor.getVideoTrack();
aviExtractor.setChunkHandler(aviTrack);
aviTrack.getClock().setIndex(10);
aviExtractor.seek(0L, 0L);
Assert.assertNull(aviExtractor.getChunkHandler());
Assert.assertEquals(0, aviTrack.getClock().getIndex());
Assert.assertEquals(aviExtractor.state, AviExtractor.STATE_SEEK_START);
final ExtractorInput input = new FakeExtractorInput.Builder().setData(new byte[0]).build();
final PositionHolder positionHolder = new PositionHolder();
Assert.assertEquals(Extractor.RESULT_SEEK, aviExtractor.read(input, positionHolder));
Assert.assertEquals(DataHelper.MOVI_OFFSET + 4, positionHolder.position);
}
@Test
public void seek_givenKeyFrame() throws IOException {
final AviExtractor aviExtractor = setupReadSamples();
final AviSeekMap aviSeekMap = DataHelper.getAviSeekMap();
aviExtractor.aviSeekMap = aviSeekMap;
final AviTrack aviTrack = aviExtractor.getVideoTrack();
final long position = DataHelper.MOVI_OFFSET + aviSeekMap.keyFrameOffsetsDiv2[1] * 2L;
aviExtractor.seek(position, 0L);
Assert.assertEquals(aviSeekMap.seekIndexes[aviTrack.id][1], aviTrack.getClock().getIndex());
}
}

View file

@ -8,9 +8,7 @@ public class AviHeaderBoxTest {
@Test
public void getters() {
final ByteBuffer byteBuffer = DataHelper.createAviHeader();
final AviHeaderBox aviHeaderBox = new AviHeaderBox(AviHeaderBox.AVIH,
byteBuffer.capacity(), byteBuffer);
final AviHeaderBox aviHeaderBox = DataHelper.createAviHeaderBox();
Assert.assertEquals(DataHelper.VIDEO_US, aviHeaderBox.getMicroSecPerFrame());
Assert.assertTrue(aviHeaderBox.hasIndex());
Assert.assertFalse(aviHeaderBox.mustUseIndex());

View file

@ -18,6 +18,7 @@ public class DataHelper {
static final int VIDEO_SIZE = 4096;
static final int AUDIO_SIZE = 256;
static final int AUDIO_ID = 1;
static final int MOVI_OFFSET = 4096;
private static final long AUDIO_US = VIDEO_US / AUDIO_PER_VIDEO;
//Base path "\ExoPlayer\library\extractor\."
@ -124,7 +125,7 @@ public class DataHelper {
audioArray.add(0);
audioArray.add(128);
return new AviSeekMap(0, 100L, 8, keyFrameOffsetsDiv2,
new UnboundedIntArray[]{videoArray, audioArray}, 4096);
new UnboundedIntArray[]{videoArray, audioArray}, MOVI_OFFSET);
}
private static void putIndex(final ByteBuffer byteBuffer, int chunkId, int flags, int offset,
@ -186,4 +187,9 @@ public class DataHelper {
byteBuffer.clear();
return byteBuffer;
}
public static AviHeaderBox createAviHeaderBox() {
final ByteBuffer byteBuffer = createAviHeader();
return new AviHeaderBox(AviHeaderBox.AVIH, byteBuffer.capacity(), byteBuffer);
}
}