Async queueing: avoid extra memory allocations

When copying CryptoInfo for asynchronous input buffer queueing,
re-use the destination CryptoInfo's arrays to avoid re-allocating
memory.

PiperOrigin-RevId: 295706771
This commit is contained in:
christosts 2020-02-18 12:31:57 +00:00 committed by Oliver Woodman
parent ab21f885d4
commit 3fb8ab2545
2 changed files with 63 additions and 32 deletions

View File

@ -15,11 +15,9 @@
*/
package com.google.android.exoplayer2.decoder;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.util.Util;
import java.util.Arrays;
/**
* Compatibility wrapper for {@link android.media.MediaCodec.CryptoInfo}.
@ -121,25 +119,6 @@ public final class CryptoInfo {
return frameworkCryptoInfo;
}
/** Performs a deep copy to {@code cryptoInfo}. */
public void copyTo(android.media.MediaCodec.CryptoInfo cryptoInfo) {
// Update cryptoInfo fields directly because CryptoInfo.set performs an unnecessary
// object allocation on Android N.
cryptoInfo.numSubSamples = numSubSamples;
cryptoInfo.numBytesOfClearData = copyOrNull(numBytesOfClearData);
cryptoInfo.numBytesOfEncryptedData = copyOrNull(numBytesOfEncryptedData);
cryptoInfo.key = copyOrNull(key);
cryptoInfo.iv = copyOrNull(iv);
cryptoInfo.mode = mode;
if (Util.SDK_INT >= 24) {
android.media.MediaCodec.CryptoInfo.Pattern pattern = patternHolder.pattern;
android.media.MediaCodec.CryptoInfo.Pattern patternCopy =
new android.media.MediaCodec.CryptoInfo.Pattern(
pattern.getEncryptBlocks(), pattern.getSkipBlocks());
cryptoInfo.setPattern(patternCopy);
}
}
/** @deprecated Use {@link #getFrameworkCryptoInfo()}. */
@Deprecated
public android.media.MediaCodec.CryptoInfo getFrameworkCryptoInfoV16() {
@ -169,16 +148,6 @@ public final class CryptoInfo {
numBytesOfClearData[0] += count;
}
@Nullable
private static int[] copyOrNull(@Nullable int[] array) {
return array != null ? Arrays.copyOf(array, array.length) : null;
}
@Nullable
private static byte[] copyOrNull(@Nullable byte[] array) {
return array != null ? Arrays.copyOf(array, array.length) : null;
}
@RequiresApi(24)
private static final class PatternHolderV24 {

View File

@ -29,6 +29,7 @@ import com.google.android.exoplayer2.decoder.CryptoInfo;
import com.google.android.exoplayer2.util.ConditionVariable;
import com.google.android.exoplayer2.util.Util;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicReference;
import org.checkerframework.checker.nullness.compatqual.NullableType;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@ -110,7 +111,7 @@ class AsynchronousMediaCodecBufferEnqueuer implements MediaCodecInputBufferEnque
maybeThrowException();
MessageParams messageParams = getMessageParams();
messageParams.setQueueParams(index, offset, /* size= */ 0, presentationTimeUs, flags);
info.copyTo(messageParams.cryptoInfo);
copy(info, messageParams.cryptoInfo);
Message message =
Util.castNonNull(handler).obtainMessage(MSG_QUEUE_SECURE_INPUT_BUFFER, messageParams);
message.sendToTarget();
@ -271,4 +272,65 @@ class AsynchronousMediaCodecBufferEnqueuer implements MediaCodecInputBufferEnque
}
return labelBuilder.toString();
}
/** Performs a deep copy of {@code cryptoInfo} to {@code frameworkCryptoInfo}. */
private static void copy(
CryptoInfo cryptoInfo, android.media.MediaCodec.CryptoInfo frameworkCryptoInfo) {
// Update frameworkCryptoInfo fields directly because CryptoInfo.set performs an unnecessary
// object allocation on Android N.
frameworkCryptoInfo.numSubSamples = cryptoInfo.numSubSamples;
frameworkCryptoInfo.numBytesOfClearData =
copy(cryptoInfo.numBytesOfClearData, frameworkCryptoInfo.numBytesOfClearData);
frameworkCryptoInfo.numBytesOfEncryptedData =
copy(cryptoInfo.numBytesOfEncryptedData, frameworkCryptoInfo.numBytesOfEncryptedData);
frameworkCryptoInfo.key = copy(cryptoInfo.key, frameworkCryptoInfo.key);
frameworkCryptoInfo.iv = copy(cryptoInfo.iv, frameworkCryptoInfo.iv);
frameworkCryptoInfo.mode = cryptoInfo.mode;
if (Util.SDK_INT >= 24) {
android.media.MediaCodec.CryptoInfo.Pattern pattern =
new android.media.MediaCodec.CryptoInfo.Pattern(
cryptoInfo.encryptedBlocks, cryptoInfo.clearBlocks);
frameworkCryptoInfo.setPattern(pattern);
}
}
/**
* Copies {@code src}, reusing {@code dst} if it's at least as long as {@code src}.
*
* @param src The source array.
* @param dst The destination array, which will be reused if it's at least as long as {@code src}.
* @return The copy, which may be {@code dst} if it was reused.
*/
private static int[] copy(int[] src, int[] dst) {
if (src == null) {
return dst;
}
if (dst == null || dst.length < src.length) {
return Arrays.copyOf(src, src.length);
} else {
System.arraycopy(src, 0, dst, 0, src.length);
return dst;
}
}
/**
* Copies {@code src}, reusing {@code dst} if it's at least as long as {@code src}.
*
* @param src The source array.
* @param dst The destination array, which will be reused if it's at least as long as {@code src}.
* @return The copy, which may be {@code dst} if it was reused.
*/
private static byte[] copy(byte[] src, byte[] dst) {
if (src == null) {
return dst;
}
if (dst == null || dst.length < src.length) {
return Arrays.copyOf(src, src.length);
} else {
System.arraycopy(src, 0, dst, 0, src.length);
return dst;
}
}
}