Fix how drop-to-keyframe events are recorded in DecoderCounters

The existing code creates an imbalance between `inputBufferCount` and
`droppedBufferCount` by adding 'dropped source buffers' to
`droppedBufferCount` but not to `inputBufferCount`. This results in
assertion failures in `DashTestRunner`.

PiperOrigin-RevId: 414672175
This commit is contained in:
ibaker 2021-12-07 11:25:22 +00:00 committed by Ian Baker
parent 0b09ac5bb0
commit dcc69056bf
5 changed files with 81 additions and 41 deletions

View File

@ -33,12 +33,12 @@ public final class DecoderCounters {
public int decoderInitCount;
/** The number of times a decoder has been released. */
public int decoderReleaseCount;
/** The number of queued input buffers. */
/** The number of input buffers queued to the decoder. */
public int inputBufferCount;
/**
* The number of skipped input buffers.
*
* <p>A skipped input buffer is an input buffer that was deliberately not sent to the decoder.
* <p>A skipped input buffer is an input buffer that was deliberately not queued to the decoder.
*/
public int skippedInputBufferCount;
/** The number of rendered output buffers. */
@ -46,16 +46,28 @@ public final class DecoderCounters {
/**
* The number of skipped output buffers.
*
* <p>A skipped output buffer is an output buffer that was deliberately not rendered.
* <p>A skipped output buffer is an output buffer that was deliberately not rendered. This
* includes buffers that were never dequeued from the decoder and instead skipped while 'inside'
* the codec due to a flush.
*/
public int skippedOutputBufferCount;
/**
* The number of dropped buffers.
*
* <p>A dropped buffer is an buffer that was supposed to be decoded/rendered, but was instead
* <p>A dropped buffer is a buffer that was supposed to be decoded/rendered, but was instead
* dropped because it could not be rendered in time.
*
* <p>This includes all of {@link #droppedInputBufferCount} in addition to buffers dropped after
* being queued to the decoder.
*/
public int droppedBufferCount;
/**
* The number of input buffers dropped.
*
* <p>A dropped input buffer is a buffer that was not queued to the decoder because it would not
* be rendered in time.
*/
public int droppedInputBufferCount;
/**
* The maximum number of dropped buffers without an interleaving rendered output buffer.
*
@ -65,9 +77,16 @@ public final class DecoderCounters {
/**
* The number of times all buffers to a keyframe were dropped.
*
* <p>Each time buffers to a keyframe are dropped, this counter is increased by one, and the
* dropped buffer counters are increased by one (for the current output buffer) plus the number of
* buffers dropped from the source to advance to the keyframe.
* <p>Each time buffers to a keyframe are dropped:
*
* <ul>
* <li>This counter is incremented by one.
* <li>{@link #droppedInputBufferCount} is incremented by the number of buffers dropped from the
* source to advance to the keyframe.
* <li>{@link #droppedBufferCount} is incremented by the sum of the number of buffers dropped
* from the source to advance to the keyframe and the number of buffers 'inside' the
* decoder.
* </ul>
*/
public int droppedToKeyframeCount;
/**
@ -114,6 +133,7 @@ public final class DecoderCounters {
renderedOutputBufferCount += other.renderedOutputBufferCount;
skippedOutputBufferCount += other.skippedOutputBufferCount;
droppedBufferCount += other.droppedBufferCount;
droppedInputBufferCount += other.droppedInputBufferCount;
maxConsecutiveDroppedBufferCount =
max(maxConsecutiveDroppedBufferCount, other.maxConsecutiveDroppedBufferCount);
droppedToKeyframeCount += other.droppedToKeyframeCount;

View File

@ -488,7 +488,8 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
* @param outputBuffer The output buffer to drop.
*/
protected void dropOutputBuffer(VideoDecoderOutputBuffer outputBuffer) {
updateDroppedBufferCounters(1);
updateDroppedBufferCounters(
/* droppedInputBufferCount= */ 0, /* droppedDecoderBufferCount= */ 1);
outputBuffer.release();
}
@ -509,21 +510,27 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
decoderCounters.droppedToKeyframeCount++;
// We dropped some buffers to catch up, so update the decoder counters and flush the decoder,
// which releases all pending buffers buffers including the current output buffer.
updateDroppedBufferCounters(buffersInCodecCount + droppedSourceBufferCount);
updateDroppedBufferCounters(
droppedSourceBufferCount, /* droppedDecoderBufferCount= */ buffersInCodecCount);
flushDecoder();
return true;
}
/**
* Updates decoder counters to reflect that {@code droppedBufferCount} additional buffers were
* dropped.
* Updates local counters and {@link #decoderCounters} to reflect that buffers were dropped.
*
* @param droppedBufferCount The number of additional dropped buffers.
* @param droppedInputBufferCount The number of buffers dropped from the source before being
* passed to the decoder.
* @param droppedDecoderBufferCount The number of buffers dropped after being passed to the
* decoder.
*/
protected void updateDroppedBufferCounters(int droppedBufferCount) {
decoderCounters.droppedBufferCount += droppedBufferCount;
droppedFrames += droppedBufferCount;
consecutiveDroppedFrameCount += droppedBufferCount;
protected void updateDroppedBufferCounters(
int droppedInputBufferCount, int droppedDecoderBufferCount) {
decoderCounters.droppedInputBufferCount += droppedInputBufferCount;
int totalDroppedBufferCount = droppedInputBufferCount + droppedDecoderBufferCount;
decoderCounters.droppedBufferCount += totalDroppedBufferCount;
droppedFrames += totalDroppedBufferCount;
consecutiveDroppedFrameCount += totalDroppedBufferCount;
decoderCounters.maxConsecutiveDroppedBufferCount =
max(consecutiveDroppedFrameCount, decoderCounters.maxConsecutiveDroppedBufferCount);
if (maxDroppedFramesToNotify > 0 && droppedFrames >= maxDroppedFramesToNotify) {

View File

@ -1111,7 +1111,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
TraceUtil.beginSection("dropVideoBuffer");
codec.releaseOutputBuffer(index, false);
TraceUtil.endSection();
updateDroppedBufferCounters(1);
updateDroppedBufferCounters(
/* droppedInputBufferCount= */ 0, /* droppedDecoderBufferCount= */ 1);
}
/**
@ -1131,29 +1132,35 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
if (droppedSourceBufferCount == 0) {
return false;
}
decoderCounters.droppedToKeyframeCount++;
// We dropped some buffers to catch up, so update the decoder counters and flush the codec,
// which releases all pending buffers buffers including the current output buffer.
int totalDroppedBufferCount = buffersInCodecCount + droppedSourceBufferCount;
if (treatDroppedBuffersAsSkipped) {
decoderCounters.skippedOutputBufferCount += totalDroppedBufferCount;
decoderCounters.skippedInputBufferCount += droppedSourceBufferCount;
decoderCounters.skippedOutputBufferCount += buffersInCodecCount;
} else {
updateDroppedBufferCounters(totalDroppedBufferCount);
decoderCounters.droppedToKeyframeCount++;
updateDroppedBufferCounters(
droppedSourceBufferCount, /* droppedDecoderBufferCount= */ buffersInCodecCount);
}
flushOrReinitializeCodec();
return true;
}
/**
* Updates local counters and {@link DecoderCounters} to reflect that {@code droppedBufferCount}
* additional buffers were dropped.
* Updates local counters and {@link #decoderCounters} to reflect that buffers were dropped.
*
* @param droppedBufferCount The number of additional dropped buffers.
* @param droppedInputBufferCount The number of buffers dropped from the source before being
* passed to the decoder.
* @param droppedDecoderBufferCount The number of buffers dropped after being passed to the
* decoder.
*/
protected void updateDroppedBufferCounters(int droppedBufferCount) {
decoderCounters.droppedBufferCount += droppedBufferCount;
droppedFrames += droppedBufferCount;
consecutiveDroppedFrameCount += droppedBufferCount;
protected void updateDroppedBufferCounters(
int droppedInputBufferCount, int droppedDecoderBufferCount) {
decoderCounters.droppedInputBufferCount += droppedInputBufferCount;
int totalDroppedBufferCount = droppedInputBufferCount + droppedDecoderBufferCount;
decoderCounters.droppedBufferCount += totalDroppedBufferCount;
droppedFrames += totalDroppedBufferCount;
consecutiveDroppedFrameCount += totalDroppedBufferCount;
decoderCounters.maxConsecutiveDroppedBufferCount =
max(consecutiveDroppedFrameCount, decoderCounters.maxConsecutiveDroppedBufferCount);
if (maxDroppedFramesToNotify > 0 && droppedFrames >= maxDroppedFramesToNotify) {

View File

@ -361,18 +361,8 @@ import java.util.List;
tag + AUDIO_TAG_SUFFIX, audioCounters, 0);
DecoderCountersUtil.assertSkippedOutputBufferCount(
tag + VIDEO_TAG_SUFFIX, videoCounters, 0);
// We allow one fewer output buffer due to the way that MediaCodecRenderer and the
// underlying decoders handle the end of stream. This should be tightened up in the future.
DecoderCountersUtil.assertTotalBufferCount(
tag + AUDIO_TAG_SUFFIX,
audioCounters,
audioCounters.inputBufferCount - 1,
audioCounters.inputBufferCount);
DecoderCountersUtil.assertTotalBufferCount(
tag + VIDEO_TAG_SUFFIX,
videoCounters,
videoCounters.inputBufferCount - 1,
videoCounters.inputBufferCount);
DecoderCountersUtil.assertTotalBufferCount(tag + AUDIO_TAG_SUFFIX, audioCounters);
DecoderCountersUtil.assertTotalBufferCount(tag + VIDEO_TAG_SUFFIX, videoCounters);
}
try {
if (!shouldSkipDroppedOutputBufferPerformanceAssertions()) {

View File

@ -34,7 +34,8 @@ public final class DecoderCountersUtil {
*/
public static int getTotalBufferCount(DecoderCounters counters) {
counters.ensureUpdated();
return counters.skippedOutputBufferCount
return counters.skippedInputBufferCount
+ counters.skippedOutputBufferCount
+ counters.droppedBufferCount
+ counters.renderedOutputBufferCount;
}
@ -49,6 +50,21 @@ public final class DecoderCountersUtil {
.isEqualTo(expected);
}
/** Asserts that the input and output values in {@code counters} are self-consistent. */
public static void assertTotalBufferCount(String name, DecoderCounters counters) {
// We allow one fewer output buffer due to the way that MediaCodecRenderer and the
// underlying decoders handle the end of stream. This should be tightened up in the future.
int totalInputBufferCount =
counters.skippedInputBufferCount
+ counters.droppedInputBufferCount
+ counters.inputBufferCount;
assertTotalBufferCount(
name,
counters,
/* minCount= */ totalInputBufferCount - 1,
/* maxCount= */ totalInputBufferCount);
}
public static void assertTotalBufferCount(
String name, DecoderCounters counters, int minCount, int maxCount) {
int actual = getTotalBufferCount(counters);