Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 763b935e authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes Id88d546a,I14c23eea,I08286bff into rvc-qpr-dev

* changes:
  MediaCodec: fix possible crash at stop & error
  stagefright: add test for MediaCodec::reclaim/release race
  MediaCodec: ensure reply does not get lost
parents e0a38742 dcf5a494
Loading
Loading
Loading
Loading
+223 −75
Original line number Diff line number Diff line
@@ -617,7 +617,10 @@ sp<PersistentSurface> MediaCodec::CreatePersistentInputSurface() {
    return new PersistentSurface(bufferProducer, bufferSource);
}

MediaCodec::MediaCodec(const sp<ALooper> &looper, pid_t pid, uid_t uid)
MediaCodec::MediaCodec(
        const sp<ALooper> &looper, pid_t pid, uid_t uid,
        std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase,
        std::function<status_t(const AString &, sp<MediaCodecInfo> *)> getCodecInfo)
    : mState(UNINITIALIZED),
      mReleasedByResourceManager(false),
      mLooper(looper),
@@ -642,7 +645,9 @@ MediaCodec::MediaCodec(const sp<ALooper> &looper, pid_t pid, uid_t uid)
      mNumLowLatencyDisables(0),
      mIsLowLatencyModeOn(false),
      mIndexOfFirstFrameWhenLowLatencyOn(-1),
      mInputBufferCounter(0) {
      mInputBufferCounter(0),
      mGetCodecBase(getCodecBase),
      mGetCodecInfo(getCodecInfo) {
    if (uid == kNoUid) {
        mUid = AIBinder_getCallingUid();
    } else {
@@ -650,6 +655,33 @@ MediaCodec::MediaCodec(const sp<ALooper> &looper, pid_t pid, uid_t uid)
    }
    mResourceManagerProxy = new ResourceManagerServiceProxy(pid, mUid,
            ::ndk::SharedRefBase::make<ResourceManagerClient>(this));
    if (!mGetCodecBase) {
        mGetCodecBase = [](const AString &name, const char *owner) {
            return GetCodecBase(name, owner);
        };
    }
    if (!mGetCodecInfo) {
        mGetCodecInfo = [](const AString &name, sp<MediaCodecInfo> *info) -> status_t {
            *info = nullptr;
            const sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
            if (!mcl) {
                return NO_INIT;  // if called from Java should raise IOException
            }
            AString tmp = name;
            if (tmp.endsWith(".secure")) {
                tmp.erase(tmp.size() - 7, 7);
            }
            for (const AString &codecName : { name, tmp }) {
                ssize_t codecIdx = mcl->findCodecByName(codecName.c_str());
                if (codecIdx < 0) {
                    continue;
                }
                *info = mcl->getCodecInfo(codecIdx);
                return OK;
            }
            return NAME_NOT_FOUND;
        };
    }

    initMediametrics();
}
@@ -1011,6 +1043,12 @@ status_t MediaCodec::PostAndAwaitResponse(
    return err;
}

void MediaCodec::PostReplyWithError(const sp<AMessage> &msg, int32_t err) {
    sp<AReplyToken> replyID;
    CHECK(msg->senderAwaitsResponse(&replyID));
    PostReplyWithError(replyID, err);
}

void MediaCodec::PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err) {
    int32_t finalErr = err;
    if (mReleasedByResourceManager) {
@@ -1087,40 +1125,30 @@ status_t MediaCodec::init(const AString &name) {
    bool secureCodec = false;
    const char *owner = "";
    if (!name.startsWith("android.filter.")) {
        AString tmp = name;
        if (tmp.endsWith(".secure")) {
            secureCodec = true;
            tmp.erase(tmp.size() - 7, 7);
        }
        const sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
        if (mcl == NULL) {
        status_t err = mGetCodecInfo(name, &mCodecInfo);
        if (err != OK) {
            mCodec = NULL;  // remove the codec.
            return NO_INIT; // if called from Java should raise IOException
            return err;
        }
        for (const AString &codecName : { name, tmp }) {
            ssize_t codecIdx = mcl->findCodecByName(codecName.c_str());
            if (codecIdx < 0) {
                continue;
        if (mCodecInfo == nullptr) {
            ALOGE("Getting codec info with name '%s' failed", name.c_str());
            return NAME_NOT_FOUND;
        }
            mCodecInfo = mcl->getCodecInfo(codecIdx);
        secureCodec = name.endsWith(".secure");
        Vector<AString> mediaTypes;
        mCodecInfo->getSupportedMediaTypes(&mediaTypes);
            for (size_t i = 0; i < mediaTypes.size(); i++) {
        for (size_t i = 0; i < mediaTypes.size(); ++i) {
            if (mediaTypes[i].startsWith("video/")) {
                mIsVideo = true;
                break;
            }
        }
            break;
        }
        if (mCodecInfo == nullptr) {
            return NAME_NOT_FOUND;
        }
        owner = mCodecInfo->getOwnerName();
    }

    mCodec = GetCodecBase(name, owner);
    mCodec = mGetCodecBase(name, owner);
    if (mCodec == NULL) {
        ALOGE("Getting codec base with name '%s' (owner='%s') failed", name.c_str(), owner);
        return NAME_NOT_FOUND;
    }

@@ -1514,7 +1542,6 @@ status_t MediaCodec::reset() {
    mStickyError = OK;

    // reset state not reset by setState(UNINITIALIZED)
    mReplyID = 0;
    mDequeueInputReplyID = 0;
    mDequeueOutputReplyID = 0;
    mDequeueInputTimeoutGeneration = 0;
@@ -2109,6 +2136,8 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                    }

                    bool sendErrorResponse = true;
                    std::string origin{"kWhatError:"};
                    origin += stateString(mState);

                    switch (mState) {
                        case INITIALIZING:
@@ -2160,14 +2189,14 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                                // be a shutdown complete notification after
                                // all.

                                // note that we're directly going from
                                // note that we may be directly going from
                                // STOPPING->UNINITIALIZED, instead of the
                                // usual STOPPING->INITIALIZED state.
                                setState(UNINITIALIZED);
                                if (mState == RELEASING) {
                                    mComponentName.clear();
                                }
                                (new AMessage)->postReply(mReplyID);
                                postPendingRepliesAndDeferredMessages(origin + ":dead");
                                sendErrorResponse = false;
                            }
                            break;
@@ -2193,7 +2222,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                        case FLUSHED:
                        case STARTED:
                        {
                            sendErrorResponse = false;
                            sendErrorResponse = (mReplyID != nullptr);

                            setStickyError(err);
                            postActivityNotificationIfPossible();
@@ -2223,7 +2252,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {

                        default:
                        {
                            sendErrorResponse = false;
                            sendErrorResponse = (mReplyID != nullptr);

                            setStickyError(err);
                            postActivityNotificationIfPossible();
@@ -2250,7 +2279,15 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                    }

                    if (sendErrorResponse) {
                        PostReplyWithError(mReplyID, err);
                        // TRICKY: replicate PostReplyWithError logic for
                        //         err code override
                        int32_t finalErr = err;
                        if (mReleasedByResourceManager) {
                            // override the err code if MediaCodec has been
                            // released by ResourceManager.
                            finalErr = DEAD_OBJECT;
                        }
                        postPendingRepliesAndDeferredMessages(origin, finalErr);
                    }
                    break;
                }
@@ -2298,7 +2335,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                                MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
                    }

                    (new AMessage)->postReply(mReplyID);
                    postPendingRepliesAndDeferredMessages("kWhatComponentAllocated");
                    break;
                }

@@ -2337,7 +2374,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                        mFlags |= kFlagUsesSoftwareRenderer;
                    }
                    setState(CONFIGURED);
                    (new AMessage)->postReply(mReplyID);
                    postPendingRepliesAndDeferredMessages("kWhatComponentConfigured");

                    // augment our media metrics info, now that we know more things
                    // such as what the codec extracted from any CSD passed in.
@@ -2382,6 +2419,12 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {

                case kWhatInputSurfaceCreated:
                {
                    if (mState != CONFIGURED) {
                        // state transitioned unexpectedly; we should have replied already.
                        ALOGD("received kWhatInputSurfaceCreated message in state %s",
                                stateString(mState).c_str());
                        break;
                    }
                    // response to initiateCreateInputSurface()
                    status_t err = NO_ERROR;
                    sp<AMessage> response = new AMessage;
@@ -2400,12 +2443,18 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                    } else {
                        response->setInt32("err", err);
                    }
                    response->postReply(mReplyID);
                    postPendingRepliesAndDeferredMessages("kWhatInputSurfaceCreated", response);
                    break;
                }

                case kWhatInputSurfaceAccepted:
                {
                    if (mState != CONFIGURED) {
                        // state transitioned unexpectedly; we should have replied already.
                        ALOGD("received kWhatInputSurfaceAccepted message in state %s",
                                stateString(mState).c_str());
                        break;
                    }
                    // response to initiateSetInputSurface()
                    status_t err = NO_ERROR;
                    sp<AMessage> response = new AMessage();
@@ -2416,19 +2465,25 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                    } else {
                        response->setInt32("err", err);
                    }
                    response->postReply(mReplyID);
                    postPendingRepliesAndDeferredMessages("kWhatInputSurfaceAccepted", response);
                    break;
                }

                case kWhatSignaledInputEOS:
                {
                    if (!isExecuting()) {
                        // state transitioned unexpectedly; we should have replied already.
                        ALOGD("received kWhatSignaledInputEOS message in state %s",
                                stateString(mState).c_str());
                        break;
                    }
                    // response to signalEndOfInputStream()
                    sp<AMessage> response = new AMessage;
                    status_t err;
                    if (msg->findInt32("err", &err)) {
                        response->setInt32("err", err);
                    }
                    response->postReply(mReplyID);
                    postPendingRepliesAndDeferredMessages("kWhatSignaledInputEOS", response);
                    break;
                }

@@ -2447,7 +2502,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                                MediaResource::GraphicMemoryResource(getGraphicBufferSize()));
                    }
                    setState(STARTED);
                    (new AMessage)->postReply(mReplyID);
                    postPendingRepliesAndDeferredMessages("kWhatStartCompleted");
                    break;
                }

