diff --git a/BUILD.gn b/BUILD.gn index 580d34ee97..98faecf7cd 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -713,6 +713,7 @@ if (rtc_include_tests && !build_with_chromium) { # TODO(pbos): Rename test suite, this is no longer "just" for video targets. video_engine_tests_resources = [ + "resources/ConferenceMotion_1280_720_50.yuv", "resources/foreman_cif_short.yuv", "resources/voice_engine/audio_long16.pcm", ] diff --git a/video/corruption_detection/BUILD.gn b/video/corruption_detection/BUILD.gn index 55ab65189d..c7ab70bc8d 100644 --- a/video/corruption_detection/BUILD.gn +++ b/video/corruption_detection/BUILD.gn @@ -61,6 +61,23 @@ rtc_library("frame_instrumentation_generator") { ] } +rtc_library("frame_pair_corruption_score") { + sources = [ + "frame_pair_corruption_score.cc", + "frame_pair_corruption_score.h", + ] + deps = [ + ":corruption_classifier", + ":generic_mapping_functions", + ":halton_frame_sampler", + ":utils", + "../../api:scoped_refptr", + "../../api/video:video_frame", + "../../rtc_base:checks", + "//third_party/abseil-cpp/absl/strings:string_view", + ] +} + rtc_library("generic_mapping_functions") { sources = [ "generic_mapping_functions.cc", @@ -95,6 +112,19 @@ rtc_library("halton_sequence") { deps = [ "../../rtc_base:checks" ] } +rtc_library("utils") { + sources = [ + "utils.cc", + "utils.h", + ] + deps = [ + "../../api:scoped_refptr", + "../../api/video:video_frame", + "//third_party/abseil-cpp/absl/strings:string_view", + "//third_party/abseil-cpp/absl/strings:strings", + ] +} + if (rtc_include_tests) { rtc_library("corruption_classifier_unittest") { testonly = true @@ -133,6 +163,21 @@ if (rtc_include_tests) { ] } + rtc_library("frame_pair_corruption_score_unittest") { + testonly = true + sources = [ "frame_pair_corruption_score_unittest.cc" ] + deps = [ + ":frame_pair_corruption_score", + "../../api:scoped_refptr", + "../../api/video:video_frame", + "../../test:fileutils", + "../../test:test_support", + "../../test:video_test_support", + "//third_party/abseil-cpp/absl/strings:string_view", + ] + data = [ "../../resources/ConferenceMotion_1280_720_50.yuv" ] + } + rtc_library("generic_mapping_functions_unittest") { testonly = true sources = [ "generic_mapping_functions_unittest.cc" ] @@ -163,6 +208,16 @@ if (rtc_include_tests) { ] } + rtc_library("utils_unittest") { + testonly = true + sources = [ "utils_unittest.cc" ] + deps = [ + ":utils", + "../../api/video:video_frame", + "../../test:test_support", + ] + } + rtc_library("corruption_detection_tests") { testonly = true sources = [] @@ -170,9 +225,11 @@ if (rtc_include_tests) { ":corruption_classifier_unittest", ":frame_instrumentation_evaluation_unittest", ":frame_instrumentation_generator_unittest", + ":frame_pair_corruption_score_unittest", ":generic_mapping_functions_unittest", ":halton_frame_sampler_unittest", ":halton_sequence_unittest", + ":utils_unittest", ] } } diff --git a/video/corruption_detection/frame_pair_corruption_score.cc b/video/corruption_detection/frame_pair_corruption_score.cc new file mode 100644 index 0000000000..084005a1dd --- /dev/null +++ b/video/corruption_detection/frame_pair_corruption_score.cc @@ -0,0 +1,99 @@ +/* + * Copyright 2024 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 "video/corruption_detection/frame_pair_corruption_score.h" + +#include +#include + +#include "absl/strings/string_view.h" +#include "api/scoped_refptr.h" +#include "api/video/i420_buffer.h" +#include "api/video/video_frame_buffer.h" +#include "rtc_base/checks.h" +#include "video/corruption_detection/generic_mapping_functions.h" +#include "video/corruption_detection/halton_frame_sampler.h" +#include "video/corruption_detection/utils.h" + +namespace webrtc { +namespace { + +constexpr float kDefaultSampleFraction = 0.5; + +} + +FramePairCorruptionScorer::FramePairCorruptionScorer( + absl::string_view codec_name, + float scale_factor, + std::optional sample_fraction) + : codec_type_(GetVideoCodecType(codec_name)), + sample_fraction_(sample_fraction.value_or(kDefaultSampleFraction)), + corruption_classifier_(scale_factor) { + RTC_CHECK_GE(sample_fraction_, 0) << "Sample fraction must be non-negative."; + RTC_CHECK_LE(sample_fraction_, 1) << "Sample fraction must be less than or " + "equal to 1."; +} + +FramePairCorruptionScorer::FramePairCorruptionScorer( + absl::string_view codec_name, + float growth_rate, + float midpoint, + std::optional sample_fraction) + : codec_type_(GetVideoCodecType(codec_name)), + sample_fraction_(sample_fraction.value_or(kDefaultSampleFraction)), + corruption_classifier_(growth_rate, midpoint) { + RTC_CHECK_GE(sample_fraction_, 0) << "Sample fraction must be non-negative."; + RTC_CHECK_LE(sample_fraction_, 1) << "Sample fraction must be less than or " + "equal to 1."; +} + +double FramePairCorruptionScorer::CalculateScore( + int qp, + I420BufferInterface& reference_buffer, + I420BufferInterface& test_buffer) { + RTC_CHECK_GE(reference_buffer.width(), test_buffer.width()); + RTC_CHECK_GE(reference_buffer.height(), test_buffer.height()); + // Adapted for VP9 and AV1. + RTC_DCHECK_GE(qp, 0); + RTC_DCHECK_LE(qp, 255); + + // We calculate corruption score per "sample" rather than per "pixel", hence + // times "3/2". + const int num_samples = static_cast( + (test_buffer.width() * test_buffer.height() * 3 / 2) * sample_fraction_); + std::vector halton_samples = + halton_frame_sampler_.GetSampleCoordinatesForFrame(num_samples); + RTC_DCHECK_EQ(halton_samples.size(), num_samples); + + scoped_refptr reference_i420_buffer = + GetAsI420Buffer(reference_buffer.ToI420()); + scoped_refptr test_i420_buffer = + GetAsI420Buffer(test_buffer.ToI420()); + + FilterSettings filter_settings = GetCorruptionFilterSettings(qp, codec_type_); + + const std::vector filtered_reference_sample_values = + GetSampleValuesForFrame( + reference_i420_buffer, halton_samples, test_i420_buffer->width(), + test_i420_buffer->height(), filter_settings.std_dev); + const std::vector filtered_test_sample_values = + GetSampleValuesForFrame( + test_i420_buffer, halton_samples, test_i420_buffer->width(), + test_i420_buffer->height(), filter_settings.std_dev); + RTC_CHECK_EQ(filtered_reference_sample_values.size(), + filtered_test_sample_values.size()); + + return corruption_classifier_.CalculateCorruptionProbability( + filtered_reference_sample_values, filtered_test_sample_values, + filter_settings.luma_error_threshold, + filter_settings.chroma_error_threshold); +} + +} // namespace webrtc diff --git a/video/corruption_detection/frame_pair_corruption_score.h b/video/corruption_detection/frame_pair_corruption_score.h new file mode 100644 index 0000000000..31a70a6a74 --- /dev/null +++ b/video/corruption_detection/frame_pair_corruption_score.h @@ -0,0 +1,81 @@ +/* + * Copyright 2024 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 VIDEO_CORRUPTION_DETECTION_FRAME_PAIR_CORRUPTION_SCORE_H_ +#define VIDEO_CORRUPTION_DETECTION_FRAME_PAIR_CORRUPTION_SCORE_H_ + +#include + +#include "absl/strings/string_view.h" +#include "api/video/video_codec_type.h" +#include "api/video/video_frame_buffer.h" +#include "video/corruption_detection/corruption_classifier.h" +#include "video/corruption_detection/halton_frame_sampler.h" + +namespace webrtc { + +// Given a `reference_buffer` and a `test_buffer`, calculates the corruption +// score of the a frame pair. The score is calculated by comparing the sample +// values (each pixel has 3 sample values, the Y, U and V samples) of the +// reference buffer and the test buffer at a set of sampled coordinates. +// +// TODO: bugs.webrtc.org/358039777 - Remove one of the constructors based on +// which mapping function works best in practice. +// There are two constructors for this class. The first one takes a +// `scale_factor` as a parameter, which is used to calculate the scaling +// function. The second one takes a `growth_rate` and a `midpoint` as +// parameters, which are used to calculate the logistic function. +// `sample_fraction` is the fraction of pixels to sample. E.g. if +// `sample_fraction` = 0.5, then we sample 50% of the samples. +// +// The dimension of the `reference_buffer` and `test_buffer` does not need to be +// the same, in order to support downscaling caused by e.g. simulcast and +// scalable encoding. However, the dimensions of the `reference_buffer` must be +// larger than or equal to the dimensions of the `test_buffer`. +class FramePairCorruptionScorer { + public: + // `scale_factor` is the parameter constructing the scaling function, which is + // used to calculate the corruption score. `sample_fraction` is the fraction + // of pixels to sample. + FramePairCorruptionScorer(absl::string_view codec_name, + float scale_factor, + std::optional sample_fraction); + + // `growth_rate` and `midpoint` are parameters constructing a logistic + // function, which is used to calculate the corruption score. + // `sample_fraction` is the fraction of pixels to sample. + FramePairCorruptionScorer(absl::string_view codec_name, + float growth_rate, + float midpoint, + std::optional sample_fraction); + + ~FramePairCorruptionScorer() = default; + + // Returns the corruption score as a probability value between 0 and 1, where + // 0 means no corruption and 1 means that the compressed frame is corrupted. + // + // However, note that the corruption score may not accurately reflect + // corruption. E.g. even if the corruption score is 0, the compressed frame + // may still be corrupted and vice versa. + double CalculateScore(int qp, + I420BufferInterface& reference_buffer, + I420BufferInterface& test_buffer); + + private: + const VideoCodecType codec_type_; + const float sample_fraction_; + + HaltonFrameSampler halton_frame_sampler_; + CorruptionClassifier corruption_classifier_; +}; + +} // namespace webrtc + +#endif // VIDEO_CORRUPTION_DETECTION_FRAME_PAIR_CORRUPTION_SCORE_H_ diff --git a/video/corruption_detection/frame_pair_corruption_score_unittest.cc b/video/corruption_detection/frame_pair_corruption_score_unittest.cc new file mode 100644 index 0000000000..cf6de29bda --- /dev/null +++ b/video/corruption_detection/frame_pair_corruption_score_unittest.cc @@ -0,0 +1,193 @@ +/* + * Copyright 2024 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 "video/corruption_detection/frame_pair_corruption_score.h" + +#include +#include +#include + +#include "absl/strings/string_view.h" +#include "api/scoped_refptr.h" +#include "api/video/i420_buffer.h" +#include "api/video/video_frame_buffer.h" +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/testsupport/file_utils.h" +#include "test/testsupport/frame_reader.h" + +namespace webrtc { +namespace { + +using test::FrameReader; + +// Input video. +constexpr absl::string_view kFilename = "ConferenceMotion_1280_720_50"; +constexpr int kWidth = 1280; +constexpr int kHeight = 720; + +constexpr absl::string_view kCodecName = "VP8"; + +// Scale function parameters. +constexpr float kScaleFactor = 14; + +// Logistic function parameters. +constexpr float kGrowthRate = 0.5; +constexpr float kMidpoint = 3; + +std::unique_ptr GetFrameGenerator() { + std::string clip_path = test::ResourcePath(kFilename, "yuv"); + EXPECT_TRUE(test::FileExists(clip_path)); + return CreateYuvFrameReader(clip_path, {.width = kWidth, .height = kHeight}, + test::YuvFrameReaderImpl::RepeatMode::kPingPong); +} + +scoped_refptr GetDowscaledFrame( + scoped_refptr frame, + float downscale_factor) { + scoped_refptr downscaled_frame = + I420Buffer::Create(kWidth * downscale_factor, kHeight * downscale_factor); + downscaled_frame->ScaleFrom(*frame); + return downscaled_frame; +} + +TEST(FramePairCorruptionScorerTest, SameFrameReturnsNoCorruptionScaleFunction) { + std::unique_ptr frame_reader = GetFrameGenerator(); + scoped_refptr frame = frame_reader->PullFrame(); + + FramePairCorruptionScorer frame_pair_corruption_score( + kCodecName, kScaleFactor, std::nullopt); + EXPECT_LT( + frame_pair_corruption_score.CalculateScore(/*qp=*/1, *frame, *frame), + 0.5); +} + +TEST(FramePairCorruptionScorerTest, + SameFrameReturnsNoCorruptionLogisticFunction) { + std::unique_ptr frame_reader = GetFrameGenerator(); + scoped_refptr frame = frame_reader->PullFrame(); + + FramePairCorruptionScorer frame_pair_corruption_score( + kCodecName, kGrowthRate, kMidpoint, std::nullopt); + EXPECT_LT( + frame_pair_corruption_score.CalculateScore(/*qp=*/1, *frame, *frame), + 0.5); +} + +TEST(FramePairCorruptionScorerTest, + HalfScaledFrameReturnsNoCorruptionScaleFunction) { + std::unique_ptr frame_reader = GetFrameGenerator(); + scoped_refptr frame = frame_reader->PullFrame(); + + FramePairCorruptionScorer frame_pair_corruption_score( + kCodecName, kScaleFactor, std::nullopt); + EXPECT_LT(frame_pair_corruption_score.CalculateScore( + /*qp=*/1, *frame, + *GetDowscaledFrame(frame, /*downscale_factor=*/0.5)), + 0.5); +} + +TEST(FramePairCorruptionScorerTest, + HalfScaledFrameReturnsNoCorruptionLogisticFunction) { + std::unique_ptr frame_reader = GetFrameGenerator(); + scoped_refptr frame = frame_reader->PullFrame(); + + FramePairCorruptionScorer frame_pair_corruption_score( + kCodecName, kGrowthRate, kMidpoint, std::nullopt); + EXPECT_LT(frame_pair_corruption_score.CalculateScore( + /*qp=*/1, *frame, + *GetDowscaledFrame(frame, /*downscale_factor=*/0.5)), + 0.5); +} + +TEST(FramePairCorruptionScorerTest, QuarterScaledFrameReturnsNoCorruption) { + std::unique_ptr frame_reader = GetFrameGenerator(); + scoped_refptr frame = frame_reader->PullFrame(); + + FramePairCorruptionScorer frame_pair_corruption_score( + kCodecName, kScaleFactor, std::nullopt); + EXPECT_LT(frame_pair_corruption_score.CalculateScore( + /*qp=*/1, *frame, + *GetDowscaledFrame(frame, /*downscale_factor=*/0.25)), + 0.5); +} + +TEST(FramePairCorruptionScorerTest, + DifferentFrameResultsInCorruptionScaleFunction) { + std::unique_ptr frame_reader = GetFrameGenerator(); + scoped_refptr frame = frame_reader->PullFrame(); + + // Get frame number 5, which should be different from the first frame, and + // hence, indicate a corruption. + scoped_refptr different_frame = + frame_reader->ReadFrame(/*frame_num=*/5); + + FramePairCorruptionScorer frame_pair_corruption_score( + kCodecName, kScaleFactor, std::nullopt); + EXPECT_GT(frame_pair_corruption_score.CalculateScore(/*qp=*/1, *frame, + *different_frame), + 0.5); +} + +TEST(FramePairCorruptionScorerTest, + DifferentFrameResultsInCorruptionLogisticFunction) { + std::unique_ptr frame_reader = GetFrameGenerator(); + scoped_refptr frame = frame_reader->PullFrame(); + + // Get frame number 5, which should be different from the first frame, and + // hence, indicate a corruption. + scoped_refptr different_frame = + frame_reader->ReadFrame(/*frame_num=*/5); + + FramePairCorruptionScorer frame_pair_corruption_score( + kCodecName, kGrowthRate, kMidpoint, std::nullopt); + EXPECT_GT(frame_pair_corruption_score.CalculateScore(/*qp=*/1, *frame, + *different_frame), + 0.5); +} + +TEST(FramePairCorruptionScorerTest, + HalfScaledDifferentFrameResultsInCorruptionScaleFunction) { + std::unique_ptr frame_reader = GetFrameGenerator(); + scoped_refptr frame = frame_reader->PullFrame(); + + // Get frame number 5, which should be different from the first frame, and + // hence, indicate a corruption. + scoped_refptr different_frame = + frame_reader->ReadFrame(/*frame_num=*/5); + + FramePairCorruptionScorer frame_pair_corruption_score( + kCodecName, kScaleFactor, std::nullopt); + EXPECT_GT(frame_pair_corruption_score.CalculateScore( + /*qp=*/1, *frame, + *GetDowscaledFrame(different_frame, /*downscale_factor=*/0.25)), + 0.5); +} + +TEST(FramePairCorruptionScorerTest, + HalfScaledDifferentFrameResultsInCorruptionLogisticFunction) { + std::unique_ptr frame_reader = GetFrameGenerator(); + scoped_refptr frame = frame_reader->PullFrame(); + + // Get frame number 5, which should be different from the first frame, and + // hence, indicate a corruption. + scoped_refptr different_frame = + frame_reader->ReadFrame(/*frame_num=*/5); + + FramePairCorruptionScorer frame_pair_corruption_score( + kCodecName, kGrowthRate, kMidpoint, std::nullopt); + EXPECT_GT(frame_pair_corruption_score.CalculateScore( + /*qp=*/1, *frame, + *GetDowscaledFrame(different_frame, /*downscale_factor=*/0.25)), + 0.5); +} + +} // namespace +} // namespace webrtc diff --git a/video/corruption_detection/utils.cc b/video/corruption_detection/utils.cc new file mode 100644 index 0000000000..b213dfb509 --- /dev/null +++ b/video/corruption_detection/utils.cc @@ -0,0 +1,70 @@ +/* + * Copyright 2024 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 "video/corruption_detection/utils.h" + +#include "absl/strings/match.h" +#include "absl/strings/string_view.h" +#include "api/video/i420_buffer.h" +#include "api/video/video_codec_type.h" +#include "api/video/video_frame_buffer.h" + +namespace webrtc { +namespace { + +constexpr char kPayloadNameVp8[] = "VP8"; +constexpr char kPayloadNameVp9[] = "VP9"; +constexpr char kPayloadNameAv1[] = "AV1"; +constexpr char kPayloadNameH264[] = "H264"; +constexpr char kPayloadNameH265[] = "H265"; +constexpr char kPayloadNameGeneric[] = "Generic"; + +} // namespace + +// Returns the `VideoCodecType` corresponding to the given `codec_name`. +// The `codec_name` does not need to "exactly" match the namings +// `kPayloadNameXXX`. For example, "VP8", "vp8" and "libvxp_vp8" are all +// valid, and will return the `kVideoCodecVP8`. +// I.e. it does the best to match a codec name to a `VideoCodecType`. +VideoCodecType GetVideoCodecType(absl::string_view codec_name) { + if (absl::StrContainsIgnoreCase(codec_name, kPayloadNameVp8)) + return kVideoCodecVP8; + if (absl::StrContainsIgnoreCase(codec_name, kPayloadNameVp9)) + return kVideoCodecVP9; + if (absl::StrContainsIgnoreCase(codec_name, kPayloadNameAv1)) + return kVideoCodecAV1; + if (absl::StrContainsIgnoreCase(codec_name, kPayloadNameH264)) + return kVideoCodecH264; + if (absl::StrContainsIgnoreCase(codec_name, kPayloadNameH265)) + return kVideoCodecH265; + if (absl::StrContainsIgnoreCase(codec_name, kPayloadNameGeneric)) + return kVideoCodecGeneric; + RTC_FATAL() << "Codec name " << codec_name << " is not supported."; +} + +// Creates a new buffer and copies the pixel data. While the copying is done, +// the type of the buffer is changed from `I420BufferInterface` to `I420Buffer`. +// Observe also that the padding bytes are removed. +scoped_refptr GetAsI420Buffer( + const scoped_refptr i420_buffer_interface) { + // Note: `I420Buffer::Copy` removes padding bytes. + // I.e. if the input is to the left the output will be as to the right. + // +------+--+ +------+ + // | | | | | + // | Y |P | --> | Y | + // | | | | | + // +------+--+ +------+ + scoped_refptr frame_as_i420_buffer = + I420Buffer::Copy(*i420_buffer_interface); + RTC_DCHECK_EQ(frame_as_i420_buffer->StrideY(), frame_as_i420_buffer->width()); + return frame_as_i420_buffer; +} + +} // namespace webrtc diff --git a/video/corruption_detection/utils.h b/video/corruption_detection/utils.h new file mode 100644 index 0000000000..7c1f896166 --- /dev/null +++ b/video/corruption_detection/utils.h @@ -0,0 +1,29 @@ +/* + * Copyright 2024 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 VIDEO_CORRUPTION_DETECTION_UTILS_H_ +#define VIDEO_CORRUPTION_DETECTION_UTILS_H_ + +#include "absl/strings/string_view.h" +#include "api/scoped_refptr.h" +#include "api/video/i420_buffer.h" +#include "api/video/video_codec_type.h" +#include "api/video/video_frame_buffer.h" + +namespace webrtc { + +VideoCodecType GetVideoCodecType(absl::string_view codec_name); + +scoped_refptr GetAsI420Buffer( + scoped_refptr i420_buffer_interface); + +} // namespace webrtc + +#endif // VIDEO_CORRUPTION_DETECTION_UTILS_H_ diff --git a/video/corruption_detection/utils_unittest.cc b/video/corruption_detection/utils_unittest.cc new file mode 100644 index 0000000000..1325f14d6b --- /dev/null +++ b/video/corruption_detection/utils_unittest.cc @@ -0,0 +1,38 @@ +/* + * Copyright 2024 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 "video/corruption_detection/utils.h" + +#include "api/video/video_codec_type.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +#if GTEST_HAS_DEATH_TEST +using ::testing::_; +#endif // GTEST_HAS_DEATH_TEST + +TEST(UtilsTest, FindCodecFromString) { + EXPECT_EQ(GetVideoCodecType(/*codec_name=*/"VP8"), kVideoCodecVP8); + EXPECT_EQ(GetVideoCodecType(/*codec_name=*/"libvpx-vp9"), kVideoCodecVP9); + EXPECT_EQ(GetVideoCodecType(/*codec_name=*/"ImprovedAV1"), kVideoCodecAV1); + EXPECT_EQ(GetVideoCodecType(/*codec_name=*/"lets_use_h264"), kVideoCodecH264); +} + +#if GTEST_HAS_DEATH_TEST +TEST(UtilsTest, IfCodecDoesNotExistRaiseError) { + EXPECT_DEATH(GetVideoCodecType(/*codec_name=*/"Not_a_codec"), _); +} +#endif // GTEST_HAS_DEATH_TEST + +} // namespace +} // namespace webrtc