Commit e3285466 by Andrew Lewis

Make reusable fakes for extractor+track outputs.

Improve Mp4Extractor test.

Add support for Xiph lacing in Matroska files.

Add support for EBML lacing in Matroska files.

Handle the initial sticky intent for HDMI audio plug.
parent bc14e87c
......@@ -68,7 +68,12 @@ public final class AudioCapabilitiesReceiver {
@TargetApi(21)
public void register() {
if (receiver != null) {
context.registerReceiver(receiver, new IntentFilter(AudioManager.ACTION_HDMI_AUDIO_PLUG));
Intent initialStickyIntent =
context.registerReceiver(receiver, new IntentFilter(AudioManager.ACTION_HDMI_AUDIO_PLUG));
if (initialStickyIntent != null) {
receiver.onReceive(context, initialStickyIntent);
return;
}
}
listener.onAudioCapabilitiesChanged(DEFAULT_AUDIO_CAPABILITIES);
......@@ -86,6 +91,10 @@ public final class AudioCapabilitiesReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (isInitialStickyBroadcast()) {
return;
}
String action = intent.getAction();
if (!action.equals(AudioManager.ACTION_HDMI_AUDIO_PLUG)) {
return;
......
......@@ -126,7 +126,9 @@ public final class WebmExtractor implements Extractor {
private static final int ID_CUE_CLUSTER_POSITION = 0xF1;
private static final int LACING_NONE = 0;
private static final int LACING_XIPH = 1;
private static final int LACING_FIXED_SIZE = 2;
private static final int LACING_EBML = 3;
private final EbmlReader reader;
private final VarintReader varintReader;
......@@ -168,7 +170,7 @@ public final class WebmExtractor implements Extractor {
private long blockTimeUs;
private int blockLacingSampleIndex;
private int blockLacingSampleCount;
private int blockLacingSampleSize;
private int[] blockLacingSampleSizes;
private int blockTrackNumber;
private int blockTrackNumberLength;
private int blockFlags;
......@@ -600,8 +602,9 @@ public final class WebmExtractor implements Extractor {
int lacing = (scratch.data[2] & 0x06) >> 1;
if (lacing == LACING_NONE) {
blockLacingSampleCount = 1;
blockLacingSampleSize = contentSize - blockTrackNumberLength - 3;
} else if (lacing == LACING_FIXED_SIZE) {
blockLacingSampleSizes = ensureArrayCapacity(blockLacingSampleSizes, 1);
blockLacingSampleSizes[0] = contentSize - blockTrackNumberLength - 3;
} else {
if (id != ID_SIMPLE_BLOCK) {
throw new ParserException("Lacing only supported in SimpleBlocks.");
}
......@@ -609,10 +612,69 @@ public final class WebmExtractor implements Extractor {
// Read the sample count (1 byte).
readScratch(input, 4);
blockLacingSampleCount = (scratch.data[3] & 0xFF) + 1;
blockLacingSampleSize =
(contentSize - blockTrackNumberLength - 4) / blockLacingSampleCount;
} else {
throw new ParserException("Lacing mode not supported: " + lacing);
blockLacingSampleSizes =
ensureArrayCapacity(blockLacingSampleSizes, blockLacingSampleCount);
if (lacing == LACING_FIXED_SIZE) {
int blockLacingSampleSize =
(contentSize - blockTrackNumberLength - 4) / blockLacingSampleCount;
Arrays.fill(blockLacingSampleSizes, 0, blockLacingSampleCount, blockLacingSampleSize);
} else if (lacing == LACING_XIPH) {
int totalSamplesSize = 0;
int headerSize = 4;
for (int sampleIndex = 0; sampleIndex < blockLacingSampleCount - 1; sampleIndex++) {
blockLacingSampleSizes[sampleIndex] = 0;
int byteValue;
do {
readScratch(input, ++headerSize);
byteValue = scratch.data[headerSize - 1] & 0xFF;
blockLacingSampleSizes[sampleIndex] += byteValue;
} while (byteValue == 0xFF);
totalSamplesSize += blockLacingSampleSizes[sampleIndex];
}
blockLacingSampleSizes[blockLacingSampleCount - 1] =
contentSize - blockTrackNumberLength - headerSize - totalSamplesSize;
} else if (lacing == LACING_EBML) {
int totalSamplesSize = 0;
int headerSize = 4;
for (int sampleIndex = 0; sampleIndex < blockLacingSampleCount - 1; sampleIndex++) {
blockLacingSampleSizes[sampleIndex] = 0;
readScratch(input, ++headerSize);
if (scratch.data[headerSize - 1] == 0) {
throw new ParserException("No valid varint length mask found");
}
long readValue = 0;
for (int i = 0; i < 8; i++) {
int lengthMask = 1 << (7 - i);
if ((scratch.data[headerSize - 1] & lengthMask) != 0) {
int readPosition = headerSize - 1;
headerSize += i;
readScratch(input, headerSize);
readValue = (scratch.data[readPosition++] & 0xFF) & ~lengthMask;
while (readPosition < headerSize) {
readValue <<= 8;
readValue |= (scratch.data[readPosition++] & 0xFF);
}
// The first read value is the first size. Later values are signed offsets.
if (sampleIndex > 0) {
readValue -= (1L << 6 + i * 7) - 1;
}
break;
}
}
if (readValue < Integer.MIN_VALUE || readValue > Integer.MAX_VALUE) {
throw new ParserException("EBML lacing sample size out of range.");
}
int intReadValue = (int) readValue;
blockLacingSampleSizes[sampleIndex] = sampleIndex == 0
? intReadValue : blockLacingSampleSizes[sampleIndex - 1] + intReadValue;
totalSamplesSize += blockLacingSampleSizes[sampleIndex];
}
blockLacingSampleSizes[blockLacingSampleCount - 1] =
contentSize - blockTrackNumberLength - headerSize - totalSamplesSize;
} else {
// Lacing is always in the range 0--3.
throw new IllegalStateException("Unexpected lacing value: " + lacing);
}
}
int timecode = (scratch.data[0] << 8) | (scratch.data[1] & 0xFF);
......@@ -629,7 +691,8 @@ public final class WebmExtractor implements Extractor {
if (id == ID_SIMPLE_BLOCK) {
// For SimpleBlock, we have metadata for each sample here.
while (blockLacingSampleIndex < blockLacingSampleCount) {
writeSampleData(input, trackOutput, sampleTrackFormat, blockLacingSampleSize);
writeSampleData(input, trackOutput, sampleTrackFormat,
blockLacingSampleSizes[blockLacingSampleIndex]);
long sampleTimeUs = this.blockTimeUs
+ (blockLacingSampleIndex * sampleTrackFormat.defaultSampleDurationNs) / 1000;
outputSampleMetadata(trackOutput, sampleTimeUs);
......@@ -639,7 +702,7 @@ public final class WebmExtractor implements Extractor {
} else {
// For Block, we send the metadata at the end of the BlockGroup element since we'll know
// if the sample is a keyframe or not only at that point.
writeSampleData(input, trackOutput, sampleTrackFormat, blockLacingSampleSize);
writeSampleData(input, trackOutput, sampleTrackFormat, blockLacingSampleSizes[0]);
}
return;
......@@ -665,6 +728,10 @@ public final class WebmExtractor implements Extractor {
if (scratch.limit() >= requiredLength) {
return;
}
if (scratch.capacity() < requiredLength) {
scratch.reset(Arrays.copyOf(scratch.data, Math.max(scratch.data.length * 2, requiredLength)),
scratch.limit());
}
input.readFully(scratch.data, scratch.limit(), requiredLength - scratch.limit());
scratch.setLimit(requiredLength);
}
......@@ -814,7 +881,7 @@ public final class WebmExtractor implements Extractor {
return TimeUnit.NANOSECONDS.toMicros(unscaledTimecode * timecodeScale);
}
private boolean isCodecSupported(String codecId) {
private static boolean isCodecSupported(String codecId) {
return CODEC_ID_VP8.equals(codecId)
|| CODEC_ID_VP9.equals(codecId)
|| CODEC_ID_H264.equals(codecId)
......@@ -825,6 +892,21 @@ public final class WebmExtractor implements Extractor {
}
/**
* Returns an array that can store (at least) {@code length} elements, which will be either a new
* array or {@code array} if it's not null and large enough.
*/
private static int[] ensureArrayCapacity(int[] array, int length) {
if (array == null) {
return new int[length];
} else if (array.length >= length) {
return array;
} else {
// Double the size to avoid allocating constantly if the required length increases gradually.
return new int[Math.max(array.length * 2, length)];
}
}
/**
* Passes events through to the outer {@link WebmExtractor}.
*/
private final class InnerEbmlReaderOutput implements EbmlReaderOutput {
......
......@@ -15,7 +15,6 @@
*/
package com.google.android.exoplayer.util;
import java.nio.ByteBuffer;
import java.util.Arrays;
/**
......@@ -105,23 +104,6 @@ public final class NalUnitUtil {
}
/**
* Replaces length prefixes of NAL units in {@code buffer} with start code prefixes, within the
* {@code size} bytes preceding the buffer's position.
*/
public static void replaceLengthPrefixesWithAvcStartCodes(ByteBuffer buffer, int size) {
int sampleOffset = buffer.position() - size;
int position = sampleOffset;
while (position < sampleOffset + size) {
buffer.position(position);
int length = readUnsignedIntToInt(buffer);
buffer.position(position);
buffer.put(NAL_START_CODE);
position += length + 4;
}
buffer.position(sampleOffset + size);
}
/**
* Constructs and returns a NAL unit with a start code followed by the data in {@code atom}.
*/
public static byte[] parseChildNalUnit(ParsableByteArray atom) {
......@@ -254,24 +236,6 @@ public final class NalUnitUtil {
return limit;
}
/**
* Reads an unsigned integer into an integer. This method is suitable for use when it can be
* assumed that the top bit will always be set to zero.
*
* @throws IllegalArgumentException If the top bit of the input data is set.
*/
private static int readUnsignedIntToInt(ByteBuffer data) {
int result = 0xFF & data.get();
for (int i = 1; i < 4; i++) {
result <<= 8;
result |= 0xFF & data.get();
}
if (result < 0) {
throw new IllegalArgumentException("Top bit not zero: " + result);
}
return result;
}
private NalUnitUtil() {
// Prevent instantiation.
}
......
......@@ -37,7 +37,7 @@ import com.google.android.exoplayer.dash.mpd.SegmentBase.SegmentTemplate;
import com.google.android.exoplayer.dash.mpd.SegmentBase.SegmentTimelineElement;
import com.google.android.exoplayer.dash.mpd.SegmentBase.SingleSegmentBase;
import com.google.android.exoplayer.dash.mpd.UrlTemplate;
import com.google.android.exoplayer.testutil.Util;
import com.google.android.exoplayer.testutil.TestUtil;
import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.util.FakeClock;
import com.google.android.exoplayer.util.ManifestFetcher;
......@@ -86,7 +86,7 @@ public class DashChunkSourceTest extends InstrumentationTestCase {
@Override
public void setUp() throws Exception {
Util.setUpMockito(this);
TestUtil.setUpMockito(this);
}
public void testMaxVideoDimensions() {
......
......@@ -24,7 +24,7 @@ import com.google.android.exoplayer.extractor.DefaultExtractorInput;
import com.google.android.exoplayer.extractor.ExtractorInput;
import com.google.android.exoplayer.extractor.TrackOutput;
import com.google.android.exoplayer.testutil.FakeDataSource;
import com.google.android.exoplayer.testutil.Util;
import com.google.android.exoplayer.testutil.TestUtil;
import com.google.android.exoplayer.upstream.DataSpec;
import com.google.android.exoplayer.util.ParsableByteArray;
......@@ -52,7 +52,7 @@ public class BufferingInputTest extends InstrumentationTestCase {
@Override
public void setUp() throws Exception {
Util.setUpMockito(this);
TestUtil.setUpMockito(this);
FakeDataSource.Builder builder = new FakeDataSource.Builder();
builder.appendReadData(STREAM_DATA);
......
......@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer.extractor.webm;
import com.google.android.exoplayer.testutil.TestUtil;
import com.google.android.exoplayer.util.Assertions;
import java.nio.ByteBuffer;
......@@ -47,28 +48,6 @@ import java.util.List;
}
public static byte[] createByteArray(int... intArray) {
byte[] byteArray = new byte[intArray.length];
for (int i = 0; i < byteArray.length; i++) {
byteArray[i] = (byte) intArray[i];
}
return byteArray;
}
public static byte[] joinByteArrays(byte[]... byteArrays) {
int length = 0;
for (byte[] byteArray : byteArrays) {
length += byteArray.length;
}
byte[] joined = new byte[length];
length = 0;
for (byte[] byteArray : byteArrays) {
System.arraycopy(byteArray, 0, joined, length, byteArray.length);
length += byteArray.length;
}
return joined;
}
public static final byte[] TEST_ENCRYPTION_KEY_ID = { 0x00, 0x01, 0x02, 0x03 };
public static final byte[] TEST_INITIALIZATION_VECTOR = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
......@@ -163,6 +142,14 @@ import java.util.List;
return this;
}
public StreamBuilder addSimpleBlockMediaWithXiphLacing(int trackNumber, int clusterTimecode,
int blockTimecode, byte[] data, int... lacingFrameSizes) {
EbmlElement simpleBlockElement = createSimpleBlock(trackNumber, blockTimecode,
0x80 /* flags = keyframe */, false, true, data, lacingFrameSizes);
mediaSegments.add(createCluster(clusterTimecode, simpleBlockElement));
return this;
}
public StreamBuilder addBlockMedia(int trackNumber, int clusterTimecode, int blockTimecode,
boolean keyframe, boolean invisible, byte[] data) {
byte flags = (byte) (invisible ? 0x08 : 0x00);
......@@ -309,32 +296,66 @@ import java.util.List;
byte[] simpleBlockBytes;
if (lacingFrameCount > 1) {
flags |= 0x04; // Fixed-size lacing
simpleBlockBytes = createByteArray(
simpleBlockBytes = TestUtil.createByteArray(
0x40, trackNumberBytes[3], // Track number size=2
timeBytes[2], timeBytes[3], flags, lacingFrameCount - 1); // Timecode, flags and lacing.
} else {
simpleBlockBytes = createByteArray(
simpleBlockBytes = TestUtil.createByteArray(
0x40, trackNumberBytes[3], // Track number size=2
timeBytes[2], timeBytes[3], flags); // Timecode and flags
}
if (encrypted) {
simpleBlockBytes = joinByteArrays(
simpleBlockBytes, createByteArray(validSignalByte ? 0x01 : 0x80),
simpleBlockBytes = TestUtil.joinByteArrays(
simpleBlockBytes, TestUtil.createByteArray(validSignalByte ? 0x01 : 0x80),
Arrays.copyOfRange(TEST_INITIALIZATION_VECTOR, 0, 8));
}
return element(0xA3, // SimpleBlock
TestUtil.joinByteArrays(simpleBlockBytes, data));
}
private static EbmlElement createSimpleBlock(int trackNumber, int timecode, int flags,
boolean encrypted, boolean validSignalByte, byte[] data, int... xiphLacingSampleSizes) {
byte[] trackNumberBytes = getIntegerBytes(trackNumber);
byte[] timeBytes = getIntegerBytes(timecode);
byte[] simpleBlockBytes;
flags |= 0x02; // Xiph lacing
simpleBlockBytes = TestUtil.createByteArray(
0x40, trackNumberBytes[3], // Track number size=2
timeBytes[2], timeBytes[3], // Timecode
flags, xiphLacingSampleSizes.length - 1); // Flags and lacing.
int lacingBufferSize = 0;
for (int sampleIndex = 0; sampleIndex < xiphLacingSampleSizes.length - 1; sampleIndex++) {
lacingBufferSize += (xiphLacingSampleSizes[sampleIndex] + 254) / 255;
}
ByteBuffer lacingBytes = ByteBuffer.allocate(lacingBufferSize);
for (int sampleIndex = 0; sampleIndex < xiphLacingSampleSizes.length - 1; sampleIndex++) {
int sampleSize = xiphLacingSampleSizes[sampleIndex];
while (sampleSize > 255) {
sampleSize -= 255;
lacingBytes.put((byte) 0xFF);
}
lacingBytes.put((byte) sampleSize);
}
simpleBlockBytes = TestUtil.joinByteArrays(simpleBlockBytes, lacingBytes.array());
if (encrypted) {
simpleBlockBytes = TestUtil.joinByteArrays(
simpleBlockBytes, TestUtil.createByteArray(validSignalByte ? 0x01 : 0x80),
Arrays.copyOfRange(TEST_INITIALIZATION_VECTOR, 0, 8));
}
return element(0xA3, // SimpleBlock
joinByteArrays(simpleBlockBytes, data));
TestUtil.joinByteArrays(simpleBlockBytes, data));
}
private static EbmlElement createBlock(int trackNumber, int timecode, boolean keyframe, int flags,
byte[] data) {
byte[] trackNumberBytes = getIntegerBytes(trackNumber);
byte[] timeBytes = getIntegerBytes(timecode);
byte[] blockBytes = createByteArray(
byte[] blockBytes = TestUtil.createByteArray(
0x40, trackNumberBytes[3], // Track number size=2
timeBytes[2], timeBytes[3], flags); // Timecode and flags
EbmlElement block = element(0xA1, // Block
joinByteArrays(blockBytes, data));
TestUtil.joinByteArrays(blockBytes, data));
EbmlElement referenceBlock = keyframe ? empty() : element(0xFB, (byte) 0x00); // ReferenceBlock
return element(0xA0, // BlockGroup
referenceBlock,
......@@ -342,7 +363,7 @@ import java.util.List;
}
private static byte[] getIntegerBytes(int value) {
return createByteArray(
return TestUtil.createByteArray(
(value & 0xFF000000) >> 24,
(value & 0x00FF0000) >> 16,
(value & 0x0000FF00) >> 8,
......
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer.testutil;
import com.google.android.exoplayer.drm.DrmInitData;
import com.google.android.exoplayer.extractor.ExtractorOutput;
import com.google.android.exoplayer.extractor.SeekMap;
import android.util.SparseArray;
import junit.framework.TestCase;
/**
* A fake {@link ExtractorOutput}.
*/
public final class FakeExtractorOutput implements ExtractorOutput {
private final boolean allowDuplicateTrackIds;
public final SparseArray<FakeTrackOutput> trackOutputs;
public boolean tracksEnded;
public SeekMap seekMap;
public DrmInitData drmInitData;
public int numberOfTracks;
public FakeExtractorOutput() {
this(false);
}
public FakeExtractorOutput(boolean allowDuplicateTrackIds) {
this.allowDuplicateTrackIds = allowDuplicateTrackIds;
trackOutputs = new SparseArray<>();
}
@Override
public FakeTrackOutput track(int trackId) {
FakeTrackOutput output = trackOutputs.get(trackId);
if (output == null) {
numberOfTracks++;
output = new FakeTrackOutput();
trackOutputs.put(trackId, output);
} else {
TestCase.assertTrue("Duplicate track id: " + trackId, allowDuplicateTrackIds);
}
return output;
}
@Override
public void endTracks() {
tracksEnded = true;
}
@Override
public void seekMap(SeekMap seekMap) {
this.seekMap = seekMap;
}
@Override
public void drmInitData(DrmInitData drmInitData) {
this.drmInitData = drmInitData;
}
}
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer.testutil;
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.extractor.ExtractorInput;
import com.google.android.exoplayer.extractor.TrackOutput;
import com.google.android.exoplayer.util.ParsableByteArray;
import android.test.MoreAsserts;
import junit.framework.TestCase;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
/**
* A fake {@link TrackOutput}.
*/
public final class FakeTrackOutput implements TrackOutput {
private final ArrayList<Long> sampleTimesUs;
private final ArrayList<Integer> sampleFlags;
private final ArrayList<Integer> sampleStartOffsets;
private final ArrayList<Integer> sampleEndOffsets;
private final ArrayList<byte[]> sampleEncryptionKeys;
private byte[] sampleData;
public MediaFormat format;
public FakeTrackOutput() {
sampleData = new byte[0];
sampleTimesUs = new ArrayList<>();
sampleFlags = new ArrayList<>();
sampleStartOffsets = new ArrayList<>();
sampleEndOffsets = new ArrayList<>();
sampleEncryptionKeys = new ArrayList<>();
}
@Override
public void format(MediaFormat format) {
this.format = format;
}
@Override
public int sampleData(ExtractorInput input, int length) throws IOException,
InterruptedException {
byte[] newData = new byte[length];
input.readFully(newData, 0, length);
sampleData = TestUtil.joinByteArrays(sampleData, newData);
return length;
}
@Override
public void sampleData(ParsableByteArray data, int length) {
byte[] newData = new byte[length];
data.readBytes(newData, 0, length);
sampleData = TestUtil.joinByteArrays(sampleData, newData);
}
@Override
public void sampleMetadata(long timeUs, int flags, int size, int offset, byte[] encryptionKey) {
sampleTimesUs.add(timeUs);
sampleFlags.add(flags);
sampleStartOffsets.add(sampleData.length - offset - size);
sampleEndOffsets.add(sampleData.length - offset);
sampleEncryptionKeys.add(encryptionKey);
}
public void assertSampleCount(int count) {
TestCase.assertEquals(count, sampleTimesUs.size());
}
public void assertSample(int index, byte[] data, long timeUs, int flags, byte[] encryptionKey) {
byte[] actualData = Arrays.copyOfRange(sampleData, sampleStartOffsets.get(index),
sampleEndOffsets.get(index));
MoreAsserts.assertEquals(data, actualData);
TestCase.assertEquals(timeUs, (long) sampleTimesUs.get(index));
TestCase.assertEquals(flags, (int) sampleFlags.get(index));
byte[] sampleEncryptionKey = sampleEncryptionKeys.get(index);
if (encryptionKey == null) {
TestCase.assertEquals(null, sampleEncryptionKey);
} else {
MoreAsserts.assertEquals(encryptionKey, sampleEncryptionKey);
}
}
}
......@@ -15,18 +15,56 @@
*/
package com.google.android.exoplayer.testutil;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.extractor.DefaultExtractorInput;
import com.google.android.exoplayer.extractor.Extractor;
import com.google.android.exoplayer.extractor.ExtractorInput;
import com.google.android.exoplayer.extractor.PositionHolder;
import com.google.android.exoplayer.upstream.DataSpec;
import android.net.Uri;
import android.test.InstrumentationTestCase;
import org.mockito.MockitoAnnotations;
import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
/**
* Utility methods for tests.
*/
public class Util {
public class TestUtil {
private TestUtil() {}
public static void consumeTestData(Extractor extractor, byte[] data)
throws IOException, InterruptedException {
ExtractorInput input = createTestExtractorInput(data);
PositionHolder seekPositionHolder = new PositionHolder();
int readResult = Extractor.RESULT_CONTINUE;
while (readResult != Extractor.RESULT_END_OF_INPUT) {
readResult = extractor.read(input, seekPositionHolder);
if (readResult == Extractor.RESULT_SEEK) {
input = createTestExtractorInput(data, (int) seekPositionHolder.position);
}
}
}
private Util() {}
public static ExtractorInput createTestExtractorInput(byte[] data) throws IOException {
return createTestExtractorInput(data, 0);
}
public static ExtractorInput createTestExtractorInput(byte[] data, int offset)
throws IOException {
if (offset != 0) {
data = Arrays.copyOfRange(data, offset, data.length);
}
FakeDataSource dataSource = new FakeDataSource.Builder().appendReadData(data).build();
dataSource.open(new DataSpec(Uri.parse("http://www.google.com")));
ExtractorInput input = new DefaultExtractorInput(dataSource, offset, C.LENGTH_UNBOUNDED);
return input;
}
public static byte[] buildTestData(int length) {
return buildTestData(length, length);
......@@ -39,6 +77,28 @@ public class Util {
return source;
}
public static byte[] createByteArray(int... intArray) {
byte[] byteArray = new byte[intArray.length];
for (int i = 0; i < byteArray.length; i++) {
byteArray[i] = (byte) intArray[i];
}
return byteArray;
}
public static byte[] joinByteArrays(byte[]... byteArrays) {
int length = 0;
for (byte[] byteArray : byteArrays) {
length += byteArray.length;
}
byte[] joined = new byte[length];
length = 0;
for (byte[] byteArray : byteArrays) {
System.arraycopy(byteArray, 0, joined, length, byteArray.length);
length += byteArray.length;
}
return joined;
}
public static void setUpMockito(InstrumentationTestCase instrumentationTestCase) {
// Workaround for https://code.google.com/p/dexmaker/issues/detail?id=2.
System.setProperty("dexmaker.dexcache",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment