Add support for H264 high-profile in injectable video encoder.

BUG=webrtc:7760

Review-Url: https://codereview.webrtc.org/3007133002
Cr-Original-Commit-Position: refs/heads/master@{#19774}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: c36daecd7785585cbd6665b8527e307bdb109992
diff --git a/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java b/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java
index ea84bc4..9324ba3 100644
--- a/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java
+++ b/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java
@@ -14,13 +14,11 @@
 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 @@
   private static final List<String> 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 @@
             : 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 @@
         return new HashMap<String, String>();
       case H264:
         Map<String, String> 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/sdk/android/api/org/webrtc/VideoCodecInfo.java b/sdk/android/api/org/webrtc/VideoCodecInfo.java
index d8ac182..70295b7 100644
--- a/sdk/android/api/org/webrtc/VideoCodecInfo.java
+++ b/sdk/android/api/org/webrtc/VideoCodecInfo.java
@@ -16,6 +16,19 @@
  * 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<String, String> params;
diff --git a/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java b/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java
index 08c09c7..f3be4cb 100644
--- a/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java
+++ b/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java
@@ -20,10 +20,8 @@
 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 @@
   // 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 @@
   private final String codecName;
   private final VideoCodecType codecType;
   private final int colorFormat;
+  private final Map<String, String> params;
   private final ColorFormat inputColorFormat;
   // Base interval for generating key frames.
   private final int keyFrameIntervalSec;
@@ -115,11 +117,12 @@
    * @throws IllegalArgumentException if colorFormat is unsupported
    */
   public HardwareVideoEncoder(String codecName, VideoCodecType codecType, int colorFormat,
-      int keyFrameIntervalSec, int forceKeyFrameIntervalMs, BitrateAdjuster bitrateAdjuster,
-      EglBase14.Context textureContext) {
+      Map<String, String> 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 @@
       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);