Bug 1278198 - Enforce codecs match the capability and content type in GetSupportedCapabilities(). r=gerald draft
authorChris Pearce <cpearce@mozilla.com>
Thu, 21 Jul 2016 19:22:59 +1200
changeset 390998 b64919e71128b0cd3a1129af56f915ffa5d2025b
parent 390997 f944a40e2287c7a7dd01a2fb145a9e5882dd2368
child 391118 c20f5717f4b47e5c3ed5c2b146deafa22c673b47
push id23779
push usercpearce@mozilla.com
push dateThu, 21 Jul 2016 22:43:31 +0000
reviewersgerald
bugs1278198
milestone50.0a1
Bug 1278198 - Enforce codecs match the capability and content type in GetSupportedCapabilities(). r=gerald We're supposed to reject MediaKeySystemCapabilities which have a contentType that has codecs which don't match their major type, i.e. audio codecs in a video container type. I missed that, and it's causing us to fail the test_eme_requestMediaKeySystemAccess case "MP4 video container with both audio and video codec type in videoType". MozReview-Commit-ID: KQVGk9hX3eC
dom/media/eme/MediaKeySystemAccess.cpp
--- a/dom/media/eme/MediaKeySystemAccess.cpp
+++ b/dom/media/eme/MediaKeySystemAccess.cpp
@@ -614,19 +614,47 @@ GetMajorType(const nsAString& aContentTy
     return Audio;
   }
   if (CaseInsensitiveFindInReadable(NS_LITERAL_STRING("video/"), aContentType)) {
     return Video;
   }
   return Invalid;
 }
 
+static CodecType
+GetCodecType(const GMPCodecString& aCodec)
+{
+  if (aCodec.Equals(GMP_CODEC_AAC) ||
+      aCodec.Equals(GMP_CODEC_OPUS) ||
+      aCodec.Equals(GMP_CODEC_VORBIS)) {
+    return Audio;
+  }
+  if (aCodec.Equals(GMP_CODEC_H264) ||
+      aCodec.Equals(GMP_CODEC_VP8) ||
+      aCodec.Equals(GMP_CODEC_VP9)) {
+    return Video;
+  }
+  return Invalid;
+}
+
+static bool
+AllCodecsOfType(const nsTArray<GMPCodecString>& aCodecs, const CodecType aCodecType)
+{
+  for (const GMPCodecString& codec : aCodecs) {
+    if (GetCodecType(codec) != aCodecType) {
+      return false;
+    }
+  }
+  return true;
+}
+
 // 3.1.2.3 Get Supported Capabilities for Audio/Video Type
 static Sequence<MediaKeySystemMediaCapability>
-GetSupportedCapabilities(mozIGeckoMediaPluginService* aGMPService,
+GetSupportedCapabilities(const CodecType aCodecType,
+                         mozIGeckoMediaPluginService* aGMPService,
                          const nsTArray<MediaKeySystemMediaCapability>& aRequestedCapabilities,
                          const MediaKeySystemConfiguration& aPartialConfig,
                          const KeySystemConfig& aKeySystem,
                          DecoderDoctorDiagnostics* aDiagnostics)
 {
   // Let local accumulated configuration be a local copy of partial configuration.
   // (Note: It's not necessary for us to maintain a local copy, as we don't need
   // to test whether capabilites from previous calls to this algorithm work with
@@ -727,48 +755,57 @@ GetSupportedCapabilities(mozIGeckoMediaP
     // If the user agent does not recognize one or more parameters, continue to
     // the next iteration.
     // Let media types be the set of codecs and codec constraints specified by
     // parameters. The case-sensitivity of string comparisons is determined by
     // the appropriate RFC or other specification.
     // (Note: codecs array is 'parameter').
 
     // If media types is empty:
-    const auto majorType = GetMajorType(container);
     if (codecs.IsEmpty()) {
       // If container normatively implies a specific set of codecs and codec constraints:
       // Let parameters be that set.
       if (isMP4) {
-        if (majorType == Audio) {
+        if (aCodecType == Audio) {
           codecs.AppendElement(GMP_CODEC_AAC);
-        } else if (majorType == Video) {
+        } else if (aCodecType == Video) {
           codecs.AppendElement(GMP_CODEC_H264);
         }
       } else if (isWebM) {
-        if (majorType == Audio) {
+        if (aCodecType == Audio) {
           codecs.AppendElement(GMP_CODEC_VORBIS);
-        } else if (majorType == Video) {
+        } else if (aCodecType == Video) {
           codecs.AppendElement(GMP_CODEC_VP8);
         }
       }
       // Otherwise: Continue to the next iteration.
       // (Note: all containers we support have implied codecs, so don't continue here.)
     }
 
     // If content type is not strictly a audio/video type, continue to the next iteration.
+    const auto majorType = GetMajorType(container);
     if (majorType == Invalid) {
       EME_LOG("MediaKeySystemConfiguration (label='%s') "
               "MediaKeySystemMediaCapability('%s','%s') unsupported; "
               "MIME type is not an audio or video MIME type.",
               NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(),
               NS_ConvertUTF16toUTF8(contentType).get(),
               NS_ConvertUTF16toUTF8(robustness).get());
       continue;
     }
-
+    if (majorType != aCodecType || !AllCodecsOfType(codecs, aCodecType)) {
+      EME_LOG("MediaKeySystemConfiguration (label='%s') "
+              "MediaKeySystemMediaCapability('%s','%s') unsupported; "
+              "MIME type mixes audio codecs in video capabilities "
+              "or video codecs in audio capabilities.",
+              NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(),
+              NS_ConvertUTF16toUTF8(contentType).get(),
+              NS_ConvertUTF16toUTF8(robustness).get());
+      continue;
+    }
     // If robustness is not the empty string and contains an unrecognized
     // value or a value not supported by implementation, continue to the
     // next iteration. String comparison is case-sensitive.
     if (!robustness.IsEmpty()) {
       if (majorType == Audio && !aKeySystem.mAudioRobustness.Contains(robustness)) {
         EME_LOG("MediaKeySystemConfiguration (label='%s') "
                 "MediaKeySystemMediaCapability('%s','%s') unsupported; "
                 "unsupported robustness string.",
@@ -1011,17 +1048,18 @@ GetSupportedConfig(mozIGeckoMediaPluginS
 
   // If the videoCapabilities member in candidate configuration is non-empty:
   if (!aCandidate.mVideoCapabilities.IsEmpty()) {
     // Let video capabilities be the result of executing the Get Supported
     // Capabilities for Audio/Video Type algorithm on Video, candidate
     // configuration's videoCapabilities member, accumulated configuration,
     // and restrictions.
     Sequence<MediaKeySystemMediaCapability> caps =
-      GetSupportedCapabilities(aGMPService,
+      GetSupportedCapabilities(Video,
+                               aGMPService,
                                aCandidate.mVideoCapabilities,
                                config,
                                aKeySystem,
                                aDiagnostics);
     // If video capabilities is null, return NotSupported.
     if (caps.IsEmpty()) {
       EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; "
               "no supported video capabilities.",
@@ -1036,17 +1074,18 @@ GetSupportedConfig(mozIGeckoMediaPluginS
   }
 
   // If the audioCapabilities member in candidate configuration is non-empty:
   if (!aCandidate.mAudioCapabilities.IsEmpty()) {
     // Let audio capabilities be the result of executing the Get Supported Capabilities
     // for Audio/Video Type algorithm on Audio, candidate configuration's audioCapabilities
     // member, accumulated configuration, and restrictions.
     Sequence<MediaKeySystemMediaCapability> caps =
-      GetSupportedCapabilities(aGMPService,
+      GetSupportedCapabilities(Audio,
+                               aGMPService,
                                aCandidate.mAudioCapabilities,
                                config,
                                aKeySystem,
                                aDiagnostics);
     // If audio capabilities is null, return NotSupported.
     if (caps.IsEmpty()) {
       EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; "
               "no supported audio capabilities.",