[go: nahoru, domu]

media/gpu: Support VP9 k-SVC decoding with HW decoder on chromeos intel platform

This CL enables VP9 k-SVC decoding with HW decoder on chromeos intel platform.
The feature is currently disabled by default and can be enabled by
--enable-features=Vp9kSVCHWDecoding. Webrtc stack sends hw decoder one SVC frame
that is composed of multiple frames without superframe index. So that HW decoder
can detect each frame, webrtc attach the data size info of each frame in
webrtc::EncodedImage. We propagate the info to HW decoder by storing it as
side_data in media::DecoderBuffer. Vp9Parser knows the width and height of all
frame embedded in one SVC frame before feeding them and notify the largest width
and height to HW decoder.

Design doc for this change is go/VP9-k-SVC-Decoing-VAAPI.

Bug: chromium:935411
Test: Hangout Meet with VP9 SVC stream
Change-Id: I40eb25f73a97b25b6131b1d969f27618d7bd0ee9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1640739
Reviewed-by: Kuang-che Wu <kcwu@chromium.org>
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
Commit-Queue: Hirokazu Honda <hiroh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#679213}
diff --git a/media/gpu/vp9_decoder.cc b/media/gpu/vp9_decoder.cc
index 4927308..68188ea4 100644
--- a/media/gpu/vp9_decoder.cc
+++ b/media/gpu/vp9_decoder.cc
@@ -7,12 +7,35 @@
 #include <memory>
 
 #include "base/bind.h"
+#include "base/feature_list.h"
 #include "base/logging.h"
 #include "media/base/limits.h"
+#include "media/base/media_switches.h"
 #include "media/gpu/vp9_decoder.h"
 
 namespace media {
 
+namespace {
+std::vector<uint32_t> GetSpatialLayerFrameSize(
+    const DecoderBuffer& decoder_buffer) {
+  const uint32_t* cue_data =
+      reinterpret_cast<const uint32_t*>(decoder_buffer.side_data());
+  if (!cue_data)
+    return {};
+  if (!base::FeatureList::IsEnabled(media::kVp9kSVCHWDecoding)) {
+    DLOG(ERROR) << "Vp9Parser doesn't support parsing SVC stream";
+    return {};
+  }
+
+  size_t num_of_layers = decoder_buffer.side_data_size() / sizeof(uint32_t);
+  if (num_of_layers > 3u) {
+    DLOG(WARNING) << "The maximum number of spatial layers in VP9 is three";
+    return {};
+  }
+  return std::vector<uint32_t>(cue_data, cue_data + num_of_layers);
+}
+}  // namespace
+
 VP9Decoder::VP9Accelerator::VP9Accelerator() {}
 
 VP9Decoder::VP9Accelerator::~VP9Accelerator() {}
@@ -38,9 +61,11 @@
            << " size: " << size;
   stream_id_ = id;
   if (decrypt_config) {
-    parser_.SetStream(ptr, size, decrypt_config->Clone());
+    parser_.SetStream(ptr, size, GetSpatialLayerFrameSize(decoder_buffer),
+                      decrypt_config->Clone());
   } else {
-    parser_.SetStream(ptr, size, nullptr);
+    parser_.SetStream(ptr, size, GetSpatialLayerFrameSize(decoder_buffer),
+                      nullptr);
   }
 }
 
@@ -66,12 +91,14 @@
     // Read a new frame header if one is not awaiting decoding already.
     std::unique_ptr<DecryptConfig> decrypt_config;
     if (!curr_frame_hdr_) {
+      gfx::Size allocate_size;
       std::unique_ptr<Vp9FrameHeader> hdr(new Vp9FrameHeader());
       Vp9Parser::Result res =
-          parser_.ParseNextFrame(hdr.get(), &decrypt_config);
+          parser_.ParseNextFrame(hdr.get(), &allocate_size, &decrypt_config);
       switch (res) {
         case Vp9Parser::kOk:
           curr_frame_hdr_ = std::move(hdr);
+          curr_frame_size_ = allocate_size;
           break;
 
         case Vp9Parser::kEOStream:
@@ -134,8 +161,7 @@
       continue;
     }
 
-    gfx::Size new_pic_size(curr_frame_hdr_->frame_width,
-                           curr_frame_hdr_->frame_height);
+    gfx::Size new_pic_size = curr_frame_size_;
     gfx::Rect new_render_rect(curr_frame_hdr_->render_width,
                               curr_frame_hdr_->render_height);
     // For safety, check the validity of render size or leave it as (0, 0).