From 25a532656c25d5ce82e0f1b5cddc3e2e9b8f7e73 Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Mon, 11 Aug 2014 17:42:08 +0100 Subject: [PATCH] Optimize some CodecCounter inefficiency. 1. Use ints rather than longs. 2. Remove some counters that dont seem hugely useful. 3. Replace use of volatile with explicit method calls that cause a memory barrier. This is a lot more efficient than using volatile because it can be invoked only once per doSomeWork. --- .../android/exoplayer/CodecCounters.java | 49 +++++++------------ .../exoplayer/ExoPlayerImplInternal.java | 12 ++--- .../exoplayer/MediaCodecTrackRenderer.java | 8 +-- 3 files changed, 25 insertions(+), 44 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer/CodecCounters.java b/library/src/main/java/com/google/android/exoplayer/CodecCounters.java index 7136ef2b1c..6b12b9c072 100644 --- a/library/src/main/java/com/google/android/exoplayer/CodecCounters.java +++ b/library/src/main/java/com/google/android/exoplayer/CodecCounters.java @@ -17,54 +17,41 @@ package com.google.android.exoplayer; /** * Maintains codec event counts, for debugging purposes only. + *

+ * Counters should be written from the playback thread only. Counters may be read from any thread. + * To ensure that the counter values are correctly reflected between threads, users of this class + * should invoke {@link #ensureUpdated()} prior to reading and after writing. */ public final class CodecCounters { - public volatile long codecInitCount; - public volatile long codecReleaseCount; - public volatile long outputFormatChangedCount; - public volatile long outputBuffersChangedCount; - public volatile long queuedInputBufferCount; - public volatile long inputBufferWaitingForSampleCount; - public volatile long keyframeCount; - public volatile long queuedEndOfStreamCount; - public volatile long renderedOutputBufferCount; - public volatile long skippedOutputBufferCount; - public volatile long droppedOutputBufferCount; - public volatile long discardedSamplesCount; + public int codecInitCount; + public int codecReleaseCount; + public int outputFormatChangedCount; + public int outputBuffersChangedCount; + public int renderedOutputBufferCount; + public int skippedOutputBufferCount; + public int droppedOutputBufferCount; /** - * Resets all counts to zero. + * Should be invoked from the playback thread after the counters have been updated. Should also + * be invoked from any other thread that wishes to read the counters, before reading. These calls + * ensure that counter updates are made visible to the reading threads. */ - public void zeroAllCounts() { - codecInitCount = 0; - codecReleaseCount = 0; - outputFormatChangedCount = 0; - outputBuffersChangedCount = 0; - queuedInputBufferCount = 0; - inputBufferWaitingForSampleCount = 0; - keyframeCount = 0; - queuedEndOfStreamCount = 0; - renderedOutputBufferCount = 0; - skippedOutputBufferCount = 0; - droppedOutputBufferCount = 0; - discardedSamplesCount = 0; + public synchronized void ensureUpdated() { + // Do nothing. The use of synchronized ensures a memory barrier should another thread also + // call this method. } public String getDebugString() { + ensureUpdated(); StringBuilder builder = new StringBuilder(); builder.append("cic(").append(codecInitCount).append(")"); builder.append("crc(").append(codecReleaseCount).append(")"); builder.append("ofc(").append(outputFormatChangedCount).append(")"); builder.append("obc(").append(outputBuffersChangedCount).append(")"); - builder.append("qib(").append(queuedInputBufferCount).append(")"); - builder.append("wib(").append(inputBufferWaitingForSampleCount).append(")"); - builder.append("kfc(").append(keyframeCount).append(")"); - builder.append("qes(").append(queuedEndOfStreamCount).append(")"); builder.append("ren(").append(renderedOutputBufferCount).append(")"); builder.append("sob(").append(skippedOutputBufferCount).append(")"); builder.append("dob(").append(droppedOutputBufferCount).append(")"); - builder.append("dsc(").append(discardedSamplesCount).append(")"); return builder.toString(); } diff --git a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java index f1a0963969..193dba6646 100644 --- a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java +++ b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java @@ -60,7 +60,7 @@ import java.util.List; private static final int IDLE_INTERVAL_MS = 1000; private final Handler handler; - private final HandlerThread internalPlayerThread; + private final HandlerThread internalPlaybackThread; private final Handler eventHandler; private final MediaClock mediaClock; private final boolean[] rendererEnabledFlags; @@ -100,7 +100,7 @@ import java.util.List; mediaClock = new MediaClock(); enabledRenderers = new ArrayList(rendererEnabledFlags.length); - internalPlayerThread = new HandlerThread(getClass().getSimpleName() + ":Handler") { + internalPlaybackThread = new HandlerThread(getClass().getSimpleName() + ":Handler") { @Override public void run() { // Note: The documentation for Process.THREAD_PRIORITY_AUDIO that states "Applications can @@ -109,12 +109,12 @@ import java.util.List; super.run(); } }; - internalPlayerThread.start(); - handler = new Handler(internalPlayerThread.getLooper(), this); + internalPlaybackThread.start(); + handler = new Handler(internalPlaybackThread.getLooper(), this); } public Looper getPlaybackLooper() { - return internalPlayerThread.getLooper(); + return internalPlaybackThread.getLooper(); } public int getCurrentPosition() { @@ -179,7 +179,7 @@ import java.util.List; Thread.currentThread().interrupt(); } } - internalPlayerThread.quit(); + internalPlaybackThread.quit(); } } diff --git a/library/src/main/java/com/google/android/exoplayer/MediaCodecTrackRenderer.java b/library/src/main/java/com/google/android/exoplayer/MediaCodecTrackRenderer.java index 9073fa93b5..14a83d2198 100644 --- a/library/src/main/java/com/google/android/exoplayer/MediaCodecTrackRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer/MediaCodecTrackRenderer.java @@ -382,6 +382,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer { while (feedInputBuffer()) {} } } + codecCounters.ensureUpdated(); } catch (IOException e) { throw new ExoPlaybackException(e); } @@ -403,7 +404,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer { if (!sampleHolder.decodeOnly) { currentPositionUs = sampleHolder.timeUs; } - codecCounters.discardedSamplesCount++; } else if (result == SampleSource.FORMAT_READ) { onInputFormatChanged(formatHolder); } @@ -476,7 +476,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer { } if (result == SampleSource.NOTHING_READ) { - codecCounters.inputBufferWaitingForSampleCount++; return false; } if (result == SampleSource.DISCONTINUITY_READ) { @@ -505,7 +504,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer { try { codec.queueInputBuffer(inputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); inputIndex = -1; - codecCounters.queuedEndOfStreamCount++; } catch (CryptoException e) { notifyCryptoError(e); throw new ExoPlaybackException(e); @@ -545,10 +543,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer { } else { codec.queueInputBuffer(inputIndex, 0 , bufferSize, presentationTimeUs, 0); } - codecCounters.queuedInputBufferCount++; - if ((sampleHolder.flags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) { - codecCounters.keyframeCount++; - } inputIndex = -1; codecReconfigurationState = RECONFIGURATION_STATE_NONE; } catch (CryptoException e) {