From c36daecd7785585cbd6665b8527e307bdb109992 Mon Sep 17 00:00:00 2001 From: sakal Date: Mon, 11 Sep 2017 06:53:27 -0700 Subject: [PATCH] Add support for H264 high-profile in injectable video encoder. BUG=webrtc:7760 Review-Url: https://codereview.webrtc.org/3007133002 Cr-Commit-Position: refs/heads/master@{#19774} --- .../webrtc/HardwareVideoEncoderFactory.java | 33 +++++-------------- .../api/org/webrtc/VideoCodecInfo.java | 13 ++++++++ .../java/org/webrtc/HardwareVideoEncoder.java | 29 +++++++++++++--- 3 files changed, 46 insertions(+), 29 deletions(-) diff --git a/webrtc/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java b/webrtc/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java index ea84bc4335..9324ba3f25 100644 --- a/webrtc/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java +++ b/webrtc/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java @@ -14,13 +14,11 @@ import static org.webrtc.MediaCodecUtils.EXYNOS_PREFIX; import static org.webrtc.MediaCodecUtils.INTEL_PREFIX; import static org.webrtc.MediaCodecUtils.QCOM_PREFIX; -import android.media.MediaCodec; import android.media.MediaCodecInfo; -import android.media.MediaCodecInfo.CodecCapabilities; import android.media.MediaCodecList; import android.os.Build; -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -41,20 +39,6 @@ public class HardwareVideoEncoderFactory implements VideoEncoderFactory { private static final List H264_HW_EXCEPTION_MODELS = Arrays.asList("SAMSUNG-SGH-I337", "Nexus 7", "Nexus 4"); - // Keys for H264 VideoCodecInfo properties. - private static final String H264_FMTP_PROFILE_LEVEL_ID = "profile-level-id"; - private static final String H264_FMTP_LEVEL_ASYMMETRY_ALLOWED = "level-asymmetry-allowed"; - private static final String H264_FMTP_PACKETIZATION_MODE = "packetization-mode"; - - // Supported H264 profile ids and levels. - private static final String H264_PROFILE_CONSTRAINED_BASELINE = "4200"; - private static final String H264_PROFILE_CONSTRAINED_HIGH = "640c"; - private static final String H264_LEVEL_3_1 = "1f"; // 31 in hex. - private static final String H264_CONSTRAINED_BASELINE_3_1 = - H264_PROFILE_CONSTRAINED_BASELINE + H264_LEVEL_3_1; - private static final String H264_CONSTRAINED_HIGH_3_1 = - H264_PROFILE_CONSTRAINED_HIGH + H264_LEVEL_3_1; - private final EglBase14.Context sharedContext; private final boolean enableIntelVp8Encoder; private final boolean enableH264HighProfile; @@ -93,9 +77,9 @@ public class HardwareVideoEncoderFactory implements VideoEncoderFactory { : MediaCodecUtils.TEXTURE_COLOR_FORMATS, info.getCapabilitiesForType(mime)); - return new HardwareVideoEncoder(codecName, type, colorFormat, getKeyFrameIntervalSec(type), - getForcedKeyFrameIntervalMs(type, codecName), createBitrateAdjuster(type, codecName), - sharedContext); + return new HardwareVideoEncoder(codecName, type, colorFormat, input.params, + getKeyFrameIntervalSec(type), getForcedKeyFrameIntervalMs(type, codecName), + createBitrateAdjuster(type, codecName), sharedContext); } @Override @@ -250,10 +234,11 @@ public class HardwareVideoEncoderFactory implements VideoEncoderFactory { return new HashMap(); case H264: Map properties = new HashMap<>(); - properties.put(H264_FMTP_LEVEL_ASYMMETRY_ALLOWED, "1"); - properties.put(H264_FMTP_PACKETIZATION_MODE, "1"); - properties.put(H264_FMTP_PROFILE_LEVEL_ID, - highProfile ? H264_CONSTRAINED_HIGH_3_1 : H264_CONSTRAINED_BASELINE_3_1); + properties.put(VideoCodecInfo.H264_FMTP_LEVEL_ASYMMETRY_ALLOWED, "1"); + properties.put(VideoCodecInfo.H264_FMTP_PACKETIZATION_MODE, "1"); + properties.put(VideoCodecInfo.H264_FMTP_PROFILE_LEVEL_ID, + highProfile ? VideoCodecInfo.H264_CONSTRAINED_HIGH_3_1 + : VideoCodecInfo.H264_CONSTRAINED_BASELINE_3_1); return properties; default: throw new IllegalArgumentException("Unsupported codec: " + type); diff --git a/webrtc/sdk/android/api/org/webrtc/VideoCodecInfo.java b/webrtc/sdk/android/api/org/webrtc/VideoCodecInfo.java index d8ac182e3f..70295b7060 100644 --- a/webrtc/sdk/android/api/org/webrtc/VideoCodecInfo.java +++ b/webrtc/sdk/android/api/org/webrtc/VideoCodecInfo.java @@ -16,6 +16,19 @@ import java.util.Map; * Represent a video codec as encoded in SDP. */ public class VideoCodecInfo { + // Keys for H264 VideoCodecInfo properties. + public static final String H264_FMTP_PROFILE_LEVEL_ID = "profile-level-id"; + public static final String H264_FMTP_LEVEL_ASYMMETRY_ALLOWED = "level-asymmetry-allowed"; + public static final String H264_FMTP_PACKETIZATION_MODE = "packetization-mode"; + + public static final String H264_PROFILE_CONSTRAINED_BASELINE = "4200"; + public static final String H264_PROFILE_CONSTRAINED_HIGH = "640c"; + public static final String H264_LEVEL_3_1 = "1f"; // 31 in hex. + public static final String H264_CONSTRAINED_HIGH_3_1 = + H264_PROFILE_CONSTRAINED_HIGH + H264_LEVEL_3_1; + public static final String H264_CONSTRAINED_BASELINE_3_1 = + H264_PROFILE_CONSTRAINED_BASELINE + H264_LEVEL_3_1; + public final int payload; public final String name; public final Map params; diff --git a/webrtc/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java b/webrtc/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java index 08c09c7fa8..f3be4cbc69 100644 --- a/webrtc/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java +++ b/webrtc/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java @@ -20,10 +20,8 @@ import android.os.Bundle; import android.view.Surface; import java.io.IOException; import java.nio.ByteBuffer; -import java.util.Arrays; import java.util.Deque; -import java.util.HashSet; -import java.util.Set; +import java.util.Map; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; @@ -40,6 +38,9 @@ class HardwareVideoEncoder implements VideoEncoder { // constant until API level 21. private static final String KEY_BITRATE_MODE = "bitrate-mode"; + private static final int VIDEO_AVC_PROFILE_HIGH = 8; + private static final int VIDEO_AVC_LEVEL_3 = 0x100; + private static final int MAX_VIDEO_FRAMERATE = 30; // See MAX_ENCODER_Q_SIZE in androidmediaencoder_jni.cc. @@ -51,6 +52,7 @@ class HardwareVideoEncoder implements VideoEncoder { private final String codecName; private final VideoCodecType codecType; private final int colorFormat; + private final Map params; private final ColorFormat inputColorFormat; // Base interval for generating key frames. private final int keyFrameIntervalSec; @@ -115,11 +117,12 @@ class HardwareVideoEncoder implements VideoEncoder { * @throws IllegalArgumentException if colorFormat is unsupported */ public HardwareVideoEncoder(String codecName, VideoCodecType codecType, int colorFormat, - int keyFrameIntervalSec, int forceKeyFrameIntervalMs, BitrateAdjuster bitrateAdjuster, - EglBase14.Context textureContext) { + Map params, int keyFrameIntervalSec, int forceKeyFrameIntervalMs, + BitrateAdjuster bitrateAdjuster, EglBase14.Context textureContext) { this.codecName = codecName; this.codecType = codecType; this.colorFormat = colorFormat; + this.params = params; if (textureContext == null) { this.inputColorFormat = ColorFormat.valueOf(colorFormat); } else { @@ -169,6 +172,22 @@ class HardwareVideoEncoder implements VideoEncoder { format.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat); format.setInteger(MediaFormat.KEY_FRAME_RATE, bitrateAdjuster.getAdjustedFramerate()); format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, keyFrameIntervalSec); + if (codecType == VideoCodecType.H264) { + String profileLevelId = params.get(VideoCodecInfo.H264_FMTP_PROFILE_LEVEL_ID); + if (profileLevelId == null) { + profileLevelId = VideoCodecInfo.H264_CONSTRAINED_BASELINE_3_1; + } + switch (profileLevelId) { + case VideoCodecInfo.H264_CONSTRAINED_HIGH_3_1: + format.setInteger("profile", VIDEO_AVC_PROFILE_HIGH); + format.setInteger("level", VIDEO_AVC_LEVEL_3); + break; + case VideoCodecInfo.H264_CONSTRAINED_BASELINE_3_1: + break; + default: + Logging.w(TAG, "Unknown profile level id: " + profileLevelId); + } + } Logging.d(TAG, "Format: " + format); codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);