Add the getSampleSize() API to MediaExtractorCompat

This API allows users to retrieve the sample size, ensuring they can allocate sufficient buffer capacity before utilizing the `readSampleData(ByteBuffer buffer, int offset)` method to read data.

PiperOrigin-RevId: 658772408
This commit is contained in:
rohks 2024-08-02 06:29:48 -07:00 committed by Copybara-Service
parent 20df8b282a
commit 8aab324fb4
2 changed files with 60 additions and 13 deletions

View File

@ -124,7 +124,8 @@ public final class MediaExtractorCompat {
private final SparseArray<MediaExtractorSampleQueue> sampleQueues;
private final ArrayDeque<Integer> trackIndicesPerSampleInQueuedOrder;
private final FormatHolder formatHolder;
private final DecoderInputBuffer sampleHolder;
private final DecoderInputBuffer sampleHolderWithBufferReplacementDisabled;
private final DecoderInputBuffer sampleHolderWithBufferReplacementDirect;
private final DecoderInputBuffer noDataBuffer;
private final Set<Integer> selectedTrackIndices;
@ -173,7 +174,10 @@ public final class MediaExtractorCompat {
sampleQueues = new SparseArray<>();
trackIndicesPerSampleInQueuedOrder = new ArrayDeque<>();
formatHolder = new FormatHolder();
sampleHolder = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED);
sampleHolderWithBufferReplacementDisabled =
new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED);
sampleHolderWithBufferReplacementDirect =
new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DIRECT);
noDataBuffer = DecoderInputBuffer.newNoDataInstance();
selectedTrackIndices = new HashSet<>();
}
@ -519,11 +523,12 @@ public final class MediaExtractorCompat {
// The platform media extractor implementation ignores the buffer's input position and limit.
buffer.position(offset);
buffer.limit(buffer.capacity());
sampleHolder.data = buffer;
peekNextSelectedTrackSample(sampleHolder, /* omitSampleData= */ false);
sampleHolderWithBufferReplacementDisabled.data = buffer;
peekNextSelectedTrackSample(
sampleHolderWithBufferReplacementDisabled, /* omitSampleData= */ false);
buffer.flip();
buffer.position(offset);
sampleHolder.data = null;
sampleHolderWithBufferReplacementDisabled.data = null;
return buffer.remaining();
}
@ -538,6 +543,19 @@ public final class MediaExtractorCompat {
return trackIndicesPerSampleInQueuedOrder.peekFirst();
}
/** Returns the current sample's size in bytes, or -1 if no more samples are available. */
public long getSampleSize() {
if (!advanceToSampleOrEndOfInput()) {
return -1;
}
peekNextSelectedTrackSample(
sampleHolderWithBufferReplacementDirect, /* omitSampleData= */ false);
ByteBuffer buffer = checkNotNull(sampleHolderWithBufferReplacementDirect.data);
int sampleSize = buffer.position();
buffer.position(0);
return sampleSize;
}
/**
* Returns the current sample's presentation time in microseconds, or -1 if no more samples are
* available.

View File

@ -199,13 +199,25 @@ public class MediaExtractorCompatTest {
assertThat(mediaExtractorCompat.getTrackCount()).isEqualTo(2);
mediaExtractorCompat.selectTrack(0);
mediaExtractorCompat.selectTrack(1);
assertReadSample(/* trackIndex= */ 0, /* timeUs= */ 4, /* sampleData...= */ (byte) 1);
assertReadSample(
/* trackIndex= */ 0, /* timeUs= */ 4, /* size= */ 1, /* sampleData...= */ (byte) 1);
mediaExtractorCompat.advance();
assertReadSample(/* trackIndex= */ 1, /* timeUs= */ 3, /* sampleData...= */ (byte) 4);
assertReadSample(
/* trackIndex= */ 1, /* timeUs= */ 3, /* size= */ 1, /* sampleData...= */ (byte) 4);
mediaExtractorCompat.advance();
assertReadSample(/* trackIndex= */ 0, /* timeUs= */ 2, /* sampleData...= */ (byte) 2, (byte) 3);
assertReadSample(
/* trackIndex= */ 0,
/* timeUs= */ 2,
/* size= */ 2,
/* sampleData...= */ (byte) 2,
(byte) 3);
mediaExtractorCompat.advance();
assertReadSample(/* trackIndex= */ 1, /* timeUs= */ 1, /* sampleData...= */ (byte) 5, (byte) 6);
assertReadSample(
/* trackIndex= */ 1,
/* timeUs= */ 1,
/* size= */ 2,
/* sampleData...= */ (byte) 5,
(byte) 6);
}
@Test
@ -237,9 +249,10 @@ public class MediaExtractorCompatTest {
assertThat(mediaExtractorCompat.getTrackCount()).isEqualTo(1);
mediaExtractorCompat.selectTrack(0);
mediaExtractorCompat.advance();
// After skipping the only sample, there should be none left, and getSampleTime should return
// -1.
// After skipping the only sample, there should be none left, and getSampleTime and
// getSampleSize should return -1.
assertThat(mediaExtractorCompat.getSampleTime()).isEqualTo(-1);
assertThat(mediaExtractorCompat.getSampleSize()).isEqualTo(-1);
assertThat(mediaExtractorCompat.getTrackFormat(0).getString(MediaFormat.KEY_MIME))
.isEqualTo(PLACEHOLDER_FORMAT_VIDEO.sampleMimeType);
}
@ -258,7 +271,7 @@ public class MediaExtractorCompatTest {
}
@Test
public void getSampleTime_withOutOfMemoryError_producesEndOfInput() throws IOException {
public void getSampleTimeAndSize_withOutOfMemoryError_producesEndOfInput() throws IOException {
// This boolean guarantees that this test remains useful. The throwing read action is being
// called as a result of an implementation detail (trying to parse a container file with no
// tracks) that could change in the future. Counting on this implementation detail simplifies
@ -276,6 +289,7 @@ public class MediaExtractorCompatTest {
});
mediaExtractorCompat.setDataSource(PLACEHOLDER_URI, /* offset= */ 0);
assertThat(mediaExtractorCompat.getSampleTime()).isEqualTo(-1);
assertThat(mediaExtractorCompat.getSampleSize()).isEqualTo(-1);
assertThat(outOfMemoryErrorWasThrown.get()).isTrue();
}
@ -313,6 +327,7 @@ public class MediaExtractorCompatTest {
assertThat(mediaExtractorCompat.getSampleTrackIndex()).isEqualTo(1);
assertThat(mediaExtractorCompat.getSampleTime()).isEqualTo(7);
assertThat(mediaExtractorCompat.getSampleSize()).isEqualTo(3);
assertThat(mediaExtractorCompat.readSampleData(scratchBuffer, /* offset= */ 0)).isEqualTo(3);
assertThat(scratchBuffer.array()).isEqualTo(sampleData);
@ -320,6 +335,7 @@ public class MediaExtractorCompatTest {
assertThat(mediaExtractorCompat.getSampleTrackIndex()).isEqualTo(0);
assertThat(mediaExtractorCompat.getSampleTime()).isEqualTo(7);
assertThat(mediaExtractorCompat.getSampleSize()).isEqualTo(3);
assertThat(mediaExtractorCompat.readSampleData(scratchBuffer, /* offset= */ 0)).isEqualTo(3);
assertThat(scratchBuffer.array()).isEqualTo(sampleData);
@ -344,9 +360,11 @@ public class MediaExtractorCompatTest {
// sample. As a result, to pass this test, the tested implementation must clear the sample
// queues when seekTo is called.
assertThat(mediaExtractorCompat.getSampleTime()).isEqualTo(7);
assertThat(mediaExtractorCompat.getSampleSize()).isEqualTo(1);
mediaExtractorCompat.seekTo(/* timeUs= */ 0, MediaExtractorCompat.SEEK_TO_PREVIOUS_SYNC);
// Test the same sample (and only that sample) is read after the seek to the start.
assertThat(mediaExtractorCompat.getSampleTime()).isEqualTo(7);
assertThat(mediaExtractorCompat.getSampleSize()).isEqualTo(1);
assertThat(mediaExtractorCompat.advance()).isFalse();
}
@ -375,18 +393,21 @@ public class MediaExtractorCompatTest {
byteBuffer.position(byteBuffer.limit());
assertThat(mediaExtractorCompat.getSampleTime()).isEqualTo(1);
assertThat(mediaExtractorCompat.getSampleSize()).isEqualTo(2);
assertThat(mediaExtractorCompat.readSampleData(byteBuffer, /* offset= */ 0)).isEqualTo(2);
assertThat(byteBuffer.position()).isEqualTo(0);
assertThat(byteBuffer.limit()).isEqualTo(2);
mediaExtractorCompat.advance();
assertThat(mediaExtractorCompat.getSampleTime()).isEqualTo(2);
assertThat(mediaExtractorCompat.getSampleSize()).isEqualTo(3);
assertThat(mediaExtractorCompat.readSampleData(byteBuffer, /* offset= */ 2)).isEqualTo(3);
assertThat(byteBuffer.position()).isEqualTo(2);
assertThat(byteBuffer.limit()).isEqualTo(5);
mediaExtractorCompat.advance();
assertThat(mediaExtractorCompat.getSampleTime()).isEqualTo(3);
assertThat(mediaExtractorCompat.getSampleSize()).isEqualTo(4);
assertThat(mediaExtractorCompat.readSampleData(byteBuffer, /* offset= */ 5)).isEqualTo(4);
assertThat(byteBuffer.position()).isEqualTo(5);
assertThat(byteBuffer.limit()).isEqualTo(9);
@ -451,6 +472,7 @@ public class MediaExtractorCompatTest {
mediaExtractorCompat.selectTrack(1);
mediaExtractorCompat.seekTo(1773911, MediaExtractorCompat.SEEK_TO_PREVIOUS_SYNC);
assertThat(mediaExtractorCompat.getSampleTime()).isEqualTo(1773911);
assertThat(mediaExtractorCompat.getSampleSize()).isEqualTo(101040);
}
// Test for b/233756471.
@ -482,21 +504,27 @@ public class MediaExtractorCompatTest {
mediaExtractorCompat.setDataSource(PLACEHOLDER_URI, /* offset= */ 0);
mediaExtractorCompat.selectTrack(/* trackIndex= */ 0);
assertThat(mediaExtractorCompat.getSampleTime()).isEqualTo(7);
assertThat(mediaExtractorCompat.getSampleSize()).isEqualTo(1);
mediaExtractorCompat.advance();
assertThat(mediaExtractorCompat.getSampleTime()).isEqualTo(14);
assertThat(mediaExtractorCompat.getSampleSize()).isEqualTo(1);
mediaExtractorCompat.advance();
assertThat(mediaExtractorCompat.getSampleTime()).isEqualTo(21);
assertThat(mediaExtractorCompat.getSampleSize()).isEqualTo(1);
mediaExtractorCompat.advance();
assertThat(mediaExtractorCompat.getSampleTime()).isEqualTo(-1);
assertThat(mediaExtractorCompat.getSampleSize()).isEqualTo(-1);
// This seek will cause the target position to be invalid, causing an IOException which should
// be treated as the end of input.
mediaExtractorCompat.seekTo(/* timeUs= */ 14, MediaExtractorCompat.SEEK_TO_CLOSEST_SYNC);
assertThat(mediaExtractorCompat.getSampleTime()).isEqualTo(-1);
assertThat(mediaExtractorCompat.getSampleSize()).isEqualTo(-1);
// This seek should go to position 0, which should be handled correctly again.
mediaExtractorCompat.seekTo(/* timeUs= */ 0, MediaExtractorCompat.SEEK_TO_CLOSEST_SYNC);
assertThat(mediaExtractorCompat.getSampleTime()).isEqualTo(7);
assertThat(mediaExtractorCompat.getSampleSize()).isEqualTo(1);
}
@Test
@ -550,9 +578,10 @@ public class MediaExtractorCompatTest {
// Internal methods.
private void assertReadSample(int trackIndex, long timeUs, byte... sampleData) {
private void assertReadSample(int trackIndex, long timeUs, int size, byte... sampleData) {
assertThat(mediaExtractorCompat.getSampleTrackIndex()).isEqualTo(trackIndex);
assertThat(mediaExtractorCompat.getSampleTime()).isEqualTo(timeUs);
assertThat(mediaExtractorCompat.getSampleSize()).isEqualTo(size);
ByteBuffer buffer = ByteBuffer.allocate(100);
assertThat(mediaExtractorCompat.readSampleData(buffer, /* offset= */ 0))
.isEqualTo(sampleData.length);