Commit e8f9c1d7 authored by Hirokazu Honda's avatar Hirokazu Honda Committed by Commit Bot

media/gpu/vaapi: Handle profile change in VaapiVD/VDA

crrev.com/c/1923986 handles a profile change in V4L2SVD/VDA. This CL
handles a profile change in VaapiVD/VDA.

Since VA-API is initialized with a codec profile, it is necessary to
reinitialize VA-API with a new profile. VaapiWrapper manages several
VA-API resources. For example, surfaces will be destroyed after
the profile change. It will be easier to replace VaapiWrapper used in
AVD::Accelerator with a new VaapiWrapper than reinitialize the
existing VaapiWrapper properly.

Bug: 1022246, 1029397
Test: video.DecodeAccel(VD).h264_profile_change (crrev.com/c/1924217) on eve and grunt
Change-Id: Ic3ff0b231cf454ce61193ee9f2642050d588ef24
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1930368
Commit-Queue: Hirokazu Honda <hiroh@chromium.org>
Reviewed-by: default avatarMiguel Casas <mcasas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#729685}
parent 96f8a0ba
...@@ -200,16 +200,22 @@ bool VaapiVideoDecodeAccelerator::Initialize(const Config& config, ...@@ -200,16 +200,22 @@ bool VaapiVideoDecodeAccelerator::Initialize(const Config& config,
} }
if (profile >= H264PROFILE_MIN && profile <= H264PROFILE_MAX) { if (profile >= H264PROFILE_MIN && profile <= H264PROFILE_MAX) {
decoder_.reset(new H264Decoder( auto accelerator =
std::make_unique<H264VaapiVideoDecoderDelegate>(this, vaapi_wrapper_), std::make_unique<H264VaapiVideoDecoderDelegate>(this, vaapi_wrapper_);
profile, config.container_color_space)); decoder_delegate_ = accelerator.get();
decoder_.reset(new H264Decoder(std::move(accelerator), profile,
config.container_color_space));
} else if (profile >= VP8PROFILE_MIN && profile <= VP8PROFILE_MAX) { } else if (profile >= VP8PROFILE_MIN && profile <= VP8PROFILE_MAX) {
decoder_.reset(new VP8Decoder( auto accelerator =
std::make_unique<VP8VaapiVideoDecoderDelegate>(this, vaapi_wrapper_))); std::make_unique<VP8VaapiVideoDecoderDelegate>(this, vaapi_wrapper_);
decoder_delegate_ = accelerator.get();
decoder_.reset(new VP8Decoder(std::move(accelerator)));
} else if (profile >= VP9PROFILE_MIN && profile <= VP9PROFILE_MAX) { } else if (profile >= VP9PROFILE_MIN && profile <= VP9PROFILE_MAX) {
decoder_.reset(new VP9Decoder( auto accelerator =
std::make_unique<VP9VaapiVideoDecoderDelegate>(this, vaapi_wrapper_), std::make_unique<VP9VaapiVideoDecoderDelegate>(this, vaapi_wrapper_);
profile, config.container_color_space)); decoder_delegate_ = accelerator.get();
decoder_.reset(new VP9Decoder(std::move(accelerator), profile,
config.container_color_space));
} else { } else {
VLOGF(1) << "Unsupported profile " << GetProfileName(profile); VLOGF(1) << "Unsupported profile " << GetProfileName(profile);
return false; return false;
...@@ -445,20 +451,14 @@ void VaapiVideoDecodeAccelerator::DecodeTask() { ...@@ -445,20 +451,14 @@ void VaapiVideoDecodeAccelerator::DecodeTask() {
switch (res) { switch (res) {
case AcceleratedVideoDecoder::kConfigChange: { case AcceleratedVideoDecoder::kConfigChange: {
gfx::Size new_size = decoder_->GetPicSize();
if (profile_ != decoder_->GetProfile() &&
requested_pic_size_ == new_size) {
// Profile only is changed.
// TODO(crbug.com/1022246): Handle profile change.
continue;
}
VLOGF(2) << "Decoder requesting a new set of surfaces"; VLOGF(2) << "Decoder requesting a new set of surfaces";
task_runner_->PostTask( task_runner_->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce( base::BindOnce(
&VaapiVideoDecodeAccelerator::InitiateSurfaceSetChange, &VaapiVideoDecodeAccelerator::InitiateSurfaceSetChange,
weak_this_, decoder_->GetRequiredNumOfPictures(), new_size, weak_this_, decoder_->GetRequiredNumOfPictures(),
decoder_->GetNumReferenceFrames(), decoder_->GetVisibleRect())); decoder_->GetPicSize(), decoder_->GetNumReferenceFrames(),
decoder_->GetVisibleRect()));
// We'll get rescheduled once ProvidePictureBuffers() finishes. // We'll get rescheduled once ProvidePictureBuffers() finishes.
return; return;
} }
...@@ -566,11 +566,25 @@ void VaapiVideoDecodeAccelerator::TryFinishSurfaceSetChange() { ...@@ -566,11 +566,25 @@ void VaapiVideoDecodeAccelerator::TryFinishSurfaceSetChange() {
// All surfaces released, destroy them and dismiss all PictureBuffers. // All surfaces released, destroy them and dismiss all PictureBuffers.
awaiting_va_surfaces_recycle_ = false; awaiting_va_surfaces_recycle_ = false;
if (buffer_allocation_mode_ != BufferAllocationMode::kNone) {
vaapi_wrapper_->DestroyContextAndSurfaces(std::vector<VASurfaceID>( VideoCodecProfile new_profile = decoder_->GetProfile();
available_va_surfaces_.begin(), available_va_surfaces_.end())); if (profile_ != new_profile) {
DCHECK(decoder_delegate_);
profile_ = new_profile;
auto new_vaapi_wrapper = VaapiWrapper::CreateForVideoCodec(
VaapiWrapper::kDecode, profile_, base::Bind(&ReportToUMA, VAAPI_ERROR));
RETURN_AND_NOTIFY_ON_FAILURE(new_vaapi_wrapper.get(),
"Failed creating VaapiWrapper",
INVALID_ARGUMENT, );
decoder_delegate_->set_vaapi_wrapper(new_vaapi_wrapper.get());
vaapi_wrapper_ = std::move(new_vaapi_wrapper);
} else { } else {
vaapi_wrapper_->DestroyContext(); if (buffer_allocation_mode_ != BufferAllocationMode::kNone) {
vaapi_wrapper_->DestroyContextAndSurfaces(std::vector<VASurfaceID>(
available_va_surfaces_.begin(), available_va_surfaces_.end()));
} else {
vaapi_wrapper_->DestroyContext();
}
} }
available_va_surfaces_.clear(); available_va_surfaces_.clear();
......
...@@ -44,6 +44,7 @@ class GLImage; ...@@ -44,6 +44,7 @@ class GLImage;
namespace media { namespace media {
class AcceleratedVideoDecoder; class AcceleratedVideoDecoder;
class VaapiVideoDecoderDelegate;
class VaapiPicture; class VaapiPicture;
// Class to provide video decode acceleration for Intel systems with hardware // Class to provide video decode acceleration for Intel systems with hardware
...@@ -246,6 +247,9 @@ class MEDIA_GPU_EXPORT VaapiVideoDecodeAccelerator ...@@ -246,6 +247,9 @@ class MEDIA_GPU_EXPORT VaapiVideoDecodeAccelerator
scoped_refptr<VaapiWrapper> vaapi_wrapper_; scoped_refptr<VaapiWrapper> vaapi_wrapper_;
// Only used on |decoder_thread_task_runner_|. // Only used on |decoder_thread_task_runner_|.
std::unique_ptr<AcceleratedVideoDecoder> decoder_; std::unique_ptr<AcceleratedVideoDecoder> decoder_;
// TODO(crbug.com/1022246): Instead of having the raw pointer here, getting
// the pointer from AcceleratedVideoDecoder.
VaapiVideoDecoderDelegate* decoder_delegate_ = nullptr;
// Filled in during Initialize(). // Filled in during Initialize().
BufferAllocationMode buffer_allocation_mode_; BufferAllocationMode buffer_allocation_mode_;
......
...@@ -228,16 +228,16 @@ class VaapiVideoDecodeAcceleratorTest : public TestWithParam<TestParams>, ...@@ -228,16 +228,16 @@ class VaapiVideoDecodeAcceleratorTest : public TestWithParam<TestParams>,
EXPECT_CALL(*mock_decoder_, Decode()) EXPECT_CALL(*mock_decoder_, Decode())
.WillOnce(Return(AcceleratedVideoDecoder::kConfigChange)); .WillOnce(Return(AcceleratedVideoDecoder::kConfigChange));
EXPECT_CALL(*mock_decoder_, GetPicSize()).WillOnce(Return(picture_size));
EXPECT_CALL(*mock_decoder_, GetProfile())
.WillOnce(Return(GetParam().video_codec));
EXPECT_CALL(*mock_decoder_, GetRequiredNumOfPictures()) EXPECT_CALL(*mock_decoder_, GetRequiredNumOfPictures())
.WillOnce(Return(num_pictures)); .WillOnce(Return(num_pictures));
EXPECT_CALL(*mock_decoder_, GetPicSize()).WillOnce(Return(picture_size));
const size_t kNumReferenceFrames = num_pictures / 2; const size_t kNumReferenceFrames = num_pictures / 2;
EXPECT_CALL(*mock_decoder_, GetNumReferenceFrames()) EXPECT_CALL(*mock_decoder_, GetNumReferenceFrames())
.WillOnce(Return(kNumReferenceFrames)); .WillOnce(Return(kNumReferenceFrames));
EXPECT_CALL(*mock_decoder_, GetVisibleRect()) EXPECT_CALL(*mock_decoder_, GetVisibleRect())
.WillOnce(Return(gfx::Rect(picture_size))); .WillOnce(Return(gfx::Rect(picture_size)));
EXPECT_CALL(*mock_decoder_, GetProfile())
.WillOnce(Return(GetParam().video_codec));
if (vda_.buffer_allocation_mode_ != if (vda_.buffer_allocation_mode_ !=
VaapiVideoDecodeAccelerator::BufferAllocationMode::kNone) { VaapiVideoDecodeAccelerator::BufferAllocationMode::kNone) {
EXPECT_CALL(*mock_vaapi_wrapper_, DestroyContextAndSurfaces(_)); EXPECT_CALL(*mock_vaapi_wrapper_, DestroyContextAndSurfaces(_));
......
...@@ -124,6 +124,7 @@ void VaapiVideoDecoder::Initialize(const VideoDecoderConfig& config, ...@@ -124,6 +124,7 @@ void VaapiVideoDecoder::Initialize(const VideoDecoderConfig& config,
decoder_ = nullptr; decoder_ = nullptr;
vaapi_wrapper_ = nullptr; vaapi_wrapper_ = nullptr;
decoder_delegate_ = nullptr;
SetState(State::kUninitialized); SetState(State::kUninitialized);
} }
...@@ -236,16 +237,6 @@ void VaapiVideoDecoder::HandleDecodeTask() { ...@@ -236,16 +237,6 @@ void VaapiVideoDecoder::HandleDecodeTask() {
} }
break; break;
case AcceleratedVideoDecoder::kConfigChange: case AcceleratedVideoDecoder::kConfigChange:
if (profile_ != decoder_->GetProfile()) {
DVLOGF(3) << "Profile is changed: " << profile_ << " -> "
<< decoder_->GetProfile();
}
if (pic_size_ == decoder_->GetPicSize()) {
// Profile only is changed.
// TODO(crbug.com/1022246): Handle profile change.
SetState(State::kError);
break;
}
// A new set of output buffers is requested. We either didn't have any // A new set of output buffers is requested. We either didn't have any
// output buffers yet or encountered a resolution change. // output buffers yet or encountered a resolution change.
// After the pipeline flushes all frames, OnPipelineFlushed() will be // After the pipeline flushes all frames, OnPipelineFlushed() will be
...@@ -401,7 +392,6 @@ void VaapiVideoDecoder::OnPipelineFlushed() { ...@@ -401,7 +392,6 @@ void VaapiVideoDecoder::OnPipelineFlushed() {
const gfx::Rect visible_rect = decoder_->GetVisibleRect(); const gfx::Rect visible_rect = decoder_->GetVisibleRect();
gfx::Size natural_size = GetNaturalSize(visible_rect, pixel_aspect_ratio_); gfx::Size natural_size = GetNaturalSize(visible_rect, pixel_aspect_ratio_);
pic_size_ = decoder_->GetPicSize(); pic_size_ = decoder_->GetPicSize();
profile_ = decoder_->GetProfile();
const base::Optional<VideoPixelFormat> format = const base::Optional<VideoPixelFormat> format =
GfxBufferFormatToVideoPixelFormat(GetBufferFormat()); GfxBufferFormatToVideoPixelFormat(GetBufferFormat());
CHECK(format); CHECK(format);
...@@ -413,7 +403,22 @@ void VaapiVideoDecoder::OnPipelineFlushed() { ...@@ -413,7 +403,22 @@ void VaapiVideoDecoder::OnPipelineFlushed() {
// All pending decode operations will be completed before triggering a // All pending decode operations will be completed before triggering a
// resolution change, so we can safely destroy the context here. // resolution change, so we can safely destroy the context here.
vaapi_wrapper_->DestroyContext(); if (profile_ != decoder_->GetProfile()) {
// When a profile is changed, we need to re-initialize VaapiWrapper.
profile_ = decoder_->GetProfile();
auto new_vaapi_wrapper = VaapiWrapper::CreateForVideoCodec(
VaapiWrapper::kDecode, profile_, base::DoNothing());
if (!new_vaapi_wrapper.get()) {
DLOG(WARNING) << "Failed creating VaapiWrapper";
SetState(State::kError);
return;
}
decoder_delegate_->set_vaapi_wrapper(new_vaapi_wrapper.get());
vaapi_wrapper_ = std::move(new_vaapi_wrapper);
} else {
vaapi_wrapper_->DestroyContext();
}
vaapi_wrapper_->CreateContext(pic_size_); vaapi_wrapper_->CreateContext(pic_size_);
// If we reset during resolution change, then there is no decode tasks. In // If we reset during resolution change, then there is no decode tasks. In
...@@ -526,16 +531,25 @@ bool VaapiVideoDecoder::CreateAcceleratedVideoDecoder() { ...@@ -526,16 +531,25 @@ bool VaapiVideoDecoder::CreateAcceleratedVideoDecoder() {
pic_size_ = gfx::Size(); pic_size_ = gfx::Size();
if (profile_ >= H264PROFILE_MIN && profile_ <= H264PROFILE_MAX) { if (profile_ >= H264PROFILE_MIN && profile_ <= H264PROFILE_MAX) {
decoder_.reset(new H264Decoder( auto accelerator =
std::make_unique<H264VaapiVideoDecoderDelegate>(this, vaapi_wrapper_), std::make_unique<H264VaapiVideoDecoderDelegate>(this, vaapi_wrapper_);
profile_, color_space_)); decoder_delegate_ = accelerator.get();
decoder_.reset(
new H264Decoder(std::move(accelerator), profile_, color_space_));
} else if (profile_ >= VP8PROFILE_MIN && profile_ <= VP8PROFILE_MAX) { } else if (profile_ >= VP8PROFILE_MIN && profile_ <= VP8PROFILE_MAX) {
decoder_.reset(new VP8Decoder( auto accelerator =
std::make_unique<VP8VaapiVideoDecoderDelegate>(this, vaapi_wrapper_))); std::make_unique<VP8VaapiVideoDecoderDelegate>(this, vaapi_wrapper_);
decoder_delegate_ = accelerator.get();
decoder_.reset(new VP8Decoder(std::move(accelerator)));
} else if (profile_ >= VP9PROFILE_MIN && profile_ <= VP9PROFILE_MAX) { } else if (profile_ >= VP9PROFILE_MIN && profile_ <= VP9PROFILE_MAX) {
decoder_.reset(new VP9Decoder( auto accelerator =
std::make_unique<VP9VaapiVideoDecoderDelegate>(this, vaapi_wrapper_), std::make_unique<VP9VaapiVideoDecoderDelegate>(this, vaapi_wrapper_);
profile_, color_space_)); decoder_delegate_ = accelerator.get();
decoder_.reset(
new VP9Decoder(std::move(accelerator), profile_, color_space_));
} else { } else {
VLOGF(1) << "Unsupported profile " << GetProfileName(profile_); VLOGF(1) << "Unsupported profile " << GetProfileName(profile_);
return false; return false;
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
namespace media { namespace media {
class AcceleratedVideoDecoder; class AcceleratedVideoDecoder;
class VaapiVideoDecoderDelegate;
class DmabufVideoFramePool; class DmabufVideoFramePool;
class VaapiWrapper; class VaapiWrapper;
class VideoFrame; class VideoFrame;
...@@ -170,6 +171,9 @@ class VaapiVideoDecoder : public DecoderInterface, ...@@ -170,6 +171,9 @@ class VaapiVideoDecoder : public DecoderInterface,
// Platform and codec specific video decoder. // Platform and codec specific video decoder.
std::unique_ptr<AcceleratedVideoDecoder> decoder_; std::unique_ptr<AcceleratedVideoDecoder> decoder_;
scoped_refptr<VaapiWrapper> vaapi_wrapper_; scoped_refptr<VaapiWrapper> vaapi_wrapper_;
// TODO(crbug.com/1022246): Instead of having the raw pointer here, getting
// the pointer from AcceleratedVideoDecoder.
VaapiVideoDecoderDelegate* decoder_delegate_ = nullptr;
SEQUENCE_CHECKER(decoder_sequence_checker_); SEQUENCE_CHECKER(decoder_sequence_checker_);
......
...@@ -24,4 +24,10 @@ VaapiVideoDecoderDelegate::~VaapiVideoDecoderDelegate() { ...@@ -24,4 +24,10 @@ VaapiVideoDecoderDelegate::~VaapiVideoDecoderDelegate() {
// DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
} }
void VaapiVideoDecoderDelegate::set_vaapi_wrapper(
scoped_refptr<VaapiWrapper> vaapi_wrapper) {
DETACH_FROM_SEQUENCE(sequence_checker_);
vaapi_wrapper_ = std::move(vaapi_wrapper);
}
} // namespace media } // namespace media
...@@ -16,12 +16,16 @@ class VaapiWrapper; ...@@ -16,12 +16,16 @@ class VaapiWrapper;
class VASurface; class VASurface;
// The common part of each AcceleratedVideoDecoder's Accelerator for VA-API. // The common part of each AcceleratedVideoDecoder's Accelerator for VA-API.
// This class allows clients to reset VaapiWrapper in case of a profile change.
// DecodeSurfaceHandler must stay alive for the lifetime of this class.
class VaapiVideoDecoderDelegate { class VaapiVideoDecoderDelegate {
public: public:
VaapiVideoDecoderDelegate(DecodeSurfaceHandler<VASurface>* const vaapi_dec, VaapiVideoDecoderDelegate(DecodeSurfaceHandler<VASurface>* const vaapi_dec,
scoped_refptr<VaapiWrapper> vaapi_wrapper); scoped_refptr<VaapiWrapper> vaapi_wrapper);
virtual ~VaapiVideoDecoderDelegate(); virtual ~VaapiVideoDecoderDelegate();
void set_vaapi_wrapper(scoped_refptr<VaapiWrapper> vaapi_wrapper);
VaapiVideoDecoderDelegate(const VaapiVideoDecoderDelegate&) = delete; VaapiVideoDecoderDelegate(const VaapiVideoDecoderDelegate&) = delete;
VaapiVideoDecoderDelegate& operator=(const VaapiVideoDecoderDelegate&) = VaapiVideoDecoderDelegate& operator=(const VaapiVideoDecoderDelegate&) =
delete; delete;
...@@ -29,7 +33,7 @@ class VaapiVideoDecoderDelegate { ...@@ -29,7 +33,7 @@ class VaapiVideoDecoderDelegate {
protected: protected:
// Both owned by caller. // Both owned by caller.
DecodeSurfaceHandler<VASurface>* const vaapi_dec_; DecodeSurfaceHandler<VASurface>* const vaapi_dec_;
const scoped_refptr<VaapiWrapper> vaapi_wrapper_; scoped_refptr<VaapiWrapper> vaapi_wrapper_;
SEQUENCE_CHECKER(sequence_checker_); SEQUENCE_CHECKER(sequence_checker_);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment