diff options
Diffstat (limited to 'chromium/media/gpu/android')
-rw-r--r-- | chromium/media/gpu/android/codec_image.cc | 34 | ||||
-rw-r--r-- | chromium/media/gpu/android/codec_image.h | 22 | ||||
-rw-r--r-- | chromium/media/gpu/android/codec_image_unittest.cc | 8 | ||||
-rw-r--r-- | chromium/media/gpu/android/frame_info_helper.cc | 229 | ||||
-rw-r--r-- | chromium/media/gpu/android/frame_info_helper.h | 21 | ||||
-rw-r--r-- | chromium/media/gpu/android/media_codec_video_decoder.cc | 76 | ||||
-rw-r--r-- | chromium/media/gpu/android/media_codec_video_decoder.h | 37 | ||||
-rw-r--r-- | chromium/media/gpu/android/media_codec_video_decoder_unittest.cc | 46 | ||||
-rw-r--r-- | chromium/media/gpu/android/video_frame_factory_impl.cc | 65 | ||||
-rw-r--r-- | chromium/media/gpu/android/video_frame_factory_impl.h | 16 | ||||
-rw-r--r-- | chromium/media/gpu/android/video_frame_factory_impl_unittest.cc | 120 |
11 files changed, 310 insertions, 364 deletions
diff --git a/chromium/media/gpu/android/codec_image.cc b/chromium/media/gpu/android/codec_image.cc index ae3a90da5c9..1a0b7d93184 100644 --- a/chromium/media/gpu/android/codec_image.cc +++ b/chromium/media/gpu/android/codec_image.cc @@ -25,11 +25,11 @@ CodecImage::~CodecImage() { void CodecImage::Initialize( std::unique_ptr<CodecOutputBufferRenderer> output_buffer_renderer, - scoped_refptr<CodecBufferWaitCoordinator> codec_buffer_wait_coordinator, + bool is_texture_owner_backed, PromotionHintAggregator::NotifyPromotionHintCB promotion_hint_cb) { DCHECK(output_buffer_renderer); output_buffer_renderer_ = std::move(output_buffer_renderer); - codec_buffer_wait_coordinator_ = std::move(codec_buffer_wait_coordinator); + is_texture_owner_backed_ = is_texture_owner_backed; promotion_hint_cb_ = std::move(promotion_hint_cb); } @@ -42,7 +42,6 @@ void CodecImage::NotifyUnused() { // our reference to the TextureOwner (if any). In other words, undo anything // that we did in Initialize. ReleaseCodecBuffer(); - codec_buffer_wait_coordinator_.reset(); promotion_hint_cb_ = base::NullCallback(); for (auto& cb : unused_cbs_) @@ -65,7 +64,7 @@ unsigned CodecImage::GetDataType() { CodecImage::BindOrCopy CodecImage::ShouldBindOrCopy() { // If we're using an overlay, then pretend it's bound. That way, we'll get // calls to ScheduleOverlayPlane. Otherwise, CopyTexImage needs to be called. - return !codec_buffer_wait_coordinator_ ? BIND : COPY; + return is_texture_owner_backed_ ? COPY : BIND; } bool CodecImage::BindTexImage(unsigned target) { @@ -82,16 +81,17 @@ bool CodecImage::CopyTexImage(unsigned target) { if (target != GL_TEXTURE_EXTERNAL_OES) return false; + if (!output_buffer_renderer_) + return true; + GLint bound_service_id = 0; glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &bound_service_id); // The currently bound texture should be the texture owner's texture. if (bound_service_id != static_cast<GLint>( - codec_buffer_wait_coordinator_->texture_owner()->GetTextureId())) + output_buffer_renderer_->texture_owner()->GetTextureId())) return false; - if (!output_buffer_renderer_) - return true; output_buffer_renderer_->RenderToTextureOwnerFrontBuffer( BindingsMode::kEnsureTexImageBound); @@ -113,7 +113,7 @@ bool CodecImage::ScheduleOverlayPlane( bool enable_blend, std::unique_ptr<gfx::GpuFence> gpu_fence) { TRACE_EVENT0("media", "CodecImage::ScheduleOverlayPlane"); - if (codec_buffer_wait_coordinator_) { + if (is_texture_owner_backed_) { DVLOG(1) << "Invalid call to ScheduleOverlayPlane; this image is " "TextureOwner backed."; return false; @@ -131,7 +131,7 @@ void CodecImage::NotifyOverlayPromotion(bool promotion, if (!promotion_hint_cb_) return; - if (!codec_buffer_wait_coordinator_ && promotion) { + if (!is_texture_owner_backed_ && promotion) { // When |CodecImage| is already backed by SurfaceView, and it should be used // as overlay. @@ -157,16 +157,6 @@ void CodecImage::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd, uint64_t process_tracing_id, const std::string& dump_name) {} -void CodecImage::GetTextureMatrix(float matrix[16]) { - static constexpr float kIdentity[16]{ - 1, 0, 0, 0, // - 0, 1, 0, 0, // - 0, 0, 1, 0, // - 0, 0, 0, 1 // - }; - memcpy(matrix, kIdentity, sizeof(kIdentity)); -} - void CodecImage::NotifyPromotionHint(bool promotion_hint, int display_x, int display_y, @@ -174,7 +164,7 @@ void CodecImage::NotifyPromotionHint(bool promotion_hint, int display_height) { // TODO(crbug.com/1004859): Add back early skip due to suspecting affecting // video smoothness. - if (promotion_hint && !codec_buffer_wait_coordinator_) + if (promotion_hint && !is_texture_owner_backed_) return; NotifyOverlayPromotion( @@ -241,11 +231,11 @@ CodecImage::GetAHardwareBuffer() { // as free when viz is still using us for drawing. This can happen if the // renderer crashes before receiving returns. It's hard to catch elsewhere, // so just handle it gracefully here. - if (!codec_buffer_wait_coordinator_) + if (!output_buffer_renderer_) return nullptr; RenderToTextureOwnerFrontBuffer(BindingsMode::kDontRestoreIfBound); - return codec_buffer_wait_coordinator_->texture_owner()->GetAHardwareBuffer(); + return output_buffer_renderer_->texture_owner()->GetAHardwareBuffer(); } gfx::Rect CodecImage::GetCropRect() { diff --git a/chromium/media/gpu/android/codec_image.h b/chromium/media/gpu/android/codec_image.h index 8693118f918..c765e24dbfe 100644 --- a/chromium/media/gpu/android/codec_image.h +++ b/chromium/media/gpu/android/codec_image.h @@ -15,7 +15,6 @@ #include "base/memory/ref_counted_delete_on_sequence.h" #include "gpu/command_buffer/service/gl_stream_texture_image.h" #include "gpu/command_buffer/service/stream_texture_shared_image_interface.h" -#include "media/gpu/android/codec_buffer_wait_coordinator.h" #include "media/gpu/android/codec_output_buffer_renderer.h" #include "media/gpu/android/promotion_hint_aggregator.h" #include "media/gpu/media_gpu_export.h" @@ -54,7 +53,7 @@ class MEDIA_GPU_EXPORT CodecImage // not in use. void Initialize( std::unique_ptr<CodecOutputBufferRenderer> output_buffer_renderer, - scoped_refptr<CodecBufferWaitCoordinator> codec_buffer_wait_coordinator, + bool is_texture_owner_backed, PromotionHintAggregator::NotifyPromotionHintCB promotion_hint_cb); // Add a callback that will be called when we're marked as unused. Does not @@ -91,7 +90,6 @@ class MEDIA_GPU_EXPORT CodecImage GetAHardwareBuffer() override; gfx::Rect GetCropRect() override; // gpu::gles2::GLStreamTextureMatrix implementation - void GetTextureMatrix(float xform[16]) override; // Currently this API is implemented by the NotifyOverlayPromotion, since this // API is expected to be removed. void NotifyPromotionHint(bool promotion_hint, @@ -129,18 +127,11 @@ class MEDIA_GPU_EXPORT CodecImage // Whether this image is backed by a texture owner. - // We want to check for texture_owner owned by - // |codec_buffer_wait_coordinator_| and hence only checking for - // |codec_buffer_wait_coordinator_| is enough here. - // TODO(vikassoni): Update the method name in future refactorings. - bool is_texture_owner_backed() const { - return !!codec_buffer_wait_coordinator_; - } + bool is_texture_owner_backed() const { return is_texture_owner_backed_; } scoped_refptr<gpu::TextureOwner> texture_owner() const { - return codec_buffer_wait_coordinator_ - ? codec_buffer_wait_coordinator_->texture_owner() - : nullptr; + return output_buffer_renderer_ ? output_buffer_renderer_->texture_owner() + : nullptr; } // Renders this image to the front buffer of its backing surface. @@ -180,9 +171,8 @@ class MEDIA_GPU_EXPORT CodecImage // frame available event before calling UpdateTexImage(). bool RenderToTextureOwnerFrontBuffer(BindingsMode bindings_mode); - // The CodecBufferWaitCoordinator that |output_buffer_| will be rendered to. - // Or null, if this image is backed by an overlay. - scoped_refptr<CodecBufferWaitCoordinator> codec_buffer_wait_coordinator_; + // Whether this image is texture_owner or overlay backed. + bool is_texture_owner_backed_ = false; // The bounds last sent to the overlay. gfx::Rect most_recent_bounds_; diff --git a/chromium/media/gpu/android/codec_image_unittest.cc b/chromium/media/gpu/android/codec_image_unittest.cc index 7fcd7eeba13..87496e335c9 100644 --- a/chromium/media/gpu/android/codec_image_unittest.cc +++ b/chromium/media/gpu/android/codec_image_unittest.cc @@ -94,7 +94,7 @@ class CodecImageTest : public testing::Test { scoped_refptr<CodecImage> image = new CodecImage(buffer_renderer->size()); image->Initialize( - std::move(buffer_renderer), codec_buffer_wait_coordinator, + std::move(buffer_renderer), kind == kTextureOwner, base::BindRepeating(&PromotionHintReceiver::OnPromotionHint, base::Unretained(&promotion_hint_receiver_))); @@ -144,7 +144,7 @@ TEST_F(CodecImageTest, UnusedCBRunsOnNotifyUnused) { base::MockCallback<CodecImage::UnusedCB> cb_2; auto i = NewImage(kTextureOwner); ASSERT_TRUE(i->get_codec_output_buffer_for_testing()); - ASSERT_TRUE(i->is_texture_owner_backed()); + ASSERT_TRUE(i->HasTextureOwner()); i->AddUnusedCB(cb_1.Get()); i->AddUnusedCB(cb_2.Get()); EXPECT_CALL(cb_1, Run(i.get())); @@ -153,7 +153,7 @@ TEST_F(CodecImageTest, UnusedCBRunsOnNotifyUnused) { // Also verify that the output buffer and texture owner are released. i->NotifyUnused(); EXPECT_FALSE(i->get_codec_output_buffer_for_testing()); - EXPECT_FALSE(i->is_texture_owner_backed()); + EXPECT_FALSE(i->HasTextureOwner()); // Verify that an additional call doesn't crash. It should do nothing. i->NotifyUnused(); @@ -391,7 +391,7 @@ TEST_F(CodecImageTest, CodedSizeVsVisibleSize) { std::make_unique<CodecOutputBufferRenderer>(std::move(buffer), nullptr); scoped_refptr<CodecImage> image = new CodecImage(coded_size); - image->Initialize(std::move(buffer_renderer), nullptr, + image->Initialize(std::move(buffer_renderer), false, PromotionHintAggregator::NotifyPromotionHintCB()); // Verify that CodecImage::GetSize returns coded_size and not visible_size diff --git a/chromium/media/gpu/android/frame_info_helper.cc b/chromium/media/gpu/android/frame_info_helper.cc index efe1873cb1c..b3cf5299aa7 100644 --- a/chromium/media/gpu/android/frame_info_helper.cc +++ b/chromium/media/gpu/android/frame_info_helper.cc @@ -4,10 +4,13 @@ #include "media/gpu/android/frame_info_helper.h" +#include "base/threading/sequence_bound.h" #include "gpu/command_buffer/service/shared_image_video.h" #include "gpu/ipc/service/command_buffer_stub.h" #include "gpu/ipc/service/gpu_channel.h" #include "gpu/ipc/service/gpu_channel_manager.h" +#include "media/base/bind_to_current_loop.h" +#include "media/gpu/android/codec_output_buffer_renderer.h" namespace media { @@ -21,100 +24,188 @@ FrameInfoHelper::FrameInfo& FrameInfoHelper::FrameInfo::operator=( // Concrete implementation of FrameInfoHelper that renders output buffers and // gets the FrameInfo they need. -class FrameInfoHelperImpl : public FrameInfoHelper, - public gpu::CommandBufferStub::DestructionObserver { +class FrameInfoHelperImpl : public FrameInfoHelper { public: - FrameInfoHelperImpl(SharedImageVideoProvider::GetStubCB get_stub_cb) { - stub_ = get_stub_cb.Run(); - if (stub_) - stub_->AddDestructionObserver(this); + FrameInfoHelperImpl(scoped_refptr<base::SequencedTaskRunner> gpu_task_runner, + SharedImageVideoProvider::GetStubCB get_stub_cb) { + on_gpu_ = base::SequenceBound<OnGpu>(std::move(gpu_task_runner), + std::move(get_stub_cb)); } - ~FrameInfoHelperImpl() override { - if (stub_) - stub_->RemoveDestructionObserver(this); + ~FrameInfoHelperImpl() override = default; + + void GetFrameInfo(std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer, + FrameInfoReadyCB callback) override { + Request request = {.buffer_renderer = std::move(buffer_renderer), + .callback = std::move(callback)}; + requests_.push(std::move(request)); + // If there were no pending requests start processing queue now. + if (requests_.size() == 1) + ProcessRequestsQueue(); } - void GetFrameInfo( - std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer, - base::OnceCallback< - void(std::unique_ptr<CodecOutputBufferRenderer>, FrameInfo, bool)> cb) - override { - if (!buffer_renderer) { - std::move(cb).Run(nullptr, FrameInfo(), false); - return; + private: + struct Request { + std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer; + FrameInfoReadyCB callback; + }; + + class OnGpu : public gpu::CommandBufferStub::DestructionObserver { + public: + OnGpu(SharedImageVideoProvider::GetStubCB get_stub_cb) { + stub_ = get_stub_cb.Run(); + if (stub_) + stub_->AddDestructionObserver(this); } - auto texture_owner = buffer_renderer->texture_owner(); + ~OnGpu() override { + if (stub_) + stub_->RemoveDestructionObserver(this); + } - FrameInfo info; + void OnWillDestroyStub(bool have_context) override { + DCHECK(stub_); + stub_ = nullptr; + } - // Indicates that the FrameInfo is reliable and can be cached by caller. - // It's true if we either return cached values or we attempted to render - // frame and succeeded. - bool success = true; - - // We default to visible size if if we can't get real size - info.coded_size = buffer_renderer->size(); - info.visible_rect = gfx::Rect(info.coded_size); - - if (texture_owner) { - if (visible_size_ == buffer_renderer->size()) { - info = frame_info_; - } else if (buffer_renderer->RenderToTextureOwnerFrontBuffer( - CodecOutputBufferRenderer::BindingsMode:: - kDontRestoreIfBound)) { - visible_size_ = buffer_renderer->size(); - texture_owner->GetCodedSizeAndVisibleRect( - visible_size_, &frame_info_.coded_size, &frame_info_.visible_rect); - - frame_info_.ycbcr_info = GetYCbCrInfo(texture_owner.get()); - info = frame_info_; - } else { - // We attempted to render frame and failed, mark request as failed so - // caller won't cache best-guess values. - success = false; + void GetFrameInfo( + std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer, + base::OnceCallback<void(std::unique_ptr<CodecOutputBufferRenderer>, + base::Optional<FrameInfo>)> cb) { + DCHECK(buffer_renderer); + + auto texture_owner = buffer_renderer->texture_owner(); + DCHECK(texture_owner); + + base::Optional<FrameInfo> info; + + if (buffer_renderer->RenderToTextureOwnerFrontBuffer( + CodecOutputBufferRenderer::BindingsMode::kDontRestoreIfBound)) { + gfx::Size coded_size; + gfx::Rect visible_rect; + if (texture_owner->GetCodedSizeAndVisibleRect( + buffer_renderer->size(), &coded_size, &visible_rect)) { + info.emplace(); + info->coded_size = coded_size; + info->visible_rect = visible_rect; + info->ycbcr_info = GetYCbCrInfo(texture_owner.get()); + } } + + std::move(cb).Run(std::move(buffer_renderer), info); + } + + private: + // Gets YCbCrInfo from last rendered frame. + base::Optional<gpu::VulkanYCbCrInfo> GetYCbCrInfo( + gpu::TextureOwner* texture_owner) { + gpu::ContextResult result; + + if (!stub_) + return base::nullopt; + + auto shared_context = + stub_->channel()->gpu_channel_manager()->GetSharedContextState( + &result); + auto context_provider = + (result == gpu::ContextResult::kSuccess) ? shared_context : nullptr; + if (!context_provider) + return base::nullopt; + + return gpu::SharedImageVideo::GetYcbcrInfo(texture_owner, + context_provider); } - std::move(cb).Run(std::move(buffer_renderer), frame_info_, success); + gpu::CommandBufferStub* stub_ = nullptr; + }; + + FrameInfo GetFrameInfoWithVisibleSize(const gfx::Size& visible_size) { + FrameInfo info; + info.coded_size = visible_size; + info.visible_rect = gfx::Rect(visible_size); + return info; } - void OnWillDestroyStub(bool have_context) override { - DCHECK(stub_); - stub_ = nullptr; + void OnFrameInfoReady( + std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer, + base::Optional<FrameInfo> frame_info) { + DCHECK(buffer_renderer); + DCHECK(!requests_.empty()); + + auto& request = requests_.front(); + + if (frame_info) { + visible_size_ = buffer_renderer->size(); + frame_info_ = *frame_info; + std::move(request.callback).Run(std::move(buffer_renderer), frame_info_); + } else { + // It's possible that we will fail to render frame and so weren't able to + // obtain FrameInfo. In this case we don't cache new values and complete + // current request with visible size, we will attempt to render next frame + // with next request. + auto info = GetFrameInfoWithVisibleSize(buffer_renderer->size()); + std::move(request.callback) + .Run(std::move(buffer_renderer), std::move(info)); + } + requests_.pop(); + ProcessRequestsQueue(); } - private: - // Gets YCbCrInfo from last rendered frame. - base::Optional<gpu::VulkanYCbCrInfo> GetYCbCrInfo( - gpu::TextureOwner* texture_owner) { - gpu::ContextResult result; - if (!stub_) - return base::nullopt; - - auto shared_context = - stub_->channel()->gpu_channel_manager()->GetSharedContextState(&result); - auto context_provider = - (result == gpu::ContextResult::kSuccess) ? shared_context : nullptr; - if (!context_provider) - return base::nullopt; - - return gpu::SharedImageVideo::GetYcbcrInfo(texture_owner, context_provider); + void ProcessRequestsQueue() { + while (!requests_.empty()) { + auto& request = requests_.front(); + + if (!request.buffer_renderer) { + // If we don't have buffer_renderer we can Run callback immediately. + std::move(request.callback).Run(nullptr, FrameInfo()); + } else if (!request.buffer_renderer->texture_owner()) { + // If there is no texture_owner (SurfaceView case), we can't render + // frame and get proper size. But as Display Compositor won't render + // this frame the actual size is not important, assume coded_size = + // visible_size. + auto info = + GetFrameInfoWithVisibleSize(request.buffer_renderer->size()); + std::move(request.callback) + .Run(std::move(request.buffer_renderer), std::move(info)); + } else if (visible_size_ == request.buffer_renderer->size()) { + // We have cached the results of last frame info request with the same + // size. We assume that coded_size doesn't change if the visible_size + // stays the same. + std::move(request.callback) + .Run(std::move(request.buffer_renderer), frame_info_); + } else { + // We have texture_owner and we don't have cached value, so we need to + // hop to GPU thread and render the frame to get proper size. + auto cb = BindToCurrentLoop( + base::BindOnce(&FrameInfoHelperImpl::OnFrameInfoReady, + weak_factory_.GetWeakPtr())); + + on_gpu_.Post(FROM_HERE, &OnGpu::GetFrameInfo, + std::move(request.buffer_renderer), std::move(cb)); + // We didn't complete this request quite yet, so we can't process queue + // any further. + break; + } + requests_.pop(); + } } - gpu::CommandBufferStub* stub_ = nullptr; + base::SequenceBound<OnGpu> on_gpu_; + std::queue<Request> requests_; + // Cached values. FrameInfo frame_info_; gfx::Size visible_size_; + + base::WeakPtrFactory<FrameInfoHelperImpl> weak_factory_{this}; }; // static -base::SequenceBound<FrameInfoHelper> FrameInfoHelper::Create( +std::unique_ptr<FrameInfoHelper> FrameInfoHelper::Create( scoped_refptr<base::SequencedTaskRunner> gpu_task_runner, SharedImageVideoProvider::GetStubCB get_stub_cb) { - return base::SequenceBound<FrameInfoHelperImpl>(std::move(gpu_task_runner), - std::move(get_stub_cb)); + return std::make_unique<FrameInfoHelperImpl>(std::move(gpu_task_runner), + std::move(get_stub_cb)); } -} // namespace media +} // namespace media
\ No newline at end of file diff --git a/chromium/media/gpu/android/frame_info_helper.h b/chromium/media/gpu/android/frame_info_helper.h index 5fc4ffca328..1f60bceb094 100644 --- a/chromium/media/gpu/android/frame_info_helper.h +++ b/chromium/media/gpu/android/frame_info_helper.h @@ -6,12 +6,11 @@ #define MEDIA_GPU_ANDROID_FRAME_INFO_HELPER_H_ #include "base/optional.h" -#include "base/threading/sequence_bound.h" -#include "media/gpu/android/codec_image.h" #include "media/gpu/android/shared_image_video_provider.h" #include "media/gpu/media_gpu_export.h" namespace media { +class CodecOutputBufferRenderer; // Helper class to fetch YCbCrInfo for Vulkan from a CodecImage. class MEDIA_GPU_EXPORT FrameInfoHelper { @@ -29,7 +28,11 @@ class MEDIA_GPU_EXPORT FrameInfoHelper { base::Optional<gpu::VulkanYCbCrInfo> ycbcr_info; }; - static base::SequenceBound<FrameInfoHelper> Create( + using FrameInfoReadyCB = + base::OnceCallback<void(std::unique_ptr<CodecOutputBufferRenderer>, + FrameInfo)>; + + static std::unique_ptr<FrameInfoHelper> Create( scoped_refptr<base::SequencedTaskRunner> gpu_task_runner, SharedImageVideoProvider::GetStubCB get_stub_cb); @@ -40,9 +43,11 @@ class MEDIA_GPU_EXPORT FrameInfoHelper { // attempt to get YCbCrInfo and cache it. If all necessary info is cached the // call will leave buffer_renderer intact and it can be rendered later. // Rendering can fail for reasons. This function will make best efforts to - // fill FrameInfo which can be used to create VideoFrame, but shouldn't be - // cached by caller. Last parameter in |cb| is bool that indicates that info - // is reliable. + // fill FrameInfo which can be used to create VideoFrame. + // + // Callbacks will be executed and on callers sequence and guaranteed to be + // called in order of GetFrameInfo calls. Callback can be called before this + // function returns if all necessary info is available right away. // // While this API might seem to be out of its Vulkan mind, it's this // complicated to (a) prevent rendering frames out of order to the front @@ -50,9 +55,7 @@ class MEDIA_GPU_EXPORT FrameInfoHelper { // can't get a YCbCrInfo from a CodecImage due to timeouts. virtual void GetFrameInfo( std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer, - base::OnceCallback<void(std::unique_ptr<CodecOutputBufferRenderer>, - FrameInfo, - bool)> cb) = 0; + FrameInfoReadyCB callback) = 0; protected: FrameInfoHelper() = default; diff --git a/chromium/media/gpu/android/media_codec_video_decoder.cc b/chromium/media/gpu/android/media_codec_video_decoder.cc index 6e127512fc2..848983075f6 100644 --- a/chromium/media/gpu/android/media_codec_video_decoder.cc +++ b/chromium/media/gpu/android/media_codec_video_decoder.cc @@ -19,6 +19,7 @@ #include "base/trace_event/trace_event.h" #include "media/base/android/media_codec_bridge_impl.h" #include "media/base/android/media_codec_util.h" +#include "media/base/async_destroy_video_decoder.h" #include "media/base/bind_to_current_loop.h" #include "media/base/cdm_context.h" #include "media/base/decoder_buffer.h" @@ -227,7 +228,9 @@ MediaCodecVideoDecoder::MediaCodecVideoDecoder( overlay_factory_cb_(std::move(overlay_factory_cb)), device_info_(device_info), enable_threaded_texture_mailboxes_( - gpu_preferences.enable_threaded_texture_mailboxes) { + gpu_preferences.enable_threaded_texture_mailboxes), + allow_nonsecure_overlays_( + base::FeatureList::IsEnabled(media::kAllowNonSecureOverlays)) { DVLOG(2) << __func__; surface_chooser_helper_.chooser()->SetClientCallbacks( base::Bind(&MediaCodecVideoDecoder::OnSurfaceChosen, @@ -236,44 +239,69 @@ MediaCodecVideoDecoder::MediaCodecVideoDecoder( weak_factory_.GetWeakPtr(), nullptr)); } +std::unique_ptr<VideoDecoder> MediaCodecVideoDecoder::Create( + const gpu::GpuPreferences& gpu_preferences, + const gpu::GpuFeatureInfo& gpu_feature_info, + std::unique_ptr<MediaLog> media_log, + DeviceInfo* device_info, + CodecAllocator* codec_allocator, + std::unique_ptr<AndroidVideoSurfaceChooser> surface_chooser, + AndroidOverlayMojoFactoryCB overlay_factory_cb, + RequestOverlayInfoCB request_overlay_info_cb, + std::unique_ptr<VideoFrameFactory> video_frame_factory) { + auto* decoder = new MediaCodecVideoDecoder( + gpu_preferences, gpu_feature_info, std::move(media_log), device_info, + codec_allocator, std::move(surface_chooser), + std::move(overlay_factory_cb), std::move(request_overlay_info_cb), + std::move(video_frame_factory)); + return std::make_unique<AsyncDestroyVideoDecoder<MediaCodecVideoDecoder>>( + base::WrapUnique(decoder)); +} + MediaCodecVideoDecoder::~MediaCodecVideoDecoder() { DVLOG(2) << __func__; TRACE_EVENT0("media", "MediaCodecVideoDecoder::~MediaCodecVideoDecoder"); ReleaseCodec(); } -void MediaCodecVideoDecoder::Destroy() { +void MediaCodecVideoDecoder::DestroyAsync( + std::unique_ptr<MediaCodecVideoDecoder> decoder) { DVLOG(1) << __func__; TRACE_EVENT0("media", "MediaCodecVideoDecoder::Destroy"); + DCHECK(decoder); + + // This will be destroyed by a call to |DeleteSoon| + // in |OnCodecDrained|. + auto* self = decoder.release(); // Cancel pending callbacks. // // WARNING: This will lose the callback we've given to MediaCodecBridge for // asynchronous notifications; so we must not leave this function with any // work necessary from StartTimerOrPumpCodec(). - weak_factory_.InvalidateWeakPtrs(); + self->weak_factory_.InvalidateWeakPtrs(); - if (media_crypto_context_) { + if (self->media_crypto_context_) { // Cancel previously registered callback (if any). - media_crypto_context_->SetMediaCryptoReadyCB(base::NullCallback()); - if (cdm_registration_id_) - media_crypto_context_->UnregisterPlayer(cdm_registration_id_); - media_crypto_context_ = nullptr; - cdm_registration_id_ = 0; + self->media_crypto_context_->SetMediaCryptoReadyCB(base::NullCallback()); + if (self->cdm_registration_id_) + self->media_crypto_context_->UnregisterPlayer(self->cdm_registration_id_); + self->media_crypto_context_ = nullptr; + self->cdm_registration_id_ = 0; } // Mojo callbacks require that they're run before destruction. - if (reset_cb_) - std::move(reset_cb_).Run(); + if (self->reset_cb_) + std::move(self->reset_cb_).Run(); // Cancel callbacks we no longer want. - codec_allocator_weak_factory_.InvalidateWeakPtrs(); - CancelPendingDecodes(DecodeStatus::ABORTED); - StartDrainingCodec(DrainType::kForDestroy); + self->codec_allocator_weak_factory_.InvalidateWeakPtrs(); + self->CancelPendingDecodes(DecodeStatus::ABORTED); + self->StartDrainingCodec(DrainType::kForDestroy); // Per the WARNING above. Validate that no draining work remains. - if (using_async_api_) - DCHECK(!drain_type_.has_value()); + if (self->using_async_api_) + DCHECK(!self->drain_type_.has_value()); } void MediaCodecVideoDecoder::Initialize(const VideoDecoderConfig& config, @@ -471,6 +499,12 @@ void MediaCodecVideoDecoder::StartLazyInit() { overlay_mode = VideoFrameFactory::OverlayMode::kRequestPromotionHints; } + // Regardless of whether we're using SurfaceControl or Dialog overlays, don't + // allow any overlays in A/B power testing mode, unless this requires a + // secure surface. Don't fail the playback for power testing. + if (!requires_secure_codec_ && !allow_nonsecure_overlays_) + overlay_mode = VideoFrameFactory::OverlayMode::kDontRequestPromotionHints; + video_frame_factory_->Initialize( overlay_mode, base::Bind(&MediaCodecVideoDecoder::OnVideoFrameFactoryInitialized, @@ -488,10 +522,16 @@ void MediaCodecVideoDecoder::OnVideoFrameFactoryInitialized( } texture_owner_bundle_ = new CodecSurfaceBundle(std::move(texture_owner)); + // This is for A/B power testing only. Turn off Dialog-based overlays in + // power testing mode, unless we need them for L1 content. + // See https://crbug.com/1081346 . + const bool allowed_for_experiment = + requires_secure_codec_ || allow_nonsecure_overlays_; + // Overlays are disabled when |enable_threaded_texture_mailboxes| is true // (http://crbug.com/582170). if (enable_threaded_texture_mailboxes_ || - !device_info_->SupportsOverlaySurfaces()) { + !device_info_->SupportsOverlaySurfaces() || !allowed_for_experiment) { OnSurfaceChosen(nullptr); return; } @@ -975,7 +1015,7 @@ void MediaCodecVideoDecoder::ForwardVideoFrame( if (reset_generation == reset_generation_) { // TODO(liberato): We might actually have a SW decoder. Consider setting // this to false if so, especially for higher bitrates. - frame->metadata()->SetBoolean(VideoFrameMetadata::POWER_EFFICIENT, true); + frame->metadata()->power_efficient = true; output_cb_.Run(std::move(frame)); } } diff --git a/chromium/media/gpu/android/media_codec_video_decoder.h b/chromium/media/gpu/android/media_codec_video_decoder.h index 59055e4d359..7e87139ae32 100644 --- a/chromium/media/gpu/android/media_codec_video_decoder.h +++ b/chromium/media/gpu/android/media_codec_video_decoder.h @@ -58,11 +58,14 @@ struct PendingDecode { // playbacks that need them. // TODO: Lazy initialization should be handled at a higher layer of the media // stack for both simplicity and cross platform support. -class MEDIA_GPU_EXPORT MediaCodecVideoDecoder : public VideoDecoder { +class MEDIA_GPU_EXPORT MediaCodecVideoDecoder final : public VideoDecoder { public: static std::vector<SupportedVideoDecoderConfig> GetSupportedConfigs(); - MediaCodecVideoDecoder( + ~MediaCodecVideoDecoder() override; + static void DestroyAsync(std::unique_ptr<MediaCodecVideoDecoder>); + + static std::unique_ptr<VideoDecoder> Create( const gpu::GpuPreferences& gpu_preferences, const gpu::GpuFeatureInfo& gpu_feature_info, std::unique_ptr<MediaLog> media_log, @@ -87,9 +90,20 @@ class MEDIA_GPU_EXPORT MediaCodecVideoDecoder : public VideoDecoder { bool CanReadWithoutStalling() const override; int GetMaxDecodeRequests() const override; - protected: - // Protected for testing. - ~MediaCodecVideoDecoder() override; + private: + // The test has access for PumpCodec() and the constructor. + friend class MediaCodecVideoDecoderTest; + + MediaCodecVideoDecoder( + const gpu::GpuPreferences& gpu_preferences, + const gpu::GpuFeatureInfo& gpu_feature_info, + std::unique_ptr<MediaLog> media_log, + DeviceInfo* device_info, + CodecAllocator* codec_allocator, + std::unique_ptr<AndroidVideoSurfaceChooser> surface_chooser, + AndroidOverlayMojoFactoryCB overlay_factory_cb, + RequestOverlayInfoCB request_overlay_info_cb, + std::unique_ptr<VideoFrameFactory> video_frame_factory); // Set up |cdm_context| as part of initialization. Guarantees that |init_cb| // will be called depending on the outcome, though not necessarily before this @@ -102,11 +116,6 @@ class MEDIA_GPU_EXPORT MediaCodecVideoDecoder : public VideoDecoder { JavaObjectPtr media_crypto, bool requires_secure_video_codec); - private: - // The test has access for PumpCodec(). - friend class MediaCodecVideoDecoderTest; - friend class base::DeleteHelper<MediaCodecVideoDecoder>; - enum class State { // Initializing resources required to create a codec. kInitializing, @@ -124,9 +133,6 @@ class MEDIA_GPU_EXPORT MediaCodecVideoDecoder : public VideoDecoder { enum class DrainType { kForReset, kForDestroy }; - // Starts teardown. - void Destroy() override; - // Finishes initialization. void StartLazyInit(); void OnVideoFrameFactoryInitialized( @@ -327,6 +333,11 @@ class MEDIA_GPU_EXPORT MediaCodecVideoDecoder : public VideoDecoder { // Optional crypto object from the Cdm. base::android::ScopedJavaGlobalRef<jobject> media_crypto_; + // For A/B power testing, this causes all non-L1 content to avoid overlays. + // This is only for A/B power testing, and can be removed after that. + // See https://crbug.com/1081346 . + bool allow_nonsecure_overlays_ = true; + base::WeakPtrFactory<MediaCodecVideoDecoder> weak_factory_{this}; base::WeakPtrFactory<MediaCodecVideoDecoder> codec_allocator_weak_factory_{ this}; diff --git a/chromium/media/gpu/android/media_codec_video_decoder_unittest.cc b/chromium/media/gpu/android/media_codec_video_decoder_unittest.cc index 61d4c13f3ed..16f3a5f4871 100644 --- a/chromium/media/gpu/android/media_codec_video_decoder_unittest.cc +++ b/chromium/media/gpu/android/media_codec_video_decoder_unittest.cc @@ -17,6 +17,7 @@ #include "media/base/android/media_codec_util.h" #include "media/base/android/mock_android_overlay.h" #include "media/base/android/mock_media_crypto_context.h" +#include "media/base/async_destroy_video_decoder.h" #include "media/base/decoder_buffer.h" #include "media/base/media_util.h" #include "media/base/test_helpers.h" @@ -52,12 +53,6 @@ std::unique_ptr<AndroidOverlay> CreateAndroidOverlayCb( return nullptr; } -// Make MCVD's destruction observable for teardown tests. -struct DestructionObservableMCVD : public DestructionObservable, - public MediaCodecVideoDecoder { - using MediaCodecVideoDecoder::MediaCodecVideoDecoder; -}; - } // namespace class MockVideoFrameFactory : public VideoFrameFactory { @@ -149,18 +144,16 @@ class MediaCodecVideoDecoderTest : public testing::TestWithParam<VideoCodec> { ON_CALL(*video_frame_factory_, Initialize(ExpectedOverlayMode(), _)) .WillByDefault(RunCallback<1>(texture_owner)); - auto* observable_mcvd = new DestructionObservableMCVD( + auto* mcvd = new MediaCodecVideoDecoder( gpu_preferences_, gpu_feature_info_, std::make_unique<NullMediaLog>(), device_info_.get(), codec_allocator_.get(), std::move(surface_chooser), base::BindRepeating(&CreateAndroidOverlayCb), base::BindRepeating(&MediaCodecVideoDecoderTest::RequestOverlayInfoCb, base::Unretained(this)), std::move(video_frame_factory)); - mcvd_.reset(observable_mcvd); - mcvd_raw_ = observable_mcvd; - destruction_observer_ = observable_mcvd->CreateDestructionObserver(); - // Ensure MCVD doesn't leak by default. - destruction_observer_->ExpectDestruction(); + mcvd_ = std::make_unique<AsyncDestroyVideoDecoder<MediaCodecVideoDecoder>>( + base::WrapUnique(mcvd)); + mcvd_raw_ = mcvd; } VideoFrameFactory::OverlayMode ExpectedOverlayMode() const { @@ -291,7 +284,6 @@ class MediaCodecVideoDecoderTest : public testing::TestWithParam<VideoCodec> { gpu::MockTextureOwner* texture_owner_; MockVideoFrameFactory* video_frame_factory_; NiceMock<base::MockCallback<VideoDecoder::DecodeCB>> decode_cb_; - std::unique_ptr<DestructionObserver> destruction_observer_; ProvideOverlayInfoCB provide_overlay_info_cb_; bool restart_for_transitions_; gpu::GpuPreferences gpu_preferences_; @@ -308,7 +300,7 @@ class MediaCodecVideoDecoderTest : public testing::TestWithParam<VideoCodec> { // |mcvd_raw_| lets us call PumpCodec() even after |mcvd_| is dropped, for // testing the teardown path. MediaCodecVideoDecoder* mcvd_raw_; - std::unique_ptr<MediaCodecVideoDecoder> mcvd_; + std::unique_ptr<VideoDecoder> mcvd_; }; // Tests which only work for a single codec. @@ -687,9 +679,6 @@ TEST_P(MediaCodecVideoDecoderVp8Test, UnregisterPlayerBeforeAsyncDestruction) { // before the decoder is actually destructed, asynchronously. EXPECT_CALL(*cdm_, UnregisterPlayer(MockMediaCryptoContext::kRegistrationId)); mcvd_.reset(); - - // Make sure the decoder has not been destroyed yet. - destruction_observer_->DoNotAllowDestruction(); } // A reference test for UnregisterPlayerBeforeAsyncDestruction. @@ -704,9 +693,6 @@ TEST_P(MediaCodecVideoDecoderVp8Test, UnregisterPlayerBeforeSyncDestruction) { // When |mcvd_| is reset, expect that it will unregister itself immediately. EXPECT_CALL(*cdm_, UnregisterPlayer(MockMediaCryptoContext::kRegistrationId)); mcvd_.reset(); - - // Make sure the decoder is now destroyed. - destruction_observer_->ExpectDestruction(); } TEST_P(MediaCodecVideoDecoderVp8Test, ResetDoesNotDrainVp8WithAsyncApi) { @@ -818,18 +804,9 @@ TEST_P(MediaCodecVideoDecoderTest, EosDecodeCbIsRunAfterEosIsDequeued) { std::move(video_frame_factory_->last_closure_).Run(); } -TEST_P(MediaCodecVideoDecoderTest, TeardownBeforeInitWorks) { - // Since we assert that MCVD is destructed by default, this test verifies that - // MCVD is destructed safely before Initialize(). -} - TEST_P(MediaCodecVideoDecoderTest, TeardownInvalidatesCodecCreationWeakPtr) { InitializeWithTextureOwner_OneDecodePending(TestVideoConfig::Large(codec_)); - destruction_observer_->DoNotAllowDestruction(); mcvd_.reset(); - // DeleteSoon() is now pending. Ensure it's safe if the codec creation - // completes before it runs. - destruction_observer_->ExpectDestruction(); EXPECT_CALL(*codec_allocator_, MockReleaseMediaCodec(NotNull())); ASSERT_TRUE(codec_allocator_->ProvideMockCodecAsync()); } @@ -837,11 +814,7 @@ TEST_P(MediaCodecVideoDecoderTest, TeardownInvalidatesCodecCreationWeakPtr) { TEST_P(MediaCodecVideoDecoderTest, TeardownInvalidatesCodecCreationWeakPtrButDoesNotCallReleaseMediaCodec) { InitializeWithTextureOwner_OneDecodePending(TestVideoConfig::Large(codec_)); - destruction_observer_->DoNotAllowDestruction(); mcvd_.reset(); - // DeleteSoon() is now pending. Ensure it's safe if the codec creation - // completes before it runs. - destruction_observer_->ExpectDestruction(); // A null codec should not be released via ReleaseMediaCodec(). EXPECT_CALL(*codec_allocator_, MockReleaseMediaCodec(_)).Times(0); @@ -880,7 +853,6 @@ TEST_P(MediaCodecVideoDecoderVp8Test, PumpCodec(); // MCVD should not be destructed immediately. - destruction_observer_->DoNotAllowDestruction(); mcvd_.reset(); base::RunLoop().RunUntilIdle(); @@ -888,7 +860,6 @@ TEST_P(MediaCodecVideoDecoderVp8Test, codec->AcceptOneInput(MockMediaCodecBridge::kEos); codec->ProduceOneOutput(MockMediaCodecBridge::kEos); EXPECT_CALL(*codec, Flush()).Times(0); - destruction_observer_->ExpectDestruction(); PumpCodec(); base::RunLoop().RunUntilIdle(); } @@ -1000,10 +971,7 @@ TEST_P(MediaCodecVideoDecoderTest, VideoFramesArePowerEfficient) { base::RunLoop().RunUntilIdle(); EXPECT_TRUE(!!most_recent_frame_); - bool power_efficient = false; - EXPECT_TRUE(most_recent_frame_->metadata()->GetBoolean( - VideoFrameMetadata::POWER_EFFICIENT, &power_efficient)); - EXPECT_TRUE(power_efficient); + EXPECT_TRUE(most_recent_frame_->metadata()->power_efficient); } TEST_P(MediaCodecVideoDecoderH264Test, CsdIsIncludedInCodecConfig) { diff --git a/chromium/media/gpu/android/video_frame_factory_impl.cc b/chromium/media/gpu/android/video_frame_factory_impl.cc index b7c768bae0c..1132f5995de 100644 --- a/chromium/media/gpu/android/video_frame_factory_impl.cc +++ b/chromium/media/gpu/android/video_frame_factory_impl.cc @@ -81,7 +81,7 @@ VideoFrameFactoryImpl::VideoFrameFactoryImpl( const gpu::GpuPreferences& gpu_preferences, std::unique_ptr<SharedImageVideoProvider> image_provider, std::unique_ptr<MaybeRenderEarlyManager> mre_manager, - base::SequenceBound<FrameInfoHelper> frame_info_helper) + std::unique_ptr<FrameInfoHelper> frame_info_helper) : image_provider_(std::move(image_provider)), gpu_task_runner_(std::move(gpu_task_runner)), enable_threaded_texture_mailboxes_( @@ -171,7 +171,7 @@ void VideoFrameFactoryImpl::CreateVideoFrame( auto image_ready_cb = base::BindOnce(&VideoFrameFactoryImpl::CreateVideoFrame_OnImageReady, weak_factory_.GetWeakPtr(), std::move(output_cb), - timestamp, natural_size, codec_buffer_wait_coordinator_, + timestamp, natural_size, !!codec_buffer_wait_coordinator_, std::move(promotion_hint_cb), pixel_format, overlay_mode_, enable_threaded_texture_mailboxes_, gpu_task_runner_); @@ -181,48 +181,20 @@ void VideoFrameFactoryImpl::CreateVideoFrame( void VideoFrameFactoryImpl::RequestImage( std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer, ImageWithInfoReadyCB image_ready_cb) { - if (buffer_renderer && visible_size_ == buffer_renderer->size()) { - auto cb = base::BindOnce(std::move(image_ready_cb), - std::move(buffer_renderer), frame_info_); - - image_provider_->RequestImage( - std::move(cb), image_spec_, - codec_buffer_wait_coordinator_ - ? codec_buffer_wait_coordinator_->texture_owner() - : nullptr); - return; - } - - // We need to reset size to make sure VFFI pipeline is still ordered. - // e.g: CreateVideoFrame is called with new size. We post task to GPU thread - // to get new frame info. While we wait CreateVideoFrame might be called with - // old size again and if we don't reset size here we will skip GPU hop and new - // frame will be created earlier than first one. - visible_size_ = gfx::Size(); - - auto info_cb = BindToCurrentLoop( + auto info_cb = base::BindOnce(&VideoFrameFactoryImpl::CreateVideoFrame_OnFrameInfoReady, weak_factory_.GetWeakPtr(), std::move(image_ready_cb), - codec_buffer_wait_coordinator_)); + codec_buffer_wait_coordinator_); - frame_info_helper_.Post(FROM_HERE, &FrameInfoHelper::GetFrameInfo, - std::move(buffer_renderer), std::move(info_cb)); + frame_info_helper_->GetFrameInfo(std::move(buffer_renderer), + std::move(info_cb)); } void VideoFrameFactoryImpl::CreateVideoFrame_OnFrameInfoReady( ImageWithInfoReadyCB image_ready_cb, scoped_refptr<CodecBufferWaitCoordinator> codec_buffer_wait_coordinator, std::unique_ptr<CodecOutputBufferRenderer> output_buffer_renderer, - FrameInfoHelper::FrameInfo frame_info, - bool success) { - // To get frame info we need to render frame which might fail for variety of - // reason. FrameInfoHelper will provide best values we can proceed with, but - // we should not cache it and attempt to get info for next frame. - if (success) { - frame_info_ = frame_info; - visible_size_ = output_buffer_renderer->size(); - } - + FrameInfoHelper::FrameInfo frame_info) { // If we don't have output buffer here we can't rely on reply from // FrameInfoHelper as there might be not cached value and we can't render // nothing. But in this case call comes from RunAfterPendingVideoFrames and we @@ -246,7 +218,7 @@ void VideoFrameFactoryImpl::CreateVideoFrame_OnImageReady( OnceOutputCB output_cb, base::TimeDelta timestamp, gfx::Size natural_size, - scoped_refptr<CodecBufferWaitCoordinator> codec_buffer_wait_coordinator, + bool is_texture_owner_backed, PromotionHintAggregator::NotifyPromotionHintCB promotion_hint_cb, VideoPixelFormat pixel_format, OverlayMode overlay_mode, @@ -268,7 +240,7 @@ void VideoFrameFactoryImpl::CreateVideoFrame_OnImageReady( // When we remove the output buffer management from CodecImage, then that's // what we'd have a reference to here rather than CodecImage. record.codec_image_holder->codec_image_raw()->Initialize( - std::move(output_buffer_renderer), codec_buffer_wait_coordinator, + std::move(output_buffer_renderer), is_texture_owner_backed, std::move(promotion_hint_cb)); // Send the CodecImage (via holder, since we can't touch the refcount here) to @@ -301,7 +273,7 @@ void VideoFrameFactoryImpl::CreateVideoFrame_OnImageReady( // The frames must be copied when threaded texture mailboxes are in use // (http://crbug.com/582170). if (enable_threaded_texture_mailboxes) - frame->metadata()->SetBoolean(VideoFrameMetadata::COPY_REQUIRED, true); + frame->metadata()->copy_required = true; const bool is_surface_control = overlay_mode == OverlayMode::kSurfaceControlSecure || @@ -309,25 +281,20 @@ void VideoFrameFactoryImpl::CreateVideoFrame_OnImageReady( const bool wants_promotion_hints = overlay_mode == OverlayMode::kRequestPromotionHints; - // Remember that we can't access |codec_buffer_wait_coordinator|, but we can - // check if we have one here. bool allow_overlay = false; if (is_surface_control) { - DCHECK(codec_buffer_wait_coordinator); + DCHECK(is_texture_owner_backed); allow_overlay = true; } else { // We unconditionally mark the picture as overlayable, even if - // |!codec_buffer_wait_coordinator|, if we want to get hints. It's + // |!is_texture_owner_backed|, if we want to get hints. It's // required, else we won't get hints. - allow_overlay = !codec_buffer_wait_coordinator || wants_promotion_hints; + allow_overlay = !is_texture_owner_backed || wants_promotion_hints; } - frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, - allow_overlay); - frame->metadata()->SetBoolean(VideoFrameMetadata::WANTS_PROMOTION_HINT, - wants_promotion_hints); - frame->metadata()->SetBoolean(VideoFrameMetadata::TEXTURE_OWNER, - !!codec_buffer_wait_coordinator); + frame->metadata()->allow_overlay = allow_overlay; + frame->metadata()->wants_promotion_hint = wants_promotion_hints; + frame->metadata()->texture_owner = is_texture_owner_backed; // TODO(liberato): if this is run via being dropped, then it would be nice // to find that out rather than treating the image as unused. If the renderer diff --git a/chromium/media/gpu/android/video_frame_factory_impl.h b/chromium/media/gpu/android/video_frame_factory_impl.h index 624d7d2b650..489149eb765 100644 --- a/chromium/media/gpu/android/video_frame_factory_impl.h +++ b/chromium/media/gpu/android/video_frame_factory_impl.h @@ -10,7 +10,6 @@ #include "base/memory/weak_ptr.h" #include "base/optional.h" #include "base/single_thread_task_runner.h" -#include "base/threading/sequence_bound.h" #include "gpu/config/gpu_preferences.h" #include "media/base/video_frame.h" #include "media/gpu/android/codec_buffer_wait_coordinator.h" @@ -52,7 +51,7 @@ class MEDIA_GPU_EXPORT VideoFrameFactoryImpl : public VideoFrameFactory { const gpu::GpuPreferences& gpu_preferences, std::unique_ptr<SharedImageVideoProvider> image_provider, std::unique_ptr<MaybeRenderEarlyManager> mre_manager, - base::SequenceBound<FrameInfoHelper> frame_info_helper); + std::unique_ptr<FrameInfoHelper> frame_info_helper); ~VideoFrameFactoryImpl() override; void Initialize(OverlayMode overlay_mode, InitCB init_cb) override; @@ -91,7 +90,7 @@ class MEDIA_GPU_EXPORT VideoFrameFactoryImpl : public VideoFrameFactory { OnceOutputCB output_cb, base::TimeDelta timestamp, gfx::Size natural_size, - scoped_refptr<CodecBufferWaitCoordinator> codec_buffer_wait_coordinator, + bool is_texture_owner_backed, PromotionHintAggregator::NotifyPromotionHintCB promotion_hint_cb, VideoPixelFormat pixel_format, OverlayMode overlay_mode, @@ -105,8 +104,7 @@ class MEDIA_GPU_EXPORT VideoFrameFactoryImpl : public VideoFrameFactory { ImageWithInfoReadyCB image_ready_cb, scoped_refptr<CodecBufferWaitCoordinator> codec_buffer_wait_coordinator, std::unique_ptr<CodecOutputBufferRenderer> output_buffer_renderer, - FrameInfoHelper::FrameInfo frame_info, - bool success); + FrameInfoHelper::FrameInfo frame_info); MaybeRenderEarlyManager* mre_manager() const { return mre_manager_.get(); } @@ -128,12 +126,8 @@ class MEDIA_GPU_EXPORT VideoFrameFactoryImpl : public VideoFrameFactory { std::unique_ptr<MaybeRenderEarlyManager> mre_manager_; - // Caches FrameInfo and visible size it was cached for. - gfx::Size visible_size_; - FrameInfoHelper::FrameInfo frame_info_; - - // Optional helper to get the Vulkan YCbCrInfo. - base::SequenceBound<FrameInfoHelper> frame_info_helper_; + // Helper to get coded_size and optional Vulkan YCbCrInfo. + std::unique_ptr<FrameInfoHelper> frame_info_helper_; // The current image spec that we'll use to request images. SharedImageVideoProvider::ImageSpec image_spec_; diff --git a/chromium/media/gpu/android/video_frame_factory_impl_unittest.cc b/chromium/media/gpu/android/video_frame_factory_impl_unittest.cc index ade0a27c05d..13231efe252 100644 --- a/chromium/media/gpu/android/video_frame_factory_impl_unittest.cc +++ b/chromium/media/gpu/android/video_frame_factory_impl_unittest.cc @@ -44,46 +44,14 @@ class MockMaybeRenderEarlyManager : public MaybeRenderEarlyManager { class MockFrameInfoHelper : public FrameInfoHelper, public DestructionObservable { public: - MockFrameInfoHelper(MockFrameInfoHelper** thiz) { *thiz = this; } - - void GetFrameInfo( - std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer, - base::OnceCallback< - void(std::unique_ptr<CodecOutputBufferRenderer>, FrameInfo, bool)> cb) - override { - MockGetFrameInfo(buffer_renderer.get()); - cb_ = std::move(cb); - buffer_renderer_ = std::move(buffer_renderer); - - if (run_callback_automatically_) { - RunWithYcbCrInfo(true); - base::RunLoop().RunUntilIdle(); - } - } - - void RunWithYcbCrInfo(bool success) { - DCHECK(buffer_renderer_); - + void GetFrameInfo(std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer, + FrameInfoReadyCB cb) override { FrameInfo info; - info.coded_size = buffer_renderer_->size(); + info.coded_size = buffer_renderer->size(); info.visible_rect = gfx::Rect(info.coded_size); - std::move(cb_).Run(std::move(buffer_renderer_), info, success); - } - - void set_run_callback_automatically(bool run_callback_automatically) { - run_callback_automatically_ = run_callback_automatically; + std::move(cb).Run(std::move(buffer_renderer), info); } - - MOCK_METHOD1(MockGetFrameInfo, - void(CodecOutputBufferRenderer* buffer_renderer)); - - private: - bool run_callback_automatically_ = true; - base::OnceCallback< - void(std::unique_ptr<CodecOutputBufferRenderer>, FrameInfo, bool)> - cb_; - std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer_; }; class VideoFrameFactoryImplTest : public testing::Test { @@ -96,15 +64,11 @@ class VideoFrameFactoryImplTest : public testing::Test { auto mre_manager = std::make_unique<MockMaybeRenderEarlyManager>(); mre_manager_raw_ = mre_manager.get(); - auto ycbcr_helper = base::SequenceBound<MockFrameInfoHelper>( - task_runner_, &ycbcr_helper_raw_); - base::RunLoop().RunUntilIdle(); // Init |ycbcr_helper_raw_|. - ycbcr_destruction_observer_ = - ycbcr_helper_raw_->CreateDestructionObserver(); + auto info_helper = std::make_unique<MockFrameInfoHelper>(); impl_ = std::make_unique<VideoFrameFactoryImpl>( task_runner_, gpu_preferences_, std::move(image_provider), - std::move(mre_manager), std::move(ycbcr_helper)); + std::move(mre_manager), std::move(info_helper)); auto texture_owner = base::MakeRefCounted<NiceMock<gpu::MockTextureOwner>>( 0, nullptr, nullptr, true); auto codec_buffer_wait_coordinator = @@ -177,7 +141,6 @@ class VideoFrameFactoryImplTest : public testing::Test { // Sent to |impl_| by RequestVideoFrame.. base::MockCallback<VideoFrameFactory::OnceOutputCB> output_cb_; - MockFrameInfoHelper* ycbcr_helper_raw_ = nullptr; std::unique_ptr<DestructionObserver> ycbcr_destruction_observer_; gpu::GpuPreferences gpu_preferences_; @@ -272,75 +235,4 @@ TEST_F(VideoFrameFactoryImplTest, impl_ = nullptr; base::RunLoop().RunUntilIdle(); } - -TEST_F(VideoFrameFactoryImplTest, DoesCallFrameInfoHelperIfVulkan) { - // We will be driving callback by ourselves in this test. - ycbcr_helper_raw_->set_run_callback_automatically(false); - // Expect call to get info for the first frame. - EXPECT_CALL(*ycbcr_helper_raw_, MockGetFrameInfo(_)).Times(1); - - RequestVideoFrame(); - - // Provide info. It should send image request. - ycbcr_helper_raw_->RunWithYcbCrInfo(true); - base::RunLoop().RunUntilIdle(); - - testing::Mock::VerifyAndClearExpectations(ycbcr_helper_raw_); - - // Fulfilling image request should provide video frame. - EXPECT_CALL(output_cb_, Run(_)).Times(1); - - auto image_record = MakeImageRecord(); - image_provider_raw_->ProvideOneRequestedImage(&image_record); - base::RunLoop().RunUntilIdle(); - - // Verify that no more calls happen, since we don't want thread hops on every - // frame. Note that multiple could be dispatched before now. It should still - // send along a VideoFrame, though. - EXPECT_CALL(*ycbcr_helper_raw_, MockGetFrameInfo(_)).Times(0); - EXPECT_CALL(output_cb_, Run(_)).Times(1); - - RequestVideoFrame(); - auto other_image_record = MakeImageRecord(); - // If the helper hasn't been destroyed, then we don't expect it to be called. - image_provider_raw_->ProvideOneRequestedImage(&other_image_record); - base::RunLoop().RunUntilIdle(); -} - -TEST_F(VideoFrameFactoryImplTest, NullYCbCrInfoDoesntCrash) { - // We will be driving callback by ourselves in this test. - ycbcr_helper_raw_->set_run_callback_automatically(false); - - // Expect call to get info for the first frame. - EXPECT_CALL(*ycbcr_helper_raw_, MockGetFrameInfo(_)).Times(1); - - RequestVideoFrame(); - - // Provide info. It should send image request. - ycbcr_helper_raw_->RunWithYcbCrInfo(false); - base::RunLoop().RunUntilIdle(); - - testing::Mock::VerifyAndClearExpectations(ycbcr_helper_raw_); - - // Fulfilling image request should provide video frame. - EXPECT_CALL(output_cb_, Run(_)).Times(1); - - auto image_record = MakeImageRecord(); - image_provider_raw_->ProvideOneRequestedImage(&image_record); - base::RunLoop().RunUntilIdle(); - - // Verify that we will get call to GetFrameInfo as previous one failed. - EXPECT_CALL(*ycbcr_helper_raw_, MockGetFrameInfo(_)).Times(1); - EXPECT_CALL(output_cb_, Run(_)).Times(1); - - RequestVideoFrame(); - ycbcr_helper_raw_->RunWithYcbCrInfo(true); - base::RunLoop().RunUntilIdle(); - - auto other_image_record = MakeImageRecord(); - // If the helper hasn't been destroyed, then we don't expect it to be called. - image_provider_raw_->ProvideOneRequestedImage(&other_image_record); - base::RunLoop().RunUntilIdle(); -} - } // namespace media |