MediaRecorder: measure frequencies for codec requests.

This change starts measuring codecs for codec requests to
isTypeSupported and the MediaRecorder ctor.

The should not change anything w.r.t functionality.

Bug: 450757339
Change-Id: I17eceb7fa708951a224645157ba67468c395dccd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7036832
Reviewed-by: Henrik Boström <hbos@chromium.org>
Reviewed-by: Johannes Kron <kron@chromium.org>
Commit-Queue: Markus Handell <handellm@google.com>
Cr-Commit-Position: refs/heads/main@{#1529417}
diff --git a/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc b/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc
index e12d2305..687386d 100644
--- a/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc
+++ b/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc
@@ -27,6 +27,7 @@
 #include "third_party/blink/renderer/core/inspector/console_message.h"
 #include "third_party/blink/renderer/modules/event_target_modules.h"
 #include "third_party/blink/renderer/modules/mediarecorder/blob_event.h"
+#include "third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.h"
 #include "third_party/blink/renderer/modules/mediarecorder/video_track_recorder.h"
 #include "third_party/blink/renderer/platform/blob/blob_data.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
@@ -402,8 +403,9 @@
   // not available to support the concrete media encoding.
   // https://w3c.github.io/mediacapture-record/#dom-mediarecorder-istypesupported
   ContentType content_type(type);
-  bool result = handler->CanSupportMimeType(content_type.GetType(),
-                                            content_type.Parameter("codecs"));
+  bool result = handler->CanSupportMimeType(
+      content_type.GetType(), content_type.Parameter("codecs"),
+      MediaRecorderHandler::CanSupportMimeTypeCaller::kIsTypeSupported);
   if (IdentifiabilityStudySettings::Get()->ShouldSampleType(
           blink::IdentifiableSurface::Type::kMediaRecorder_IsTypeSupported)) {
     blink::IdentifiabilityMetricBuilder(context->UkmSourceID())
diff --git a/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.cc b/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.cc
index 3d0944a4..b274ada 100644
--- a/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.cc
+++ b/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.cc
@@ -24,6 +24,7 @@
 #include "media/base/audio_codecs.h"
 #include "media/base/audio_parameters.h"
 #include "media/base/decoder_buffer.h"
+#include "media/base/media_serializers_base.h"
 #include "media/base/media_switches.h"
 #include "media/base/mime_util.h"
 #include "media/base/supported_types.h"
@@ -283,7 +284,8 @@
       media_stream_observer_(std::make_unique<MediaStreamObserver>(this)) {}
 
 bool MediaRecorderHandler::CanSupportMimeType(const String& type,
-                                              const String& web_codecs) {
+                                              const String& web_codecs,
+                                              CanSupportMimeTypeCaller caller) {
   DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
   // An empty |type| means MediaRecorderHandler can choose its preferred codecs.
   if (type.empty())
@@ -294,6 +296,49 @@
   if (!video && !audio)
     return false;
 
+  std::vector<std::string> codecs_list;
+  media::SplitCodecs(web_codecs.Utf8(), &codecs_list);
+
+  for (const auto& codec : codecs_list) {
+    const auto profile = VideoStringToCodecProfile(String(codec));
+    const bool can_support = CanSupportMimeTypeForCodec(type, codec);
+
+    Vector<String> uma_key_vector;
+    uma_key_vector.push_back("Media.MediaRecorder.Codec");
+    uma_key_vector.push_back(StringFromCanSupportMimeTypeCaller(caller));
+    uma_key_vector.push_back(can_support ? "Supported" : "Unsupported");
+    StringBuilder builder;
+    builder.AppendRange(uma_key_vector, ".");
+    String uma_handle = builder.ReleaseString();
+    base::UmaHistogramEnumeration(
+        uma_handle.Ascii().c_str(),
+        VideoTrackRecorder::CodecHistogramFromCodecId(profile.codec_id));
+
+    if (!can_support) {
+      return false;
+    }
+  }
+  return true;
+}
+
+const char* MediaRecorderHandler::StringFromCanSupportMimeTypeCaller(
+    CanSupportMimeTypeCaller caller) {
+  switch (caller) {
+    case CanSupportMimeTypeCaller::kMediaRecorderCtor:
+      return "MediaRecorderCtor";
+    case CanSupportMimeTypeCaller::kIsTypeSupported:
+      return "IsTypeSupported";
+    case CanSupportMimeTypeCaller::kEncodingInfo:
+      return "EncodingInfo";
+    default:
+      return "Test";
+  }
+}
+
+bool MediaRecorderHandler::CanSupportMimeTypeForCodec(const String& type,
+                                                      std::string_view codec) {
+  const bool video = CanSupportVideoType(type);
+
   // Both |video| and |audio| support empty |codecs|; |type| == "video" supports
   // vp8, vp9, h264, avc1, avc3, av01, av1, hvc1, hev1, opus, or pcm; |type| =
   // "audio", supports opus or pcm (little-endian 32-bit float).
@@ -313,14 +358,14 @@
       "opus", "pcm"};
   static const char* const kAudioCodecs[] = {"opus", "pcm"};
 
-  auto* const* relevant_codecs_begin =
-      video ? std::begin(kVideoCodecs) : std::begin(kAudioCodecs);
-  auto* const* relevant_codecs_end =
-      video ? std::end(kVideoCodecs) : std::end(kAudioCodecs);
+  base::span<const char* const> relevant_codecs;
+  if (video) {
+    relevant_codecs = kVideoCodecs;
+  } else {
+    relevant_codecs = kAudioCodecs;
+  }
 
-  bool mp4_mime_type = false;
-
-  mp4_mime_type = IsAllowedMp4Type(type);
+  const bool mp4_mime_type = IsAllowedMp4Type(type);
   if (mp4_mime_type) {
     static const char* const kVideoCodecsForMP4[] = {
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
@@ -337,152 +382,148 @@
 #endif
         "opus"};
 
-    relevant_codecs_begin =
-        video ? std::begin(kVideoCodecsForMP4) : std::begin(kAudioCodecsForMp4);
-    relevant_codecs_end =
-        video ? std::end(kVideoCodecsForMP4) : std::end(kAudioCodecsForMp4);
+    if (video) {
+      relevant_codecs = kVideoCodecsForMP4;
+    } else {
+      relevant_codecs = kAudioCodecsForMp4;
+    }
   }
 
-  std::vector<std::string> codecs_list;
-  media::SplitCodecs(web_codecs.Utf8(), &codecs_list);
+  // For `video/x-matroska`, `video/webm`, and `audio/webm`, trim the content
+  // after first '.' to do the case insensitive match based on historical
+  // logic. For `video/mp4`, and `audio/mp4`, preserve the whole string to do
+  // the case sensitive match.
+  String codec_string = String::FromUTF8(codec);
+  if (!mp4_mime_type) {
+    auto str_index = codec.find_first_of('.');
+    if (str_index != std::string::npos) {
+      codec_string = String::FromUTF8(codec.substr(0, str_index));
+    }
+  }
 
-  for (const auto& codec : codecs_list) {
-    // For `video/x-matroska`, `video/webm`, and `audio/webm`, trim the content
-    // after first '.' to do the case insensitive match based on historical
-    // logic. For `video/mp4`, and `audio/mp4`, preserve the whole string to do
-    // the case sensitive match.
-    String codec_string = String::FromUTF8(codec);
-    if (!mp4_mime_type) {
-      auto str_index = codec.find_first_of('.');
-      if (str_index != std::string::npos) {
-        codec_string = String::FromUTF8(codec.substr(0, str_index));
+  bool match =
+      std::any_of(relevant_codecs.begin(), relevant_codecs.end(),
+                  [&codec_string, &mp4_mime_type](const char* name) {
+                    if (mp4_mime_type) {
+                      return EqualStringView(codec_string, name);
+                    } else {
+                      return EqualIgnoringASCIICase(codec_string, name);
+                    }
+                  });
+
+  if (video) {
+    // Currently `video/x-matroska` is not supported by mime util, replace to
+    // `video/mp4` instead.
+    //
+    // TODO(crbug.com/40276507): rework MimeUtil such that clients can inject
+    // their own supported mime+codec types.
+    std::string mime_type = EqualIgnoringASCIICase(type, "video/x-matroska")
+                                ? "video/mp4"
+                                : type.Ascii();
+    // It supports full qualified string for `avc1`, `avc3`, `hvc1`, `hev1`,
+    // and `av01` codecs, e.g.
+    //  `avc1.<profile>.<level>`,
+    //  `avc3.<profile>.<level>`,
+    //  `hvc1.<profile>.<profile_compatibility>.<tier and level>.*`,
+    //  `hev1.<profile>.<profile_compatibility>.<tier and level>.*`,
+    //  `av01.<profile>.<level>.<color depth>.*`.
+    auto parsed_result =
+        media::ParseVideoCodecString(mime_type, codec,
+                                     /*allow_ambiguous_matches=*/false);
+    if (!match && mp4_mime_type) {
+      match =
+          parsed_result && (parsed_result->codec == media::VideoCodec::kH264 ||
+                            parsed_result->codec == media::VideoCodec::kAV1);
+    }
+
+    if (codec_string.StartsWith("h264", kTextCaseASCIIInsensitive) ||
+        codec_string.StartsWith("avc1", kTextCaseASCIIInsensitive) ||
+        codec_string.StartsWith("avc3", kTextCaseASCIIInsensitive)) {
+      // In the case of the `video/mp4` mimetype, when the profile can be
+      // parsed, make use of the parsed profile.
+      const media::VideoCodecProfile profile =
+          (mp4_mime_type && parsed_result)
+              ? parsed_result->profile
+              : media::VideoCodecProfile::H264PROFILE_BASELINE;
+
+      // If the profile is not any of the H.264 baseline, main, extended, and
+      // high profiles, reject it.
+      if (profile != media::VideoCodecProfile::H264PROFILE_BASELINE &&
+          profile != media::VideoCodecProfile::H264PROFILE_MAIN &&
+          profile != media::VideoCodecProfile::H264PROFILE_EXTENDED &&
+          profile != media::VideoCodecProfile::H264PROFILE_HIGH) {
+        match = false;
+      }
+
+      // If the profile is not supported by either the HW or the SW encoder,
+      // reject it.
+      if (!media::IsEncoderSupportedVideoType(
+              {media::VideoCodec::kH264, profile})) {
+        match = false;
       }
     }
 
-    bool match =
-        std::any_of(relevant_codecs_begin, relevant_codecs_end,
-                    [&codec_string, &mp4_mime_type](const char* name) {
-                      if (mp4_mime_type) {
-                        return EqualStringView(codec_string, name);
-                      } else {
-                        return EqualIgnoringASCIICase(codec_string, name);
-                      }
-                    });
+    if (codec_string.StartsWith("av1", kTextCaseASCIIInsensitive) ||
+        codec_string.StartsWith("av01", kTextCaseASCIIInsensitive)) {
+      // In the case of the `video/mp4` mimetype, when the profile can be
+      // parsed, make use of the parsed profile.
+      const media::VideoCodecProfile profile =
+          (mp4_mime_type && parsed_result)
+              ? parsed_result->profile
+              : media::VideoCodecProfile::AV1PROFILE_PROFILE_MAIN;
 
-    if (video) {
-      // Currently `video/x-matroska` is not supported by mime util, replace to
-      // `video/mp4` instead.
-      //
-      // TODO(crbug.com/40276507): rework MimeUtil such that clients can inject
-      // their own supported mime+codec types.
-      std::string mime_type = EqualIgnoringASCIICase(type, "video/x-matroska")
-                                  ? "video/mp4"
-                                  : type.Ascii();
-      // It supports full qualified string for `avc1`, `avc3`, `hvc1`, `hev1`,
-      // and `av01` codecs, e.g.
-      //  `avc1.<profile>.<level>`,
-      //  `avc3.<profile>.<level>`,
-      //  `hvc1.<profile>.<profile_compatibility>.<tier and level>.*`,
-      //  `hev1.<profile>.<profile_compatibility>.<tier and level>.*`,
-      //  `av01.<profile>.<level>.<color depth>.*`.
-      auto parsed_result =
-          media::ParseVideoCodecString(mime_type, codec,
-                                       /*allow_ambiguous_matches=*/false);
-      if (!match && mp4_mime_type) {
-        match = parsed_result &&
-                (parsed_result->codec == media::VideoCodec::kH264 ||
-                 parsed_result->codec == media::VideoCodec::kAV1);
+      // If the profile does not match the AV1 main profile, reject it.
+      if (profile != media::VideoCodecProfile::AV1PROFILE_PROFILE_MAIN) {
+        match = false;
       }
 
-      if (codec_string.StartsWith("h264", kTextCaseASCIIInsensitive) ||
-          codec_string.StartsWith("avc1", kTextCaseASCIIInsensitive) ||
-          codec_string.StartsWith("avc3", kTextCaseASCIIInsensitive)) {
-        // In the case of the `video/mp4` mimetype, when the profile can be
-        // parsed, make use of the parsed profile.
-        const media::VideoCodecProfile profile =
-            (mp4_mime_type && parsed_result)
-                ? parsed_result->profile
-                : media::VideoCodecProfile::H264PROFILE_BASELINE;
-
-        // If the profile is not any of the H.264 baseline, main, extended, and
-        // high profiles, reject it.
-        if (profile != media::VideoCodecProfile::H264PROFILE_BASELINE &&
-            profile != media::VideoCodecProfile::H264PROFILE_MAIN &&
-            profile != media::VideoCodecProfile::H264PROFILE_EXTENDED &&
-            profile != media::VideoCodecProfile::H264PROFILE_HIGH) {
-          match = false;
-        }
-
-        // If the profile is not supported by either the HW or the SW encoder,
-        // reject it.
-        if (!media::IsEncoderSupportedVideoType(
-                {media::VideoCodec::kH264, profile})) {
-          match = false;
-        }
+      if (match) {
+        base::UmaHistogramBoolean(
+            "Media.MediaRecorder.HasCorrectAV1CodecString",
+            codec_string.StartsWith("av01", kTextCaseASCIIInsensitive));
       }
 
-      if (codec_string.StartsWith("av1", kTextCaseASCIIInsensitive) ||
-          codec_string.StartsWith("av01", kTextCaseASCIIInsensitive)) {
-        // In the case of the `video/mp4` mimetype, when the profile can be
-        // parsed, make use of the parsed profile.
-        const media::VideoCodecProfile profile =
-            (mp4_mime_type && parsed_result)
-                ? parsed_result->profile
-                : media::VideoCodecProfile::AV1PROFILE_PROFILE_MAIN;
-
-        // If the profile does not match the AV1 main profile, reject it.
-        if (profile != media::VideoCodecProfile::AV1PROFILE_PROFILE_MAIN) {
-          match = false;
-        }
-
-        if (match) {
-          base::UmaHistogramBoolean(
-              "Media.MediaRecorder.HasCorrectAV1CodecString",
-              codec_string.StartsWith("av01", kTextCaseASCIIInsensitive));
-        }
-
-        // If the profile is not supported by either the HW or the SW encoder,
-        // reject it.
-        if (!media::IsEncoderSupportedVideoType(
-                {media::VideoCodec::kAV1, profile})) {
-          match = false;
-        }
+      // If the profile is not supported by either the HW or the SW encoder,
+      // reject it.
+      if (!media::IsEncoderSupportedVideoType(
+              {media::VideoCodec::kAV1, profile})) {
+        match = false;
       }
+    }
 
 #if BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
-      // Support `hev1` tag as it allow parameter sets write into the bitstream,
-      // which is the only option if the MediaStream has dynamically changing
-      // resolution. Also support `hvc1` tag for better compatibility given the
-      // fact that QuickTime and Safari only support playing `hvc1` tag mp4
-      // videos, and Apple only recommend using `hvc1` for HLS.
-      // https://developer.apple.com/documentation/http-live-streaming/hls-authoring-specification-for-apple-devices#2969487
-      if (codec_string.StartsWith("hvc1", kTextCaseASCIIInsensitive) ||
-          codec_string.StartsWith("hev1", kTextCaseASCIIInsensitive)) {
-        match =
-            // If the profile can be parsed, ensure it must be HEVC main
-            // profile.
-            (parsed_result && parsed_result->profile ==
-                                  media::VideoCodecProfile::HEVCPROFILE_MAIN) &&
-            // Only if the feature is enabled.
-            base::FeatureList::IsEnabled(media::kMediaRecorderHEVCSupport) &&
-            // Only `mkv` and `mp4` are supported, `webm` is not supported.
-            !EqualIgnoringASCIICase(type, "video/webm") &&
-            // Only if there are platform HEVC main profile support.
-            media::IsEncoderSupportedVideoType(
-                {media::VideoCodec::kHEVC,
-                 media::VideoCodecProfile::HEVCPROFILE_MAIN});
-      }
+    // Support `hev1` tag as it allow parameter sets write into the bitstream,
+    // which is the only option if the MediaStream has dynamically changing
+    // resolution. Also support `hvc1` tag for better compatibility given the
+    // fact that QuickTime and Safari only support playing `hvc1` tag mp4
+    // videos, and Apple only recommend using `hvc1` for HLS.
+    // https://developer.apple.com/documentation/http-live-streaming/hls-authoring-specification-for-apple-devices#2969487
+    if (codec_string.StartsWith("hvc1", kTextCaseASCIIInsensitive) ||
+        codec_string.StartsWith("hev1", kTextCaseASCIIInsensitive)) {
+      match =
+          // If the profile can be parsed, ensure it must be HEVC main
+          // profile.
+          (parsed_result && parsed_result->profile ==
+                                media::VideoCodecProfile::HEVCPROFILE_MAIN) &&
+          // Only if the feature is enabled.
+          base::FeatureList::IsEnabled(media::kMediaRecorderHEVCSupport) &&
+          // Only `mkv` and `mp4` are supported, `webm` is not supported.
+          !EqualIgnoringASCIICase(type, "video/webm") &&
+          // Only if there are platform HEVC main profile support.
+          media::IsEncoderSupportedVideoType(
+              {media::VideoCodec::kHEVC,
+               media::VideoCodecProfile::HEVCPROFILE_MAIN});
+    }
 #endif
-    }
+  }
 
-    if (!match) {
-      return false;
-    }
+  if (!match) {
+    return false;
+  }
 
-    if (codec_string == "mp4a.40.2" &&
-        !media::MojoAudioEncoder::IsSupported(media::AudioCodec::kAAC)) {
-      return false;
-    }
+  if (codec_string == "mp4a.40.2" &&
+      !media::MojoAudioEncoder::IsSupported(media::AudioCodec::kAAC)) {
+    return false;
   }
   return true;
 }
@@ -500,7 +541,8 @@
 
   type_ = type;
 
-  if (!CanSupportMimeType(type_, codecs)) {
+  if (!CanSupportMimeType(type_, codecs,
+                          CanSupportMimeTypeCaller::kMediaRecorderCtor)) {
     DLOG(ERROR) << "Unsupported " << type.Utf8() << ";codecs=" << codecs.Utf8();
     return false;
   }
@@ -786,7 +828,8 @@
     codec = configuration.audio_configuration->codec;
   }
 
-  info->supported = CanSupportMimeType(mime_type, codec);
+  info->supported = CanSupportMimeType(mime_type, codec,
+                                       CanSupportMimeTypeCaller::kEncodingInfo);
 
   if (configuration.video_configuration && info->supported) {
     VideoTrackRecorder::CodecProfile codec_profile =
diff --git a/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.h b/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.h
index 30fb95e..4fb1e4c 100644
--- a/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.h
+++ b/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.h
@@ -71,6 +71,14 @@
       public VideoTrackRecorder::CallbackInterface,
       public AudioTrackRecorder::CallbackInterface {
  public:
+  // Caller for CanSupportMimeType. Influences emitted UMA histograms.
+  enum class CanSupportMimeTypeCaller {
+    kIsTypeSupported,
+    kMediaRecorderCtor,
+    kEncodingInfo,
+    kTest,
+  };
+
   MediaRecorderHandler(
       scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner,
       KeyFrameRequestProcessor::Configuration key_frame_config);
@@ -84,7 +92,12 @@
   // sufficient resources are not available to support the concrete media
   // encoding."
   // [1] https://w3c.github.io/mediacapture-record/MediaRecorder.html#methods
-  bool CanSupportMimeType(const String& type, const String& web_codecs);
+  bool CanSupportMimeType(const String& type,
+                          const String& web_codecs,
+                          CanSupportMimeTypeCaller caller);
+  bool CanSupportMimeTypeForCodec(const String& type, std::string_view codec);
+  static const char* StringFromCanSupportMimeTypeCaller(
+      CanSupportMimeTypeCaller);
   bool Initialize(MediaRecorder* client,
                   MediaStreamDescriptor* media_stream,
                   const String& type,
diff --git a/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler_unittest.cc b/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler_unittest.cc
index eaa5b2d..f0a9c6cc 100644
--- a/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler_unittest.cc
+++ b/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler_unittest.cc
@@ -353,6 +353,12 @@
   }
 #endif
 
+  bool CanSupportMimeType(const String& mime_type, const String& codecs) {
+    return media_recorder_handler_->CanSupportMimeType(
+        mime_type, codecs,
+        MediaRecorderHandler::CanSupportMimeTypeCaller::kTest);
+  }
+
   test::TaskEnvironment task_environment_;
   ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform_;
   MockMediaStreamRegistry registry_;
@@ -428,71 +434,55 @@
 // combinations and unsupported ones.
 TEST_P(MediaRecorderHandlerTest, CanSupportMimeType) {
   const String unsupported_mime_type("video/mpeg");
-  EXPECT_FALSE(media_recorder_handler_->CanSupportMimeType(
-      unsupported_mime_type, String()));
+  EXPECT_FALSE(CanSupportMimeType(unsupported_mime_type, String()));
 
   const String mime_type_video("video/webm");
-  EXPECT_TRUE(
-      media_recorder_handler_->CanSupportMimeType(mime_type_video, String()));
+  EXPECT_TRUE(CanSupportMimeType(mime_type_video, String()));
   const String mime_type_video_uppercase("video/WEBM");
-  EXPECT_TRUE(media_recorder_handler_->CanSupportMimeType(
-      mime_type_video_uppercase, String()));
+  EXPECT_TRUE(CanSupportMimeType(mime_type_video_uppercase, String()));
   const String example_good_codecs_1("vp8");
-  EXPECT_TRUE(media_recorder_handler_->CanSupportMimeType(
-      mime_type_video, example_good_codecs_1));
+  EXPECT_TRUE(CanSupportMimeType(mime_type_video, example_good_codecs_1));
   const String example_good_codecs_2("vp9,opus");
-  EXPECT_TRUE(media_recorder_handler_->CanSupportMimeType(
-      mime_type_video, example_good_codecs_2));
+  EXPECT_TRUE(CanSupportMimeType(mime_type_video, example_good_codecs_2));
   const String example_good_codecs_3("VP9,opus");
-  EXPECT_TRUE(media_recorder_handler_->CanSupportMimeType(
-      mime_type_video, example_good_codecs_3));
+  EXPECT_TRUE(CanSupportMimeType(mime_type_video, example_good_codecs_3));
   const String example_good_codecs_4("H264");
-  EXPECT_EQ(media_recorder_handler_->CanSupportMimeType(mime_type_video,
-                                                        example_good_codecs_4),
+  EXPECT_EQ(CanSupportMimeType(mime_type_video, example_good_codecs_4),
             BUILDFLAG(ENABLE_OPENH264));
 
   const String example_unsupported_codecs_1("daala");
-  EXPECT_FALSE(media_recorder_handler_->CanSupportMimeType(
-      mime_type_video, example_unsupported_codecs_1));
+  EXPECT_FALSE(
+      CanSupportMimeType(mime_type_video, example_unsupported_codecs_1));
 
   const String mime_type_audio("audio/webm");
-  EXPECT_TRUE(
-      media_recorder_handler_->CanSupportMimeType(mime_type_audio, String()));
+  EXPECT_TRUE(CanSupportMimeType(mime_type_audio, String()));
   const String example_good_codecs_5("opus");
-  EXPECT_TRUE(media_recorder_handler_->CanSupportMimeType(
-      mime_type_audio, example_good_codecs_5));
+  EXPECT_TRUE(CanSupportMimeType(mime_type_audio, example_good_codecs_5));
   const String example_good_codecs_6("OpUs");
-  EXPECT_TRUE(media_recorder_handler_->CanSupportMimeType(
-      mime_type_audio, example_good_codecs_6));
+  EXPECT_TRUE(CanSupportMimeType(mime_type_audio, example_good_codecs_6));
   const String example_good_codecs_7("pcm");
-  EXPECT_TRUE(media_recorder_handler_->CanSupportMimeType(
-      mime_type_audio, example_good_codecs_7));
+  EXPECT_TRUE(CanSupportMimeType(mime_type_audio, example_good_codecs_7));
 
   const String example_good_codecs_8("AV01,opus");
-  EXPECT_EQ(media_recorder_handler_->CanSupportMimeType(mime_type_video,
-                                                        example_good_codecs_8),
+  EXPECT_EQ(CanSupportMimeType(mime_type_video, example_good_codecs_8),
             BUILDFLAG(ENABLE_LIBAOM));
 
   const String example_good_codecs_9("avc1");
   const String example_good_codecs_10("avc3");
   const String example_good_codecs_11("avc1.42E01E");
   const String example_good_codecs_12("avc3.42E01E");
-  EXPECT_EQ(media_recorder_handler_->CanSupportMimeType(mime_type_video,
-                                                        example_good_codecs_9),
+  EXPECT_EQ(CanSupportMimeType(mime_type_video, example_good_codecs_9),
             BUILDFLAG(ENABLE_OPENH264));
-  EXPECT_EQ(media_recorder_handler_->CanSupportMimeType(mime_type_video,
-                                                        example_good_codecs_10),
+  EXPECT_EQ(CanSupportMimeType(mime_type_video, example_good_codecs_10),
             BUILDFLAG(ENABLE_OPENH264));
-  EXPECT_EQ(media_recorder_handler_->CanSupportMimeType(mime_type_video,
-                                                        example_good_codecs_11),
+  EXPECT_EQ(CanSupportMimeType(mime_type_video, example_good_codecs_11),
             BUILDFLAG(ENABLE_OPENH264));
-  EXPECT_EQ(media_recorder_handler_->CanSupportMimeType(mime_type_video,
-                                                        example_good_codecs_12),
+  EXPECT_EQ(CanSupportMimeType(mime_type_video, example_good_codecs_12),
             BUILDFLAG(ENABLE_OPENH264));
 
   const String example_unsupported_codecs_2("vorbis");
-  EXPECT_FALSE(media_recorder_handler_->CanSupportMimeType(
-      mime_type_audio, example_unsupported_codecs_2));
+  EXPECT_FALSE(
+      CanSupportMimeType(mime_type_audio, example_unsupported_codecs_2));
 
   // HEVC only supports hardware encoding, and whether hardware encoding is
   // supported depends on the supported profiles retrieved by the
@@ -500,12 +490,12 @@
   // unable to know if HEVC is supported or not, so it should always return
   // false here.
   const String example_good_codecs_with_supported_tag("hev1.1.6.L93.B0");
-  EXPECT_FALSE(media_recorder_handler_->CanSupportMimeType(
-      mime_type_video, example_good_codecs_with_supported_tag));
+  EXPECT_FALSE(CanSupportMimeType(mime_type_video,
+                                  example_good_codecs_with_supported_tag));
 
   const String example_good_codecs_with_supported_tag_2("hvc1.1.6.L93.B0");
-  EXPECT_FALSE(media_recorder_handler_->CanSupportMimeType(
-      mime_type_video, example_good_codecs_with_supported_tag_2));
+  EXPECT_FALSE(CanSupportMimeType(mime_type_video,
+                                  example_good_codecs_with_supported_tag_2));
 }
 
 // Checks that it uses the specified bitrate mode.
@@ -1076,14 +1066,13 @@
   // success cases.
   for (const auto& type : good_mp4_video_mime_types) {
     for (const auto& codec : good_mp4_video_codecs) {
-      EXPECT_EQ(media_recorder_handler_->CanSupportMimeType(type, codec),
-                IsVideoCodecSupported(codec));
+      EXPECT_EQ(CanSupportMimeType(type, codec), IsVideoCodecSupported(codec));
     }
   }
 
   for (const auto& type : good_mp4_video_mime_types) {
     for (const auto& codec : good_mp4_audio_codecs) {
-      EXPECT_EQ(media_recorder_handler_->CanSupportMimeType(type, codec),
+      EXPECT_EQ(CanSupportMimeType(type, codec),
                 IsTargetAudioCodecSupported(codec));
     }
   }
@@ -1094,12 +1083,10 @@
         const bool supported = IsVideoCodecSupported(video_codec) &&
                                IsTargetAudioCodecSupported(audio_codec);
         String codecs = video_codec + "," + audio_codec;
-        EXPECT_EQ(media_recorder_handler_->CanSupportMimeType(type, codecs),
-                  supported);
+        EXPECT_EQ(CanSupportMimeType(type, codecs), supported);
 
         String codecs2 = audio_codec + "," + video_codec;
-        EXPECT_EQ(media_recorder_handler_->CanSupportMimeType(type, codecs2),
-                  supported);
+        EXPECT_EQ(CanSupportMimeType(type, codecs2), supported);
       }
     }
   }
@@ -1107,27 +1094,26 @@
   // failure cases.
   for (const auto& type : bad_mp4_video_mime_types) {
     for (const auto& codec : good_mp4_video_codecs) {
-      EXPECT_FALSE(media_recorder_handler_->CanSupportMimeType(type, codec));
+      EXPECT_FALSE(CanSupportMimeType(type, codec));
     }
   }
 
   for (const auto& type : good_mp4_video_mime_types) {
     for (const auto& codec : bad_mp4_video_codecs) {
-      EXPECT_FALSE(media_recorder_handler_->CanSupportMimeType(type, codec));
+      EXPECT_FALSE(CanSupportMimeType(type, codec));
     }
   }
 #else
   // success cases.
   for (const auto& type : good_mp4_video_mime_types) {
     for (const auto& codec : good_mp4_video_codecs_non_proprietary) {
-      EXPECT_EQ(media_recorder_handler_->CanSupportMimeType(type, codec),
-                IsVideoCodecSupported(codec));
+      EXPECT_EQ(CanSupportMimeType(type, codec), IsVideoCodecSupported(codec));
     }
   }
 
   for (const auto& type : good_mp4_video_mime_types) {
     for (const auto& codec : good_mp4_audio_codecs_non_proprietary) {
-      EXPECT_TRUE(media_recorder_handler_->CanSupportMimeType(type, codec));
+      EXPECT_TRUE(CanSupportMimeType(type, codec));
     }
   }
 
@@ -1135,11 +1121,11 @@
     for (const auto& video_codec : good_mp4_video_codecs_non_proprietary) {
       for (const auto& audio_codec : good_mp4_audio_codecs_non_proprietary) {
         String codecs = video_codec + "," + audio_codec;
-        EXPECT_EQ(media_recorder_handler_->CanSupportMimeType(type, codecs),
+        EXPECT_EQ(CanSupportMimeType(type, codecs),
                   IsVideoCodecSupported(video_codec));
 
         String codecs2 = audio_codec + "," + video_codec;
-        EXPECT_EQ(media_recorder_handler_->CanSupportMimeType(type, codecs2),
+        EXPECT_EQ(CanSupportMimeType(type, codecs2),
                   IsVideoCodecSupported(video_codec));
       }
     }
@@ -1148,7 +1134,7 @@
   // failure cases.
   for (const auto& type : good_mp4_video_mime_types) {
     for (const auto& codec : bad_mp4_video_codecs) {
-      EXPECT_FALSE(media_recorder_handler_->CanSupportMimeType(type, codec));
+      EXPECT_FALSE(CanSupportMimeType(type, codec));
     }
   }
 #endif
@@ -1158,7 +1144,7 @@
   // success cases.
   for (const auto& type : good_mp4_audio_mime_types) {
     for (const auto& codec : good_mp4_audio_codecs) {
-      EXPECT_EQ(media_recorder_handler_->CanSupportMimeType(type, codec),
+      EXPECT_EQ(CanSupportMimeType(type, codec),
                 IsTargetAudioCodecSupported(codec));
     }
   }
@@ -1166,19 +1152,19 @@
   // failure cases.
   for (const auto& type : bad_mp4_audio_mime_types) {
     for (const auto& codec : good_mp4_audio_codecs) {
-      EXPECT_FALSE(media_recorder_handler_->CanSupportMimeType(type, codec));
+      EXPECT_FALSE(CanSupportMimeType(type, codec));
     }
   }
 
   for (const auto& type : good_mp4_audio_mime_types) {
     for (const auto& codec : bad_mp4_audio_codecs) {
-      EXPECT_FALSE(media_recorder_handler_->CanSupportMimeType(type, codec));
+      EXPECT_FALSE(CanSupportMimeType(type, codec));
     }
   }
 
   for (const auto& type : good_mp4_audio_mime_types) {
     for (const auto& codec : good_mp4_video_codecs) {
-      EXPECT_FALSE(media_recorder_handler_->CanSupportMimeType(type, codec));
+      EXPECT_FALSE(CanSupportMimeType(type, codec));
     }
   }
 
@@ -1186,11 +1172,10 @@
     for (const auto& video_codec : good_mp4_video_codecs) {
       for (const auto& audio_codec : good_mp4_audio_codecs) {
         String codecs = video_codec + "," + audio_codec;
-        EXPECT_FALSE(media_recorder_handler_->CanSupportMimeType(type, codecs));
+        EXPECT_FALSE(CanSupportMimeType(type, codecs));
 
         String codecs2 = audio_codec + "," + video_codec;
-        EXPECT_FALSE(
-            media_recorder_handler_->CanSupportMimeType(type, codecs2));
+        EXPECT_FALSE(CanSupportMimeType(type, codecs2));
       }
     }
   }
@@ -1198,14 +1183,14 @@
   // success cases.
   for (const auto& type : good_mp4_audio_mime_types) {
     for (const auto& codec : good_mp4_audio_codecs_non_proprietary) {
-      EXPECT_TRUE(media_recorder_handler_->CanSupportMimeType(type, codec));
+      EXPECT_TRUE(CanSupportMimeType(type, codec));
     }
   }
 
   // failure cases.
   for (const auto& type : good_mp4_audio_mime_types) {
     for (const auto& codec : bad_mp4_audio_codecs) {
-      EXPECT_FALSE(media_recorder_handler_->CanSupportMimeType(type, codec));
+      EXPECT_FALSE(CanSupportMimeType(type, codec));
     }
   }
 #endif
@@ -1221,15 +1206,13 @@
   {
     base::test::ScopedOSInfoOverride scoped_os_info_override(
         base::test::ScopedOSInfoOverride::Type::kWin11Home);
-    EXPECT_TRUE(
-        media_recorder_handler_->CanSupportMimeType("audio/mp4", "mp4a.40.2"));
+    EXPECT_TRUE(CanSupportMimeType("audio/mp4", "mp4a.40.2"));
   }
 
   {
     base::test::ScopedOSInfoOverride scoped_os_info_override(
         base::test::ScopedOSInfoOverride::Type::kWin11HomeN);
-    EXPECT_FALSE(
-        media_recorder_handler_->CanSupportMimeType("audio/mp4", "mp4a.40.2"));
+    EXPECT_FALSE(CanSupportMimeType("audio/mp4", "mp4a.40.2"));
   }
 }
 #endif  // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_PROPRIETARY_CODECS)
diff --git a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
index 9231f243..1a2502c5 100644
--- a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
+++ b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
@@ -230,12 +230,12 @@
       media::VideoEncodeAccelerator::SupportedProfiles());
 }
 
-void UmaHistogramForCodec(bool uses_acceleration, CodecId codec_id) {
+void UmaHistogramForCodecImpl(bool uses_acceleration, CodecId codec_id) {
   // These values are persisted to logs. Entries should not be renumbered and
   // numeric values should never be reused.
   // (kMaxValue being the only exception, as it does not map to a logged value,
   // and should be renumbered as new values are inserted.)
-  enum class VideoTrackRecorderCodecHistogram : uint8_t {
+  enum class VideoTrackRecorderCodecImplHistogram : uint8_t {
     kUnknown = 0,
     kVp8Sw = 1,
     kVp8Hw = 2,
@@ -248,26 +248,26 @@
     kHevcHw = 9,
     kMaxValue = kHevcHw,
   };
-  auto histogram = VideoTrackRecorderCodecHistogram::kUnknown;
+  auto histogram = VideoTrackRecorderCodecImplHistogram::kUnknown;
   if (uses_acceleration) {
     switch (codec_id) {
       case CodecId::kVp8:
-        histogram = VideoTrackRecorderCodecHistogram::kVp8Hw;
+        histogram = VideoTrackRecorderCodecImplHistogram::kVp8Hw;
         break;
       case CodecId::kVp9:
-        histogram = VideoTrackRecorderCodecHistogram::kVp9Hw;
+        histogram = VideoTrackRecorderCodecImplHistogram::kVp9Hw;
         break;
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
       case CodecId::kH264:
-        histogram = VideoTrackRecorderCodecHistogram::kH264Hw;
+        histogram = VideoTrackRecorderCodecImplHistogram::kH264Hw;
         break;
 #endif
       case CodecId::kAv1:
-        histogram = VideoTrackRecorderCodecHistogram::kAv1Hw;
+        histogram = VideoTrackRecorderCodecImplHistogram::kAv1Hw;
         break;
 #if BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
       case CodecId::kHevc:
-        histogram = VideoTrackRecorderCodecHistogram::kHevcHw;
+        histogram = VideoTrackRecorderCodecImplHistogram::kHevcHw;
         break;
 #endif
       case CodecId::kLast:
@@ -276,18 +276,18 @@
   } else {
     switch (codec_id) {
       case CodecId::kVp8:
-        histogram = VideoTrackRecorderCodecHistogram::kVp8Sw;
+        histogram = VideoTrackRecorderCodecImplHistogram::kVp8Sw;
         break;
       case CodecId::kVp9:
-        histogram = VideoTrackRecorderCodecHistogram::kVp9Sw;
+        histogram = VideoTrackRecorderCodecImplHistogram::kVp9Sw;
         break;
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
       case CodecId::kH264:
-        histogram = VideoTrackRecorderCodecHistogram::kH264Sw;
+        histogram = VideoTrackRecorderCodecImplHistogram::kH264Sw;
         break;
 #endif
       case CodecId::kAv1:
-        histogram = VideoTrackRecorderCodecHistogram::kAv1Sw;
+        histogram = VideoTrackRecorderCodecImplHistogram::kAv1Sw;
         break;
 #if BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
       case CodecId::kHevc:
@@ -412,6 +412,29 @@
 }
 }  // anonymous namespace
 
+// static
+VideoTrackRecorder::CodecHistogram
+VideoTrackRecorder::CodecHistogramFromCodecId(CodecId codec_id) {
+  switch (codec_id) {
+    case CodecId::kVp8:
+      return CodecHistogram::kVp8;
+    case CodecId::kVp9:
+      return CodecHistogram::kVp9;
+#if BUILDFLAG(USE_PROPRIETARY_CODECS)
+    case CodecId::kH264:
+      return CodecHistogram::kH264;
+#endif
+    case CodecId::kAv1:
+      return CodecHistogram::kAv1;
+#if BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
+    case CodecId::kHevc:
+      return CodecHistogram::kHevc;
+#endif
+    default:
+      return CodecHistogram::kUnknown;
+  }
+}
+
 VideoTrackRecorder::VideoTrackRecorder(
     scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner,
     WeakCell<CallbackInterface>* callback_interface)
@@ -1033,7 +1056,7 @@
   auto encoding_task_runner =
       base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()});
   CHECK(encoding_task_runner);
-  UmaHistogramForCodec(create_vea_encoder, codec_profile.codec_id);
+  UmaHistogramForCodecImpl(create_vea_encoder, codec_profile.codec_id);
 
   CreateMediaVideoEncoder(encoding_task_runner, codec_profile, is_screencast,
                           create_vea_encoder);
diff --git a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.h b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.h
index 5c8e30cc..21ac73012 100644
--- a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.h
+++ b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.h
@@ -82,6 +82,25 @@
     kLast
   };
 
+  // These values are persisted to logs. Entries should not be renumbered and
+  // numeric values should never be reused.
+  // (kMaxValue being the only exception, as it does not map to a logged value,
+  // and should be renumbered as new values are inserted.)
+  //
+  // LINT.IfChange(CodecHistogram)
+  enum class CodecHistogram : uint8_t {
+    kUnknown = 0,
+    kVp8 = 1,
+    kVp9 = 2,
+    kH264 = 3,
+    kAv1 = 4,
+    kHevc = 5,
+    kMaxValue = kHevc,
+  };
+  // LINT.ThenChange(//tools/metrics/histograms/metadata/media/enums.xml:MediaRecorderVideoCodec)
+
+  static CodecHistogram CodecHistogramFromCodecId(CodecId);
+
   // Callback interface for VideoTrackRecorders. The methods here need to all be
   // called on the main thread.
   class CallbackInterface : public GarbageCollectedMixin {
diff --git a/tools/metrics/histograms/metadata/media/enums.xml b/tools/metrics/histograms/metadata/media/enums.xml
index 375e478..e32c397 100644
--- a/tools/metrics/histograms/metadata/media/enums.xml
+++ b/tools/metrics/histograms/metadata/media/enums.xml
@@ -1464,7 +1464,20 @@
   <int value="2" label="User opened the combobox and chose a different device"/>
 </enum>
 
-<enum name="MediaRecorderCodec">
+<!-- LINT.IfChange(MediaRecorderVideoCodec) -->
+
+<enum name="MediaRecorderVideoCodec">
+  <int value="0" label="UnknownOrAudio"/>
+  <int value="1" label="VP8"/>
+  <int value="2" label="VP9"/>
+  <int value="3" label="H264"/>
+  <int value="4" label="AV1"/>
+  <int value="5" label="H265"/>
+</enum>
+
+<!-- LINT.ThenChange(//third_party/blink/renderer/modules/mediarecorder/video_track_recorder.h:CodecHistogram) -->
+
+<enum name="MediaRecorderVideoCodecImpl">
   <int value="0" label="Unknown"/>
   <int value="1" label="VP8_sw"/>
   <int value="2" label="VP8_hw"/>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml
index 27d2f6f..bdecbf59 100644
--- a/tools/metrics/histograms/metadata/media/histograms.xml
+++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -5040,7 +5040,7 @@
   </summary>
 </histogram>
 
-<histogram name="Media.MediaRecorder.Codec" enum="MediaRecorderCodec"
+<histogram name="Media.MediaRecorder.Codec" enum="MediaRecorderVideoCodecImpl"
     expires_after="2026-02-22">
   <owner>clarissagarvey@chromium.org</owner>
   <owner>chromeos-gfx-video@chromium.org</owner>
@@ -5050,6 +5050,26 @@
   </summary>
 </histogram>
 
+<histogram name="Media.MediaRecorder.Codec.{Query}.{Result}"
+    enum="MediaRecorderVideoCodec" expires_after="2026-05-01">
+  <owner>handellm@google.com</owner>
+  <owner>guidou@google.com</owner>
+  <summary>
+    Codec queried through MediaRecorder{Query} where the result is {Result}.
+    Logged when the call is made.
+  </summary>
+  <token key="Query">
+    <variant name="EncodingInfo" summary="EncodingInfo"/>
+    <variant name="IsTypeSupported" summary=".isTypeSupported"/>
+    <variant name="MediaRecorderCtor" summary="ctor"/>
+    <variant name="Test" summary="Test"/>
+  </token>
+  <token key="Result">
+    <variant name="Supported" summary="supported"/>
+    <variant name="Unsupported" summary="unsupported"/>
+  </token>
+</histogram>
+
 <histogram name="Media.MediaRecorder.HasCorrectAV1CodecString"
     enum="BooleanCorrect" expires_after="2024-06-30">
   <owner>hiroh@chromium.org</owner>