@@ -2583,7 +2638,13 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                        break;
                    }
                    setState(INITIALIZED);
                    (new AMessage)->postReply(mReplyID);
                    if (mReplyID) {
                        postPendingRepliesAndDeferredMessages("kWhatStopCompleted");
                    } else {
                        ALOGW("kWhatStopCompleted: presumably an error occurred earlier, "
                              "but the operation completed anyway. (last reply origin=%s)",
                              mLastReplyOrigin.c_str());
                    }
                    break;
                }

@@ -2607,7 +2668,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                    mReleaseSurface.reset();

                    if (mReplyID != nullptr) {
                        (new AMessage)->postReply(mReplyID);
                        postPendingRepliesAndDeferredMessages("kWhatReleaseCompleted");
                    }
                    if (mAsyncReleaseCompleteNotification != nullptr) {
                        flushMediametrics();
@@ -2632,7 +2693,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                        mCodec->signalResume();
                    }

                    (new AMessage)->postReply(mReplyID);
                    postPendingRepliesAndDeferredMessages("kWhatFlushCompleted");
                    break;
                }

@@ -2644,13 +2705,17 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {

        case kWhatInit:
        {
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            if (mState != UNINITIALIZED) {
                PostReplyWithError(replyID, INVALID_OPERATION);
                PostReplyWithError(msg, INVALID_OPERATION);
                break;
            }

            if (mReplyID) {
                mDeferredMessages.push_back(msg);
                break;
            }
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            mReplyID = replyID;
            setState(INITIALIZING);
@@ -2713,14 +2778,18 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {

        case kWhatConfigure:
        {
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            if (mState != INITIALIZED) {
                PostReplyWithError(replyID, INVALID_OPERATION);
                PostReplyWithError(msg, INVALID_OPERATION);
                break;
            }

            if (mReplyID) {
                mDeferredMessages.push_back(msg);
                break;
            }
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            sp<RefBase> obj;
            CHECK(msg->findObject("surface", &obj));

@@ -2858,15 +2927,19 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
        case kWhatCreateInputSurface:
        case kWhatSetInputSurface:
        {
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            // Must be configured, but can't have been started yet.
            if (mState != CONFIGURED) {
                PostReplyWithError(replyID, INVALID_OPERATION);
                PostReplyWithError(msg, INVALID_OPERATION);
                break;
            }

            if (mReplyID) {
                mDeferredMessages.push_back(msg);
                break;
            }
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            mReplyID = replyID;
            if (msg->what() == kWhatCreateInputSurface) {
                mCodec->initiateCreateInputSurface();
@@ -2881,9 +2954,6 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
        }
        case kWhatStart:
        {
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            if (mState == FLUSHED) {
                setState(STARTED);
                if (mHavePendingInputBuffers) {
@@ -2891,13 +2961,20 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                    mHavePendingInputBuffers = false;
                }
                mCodec->signalResume();
                PostReplyWithError(replyID, OK);
                PostReplyWithError(msg, OK);
                break;
            } else if (mState != CONFIGURED) {
                PostReplyWithError(replyID, INVALID_OPERATION);
                PostReplyWithError(msg, INVALID_OPERATION);
                break;
            }

            if (mReplyID) {
                mDeferredMessages.push_back(msg);
                break;
            }
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            mReplyID = replyID;
            setState(STARTING);

@@ -2905,15 +2982,42 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
            break;
        }

        case kWhatStop:
        case kWhatStop: {
            if (mReplyID) {
                mDeferredMessages.push_back(msg);
                break;
            }
            [[fallthrough]];
        }
        case kWhatRelease:
        {
            State targetState =
                (msg->what() == kWhatStop) ? INITIALIZED : UNINITIALIZED;

            if ((mState == RELEASING && targetState == UNINITIALIZED)
                    || (mState == STOPPING && targetState == INITIALIZED)) {
                mDeferredMessages.push_back(msg);
                break;
            }

            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            sp<AMessage> asyncNotify;
            (void)msg->findMessage("async", &asyncNotify);
            // post asyncNotify if going out of scope.
            struct AsyncNotifyPost {
                AsyncNotifyPost(const sp<AMessage> &asyncNotify) : mAsyncNotify(asyncNotify) {}
                ~AsyncNotifyPost() {
                    if (mAsyncNotify) {
                        mAsyncNotify->post();
                    }
                }
                void clear() { mAsyncNotify.clear(); }
            private:
                sp<AMessage> mAsyncNotify;
            } asyncNotifyPost{asyncNotify};

            // already stopped/released
            if (mState == UNINITIALIZED && mReleasedByResourceManager) {
                sp<AMessage> response = new AMessage;
@@ -2977,12 +3081,15 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
            // after this, and we'll no longer be able to reply.
            if (mState == FLUSHING || mState == STOPPING
                    || mState == CONFIGURING || mState == STARTING) {
                (new AMessage)->postReply(mReplyID);
                // mReply is always set if in these states.
                postPendingRepliesAndDeferredMessages(
                        std::string("kWhatRelease:") + stateString(mState));
            }

            if (mFlags & kFlagSawMediaServerDie) {
                // It's dead, Jim. Don't expect initiateShutdown to yield
                // any useful results now...
                // Any pending reply would have been handled at kWhatError.
                setState(UNINITIALIZED);
                if (targetState == UNINITIALIZED) {
                    mComponentName.clear();
@@ -2996,12 +3103,12 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
            // reply now with an error to unblock the client, client can
            // release after the failure (instead of ANR).
            if (msg->what() == kWhatStop && (mFlags & kFlagStickyError)) {
                // Any pending reply would have been handled at kWhatError.
                PostReplyWithError(replyID, getStickyError());
                break;
            }

            sp<AMessage> asyncNotify;
            if (msg->findMessage("async", &asyncNotify) && asyncNotify != nullptr) {
            if (asyncNotify != nullptr) {
                if (mSurface != NULL) {
                    if (!mReleaseSurface) {
                        mReleaseSurface.reset(new ReleaseSurface);
@@ -3021,6 +3128,12 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                }
            }

            if (mReplyID) {
                // State transition replies are handled above, so this reply
                // would not be related to state transition. As we are
                // shutting down the component, just fail the operation.
                postPendingRepliesAndDeferredMessages("kWhatRelease:reply", UNKNOWN_ERROR);
            }
            mReplyID = replyID;
            setState(msg->what() == kWhatStop ? STOPPING : RELEASING);

@@ -3035,8 +3148,8 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {

            if (asyncNotify != nullptr) {
                mResourceManagerProxy->markClientForPendingRemoval();
                (new AMessage)->postReply(mReplyID);
                mReplyID = 0;
                postPendingRepliesAndDeferredMessages("kWhatRelease:async");
                asyncNotifyPost.clear();
                mAsyncReleaseCompleteNotification = asyncNotify;
            }

@@ -3207,17 +3320,21 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {

        case kWhatSignalEndOfInputStream:
        {
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            if (!isExecuting() || !mHaveInputSurface) {
                PostReplyWithError(replyID, INVALID_OPERATION);
                PostReplyWithError(msg, INVALID_OPERATION);
                break;
            } else if (mFlags & kFlagStickyError) {
                PostReplyWithError(replyID, getStickyError());
                PostReplyWithError(msg, getStickyError());
                break;
            }

            if (mReplyID) {
                mDeferredMessages.push_back(msg);
                break;
            }
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            mReplyID = replyID;
            mCodec->signalEndOfInputStream();
            break;
@@ -3259,17 +3376,21 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {

        case kWhatFlush:
        {
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            if (!isExecuting()) {
                PostReplyWithError(replyID, INVALID_OPERATION);
                PostReplyWithError(msg, INVALID_OPERATION);
                break;
            } else if (mFlags & kFlagStickyError) {
                PostReplyWithError(replyID, getStickyError());
                PostReplyWithError(msg, getStickyError());
                break;
            }

            if (mReplyID) {
                mDeferredMessages.push_back(msg);
                break;
            }
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            mReplyID = replyID;
            // TODO: skip flushing if already FLUSHED
            setState(FLUSHING);
@@ -4214,6 +4335,33 @@ status_t MediaCodec::amendOutputFormatWithCodecSpecificData(
    return OK;
}

void MediaCodec::postPendingRepliesAndDeferredMessages(
        std::string origin, status_t err /* = OK */) {
    sp<AMessage> response{new AMessage};
    if (err != OK) {
        response->setInt32("err", err);
    }
    postPendingRepliesAndDeferredMessages(origin, response);
}

void MediaCodec::postPendingRepliesAndDeferredMessages(
        std::string origin, const sp<AMessage> &response) {
    LOG_ALWAYS_FATAL_IF(
            !mReplyID,
            "postPendingRepliesAndDeferredMessages: mReplyID == null, from %s following %s",
            origin.c_str(),
            mLastReplyOrigin.c_str());
    mLastReplyOrigin = origin;
    response->postReply(mReplyID);
    mReplyID.clear();
    ALOGV_IF(!mDeferredMessages.empty(),
            "posting %zu deferred messages", mDeferredMessages.size());
    for (sp<AMessage> msg : mDeferredMessages) {
        msg->post();
    }
    mDeferredMessages.clear();
}

std::string MediaCodec::stateString(State state) {
    const char *rval = NULL;
    char rawbuffer[16]; // room for "%d"
+3 −0
Original line number Diff line number Diff line
@@ -17,6 +17,9 @@
          "exclude-filter": "android.media.cts.AudioRecordTest"
        }
      ]
    },
    {
      "name": "mediacodecTest"
    }
  ],
  "postsubmit": [
+14 −1
Original line number Diff line number Diff line
@@ -366,6 +366,8 @@ private:
    AString mOwnerName;
    sp<MediaCodecInfo> mCodecInfo;
    sp<AReplyToken> mReplyID;
    std::string mLastReplyOrigin;
    std::vector<sp<AMessage>> mDeferredMessages;
    uint32_t mFlags;
    status_t mStickyError;
    sp<Surface> mSurface;
@@ -428,13 +430,17 @@ private:

    std::shared_ptr<BufferChannelBase> mBufferChannel;

    MediaCodec(const sp<ALooper> &looper, pid_t pid, uid_t uid);
    MediaCodec(
            const sp<ALooper> &looper, pid_t pid, uid_t uid,
            std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase = nullptr,
            std::function<status_t(const AString &, sp<MediaCodecInfo> *)> getCodecInfo = nullptr);

    static sp<CodecBase> GetCodecBase(const AString &name, const char *owner = nullptr);

    static status_t PostAndAwaitResponse(
            const sp<AMessage> &msg, sp<AMessage> *response);

    void PostReplyWithError(const sp<AMessage> &msg, int32_t err);
    void PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err);

    status_t init(const AString &name);
@@ -486,6 +492,9 @@ private:
    bool hasPendingBuffer(int portIndex);
    bool hasPendingBuffer();

    void postPendingRepliesAndDeferredMessages(std::string origin, status_t err = OK);
    void postPendingRepliesAndDeferredMessages(std::string origin, const sp<AMessage> &response);

    /* called to get the last codec error when the sticky flag is set.
     * if no such codec error is found, returns UNKNOWN_ERROR.
     */
@@ -571,6 +580,10 @@ private:

    Histogram mLatencyHist;

    std::function<sp<CodecBase>(const AString &, const char *)> mGetCodecBase;
    std::function<status_t(const AString &, sp<MediaCodecInfo> *)> mGetCodecInfo;
    friend class MediaTestHelper;

    DISALLOW_EVIL_CONSTRUCTORS(MediaCodec);
};

+1 −1
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@
#define MEDIA_CODEC_LIST_WRITER_H_

#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/MediaCodecListWriter.h>
#include <media/MediaCodecInfo.h>

#include <utils/Errors.h>
@@ -65,6 +64,7 @@ private:
    std::vector<sp<MediaCodecInfo>> mCodecInfos;

    friend struct MediaCodecList;
    friend class MediaTestHelper;
};

/**
+62 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading