#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 {
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;
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();
}
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:
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));
}
void OnBufferRead(scoped_refptr<media::DecoderBuffer> buffer) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
DCHECK(new_buffer_callback_);
std::move(new_buffer_callback_).Run(std::move(buffer));
}
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_;
};
}
#endif