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; public int decoderInitCount;
/** The number of times a decoder has been released. */ /** The number of times a decoder has been released. */
public int decoderReleaseCount; public int decoderReleaseCount;
/** The number of queued input buffers. */ /** The number of input buffers queued to the decoder. */
public int inputBufferCount; public int inputBufferCount;
/** /**
* The number of skipped input buffers. * 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; public int skippedInputBufferCount;
/** The number of rendered output buffers. */ /** The number of rendered output buffers. */
@ -46,16 +46,28 @@ public final class DecoderCounters {
/** /**
* The number of skipped output buffers. * 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; public int skippedOutputBufferCount;
/** /**
* The number of dropped buffers. * 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. * 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; 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. * 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. * 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 * <p>Each time buffers to a keyframe are dropped:
* 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. * <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; public int droppedToKeyframeCount;
/** /**
@ -114,6 +133,7 @@ public final class DecoderCounters {
renderedOutputBufferCount += other.renderedOutputBufferCount; renderedOutputBufferCount += other.renderedOutputBufferCount;
skippedOutputBufferCount += other.skippedOutputBufferCount; skippedOutputBufferCount += other.skippedOutputBufferCount;
droppedBufferCount += other.droppedBufferCount; droppedBufferCount += other.droppedBufferCount;
droppedInputBufferCount += other.droppedInputBufferCount;
maxConsecutiveDroppedBufferCount = maxConsecutiveDroppedBufferCount =
max(maxConsecutiveDroppedBufferCount, other.maxConsecutiveDroppedBufferCount); max(maxConsecutiveDroppedBufferCount, other.maxConsecutiveDroppedBufferCount);
droppedToKeyframeCount += other.droppedToKeyframeCount; droppedToKeyframeCount += other.droppedToKeyframeCount;

View File

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

View File

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

View File

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

View File

@ -34,7 +34,8 @@ public final class DecoderCountersUtil {
*/ */
public static int getTotalBufferCount(DecoderCounters counters) { public static int getTotalBufferCount(DecoderCounters counters) {
counters.ensureUpdated(); counters.ensureUpdated();
return counters.skippedOutputBufferCount return counters.skippedInputBufferCount
+ counters.skippedOutputBufferCount
+ counters.droppedBufferCount + counters.droppedBufferCount
+ counters.renderedOutputBufferCount; + counters.renderedOutputBufferCount;
} }
@ -49,6 +50,21 @@ public final class DecoderCountersUtil {
.isEqualTo(expected); .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( public static void assertTotalBufferCount(
String name, DecoderCounters counters, int minCount, int maxCount) { String name, DecoderCounters counters, int minCount, int maxCount) {
int actual = getTotalBufferCount(counters); int actual = getTotalBufferCount(counters);