Chromium源码视频播放分析


下载代码,调试方法等见Chromium视频播放相关调试记录_bberdong的博客-CSDN博客

硬解流程

GPU进程

MediaService::CreateInterfaceFactory,然后创建了InterfaceFactoryImpl。

创建解码器

  1. 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)
}
  1. 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();
  ...
}

猜你喜欢

转载自blog.csdn.net/bberdong/article/details/130645884