blob: 7eedc60c2ed51c7e3c2a735d8867fc8f8a6a0d56 [file] [log] [blame]
// Copyright 2018 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_TEST_VIDEO_PLAYER_VIDEO_DECODER_CLIENT_H_
#define MEDIA_GPU_TEST_VIDEO_PLAYER_VIDEO_DECODER_CLIENT_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <vector>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/threading/thread.h"
#include "gpu/ipc/service/gpu_memory_buffer_factory.h"
#include "media/base/decode_status.h"
#include "media/base/video_decoder.h"
#include "media/base/video_decoder_config.h"
#include "media/gpu/test/video_player/video_player.h"
namespace media {
class Video;
class VideoFrame;
namespace test {
class EncodedDataHelper;
class FrameRenderer;
class VideoFrameProcessor;
// The supported video decoding implementation.
enum class DecoderImplementation {
kVDA, // VDA-based video decoder.
kVD, // VD-based video decoder.
kVDVDA, // VD-based video decoder with VdVDA.
};
// Video decoder client configuration.
struct VideoDecoderClientConfig {
// The maximum number of bitstream buffer decodes that can be requested
// without waiting for the result of the previous decode requests.
size_t max_outstanding_decode_requests = 1;
DecoderImplementation implementation = DecoderImplementation::kVDA;
};
// The video decoder client is responsible for the communication between the
// video player and the video decoder. It also communicates with the frame
// renderer and other components. The video decoder client can only have one
// active decoder at any time. To decode a different stream the DestroyDecoder()
// and CreateDecoder() functions have to be called to destroy and re-create the
// decoder.
//
// All communication with the decoder is done on the |decoder_client_thread_|,
// so callbacks scheduled by the decoder can be executed asynchronously. This is
// necessary if we don't want to interrupt the test flow.
class VideoDecoderClient {
public:
VideoDecoderClient(const VideoDecoderClient&) = delete;
VideoDecoderClient& operator=(const VideoDecoderClient&) = delete;
~VideoDecoderClient();
// Return an instance of the VideoDecoderClient. The
// |gpu_memory_buffer_factory| will not be owned by the decoder client, the
// caller should guarantee it outlives the decoder client. The |event_cb| will
// be called whenever an event occurs (e.g. frame decoded) and should be
// thread-safe. Initialization is performed asynchronous, upon completion a
// 'kInitialized' event will be thrown.
static std::unique_ptr<VideoDecoderClient> Create(
const VideoPlayer::EventCallback& event_cb,
gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
std::unique_ptr<FrameRenderer> frame_renderer,
std::vector<std::unique_ptr<VideoFrameProcessor>> frame_processors,
const VideoDecoderClientConfig& config);
// Wait until all frame processors have finished processing. Returns whether
// processing was successful.
bool WaitForFrameProcessors();
// Wait until the renderer has finished rendering all queued frames.
void WaitForRenderer();
// Get the frame renderer associated with the video decoder client.
FrameRenderer* GetFrameRenderer() const;
// Initialize the video decoder for the specified |video|. This function can
// be called multiple times and needs to be called before Play().
// Initialization is performed asynchronous, upon completion a 'kInitialized'
// event is thrown.
void Initialize(const Video* video);
// Start decoding the video stream, decoder should be idle when this function
// is called. This function is non-blocking, for each frame decoded a
// 'kFrameDecoded' event will be thrown.
void Play();
// Queue decoder flush. This function is non-blocking, a kFlushing/kFlushDone
// event is thrown upon start/finish.
void Flush();
// Queue decoder reset. This function is non-blocking, a kResetting/kResetDone
// event is thrown upon start/finish.
void Reset();
private:
enum class VideoDecoderClientState : size_t {
kUninitialized = 0,
kIdle,
kDecoding,
kFlushing,
kResetting,
};
VideoDecoderClient(
const VideoPlayer::EventCallback& event_cb,
gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
std::unique_ptr<FrameRenderer> renderer,
std::vector<std::unique_ptr<VideoFrameProcessor>> frame_processors,
const VideoDecoderClientConfig& config);
// Create a new decoder, returns whether creating was successful.
bool CreateDecoder();
// Destroy the currently active decoder.
void DestroyDecoder();
// Create a new video |decoder_| on the |decoder_client_thread_|.
void CreateDecoderTask(bool* success, base::WaitableEvent* done);
// Destroy the active video |decoder_| on the |decoder_client_thread_|.
void DestroyDecoderTask(base::WaitableEvent* done);
// Initialize the video |decoder_| with |video| on the
// |decoder_client_thread_|.
void InitializeDecoderTask(const Video* video, base::WaitableEvent* done);
// Start decoding video stream fragments on the |decoder_client_thread_|.
void PlayTask();
// Instruct the decoder to decode the next video stream fragment on the
// |decoder_client_thread_|.
void DecodeNextFragmentTask();
// Instruct the decoder to perform a flush on the |decoder_client_thread_|.
void FlushTask();
// Instruct the decoder to perform a Reset on the |decoder_client_thread_|.
void ResetTask();
// The below functions are callbacks provided to the video decoder. They are
// all executed on the |decoder_client_thread_|.
// Called by the decoder when initialization has completed.
void DecoderInitializedTask(Status status);
// Called by the decoder when a fragment has been decoded.
void DecodeDoneTask(media::Status status);
// Called by the decoder when a video frame is ready.
void FrameReadyTask(scoped_refptr<VideoFrame> video_frame);
// Called by the decoder when flushing has completed.
void FlushDoneTask(media::Status status);
// Called by the decoder when resetting has completed.
void ResetDoneTask();
// Fire the specified event.
void FireEvent(VideoPlayerEvent event);
VideoPlayer::EventCallback event_cb_;
std::unique_ptr<FrameRenderer> frame_renderer_;
std::vector<std::unique_ptr<VideoFrameProcessor>> frame_processors_;
std::unique_ptr<media::VideoDecoder> decoder_;
const VideoDecoderClientConfig decoder_client_config_;
base::Thread decoder_client_thread_;
// Decoder client state, should only be accessed on the decoder client thread.
VideoDecoderClientState decoder_client_state_;
// Index of the frame that's currently being decoded.
size_t current_frame_index_ = 0;
// The current number of outgoing bitstream buffers decode requests.
size_t num_outstanding_decode_requests_ = 0;
// TODO(dstaessens@) Replace with StreamParser.
std::unique_ptr<media::test::EncodedDataHelper> encoded_data_helper_;
// The video being decoded.
const Video* video_ = nullptr;
// Owned by VideoPlayerTestEnvironment.
gpu::GpuMemoryBufferFactory* const gpu_memory_buffer_factory_;
SEQUENCE_CHECKER(video_player_sequence_checker_);
SEQUENCE_CHECKER(decoder_client_sequence_checker_);
base::WeakPtr<VideoDecoderClient> weak_this_;
base::WeakPtrFactory<VideoDecoderClient> weak_this_factory_{this};
};
} // namespace test
} // namespace media
#endif // MEDIA_GPU_TEST_VIDEO_PLAYER_VIDEO_DECODER_CLIENT_H_