diff --git a/resources/foreman_128x96.yuv.sha1 b/resources/foreman_128x96.yuv.sha1 new file mode 100644 index 0000000000..0299f5acb4 --- /dev/null +++ b/resources/foreman_128x96.yuv.sha1 @@ -0,0 +1 @@ +bf2fe75c6921c2be9c8cfd1cc00c6540133a2931 \ No newline at end of file diff --git a/resources/foreman_160x120.yuv.sha1 b/resources/foreman_160x120.yuv.sha1 new file mode 100644 index 0000000000..8a932f91bc --- /dev/null +++ b/resources/foreman_160x120.yuv.sha1 @@ -0,0 +1 @@ +315d8a7cc06fe15b68a6f2106d59d25b16270552 \ No newline at end of file diff --git a/resources/foreman_176x144.yuv.sha1 b/resources/foreman_176x144.yuv.sha1 new file mode 100644 index 0000000000..d728721257 --- /dev/null +++ b/resources/foreman_176x144.yuv.sha1 @@ -0,0 +1 @@ +4a38b5629845646844350a4257a60554888509b9 \ No newline at end of file diff --git a/resources/foreman_320x240.yuv.sha1 b/resources/foreman_320x240.yuv.sha1 new file mode 100644 index 0000000000..5dae3f8bab --- /dev/null +++ b/resources/foreman_320x240.yuv.sha1 @@ -0,0 +1 @@ +bb838d60f2a0454af4ca63735d573069858ec004 \ No newline at end of file diff --git a/webrtc/modules/video_coding/BUILD.gn b/webrtc/modules/video_coding/BUILD.gn index a3ad4b37c7..e8ac6719ab 100644 --- a/webrtc/modules/video_coding/BUILD.gn +++ b/webrtc/modules/video_coding/BUILD.gn @@ -341,13 +341,13 @@ if (rtc_include_tests) { ] } - 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 @@ if (rtc_include_tests) { ":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 d8e3c22cd6..01cd4d574d 100644 --- a/webrtc/modules/video_coding/DEPS +++ b/webrtc/modules/video_coding/DEPS @@ -8,3 +8,14 @@ include_rules = [ "+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 0000000000..cb2c5c1f5b --- /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 + +#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 0000000000..a4ec9d2012 --- /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 d4152e0c74..f265230607 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 kDenoisingOn = false; 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 @@ class PlotVideoProcessorIntegrationTest 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 @@ INSTANTIATE_TEST_CASE_P( ::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 cd07a866a6..2acc8484e2 100644 --- a/webrtc/modules/video_coding/codecs/test/videoprocessor.cc +++ b/webrtc/modules/video_coding/codecs/test/videoprocessor.cc @@ -374,7 +374,11 @@ void VideoProcessorImpl::FrameDecoded(const VideoFrame& image) { 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 @@ void VideoProcessorImpl::FrameDecoded(const VideoFrame& image) { // 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 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 736acc64c0..de20020bdc 100644 --- a/webrtc/modules/video_coding/codecs/test/videoprocessor.h +++ b/webrtc/modules/video_coding/codecs/test/videoprocessor.h @@ -205,13 +205,13 @@ class VideoProcessorImpl : public VideoProcessor { } 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 decode_time_ms, rtc::Optional qp) override { - RTC_NOTREACHED(); + Decoded(image, + decode_time_ms ? static_cast(*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 841303e7e4..cb2315db3d 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 @@ TEST_F(VideoProcessorIntegrationTest, Process0PercentPacketLossH264) { 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 @@ TEST_F(VideoProcessorIntegrationTest, Process0PercentPacketLossVP9) { 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 @@ TEST_F(VideoProcessorIntegrationTest, Process5PercentPacketLossVP9) { 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 @@ TEST_F(VideoProcessorIntegrationTest, ProcessNoLossChangeBitRateVP9) { 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 @@ TEST_F(VideoProcessorIntegrationTest, 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 @@ TEST_F(VideoProcessorIntegrationTest, ProcessNoLossDenoiserOnVP9) { 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 @@ TEST_F(VideoProcessorIntegrationTest, 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 @@ TEST_F(VideoProcessorIntegrationTest, ProcessZeroPacketLoss) { 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 @@ TEST_F(VideoProcessorIntegrationTest, Process5PercentPacketLoss) { 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 @@ TEST_F(VideoProcessorIntegrationTest, Process10PercentPacketLoss) { 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 @@ TEST_F(VideoProcessorIntegrationTest, MAYBE_ProcessNoLossChangeBitRateVP8) { 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 @@ TEST_F(VideoProcessorIntegrationTest, 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 @@ TEST_F(VideoProcessorIntegrationTest, MAYBE_ProcessNoLossTemporalLayersVP8) { 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 54700c1b53..e1c085ed43 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 #include +#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 @@ const char kFilenameForemanCif[] = "foreman_cif"; // 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 @@ const float kScaleKeyFrameSize = 0.5f; // 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 @@ class VideoProcessorIntegrationTest : public testing::Test { 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 @@ class VideoProcessorIntegrationTest : public testing::Test { 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 @@ class VideoProcessorIntegrationTest : public testing::Test { 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 @@ class VideoProcessorIntegrationTest : public testing::Test { 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 @@ class VideoProcessorIntegrationTest : public testing::Test { 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 @@ class VideoProcessorIntegrationTest : public testing::Test { } std::unique_ptr encoder_; + std::unique_ptr external_encoder_factory_; std::unique_ptr decoder_; + std::unique_ptr external_decoder_factory_; std::unique_ptr frame_reader_; std::unique_ptr frame_writer_; test::PacketReader packet_reader_; @@ -583,6 +649,7 @@ class VideoProcessorIntegrationTest : public testing::Test { test::Stats stats_; test::TestConfig config_; VideoCodec codec_settings_; + // Must be destroyed before |encoder_| and |decoder_|. std::unique_ptr processor_; TemporalLayersFactory tl_factory_; @@ -612,6 +679,7 @@ class VideoProcessorIntegrationTest : public testing::Test { // Codec and network settings. VideoCodecType codec_type_; + bool hw_codec_; float packet_loss_; int num_temporal_layers_; int key_frame_interval_;