Separate the notion of "stop" from that of "release", i.e.

stop - means transition back to LOADED state and keeping the component
instance allocated.

release - means we get rid of the component completely.

Change-Id: I40ad01ce70821faaad43f57999249904f9144924
This commit is contained in:
Andreas Huber
2012-02-28 15:54:51 -08:00
parent f64dfccd96
commit 4484bdd2f9
7 changed files with 207 additions and 58 deletions

View File

@@ -396,7 +396,7 @@ status_t SimplePlayer::onReset() {
for (size_t i = 0; i < mStateByTrackIndex.size(); ++i) {
CodecState *state = &mStateByTrackIndex.editValueAt(i);
CHECK_EQ(state->mCodec->stop(), (status_t)OK);
CHECK_EQ(state->mCodec->release(), (status_t)OK);
}
mStartTimeRealUs = -1ll;

View File

@@ -295,7 +295,7 @@ static int decode(
for (size_t i = 0; i < stateByTrack.size(); ++i) {
CodecState *state = &stateByTrack.editValueAt(i);
CHECK_EQ((status_t)OK, state->mCodec->stop());
CHECK_EQ((status_t)OK, state->mCodec->release());
}
return 0;

View File

@@ -49,7 +49,7 @@ struct ACodec : public AHierarchicalStateMachine {
void initiateSetup(const sp<AMessage> &msg);
void signalFlush();
void signalResume();
void initiateShutdown();
void initiateShutdown(bool keepComponentAllocated = false);
void initiateAllocateComponent(const sp<AMessage> &msg);
void initiateConfigureComponent(const sp<AMessage> &msg);
@@ -61,6 +61,7 @@ protected:
private:
struct BaseState;
struct UninitializedState;
struct LoadedState;
struct LoadedToIdleState;
struct IdleToExecutingState;
struct ExecutingState;
@@ -107,6 +108,7 @@ private:
sp<AMessage> mNotify;
sp<UninitializedState> mUninitializedState;
sp<LoadedState> mLoadedState;
sp<LoadedToIdleState> mLoadedToIdleState;
sp<IdleToExecutingState> mIdleToExecutingState;
sp<ExecutingState> mExecutingState;
@@ -131,6 +133,12 @@ private:
bool mSentFormat;
bool mIsEncoder;
bool mShutdownInProgress;
// If "mKeepComponentAllocated" we only transition back to Loaded state
// and do not release the component instance.
bool mKeepComponentAllocated;
status_t allocateBuffersOnPort(OMX_U32 portIndex);
status_t freeBuffersOnPort(OMX_U32 portIndex);
status_t freeBuffer(OMX_U32 portIndex, size_t i);

View File

@@ -53,8 +53,15 @@ struct MediaCodec : public AHandler {
uint32_t flags);
status_t start();
// Returns to a state in which the component remains allocated but
// unconfigured.
status_t stop();
// Client MUST call release before releasing final reference to this
// object.
status_t release();
status_t flush();
status_t queueInputBuffer(
@@ -97,6 +104,7 @@ private:
STARTED,
FLUSHING,
STOPPING,
RELEASING,
};
enum {
@@ -109,6 +117,7 @@ private:
kWhatConfigure = 'conf',
kWhatStart = 'strt',
kWhatStop = 'stop',
kWhatRelease = 'rele',
kWhatDequeueInputBuffer = 'deqI',
kWhatQueueInputBuffer = 'queI',
kWhatDequeueOutputBuffer = 'deqO',

View File

@@ -84,7 +84,7 @@ status_t JMediaCodec::initCheck() const {
}
JMediaCodec::~JMediaCodec() {
mCodec->stop();
mCodec->release();
JNIEnv *env = AndroidRuntime::getJNIEnv();

View File

@@ -165,18 +165,36 @@ struct ACodec::UninitializedState : public ACodec::BaseState {
protected:
virtual bool onMessageReceived(const sp<AMessage> &msg);
virtual void stateEntered();
private:
void onSetup(const sp<AMessage> &msg);
void onAllocateComponent(const sp<AMessage> &msg);
void onConfigureComponent(const sp<AMessage> &msg);
void onStart();
bool onAllocateComponent(const sp<AMessage> &msg);
DISALLOW_EVIL_CONSTRUCTORS(UninitializedState);
};
////////////////////////////////////////////////////////////////////////////////
struct ACodec::LoadedState : public ACodec::BaseState {
LoadedState(ACodec *codec);
protected:
virtual bool onMessageReceived(const sp<AMessage> &msg);
virtual void stateEntered();
private:
friend struct ACodec::UninitializedState;
bool onConfigureComponent(const sp<AMessage> &msg);
void onStart();
void onShutdown(bool keepComponentAllocated);
DISALLOW_EVIL_CONSTRUCTORS(LoadedState);
};
////////////////////////////////////////////////////////////////////////////////
struct ACodec::LoadedToIdleState : public ACodec::BaseState {
LoadedToIdleState(ACodec *codec);
@@ -312,8 +330,10 @@ private:
ACodec::ACodec()
: mNode(NULL),
mSentFormat(false),
mIsEncoder(false) {
mIsEncoder(false),
mShutdownInProgress(false) {
mUninitializedState = new UninitializedState(this);
mLoadedState = new LoadedState(this);
mLoadedToIdleState = new LoadedToIdleState(this);
mIdleToExecutingState = new IdleToExecutingState(this);
mExecutingState = new ExecutingState(this);
@@ -369,8 +389,10 @@ void ACodec::signalResume() {
(new AMessage(kWhatResume, id()))->post();
}
void ACodec::initiateShutdown() {
(new AMessage(kWhatShutdown, id()))->post();
void ACodec::initiateShutdown(bool keepComponentAllocated) {
sp<AMessage> msg = new AMessage(kWhatShutdown, id());
msg->setInt32("keepComponentAllocated", keepComponentAllocated);
msg->post();
}
status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) {
@@ -2492,6 +2514,10 @@ ACodec::UninitializedState::UninitializedState(ACodec *codec)
: BaseState(codec) {
}
void ACodec::UninitializedState::stateEntered() {
ALOGV("Now uninitialized");
}
bool ACodec::UninitializedState::onMessageReceived(const sp<AMessage> &msg) {
bool handled = false;
@@ -2511,22 +2537,13 @@ bool ACodec::UninitializedState::onMessageReceived(const sp<AMessage> &msg) {
break;
}
case ACodec::kWhatConfigureComponent:
{
onConfigureComponent(msg);
handled = true;
break;
}
case ACodec::kWhatStart:
{
onStart();
handled = true;
break;
}
case ACodec::kWhatShutdown:
{
int32_t keepComponentAllocated;
CHECK(msg->findInt32(
"keepComponentAllocated", &keepComponentAllocated));
CHECK(!keepComponentAllocated);
sp<AMessage> notify = mCodec->mNotify->dup();
notify->setInt32("what", ACodec::kWhatShutdownCompleted);
notify->post();
@@ -2554,22 +2571,16 @@ bool ACodec::UninitializedState::onMessageReceived(const sp<AMessage> &msg) {
void ACodec::UninitializedState::onSetup(
const sp<AMessage> &msg) {
onAllocateComponent(msg);
onConfigureComponent(msg);
onStart();
if (onAllocateComponent(msg)
&& mCodec->mLoadedState->onConfigureComponent(msg)) {
mCodec->mLoadedState->onStart();
}
}
void ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) {
bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) {
ALOGV("onAllocateComponent");
if (mCodec->mNode != NULL) {
CHECK_EQ(mCodec->mOMX->freeNode(mCodec->mNode), (status_t)OK);
mCodec->mNativeWindow.clear();
mCodec->mNode = NULL;
mCodec->mOMX.clear();
mCodec->mComponentName.clear();
}
CHECK(mCodec->mNode == NULL);
OMXClient client;
CHECK_EQ(client.connect(), (status_t)OK);
@@ -2628,7 +2639,7 @@ void ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) {
}
mCodec->signalError(OMX_ErrorComponentNotFound);
return;
return false;
}
sp<AMessage> notify = new AMessage(kWhatOMXMessage, mCodec->id());
@@ -2649,9 +2660,96 @@ void ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) {
notify->setString("componentName", mCodec->mComponentName.c_str());
notify->post();
}
mCodec->changeState(mCodec->mLoadedState);
return true;
}
void ACodec::UninitializedState::onConfigureComponent(
////////////////////////////////////////////////////////////////////////////////
ACodec::LoadedState::LoadedState(ACodec *codec)
: BaseState(codec) {
}
void ACodec::LoadedState::stateEntered() {
ALOGV("[%s] Now Loaded", mCodec->mComponentName.c_str());
if (mCodec->mShutdownInProgress) {
bool keepComponentAllocated = mCodec->mKeepComponentAllocated;
mCodec->mShutdownInProgress = false;
mCodec->mKeepComponentAllocated = false;
onShutdown(keepComponentAllocated);
}
}
void ACodec::LoadedState::onShutdown(bool keepComponentAllocated) {
if (!keepComponentAllocated) {
CHECK_EQ(mCodec->mOMX->freeNode(mCodec->mNode), (status_t)OK);
mCodec->mNativeWindow.clear();
mCodec->mNode = NULL;
mCodec->mOMX.clear();
mCodec->mComponentName.clear();
mCodec->changeState(mCodec->mUninitializedState);
}
sp<AMessage> notify = mCodec->mNotify->dup();
notify->setInt32("what", ACodec::kWhatShutdownCompleted);
notify->post();
}
bool ACodec::LoadedState::onMessageReceived(const sp<AMessage> &msg) {
bool handled = false;
switch (msg->what()) {
case ACodec::kWhatConfigureComponent:
{
onConfigureComponent(msg);
handled = true;
break;
}
case ACodec::kWhatStart:
{
onStart();
handled = true;
break;
}
case ACodec::kWhatShutdown:
{
int32_t keepComponentAllocated;
CHECK(msg->findInt32(
"keepComponentAllocated", &keepComponentAllocated));
onShutdown(keepComponentAllocated);
handled = true;
break;
}
case ACodec::kWhatFlush:
{
sp<AMessage> notify = mCodec->mNotify->dup();
notify->setInt32("what", ACodec::kWhatFlushCompleted);
notify->post();
handled = true;
break;
}
default:
return BaseState::onMessageReceived(msg);
}
return handled;
}
bool ACodec::LoadedState::onConfigureComponent(
const sp<AMessage> &msg) {
ALOGV("onConfigureComponent");
@@ -2664,7 +2762,7 @@ void ACodec::UninitializedState::onConfigureComponent(
if (err != OK) {
mCodec->signalError(OMX_ErrorUndefined, err);
return;
return false;
}
sp<RefBase> obj;
@@ -2682,9 +2780,11 @@ void ACodec::UninitializedState::onConfigureComponent(
notify->setInt32("what", ACodec::kWhatComponentConfigured);
notify->post();
}
return true;
}
void ACodec::UninitializedState::onStart() {
void ACodec::LoadedState::onStart() {
ALOGV("onStart");
CHECK_EQ(mCodec->mOMX->sendCommand(
@@ -2873,6 +2973,13 @@ bool ACodec::ExecutingState::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatShutdown:
{
int32_t keepComponentAllocated;
CHECK(msg->findInt32(
"keepComponentAllocated", &keepComponentAllocated));
mCodec->mShutdownInProgress = true;
mCodec->mKeepComponentAllocated = keepComponentAllocated;
mActive = false;
CHECK_EQ(mCodec->mOMX->sendCommand(
@@ -3210,20 +3317,7 @@ bool ACodec::IdleToLoadedState::onOMXEvent(
CHECK_EQ(data1, (OMX_U32)OMX_CommandStateSet);
CHECK_EQ(data2, (OMX_U32)OMX_StateLoaded);
ALOGV("[%s] Now Loaded", mCodec->mComponentName.c_str());
CHECK_EQ(mCodec->mOMX->freeNode(mCodec->mNode), (status_t)OK);
mCodec->mNativeWindow.clear();
mCodec->mNode = NULL;
mCodec->mOMX.clear();
mCodec->mComponentName.clear();
mCodec->changeState(mCodec->mUninitializedState);
sp<AMessage> notify = mCodec->mNotify->dup();
notify->setInt32("what", ACodec::kWhatShutdownCompleted);
notify->post();
mCodec->changeState(mCodec->mLoadedState);
return true;
}

View File

@@ -164,6 +164,13 @@ status_t MediaCodec::stop() {
return PostAndAwaitResponse(msg, &response);
}
status_t MediaCodec::release() {
sp<AMessage> msg = new AMessage(kWhatRelease, id());
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
}
status_t MediaCodec::queueInputBuffer(
size_t index,
size_t offset,
@@ -422,6 +429,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
}
case STOPPING:
case RELEASING:
{
// Ignore the error, assuming we'll still get
// the shutdown complete notification.
@@ -577,7 +585,9 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
{
/* size_t index = */updateBuffers(kPortIndexInput, msg);
if (mState == FLUSHING || mState == STOPPING) {
if (mState == FLUSHING
|| mState == STOPPING
|| mState == RELEASING) {
returnBuffersToCodecOnPort(kPortIndexInput);
break;
}
@@ -596,7 +606,9 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
{
/* size_t index = */updateBuffers(kPortIndexOutput, msg);
if (mState == FLUSHING || mState == STOPPING) {
if (mState == FLUSHING
|| mState == STOPPING
|| mState == RELEASING) {
returnBuffersToCodecOnPort(kPortIndexOutput);
break;
}
@@ -628,8 +640,12 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
case ACodec::kWhatShutdownCompleted:
{
CHECK_EQ(mState, STOPPING);
setState(UNINITIALIZED);
if (mState == STOPPING) {
setState(INITIALIZED);
} else {
CHECK_EQ(mState, RELEASING);
setState(UNINITIALIZED);
}
(new AMessage)->postReply(mReplyID);
break;
@@ -767,6 +783,28 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
mReplyID = replyID;
setState(STOPPING);
mCodec->initiateShutdown(true /* keepComponentAllocated */);
returnBuffersToCodec();
break;
}
case kWhatRelease:
{
uint32_t replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
if (mState != INITIALIZED
&& mState != CONFIGURED && mState != STARTED) {
sp<AMessage> response = new AMessage;
response->setInt32("err", INVALID_OPERATION);
response->postReply(replyID);
break;
}
mReplyID = replyID;
setState(RELEASING);
mCodec->initiateShutdown();
returnBuffersToCodec();
break;