blob: 3978f6b730457dbef2955ce7491a59755a19cc9e [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_GPU_CHROMEOS_VIDEO_DECODER_PIPELINE_H_
#define MEDIA_GPU_CHROMEOS_VIDEO_DECODER_PIPELINE_H_
#include <memory>
#include "base/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/sequence_checker.h"
#include "media/base/video_decoder.h"
#include "media/base/video_decoder_config.h"
#include "media/gpu/chromeos/fourcc.h"
#include "media/gpu/chromeos/image_processor_with_pool.h"
#include "media/gpu/chromeos/video_frame_converter.h"
#include "media/gpu/media_gpu_export.h"
#include "ui/gfx/geometry/size.h"
namespace base {
class SequencedTaskRunner;
}
namespace media {
class DmabufVideoFramePool;
class MediaLog;
// An interface that defines methods to operate on video decoder components
// inside the VideoDecoderPipeline. The interface is similar to
// media::VideoDecoder. The reason not using media::VideoDecoder is that some
// decoders might need to attach an image processor to perform frame
// processing, the output of VideoDecoder is not suitable when the
// intermediate output cannot be rendered by the compositor.
//
// Note: All methods and callbacks should be called on the same sequence.
class MEDIA_GPU_EXPORT DecoderInterface {
public:
using InitCB = base::OnceCallback<void(Status status)>;
// TODO(crbug.com/998413): Replace VideoFrame to GpuMemoryBuffer-based
// instance.
using OutputCB = base::RepeatingCallback<void(scoped_refptr<VideoFrame>)>;
using DecodeCB = VideoDecoder::DecodeCB;
// Client interface of DecoderInterface.
class MEDIA_GPU_EXPORT Client {
public:
Client() = default;
virtual ~Client() = default;
// Get the video frame pool without passing the ownership. Return nullptr if
// the decoder is responsible for allocating its own frames.
virtual DmabufVideoFramePool* GetVideoFramePool() const = 0;
// After this method is called from |decoder_|, the client needs to call
// DecoderInterface::ApplyResolutionChange() when all pending frames are
// flushed.
virtual void PrepareChangeResolution() = 0;
// Return a valid format and size for |decoder_| output from given
// |candidates| and the visible rect. The size might be modified from the
// ones provided originally to accommodate the needs of the pipeline.
// Return base::nullopt if no valid format is found.
virtual base::Optional<std::pair<Fourcc, gfx::Size>>
PickDecoderOutputFormat(
const std::vector<std::pair<Fourcc, gfx::Size>>& candidates,
const gfx::Rect& visible_rect) = 0;
};
DecoderInterface(scoped_refptr<base::SequencedTaskRunner> decoder_task_runner,
base::WeakPtr<DecoderInterface::Client> client);
virtual ~DecoderInterface();
// Initializes a DecoderInterface with the given |config|, executing the
// |init_cb| upon completion. |output_cb| is called for each output frame
// decoded by Decode().
//
// Note:
// 1) DecoderInterface will be reinitialized if it was initialized before.
// 2) This method should not be called during pending decode or reset.
// 3) No DecoderInterface calls should be made before |init_cb| is executed
// successfully.
// TODO(akahuang): Add an error notification method to handle misused case.
// 4) |init_cb| may be called before this returns.
virtual void Initialize(const VideoDecoderConfig& config,
CdmContext* cdm_context,
InitCB init_cb,
const OutputCB& output_cb,
const WaitingCB& waiting_cb) = 0;
// Requests a |buffer| to be decoded. The decode result will be returned via
// |decode_cb|.
//
// After decoding is finished the decoder calls |output_cb| specified in
// Initialize() for each decoded frame. |output_cb| may be called before or
// after |decode_cb|, including before Decode() returns.
//
// If |buffer| is an EOS buffer then the decoder must be flushed, i.e.
// |output_cb| must be called for each frame pending in the queue and
// |decode_cb| must be called after that. Callers will not call Decode()
// again until after the flush completes.
// TODO(akahuang): Add an error notification method to handle misused case.
virtual void Decode(scoped_refptr<DecoderBuffer> buffer,
DecodeCB decode_cb) = 0;
// Resets decoder state. All pending Decode() requests will be finished or
// aborted before |closure| is called.
// Note: No VideoDecoder calls should be made before |closure| is executed.
// TODO(akahuang): Add an error notification method to handle misused case.
virtual void Reset(base::OnceClosure closure) = 0;
// After DecoderInterface calls |prepare_change_resolution_cb| passed
// from the constructor, this method is called when the pipeline flushes
// pending frames.
virtual void ApplyResolutionChange() = 0;
protected:
// Decoder task runner. All public methods of
// DecoderInterface are executed at this task runner.
const scoped_refptr<base::SequencedTaskRunner> decoder_task_runner_;
// The WeakPtr client instance, bound to |decoder_task_runner_|.
base::WeakPtr<DecoderInterface::Client> client_;
DISALLOW_COPY_AND_ASSIGN(DecoderInterface);
};
class MEDIA_GPU_EXPORT VideoDecoderPipeline : public VideoDecoder,
public DecoderInterface::Client {
public:
using CreateDecoderFunction = std::unique_ptr<DecoderInterface> (*)(
scoped_refptr<base::SequencedTaskRunner>,
base::WeakPtr<DecoderInterface::Client>);
using CreateDecoderFunctions = std::list<CreateDecoderFunction>;
using GetCreateDecoderFunctionsCB =
base::RepeatingCallback<CreateDecoderFunctions()>;
static std::unique_ptr<VideoDecoder> Create(
scoped_refptr<base::SequencedTaskRunner> client_task_runner,
std::unique_ptr<DmabufVideoFramePool> frame_pool,
std::unique_ptr<VideoFrameConverter> frame_converter,
std::unique_ptr<MediaLog> media_log,
GetCreateDecoderFunctionsCB get_create_decoder_functions_cb);
~VideoDecoderPipeline() override;
static void DestroyAsync(std::unique_ptr<VideoDecoderPipeline>);
// VideoDecoder implementation
std::string GetDisplayName() const override;
bool IsPlatformDecoder() const override;
int GetMaxDecodeRequests() const override;
bool NeedsBitstreamConversion() const override;
bool CanReadWithoutStalling() const override;
void Initialize(const VideoDecoderConfig& config,
bool low_delay,
CdmContext* cdm_context,
InitCB init_cb,
const OutputCB& output_cb,
const WaitingCB& waiting_cb) override;
void Reset(base::OnceClosure closure) override;
void Decode(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb) override;
// DecoderInterface::Client implementation.
DmabufVideoFramePool* GetVideoFramePool() const override;
void PrepareChangeResolution() override;
// After picking a format, it instantiates an |image_processor_| if none of
// format in |candidates| is renderable and an ImageProcessor can convert a
// candidate to renderable format.
base::Optional<std::pair<Fourcc, gfx::Size>> PickDecoderOutputFormat(
const std::vector<std::pair<Fourcc, gfx::Size>>& candidates,
const gfx::Rect& visible_rect) override;
private:
friend class VideoDecoderPipelineTest;
VideoDecoderPipeline(
scoped_refptr<base::SequencedTaskRunner> client_task_runner,
std::unique_ptr<DmabufVideoFramePool> frame_pool,
std::unique_ptr<VideoFrameConverter> frame_converter,
GetCreateDecoderFunctionsCB get_create_decoder_functions_cb);
void InitializeTask(const VideoDecoderConfig& config,
CdmContext* cdm_context,
InitCB init_cb,
const OutputCB& output_cb,
const WaitingCB& waiting_cb);
void ResetTask(base::OnceClosure closure);
void DecodeTask(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb);
void CreateAndInitializeVD(VideoDecoderConfig config,
CdmContext* cdm_context,
const WaitingCB& waiting_cb,
Status parent_error);
void OnInitializeDone(VideoDecoderConfig config,
CdmContext* cdm_context,
const WaitingCB& waiting_cb,
Status parent_error,
Status status);
void OnDecodeDone(bool eos_buffer, DecodeCB decode_cb, Status status);
void OnResetDone();
void OnError(const std::string& msg);
// Called when |decoder_| finishes decoding a frame.
void OnFrameDecoded(scoped_refptr<VideoFrame> frame);
// Called when |image_processor_| finishes processing a frame.
void OnFrameProcessed(scoped_refptr<VideoFrame> frame);
// Called when |frame_converter_| finishes converting a frame.
void OnFrameConverted(scoped_refptr<VideoFrame> frame);
// Return true if the pipeline has pending frames that are returned from
// |decoder_| but haven't been passed to the client.
// i.e. |image_processor_| or |frame_converter_| has pending frames.
bool HasPendingFrames() const;
// Call DecoderInterface::ApplyResolutionChange() when we need to.
void CallApplyResolutionChangeIfNeeded();
// Call |client_flush_cb_| with |status|.
void CallFlushCbIfNeeded(DecodeStatus status);
// Handle ImageProcessor error callback.
void OnImageProcessorError();
// The client task runner and its sequence checker. All public methods should
// run on this task runner.
const scoped_refptr<base::SequencedTaskRunner> client_task_runner_;
SEQUENCE_CHECKER(client_sequence_checker_);
// The decoder task runner and its sequence checker. Call |decoder_|'s,
// |frame_pool_|'s, and |frame_converter_|'s methods on this task runner.
const scoped_refptr<base::SequencedTaskRunner> decoder_task_runner_;
SEQUENCE_CHECKER(decoder_sequence_checker_);
// The frame pool passed from the client. While internally other additional
// frame pools might be used for intermediate results, all frames passed to
// the client should be created using this pool.
// Used on |decoder_task_runner_|.
std::unique_ptr<DmabufVideoFramePool> main_frame_pool_;
// The image processor is only created when the decoder cannot output frames
// with renderable format.
std::unique_ptr<ImageProcessorWithPool> image_processor_;
// The frame converter passed from the client. Destroyed on
// |client_task_runner_|.
std::unique_ptr<VideoFrameConverter> frame_converter_;
// The current video decoder implementation. Valid after initialization is
// successfully done.
std::unique_ptr<DecoderInterface> decoder_;
// |remaining_create_decoder_functions_| holds all the potential video decoder
// creation functions. We try them all in the given order until one succeeds.
// Only used after initialization on |decoder_sequence_checker_|.
CreateDecoderFunctions remaining_create_decoder_functions_;
// Callback from the client. These callback are called on
// |client_task_runner_|.
InitCB init_cb_;
OutputCB client_output_cb_;
DecodeCB client_flush_cb_;
base::OnceClosure client_reset_cb_;
// True if we need to notify |decoder_| that the pipeline is flushed via
// DecoderInterface::ApplyResolutionChange().
bool need_apply_new_resolution = false;
// True if the decoder needs bitstream conversion before decoding.
bool needs_bitstream_conversion_ = false;
// Set to true when any unexpected error occurs.
bool has_error_ = false;
base::WeakPtr<VideoDecoderPipeline> client_weak_this_;
base::WeakPtr<VideoDecoderPipeline> decoder_weak_this_;
// The weak pointer of this, bound to |client_task_runner_|.
base::WeakPtrFactory<VideoDecoderPipeline> client_weak_this_factory_{this};
// The weak pointer of this, bound to |decoder_task_runner_|.
base::WeakPtrFactory<VideoDecoderPipeline> decoder_weak_this_factory_{this};
};
} // namespace media
#endif // MEDIA_GPU_CHROMEOS_VIDEO_DECODER_PIPELINE_H_