上一章介绍MediaCodec中创建到start过程(到jni部分),从今天开始,将深入源码中看看其c++过程,看下Agenda如下:
BufferInfo在MediaCodec.h中对应是一个结构体
//create by 逆流的鱼yuiop on 2016/12/11
//blog地址:http://blog.csdn.net/hejjunlin
struct BufferInfo {
uint32_t mBufferID;
sp<ABuffer> mData;
sp<ABuffer> mEncryptedData;
sp<IMemory> mSharedEncryptedBuffer;
sp<AMessage> mNotify;
sp<AMessage> mFormat;
bool mOwnedByClient;
};
mediacodec.h的方法的声明,位于\frameworks\av\include\media\stagefright下
//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<MediaCodec> CreateByType(
const sp<ALooper> &looper, const char *mime, bool encoder, status_t *err = NULL,
pid_t pid = kNoPid);
static sp<MediaCodec> CreateByComponentName(
const sp<ALooper> &looper, const char *name, status_t *err = NULL,
pid_t pid = kNoPid);
static sp<PersistentSurface> CreatePersistentInputSurface();
status_t configure(
const sp<AMessage> &format,
const sp<Surface> &nativeWindow,
const sp<ICrypto> &crypto,
uint32_t flags);
status_t setCallback(const sp<AMessage> &callback);
status_t setOnFrameRenderedNotification(const sp<AMessage> ¬ify);
status_t createInputSurface(sp<IGraphicBufferProducer>* bufferProducer);
status_t setInputSurface(const sp<PersistentSurface> &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<AMessage> *format) const;
status_t getInputFormat(sp<AMessage> *format) const;
status_t getWidevineLegacyBuffers(Vector<sp<ABuffer> > *buffers) const;
status_t getInputBuffers(Vector<sp<ABuffer> > *buffers) const;
status_t getOutputBuffers(Vector<sp<ABuffer> > *buffers) const;
status_t getOutputBuffer(size_t index, sp<ABuffer> *buffer);
status_t getOutputFormat(size_t index, sp<AMessage> *format);
status_t getInputBuffer(size_t index, sp<ABuffer> *buffer);
status_t setSurface(const sp<Surface> &nativeWindow);
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<AMessage> ¬ify);
status_t getName(AString *componentName) const;
status_t setParameters(const sp<AMessage> ¶ms);
// 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<FrameRenderTracker::Info> done, sp<AMessage> &msg);
protected:
virtual ~MediaCodec();
virtual void onMessageReceived(const sp<AMessage> &msg);
private:
// 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<ABuffer> mData;
sp<ABuffer> mEncryptedData;
sp<IMemory> mSharedEncryptedBuffer;
sp<AMessage> mNotify;
sp<AMessage> mFormat;
bool mOwnedByClient;
};
struct ResourceManagerServiceProxy : public IBinder::DeathRecipient {
ResourceManagerServiceProxy(pid_t pid);
~ResourceManagerServiceProxy();
void init();
// implements DeathRecipient
virtual void binderDied(const wp<IBinder>& /*who*/);
void addResource(
int64_t clientId,
const sp<IResourceManagerClient> client,
const Vector<MediaResource> &resources);
void removeResource(int64_t clientId);
bool reclaimResource(const Vector<MediaResource> &resources);
private:
Mutex mLock;
sp<IResourceManagerService> mService;
pid_t mPid;
};
State mState;
bool mReleasedByResourceManager;
sp<ALooper> mLooper;
sp<ALooper> mCodecLooper;
sp<CodecBase> mCodec;
AString mComponentName;
sp<AReplyToken> mReplyID;
uint32_t mFlags;
status_t mStickyError;
sp<Surface> mSurface;
SoftwareRenderer *mSoftRenderer;
sp<AMessage> mOutputFormat;
sp<AMessage> mInputFormat;
sp<AMessage> mCallback;
sp<AMessage> mOnFrameRenderedNotification;
sp<MemoryDealer> mDealer;
sp<IResourceManagerClient> mResourceManagerClient;
sp<ResourceManagerServiceProxy> mResourceManagerService;
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<AMessage> mConfigureMsg;
// 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
mAvailPortBuffers[2]; Vector<BufferInfo> mPortBuffers[2];
int32_t mDequeueInputTimeoutGeneration;
sp<AReplyToken> mDequeueInputReplyID;
int32_t mDequeueOutputTimeoutGeneration;
sp<AReplyToken> mDequeueOutputReplyID;
sp<ICrypto> mCrypto;
List<sp<ABuffer> > mCSD;
sp<AMessage> mActivityNotify;
bool mHaveInputSurface;
bool mHavePendingInputBuffers;
MediaCodec(const sp<ALooper> &looper, pid_t pid);
static status_t PostAndAwaitResponse(
const sp<AMessage> &msg, sp<AMessage> *response);
void PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err);
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<AMessage> &msg);
status_t onQueueInputBuffer(const sp<AMessage> &msg);
status_t onReleaseOutputBuffer(const sp<AMessage> &msg);
ssize_t dequeuePortBuffer(int32_t portIndex);
status_t getBufferAndFormat(
size_t portIndex, size_t index,
sp<ABuffer> *buffer, sp<AMessage> *format);
bool handleDequeueInputBuffer(const sp<AReplyToken> &replyID, bool newRequest = false);
bool handleDequeueOutputBuffer(const sp<AReplyToken> &replyID, bool newRequest = false);
void cancelPendingDequeueOperations();
void extractCSD(const sp<AMessage> &format);
status_t queueCSDInputBuffer(size_t bufferIndex);
status_t handleSetSurface(const sp<Surface> &surface);
status_t connectToSurface(const sp<Surface> &surface);
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<AMessage> ¶ms);
status_t amendOutputFormatWithCodecSpecificData(const sp<ABuffer> &buffer);
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<MediaCodec> MediaCodec::CreateByType(
const sp<ALooper> &looper, const char *mime, bool encoder, status_t *err, pid_t pid) {
sp<MediaCodec> codec = new MediaCodec(looper, pid);//这果实际上new出MediaCodec对象
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<IMediaCodecList> mcl = MediaCodecList::getInstance();
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<MediaCodecInfo> info = mcl->getCodecInfo(codecIdx);
Vector<AString> mimes;
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<AMessage> msg = new AMessage(kWhatInit, this);
msg->setString("name", name);
msg->setInt32("nameIsType", nameIsType);
if (nameIsType) {
msg->setInt32("encoder", encoder);
}
status_t err;
Vector<MediaResource> resources;
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<AMessage> response;
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<AMessage> &format,
const sp<Surface> &surface,
const sp<ICrypto> &crypto,
uint32_t flags) {
sp<AMessage> msg = new AMessage(kWhatConfigure, this);
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<MediaResource> resources;
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<AMessage> response;
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<AMessage> msg = new AMessage(kWhatStart, this);
status_t err;
Vector<MediaResource> resources;
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;
}
// Recover codec from previous error before retry start.
err = reset();
if (err != OK) {
ALOGE("retrying start: failed to reset codec");
break;
}
sp<AMessage> response;
err = PostAndAwaitResponse(mConfigureMsg, &response);
if (err != OK) {
ALOGE("retrying start: failed to configure codec");
break;
}
}
sp<AMessage> response;
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<AMessage> msg = new AMessage(kWhatStop, this);
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
}
找到对应的AMessage.cpp,对应同样有一套AHandler.cpp,及ALooper.cpp,这此组成了在c++中一套机制,接口 方法的名字和Java层保持一致。
所有message都在onMessageReceived方法中处理,MediaCodec的各个状态的相关切换。
//create by 逆流的鱼yuiop on 2016/12/11
//blog地址:http://blog.csdn.net/hejjunlin
void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
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 shutdown 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();
}
(new AMessage)->postReply(mReplyID);
}
break;
}
case FLUSHING://刷新中
{
if (actionCode == ACTION_CODE_FATAL) {
setState(UNINITIALIZED);
} else {
setState(
(mFlags & kFlagIsAsync) ? FLUSHED : STARTED);
}
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;
}
}