Remove pipelining from MetadataRenderer

This reverts
<unknown commit>

Which was a temporary workaround for Issue: #1874

Also add a loop to ensure we process as many metadata items as
applicable in each render() call.

PiperOrigin-RevId: 366965504
This commit is contained in:
ibaker 2021-04-06 10:33:31 +01:00 committed by Oliver Woodman
parent 9510ba4d91
commit 9e0e937c31
3 changed files with 65 additions and 67 deletions

View file

@ -31,9 +31,7 @@ import com.google.android.exoplayer2.source.SampleStream.ReadDataResult;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/**
* A renderer for metadata.
@ -42,24 +40,18 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
private static final String TAG = "MetadataRenderer";
private static final int MSG_INVOKE_RENDERER = 0;
// TODO: Holding multiple pending metadata objects is temporary mitigation against
// https://github.com/google/ExoPlayer/issues/1874. It should be removed once this issue has been
// addressed.
private static final int MAX_PENDING_METADATA_COUNT = 5;
private final MetadataDecoderFactory decoderFactory;
private final MetadataOutput output;
@Nullable private final Handler outputHandler;
private final MetadataInputBuffer buffer;
private final @NullableType Metadata[] pendingMetadata;
private final long[] pendingMetadataTimestamps;
private int pendingMetadataIndex;
private int pendingMetadataCount;
@Nullable private MetadataDecoder decoder;
private boolean inputStreamEnded;
private boolean outputStreamEnded;
private long subsampleOffsetUs;
private long pendingMetadataTimestampUs;
@Nullable private Metadata pendingMetadata;
/**
* @param output The output.
@ -90,8 +82,7 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
outputLooper == null ? null : Util.createHandler(outputLooper, /* callback= */ this);
this.decoderFactory = Assertions.checkNotNull(decoderFactory);
buffer = new MetadataInputBuffer();
pendingMetadata = new Metadata[MAX_PENDING_METADATA_COUNT];
pendingMetadataTimestamps = new long[MAX_PENDING_METADATA_COUNT];
pendingMetadataTimestampUs = C.TIME_UNSET;
}
@Override
@ -117,51 +108,18 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
@Override
protected void onPositionReset(long positionUs, boolean joining) {
flushPendingMetadata();
pendingMetadata = null;
pendingMetadataTimestampUs = C.TIME_UNSET;
inputStreamEnded = false;
outputStreamEnded = false;
}
@Override
public void render(long positionUs, long elapsedRealtimeUs) {
if (!inputStreamEnded && pendingMetadataCount < MAX_PENDING_METADATA_COUNT) {
buffer.clear();
FormatHolder formatHolder = getFormatHolder();
@ReadDataResult int result = readSource(formatHolder, buffer, /* readFlags= */ 0);
if (result == C.RESULT_BUFFER_READ) {
if (buffer.isEndOfStream()) {
inputStreamEnded = true;
} else {
buffer.subsampleOffsetUs = subsampleOffsetUs;
buffer.flip();
@Nullable Metadata metadata = castNonNull(decoder).decode(buffer);
if (metadata != null) {
List<Metadata.Entry> entries = new ArrayList<>(metadata.length());
decodeWrappedMetadata(metadata, entries);
if (!entries.isEmpty()) {
Metadata expandedMetadata = new Metadata(entries);
int index =
(pendingMetadataIndex + pendingMetadataCount) % MAX_PENDING_METADATA_COUNT;
pendingMetadata[index] = expandedMetadata;
pendingMetadataTimestamps[index] = buffer.timeUs;
pendingMetadataCount++;
}
}
}
} else if (result == C.RESULT_FORMAT_READ) {
subsampleOffsetUs = Assertions.checkNotNull(formatHolder.format).subsampleOffsetUs;
}
}
if (pendingMetadataCount > 0 && pendingMetadataTimestamps[pendingMetadataIndex] <= positionUs) {
Metadata metadata = castNonNull(pendingMetadata[pendingMetadataIndex]);
invokeRenderer(metadata);
pendingMetadata[pendingMetadataIndex] = null;
pendingMetadataIndex = (pendingMetadataIndex + 1) % MAX_PENDING_METADATA_COUNT;
pendingMetadataCount--;
}
if (inputStreamEnded && pendingMetadataCount == 0) {
outputStreamEnded = true;
boolean working = true;
while (working) {
readMetadata();
working = outputMetadata(positionUs);
}
}
@ -197,7 +155,8 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
@Override
protected void onDisabled() {
flushPendingMetadata();
pendingMetadata = null;
pendingMetadataTimestampUs = C.TIME_UNSET;
decoder = null;
}
@ -211,20 +170,6 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
return true;
}
private void invokeRenderer(Metadata metadata) {
if (outputHandler != null) {
outputHandler.obtainMessage(MSG_INVOKE_RENDERER, metadata).sendToTarget();
} else {
invokeRendererInternal(metadata);
}
}
private void flushPendingMetadata() {
Arrays.fill(pendingMetadata, null);
pendingMetadataIndex = 0;
pendingMetadataCount = 0;
}
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
@ -237,6 +182,56 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
}
}
private void readMetadata() {
if (!inputStreamEnded && pendingMetadata == null) {
buffer.clear();
FormatHolder formatHolder = getFormatHolder();
@ReadDataResult int result = readSource(formatHolder, buffer, /* readFlags= */ 0);
if (result == C.RESULT_BUFFER_READ) {
if (buffer.isEndOfStream()) {
inputStreamEnded = true;
} else {
buffer.subsampleOffsetUs = subsampleOffsetUs;
buffer.flip();
@Nullable Metadata metadata = castNonNull(decoder).decode(buffer);
if (metadata != null) {
List<Metadata.Entry> entries = new ArrayList<>(metadata.length());
decodeWrappedMetadata(metadata, entries);
if (!entries.isEmpty()) {
Metadata expandedMetadata = new Metadata(entries);
pendingMetadata = expandedMetadata;
pendingMetadataTimestampUs = buffer.timeUs;
}
}
}
} else if (result == C.RESULT_FORMAT_READ) {
subsampleOffsetUs = Assertions.checkNotNull(formatHolder.format).subsampleOffsetUs;
}
}
}
private boolean outputMetadata(long positionUs) {
boolean didOutput = false;
if (pendingMetadata != null && pendingMetadataTimestampUs <= positionUs) {
invokeRenderer(pendingMetadata);
pendingMetadata = null;
pendingMetadataTimestampUs = C.TIME_UNSET;
didOutput = true;
}
if (inputStreamEnded && pendingMetadata == null) {
outputStreamEnded = true;
}
return didOutput;
}
private void invokeRenderer(Metadata metadata) {
if (outputHandler != null) {
outputHandler.obtainMessage(MSG_INVOKE_RENDERER, metadata).sendToTarget();
} else {
invokeRendererInternal(metadata);
}
}
private void invokeRendererInternal(Metadata metadata) {
output.onMetadata(metadata);
}

View file

@ -19,7 +19,8 @@ $ packager-linux \
</AdaptationSet>
<EventStream schemeIdUri="urn:mpeg:dash:event:callback:2015" timescale="1000" value="1">
<Event presentationTime="100" duration="1000" id="0" messageData="" />
<Event presentationTime="1000" duration="1000" id="1" messageData="" />
<Event presentationTime="100" duration="1000" id="1" messageData="" />
<Event presentationTime="1000" duration="1000" id="2" messageData="" />
</EventStream>
</Period>
<Period id="1" start="PT1.022S">

View file

@ -97,3 +97,5 @@ MetadataOutput:
entry[0] = EMSG: scheme=urn:mpeg:dash:event:callback:2015, id=0, durationMs=1000, value=1
Metadata[1]:
entry[0] = EMSG: scheme=urn:mpeg:dash:event:callback:2015, id=1, durationMs=1000, value=1
Metadata[2]:
entry[0] = EMSG: scheme=urn:mpeg:dash:event:callback:2015, id=2, durationMs=1000, value=1