[go: nahoru, domu]

vaapi: Enable AV1 protected content for AMD

This enables AV1 playback of protected content on AMD platforms that
support it. In the cdm-oemcrypto daemon, we take the transcrypted data
that AMD generates and hide it inside of a padding OBU. Then we extract
that here because that is the only data marked as the encrypted range.
We expect there to be 2 subsamples because there is a single trailing
unencrypted byte at the end of the padding OBU.

BUG=b:232908730
TEST=protected AV1 playback works on skyrim

Change-Id: Ie9843505ea8d49febd9cba9595a6c3851208f2e5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3696487
Reviewed-by: Hirokazu Honda <hiroh@chromium.org>
Commit-Queue: Jeffrey Kardatzke <jkardatzke@google.com>
Cr-Commit-Position: refs/heads/main@{#1042634}
diff --git a/media/gpu/vaapi/av1_vaapi_video_decoder_delegate.cc b/media/gpu/vaapi/av1_vaapi_video_decoder_delegate.cc
index 7c7214d..fbc0e61 100644
--- a/media/gpu/vaapi/av1_vaapi_video_decoder_delegate.cc
+++ b/media/gpu/vaapi/av1_vaapi_video_decoder_delegate.cc
@@ -738,6 +738,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!picture_params_);
   DCHECK(!crypto_params_);
+  DCHECK(!protected_params_);
 }
 
 scoped_refptr<AV1Picture> AV1VaapiVideoDecoderDelegate::CreateAV1Picture(
@@ -852,22 +853,47 @@
   // also be adjusted.
   // Create VASliceData buffer |encoded_data| every frame so that decoding can
   // be more asynchronous than reusing the buffer.
-  auto encoded_data =
-      vaapi_wrapper_->CreateVABuffer(VASliceDataBufferType, data.size_bytes());
-  if (!encoded_data)
-    return DecodeStatus::kFail;
+  std::unique_ptr<ScopedVABuffer> encoded_data;
 
   std::vector<std::pair<VABufferID, VaapiWrapper::VABufferDescriptor>> buffers =
       {{picture_params_->id(),
-        {picture_params_->type(), picture_params_->size(), &pic_param}},
-       {encoded_data->id(),
-        {encoded_data->type(), encoded_data->size(), data.data()}}};
-  for (size_t i = 0; i < slice_params.size(); ++i) {
-    buffers.push_back({slice_params_va_buffers[i]->id(),
-                       {slice_params_va_buffers[i]->type(),
-                        slice_params_va_buffers[i]->size(), &slice_params[i]}});
-  }
+        {picture_params_->type(), picture_params_->size(), &pic_param}}};
+  buffers.reserve(3 + slice_params.size());
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+  if (IsTranscrypted()) {
+    CHECK(decrypt_config);
+    CHECK_EQ(decrypt_config->subsamples().size(), 2u);
+    if (!protected_params_) {
+      protected_params_ = vaapi_wrapper_->CreateVABuffer(
+          VAProtectedSliceDataBufferType, decrypt_config->key_id().length());
+      if (!protected_params_)
+        return DecodeStatus::kFail;
+    }
+    DCHECK_EQ(decrypt_config->key_id().length(), protected_params_->size());
+    buffers.push_back({protected_params_->id(),
+                       {protected_params_->type(), protected_params_->size(),
+                        decrypt_config->key_id().data()}});
+    encoded_data = vaapi_wrapper_->CreateVABuffer(
+        VASliceDataBufferType,
+        base::strict_cast<size_t>(
+            decrypt_config->subsamples()[0].cypher_bytes));
+    if (!encoded_data)
+      return DecodeStatus::kFail;
+    buffers.push_back(
+        {encoded_data->id(),
+         {encoded_data->type(), encoded_data->size(),
+          data.data() + decrypt_config->subsamples()[0].clear_bytes}});
+  } else {
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+    encoded_data = vaapi_wrapper_->CreateVABuffer(VASliceDataBufferType,
+                                                  data.size_bytes());
+    if (!encoded_data)
+      return DecodeStatus::kFail;
+    buffers.push_back(
+        {encoded_data->id(),
+         {encoded_data->type(), encoded_data->size(), data.data()}});
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  }
   if (uses_crypto) {
     buffers.push_back(
         {crypto_params_->id(),
@@ -875,6 +901,12 @@
   }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
+  for (size_t i = 0; i < slice_params.size(); ++i) {
+    buffers.push_back({slice_params_va_buffers[i]->id(),
+                       {slice_params_va_buffers[i]->type(),
+                        slice_params_va_buffers[i]->size(), &slice_params[i]}});
+  }
+
   const auto* vaapi_pic = static_cast<const VaapiAV1Picture*>(&pic);
   const bool success = vaapi_wrapper_->MapAndCopyAndExecute(
       vaapi_pic->reconstruct_va_surface()->id(), buffers);
@@ -892,5 +924,6 @@
   // that will be destroyed soon.
   picture_params_.reset();
   crypto_params_.reset();
+  protected_params_.reset();
 }
 }  // namespace media
diff --git a/media/gpu/vaapi/av1_vaapi_video_decoder_delegate.h b/media/gpu/vaapi/av1_vaapi_video_decoder_delegate.h
index 31fd5a4..dfc38c0 100644
--- a/media/gpu/vaapi/av1_vaapi_video_decoder_delegate.h
+++ b/media/gpu/vaapi/av1_vaapi_video_decoder_delegate.h
@@ -44,6 +44,7 @@
  private:
   std::unique_ptr<ScopedVABuffer> picture_params_;
   std::unique_ptr<ScopedVABuffer> crypto_params_;
+  std::unique_ptr<ScopedVABuffer> protected_params_;
 };
 }  // namespace media
 #endif  // MEDIA_GPU_VAAPI_AV1_VAAPI_VIDEO_DECODER_DELEGATE_H_