blob: efc16653550f43b802c1abb661daa86671a9ecca [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 <VideoEncodeAcceleratorAdaptor.h>
#include <size.h>
#include <C2Component.h>
#include <C2Config.h>
#include <C2Enum.h>
#include <C2Param.h>
#include <C2ParamDef.h>
#include <SimpleC2Interface.h>
#include <util/C2InterfaceHelper.h>
#include <base/macros.h>
#include <base/memory/ref_counted.h>
#include <base/single_thread_task_runner.h>
#include <base/synchronization/waitable_event.h>
#include <base/threading/thread.h>
#include <atomic>
#include <map>
#include <memory>
namespace android {
class C2VEAComponent : public C2Component,
public VideoEncodeAcceleratorAdaptor::Client,
public std::enable_shared_from_this<C2VEAComponent> {
public:
class IntfImpl : public C2InterfaceHelper {
public:
IntfImpl(C2String name, const std::shared_ptr<C2ReflectorHelper>& helper,
std::unique_ptr<VideoEncodeAcceleratorAdaptor>* const adaptor /* nonnull */);
// Interfaces for C2VEAComponent
// Note: these getters are not thread-safe. For dynamic parameters, component should use
// formal query API for C2ComponentInterface instead.
c2_status_t status() const { return mInitStatus; }
C2Config::profile_t getOutputProfile() const { return mProfileLevel->profile; }
C2Config::level_t getOutputLevel() const { return mProfileLevel->level; }
const media::Size getInputVisibleSize() const {
return media::Size(mInputVisibleSize->width, mInputVisibleSize->height);
}
C2BlockPool::local_id_t getBlockPoolId() const { return mOutputBlockPoolIds->m.values[0]; }
// Get sync key-frame period in frames.
uint32_t getKeyFramePeriod() const;
private:
// Configurable parameter setters.
static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::output>& info,
const C2P<C2StreamPictureSizeInfo::input>& videosize,
const C2P<C2StreamFrameRateInfo::output>& frameRate,
const C2P<C2StreamBitrateInfo::output>& bitrate);
static C2R SizeSetter(bool mayBlock, C2P<C2StreamPictureSizeInfo::input>& videoSize);
static C2R IntraRefreshPeriodSetter(bool mayBlock,
C2P<C2StreamIntraRefreshTuning::output>& period);
// Constant parameters
// The input format kind; should be C2FormatVideo.
std::shared_ptr<C2StreamBufferTypeSetting::input> mInputFormat;
// The output format kind; should be C2FormatCompressed.
std::shared_ptr<C2StreamBufferTypeSetting::output> mOutputFormat;
// The MIME type of input port; should be MEDIA_MIMETYPE_VIDEO_RAW.
std::shared_ptr<C2PortMediaTypeSetting::input> mInputMediaType;
// The MIME type of output port.
std::shared_ptr<C2PortMediaTypeSetting::output> mOutputMediaType;
// The suggested usage of input buffer allocator ID.
std::shared_ptr<C2PortAllocatorsTuning::input> mInputAllocatorIds;
// The suggested usage of output buffer allocator ID.
std::shared_ptr<C2PortAllocatorsTuning::output> mOutputAllocatorIds;
// Initialization parameters
// The visible size for input raw video.
std::shared_ptr<C2StreamPictureSizeInfo::input> mInputVisibleSize;
// The output codec profile and level.
std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel;
// The expected period for key frames in microseconds.
std::shared_ptr<C2StreamSyncFrameIntervalTuning::output> mKeyFramePeriodUs;
// Compnent uses this ID to fetch corresponding output block pool from platform.
std::shared_ptr<C2PortBlockPoolsTuning::output> mOutputBlockPoolIds;
// Dynamic parameters
// The requested bitrate of the encoded output stream, in bits per second.
std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
// The requested framerate, in frames per second.
std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate;
// The switch-type parameter that will be set to true while client requests keyframe. It
// will be reset once encoder gets the request.
std::shared_ptr<C2StreamRequestSyncFrameTuning::output> mRequestKeyFrame;
// The intra-frame refresh period. This is unused for the component now.
// TODO: adapt intra refresh period to encoder.
std::shared_ptr<C2StreamIntraRefreshTuning::output> mIntraRefreshPeriod;
c2_status_t mInitStatus;
};
C2VEAComponent(C2String name, c2_node_id_t id,
const std::shared_ptr<C2ReflectorHelper>& helper);
virtual ~C2VEAComponent() override;
// 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(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(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 work should be excluded because its timestmap is not meaningful.
C2Work* getPendingWorkByTimestamp(int64_t timestamp);
// For VEA, the codec-specific data (CSD in abbreviation, SPS and PPS for H264 encode) will be
// concatenated with the first encoded slice in one bitstream buffer. This function extracts CSD
// out of the bitstream and stores into |csd|.
void extractCSDInfo(std::unique_ptr<C2StreamCsdInfo::output>* const csd, const uint8_t* data,
size_t length);
// 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);
// 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.
const 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;
// Constants of states of CSD manipulation which will be used by |mCSDWorkIndex|.
constexpr static int64_t kCSDInit = -1;
constexpr static int64_t kCSDSubmitted = -2;
// Record the frame index of CSD-holder work, or indicate the state of CSD manipulation.
int64_t mCSDWorkIndex = kCSDInit;
// The output block pool.
std::shared_ptr<C2BlockPool> mOutputBlockPool;
// Store the mapping table for the allocated linear output block with corresponding timestamp.
// 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<int64_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;
// 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;
DISALLOW_COPY_AND_ASSIGN(C2VEAComponent);
};
} // namespace android
#endif // ANDROID_C2_VEA_COMPONENT_H