mirror of
https://github.com/androidx/media.git
synced 2025-05-09 16:40:55 +08:00
Remove SynchronousMediaCodecBufferEnqueuer
Remove the SynchronousMediaCodecBufferEnqueuer interface since we only keep the AsynchronousMediaCodecBufferEnqueuer implementation. PiperOrigin-RevId: 333701115
This commit is contained in:
parent
7dfdde9246
commit
0066586499
@ -69,59 +69,33 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
private long pendingFlushCount;
|
||||
|
||||
private @State int state;
|
||||
private final MediaCodecInputBufferEnqueuer bufferEnqueuer;
|
||||
private final AsynchronousMediaCodecBufferEnqueuer bufferEnqueuer;
|
||||
|
||||
@GuardedBy("lock")
|
||||
@Nullable
|
||||
private IllegalStateException internalException;
|
||||
|
||||
/**
|
||||
* Creates an instance that wraps the specified {@link MediaCodec}. Instances created with this
|
||||
* constructor will queue input buffers to the {@link MediaCodec} synchronously.
|
||||
* Creates an instance that wraps the specified {@link MediaCodec}.
|
||||
*
|
||||
* @param codec The {@link MediaCodec} to wrap.
|
||||
* @param trackType One of {@link C#TRACK_TYPE_AUDIO} or {@link C#TRACK_TYPE_VIDEO}. Used for
|
||||
* labelling the internal thread accordingly.
|
||||
*/
|
||||
/* package */ AsynchronousMediaCodecAdapter(MediaCodec codec, int trackType) {
|
||||
this(
|
||||
codec,
|
||||
/* enableAsynchronousQueueing= */ false,
|
||||
trackType,
|
||||
new HandlerThread(createThreadLabel(trackType)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance that wraps the specified {@link MediaCodec}.
|
||||
*
|
||||
* @param codec The {@link MediaCodec} to wrap.
|
||||
* @param enableAsynchronousQueueing Whether input buffers will be queued asynchronously.
|
||||
* @param trackType One of {@link C#TRACK_TYPE_AUDIO} or {@link C#TRACK_TYPE_VIDEO}. Used for
|
||||
* labelling the internal thread accordingly.
|
||||
*/
|
||||
/* package */ AsynchronousMediaCodecAdapter(
|
||||
MediaCodec codec, boolean enableAsynchronousQueueing, int trackType) {
|
||||
this(
|
||||
codec,
|
||||
enableAsynchronousQueueing,
|
||||
trackType,
|
||||
new HandlerThread(createThreadLabel(trackType)));
|
||||
this(codec, trackType, new HandlerThread(createThreadLabel(trackType)));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
/* package */ AsynchronousMediaCodecAdapter(
|
||||
MediaCodec codec,
|
||||
boolean enableAsynchronousQueueing,
|
||||
int trackType,
|
||||
HandlerThread handlerThread) {
|
||||
this.lock = new Object();
|
||||
this.mediaCodecAsyncCallback = new MediaCodecAsyncCallback();
|
||||
this.codec = codec;
|
||||
this.handlerThread = handlerThread;
|
||||
this.bufferEnqueuer =
|
||||
enableAsynchronousQueueing
|
||||
? new AsynchronousMediaCodecBufferEnqueuer(codec, trackType)
|
||||
: new SynchronousMediaCodecBufferEnqueuer(this.codec);
|
||||
this.bufferEnqueuer = new AsynchronousMediaCodecBufferEnqueuer(codec, trackType);
|
||||
this.state = STATE_CREATED;
|
||||
}
|
||||
|
||||
|
@ -37,13 +37,13 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
/**
|
||||
* A {@link MediaCodecInputBufferEnqueuer} that defers queueing operations on a background thread.
|
||||
* Performs {@link MediaCodec} input buffer queueing on a background thread.
|
||||
*
|
||||
* <p>The implementation of this class assumes that its public methods will be called from the same
|
||||
* thread.
|
||||
*/
|
||||
@RequiresApi(23)
|
||||
class AsynchronousMediaCodecBufferEnqueuer implements MediaCodecInputBufferEnqueuer {
|
||||
class AsynchronousMediaCodecBufferEnqueuer {
|
||||
|
||||
private static final int MSG_QUEUE_INPUT_BUFFER = 0;
|
||||
private static final int MSG_QUEUE_SECURE_INPUT_BUFFER = 1;
|
||||
@ -85,7 +85,11 @@ class AsynchronousMediaCodecBufferEnqueuer implements MediaCodecInputBufferEnque
|
||||
needsSynchronizationWorkaround = needsSynchronizationWorkaround();
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Starts this instance.
|
||||
*
|
||||
* <p>Call this method after creating an instance and before queueing input buffers.
|
||||
*/
|
||||
public void start() {
|
||||
if (!started) {
|
||||
handlerThread.start();
|
||||
@ -100,7 +104,11 @@ class AsynchronousMediaCodecBufferEnqueuer implements MediaCodecInputBufferEnque
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Submits an input buffer for decoding.
|
||||
*
|
||||
* @see android.media.MediaCodec#queueInputBuffer
|
||||
*/
|
||||
public void queueInputBuffer(
|
||||
int index, int offset, int size, long presentationTimeUs, int flags) {
|
||||
maybeThrowException();
|
||||
@ -111,7 +119,15 @@ class AsynchronousMediaCodecBufferEnqueuer implements MediaCodecInputBufferEnque
|
||||
message.sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Submits an input buffer that potentially contains encrypted data for decoding.
|
||||
*
|
||||
* <p>Note: This method behaves as {@link MediaCodec#queueSecureInputBuffer} with the difference
|
||||
* that {@code info} is of type {@link CryptoInfo} and not {@link
|
||||
* android.media.MediaCodec.CryptoInfo}.
|
||||
*
|
||||
* @see android.media.MediaCodec#queueSecureInputBuffer
|
||||
*/
|
||||
public void queueSecureInputBuffer(
|
||||
int index, int offset, CryptoInfo info, long presentationTimeUs, int flags) {
|
||||
maybeThrowException();
|
||||
@ -123,7 +139,7 @@ class AsynchronousMediaCodecBufferEnqueuer implements MediaCodecInputBufferEnque
|
||||
message.sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
/** Flushes the instance. */
|
||||
public void flush() {
|
||||
if (started) {
|
||||
try {
|
||||
@ -137,7 +153,7 @@ class AsynchronousMediaCodecBufferEnqueuer implements MediaCodecInputBufferEnque
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
/** Shut down the instance. Make sure to call this method to release its internal resources. */
|
||||
public void shutdown() {
|
||||
if (started) {
|
||||
flush();
|
||||
@ -146,36 +162,8 @@ class AsynchronousMediaCodecBufferEnqueuer implements MediaCodecInputBufferEnque
|
||||
started = false;
|
||||
}
|
||||
|
||||
private void doHandleMessage(Message msg) {
|
||||
MessageParams params = null;
|
||||
switch (msg.what) {
|
||||
case MSG_QUEUE_INPUT_BUFFER:
|
||||
params = (MessageParams) msg.obj;
|
||||
doQueueInputBuffer(
|
||||
params.index, params.offset, params.size, params.presentationTimeUs, params.flags);
|
||||
break;
|
||||
case MSG_QUEUE_SECURE_INPUT_BUFFER:
|
||||
params = (MessageParams) msg.obj;
|
||||
doQueueSecureInputBuffer(
|
||||
params.index,
|
||||
params.offset,
|
||||
params.cryptoInfo,
|
||||
params.presentationTimeUs,
|
||||
params.flags);
|
||||
break;
|
||||
case MSG_FLUSH:
|
||||
conditionVariable.open();
|
||||
break;
|
||||
default:
|
||||
setPendingRuntimeException(new IllegalStateException(String.valueOf(msg.what)));
|
||||
}
|
||||
if (params != null) {
|
||||
recycleMessageParams(params);
|
||||
}
|
||||
}
|
||||
|
||||
private void maybeThrowException() {
|
||||
RuntimeException exception = pendingRuntimeException.getAndSet(null);
|
||||
@Nullable RuntimeException exception = pendingRuntimeException.getAndSet(null);
|
||||
if (exception != null) {
|
||||
throw exception;
|
||||
}
|
||||
@ -202,6 +190,34 @@ class AsynchronousMediaCodecBufferEnqueuer implements MediaCodecInputBufferEnque
|
||||
pendingRuntimeException.set(exception);
|
||||
}
|
||||
|
||||
private void doHandleMessage(Message msg) {
|
||||
@Nullable MessageParams params = null;
|
||||
switch (msg.what) {
|
||||
case MSG_QUEUE_INPUT_BUFFER:
|
||||
params = (MessageParams) msg.obj;
|
||||
doQueueInputBuffer(
|
||||
params.index, params.offset, params.size, params.presentationTimeUs, params.flags);
|
||||
break;
|
||||
case MSG_QUEUE_SECURE_INPUT_BUFFER:
|
||||
params = (MessageParams) msg.obj;
|
||||
doQueueSecureInputBuffer(
|
||||
params.index,
|
||||
params.offset,
|
||||
params.cryptoInfo,
|
||||
params.presentationTimeUs,
|
||||
params.flags);
|
||||
break;
|
||||
case MSG_FLUSH:
|
||||
conditionVariable.open();
|
||||
break;
|
||||
default:
|
||||
setPendingRuntimeException(new IllegalStateException(String.valueOf(msg.what)));
|
||||
}
|
||||
if (params != null) {
|
||||
recycleMessageParams(params);
|
||||
}
|
||||
}
|
||||
|
||||
private void doQueueInputBuffer(
|
||||
int index, int offset, int size, long presentationTimeUs, int flag) {
|
||||
try {
|
||||
@ -226,13 +242,6 @@ class AsynchronousMediaCodecBufferEnqueuer implements MediaCodecInputBufferEnque
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
/* package */ static int getInstancePoolSize() {
|
||||
synchronized (MESSAGE_PARAMS_INSTANCE_POOL) {
|
||||
return MESSAGE_PARAMS_INSTANCE_POOL.size();
|
||||
}
|
||||
}
|
||||
|
||||
private static MessageParams getMessageParams() {
|
||||
synchronized (MESSAGE_PARAMS_INSTANCE_POOL) {
|
||||
if (MESSAGE_PARAMS_INSTANCE_POOL.isEmpty()) {
|
||||
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.android.exoplayer2.mediacodec;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
import com.google.android.exoplayer2.decoder.CryptoInfo;
|
||||
|
||||
/** Abstracts operations to enqueue input buffer on a {@link android.media.MediaCodec}. */
|
||||
interface MediaCodecInputBufferEnqueuer {
|
||||
|
||||
/**
|
||||
* Starts this instance.
|
||||
*
|
||||
* <p>Call this method after creating an instance.
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Submits an input buffer for decoding.
|
||||
*
|
||||
* @see android.media.MediaCodec#queueInputBuffer
|
||||
*/
|
||||
void queueInputBuffer(int index, int offset, int size, long presentationTimeUs, int flags);
|
||||
|
||||
/**
|
||||
* Submits an input buffer that potentially contains encrypted data for decoding.
|
||||
*
|
||||
* <p>Note: This method behaves as {@link MediaCodec#queueSecureInputBuffer} with the difference
|
||||
* that {@code info} is of type {@link CryptoInfo} and not {@link
|
||||
* android.media.MediaCodec.CryptoInfo}.
|
||||
*
|
||||
* @see android.media.MediaCodec#queueSecureInputBuffer
|
||||
*/
|
||||
void queueSecureInputBuffer(
|
||||
int index, int offset, CryptoInfo info, long presentationTimeUs, int flags);
|
||||
|
||||
/** Flushes the instance. */
|
||||
void flush();
|
||||
|
||||
/** Shut down the instance. Make sure to call this method to release its internal resources. */
|
||||
void shutdown();
|
||||
}
|
@ -1056,13 +1056,10 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
||||
TraceUtil.beginSection("createCodec:" + codecName);
|
||||
codec = MediaCodec.createByCodecName(codecName);
|
||||
if (enableAsynchronousBufferQueueing && Util.SDK_INT >= 23) {
|
||||
codecAdapter =
|
||||
new AsynchronousMediaCodecAdapter(
|
||||
codec, /* enableAsynchronousQueueing= */ true, getTrackType());
|
||||
codecAdapter = new AsynchronousMediaCodecAdapter(codec, getTrackType());
|
||||
} else {
|
||||
codecAdapter = new SynchronousMediaCodecAdapter(codec);
|
||||
}
|
||||
|
||||
TraceUtil.endSection();
|
||||
TraceUtil.beginSection("configureCodec");
|
||||
configureCodec(codecInfo, codecAdapter, inputFormat, crypto, codecOperatingRate);
|
||||
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.android.exoplayer2.mediacodec;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
import com.google.android.exoplayer2.decoder.CryptoInfo;
|
||||
|
||||
/**
|
||||
* A {@link MediaCodecInputBufferEnqueuer} that forwards queueing methods directly to {@link
|
||||
* MediaCodec}.
|
||||
*/
|
||||
class SynchronousMediaCodecBufferEnqueuer implements MediaCodecInputBufferEnqueuer {
|
||||
private final MediaCodec codec;
|
||||
|
||||
/**
|
||||
* Creates an instance that queues input buffers on the specified {@link MediaCodec}.
|
||||
*
|
||||
* @param codec The {@link MediaCodec} to submit input buffers to.
|
||||
*/
|
||||
SynchronousMediaCodecBufferEnqueuer(MediaCodec codec) {
|
||||
this.codec = codec;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {}
|
||||
|
||||
@Override
|
||||
public void queueInputBuffer(
|
||||
int index, int offset, int size, long presentationTimeUs, int flags) {
|
||||
codec.queueInputBuffer(index, offset, size, presentationTimeUs, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queueSecureInputBuffer(
|
||||
int index, int offset, CryptoInfo info, long presentationTimeUs, int flags) {
|
||||
codec.queueSecureInputBuffer(
|
||||
index, offset, info.getFrameworkCryptoInfo(), presentationTimeUs, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {}
|
||||
|
||||
@Override
|
||||
public void shutdown() {}
|
||||
}
|
@ -48,7 +48,6 @@ public class AsynchronousMediaCodecAdapterTest {
|
||||
adapter =
|
||||
new AsynchronousMediaCodecAdapter(
|
||||
codec,
|
||||
/* enableAsynchronousQueueing= */ false,
|
||||
/* trackType= */ C.TRACK_TYPE_VIDEO,
|
||||
handlerThread);
|
||||
bufferInfo = new MediaCodec.BufferInfo();
|
||||
|
@ -19,6 +19,7 @@ package com.google.android.exoplayer2.mediacodec;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.robolectric.Shadows.shadowOf;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaFormat;
|
||||
@ -28,6 +29,7 @@ import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.decoder.CryptoInfo;
|
||||
import com.google.android.exoplayer2.util.ConditionVariable;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@ -66,6 +68,33 @@ public class AsynchronousMediaCodecBufferEnqueuerTest {
|
||||
assertThat(TestHandlerThread.INSTANCES_STARTED.get()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void queueInputBuffer_queuesInputBufferOnMediaCodec() {
|
||||
enqueuer.start();
|
||||
int inputBufferIndex = codec.dequeueInputBuffer(0);
|
||||
assertThat(inputBufferIndex).isAtLeast(0);
|
||||
byte[] inputData = new byte[] {0, 1, 2, 3};
|
||||
codec.getInputBuffer(inputBufferIndex).put(inputData);
|
||||
|
||||
enqueuer.queueInputBuffer(
|
||||
inputBufferIndex,
|
||||
/* offset= */ 0,
|
||||
/* size= */ 4,
|
||||
/* presentationTimeUs= */ 0,
|
||||
/* flags= */ 0);
|
||||
shadowOf(handlerThread.getLooper()).idle();
|
||||
|
||||
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
|
||||
assertThat(codec.dequeueOutputBuffer(bufferInfo, 0))
|
||||
.isEqualTo(MediaCodec.INFO_OUTPUT_FORMAT_CHANGED);
|
||||
assertThat(codec.dequeueOutputBuffer(bufferInfo, 0)).isEqualTo(inputBufferIndex);
|
||||
ByteBuffer outputBuffer = codec.getOutputBuffer(inputBufferIndex);
|
||||
assertThat(outputBuffer.limit()).isEqualTo(4);
|
||||
byte[] outputData = new byte[4];
|
||||
outputBuffer.get(outputData);
|
||||
assertThat(outputData).isEqualTo(inputData);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void queueInputBuffer_withPendingCryptoExceptionSet_throwsCryptoException() {
|
||||
enqueuer.setPendingRuntimeException(
|
||||
@ -111,7 +140,7 @@ public class AsynchronousMediaCodecBufferEnqueuerTest {
|
||||
enqueuer.queueSecureInputBuffer(
|
||||
/* index= */ 0,
|
||||
/* offset= */ 0,
|
||||
/* info= */ info,
|
||||
info,
|
||||
/* presentationTimeUs= */ 0,
|
||||
/* flags= */ 0));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user