Switch to getInput/OutputBuffer

Use getInput/OutputBuffer(index) instead of getInput/OutputBuffers() in
Android MediaCodec video encoder and decoder wrappers.

getInput/OutputBuffers(index) are available from SDK 21 which is the minimum required version in WebRTC: https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/sdk/android/AndroidManifest.xml

Bug: b/234879577
Change-Id: I79fd234b104420ae3544229e8c62d7db2344cd01
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/265804
Reviewed-by: Xavier Lepaul‎ <xalep@webrtc.org>
Commit-Queue: Sergey Silkin <ssilkin@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#37241}
This commit is contained in:
Sergey Silkin 2022-06-14 10:40:19 +00:00 committed by WebRTC LUCI CQ
parent ef3137a928
commit 7517fb639b
7 changed files with 27 additions and 31 deletions

View File

@ -264,9 +264,9 @@ class AndroidVideoDecoder implements VideoDecoder, VideoSink {
ByteBuffer buffer;
try {
buffer = codec.getInputBuffers()[index];
buffer = codec.getInputBuffer(index);
} catch (IllegalStateException e) {
Logging.e(TAG, "getInputBuffers failed", e);
Logging.e(TAG, "getInputBuffer with index=" + index + " failed", e);
return VideoCodecStatus.ERROR;
}
@ -377,14 +377,14 @@ class AndroidVideoDecoder implements VideoDecoder, VideoSink {
// exceeded, deliverDecodedFrame() will be called again on the next iteration of the output
// thread's loop. Blocking here prevents the output thread from busy-waiting while the codec
// is idle.
int result = codec.dequeueOutputBuffer(info, DEQUEUE_OUTPUT_BUFFER_TIMEOUT_US);
if (result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
int index = codec.dequeueOutputBuffer(info, DEQUEUE_OUTPUT_BUFFER_TIMEOUT_US);
if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
reformat(codec.getOutputFormat());
return;
}
if (result < 0) {
Logging.v(TAG, "dequeueOutputBuffer returned " + result);
if (index < 0) {
Logging.v(TAG, "dequeueOutputBuffer returned " + index);
return;
}
@ -399,9 +399,9 @@ class AndroidVideoDecoder implements VideoDecoder, VideoSink {
hasDecodedFirstFrame = true;
if (surfaceTextureHelper != null) {
deliverTextureFrame(result, info, rotation, decodeTimeMs);
deliverTextureFrame(index, info, rotation, decodeTimeMs);
} else {
deliverByteFrame(result, info, rotation, decodeTimeMs);
deliverByteFrame(index, info, rotation, decodeTimeMs);
}
} catch (IllegalStateException e) {
@ -452,7 +452,7 @@ class AndroidVideoDecoder implements VideoDecoder, VideoSink {
}
private void deliverByteFrame(
int result, MediaCodec.BufferInfo info, int rotation, Integer decodeTimeMs) {
int index, MediaCodec.BufferInfo info, int rotation, Integer decodeTimeMs) {
// Load dimensions from shared memory under the dimension lock.
int width;
int height;
@ -479,7 +479,7 @@ class AndroidVideoDecoder implements VideoDecoder, VideoSink {
stride = info.size * 2 / (height * 3);
}
ByteBuffer buffer = codec.getOutputBuffers()[result];
ByteBuffer buffer = codec.getOutputBuffer(index);
buffer.position(info.offset);
buffer.limit(info.offset + info.size);
buffer = buffer.slice();
@ -491,7 +491,7 @@ class AndroidVideoDecoder implements VideoDecoder, VideoSink {
// All other supported color formats are NV12.
frameBuffer = copyNV12ToI420Buffer(buffer, stride, sliceHeight, width, height);
}
codec.releaseOutputBuffer(result, /* render= */ false);
codec.releaseOutputBuffer(index, /* render= */ false);
long presentationTimeNs = info.presentationTimeUs * 1000;
VideoFrame frame = new VideoFrame(frameBuffer, rotation, presentationTimeNs);

View File

@ -56,7 +56,7 @@ class HardwareVideoEncoder implements VideoEncoder {
/**
* Keeps track of the number of output buffers that have been passed down the pipeline and not yet
* released. We need to wait for this to go down to zero before operations invalidating the output
* buffers, i.e., stop() and getOutputBuffers().
* buffers, i.e., stop() and getOutputBuffer().
*/
private static class BusyCount {
private final Object countLock = new Object();
@ -132,7 +132,6 @@ class HardwareVideoEncoder implements VideoEncoder {
// --- Valid and immutable while an encoding session is running.
@Nullable private MediaCodecWrapper codec;
@Nullable private ByteBuffer[] outputBuffers;
// Thread that delivers encoded frames to the user callback.
@Nullable private Thread outputThread;
@ -285,7 +284,6 @@ class HardwareVideoEncoder implements VideoEncoder {
sliceHeight = getSliceHeight(inputFormat, height);
codec.start();
outputBuffers = codec.getOutputBuffers();
} catch (IllegalStateException e) {
Logging.e(TAG, "initEncodeInternal failed", e);
release();
@ -335,7 +333,6 @@ class HardwareVideoEncoder implements VideoEncoder {
outputBuilders.clear();
codec = null;
outputBuffers = null;
outputThread = null;
// Allow changing thread after release.
@ -454,9 +451,9 @@ class HardwareVideoEncoder implements VideoEncoder {
ByteBuffer buffer;
try {
buffer = codec.getInputBuffers()[index];
buffer = codec.getInputBuffer(index);
} catch (IllegalStateException e) {
Logging.e(TAG, "getInputBuffers failed", e);
Logging.e(TAG, "getInputBuffer with index=" + index + " failed", e);
return VideoCodecStatus.ERROR;
}
fillInputBuffer(buffer, videoFrameBuffer);
@ -582,12 +579,11 @@ class HardwareVideoEncoder implements VideoEncoder {
if (index < 0) {
if (index == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
outputBuffersBusyCount.waitForZero();
outputBuffers = codec.getOutputBuffers();
}
return;
}
ByteBuffer codecOutputBuffer = outputBuffers[index];
ByteBuffer codecOutputBuffer = codec.getOutputBuffer(index);
codecOutputBuffer.position(info.offset);
codecOutputBuffer.limit(info.offset + info.size);

View File

@ -45,9 +45,9 @@ interface MediaCodecWrapper {
MediaFormat getOutputFormat();
ByteBuffer[] getInputBuffers();
ByteBuffer getInputBuffer(int index);
ByteBuffer[] getOutputBuffers();
ByteBuffer getOutputBuffer(int index);
Surface createInputSurface();

View File

@ -88,13 +88,13 @@ class MediaCodecWrapperFactoryImpl implements MediaCodecWrapperFactory {
}
@Override
public ByteBuffer[] getInputBuffers() {
return mediaCodec.getInputBuffers();
public ByteBuffer getInputBuffer(int index) {
return mediaCodec.getInputBuffer(index);
}
@Override
public ByteBuffer[] getOutputBuffers() {
return mediaCodec.getOutputBuffers();
public ByteBuffer getOutputBuffer(int index) {
return mediaCodec.getOutputBuffer(index);
}
@Override

View File

@ -283,7 +283,7 @@ public class AndroidVideoDecoderTest {
/* presentationTimeUs= */ anyLong(),
/* flags= */ eq(0));
ByteBuffer inputBuffer = fakeMediaCodecWrapper.getInputBuffers()[indexCaptor.getValue()];
ByteBuffer inputBuffer = fakeMediaCodecWrapper.getInputBuffer(indexCaptor.getValue());
CodecTestHelper.assertEqualContents(
ENCODED_TEST_DATA, inputBuffer, offsetCaptor.getValue(), sizeCaptor.getValue());
}

View File

@ -292,13 +292,13 @@ public class FakeMediaCodecWrapper implements MediaCodecWrapper {
}
@Override
public ByteBuffer[] getInputBuffers() {
return inputBuffers;
public ByteBuffer getInputBuffer(int index) {
return inputBuffers[index];
}
@Override
public ByteBuffer[] getOutputBuffers() {
return outputBuffers;
public ByteBuffer getOutputBuffer(int index) {
return outputBuffers[index];
}
@Override

View File

@ -216,7 +216,7 @@ public class HardwareVideoEncoderTest {
verify(fakeMediaCodecWrapper)
.queueInputBuffer(indexCaptor.capture(), offsetCaptor.capture(), sizeCaptor.capture(),
anyLong(), anyInt());
ByteBuffer buffer = fakeMediaCodecWrapper.getInputBuffers()[indexCaptor.getValue()];
ByteBuffer buffer = fakeMediaCodecWrapper.getInputBuffer(indexCaptor.getValue());
CodecTestHelper.assertEqualContents(
i420, buffer, offsetCaptor.getValue(), sizeCaptor.getValue());
}