mirror of
https://github.com/androidx/media.git
synced 2025-05-04 14:10:40 +08:00
Tests for Mp4vAviTrack and StreamHeaderBox
This commit is contained in:
parent
3ce652ead2
commit
c4cf876ddb
@ -19,7 +19,11 @@ android {
|
||||
testCoverageEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
testOptions{
|
||||
unitTests.all {
|
||||
jvmArgs '-noverify'
|
||||
}
|
||||
}
|
||||
sourceSets.test.assets.srcDir '../../testdata/src/test/assets/'
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.google.android.exoplayer2.extractor.avi;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
@ -13,7 +15,7 @@ public class Mp4vAviTrack extends AviTrack {
|
||||
private static final float[] ASPECT_RATIO = {0f, 1f, 12f/11f, 10f/11f, 16f/11f, 40f/33f};
|
||||
private static final int Extended_PAR = 0xf;
|
||||
private final Format.Builder formatBuilder;
|
||||
private float pixelWidthHeightRatio = 1f;
|
||||
float pixelWidthHeightRatio = 1f;
|
||||
|
||||
Mp4vAviTrack(int id, @NonNull StreamHeaderBox streamHeaderBox, @NonNull TrackOutput trackOutput,
|
||||
@NonNull Format.Builder formatBuilder) {
|
||||
@ -21,8 +23,8 @@ public class Mp4vAviTrack extends AviTrack {
|
||||
this.formatBuilder = formatBuilder;
|
||||
}
|
||||
|
||||
private void processLayerStart(byte[] peek, int offset) {
|
||||
final ParsableNalUnitBitArray in = new ParsableNalUnitBitArray(peek, offset, peek.length);
|
||||
@VisibleForTesting
|
||||
void processLayerStart(@NonNull final ParsableNalUnitBitArray in) {
|
||||
in.skipBit(); // random_accessible_vol
|
||||
in.skipBits(8); // video_object_type_indication
|
||||
boolean is_object_layer_identifier = in.readBit();
|
||||
@ -44,23 +46,35 @@ public class Mp4vAviTrack extends AviTrack {
|
||||
}
|
||||
}
|
||||
|
||||
private void seekLayerStart(ExtractorInput input) throws IOException {
|
||||
byte[] peek = new byte[128];
|
||||
input.peekFully(peek, 0, peek.length);
|
||||
@VisibleForTesting
|
||||
@Nullable
|
||||
static ParsableNalUnitBitArray findLayerStart(ExtractorInput input, final int peekSize)
|
||||
throws IOException {
|
||||
byte[] peek = new byte[peekSize];
|
||||
input.peekFully(peek, 0, peekSize);
|
||||
for (int i = 4;i<peek.length - 4;i++) {
|
||||
if (peek[i] == 0 && peek[i+1] == 0 && peek[i+2] == 1 && (peek[i+3] & 0xf0) == LAYER_START_CODE) {
|
||||
processLayerStart(peek, i+4);
|
||||
break;
|
||||
return new ParsableNalUnitBitArray(peek, i+4, peek.length);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static boolean isSequenceStart(ExtractorInput input) throws IOException {
|
||||
final byte[] peek = new byte[4];
|
||||
input.peekFully(peek, 0, peek.length);
|
||||
return peek[0] == 0 && peek[1] == 0 && peek[2] == 1 && peek[3] == SEQUENCE_START_CODE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean newChunk(int tag, int size, ExtractorInput input) throws IOException {
|
||||
final byte[] peek = new byte[4];
|
||||
input.peekFully(peek, 0, peek.length);
|
||||
if (peek[0] == 0 && peek[1] == 0 && peek[2] == 1 && peek[3] == SEQUENCE_START_CODE) {
|
||||
seekLayerStart(input);
|
||||
if (isSequenceStart(input)) {
|
||||
// -4 because isSequenceStart peeks 4
|
||||
final ParsableNalUnitBitArray layerStart = findLayerStart(input, Math.min(size - 4, 128));
|
||||
if (layerStart != null) {
|
||||
processLayerStart(layerStart);
|
||||
}
|
||||
}
|
||||
return super.newChunk(tag, size, input);
|
||||
}
|
||||
|
@ -11,10 +11,12 @@ public class StreamHeaderBox extends ResidentBox {
|
||||
public static final int STRH = 's' | ('t' << 8) | ('r' << 16) | ('h' << 24);
|
||||
|
||||
//Audio Stream
|
||||
private static final int AUDS = 'a' | ('u' << 8) | ('d' << 16) | ('s' << 24);
|
||||
static final int AUDS = 'a' | ('u' << 8) | ('d' << 16) | ('s' << 24);
|
||||
|
||||
//Videos Stream
|
||||
private static final int VIDS = 'v' | ('i' << 8) | ('d' << 16) | ('s' << 24);
|
||||
static final int VIDS = 'v' | ('i' << 8) | ('d' << 16) | ('s' << 24);
|
||||
|
||||
static final int XVID = 'X' | ('V' << 8) | ('I' << 16) | ('D' << 24);
|
||||
|
||||
private static final SparseArray<String> STREAM_MAP = new SparseArray<>();
|
||||
|
||||
@ -30,7 +32,7 @@ public class StreamHeaderBox extends ResidentBox {
|
||||
STREAM_MAP.put('A' | ('V' << 8) | ('C' << 16) | ('1' << 24), MimeTypes.VIDEO_H264);
|
||||
STREAM_MAP.put('3' | ('V' << 8) | ('I' << 16) | ('D' << 24), mimeType);
|
||||
STREAM_MAP.put('x' | ('v' << 8) | ('i' << 16) | ('d' << 24), mimeType);
|
||||
STREAM_MAP.put('X' | ('V' << 8) | ('I' << 16) | ('D' << 24), mimeType);
|
||||
STREAM_MAP.put(XVID, mimeType);
|
||||
STREAM_MAP.put('D' | ('X' << 8) | ('5' << 16) | ('0' << 24), mimeType);
|
||||
|
||||
STREAM_MAP.put('m' | ('j' << 8) | ('p' << 16) | ('g' << 24), MimeTypes.VIDEO_JPEG);
|
||||
@ -86,15 +88,17 @@ public class StreamHeaderBox extends ResidentBox {
|
||||
public int getRate() {
|
||||
return byteBuffer.getInt(24);
|
||||
}
|
||||
public int getStart() {
|
||||
return byteBuffer.getInt(28);
|
||||
}
|
||||
// 28 - dwStart
|
||||
// public int getStart() {
|
||||
// return byteBuffer.getInt(28);
|
||||
// }
|
||||
public long getLength() {
|
||||
return byteBuffer.getInt(32) & AviExtractor.UINT_MASK;
|
||||
}
|
||||
//36 - dwSuggestedBufferSize
|
||||
//40 - dwQuality
|
||||
public int getSampleSize() {
|
||||
return byteBuffer.getInt(44);
|
||||
}
|
||||
//44 - dwSampleSize
|
||||
// public int getSampleSize() {
|
||||
// return byteBuffer.getInt(44);
|
||||
// }
|
||||
}
|
||||
|
@ -0,0 +1,32 @@
|
||||
package com.google.android.exoplayer2.extractor.avi;
|
||||
|
||||
import com.google.android.exoplayer2.testutil.FakeExtractorInput;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
public class DataHelper {
|
||||
//Base path "\ExoPlayer\library\extractor\."
|
||||
private static final File RELATIVE_PATH = new File("../../testdata/src/test/assets/extractordumps/avi/");
|
||||
public static FakeExtractorInput getInput(final String fileName) throws IOException {
|
||||
return new FakeExtractorInput.Builder().setData(getBytes(fileName)).build();
|
||||
}
|
||||
|
||||
public static byte[] getBytes(final String fileName) throws IOException {
|
||||
final File file = new File(RELATIVE_PATH, fileName);
|
||||
try (FileInputStream in = new FileInputStream(file)) {
|
||||
final byte[] buffer = new byte[in.available()];
|
||||
in.read(buffer);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
public static StreamHeaderBox getVidsStreamHeader() throws IOException {
|
||||
final byte[] buffer = getBytes("vids_stream_header.dump");
|
||||
final ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
|
||||
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
return new StreamHeaderBox(StreamHeaderBox.STRH, buffer.length, byteBuffer);
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package com.google.android.exoplayer2.extractor.avi;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.testutil.FakeExtractorInput;
|
||||
import com.google.android.exoplayer2.testutil.FakeTrackOutput;
|
||||
import com.google.android.exoplayer2.util.ParsableNalUnitBitArray;
|
||||
import java.io.IOException;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class Mp4vAviTrackTest {
|
||||
|
||||
@Test
|
||||
public void isSequenceStart_givenSequence() throws IOException {
|
||||
final FakeExtractorInput input = DataHelper.getInput("mp4v_sequence.dump");
|
||||
Assert.assertTrue(Mp4vAviTrack.isSequenceStart(input));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findLayerStart_givenSequence() throws IOException {
|
||||
final FakeExtractorInput input = DataHelper.getInput("mp4v_sequence.dump");
|
||||
final ParsableNalUnitBitArray bitArray = Mp4vAviTrack.findLayerStart(input,
|
||||
(int)input.getLength());
|
||||
//Offset 0x12
|
||||
Assert.assertEquals(8, bitArray.readBits(8));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findLayerStart_givenAllZeros() throws IOException {
|
||||
final FakeExtractorInput fakeExtractorInput = new FakeExtractorInput.Builder().
|
||||
setData(new byte[128]).build();
|
||||
Assert.assertNull(Mp4vAviTrack.findLayerStart(fakeExtractorInput, 128));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pixelWidthHeightRatio_givenSequence() throws IOException {
|
||||
final FakeTrackOutput fakeTrackOutput = new FakeTrackOutput(false);
|
||||
final Format.Builder formatBuilder = new Format.Builder();
|
||||
final Mp4vAviTrack mp4vAviTrack = new Mp4vAviTrack(0, DataHelper.getVidsStreamHeader(),
|
||||
fakeTrackOutput, formatBuilder);
|
||||
final FakeExtractorInput input = DataHelper.getInput("mp4v_sequence.dump");
|
||||
mp4vAviTrack.newChunk(0, (int)input.getLength(), input);
|
||||
// final ParsableNalUnitBitArray bitArray = Mp4vAviTrack.findLayerStart(input,
|
||||
// (int)input.getLength());
|
||||
// mp4vAviTrack.processLayerStart(bitArray);
|
||||
Assert.assertEquals(mp4vAviTrack.pixelWidthHeightRatio, 1.2121212, 0.01);
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.google.android.exoplayer2.extractor.avi;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import java.io.IOException;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class StreamHeaderBoxTest {
|
||||
private static float FPS24 = 24000f/1001f;
|
||||
private static final long US_SAMPLE24FPS = (long)(1_000_000L / FPS24);
|
||||
|
||||
@Test
|
||||
public void getters_givenXvidStreamHeader() throws IOException {
|
||||
final StreamHeaderBox streamHeaderBox = DataHelper.getVidsStreamHeader();
|
||||
|
||||
Assert.assertTrue(streamHeaderBox.isVideo());
|
||||
Assert.assertFalse(streamHeaderBox.isAudio());
|
||||
Assert.assertEquals(StreamHeaderBox.VIDS, streamHeaderBox.getSteamType());
|
||||
Assert.assertEquals(StreamHeaderBox.XVID, streamHeaderBox.getFourCC());
|
||||
Assert.assertEquals(0, streamHeaderBox.getInitialFrames());
|
||||
Assert.assertEquals(FPS24, streamHeaderBox.getFrameRate(), 0.1);
|
||||
Assert.assertEquals(US_SAMPLE24FPS, streamHeaderBox.getUsPerSample());
|
||||
Assert.assertEquals(MimeTypes.VIDEO_MP4V, streamHeaderBox.getMimeType());
|
||||
Assert.assertEquals(11805L, streamHeaderBox.getLength());
|
||||
}
|
||||
}
|
BIN
testdata/src/test/assets/extractordumps/avi/mp4v_sequence.dump
vendored
Normal file
BIN
testdata/src/test/assets/extractordumps/avi/mp4v_sequence.dump
vendored
Normal file
Binary file not shown.
BIN
testdata/src/test/assets/extractordumps/avi/vids_stream_header.dump
vendored
Normal file
BIN
testdata/src/test/assets/extractordumps/avi/vids_stream_header.dump
vendored
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user