Rename ReorderingSeiMessageQueue to remove reference to SEI

In a follow-up change I am going to use this class in a non-SEI context
for H.262 'user data'.

Issue: androidx/media#2372
PiperOrigin-RevId: 752683541
This commit is contained in:
ibaker 2025-04-29 04:50:19 -07:00 committed by Copybara-Service
parent 721f3c517b
commit 5775abd7e3
4 changed files with 127 additions and 128 deletions

View File

@ -30,42 +30,42 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.PriorityQueue; import java.util.PriorityQueue;
/** A queue of SEI messages, ordered by presentation timestamp. */ /** A queue of buffers, ordered by presentation timestamp. */
@UnstableApi @UnstableApi
@RestrictTo(LIBRARY_GROUP) @RestrictTo(LIBRARY_GROUP)
public final class ReorderingSeiMessageQueue { public final class ReorderingBufferQueue {
/** Functional interface to handle an SEI message that is being removed from the queue. */ /** Functional interface to handle a buffer that is being removed from the queue. */
public interface SeiConsumer { public interface OutputConsumer {
/** Handles an SEI message that is being removed from the queue. */ /** Handles a buffer that is being removed from the queue. */
void consume(long presentationTimeUs, ParsableByteArray seiBuffer); void consume(long presentationTimeUs, ParsableByteArray buffer);
} }
private final SeiConsumer seiConsumer; private final OutputConsumer outputConsumer;
/** Pool of re-usable {@link ParsableByteArray} objects to avoid repeated allocations. */ /** Pool of re-usable {@link ParsableByteArray} objects to avoid repeated allocations. */
private final ArrayDeque<ParsableByteArray> unusedParsableByteArrays; private final ArrayDeque<ParsableByteArray> unusedParsableByteArrays;
/** Pool of re-usable {@link SampleSeiMessages} objects to avoid repeated allocations. */ /** Pool of re-usable {@link BuffersWithTimestamp} objects to avoid repeated allocations. */
private final ArrayDeque<SampleSeiMessages> unusedSampleSeiMessages; private final ArrayDeque<BuffersWithTimestamp> unusedBuffersWithTimestamp;
private final PriorityQueue<SampleSeiMessages> pendingSeiMessages; private final PriorityQueue<BuffersWithTimestamp> pendingBuffers;
private int reorderingQueueSize; private int reorderingQueueSize;
@Nullable private SampleSeiMessages lastQueuedMessage; @Nullable private BuffersWithTimestamp lastQueuedBuffer;
/** /**
* Creates an instance, initially with no max size. * Creates an instance, initially with no max size.
* *
* @param seiConsumer Callback to invoke when SEI messages are removed from the head of queue, * @param outputConsumer Callback to invoke when buffers are removed from the head of the queue,
* either due to exceeding the {@linkplain #setMaxSize(int) max queue size} during a call to * either due to exceeding the {@linkplain #setMaxSize(int) max queue size} during a call to
* {@link #add(long, ParsableByteArray)}, or due to {@link #flush()}. * {@link #add(long, ParsableByteArray)}, or due to {@link #flush()}.
*/ */
public ReorderingSeiMessageQueue(SeiConsumer seiConsumer) { public ReorderingBufferQueue(OutputConsumer outputConsumer) {
this.seiConsumer = seiConsumer; this.outputConsumer = outputConsumer;
unusedParsableByteArrays = new ArrayDeque<>(); unusedParsableByteArrays = new ArrayDeque<>();
unusedSampleSeiMessages = new ArrayDeque<>(); unusedBuffersWithTimestamp = new ArrayDeque<>();
pendingSeiMessages = new PriorityQueue<>(); pendingBuffers = new PriorityQueue<>();
reorderingQueueSize = C.LENGTH_UNSET; reorderingQueueSize = C.LENGTH_UNSET;
} }
@ -73,18 +73,18 @@ public final class ReorderingSeiMessageQueue {
* Sets the max size of the re-ordering queue. * Sets the max size of the re-ordering queue.
* *
* <p>The size is defined in terms of the number of unique presentation timestamps, rather than * <p>The size is defined in terms of the number of unique presentation timestamps, rather than
* the number of messages. This ensures that properties like H.264's {@code * the number of buffers. This ensures that properties like H.264's {@code
* max_number_reorder_frames} can be used to set this max size in the case of multiple SEI * max_number_reorder_frames} can be used to set this max size in the case of multiple SEI
* messages per sample (where multiple SEI messages therefore have the same presentation * messages per sample (where multiple SEI messages therefore have the same presentation
* timestamp). * timestamp).
* *
* <p>When the queue exceeds this size during a call to {@link #add(long, ParsableByteArray)}, the * <p>When the queue exceeds this size during a call to {@link #add(long, ParsableByteArray)}, the
* messages associated with the least timestamp are passed to the {@link SeiConsumer} provided * buffers associated with the least timestamp are passed to the {@link OutputConsumer} provided
* during construction. * during construction.
* *
* <p>If the new size is larger than the number of elements currently in the queue, items are * <p>If the new size is larger than the number of elements currently in the queue, items are
* removed from the head of the queue (least first) and passed to the {@link SeiConsumer} provided * removed from the head of the queue (least first) and passed to the {@link OutputConsumer}
* during construction. * provided during construction.
*/ */
public void setMaxSize(int reorderingQueueSize) { public void setMaxSize(int reorderingQueueSize) {
checkState(reorderingQueueSize >= 0); checkState(reorderingQueueSize >= 0);
@ -102,39 +102,41 @@ public final class ReorderingSeiMessageQueue {
} }
/** /**
* Adds a message to the queue. * Adds a buffer to the queue.
* *
* <p>If this causes the queue to exceed its {@linkplain #setMaxSize(int) max size}, messages * <p>If this causes the queue to exceed its {@linkplain #setMaxSize(int) max size}, buffers
* associated with the least timestamp (which may be the message passed to this method) are passed * associated with the least timestamp (which may be the buffer passed to this method) are passed
* to the {@link SeiConsumer} provided during construction. * to the {@link OutputConsumer} provided during construction.
* *
* <p>Messages with matching timestamps must be added consecutively (this will naturally happen * <p>buffers with matching timestamps must be added consecutively (this will naturally happen
* when parsing messages from a container). * when parsing buffers from a container).
* *
* @param presentationTimeUs The presentation time of the SEI message. * @param presentationTimeUs The presentation time of the buffer.
* @param seiBuffer The SEI data. The data will be copied, so the provided object can be re-used * @param buffer The buffer data. The data will be copied, so the provided object can be re-used
* after this method returns. * after this method returns.
*/ */
public void add(long presentationTimeUs, ParsableByteArray seiBuffer) { public void add(long presentationTimeUs, ParsableByteArray buffer) {
if (reorderingQueueSize == 0 if (reorderingQueueSize == 0
|| (reorderingQueueSize != C.LENGTH_UNSET || (reorderingQueueSize != C.LENGTH_UNSET
&& pendingSeiMessages.size() >= reorderingQueueSize && pendingBuffers.size() >= reorderingQueueSize
&& presentationTimeUs < castNonNull(pendingSeiMessages.peek()).presentationTimeUs)) { && presentationTimeUs < castNonNull(pendingBuffers.peek()).presentationTimeUs)) {
seiConsumer.consume(presentationTimeUs, seiBuffer); outputConsumer.consume(presentationTimeUs, buffer);
return; return;
} }
// Make a local copy of the SEI data so we can store it in the queue and allow the seiBuffer // Make a local copy of the buffer data so we can store it in the queue and allow the buffer
// parameter to be safely re-used after this add() method returns. // parameter to be safely re-used after this add() method returns.
ParsableByteArray seiBufferCopy = copy(seiBuffer); ParsableByteArray bufferCopy = copy(buffer);
if (lastQueuedMessage != null && presentationTimeUs == lastQueuedMessage.presentationTimeUs) { if (lastQueuedBuffer != null && presentationTimeUs == lastQueuedBuffer.presentationTimeUs) {
lastQueuedMessage.nalBuffers.add(seiBufferCopy); lastQueuedBuffer.nalBuffers.add(bufferCopy);
return; return;
} }
SampleSeiMessages sampleSeiMessages = BuffersWithTimestamp buffersWithTimestamp =
unusedSampleSeiMessages.isEmpty() ? new SampleSeiMessages() : unusedSampleSeiMessages.pop(); unusedBuffersWithTimestamp.isEmpty()
sampleSeiMessages.init(presentationTimeUs, seiBufferCopy); ? new BuffersWithTimestamp()
pendingSeiMessages.add(sampleSeiMessages); : unusedBuffersWithTimestamp.pop();
lastQueuedMessage = sampleSeiMessages; buffersWithTimestamp.init(presentationTimeUs, bufferCopy);
pendingBuffers.add(buffersWithTimestamp);
lastQueuedBuffer = buffersWithTimestamp;
if (reorderingQueueSize != C.LENGTH_UNSET) { if (reorderingQueueSize != C.LENGTH_UNSET) {
flushQueueDownToSize(reorderingQueueSize); flushQueueDownToSize(reorderingQueueSize);
} }
@ -159,13 +161,13 @@ public final class ReorderingSeiMessageQueue {
return result; return result;
} }
/** Empties the queue, discarding all previously {@linkplain #add added} messages. */ /** Empties the queue, discarding all previously {@linkplain #add added} buffers. */
public void clear() { public void clear() {
pendingSeiMessages.clear(); pendingBuffers.clear();
} }
/** /**
* Empties the queue, passing all messages (least first) to the {@link SeiConsumer} provided * Empties the queue, passing all buffers (least first) to the {@link OutputConsumer} provided
* during construction. * during construction.
*/ */
public void flush() { public void flush() {
@ -173,29 +175,29 @@ public final class ReorderingSeiMessageQueue {
} }
private void flushQueueDownToSize(int targetSize) { private void flushQueueDownToSize(int targetSize) {
while (pendingSeiMessages.size() > targetSize) { while (pendingBuffers.size() > targetSize) {
SampleSeiMessages sampleSeiMessages = castNonNull(pendingSeiMessages.poll()); BuffersWithTimestamp buffersWithTimestamp = castNonNull(pendingBuffers.poll());
for (int i = 0; i < sampleSeiMessages.nalBuffers.size(); i++) { for (int i = 0; i < buffersWithTimestamp.nalBuffers.size(); i++) {
seiConsumer.consume( outputConsumer.consume(
sampleSeiMessages.presentationTimeUs, sampleSeiMessages.nalBuffers.get(i)); buffersWithTimestamp.presentationTimeUs, buffersWithTimestamp.nalBuffers.get(i));
unusedParsableByteArrays.push(sampleSeiMessages.nalBuffers.get(i)); unusedParsableByteArrays.push(buffersWithTimestamp.nalBuffers.get(i));
} }
sampleSeiMessages.nalBuffers.clear(); buffersWithTimestamp.nalBuffers.clear();
if (lastQueuedMessage != null if (lastQueuedBuffer != null
&& lastQueuedMessage.presentationTimeUs == sampleSeiMessages.presentationTimeUs) { && lastQueuedBuffer.presentationTimeUs == buffersWithTimestamp.presentationTimeUs) {
lastQueuedMessage = null; lastQueuedBuffer = null;
} }
unusedSampleSeiMessages.push(sampleSeiMessages); unusedBuffersWithTimestamp.push(buffersWithTimestamp);
} }
} }
/** Holds the presentation timestamp of a sample and the data from associated SEI messages. */ /** Holds the presentation timestamp of a sample and its associated buffers. */
private static final class SampleSeiMessages implements Comparable<SampleSeiMessages> { private static final class BuffersWithTimestamp implements Comparable<BuffersWithTimestamp> {
public final List<ParsableByteArray> nalBuffers; public final List<ParsableByteArray> nalBuffers;
public long presentationTimeUs; public long presentationTimeUs;
public SampleSeiMessages() { public BuffersWithTimestamp() {
presentationTimeUs = C.TIME_UNSET; presentationTimeUs = C.TIME_UNSET;
nalBuffers = new ArrayList<>(); nalBuffers = new ArrayList<>();
} }
@ -208,7 +210,7 @@ public final class ReorderingSeiMessageQueue {
} }
@Override @Override
public int compareTo(SampleSeiMessages other) { public int compareTo(BuffersWithTimestamp other) {
return Long.compare(this.presentationTimeUs, other.presentationTimeUs); return Long.compare(this.presentationTimeUs, other.presentationTimeUs);
} }
} }

View File

@ -25,6 +25,7 @@ import static org.mockito.Mockito.verifyNoInteractions;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.util.ParsableByteArray; import androidx.media3.common.util.ParsableByteArray;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import androidx.media3.container.ReorderingBufferQueue.OutputConsumer;
import androidx.media3.test.utils.TestUtil; import androidx.media3.test.utils.TestUtil;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.util.ArrayList; import java.util.ArrayList;
@ -33,17 +34,17 @@ import java.util.Objects;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
/** Tests for {@link ReorderingSeiMessageQueue}. */ /** Tests for {@link ReorderingBufferQueue}. */
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public final class ReorderingSeiMessageQueueTest { public final class ReorderingBufferQueueTest {
@Test @Test
public void noMaxSize_queueOnlyEmitsOnExplicitFlushCall() { public void noMaxSize_queueOnlyEmitsOnExplicitFlushCall() {
ArrayList<SeiMessage> emittedMessages = new ArrayList<>(); ArrayList<Buffer> emittedMessages = new ArrayList<>();
ReorderingSeiMessageQueue reorderingQueue = ReorderingBufferQueue reorderingQueue =
new ReorderingSeiMessageQueue( new ReorderingBufferQueue(
(presentationTimeUs, seiBuffer) -> (presentationTimeUs, buffer) ->
emittedMessages.add(new SeiMessage(presentationTimeUs, seiBuffer))); emittedMessages.add(new Buffer(presentationTimeUs, buffer)));
// Deliberately re-use a single ParsableByteArray instance to ensure the implementation is // Deliberately re-use a single ParsableByteArray instance to ensure the implementation is
// making copies as required. // making copies as required.
@ -61,18 +62,18 @@ public final class ReorderingSeiMessageQueueTest {
assertThat(emittedMessages) assertThat(emittedMessages)
.containsExactly( .containsExactly(
new SeiMessage(/* presentationTimeUs= */ 123, data2), new Buffer(/* presentationTimeUs= */ 123, data2),
new SeiMessage(/* presentationTimeUs= */ 345, data1)) new Buffer(/* presentationTimeUs= */ 345, data1))
.inOrder(); .inOrder();
} }
@Test @Test
public void setMaxSize_emitsImmediatelyIfQueueIsOversized() { public void setMaxSize_emitsImmediatelyIfQueueIsOversized() {
ArrayList<SeiMessage> emittedMessages = new ArrayList<>(); ArrayList<Buffer> emittedMessages = new ArrayList<>();
ReorderingSeiMessageQueue reorderingQueue = ReorderingBufferQueue reorderingQueue =
new ReorderingSeiMessageQueue( new ReorderingBufferQueue(
(presentationTimeUs, seiBuffer) -> (presentationTimeUs, buffer) ->
emittedMessages.add(new SeiMessage(presentationTimeUs, seiBuffer))); emittedMessages.add(new Buffer(presentationTimeUs, buffer)));
ParsableByteArray scratchData = new ParsableByteArray(); ParsableByteArray scratchData = new ParsableByteArray();
byte[] data1 = TestUtil.buildTestData(5); byte[] data1 = TestUtil.buildTestData(5);
scratchData.reset(data1); scratchData.reset(data1);
@ -85,17 +86,16 @@ public final class ReorderingSeiMessageQueueTest {
reorderingQueue.setMaxSize(1); reorderingQueue.setMaxSize(1);
assertThat(emittedMessages) assertThat(emittedMessages).containsExactly(new Buffer(/* presentationTimeUs= */ 123, data2));
.containsExactly(new SeiMessage(/* presentationTimeUs= */ 123, data2));
} }
@Test @Test
public void withMaxSize_addEmitsWhenQueueIsFull() { public void withMaxSize_addEmitsWhenQueueIsFull() {
ArrayList<SeiMessage> emittedMessages = new ArrayList<>(); ArrayList<Buffer> emittedMessages = new ArrayList<>();
ReorderingSeiMessageQueue reorderingQueue = ReorderingBufferQueue reorderingQueue =
new ReorderingSeiMessageQueue( new ReorderingBufferQueue(
(presentationTimeUs, seiBuffer) -> (presentationTimeUs, buffer) ->
emittedMessages.add(new SeiMessage(presentationTimeUs, seiBuffer))); emittedMessages.add(new Buffer(presentationTimeUs, buffer)));
reorderingQueue.setMaxSize(1); reorderingQueue.setMaxSize(1);
// Deliberately re-use a single ParsableByteArray instance to ensure the implementation is // Deliberately re-use a single ParsableByteArray instance to ensure the implementation is
@ -111,17 +111,16 @@ public final class ReorderingSeiMessageQueueTest {
scratchData.reset(data2); scratchData.reset(data2);
reorderingQueue.add(/* presentationTimeUs= */ -123, scratchData); reorderingQueue.add(/* presentationTimeUs= */ -123, scratchData);
assertThat(emittedMessages) assertThat(emittedMessages).containsExactly(new Buffer(/* presentationTimeUs= */ -123, data2));
.containsExactly(new SeiMessage(/* presentationTimeUs= */ -123, data2));
} }
@Test @Test
public void withMaxSize_addEmitsWhenQueueIsFull_handlesDuplicateTimestamps() { public void withMaxSize_addEmitsWhenQueueIsFull_handlesDuplicateTimestamps() {
ArrayList<SeiMessage> emittedMessages = new ArrayList<>(); ArrayList<Buffer> emittedMessages = new ArrayList<>();
ReorderingSeiMessageQueue reorderingQueue = ReorderingBufferQueue reorderingQueue =
new ReorderingSeiMessageQueue( new ReorderingBufferQueue(
(presentationTimeUs, seiBuffer) -> (presentationTimeUs, buffer) ->
emittedMessages.add(new SeiMessage(presentationTimeUs, seiBuffer))); emittedMessages.add(new Buffer(presentationTimeUs, buffer)));
reorderingQueue.setMaxSize(1); reorderingQueue.setMaxSize(1);
// Deliberately re-use a single ParsableByteArray instance to ensure the implementation is // Deliberately re-use a single ParsableByteArray instance to ensure the implementation is
@ -144,9 +143,9 @@ public final class ReorderingSeiMessageQueueTest {
assertThat(emittedMessages) assertThat(emittedMessages)
.containsExactly( .containsExactly(
new SeiMessage(/* presentationTimeUs= */ -123, data3), new Buffer(/* presentationTimeUs= */ -123, data3),
new SeiMessage(/* presentationTimeUs= */ 345, data1), new Buffer(/* presentationTimeUs= */ 345, data1),
new SeiMessage(/* presentationTimeUs= */ 345, data2)) new Buffer(/* presentationTimeUs= */ 345, data2))
.inOrder(); .inOrder();
} }
@ -157,9 +156,8 @@ public final class ReorderingSeiMessageQueueTest {
*/ */
@Test @Test
public void withMaxSize_addEmitsWhenQueueIsFull_skippingQueueReusesPbaInstance() { public void withMaxSize_addEmitsWhenQueueIsFull_skippingQueueReusesPbaInstance() {
ReorderingSeiMessageQueue.SeiConsumer mockSeiConsumer = OutputConsumer mockOutputConsumer = mock(OutputConsumer.class);
mock(ReorderingSeiMessageQueue.SeiConsumer.class); ReorderingBufferQueue reorderingQueue = new ReorderingBufferQueue(mockOutputConsumer);
ReorderingSeiMessageQueue reorderingQueue = new ReorderingSeiMessageQueue(mockSeiConsumer);
reorderingQueue.setMaxSize(1); reorderingQueue.setMaxSize(1);
ParsableByteArray scratchData = new ParsableByteArray(); ParsableByteArray scratchData = new ParsableByteArray();
@ -167,28 +165,28 @@ public final class ReorderingSeiMessageQueueTest {
scratchData.reset(data1); scratchData.reset(data1);
reorderingQueue.add(/* presentationTimeUs= */ 345, scratchData); reorderingQueue.add(/* presentationTimeUs= */ 345, scratchData);
verifyNoInteractions(mockSeiConsumer); verifyNoInteractions(mockOutputConsumer);
byte[] data2 = TestUtil.buildTestData(10); byte[] data2 = TestUtil.buildTestData(10);
scratchData.reset(data2); scratchData.reset(data2);
reorderingQueue.add(/* presentationTimeUs= */ 123, scratchData); reorderingQueue.add(/* presentationTimeUs= */ 123, scratchData);
verify(mockSeiConsumer).consume(eq(123L), same(scratchData)); verify(mockOutputConsumer).consume(eq(123L), same(scratchData));
} }
private static final class SeiMessage { private static final class Buffer {
public final long presentationTimeUs; public final long presentationTimeUs;
public final byte[] data; public final byte[] data;
public SeiMessage(long presentationTimeUs, ParsableByteArray seiBuffer) { public Buffer(long presentationTimeUs, ParsableByteArray bufferData) {
this( this(
presentationTimeUs, presentationTimeUs,
Arrays.copyOfRange(seiBuffer.getData(), seiBuffer.getPosition(), seiBuffer.limit())); Arrays.copyOfRange(bufferData.getData(), bufferData.getPosition(), bufferData.limit()));
} }
public SeiMessage(long presentationTimeUs, byte[] seiBuffer) { public Buffer(long presentationTimeUs, byte[] bufferData) {
this.presentationTimeUs = presentationTimeUs; this.presentationTimeUs = presentationTimeUs;
this.data = seiBuffer; this.data = bufferData;
} }
@Override @Override
@ -198,17 +196,17 @@ public final class ReorderingSeiMessageQueueTest {
@Override @Override
public boolean equals(@Nullable Object obj) { public boolean equals(@Nullable Object obj) {
if (!(obj instanceof SeiMessage)) { if (!(obj instanceof Buffer)) {
return false; return false;
} }
SeiMessage that = (SeiMessage) obj; Buffer that = (Buffer) obj;
return this.presentationTimeUs == that.presentationTimeUs return this.presentationTimeUs == that.presentationTimeUs
&& Arrays.equals(this.data, that.data); && Arrays.equals(this.data, that.data);
} }
@Override @Override
public String toString() { public String toString() {
return "SeiMessage { ts=" + presentationTimeUs + ",data=0x" + Util.toHexString(data) + " }"; return "Buffer { ts=" + presentationTimeUs + ",data=0x" + Util.toHexString(data) + " }";
} }
} }
} }

View File

@ -43,7 +43,7 @@ import androidx.media3.container.Mp4Box;
import androidx.media3.container.Mp4Box.ContainerBox; import androidx.media3.container.Mp4Box.ContainerBox;
import androidx.media3.container.Mp4Box.LeafBox; import androidx.media3.container.Mp4Box.LeafBox;
import androidx.media3.container.NalUnitUtil; import androidx.media3.container.NalUnitUtil;
import androidx.media3.container.ReorderingSeiMessageQueue; import androidx.media3.container.ReorderingBufferQueue;
import androidx.media3.extractor.Ac4Util; import androidx.media3.extractor.Ac4Util;
import androidx.media3.extractor.CeaUtil; import androidx.media3.extractor.CeaUtil;
import androidx.media3.extractor.ChunkIndex; import androidx.media3.extractor.ChunkIndex;
@ -216,7 +216,7 @@ public class FragmentedMp4Extractor implements Extractor {
private final ParsableByteArray atomHeader; private final ParsableByteArray atomHeader;
private final ArrayDeque<ContainerBox> containerAtoms; private final ArrayDeque<ContainerBox> containerAtoms;
private final ArrayDeque<MetadataSampleInfo> pendingMetadataSampleInfos; private final ArrayDeque<MetadataSampleInfo> pendingMetadataSampleInfos;
private final ReorderingSeiMessageQueue reorderingSeiMessageQueue; private final ReorderingBufferQueue reorderingBufferQueue;
@Nullable private final TrackOutput additionalEmsgTrackOutput; @Nullable private final TrackOutput additionalEmsgTrackOutput;
private ImmutableList<SniffFailure> lastSniffFailures; private ImmutableList<SniffFailure> lastSniffFailures;
@ -424,10 +424,10 @@ public class FragmentedMp4Extractor implements Extractor {
extractorOutput = ExtractorOutput.PLACEHOLDER; extractorOutput = ExtractorOutput.PLACEHOLDER;
emsgTrackOutputs = new TrackOutput[0]; emsgTrackOutputs = new TrackOutput[0];
ceaTrackOutputs = new TrackOutput[0]; ceaTrackOutputs = new TrackOutput[0];
reorderingSeiMessageQueue = reorderingBufferQueue =
new ReorderingSeiMessageQueue( new ReorderingBufferQueue(
(presentationTimeUs, seiBuffer) -> (presentationTimeUs, buffer) ->
CeaUtil.consume(presentationTimeUs, seiBuffer, ceaTrackOutputs)); CeaUtil.consume(presentationTimeUs, buffer, ceaTrackOutputs));
} }
/** /**
@ -498,7 +498,7 @@ public class FragmentedMp4Extractor implements Extractor {
} }
pendingMetadataSampleInfos.clear(); pendingMetadataSampleInfos.clear();
pendingMetadataSampleBytes = 0; pendingMetadataSampleBytes = 0;
reorderingSeiMessageQueue.clear(); reorderingBufferQueue.clear();
pendingSeekTimeUs = timeUs; pendingSeekTimeUs = timeUs;
containerAtoms.clear(); containerAtoms.clear();
enterReadingAtomHeaderState(); enterReadingAtomHeaderState();
@ -515,7 +515,7 @@ public class FragmentedMp4Extractor implements Extractor {
switch (parserState) { switch (parserState) {
case STATE_READING_ATOM_HEADER: case STATE_READING_ATOM_HEADER:
if (!readAtomHeader(input)) { if (!readAtomHeader(input)) {
reorderingSeiMessageQueue.flush(); reorderingBufferQueue.flush();
return Extractor.RESULT_END_OF_INPUT; return Extractor.RESULT_END_OF_INPUT;
} }
break; break;
@ -1680,17 +1680,16 @@ public class FragmentedMp4Extractor implements Extractor {
nalUnitWithoutHeaderBuffer.setLimit(unescapedLength); nalUnitWithoutHeaderBuffer.setLimit(unescapedLength);
if (track.format.maxNumReorderSamples == Format.NO_VALUE) { if (track.format.maxNumReorderSamples == Format.NO_VALUE) {
if (reorderingSeiMessageQueue.getMaxSize() != 0) { if (reorderingBufferQueue.getMaxSize() != 0) {
reorderingSeiMessageQueue.setMaxSize(0); reorderingBufferQueue.setMaxSize(0);
} }
} else if (reorderingSeiMessageQueue.getMaxSize() } else if (reorderingBufferQueue.getMaxSize() != track.format.maxNumReorderSamples) {
!= track.format.maxNumReorderSamples) { reorderingBufferQueue.setMaxSize(track.format.maxNumReorderSamples);
reorderingSeiMessageQueue.setMaxSize(track.format.maxNumReorderSamples);
} }
reorderingSeiMessageQueue.add(sampleTimeUs, nalUnitWithoutHeaderBuffer); reorderingBufferQueue.add(sampleTimeUs, nalUnitWithoutHeaderBuffer);
if ((trackBundle.getCurrentSampleFlags() & C.BUFFER_FLAG_END_OF_STREAM) != 0) { if ((trackBundle.getCurrentSampleFlags() & C.BUFFER_FLAG_END_OF_STREAM) != 0) {
reorderingSeiMessageQueue.flush(); reorderingBufferQueue.flush();
} }
} else { } else {
// Write the payload of the NAL unit. // Write the payload of the NAL unit.

View File

@ -22,7 +22,7 @@ import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.ParsableByteArray; import androidx.media3.common.util.ParsableByteArray;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.container.ReorderingSeiMessageQueue; import androidx.media3.container.ReorderingBufferQueue;
import androidx.media3.extractor.CeaUtil; import androidx.media3.extractor.CeaUtil;
import androidx.media3.extractor.ExtractorOutput; import androidx.media3.extractor.ExtractorOutput;
import androidx.media3.extractor.TrackOutput; import androidx.media3.extractor.TrackOutput;
@ -36,7 +36,7 @@ public final class SeiReader {
private final List<Format> closedCaptionFormats; private final List<Format> closedCaptionFormats;
private final String containerMimeType; private final String containerMimeType;
private final TrackOutput[] outputs; private final TrackOutput[] outputs;
private final ReorderingSeiMessageQueue reorderingSeiMessageQueue; private final ReorderingBufferQueue reorderingBufferQueue;
/** /**
* @param closedCaptionFormats A list of formats for the closed caption channels to expose. * @param closedCaptionFormats A list of formats for the closed caption channels to expose.
@ -46,10 +46,10 @@ public final class SeiReader {
this.closedCaptionFormats = closedCaptionFormats; this.closedCaptionFormats = closedCaptionFormats;
this.containerMimeType = containerMimeType; this.containerMimeType = containerMimeType;
outputs = new TrackOutput[closedCaptionFormats.size()]; outputs = new TrackOutput[closedCaptionFormats.size()];
reorderingSeiMessageQueue = reorderingBufferQueue =
new ReorderingSeiMessageQueue( new ReorderingBufferQueue(
((presentationTimeUs, seiBuffer) -> (presentationTimeUs, seiBuffer) ->
CeaUtil.consume(presentationTimeUs, seiBuffer, outputs))); CeaUtil.consume(presentationTimeUs, seiBuffer, outputs));
} }
public void createTracks(ExtractorOutput extractorOutput, TrackIdGenerator idGenerator) { public void createTracks(ExtractorOutput extractorOutput, TrackIdGenerator idGenerator) {
@ -82,11 +82,11 @@ public final class SeiReader {
* presentation order. * presentation order.
*/ */
public void setReorderingQueueSize(int reorderingQueueSize) { public void setReorderingQueueSize(int reorderingQueueSize) {
reorderingSeiMessageQueue.setMaxSize(reorderingQueueSize); reorderingBufferQueue.setMaxSize(reorderingQueueSize);
} }
public void consume(long pesTimeUs, ParsableByteArray seiBuffer) { public void consume(long pesTimeUs, ParsableByteArray seiBuffer) {
reorderingSeiMessageQueue.add(pesTimeUs, seiBuffer); reorderingBufferQueue.add(pesTimeUs, seiBuffer);
} }
/** /**
@ -95,11 +95,11 @@ public final class SeiReader {
* TrackOutput[])}. * TrackOutput[])}.
*/ */
public void flush() { public void flush() {
reorderingSeiMessageQueue.flush(); reorderingBufferQueue.flush();
} }
/** Drops any 'buffered for re-ordering' messages. */ /** Drops any 'buffered for re-ordering' messages. */
public void clear() { public void clear() {
reorderingSeiMessageQueue.flush(); reorderingBufferQueue.flush();
} }
} }