blob: ca608657308acd93158a5b544aeaffe3ffd9a90b [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 ANDROID_C2_VEA_COMPONENT_H
#define ANDROID_C2_VEA_COMPONENT_H
#include <atomic>
#include <map>
#include <memory>
#include <C2Component.h>
#include <base/memory/weak_ptr.h>
#include <base/optional.h>
#include <base/single_thread_task_runner.h>
#include <base/synchronization/waitable_event.h>
#include <base/threading/thread.h>
#include <size.h>
#include <C2EncoderInterface.h>
#include <VideoEncodeAcceleratorAdaptor.h>
class C2ReflectorHelper;
namespace android {
class FormatConverter;
class C2VEAComponent : public C2Component,
public VideoEncodeAcceleratorAdaptor::Client,
public std::enable_shared_from_this<C2VEAComponent> {
public:
class IntfImpl : public C2EncoderInterface {
public:
IntfImpl(C2String name, const std::shared_ptr<C2ReflectorHelper>& helper);
protected:
base::Optional<media::VideoCodec> getCodecFromComponentName(
const std::string& name) const override;
};
C2VEAComponent(C2String name, c2_node_id_t id,
const std::shared_ptr<C2ReflectorHelper>& helper);
virtual ~C2VEAComponent() override;
// Disable copy and assign.
C2VEAComponent(const C2VEAComponent&) = delete;
C2VEAComponent& operator=(const C2VEAComponent&) = delete;
// Implementation of C2Component interface
virtual c2_status_t setListener_vb(const std::shared_ptr<Listener>& listener,
c2_blocking_t mayBlock) override;
virtual c2_status_t queue_nb(std::list<std::unique_ptr<C2Work>>* const items) override;
virtual c2_status_t announce_nb(const std::vector<C2WorkOutline>& items) override;
virtual c2_status_t flush_sm(flush_mode_t mode,
std::list<std::unique_ptr<C2Work>>* const flushedWork) override;
virtual c2_status_t drain_nb(drain_mode_t mode) override;
virtual c2_status_t start() override;
virtual c2_status_t stop() override;
virtual c2_status_t reset() override;
virtual c2_status_t release() override;
virtual std::shared_ptr<C2ComponentInterface> intf() override;
// Implementation of VideEecodeAcceleratorAdaptor::Client interface
virtual void requireBitstreamBuffers(uint32_t inputCount, const media::Size& inputCodedSize,
uint32_t outputBufferSize) override;
virtual void notifyVideoFrameDone(uint64_t index) override;
virtual void bitstreamBufferReady(uint64_t index, uint32_t payloadSize, bool keyFrame,
int64_t timestamp) override;
virtual void notifyFlushDone(bool done) override;
virtual void notifyError(VideoEncodeAcceleratorAdaptor::Result error) override;
private:
// The state machine enumeration on parent thread.
enum class State : int32_t {
// The initial state of component. State will change to LOADED after the component is
// created.
UNLOADED,
// The component is stopped. State will change to RUNNING when start() is called by
// framework.
LOADED,
// The component is running, State will change to LOADED when stop() or reset() is called by
// framework.
RUNNING,
// The component is in error state.
ERROR,
};
// The state machine enumeration on component thread.
enum class ComponentState : int32_t {
// This is the initial state until VEA initialization returns successfully.
UNINITIALIZED,
// VEA initialization has returned successfully. Component is still waiting for
// requireBitstreamBuffers callback.
CONFIGURED,
// requireBitstreamBuffers callback has received. VEA is ready to make progress.
STARTED,
// onDrain() is called. VEA is draining. Component will hold on queueing works until
// onDrainDone().
DRAINING,
// reportError() is called. Component will stay in the error state unless stop() is called.
ERROR,
};
// This constant is used to tell apart from drain_mode_t enumerations in C2Component.h, which
// means no drain request.
// Note: this value must be different than all enumerations in drain_mode_t.
static constexpr uint32_t NO_DRAIN = ~0u;
// Internal struct for work queue.
struct WorkEntry {
std::unique_ptr<C2Work> mWork;
uint32_t mDrainMode = NO_DRAIN;
};
// These tasks should be run on the component thread |mThread|.
void onDestroy();
void onStart(::base::WaitableEvent* done);
void onDrain(uint32_t drainMode);
void onDrainDone(bool done);
void onFlush(bool reinitAdaptor);
void onStop(::base::WaitableEvent* done);
void onRequireBitstreamBuffers(uint32_t inputCount, const media::Size& inputCodedSize,
uint32_t outputBufferSize);
void onQueueWork(std::unique_ptr<C2Work> work);
void onDequeueWork();
void onInputBufferDone(uint64_t index);
void onOutputBufferDone(uint64_t index, uint32_t payloadSize, bool keyFrame, int64_t timestamp);
// Initialize VEA with configuration from the component interface.
VideoEncodeAcceleratorAdaptor::Result initializeVEA();
// Update |mRequestedBitrate| and |mRequestedFrameRate| from the component interface.
// Return true if there is any value changed. Component will need to call
// requestEncodingParametersChange() to VEA for updating new values.
bool updateEncodingParametersIfChanged();
// Send input buffer |inputBlock| to accelerator for encode with corresponding |index| and
// |timestamp|, and set |keyframe| to true on key frame request.
void sendInputBufferToAccelerator(const C2ConstGraphicBlock& inputBlock, uint64_t index,
int64_t timestamp, bool keyframe);
// Helper function to find the work iterator in |mPendingWorks| by frame index.
std::deque<std::unique_ptr<C2Work>>::iterator findPendingWorkByIndex(uint64_t index);
// Helper function to get the specified work in |mPendingWorks| by frame index.
C2Work* getPendingWorkByIndex(uint64_t index);
// Helper function to get the specified work in |mPendingWorks| with the same |timestamp|.
// Note that EOS and CSD-holder work should be excluded because its timestmap is not meaningful.
C2Work* getPendingWorkByTimestamp(int64_t timestamp);
// Helper function to determine if work queue is flushed. This is used to indicate that returned
// input or output buffer from VEA is no longer needed.
bool isFlushedState() const;
// Check if the corresponding work is finished by |index|. If yes, make onWorkDone call to
// listener and erase the work from |mPendingWorks|.
void reportWorkIfFinished(uint64_t index);
// Report the work by onWorkDone call.
void reportWork(std::unique_ptr<C2Work> work);
// Helper function to determine if the work is finished.
bool isWorkDone(const C2Work* work) const;
// Make onWorkDone call to listener for reporting EOS work in |mPendingWorks|.
void reportEOSWork();
// Abandon all works in |mPendingWorks| and |mAbandonedWorks|.
void reportAbandonedWorks();
// Make onError call to listener for reporting errors.
void reportError(c2_status_t error);
// The pointer of VideoEncodeAcceleratorAdaptor. It should be initialized by the ctor of
// |mIntfImpl| and used for getSupportProfiles. Then it will be owned by component and utilized
// on component thread |mThread|.
// Note: this must be placed before |mIntfImpl| definition due to member variable init order.
std::unique_ptr<VideoEncodeAcceleratorAdaptor> mVEAAdaptor;
// The pointer of component interface implementation.
std::shared_ptr<IntfImpl> mIntfImpl;
// The pointer of component interface.
std::shared_ptr<C2ComponentInterface> mIntf;
// The pointer of component listener.
std::shared_ptr<Listener> mListener;
// The main component thread.
::base::Thread mThread;
// The task runner on component thread.
scoped_refptr<::base::SingleThreadTaskRunner> mTaskRunner;
// The following members should be utilized on component thread |mThread|.
// The initialization result retrieved from VEA.
VideoEncodeAcceleratorAdaptor::Result mVEAInitResult;
// The done event pointer of start procedure. It should be restored in onStart() and signaled in
// onRequireBitstreamBuffers().
::base::WaitableEvent* mStartDoneEvent;
// The state machine on component thread.
ComponentState mComponentState;
// The work queue. Works are queued along with drain mode from component API queue_nb and
// dequeued by the encode process of component.
std::queue<WorkEntry> mQueue;
// Store the output buffer size specified by VEA on RequireBitstreamBuffers.
uint32_t mOutputBufferSize = 0;
// Currently requested bitrate. It would be updated as the value in component interface on
// updateEncodingParametersIfChanged().
uint32_t mRequestedBitrate = 0;
// Currently requested frame rate. It would be updated as the value in component interface on
// updateEncodingParametersIfChanged().
uint32_t mRequestedFrameRate = 0;
// Store the key frame period in frames from the component interface.
uint32_t mKeyFramePeriod = 0;
// The counter for determining whether an input frame is key frame. It has range
// [0, |mKeyFramePeriod|-1] and is circularly increased for each sendInputBufferToAccelerator().
// The current input will be marked as key frame when |mKeyFrameSerial| is 0.
uint32_t mKeyFrameSerial = 0;
// The indicator for extracting CSD info. Set to true once CSD info is extracted and submitted.
bool mCSDSubmitted = false;
// The output block pool.
std::shared_ptr<C2BlockPool> mOutputBlockPool;
// Store the mapping table for the allocated linear output block with corresponding index. Each
// newly-allocated output block will be stored here first, and moved to the corresponding work
// in respect of timestamp when the output buffer is returned from VEA.
std::map<uint64_t, std::shared_ptr<C2LinearBlock>> mOutputBlockMap;
// The indicator of draining with EOS. This should be always set along with component going to
// DRAINING state, and will be unset either after reportEOSWork() (EOS is outputted), or
// reportAbandonedWorks() (drain is cancelled and works are abandoned).
bool mPendingOutputEOS = false;
// Store all pending works. The dequeued works are placed here until they are finished and then
// sent out by onWorkDone call to listener.
std::deque<std::unique_ptr<C2Work>> mPendingWorks;
// If using format converter for input frames, this will be initialized for converting input
// frames to the default pixel format (onto the additional buffers) to send to VEA.
std::unique_ptr<FormatConverter> mFormatConverter;
// The following members should be utilized on parent thread.
// The state machine on parent thread which should be atomic.
std::atomic<State> mState;
// The mutex lock to synchronize start/stop/reset/release calls.
std::mutex mStartStopLock;
// The WeakPtrFactory for getting weak pointer of this.
::base::WeakPtrFactory<C2VEAComponent> mWeakThisFactory;
};
} // namespace android
#endif // ANDROID_C2_VEA_COMPONENT_H