Add support for creating HW codecs in the VideoProcessor tests.

This CL adds the ability to _create_ HW codecs (Android and iOS) in the
VideoProcessor integration tests. Since the VideoProcessor class is not thread
safe yet, this CL does not add the ability to _use_ HW codecs in the tests. A
follow-up CL is planned that will add this ability.

This CL further adds a separate build target which is used to separate the
"plot" versions of the integration tests from the "correctness" versions. The
former will be run manually on devices, whereas the latter are used on the
trybots/buildbots to find regressions in the SW codecs. The underlying test
is the same, however.

BUG=webrtc:6634

Review-Url: https://codereview.webrtc.org/2695653002
Cr-Commit-Position: refs/heads/master@{#16716}
diff --git a/webrtc/modules/video_coding/BUILD.gn b/webrtc/modules/video_coding/BUILD.gn
index a3ad4b3..e8ac671 100644
--- a/webrtc/modules/video_coding/BUILD.gn
+++ b/webrtc/modules/video_coding/BUILD.gn
@@ -341,13 +341,13 @@
     ]
   }
 
-  rtc_source_set("video_coding_modules_tests") {
+  rtc_source_set("video_coding_videoprocessor_integration_test") {
     testonly = true
+
     sources = [
-      "codecs/test/videoprocessor_integrationtest.cc",
       "codecs/test/videoprocessor_integrationtest.h",
-      "codecs/vp8/test/vp8_impl_unittest.cc",
     ]
+
     deps = [
       ":video_codecs_test_framework",
       ":video_coding",
@@ -355,18 +355,123 @@
       ":webrtc_vp8",
       ":webrtc_vp9",
       "../..:webrtc_common",
+      "../../base:rtc_base_approved",
+      "../../media:rtc_media",
+      "../../test:test_support",
+      "../../test:video_test_support",
+    ]
+
+    if (is_android) {
+      sources += [
+        "codecs/test/android_test_initializer.cc",
+        "codecs/test/android_test_initializer.h",
+      ]
+
+      deps += [
+        "../../base:rtc_base_approved",
+        "../../sdk/android:libjingle_peerconnection_jni",
+        "//base",
+      ]
+    }
+
+    if (is_ios || is_mac) {
+      deps += [
+        "../../media:rtc_media_base",
+        "../../sdk:webrtc_h264_video_toolbox",
+      ]
+    }
+  }
+
+  rtc_source_set("video_coding_modules_tests") {
+    testonly = true
+
+    sources = [
+      "codecs/test/videoprocessor_integrationtest.cc",
+      "codecs/vp8/test/vp8_impl_unittest.cc",
+    ]
+
+    deps = [
+      ":video_coding_videoprocessor_integration_test",
+      ":webrtc_vp8",
       "../../api:video_frame_api",
       "../../base:rtc_base_approved",
       "../../common_video:common_video",
-      "../../media:rtc_media_base",
       "../../test:test_support",
       "../../test:video_test_common",
-      "../../test:video_test_support",
       "../video_capture",
     ]
+
     if (rtc_use_h264) {
       defines = [ "WEBRTC_VIDEOPROCESSOR_H264_TESTS" ]
     }
+
+    if (!build_with_chromium && is_clang) {
+      # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
+      suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
+    }
+  }
+
+  plot_videoprocessor_integrationtest_resources = [
+    "//resources/foreman_128x96.yuv",
+    "//resources/foreman_160x120.yuv",
+    "//resources/foreman_176x144.yuv",
+    "//resources/foreman_320x240.yuv",
+    "//resources/foreman_cif.yuv",
+  ]
+
+  if (is_ios || is_mac) {
+    bundle_data("plot_videoprocessor_integrationtest_bundle_data") {
+      testonly = true
+      sources = plot_videoprocessor_integrationtest_resources
+      outputs = [
+        "{{bundle_resources_dir}}/{{source_file_part}}",
+      ]
+    }
+  }
+
+  # This executable is meant for local codec perf testing and should not be run
+  # on the trybots/buildbots, hence the existence of this special build target.
+  rtc_test("plot_videoprocessor_integrationtest") {
+    testonly = true
+
+    sources = [
+      "codecs/test/plot_videoprocessor_integrationtest.cc",
+    ]
+
+    deps = [
+      ":video_coding_videoprocessor_integration_test",
+      "../../test:test_main",
+      "../../test:video_test_common",
+      "../video_capture",
+    ]
+
+    data = plot_videoprocessor_integrationtest_resources
+
+    if (is_android) {
+      deps += [
+        "../../base:rtc_base_approved",
+
+        # TODO(brandtr): Figure out if the java dep below could be moved into
+        # :video_coding_videoprocessor_integration_test, where it belongs.
+        # When that is done, support for Android HW codecs can be added to the
+        # modules_tests target as well.
+        "../../sdk/android:libjingle_peerconnection_java",
+        "../../sdk/android:libjingle_peerconnection_jni",
+        "//base",
+        "//testing/android/native_test:native_test_support",
+      ]
+
+      shard_timeout = 900
+    }
+
+    if (is_ios || is_mac) {
+      deps += [ ":plot_videoprocessor_integrationtest_bundle_data" ]
+    }
+
+    # TODO(brandtr): Remove this define when the modules_tests target properly
+    # loads the Java classes mentioned above.
+    defines = [ "WEBRTC_VIDEOPROCESSOR_INTEGRATIONTEST_HW_CODECS_ENABLED" ]
+
     if (!build_with_chromium && is_clang) {
       # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
       suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
diff --git a/webrtc/modules/video_coding/DEPS b/webrtc/modules/video_coding/DEPS
index d8e3c22..01cd4d5 100644
--- a/webrtc/modules/video_coding/DEPS
+++ b/webrtc/modules/video_coding/DEPS
@@ -8,3 +8,14 @@
   "+webrtc/system_wrappers",
   "+webrtc/tools",
 ]
+
+specific_include_rules = {
+  "android_test_initializer\.cc": [
+    "+base/android",
+    "+webrtc/sdk",
+  ],
+  "(.*test\.cc|.*test\.h)": [
+     "+webrtc/media/engine",
+     "+webrtc/sdk",
+  ],
+}
diff --git a/webrtc/modules/video_coding/codecs/test/android_test_initializer.cc b/webrtc/modules/video_coding/codecs/test/android_test_initializer.cc
new file mode 100644
index 0000000..cb2c5c1
--- /dev/null
+++ b/webrtc/modules/video_coding/codecs/test/android_test_initializer.cc
@@ -0,0 +1,55 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <pthread.h>
+
+#include "webrtc/base/ignore_wundef.h"
+#include "webrtc/modules/video_coding/codecs/test/android_test_initializer.h"
+#include "webrtc/sdk/android/src/jni/classreferenceholder.h"
+#include "webrtc/sdk/android/src/jni/jni_helpers.h"
+
+// Note: this dependency is dangerous since it reaches into Chromium's base.
+// There's a risk of e.g. macro clashes. This file may only be used in tests.
+// Since we use Chrome's build system for creating the gtest binary, this should
+// be fine.
+RTC_PUSH_IGNORING_WUNDEF()
+#include "base/android/jni_android.h"
+RTC_POP_IGNORING_WUNDEF()
+
+#include "webrtc/base/checks.h"
+
+namespace webrtc {
+
+namespace {
+
+static pthread_once_t g_initialize_once = PTHREAD_ONCE_INIT;
+
+// There can only be one JNI_OnLoad in each binary. So since this is a GTEST
+// C++ runner binary, we want to initialize the same global objects we normally
+// do if this had been a Java binary.
+void EnsureInitializedOnce() {
+  RTC_CHECK(::base::android::IsVMInitialized());
+  JNIEnv* jni = ::base::android::AttachCurrentThread();
+  JavaVM* jvm = NULL;
+  RTC_CHECK_EQ(0, jni->GetJavaVM(&jvm));
+
+  jint ret = webrtc_jni::InitGlobalJniVariables(jvm);
+  RTC_DCHECK_GE(ret, 0);
+
+  webrtc_jni::LoadGlobalClassReferenceHolder();
+}
+
+}  // namespace
+
+void InitializeAndroidObjects() {
+  RTC_CHECK_EQ(0, pthread_once(&g_initialize_once, &EnsureInitializedOnce));
+}
+
+}  // namespace webrtc
diff --git a/webrtc/modules/video_coding/codecs/test/android_test_initializer.h b/webrtc/modules/video_coding/codecs/test/android_test_initializer.h
new file mode 100644
index 0000000..a4ec9d2
--- /dev/null
+++ b/webrtc/modules/video_coding/codecs/test/android_test_initializer.h
@@ -0,0 +1,20 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_CODECS_TEST_ANDROID_TEST_INITIALIZER_H_
+#define WEBRTC_MODULES_VIDEO_CODING_CODECS_TEST_ANDROID_TEST_INITIALIZER_H_
+
+namespace webrtc {
+
+void InitializeAndroidObjects();
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_MODULES_VIDEO_CODING_CODECS_TEST_ANDROID_TEST_INITIALIZER_H_
diff --git a/webrtc/modules/video_coding/codecs/test/plot_videoprocessor_integrationtest.cc b/webrtc/modules/video_coding/codecs/test/plot_videoprocessor_integrationtest.cc
index d4152e0..f265230 100644
--- a/webrtc/modules/video_coding/codecs/test/plot_videoprocessor_integrationtest.cc
+++ b/webrtc/modules/video_coding/codecs/test/plot_videoprocessor_integrationtest.cc
@@ -21,6 +21,7 @@
 const bool kFrameDropperOn = true;
 const bool kSpatialResizeOn = false;
 const VideoCodecType kVideoCodecType[] = {kVideoCodecVP8};
+const bool kHwCodec = false;
 
 // Packet loss probability [0.0, 1.0].
 const float kPacketLoss = 0.0f;
@@ -52,7 +53,7 @@
     rate_profile.num_frames = kNumFramesLong;
     // Codec/network settings.
     CodecConfigPars process_settings;
-    SetCodecParameters(&process_settings, codec_type_, kPacketLoss,
+    SetCodecParameters(&process_settings, codec_type_, kHwCodec, kPacketLoss,
                        -1,  // key_frame_interval
                        1,   // num_temporal_layers
                        kErrorConcealmentOn, kDenoisingOn, kFrameDropperOn,
@@ -87,23 +88,23 @@
                        ::testing::ValuesIn(kFps),
                        ::testing::ValuesIn(kVideoCodecType)));
 
-TEST_P(PlotVideoProcessorIntegrationTest, ProcessSQCif) {
+TEST_P(PlotVideoProcessorIntegrationTest, Process128x96) {
   RunTest(128, 96, "foreman_128x96");
 }
 
-TEST_P(PlotVideoProcessorIntegrationTest, ProcessQQVga) {
+TEST_P(PlotVideoProcessorIntegrationTest, Process160x120) {
   RunTest(160, 120, "foreman_160x120");
 }
 
-TEST_P(PlotVideoProcessorIntegrationTest, ProcessQCif) {
+TEST_P(PlotVideoProcessorIntegrationTest, Process176x144) {
   RunTest(176, 144, "foreman_176x144");
 }
 
-TEST_P(PlotVideoProcessorIntegrationTest, ProcessQVga) {
+TEST_P(PlotVideoProcessorIntegrationTest, Process320x240) {
   RunTest(320, 240, "foreman_320x240");
 }
 
-TEST_P(PlotVideoProcessorIntegrationTest, ProcessCif) {
+TEST_P(PlotVideoProcessorIntegrationTest, Process352x288) {
   RunTest(352, 288, "foreman_cif");
 }
 
diff --git a/webrtc/modules/video_coding/codecs/test/videoprocessor.cc b/webrtc/modules/video_coding/codecs/test/videoprocessor.cc
index cd07a86..2acc848 100644
--- a/webrtc/modules/video_coding/codecs/test/videoprocessor.cc
+++ b/webrtc/modules/video_coding/codecs/test/videoprocessor.cc
@@ -374,7 +374,11 @@
                            config_.codec_settings->height));
 
     // Should be the same aspect ratio, no cropping needed.
-    up_image->ScaleFrom(*image.video_frame_buffer());
+    if (image.video_frame_buffer()->native_handle()) {
+      up_image->ScaleFrom(*image.video_frame_buffer()->NativeToI420Buffer());
+    } else {
+      up_image->ScaleFrom(*image.video_frame_buffer());
+    }
 
     // TODO(mikhal): Extracting the buffer for now - need to update test.
     size_t length =
@@ -395,7 +399,15 @@
     // TODO(mikhal): Add as a member function, so won't be allocated per frame.
     size_t length = CalcBufferSize(kI420, image.width(), image.height());
     std::unique_ptr<uint8_t[]> image_buffer(new uint8_t[length]);
-    int extracted_length = ExtractBuffer(image, length, image_buffer.get());
+    int extracted_length;
+    if (image.video_frame_buffer()->native_handle()) {
+      extracted_length =
+          ExtractBuffer(image.video_frame_buffer()->NativeToI420Buffer(),
+                        length, image_buffer.get());
+    } else {
+      extracted_length =
+          ExtractBuffer(image.video_frame_buffer(), length, image_buffer.get());
+    }
     RTC_DCHECK_GT(extracted_length, 0);
     memcpy(last_successful_frame_buffer_.get(), image_buffer.get(),
            extracted_length);
diff --git a/webrtc/modules/video_coding/codecs/test/videoprocessor.h b/webrtc/modules/video_coding/codecs/test/videoprocessor.h
index 736acc6..de20020 100644
--- a/webrtc/modules/video_coding/codecs/test/videoprocessor.h
+++ b/webrtc/modules/video_coding/codecs/test/videoprocessor.h
@@ -205,13 +205,13 @@
     }
     int32_t Decoded(webrtc::VideoFrame& image,
                     int64_t decode_time_ms) override {
-      RTC_NOTREACHED();
-      return -1;
+      return Decoded(image);
     }
-    void Decoded(VideoFrame& frame,
+    void Decoded(webrtc::VideoFrame& image,
                  rtc::Optional<int32_t> decode_time_ms,
                  rtc::Optional<uint8_t> qp) override {
-      RTC_NOTREACHED();
+      Decoded(image,
+              decode_time_ms ? static_cast<int32_t>(*decode_time_ms) : -1);
     }
 
    private:
diff --git a/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.cc b/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.cc
index 841303e..cb2315d 100644
--- a/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.cc
+++ b/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.cc
@@ -13,6 +13,13 @@
 namespace webrtc {
 namespace test {
 
+namespace {
+
+// In these correctness tests, we only consider SW codecs.
+const bool kHwCodec = false;
+
+}  // namespace
+
 #if defined(WEBRTC_VIDEOPROCESSOR_H264_TESTS)
 
 // H264: Run with no packet loss and fixed bitrate. Quality should be very high.
@@ -28,8 +35,8 @@
   rate_profile.num_frames = kNumFramesShort;
   // Codec/network settings.
   CodecConfigPars process_settings;
-  SetCodecParameters(&process_settings, kVideoCodecH264, 0.0f, -1, 1, false,
-                     false, true, false);
+  SetCodecParameters(&process_settings, kVideoCodecH264, kHwCodec, 0.0f, -1, 1,
+                     false, false, true, false);
   // Metrics for expected quality.
   QualityMetrics quality_metrics;
   SetQualityMetrics(&quality_metrics, 35.0, 25.0, 0.93, 0.70);
@@ -59,8 +66,8 @@
   rate_profile.num_frames = kNumFramesShort;
   // Codec/network settings.
   CodecConfigPars process_settings;
-  SetCodecParameters(&process_settings, kVideoCodecVP9, 0.0f, -1, 1, false,
-                     false, true, false);
+  SetCodecParameters(&process_settings, kVideoCodecVP9, kHwCodec, 0.0f, -1, 1,
+                     false, false, true, false);
   // Metrics for expected quality.
   QualityMetrics quality_metrics;
   SetQualityMetrics(&quality_metrics, 37.0, 36.0, 0.93, 0.92);
@@ -81,8 +88,8 @@
   rate_profile.num_frames = kNumFramesShort;
   // Codec/network settings.
   CodecConfigPars process_settings;
-  SetCodecParameters(&process_settings, kVideoCodecVP9, 0.05f, -1, 1, false,
-                     false, true, false);
+  SetCodecParameters(&process_settings, kVideoCodecVP9, kHwCodec, 0.05f, -1, 1,
+                     false, false, true, false);
   // Metrics for expected quality.
   QualityMetrics quality_metrics;
   SetQualityMetrics(&quality_metrics, 17.0, 14.0, 0.45, 0.36);
@@ -107,8 +114,8 @@
   rate_profile.num_frames = kNumFramesLong;
   // Codec/network settings.
   CodecConfigPars process_settings;
-  SetCodecParameters(&process_settings, kVideoCodecVP9, 0.0f, -1, 1, false,
-                     false, true, false);
+  SetCodecParameters(&process_settings, kVideoCodecVP9, kHwCodec, 0.0f, -1, 1,
+                     false, false, true, false);
   // Metrics for expected quality.
   QualityMetrics quality_metrics;
   SetQualityMetrics(&quality_metrics, 35.5, 30.0, 0.90, 0.85);
@@ -140,8 +147,8 @@
   rate_profile.num_frames = kNumFramesLong;
   // Codec/network settings.
   CodecConfigPars process_settings;
-  SetCodecParameters(&process_settings, kVideoCodecVP9, 0.0f, -1, 1, false,
-                     false, true, false);
+  SetCodecParameters(&process_settings, kVideoCodecVP9, kHwCodec, 0.0f, -1, 1,
+                     false, false, true, false);
   // Metrics for expected quality.
   QualityMetrics quality_metrics;
   SetQualityMetrics(&quality_metrics, 31.5, 18.0, 0.80, 0.43);
@@ -163,8 +170,8 @@
   rate_profile.num_frames = kNumFramesShort;
   // Codec/network settings.
   CodecConfigPars process_settings;
-  SetCodecParameters(&process_settings, kVideoCodecVP9, 0.0f, -1, 1, false,
-                     true, true, false);
+  SetCodecParameters(&process_settings, kVideoCodecVP9, kHwCodec, 0.0f, -1, 1,
+                     false, true, true, false);
   // Metrics for expected quality.
   QualityMetrics quality_metrics;
   SetQualityMetrics(&quality_metrics, 36.8, 35.8, 0.92, 0.91);
@@ -188,8 +195,8 @@
   rate_profile.num_frames = kNumFramesLong;
   // Codec/network settings.
   CodecConfigPars process_settings;
-  SetCodecParameters(&process_settings, kVideoCodecVP9, 0.0f, -1, 1, false,
-                     false, true, true);
+  SetCodecParameters(&process_settings, kVideoCodecVP9, kHwCodec, 0.0f, -1, 1,
+                     false, false, true, true);
   // Metrics for expected quality.
   QualityMetrics quality_metrics;
   SetQualityMetrics(&quality_metrics, 24.0, 13.0, 0.65, 0.37);
@@ -216,8 +223,8 @@
   rate_profile.num_frames = kNumFramesShort;
   // Codec/network settings.
   CodecConfigPars process_settings;
-  SetCodecParameters(&process_settings, kVideoCodecVP8, 0.0f, -1, 1, false,
-                     true, true, false);
+  SetCodecParameters(&process_settings, kVideoCodecVP8, kHwCodec, 0.0f, -1, 1,
+                     false, true, true, false);
   // Metrics for expected quality.
   QualityMetrics quality_metrics;
   SetQualityMetrics(&quality_metrics, 34.95, 33.0, 0.90, 0.89);
@@ -238,8 +245,8 @@
   rate_profile.num_frames = kNumFramesShort;
   // Codec/network settings.
   CodecConfigPars process_settings;
-  SetCodecParameters(&process_settings, kVideoCodecVP8, 0.05f, -1, 1, false,
-                     true, true, false);
+  SetCodecParameters(&process_settings, kVideoCodecVP8, kHwCodec, 0.05f, -1, 1,
+                     false, true, true, false);
   // Metrics for expected quality.
   QualityMetrics quality_metrics;
   SetQualityMetrics(&quality_metrics, 20.0, 16.0, 0.60, 0.40);
@@ -260,8 +267,8 @@
   rate_profile.num_frames = kNumFramesShort;
   // Codec/network settings.
   CodecConfigPars process_settings;
-  SetCodecParameters(&process_settings, kVideoCodecVP8, 0.1f, -1, 1, false,
-                     true, true, false);
+  SetCodecParameters(&process_settings, kVideoCodecVP8, kHwCodec, 0.1f, -1, 1,
+                     false, true, true, false);
   // Metrics for expected quality.
   QualityMetrics quality_metrics;
   SetQualityMetrics(&quality_metrics, 19.0, 16.0, 0.50, 0.35);
@@ -304,8 +311,8 @@
   rate_profile.num_frames = kNumFramesLong;
   // Codec/network settings.
   CodecConfigPars process_settings;
-  SetCodecParameters(&process_settings, kVideoCodecVP8, 0.0f, -1, 1, false,
-                     true, true, false);
+  SetCodecParameters(&process_settings, kVideoCodecVP8, kHwCodec, 0.0f, -1, 1,
+                     false, true, true, false);
   // Metrics for expected quality.
   QualityMetrics quality_metrics;
   SetQualityMetrics(&quality_metrics, 34.0, 32.0, 0.85, 0.80);
@@ -345,8 +352,8 @@
   rate_profile.num_frames = kNumFramesLong;
   // Codec/network settings.
   CodecConfigPars process_settings;
-  SetCodecParameters(&process_settings, kVideoCodecVP8, 0.0f, -1, 1, false,
-                     true, true, false);
+  SetCodecParameters(&process_settings, kVideoCodecVP8, kHwCodec, 0.0f, -1, 1,
+                     false, true, true, false);
   // Metrics for expected quality.
   QualityMetrics quality_metrics;
   SetQualityMetrics(&quality_metrics, 31.0, 22.0, 0.80, 0.65);
@@ -381,8 +388,8 @@
   rate_profile.num_frames = kNumFramesLong;
   // Codec/network settings.
   CodecConfigPars process_settings;
-  SetCodecParameters(&process_settings, kVideoCodecVP8, 0.0f, -1, 3, false,
-                     true, true, false);
+  SetCodecParameters(&process_settings, kVideoCodecVP8, kHwCodec, 0.0f, -1, 3,
+                     false, true, true, false);
   // Metrics for expected quality.
   QualityMetrics quality_metrics;
   SetQualityMetrics(&quality_metrics, 32.5, 30.0, 0.85, 0.80);
diff --git a/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.h b/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.h
index 54700c1..e1c085e 100644
--- a/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.h
+++ b/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.h
@@ -16,7 +16,18 @@
 #include <memory>
 #include <string>
 
+#if defined(WEBRTC_ANDROID)
+#include "webrtc/modules/video_coding/codecs/test/android_test_initializer.h"
+#include "webrtc/sdk/android/src/jni/androidmediadecoder_jni.h"
+#include "webrtc/sdk/android/src/jni/androidmediaencoder_jni.h"
+#elif defined(WEBRTC_IOS)
+#include "webrtc/sdk/objc/Framework/Classes/h264_video_toolbox_decoder.h"
+#include "webrtc/sdk/objc/Framework/Classes/h264_video_toolbox_encoder.h"
+#endif
+
 #include "webrtc/base/checks.h"
+#include "webrtc/media/engine/webrtcvideodecoderfactory.h"
+#include "webrtc/media/engine/webrtcvideoencoderfactory.h"
 #include "webrtc/modules/video_coding/codecs/h264/include/h264.h"
 #include "webrtc/modules/video_coding/codecs/test/packet_manipulator.h"
 #include "webrtc/modules/video_coding/codecs/test/videoprocessor.h"
@@ -51,6 +62,7 @@
 // Codec and network settings.
 struct CodecConfigPars {
   VideoCodecType codec_type;
+  bool hw_codec;
   float packet_loss;
   int num_temporal_layers;
   int key_frame_interval;
@@ -117,27 +129,75 @@
 // happen when some significant regression or breakdown occurs.
 class VideoProcessorIntegrationTest : public testing::Test {
  protected:
-  VideoProcessorIntegrationTest() {}
-  virtual ~VideoProcessorIntegrationTest() {}
+  VideoProcessorIntegrationTest() {
+#if defined(WEBRTC_VIDEOPROCESSOR_INTEGRATIONTEST_HW_CODECS_ENABLED) && \
+    defined(WEBRTC_ANDROID)
+    InitializeAndroidObjects();
+
+    external_encoder_factory_.reset(
+        new webrtc_jni::MediaCodecVideoEncoderFactory());
+    external_decoder_factory_.reset(
+        new webrtc_jni::MediaCodecVideoDecoderFactory());
+#endif
+  }
+  virtual ~VideoProcessorIntegrationTest() = default;
 
   void SetUpCodecConfig(const std::string& filename,
                         int width,
                         int height,
                         bool verbose_logging) {
-    if (codec_type_ == kVideoCodecH264) {
-      encoder_.reset(H264Encoder::Create(cricket::VideoCodec("H264")));
-      decoder_.reset(H264Decoder::Create());
-      VideoCodingModule::Codec(kVideoCodecH264, &codec_settings_);
-    } else if (codec_type_ == kVideoCodecVP8) {
-      encoder_.reset(VP8Encoder::Create());
-      decoder_.reset(VP8Decoder::Create());
-      VideoCodingModule::Codec(kVideoCodecVP8, &codec_settings_);
-    } else if (codec_type_ == kVideoCodecVP9) {
-      encoder_.reset(VP9Encoder::Create());
-      decoder_.reset(VP9Decoder::Create());
-      VideoCodingModule::Codec(kVideoCodecVP9, &codec_settings_);
+    if (hw_codec_) {
+#if defined(WEBRTC_VIDEOPROCESSOR_INTEGRATIONTEST_HW_CODECS_ENABLED)
+#if defined(WEBRTC_ANDROID)
+      // In general, external codecs should be destroyed by the factories that
+      // allocated them. For the particular case of the Android
+      // MediaCodecVideo{En,De}coderFactory's, however, it turns out that it is
+      // fine for the std::unique_ptr to destroy the owned codec directly.
+      if (codec_type_ == kVideoCodecH264) {
+        encoder_.reset(external_encoder_factory_->CreateVideoEncoder(
+            cricket::VideoCodec(cricket::kH264CodecName)));
+        decoder_.reset(
+            external_decoder_factory_->CreateVideoDecoder(kVideoCodecH264));
+      } else if (codec_type_ == kVideoCodecVP8) {
+        encoder_.reset(external_encoder_factory_->CreateVideoEncoder(
+            cricket::VideoCodec(cricket::kVp8CodecName)));
+        decoder_.reset(
+            external_decoder_factory_->CreateVideoDecoder(kVideoCodecVP8));
+      } else if (codec_type_ == kVideoCodecVP9) {
+        encoder_.reset(external_encoder_factory_->CreateVideoEncoder(
+            cricket::VideoCodec(cricket::kVp9CodecName)));
+        decoder_.reset(
+            external_decoder_factory_->CreateVideoDecoder(kVideoCodecVP9));
+      }
+#elif defined(WEBRTC_IOS)
+      RTC_DCHECK_EQ(kVideoCodecH264, codec_type_)
+          << "iOS HW codecs only support H264.";
+      encoder_.reset(new H264VideoToolboxEncoder(
+          cricket::VideoCodec(cricket::kH264CodecName)));
+      decoder_.reset(new H264VideoToolboxDecoder());
+#else
+      RTC_NOTREACHED() << "Only support HW codecs on Android and iOS.";
+#endif
+#endif  // WEBRTC_VIDEOPROCESSOR_INTEGRATIONTEST_HW_CODECS_ENABLED
+      RTC_DCHECK(encoder_) << "HW encoder not successfully created.";
+      RTC_DCHECK(decoder_) << "HW decoder not successfully created.";
+    } else {
+      // SW codecs.
+      if (codec_type_ == kVideoCodecH264) {
+        encoder_.reset(
+            H264Encoder::Create(cricket::VideoCodec(cricket::kH264CodecName)));
+        decoder_.reset(H264Decoder::Create());
+      } else if (codec_type_ == kVideoCodecVP8) {
+        encoder_.reset(VP8Encoder::Create());
+        decoder_.reset(VP8Decoder::Create());
+      } else if (codec_type_ == kVideoCodecVP9) {
+        encoder_.reset(VP9Encoder::Create());
+        decoder_.reset(VP9Decoder::Create());
+      }
     }
 
+    VideoCodingModule::Codec(codec_type_, &codec_settings_);
+
     // Configure input filename.
     config_.input_filename = test::ResourcePath(filename, "yuv");
     if (verbose_logging)
@@ -389,6 +449,7 @@
                               RateControlMetrics* rc_metrics) {
     // Codec/config settings.
     codec_type_ = process.codec_type;
+    hw_codec_ = process.hw_codec;
     start_bitrate_ = rate_profile.target_bit_rate[0];
     packet_loss_ = process.packet_loss;
     key_frame_interval_ = process.key_frame_interval;
@@ -501,6 +562,7 @@
 
   static void SetCodecParameters(CodecConfigPars* process_settings,
                                  VideoCodecType codec_type,
+                                 bool hw_codec,
                                  float packet_loss,
                                  int key_frame_interval,
                                  int num_temporal_layers,
@@ -513,6 +575,7 @@
                                  const std::string& filename,
                                  bool verbose_logging) {
     process_settings->codec_type = codec_type;
+    process_settings->hw_codec = hw_codec;
     process_settings->packet_loss = packet_loss;
     process_settings->key_frame_interval = key_frame_interval;
     process_settings->num_temporal_layers = num_temporal_layers,
@@ -528,6 +591,7 @@
 
   static void SetCodecParameters(CodecConfigPars* process_settings,
                                  VideoCodecType codec_type,
+                                 bool hw_codec,
                                  float packet_loss,
                                  int key_frame_interval,
                                  int num_temporal_layers,
@@ -535,7 +599,7 @@
                                  bool denoising_on,
                                  bool frame_dropper_on,
                                  bool spatial_resize_on) {
-    SetCodecParameters(process_settings, codec_type, packet_loss,
+    SetCodecParameters(process_settings, codec_type, hw_codec, packet_loss,
                        key_frame_interval, num_temporal_layers,
                        error_concealment_on, denoising_on, frame_dropper_on,
                        spatial_resize_on, kCifWidth, kCifHeight,
@@ -575,7 +639,9 @@
   }
 
   std::unique_ptr<VideoEncoder> encoder_;
+  std::unique_ptr<cricket::WebRtcVideoEncoderFactory> external_encoder_factory_;
   std::unique_ptr<VideoDecoder> decoder_;
+  std::unique_ptr<cricket::WebRtcVideoDecoderFactory> external_decoder_factory_;
   std::unique_ptr<test::FrameReader> frame_reader_;
   std::unique_ptr<test::FrameWriter> frame_writer_;
   test::PacketReader packet_reader_;
@@ -583,6 +649,7 @@
   test::Stats stats_;
   test::TestConfig config_;
   VideoCodec codec_settings_;
+  // Must be destroyed before |encoder_| and |decoder_|.
   std::unique_ptr<test::VideoProcessor> processor_;
   TemporalLayersFactory tl_factory_;
 
@@ -612,6 +679,7 @@
 
   // Codec and network settings.
   VideoCodecType codec_type_;
+  bool hw_codec_;
   float packet_loss_;
   int num_temporal_layers_;
   int key_frame_interval_;