Require 16x16 alignment when using HardwareVideoEncoder for encoding.

It seems the Android CTS tests only verify that 16x16 aligned resolutions
are supported.

This change checks the validity of input frame's size when initialing
or encoding processes are about to start using H/W MediaCodec.

This change has additional APIs to retrieve
|requested_resolution_alignment| and |apply_alignment_to_all_simulcast_layers|
from JAVA VideoEncoder class and its inherited classes. HardwareVideoEncoder
using MediaCodec has values of 16 and true for above variables.

Bug: webrtc:13089
Change-Id: I0c4ebf94eb36da29c2e384a3edf85b82e779b7f9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/229460
Reviewed-by: Sergey Silkin <ssilkin@webrtc.org>
Reviewed-by: Åsa Persson <asapersson@webrtc.org>
Commit-Queue: Sergey Silkin <ssilkin@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#35169}
This commit is contained in:
Jiwon Jung
2021-10-08 16:41:01 +09:00
committed by WebRTC LUCI CQ
parent 3179fb2931
commit 5a79d28eba
8 changed files with 178 additions and 12 deletions

View File

@ -54,6 +54,9 @@ class HardwareVideoEncoder implements VideoEncoder {
private static final int MEDIA_CODEC_RELEASE_TIMEOUT_MS = 5000;
private static final int DEQUEUE_OUTPUT_BUFFER_TIMEOUT_US = 100000;
// Size of the input frames should be multiple of 16 for the H/W encoder.
private static final int REQUIRED_RESOLUTION_ALIGNMENT = 16;
/**
* 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
@ -207,6 +210,12 @@ class HardwareVideoEncoder implements VideoEncoder {
this.callback = callback;
automaticResizeOn = settings.automaticResizeOn;
if (settings.width % REQUIRED_RESOLUTION_ALIGNMENT != 0
|| settings.height % REQUIRED_RESOLUTION_ALIGNMENT != 0) {
Logging.e(TAG, "MediaCodec is only tested with resolutions that are 16x16 aligned.");
return VideoCodecStatus.ERR_SIZE;
}
this.width = settings.width;
this.height = settings.height;
useSurfaceMode = canUseSurface();
@ -498,12 +507,28 @@ class HardwareVideoEncoder implements VideoEncoder {
return "HWEncoder";
}
@Override
public EncoderInfo getEncoderInfo() {
// Since our MediaCodec is guaranteed to encode 16-pixel-aligned frames only, we set alignment
// value to be 16. Additionally, this encoder produces a single stream. So it should not require
// alignment for all layers.
return new EncoderInfo(
/* requestedResolutionAlignment= */ REQUIRED_RESOLUTION_ALIGNMENT,
/* applyAlignmentToAllSimulcastLayers= */ false);
}
private VideoCodecStatus resetCodec(int newWidth, int newHeight, boolean newUseSurfaceMode) {
encodeThreadChecker.checkIsOnValidThread();
VideoCodecStatus status = release();
if (status != VideoCodecStatus.OK) {
return status;
}
if (newWidth % REQUIRED_RESOLUTION_ALIGNMENT != 0
|| newHeight % REQUIRED_RESOLUTION_ALIGNMENT != 0) {
Logging.e(TAG, "MediaCodec is only tested with resolutions that are 16x16 aligned.");
return VideoCodecStatus.ERR_SIZE;
}
width = newWidth;
height = newHeight;
useSurfaceMode = newUseSurfaceMode;

View File

@ -113,6 +113,12 @@ void VideoEncoderWrapper::UpdateEncoderInfo(JNIEnv* jni) {
encoder_info_.resolution_bitrate_limits = JavaToNativeResolutionBitrateLimits(
jni, Java_VideoEncoder_getResolutionBitrateLimits(jni, encoder_));
EncoderInfo info = GetEncoderInfoInternal(jni);
encoder_info_.requested_resolution_alignment =
info.requested_resolution_alignment;
encoder_info_.apply_alignment_to_all_simulcast_layers =
info.apply_alignment_to_all_simulcast_layers;
}
int32_t VideoEncoderWrapper::RegisterEncodeCompleteCallback(
@ -230,6 +236,26 @@ VideoEncoderWrapper::GetScalingSettingsInternal(JNIEnv* jni) const {
}
}
VideoEncoder::EncoderInfo VideoEncoderWrapper::GetEncoderInfoInternal(
JNIEnv* jni) const {
ScopedJavaLocalRef<jobject> j_encoder_info =
Java_VideoEncoder_getEncoderInfo(jni, encoder_);
jint requested_resolution_alignment =
Java_EncoderInfo_getRequestedResolutionAlignment(jni, j_encoder_info);
jboolean apply_alignment_to_all_simulcast_layers =
Java_EncoderInfo_getApplyAlignmentToAllSimulcastLayers(jni,
j_encoder_info);
VideoEncoder::EncoderInfo info;
info.requested_resolution_alignment = requested_resolution_alignment;
info.apply_alignment_to_all_simulcast_layers =
apply_alignment_to_all_simulcast_layers;
return info;
}
void VideoEncoderWrapper::OnEncodedFrame(
JNIEnv* jni,
const JavaRef<jobject>& j_encoded_image) {

View File

@ -87,6 +87,8 @@ class VideoEncoderWrapper : public VideoEncoder {
std::vector<ResolutionBitrateLimits> GetResolutionBitrateLimits(
JNIEnv* jni) const;
VideoEncoder::EncoderInfo GetEncoderInfoInternal(JNIEnv* jni) const;
const ScopedJavaGlobalRef<jobject> encoder_;
const ScopedJavaGlobalRef<jclass> int_array_class_;