第一篇:Android Multimedia框架总结(二十二)MediaCodec中C++中创建到start过程及状态变换
Android Multimedia框架总结(二十二)MediaCodec中C++中创建到start过程
及状态变换
从今天开始,将深入源码中看看其c++过程,看下Agenda如下:
mediacodec.h CreateByType initMediaCodec中BufferInfo内部类: configure过程 start BufferInfo在MediaCodec.h中对应是一个结构体
//create by 逆流的鱼yuiop on 2016/12/11 //blog地址:http://blog.csdn.net/hejjunlin struct BufferInfo {
uint32_t mBufferID;
sp
sp
sp
sp
sp
bool mOwnedByClient;};mediacodec.h的方法的声明,位于frameworksavincludemediastagefright下
//create by 逆流的鱼yuiop on 2016/12/11 //blog地址:http://blog.csdn.net/hejjunlin namespace android { struct ABuffer;struct AMessage;struct AReplyToken;struct AString;struct CodecBase;struct IBatteryStats;struct ICrypto;class IMemory;struct MemoryDealer;class IResourceManagerClient;class IResourceManagerService;struct PersistentSurface;struct SoftwareRenderer;struct Surface;struct MediaCodec : public AHandler {
enum ConfigureFlags {
CONFIGURE_FLAG_ENCODE
= 1,};
enum BufferFlags {
BUFFER_FLAG_SYNCFRAME
= 1,BUFFER_FLAG_CODECCONFIG = 2,BUFFER_FLAG_EOS
= 4,};
enum {
CB_INPUT_AVAILABLE = 1,CB_OUTPUT_AVAILABLE = 2,CB_ERROR = 3,CB_OUTPUT_FORMAT_CHANGED = 4,CB_RESOURCE_RECLAIMED = 5,};
static const pid_t kNoPid =-1;
static sp
static sp
static sp
CreatePersistentInputSurface();
status_t configure(const sp
status_t setCallback(const sp
status_t setOnFrameRenderedNotification(const sp
status_t createInputSurface(sp
status_t setInputSurface(const sp
&surface);
status_t start();
// Returns to a state in which the component remains allocated but
// unconfigured.status_t stop();
// Resets the codec to the INITIALIZED state.Can be called after an error
// has occured to make the codec usable.status_t reset();
// Client MUST call release before releasing final reference to this
// object.status_t release();
status_t flush();
status_t queueInputBuffer(size_t index,size_t offset,size_t size,int64_t presentationTimeUs,uint32_t flags,AString *errorDetailMsg = NULL);
status_t queueSecureInputBuffer(size_t index,size_t offset,const CryptoPlugin::SubSample *subSamples,size_t numSubSamples,const uint8_t key[16],const uint8_t iv[16],CryptoPlugin::Mode mode,int64_t presentationTimeUs,uint32_t flags,AString *errorDetailMsg = NULL);
status_t dequeueInputBuffer(size_t *index, int64_t timeoutUs = 0ll);
status_t dequeueOutputBuffer(size_t *index,size_t *offset,size_t *size,int64_t *presentationTimeUs,uint32_t *flags,int64_t timeoutUs = 0ll);
status_t renderOutputBufferAndRelease(size_t index, int64_t timestampNs);
status_t renderOutputBufferAndRelease(size_t index);
status_t releaseOutputBuffer(size_t index);
status_t signalEndOfInputStream();
status_t getOutputFormat(sp
status_t getInputFormat(sp
status_t getWidevineLegacyBuffers(Vector
status_t getInputBuffers(Vector
status_t getOutputBuffers(Vector
status_t getOutputBuffer(size_t index, sp
status_t getOutputFormat(size_t index, sp
status_t getInputBuffer(size_t index, sp
status_t setSurface(const sp
status_t requestIDRFrame();
// Notification will be posted once there “is something to do”, i.e.// an input/output buffer has become available, a format change is
// pending, an error is pending.void requestActivityNotification(const sp
status_t getName(AString *componentName)const;
status_t setParameters(const sp
// Create a MediaCodec notification message from a list of rendered or dropped render infos
// by adding rendered frame information to a base notification message.Returns the number
// of frames that were rendered.static size_t CreateFramesRenderedMessage(std::list
virtual ~MediaCodec();
virtual void onMessageReceived(const sp
// used by ResourceManagerClient
status_t reclaim(bool force = false);
friend struct ResourceManagerClient;private:
enum State {
UNINITIALIZED,INITIALIZING,INITIALIZED,CONFIGURING,CONFIGURED,STARTING,STARTED,FLUSHING,FLUSHED,STOPPING,RELEASING,};
enum {
kPortIndexInput
= 0,kPortIndexOutput
= 1,};
enum {
kWhatInit
= 'init',kWhatConfigure
= 'conf',kWhatSetSurface
= 'sSur',kWhatCreateInputSurface
= 'cisf',kWhatSetInputSurface
= 'sisf',kWhatStart
= 'strt',kWhatStop
= 'stop',kWhatRelease
= 'rele',kWhatDequeueInputBuffer
= 'deqI',kWhatQueueInputBuffer
= 'queI',kWhatDequeueOutputBuffer
= 'deqO',kWhatReleaseOutputBuffer
= 'relO',kWhatSignalEndOfInputStream
= 'eois',kWhatGetBuffers
= 'getB',kWhatFlush
= 'flus',kWhatGetOutputFormat
= 'getO',kWhatGetInputFormat
= 'getI',kWhatDequeueInputTimedOut
= 'dITO',kWhatDequeueOutputTimedOut
= 'dOTO',kWhatCodecNotify
= 'codc',kWhatRequestIDRFrame
= 'ridr',kWhatRequestActivityNotification
= 'racN',kWhatGetName
= 'getN',kWhatSetParameters
= 'setP',kWhatSetCallback
= 'setC',kWhatSetNotification
= 'setN',};
enum {
kFlagUsesSoftwareRenderer
= 1,kFlagOutputFormatChanged
= 2,kFlagOutputBuffersChanged
= 4,kFlagStickyError
= 8,kFlagDequeueInputPending
= 16,kFlagDequeueOutputPending
= 32,kFlagIsSecure
= 64,kFlagSawMediaServerDie
= 128,kFlagIsEncoder
= 256,kFlagGatherCodecSpecificData
= 512,kFlagIsAsync
= 1024,kFlagIsComponentAllocated
= 2048,kFlagPushBlankBuffersOnShutdown = 4096,};
struct BufferInfo {
uint32_t mBufferID;
sp
sp
sp
sp
sp
bool mOwnedByClient;
};
struct ResourceManagerServiceProxy : public IBinder::DeathRecipient {
ResourceManagerServiceProxy(pid_t pid);
~ResourceManagerServiceProxy();
void init();
// implements DeathRecipient
virtual void binderDied(const wp
void addResource(int64_t clientId,const sp
void removeResource(int64_t clientId);
bool reclaimResource(const Vector
private:
Mutex mLock;
sp
pid_t mPid;
};
State mState;
bool mReleasedByResourceManager;
sp
sp
sp
AString mComponentName;
sp
uint32_t mFlags;
status_t mStickyError;
sp
SoftwareRenderer *mSoftRenderer;
sp
sp
sp
sp
sp
sp
sp
bool mBatteryStatNotified;
bool mIsVideo;
int32_t mVideoWidth;
int32_t mVideoHeight;
int32_t mRotationDegrees;
// initial create parameters
AString mInitName;
bool mInitNameIsType;
bool mInitIsEncoder;
// configure parameter
sp
// Used only to synchronize asynchronous getBufferAndFormat
// across all the other(synchronous)buffer state change
// operations, such as de/queueIn/OutputBuffer, start and
// stop/flush/reset/release.Mutex mBufferLock;
List
Vector
int32_t mDequeueInputTimeoutGeneration;
sp
int32_t mDequeueOutputTimeoutGeneration;
sp
sp
List
sp
bool mHaveInputSurface;
bool mHavePendingInputBuffers;
MediaCodec(const sp
static status_t PostAndAwaitResponse(const sp
void PostReplyWithError(const sp
status_t init(const AString &name, bool nameIsType, bool encoder);
void setState(State newState);
void returnBuffersToCodec();
void returnBuffersToCodecOnPort(int32_t portIndex);
size_t updateBuffers(int32_t portIndex, const sp
status_t onQueueInputBuffer(const sp
status_t onReleaseOutputBuffer(const sp
ssize_t dequeuePortBuffer(int32_t portIndex);
status_t getBufferAndFormat(size_t portIndex, size_t index,sp
bool handleDequeueInputBuffer(const sp
bool handleDequeueOutputBuffer(const sp
void cancelPendingDequeueOperations();
void extractCSD(const sp
status_t queueCSDInputBuffer(size_t bufferIndex);
status_t handleSetSurface(const sp
status_t connectToSurface(const sp
status_t disconnectFromSurface();
void postActivityNotificationIfPossible();
void onInputBufferAvailable();
void onOutputBufferAvailable();
void onError(status_t err, int32_t actionCode, const char *detail = NULL);
void onOutputFormatChanged();
status_t onSetParameters(const sp
status_t amendOutputFormatWithCodecSpecificData(const sp
void updateBatteryStat();
bool isExecuting()const;
uint64_t getGraphicBufferSize();
void addResource(const String8 &type, const String8 &subtype, uint64_t value);
bool hasPendingBuffer(int portIndex);
bool hasPendingBuffer();
/* called to get the last codec error when the sticky flag is set.* if no such codec error is found, returns UNKNOWN_ERROR.*/
inline status_t getStickyError()const {
return mStickyError!= 0 ? mStickyError : UNKNOWN_ERROR;
}
inline void setStickyError(status_t err){
mFlags |= kFlagStickyError;
mStickyError = err;
}
DISALLOW_EVIL_CONSTRUCTORS(MediaCodec);};} // namespace android CreateByType
//create by 逆流的鱼yuiop on 2016/12/11 //blog地址:http://blog.csdn.net/hejjunlin // static sp
sp
const status_t ret = codec->init(mime, true /* nameIsType */, encoder);
if(err!= NULL){
*err = ret;
}
return ret == OK ? codec : NULL;// NULL deallocates codec.} 接着到init过程
//create by 逆流的鱼yuiop on 2016/12/11 //blog地址:http://blog.csdn.net/hejjunlin status_t MediaCodec::init(const AString &name, bool nameIsType, bool encoder){
mResourceManagerService->init();
// 保存 初始参数,到时用于reset
mInitName = name;
mInitNameIsType = nameIsType;
mInitIsEncoder = encoder;
// 目前视频解码器不能马上从OMX_FillThisBuffer返回,违反OpenMAX规格,直到提醒我们需要入驻另一个第三方的looper释放在事件队列中。
if(nameIsType ||!strncasecmp(name.c_str(), “omx.”, 4)){//omx.匹配
mCodec = new ACodec;//实例化ACodec
} else if(!nameIsType
&&!strncasecmp(name.c_str(), “android.filter.”, 15)){
mCodec = new MediaFilter;// 实例化MediaFilter
} else {
return NAME_NOT_FOUND;
}
bool secureCodec = false;
if(nameIsType &&!strncasecmp(name.c_str(), “video/”, 6)){
mIsVideo = true;
} else {
AString tmp = name;
if(tmp.endsWith(“.secure”)){
secureCodec = true;
tmp.erase(tmp.size()-7, 7);
}
const sp
if(mcl == NULL){
mCodec = NULL;// remove the codec.return NO_INIT;// if called from Java should raise IOException
}
ssize_t codecIdx = mcl->findCodecByName(tmp.c_str());
if(codecIdx >= 0){
const sp
Vector
info->getSupportedMimes(&mimes);
for(size_t i = 0;i < mimes.size();i++){
if(mimes[i].startsWith(“video/”)){
mIsVideo = true;
break;
}
}
}
}
if(mIsVideo){
// video codec needs dedicated looper
if(mCodecLooper == NULL){
mCodecLooper = new ALooper;
mCodecLooper->setName(“CodecLooper”);//设置名字为CodecLooper
mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
}
mCodecLooper->registerHandler(mCodec);
} else {
mLooper->registerHandler(mCodec);
}
mLooper->registerHandler(this);
mCodec->setNotificationMessage(new AMessage(kWhatCodecNotify, this));
sp
msg->setString(“name”, name);
msg->setInt32(“nameIsType”, nameIsType);
if(nameIsType){
msg->setInt32(“encoder”, encoder);
}
status_t err;
Vector
const char *type = secureCodec ? kResourceSecureCodec : kResourceNonSecureCodec;
const char *subtype = mIsVideo ? kResourceVideoCodec : kResourceAudioCodec;
resources.push_back(MediaResource(String8(type), String8(subtype), 1));
for(int i = 0;i <= kMaxRetry;++i){
if(i > 0){
// Don't try to reclaim resource for the first time.if(!mResourceManagerService->reclaimResource(resources)){
break;
}
}
sp
err = PostAndAwaitResponse(msg, &response);
if(!isResourceError(err)){
break;
}
}
return err;} configure过程
//create by 逆流的鱼yuiop on 2016/12/11 //blog地址:http://blog.csdn.net/hejjunlin status_t MediaCodec::configure(const sp
sp
if(mIsVideo){
format->findInt32(“width”, &mVideoWidth);
format->findInt32(“height”, &mVideoHeight);
if(!format->findInt32(“rotation-degrees”, &mRotationDegrees)){
mRotationDegrees = 0;
}
}
msg->setMessage(“format”, format);
msg->setInt32(“flags”, flags);
msg->setObject(“surface”, surface);
if(crypto!= NULL){
msg->setPointer(“crypto”, crypto.get());
}
// save msg for reset
mConfigureMsg = msg;
status_t err;
Vector
const char *type =(mFlags & kFlagIsSecure)?
kResourceSecureCodec : kResourceNonSecureCodec;
const char *subtype = mIsVideo ? kResourceVideoCodec : kResourceAudioCodec;
resources.push_back(MediaResource(String8(type), String8(subtype), 1));
// Don't know the buffer size at this point, but it's fine to use 1 because
// the reclaimResource call doesn't consider the requester's buffer size for now.resources.push_back(MediaResource(String8(kResourceGraphicMemory), 1));
for(int i = 0;i <= kMaxRetry;++i){
if(i > 0){
// Don't try to reclaim resource for the first time.if(!mResourceManagerService->reclaimResource(resources)){
break;
}
}
sp
err = PostAndAwaitResponse(msg, &response);
if(err!= OK && err!= INVALID_OPERATION){
// MediaCodec now set state to UNINITIALIZED upon any fatal error.// To maintain backward-compatibility, do a reset()to put codec
// back into INITIALIZED state.// But don't reset if the err is INVALID_OPERATION, which means
// the configure failure is due to wrong state.ALOGE(“configure failed with err 0x%08x, resetting...”, err);
reset();
}
if(!isResourceError(err)){
break;
}
}
return err;} start过程
//create by 逆流的鱼yuiop on 2016/12/11 //blog地址:http://blog.csdn.net/hejjunlin status_t MediaCodec::start(){
sp
status_t err;
Vector
const char *type =(mFlags & kFlagIsSecure)?
kResourceSecureCodec : kResourceNonSecureCodec;
const char *subtype = mIsVideo ? kResourceVideoCodec : kResourceAudioCodec;
resources.push_back(MediaResource(String8(type), String8(subtype), 1));
// Don't know the buwww.xiexiebang.comffer size at this point, but it's fine to use 1 because
// the reclaimResource call doesn't consider the requester's buffer size for now.resources.push_back(MediaResource(String8(kResourceGraphicMemory), 1));
for(int i = 0;i <= kMaxRetry;++i){
if(i > 0){
// Don't try to reclaim resource for the first time.if(!mResourceManagerService->reclaimResource(resources)){
break;
}
// Recover codec from previous error before retry start.err = reset();
if(err!= OK){
ALOGE(“retrying start: failed to reset codec”);
break;
}
sp
err = PostAndAwaitResponse(mConfigureMsg, &response);
if(err!= OK){
ALOGE(“retrying start: failed to configure codec”);
break;
}
}
sp
err = PostAndAwaitResponse(msg, &response);
if(!isResourceError(err)){
break;
}
}
return err;} stop过程
//create by 逆流的鱼yuiop on 2016/12/11 //blog地址:http://blog.csdn.net/hejjunlin status_t MediaCodec::stop(){
sp
sp
return PostAndAwaitResponse(msg, &response);} 找到对应的AMessage.cpp,对应同样有一套AHandler.cpp,及ALooper.cpp,这此组成了在c++中一套机制,接口 方法的名字和Java层保持一致。
所有message都在onMessageReceived方法中处理,MediaCodec的各个状态的相关切换。
void MediaCodec::onMessageReceived(const sp
switch(mState){
case INITIALIZING://初始化中
{
setState(UNINITIALIZED);
break;
}
case CONFIGURING://配置中
{
setState(actionCode == ACTION_CODE_FATAL ?
UNINITIALIZED : INITIALIZED);
break;
}
case STARTING://start中
{
setState(actionCode == ACTION_CODE_FATAL ?
UNINITIALIZED : CONFIGURED);
break;
}
case STOPPING://停止中
case RELEASING://释放中
{
// Ignore the error, assuming we'll still get
// the shnc630.comutdown complete notification.sendErrorResponse = false;
if(mFlags & kFlagSawMediaServerDie){
// MediaServer died, there definitely won't
// be a shutdown complete notification after
// all.// note that we're directly going from
// STOPPING->UNINITIALIZED, instead of the
// usual STOPPING->INITIALIZED state.setState(UNINITIALIZED);
if(mState == RELEASING){
mComponentName.clear();
}
STARTED);
(new AMessage)->postReply(mReplyID);
}
break;}
case FLUSHING://刷新中 {
if(actionCode == ACTION_CODE_FATAL){
setState(UNINITIALIZED);
} else {
setState((mFlags & kFlagIsAsync)? FLUSHED :
}
break;}
case FLUSHED: case STARTED: {
sendErrorResponse = false;
setStickyError(err);
postActivityNotificationIfPossible();
cancelPendingDequeueOperations();
if(mFlags & kFlagIsAsync){
onError(err, actionCode);
}
switch(actionCode){
case ACTION_CODE_TRANSIENT:
break;
case ACTION_CODE_RECOVERABLE:
setState(INITIALIZED);
break;
default:
setState(UNINITIALIZED);
break;
}
break;
}
default:
{
sendErrorResponse = false;
setStickyError(err);
postActivityNotificationIfPossible();
// actionCode in an uninitialized state is always fatal.if(mState == UNINITIALIZED){
}
actionCode = ACTION_CODE_FATAL;
}
if(mFlags & kFlagIsAsync){
onError(err, actionCode);
}
switch(actionCode){
case ACTION_CODE_TRANSIENT:
break;
case ACTION_CODE_RECOVERABLE:
setState(INITIALIZED);
break;
default:
setState(UNINITIALIZED);
break;
}
break;}