910e62b5创建于 1月15日历史提交
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_CAST_STREAMING_RENDERER_COMMON_DECODER_BUFFER_PROVIDER_IMPL_H_
#define COMPONENTS_CAST_STREAMING_RENDERER_COMMON_DECODER_BUFFER_PROVIDER_IMPL_H_

#include <memory>

#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "components/cast_streaming/renderer/public/decoder_buffer_provider.h"
#include "media/base/decoder_buffer.h"
#include "media/cast/openscreen/decoder_buffer_reader.h"
#include "media/mojo/mojom/media_types.mojom-forward.h"
#include "mojo/public/cpp/system/data_pipe.h"

namespace cast_streaming {

// This class provides a synchronous implementation of DecoderBufferProvider,
// to be used for processing decoder buffers with respect to a single config.
template <typename TConfigType>
class DecoderBufferProviderImpl : public DecoderBufferProvider<TConfigType> {
 public:
  using NewBufferCb = typename DecoderBufferProvider<TConfigType>::NewBufferCb;
  using GetConfigCb = typename DecoderBufferProvider<TConfigType>::GetConfigCb;
  using DeletionCb = typename DecoderBufferProvider<TConfigType>::DeletionCb;

  class Client {
   public:
    virtual ~Client() = default;

    // Requests a new buffer be provided to this class, which will be returned
    // via call to |on_buffer_received|.
    using BufferProviderRequestCB =
        base::OnceCallback<void(media::mojom::DecoderBufferPtr)>;
    virtual void RequestBufferAsync(
        BufferProviderRequestCB n_buffer_received) = 0;
  };

  DecoderBufferProviderImpl(
      TConfigType config,
      mojo::ScopedDataPipeConsumerHandle data_pipe,
      Client* client,
      scoped_refptr<base::SequencedTaskRunner> task_runner)
      : config_(std::move(config)),
        client_(client),
        task_runner_(std::move(task_runner)),
        weak_factory_(this) {
    DCHECK(task_runner_);
    DCHECK(client_);
    DCHECK(task_runner_->RunsTasksInCurrentSequence());

    buffer_reader_ = std::make_unique<media::cast::DecoderBufferReader>(
        base::BindRepeating(
            &DecoderBufferProviderImpl<TConfigType>::OnBufferRead,
            weak_factory_.GetWeakPtr()),
        std::move(data_pipe));
  }

  ~DecoderBufferProviderImpl() override {
    DCHECK(task_runner_->RunsTasksInCurrentSequence());
    if (deletion_callback_) {
      std::move(deletion_callback_).Run();
    }
  }

  base::WeakPtr<DecoderBufferProviderImpl<TConfigType>> GetWeakPtr() {
    DCHECK(task_runner_->RunsTasksInCurrentSequence());
    return weak_factory_.GetWeakPtr();
  }

  // DecoderBufferProvider overrides.
  bool IsValid() const override { return true; }

  void GetConfigAsync(GetConfigCb callback) const override {
    DCHECK(task_runner_->RunsTasksInCurrentSequence());
    std::move(callback).Run(config_);
  }

  void ReadBufferAsync(NewBufferCb callback) override {
    DCHECK(task_runner_->RunsTasksInCurrentSequence());
    DCHECK(!new_buffer_callback_);
    new_buffer_callback_ = std::move(callback);
    RequestBuffer();
  }

  void SetInvalidationCallback(DeletionCb callback) override {
    DCHECK(task_runner_->RunsTasksInCurrentSequence());
    deletion_callback_ = std::move(callback);
  }

 private:
  // Provided as the callback to Client::RequestBufferAsync().
  void OnMojoBufferReceived(media::mojom::DecoderBufferPtr buffer) {
    if (!task_runner_->RunsTasksInCurrentSequence()) {
      task_runner_->PostTask(
          FROM_HERE,
          base::BindOnce(&DecoderBufferProviderImpl::OnMojoBufferReceived,
                         weak_factory_.GetWeakPtr(), std::move(buffer)));
      return;
    }

    DCHECK(new_buffer_callback_);
    if (!buffer) {
      buffer_reader_->ClearReadPending();
      std::move(new_buffer_callback_).Run(nullptr);
      return;
    }
    buffer_reader_->ProvideBuffer(std::move(buffer));
  }

  // Callback provided to |buffer_reader_| to be called when a new |buffer| is
  // available for processing.
  void OnBufferRead(scoped_refptr<media::DecoderBuffer> buffer) {
    DCHECK(task_runner_->RunsTasksInCurrentSequence());
    DCHECK(new_buffer_callback_);
    std::move(new_buffer_callback_).Run(std::move(buffer));
  }

  // Requests a new buffer be provided at some point in the future.
  void RequestBuffer() {
    DCHECK(task_runner_->RunsTasksInCurrentSequence());
    buffer_reader_->ReadBufferAsync();
    client_->RequestBufferAsync(base::BindOnce(
        &DecoderBufferProviderImpl<TConfigType>::OnMojoBufferReceived,
        weak_factory_.GetWeakPtr()));
  }

  const TConfigType config_;
  NewBufferCb new_buffer_callback_;
  std::unique_ptr<media::cast::DecoderBufferReader> buffer_reader_;
  DeletionCb deletion_callback_;
  raw_ptr<Client> client_;

  scoped_refptr<base::SequencedTaskRunner> task_runner_;

  base::WeakPtrFactory<DecoderBufferProviderImpl> weak_factory_;
};

}  // namespace cast_streaming

#endif  // COMPONENTS_CAST_STREAMING_RENDERER_COMMON_DECODER_BUFFER_PROVIDER_IMPL_H_