下载代码,调试方法等见Chromium视频播放相关调试记录_bberdong的博客-CSDN博客
硬解流程
GPU进程
MediaService::CreateInterfaceFactory,然后创建了InterfaceFactoryImpl。
创建解码器
- gpu进程收到了一个message创建了一个MojoVideoDecoderService出来
源码路径: media/mojo/services/interface_factory_impl.cc
void InterfaceFactoryImpl::CreateVideoDecoder(
mojo::PendingReceiver<mojom::VideoDecoder> receiver,
mojo::PendingRemote<media::stable::mojom::StableVideoDecoder>
dst_video_decoder) {
DVLOG(2) << __func__;
#if BUILDFLAG(ENABLE_MOJO_VIDEO_DECODER)
video_decoder_receivers_.Add(std::make_unique<MojoVideoDecoderService>(
mojo_media_client_, &cdm_service_context_,
std::move(dst_video_decoder)),
std::move(receiver));
#endif // BUILDFLAG(ENABLE_MOJO_VIDEO_DECODER)
}
- MojoVideoDecoderService创建了一个platform video decoder。咱们这里是VadVideoDecoder
源码路径: media/mojo/services/mojo_video_decoder_service.cc
void MojoVideoDecoderService::Construct(...
{
...
decoder_ = mojo_media_client_->CreateVideoDecoder(...)
...
}
// decoder_定义
std::unique_ptr<media::VideoDecoder> decoder_;
// mojo_media_client_定义
// Decoder factory.
raw_ptr<MojoMediaClient> mojo_media_client_;
而GpuMojoMediaClient继承自MojoMediaClient
std::unique_ptr<VideoDecoder> GpuMojoMediaClient::CreateVideoDecoder(...
{
...
return CreatePlatformVideoDecoder(traits);
...
}
调用的CreatePlatformVideoDecoder方法在另外一个文件里
源码路径: media/mojo/services/gpu_mojo_media_client_cros.cc
std::unique_ptr<VideoDecoder> CreatePlatformVideoDecoder(
const VideoDecoderTraits& traits) {
switch (GetActualPlatformDecoderImplementation(traits.gpu_preferences,
traits.gpu_info)) {
case VideoDecoderType::kVaapi:
case VideoDecoderType::kV4L2: {
auto frame_pool = std::make_unique<PlatformVideoFramePool>(
traits.gpu_memory_buffer_factory);
auto frame_converter = MailboxVideoFrameConverter::Create(
base::BindRepeating(&PlatformVideoFramePool::UnwrapFrame,
base::Unretained(frame_pool.get())),
traits.gpu_task_runner, traits.get_command_buffer_stub_cb);
return VideoDecoderPipeline::Create(
traits.task_runner, std::move(frame_pool), std::move(frame_converter),
traits.media_log->Clone());
}
// 这里竟然是kVda类型的
case VideoDecoderType::kVda: {
return VdaVideoDecoder::Create(
traits.task_runner, traits.gpu_task_runner, traits.media_log->Clone(),
*traits.target_color_space, traits.gpu_preferences,
*traits.gpu_workarounds, traits.get_command_buffer_stub_cb);
}
default: {
return nullptr;
}
}
}
VdaVideoDecoder又包装了一个AsyncDestroyVideoDecoder
std::unique_ptr<VideoDecoder> VdaVideoDecoder::Create(
scoped_refptr<base::SingleThreadTaskRunner> parent_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
std::unique_ptr<MediaLog> media_log,
const gfx::ColorSpace& target_color_space,
const gpu::GpuPreferences& gpu_preferences,
const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
GetStubCB get_stub_cb) {
auto* decoder = new VdaVideoDecoder(
std::move(parent_task_runner), std::move(gpu_task_runner),
std::move(media_log), target_color_space,
base::BindOnce(&PictureBufferManager::Create),
base::BindOnce(&CreateCommandBufferHelper, std::move(get_stub_cb)),
base::BindRepeating(&CreateAndInitializeVda, gpu_preferences,
gpu_workarounds),
GpuVideoAcceleratorUtil::ConvertGpuToMediaDecodeCapabilities(
GpuVideoDecodeAcceleratorFactory::GetDecoderCapabilities(
gpu_preferences, gpu_workarounds)));
return std::make_unique<AsyncDestroyVideoDecoder<VdaVideoDecoder>>(
base::WrapUnique(decoder));
}
AsyncDestroyVideoDecoder类定义如下:
template <typename T>
class AsyncDestroyVideoDecoder final : public VideoDecoder {
public:
explicit AsyncDestroyVideoDecoder(std::unique_ptr<T> wrapped_decoder)
: wrapped_decoder_(std::move(wrapped_decoder)) {
static_assert(std::is_base_of<VideoDecoder, T>::value,
"T must implement 'media::VideoDecoder'");
DCHECK(wrapped_decoder_);
}
...
...
std::unique_ptr<T> wrapped_decoder_;
}
也就是说这里AsyncDestroyVideoDecoder包了一层VdaVideoDecoder,wrapped_decoder_就是一个VdaVideoDecoder::Create通过make_unique创建出来的,VdaVideoDecoder对象的引用。
而VdaVideoDecoder最终在硬解的时候就是使用的VaapiVideoDecodeAccelerator
// TODO 详细展开一下Vda到Vaapi!
解码过程
使用chrome://tracing跟踪代码过程
trace选中的是media和gpu两个模块
chrome进程:
注意,这里是MojoVideoDecoder一直在调用Decode方法
GPU进程
这里也是MojoVideoDecoder的对端,MojoVideoDecoderService
这里也一直在调用MojoVideoDecoderService::Decode()方法,后面还有VaapiDecoderThread在干具体的工作,调用vaapi接口来进行解码。
释放解码器
源码路径: media/mojo/services/mojo_video_decoder_service.cc
MojoVideoDecoderService::~MojoVideoDecoderService() {
...
if (init_cb_) {
OnDecoderInitialized(DecoderStatus::Codes::kInterrupted);
}
if (reset_cb_)
OnDecoderReset();
...
// Destruct the VideoDecoder here so its destruction duration is included by
// the histogram timer below.
weak_factory_.InvalidateWeakPtrs();
decoder_.reset();
}
前面说过,这里的decoder关联的就是VdaVideoDecoder,但这里调用的不是decoder的Reset方法,那样的话应该写作decoder_->reset(); 这里直接.操作符说明,这里调用的是decoder本身的类型—unique_ptr的reset方法。
也就是说MojoVideoDecoderService的指针被reset了,这个操作直接引发了对应的decoder对象的析构。
源码路径: media/base/async_destroy_video_decoder.h
~AsyncDestroyVideoDecoder() override {
if (wrapped_decoder_)
T::DestroyAsync(std::move(wrapped_decoder_));
}
如前面所说,这里通过AsyncDestroyVideoDecoder这个包装实际调用的是下面的函数
源码路径: media/gpu/ipc/service/vda_video_decoder.cc
void VdaVideoDecoder::DestroyAsync(std::unique_ptr<VdaVideoDecoder> decoder) {
// TODO(sandersd): The documentation says that DestroyAsync() fires any
// pending callbacks.
// Prevent any more callbacks to this thread.
decoder->parent_weak_this_factory_.InvalidateWeakPtrs();
// Pass ownership of the destruction process over to the GPU thread.
auto* gpu_task_runner = decoder->gpu_task_runner_.get();
gpu_task_runner->PostTask(
FROM_HERE,
base::BindOnce(&VdaVideoDecoder::CleanupOnGpuThread, std::move(decoder)));
}
void VdaVideoDecoder::CleanupOnGpuThread(
std::unique_ptr<VdaVideoDecoder> decoder) {
DVLOG(2) << __func__;
DCHECK(decoder);
DCHECK(decoder->gpu_task_runner_->BelongsToCurrentThread());
// VDA destruction is likely to result in reentrant calls to
// NotifyEndOfBitstreamBuffer(). Invalidating |gpu_weak_vda_| ensures that we
// don't call back into |vda_| during its destruction.
decoder->gpu_weak_vda_factory_ = nullptr;
decoder->vda_ = nullptr;
decoder->media_log_ = nullptr;
// Because |parent_weak_this_| was invalidated in Destroy(), picture buffer
// dismissals since then have been dropped on the floor.
decoder->picture_buffer_manager_->DismissAllPictureBuffers();
}
vad_的定义:
// Only written on the GPU thread during initialization, which is mutually
// exclusive with reads on the parent thread.
std::unique_ptr<VideoDecodeAccelerator> vda_;
而在硬解的时候,这里VideoDecodeAccelerator的实例即是VaapiVideoDecodeAccelerator
源码路径: media/gpu/vaapi/vaapi_video_decode_accelerator.cc
// Class to provide video decode acceleration for Intel systems with hardware
// support for it, and on which libva is available.
// Decoding tasks are performed in a separate decoding thread.
//
// Threading/life-cycle: this object is created & destroyed on the GPU
// ChildThread. A few methods on it are called on the decoder thread which is
// stopped during |this->Destroy()|, so any tasks posted to the decoder thread
// can assume |*this| is still alive. See |weak_this_| below for more details.
class MEDIA_GPU_EXPORT VaapiVideoDecodeAccelerator
: public VideoDecodeAccelerator,
public DecodeSurfaceHandler<VASurface>,
public base::trace_event::MemoryDumpProvider {
在这个对象被置为nullptr的时候,就触发了VaapiVideoDecodeAccelerator的 destructor函数。然后调用了Destroy函数,Destroy中调用的Cleanup才是真正做清理的函数。
void VaapiVideoDecodeAccelerator::Cleanup() {
DCHECK(task_runner_->BelongsToCurrentThread());
base::AutoLock auto_lock(lock_);
if (state_ == kUninitialized || state_ == kDestroying)
return;
// 在停止播放的时候比较常见的一行log
VLOGF(2) << "Destroying VAVDA";
state_ = kDestroying;
// Call DismissPictureBuffer() to notify |client_| that the picture buffers
// are no longer used and thus |client_| shall release them. If |client_| has
// been invalidated in NotifyError(),|client_| will be destroyed shortly. The
// destruction should release all the PictureBuffers.
if (client_) {
for (const auto& id_and_picture : pictures_)
client_->DismissPictureBuffer(id_and_picture.first);
}
pictures_.clear();
client_ptr_factory_.reset();
weak_this_factory_.InvalidateWeakPtrs();
// TODO(mcasas): consider deleting |decoder_| on
// |decoder_thread_task_runner_|, https://crbug.com/789160.
// Signal all potential waiters on the decoder_thread_, let them early-exit,
// as we've just moved to the kDestroying state, and wait for all tasks
// to finish.
input_ready_.Signal();
surfaces_available_.Signal();
{
base::AutoUnlock auto_unlock(lock_);
decoder_thread_.Stop();
}
if (buffer_allocation_mode_ != BufferAllocationMode::kNone)
available_va_surfaces_.clear();
// Notify |decoder_delegate_| of an imminent VAContextID destruction, so it
// can destroy any internal structures making use of it. At this point
// |decoder_thread_| is stopped so we can access |decoder_delegate_| from
// |task_runner_|.
decoder_delegate_->OnVAContextDestructionSoon();
vaapi_wrapper_->DestroyContext();
if (vpp_vaapi_wrapper_)
vpp_vaapi_wrapper_->DestroyContext();
state_ = kUninitialized;
}
RendererImpl::OnRendererEnded
void RendererImpl::OnRendererEnded(DemuxerStream::Type type) {
...
// If all streams are ended, do not propagate a redundant ended event.
if (state_ != STATE_PLAYING || PlaybackHasEnded())
return;
if (type == DemuxerStream::AUDIO) {
DCHECK(audio_renderer_);
audio_ended_ = true;
} else {
DCHECK(video_renderer_);
video_ended_ = true;
video_renderer_->OnTimeStopped();
}
RunEndedCallbackIfNeeded();
...
}