add 422 8 and 10 bit decoding support

Bug: webrtc:14195
Change-Id: I2048d567850ae669d76d9e593752683f3c76499f
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/266180
Reviewed-by: Niels Moller <nisse@webrtc.org>
Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#37306}
diff --git a/api/video_codecs/vp9_profile.cc b/api/video_codecs/vp9_profile.cc
index 5e2bd53..7e627cc 100644
--- a/api/video_codecs/vp9_profile.cc
+++ b/api/video_codecs/vp9_profile.cc
@@ -28,6 +28,8 @@
       return "1";
     case VP9Profile::kProfile2:
       return "2";
+    case VP9Profile::kProfile3:
+      return "3";
   }
   return "0";
 }
@@ -44,6 +46,8 @@
       return VP9Profile::kProfile1;
     case 2:
       return VP9Profile::kProfile2;
+    case 3:
+      return VP9Profile::kProfile3;
     default:
       return absl::nullopt;
   }
diff --git a/api/video_codecs/vp9_profile.h b/api/video_codecs/vp9_profile.h
index e632df4..b570bc3 100644
--- a/api/video_codecs/vp9_profile.h
+++ b/api/video_codecs/vp9_profile.h
@@ -26,6 +26,7 @@
   kProfile0,
   kProfile1,
   kProfile2,
+  kProfile3,
 };
 
 // Helper functions to convert VP9Profile to std::string. Returns "0" by
diff --git a/media/base/media_constants.cc b/media/base/media_constants.cc
index da5e7a8..2f29a20 100644
--- a/media/base/media_constants.cc
+++ b/media/base/media_constants.cc
@@ -114,6 +114,8 @@
 const char kH264ProfileLevelConstrainedBaseline[] = "42e01f";
 const char kH264ProfileLevelConstrainedHigh[] = "640c1f";
 
+const char kVP9ProfileId[] = "profile-id";
+
 const int kDefaultVideoMaxFramerate = 60;
 
 const size_t kConferenceMaxNumSpatialLayers = 3;
diff --git a/media/base/media_constants.h b/media/base/media_constants.h
index 16c5db9..f843d50 100644
--- a/media/base/media_constants.h
+++ b/media/base/media_constants.h
@@ -134,6 +134,8 @@
 extern const char kH264ProfileLevelConstrainedBaseline[];
 extern const char kH264ProfileLevelConstrainedHigh[];
 
+extern const char kVP9ProfileId[];
+
 extern const int kDefaultVideoMaxFramerate;
 
 extern const size_t kConferenceMaxNumSpatialLayers;
diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc
index 0ce0f0c..561eba6 100644
--- a/media/engine/webrtc_video_engine.cc
+++ b/media/engine/webrtc_video_engine.cc
@@ -133,17 +133,25 @@
       absl::EqualsIgnoreCase(codec.name, kAv1xCodecName)) {
     return true;
   } else if (absl::EqualsIgnoreCase(codec.name, kH264CodecName)) {
-    std::string profileLevelId;
-    std::string packetizationMode;
+    std::string profile_level_id;
+    std::string packetization_mode;
 
-    if (codec.GetParam(kH264FmtpProfileLevelId, &profileLevelId)) {
-      if (absl::StartsWithIgnoreCase(profileLevelId, "4d00")) {
-        if (codec.GetParam(kH264FmtpPacketizationMode, &packetizationMode)) {
-          return packetizationMode == "0";
+    if (codec.GetParam(kH264FmtpProfileLevelId, &profile_level_id)) {
+      if (absl::StartsWithIgnoreCase(profile_level_id, "4d00")) {
+        if (codec.GetParam(kH264FmtpPacketizationMode, &packetization_mode)) {
+          return packetization_mode == "0";
         }
       }
       // H264 with YUV444.
-      return absl::StartsWithIgnoreCase(profileLevelId, "f400");
+      return absl::StartsWithIgnoreCase(profile_level_id, "f400");
+    }
+  } else if (absl::EqualsIgnoreCase(codec.name, kVp9CodecName)) {
+    std::string profile_id;
+
+    if (codec.GetParam(kVP9ProfileId, &profile_id)) {
+      if (profile_id.compare("1") == 0 || profile_id.compare("3") == 0) {
+        return true;
+      }
     }
   }
   return false;
diff --git a/modules/video_coding/codecs/vp9/libvpx_vp9_decoder.cc b/modules/video_coding/codecs/vp9/libvpx_vp9_decoder.cc
index ffb4705..843c9bd 100644
--- a/modules/video_coding/codecs/vp9/libvpx_vp9_decoder.cc
+++ b/modules/video_coding/codecs/vp9/libvpx_vp9_decoder.cc
@@ -281,55 +281,59 @@
   // The buffer can be used directly by the VideoFrame (without copy) by
   // using a Wrapped*Buffer.
   rtc::scoped_refptr<VideoFrameBuffer> img_wrapped_buffer;
-  switch (img->bit_depth) {
-    case 8:
-      if (img->fmt == VPX_IMG_FMT_I420) {
-        if (preferred_output_format_ == VideoFrameBuffer::Type::kNV12) {
-          rtc::scoped_refptr<NV12Buffer> nv12_buffer =
-              output_buffer_pool_.CreateNV12Buffer(img->d_w, img->d_h);
-          if (!nv12_buffer.get()) {
-            // Buffer pool is full.
-            return WEBRTC_VIDEO_CODEC_NO_OUTPUT;
-          }
-          img_wrapped_buffer = nv12_buffer;
-          libyuv::I420ToNV12(img->planes[VPX_PLANE_Y], img->stride[VPX_PLANE_Y],
-                             img->planes[VPX_PLANE_U], img->stride[VPX_PLANE_U],
-                             img->planes[VPX_PLANE_V], img->stride[VPX_PLANE_V],
-                             nv12_buffer->MutableDataY(),
-                             nv12_buffer->StrideY(),
-                             nv12_buffer->MutableDataUV(),
-                             nv12_buffer->StrideUV(), img->d_w, img->d_h);
-          // No holding onto img_buffer as it's no longer needed and can be
-          // reused.
-        } else {
-          img_wrapped_buffer = WrapI420Buffer(
-              img->d_w, img->d_h, img->planes[VPX_PLANE_Y],
-              img->stride[VPX_PLANE_Y], img->planes[VPX_PLANE_U],
-              img->stride[VPX_PLANE_U], img->planes[VPX_PLANE_V],
-              img->stride[VPX_PLANE_V],
-              // WrappedI420Buffer's mechanism for allowing the release of its
-              // frame buffer is through a callback function. This is where we
-              // should release `img_buffer`.
-              [img_buffer] {});
+  switch (img->fmt) {
+    case VPX_IMG_FMT_I420:
+      if (preferred_output_format_ == VideoFrameBuffer::Type::kNV12) {
+        rtc::scoped_refptr<NV12Buffer> nv12_buffer =
+            output_buffer_pool_.CreateNV12Buffer(img->d_w, img->d_h);
+        if (!nv12_buffer.get()) {
+          // Buffer pool is full.
+          return WEBRTC_VIDEO_CODEC_NO_OUTPUT;
         }
-      } else if (img->fmt == VPX_IMG_FMT_I444) {
-        img_wrapped_buffer = WrapI444Buffer(
+        img_wrapped_buffer = nv12_buffer;
+        libyuv::I420ToNV12(img->planes[VPX_PLANE_Y], img->stride[VPX_PLANE_Y],
+                           img->planes[VPX_PLANE_U], img->stride[VPX_PLANE_U],
+                           img->planes[VPX_PLANE_V], img->stride[VPX_PLANE_V],
+                           nv12_buffer->MutableDataY(), nv12_buffer->StrideY(),
+                           nv12_buffer->MutableDataUV(),
+                           nv12_buffer->StrideUV(), img->d_w, img->d_h);
+        // No holding onto img_buffer as it's no longer needed and can be
+        // reused.
+      } else {
+        img_wrapped_buffer = WrapI420Buffer(
             img->d_w, img->d_h, img->planes[VPX_PLANE_Y],
             img->stride[VPX_PLANE_Y], img->planes[VPX_PLANE_U],
             img->stride[VPX_PLANE_U], img->planes[VPX_PLANE_V],
             img->stride[VPX_PLANE_V],
-            // WrappedI444Buffer's mechanism for allowing the release of its
+            // WrappedI420Buffer's mechanism for allowing the release of its
             // frame buffer is through a callback function. This is where we
             // should release `img_buffer`.
             [img_buffer] {});
-      } else {
-        RTC_LOG(LS_ERROR)
-            << "Unsupported pixel format produced by the decoder: "
-            << static_cast<int>(img->fmt);
-        return WEBRTC_VIDEO_CODEC_NO_OUTPUT;
       }
       break;
-    case 10:
+    case VPX_IMG_FMT_I422:
+      img_wrapped_buffer = WrapI422Buffer(
+          img->d_w, img->d_h, img->planes[VPX_PLANE_Y],
+          img->stride[VPX_PLANE_Y], img->planes[VPX_PLANE_U],
+          img->stride[VPX_PLANE_U], img->planes[VPX_PLANE_V],
+          img->stride[VPX_PLANE_V],
+          // WrappedI444Buffer's mechanism for allowing the release of its
+          // frame buffer is through a callback function. This is where we
+          // should release `img_buffer`.
+          [img_buffer] {});
+      break;
+    case VPX_IMG_FMT_I444:
+      img_wrapped_buffer = WrapI444Buffer(
+          img->d_w, img->d_h, img->planes[VPX_PLANE_Y],
+          img->stride[VPX_PLANE_Y], img->planes[VPX_PLANE_U],
+          img->stride[VPX_PLANE_U], img->planes[VPX_PLANE_V],
+          img->stride[VPX_PLANE_V],
+          // WrappedI444Buffer's mechanism for allowing the release of its
+          // frame buffer is through a callback function. This is where we
+          // should release `img_buffer`.
+          [img_buffer] {});
+      break;
+    case VPX_IMG_FMT_I42016:
       img_wrapped_buffer = WrapI010Buffer(
           img->d_w, img->d_h,
           reinterpret_cast<const uint16_t*>(img->planes[VPX_PLANE_Y]),
@@ -339,9 +343,19 @@
           reinterpret_cast<const uint16_t*>(img->planes[VPX_PLANE_V]),
           img->stride[VPX_PLANE_V] / 2, [img_buffer] {});
       break;
+    case VPX_IMG_FMT_I42216:
+      img_wrapped_buffer = WrapI210Buffer(
+          img->d_w, img->d_h,
+          reinterpret_cast<const uint16_t*>(img->planes[VPX_PLANE_Y]),
+          img->stride[VPX_PLANE_Y] / 2,
+          reinterpret_cast<const uint16_t*>(img->planes[VPX_PLANE_U]),
+          img->stride[VPX_PLANE_U] / 2,
+          reinterpret_cast<const uint16_t*>(img->planes[VPX_PLANE_V]),
+          img->stride[VPX_PLANE_V] / 2, [img_buffer] {});
+      break;
     default:
-      RTC_LOG(LS_ERROR) << "Unsupported bit depth produced by the decoder: "
-                        << img->bit_depth;
+      RTC_LOG(LS_ERROR) << "Unsupported pixel format produced by the decoder: "
+                        << static_cast<int>(img->fmt);
       return WEBRTC_VIDEO_CODEC_NO_OUTPUT;
   }
 
diff --git a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc
index 58beacd..b252fb7 100644
--- a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc
+++ b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc
@@ -628,6 +628,10 @@
       config_->g_profile = 2;
       config_->g_input_bit_depth = 10;
       break;
+    case VP9Profile::kProfile3:
+      // Encoding of profile 3 is not implemented.
+      RTC_DCHECK_NOTREACHED();
+      break;
   }
 
   // Creating a wrapper to the image - setting image data to nullptr. Actual
@@ -1194,6 +1198,10 @@
       raw_->stride[VPX_PLANE_V] = i010_buffer->StrideV() * 2;
       break;
     }
+    case VP9Profile::kProfile3: {
+      RTC_DCHECK_NOTREACHED();
+      break;
+    }
   }
 
   vpx_enc_frame_flags_t flags = 0;
diff --git a/modules/video_coding/codecs/vp9/vp9.cc b/modules/video_coding/codecs/vp9/vp9.cc
index 42d6987..7a7a7d6 100644
--- a/modules/video_coding/codecs/vp9/vp9.cc
+++ b/modules/video_coding/codecs/vp9/vp9.cc
@@ -54,12 +54,15 @@
 std::vector<SdpVideoFormat> SupportedVP9DecoderCodecs() {
 #ifdef RTC_ENABLE_VP9
   std::vector<SdpVideoFormat> supported_formats = SupportedVP9Codecs();
-  // The WebRTC internal decoder supports VP9 profile 1. However, there's
-  // currently no way of sending VP9 profile 1 using the internal encoder.
+  // The WebRTC internal decoder supports VP9 profile 1 and 3. However, there's
+  // currently no way of sending VP9 profile 1 or 3 using the internal encoder.
   // It would require extended support for I444, I422, and I440 buffers.
   supported_formats.push_back(SdpVideoFormat(
       cricket::kVp9CodecName,
       {{kVP9FmtpProfileId, VP9ProfileToString(VP9Profile::kProfile1)}}));
+  supported_formats.push_back(SdpVideoFormat(
+      cricket::kVp9CodecName,
+      {{kVP9FmtpProfileId, VP9ProfileToString(VP9Profile::kProfile3)}}));
   return supported_formats;
 #else
   return std::vector<SdpVideoFormat>();