diff options
author | Hangyu Kuang <hkuang@google.com> | 2019-04-28 21:18:48 -0700 |
---|---|---|
committer | Hangyu Kuang <hkuang@google.com> | 2019-05-06 15:44:36 -0700 |
commit | 9c4de66caf0b87745bc83860c22174412d5af1b7 (patch) | |
tree | 0304bc6681c1a4ee5c2a5ff2e847e27128e03154 | |
parent | 28aeb9e1a83027199b4e406418c6dcb351a7765a (diff) | |
download | av-9c4de66caf0b87745bc83860c22174412d5af1b7.tar.gz |
[ECOService]: Support adding listener after provider starts.
If a listener subscribe to ECOSession after the provider sending the
first session info, ECOSession should send the listener the latest
session info right after adding it to internal.
Also add a fix for the failrue in ECOSessionTest due to changing
FrameType from int32_t to int8_t.
Bug:117877984
Test: Unit test
Change-Id: Ib982c6d9bfadb625eb85e0653941e2608158c054
-rw-r--r-- | media/eco/ECOSession.cpp | 77 | ||||
-rw-r--r-- | media/eco/include/eco/ECOSession.h | 23 | ||||
-rw-r--r-- | media/eco/tests/EcoSessionTest.cpp | 108 |
3 files changed, 193 insertions, 15 deletions
diff --git a/media/eco/ECOSession.cpp b/media/eco/ECOSession.cpp index 3419d1d..1a1bc59 100644 --- a/media/eco/ECOSession.cpp +++ b/media/eco/ECOSession.cpp @@ -92,7 +92,7 @@ ECOSession::ECOSession(int32_t width, int32_t height, bool isCameraRecording) ECOSession::~ECOSession() { mStopThread = true; - mStatsQueueWaitCV.notify_all(); + mWorkerWaitCV.notify_all(); if (mThread.joinable()) { ECOLOGD("ECOSession: join the thread"); mThread.join(); @@ -112,8 +112,22 @@ void ECOSession::run() { while (!mStopThread) { std::unique_lock<std::mutex> runLock(mStatsQueueLock); - mStatsQueueWaitCV.wait(runLock, - [this] { return mStopThread == true || !mStatsQueue.empty(); }); + mWorkerWaitCV.wait(runLock, [this] { + return mStopThread == true || !mStatsQueue.empty() || mNewListenerAdded; + }); + + if (mStopThread) return; + + std::scoped_lock<std::mutex> lock(mSessionLock); + if (mNewListenerAdded) { + // Check if there is any session info available. + ECOData sessionInfo = generateLatestSessionInfoEcoData(); + if (!sessionInfo.isEmpty()) { + mListener->onNewInfo(sessionInfo); + } + mNewListenerAdded = false; + } + if (!mStatsQueue.empty()) { ECOData stats = mStatsQueue.front(); mStatsQueue.pop_front(); @@ -211,6 +225,57 @@ bool ECOSession::processSessionStats(const ECOData& stats) { return true; } +ECOData ECOSession::generateLatestSessionInfoEcoData() { + bool hasInfo = false; + + ECOData info(ECOData::DATA_TYPE_INFO, systemTime(SYSTEM_TIME_BOOTTIME)); + + if (mOutputWidth != -1) { + info.setInt32(ENCODER_OUTPUT_WIDTH, mOutputWidth); + hasInfo = true; + } + + if (mOutputHeight != -1) { + info.setInt32(ENCODER_OUTPUT_HEIGHT, mOutputHeight); + hasInfo = true; + } + + if (mCodecType != -1) { + info.setInt32(ENCODER_TYPE, mCodecType); + hasInfo = true; + } + + if (mCodecProfile != -1) { + info.setInt32(ENCODER_PROFILE, mCodecProfile); + hasInfo = true; + } + + if (mCodecLevel != -1) { + info.setInt32(ENCODER_LEVEL, mCodecLevel); + hasInfo = true; + } + + if (mBitrateBps != -1) { + info.setInt32(ENCODER_TARGET_BITRATE_BPS, mBitrateBps); + hasInfo = true; + } + + if (mKeyFrameIntervalFrames != -1) { + info.setInt32(ENCODER_KFI_FRAMES, mKeyFrameIntervalFrames); + hasInfo = true; + } + + if (mFramerateFps > 0) { + info.setFloat(ENCODER_FRAMERATE_FPS, mFramerateFps); + hasInfo = true; + } + + if (hasInfo) { + info.setString(KEY_INFO_TYPE, VALUE_INFO_TYPE_SESSION); + } + return info; +} + bool ECOSession::processFrameStats(const ECOData& stats) { ECOLOGD("processFrameStats"); @@ -371,6 +436,9 @@ Status ECOSession::addInfoListener( IPCThreadState::self()->getCallingUid(), IPCThreadState::self()->getCallingPid()); mListener = listener; + mNewListenerAdded = true; + mWorkerWaitCV.notify_all(); + *status = true; return binder::Status::ok(); } @@ -385,6 +453,7 @@ Status ECOSession::removeInfoListener( } mListener = nullptr; + mNewListenerAdded = false; *_aidl_return = true; return binder::Status::ok(); } @@ -393,7 +462,7 @@ Status ECOSession::pushNewStats(const ::android::media::eco::ECOData& stats, boo ECOLOGV("ECOSession get new stats type: %s", stats.getDataTypeString().c_str()); std::unique_lock<std::mutex> lock(mStatsQueueLock); mStatsQueue.push_back(stats); - mStatsQueueWaitCV.notify_all(); + mWorkerWaitCV.notify_all(); return binder::Status::ok(); } diff --git a/media/eco/include/eco/ECOSession.h b/media/eco/include/eco/ECOSession.h index afde89c..c801de2 100644 --- a/media/eco/include/eco/ECOSession.h +++ b/media/eco/include/eco/ECOSession.h @@ -109,11 +109,16 @@ private: // Process the frame stats received from provider. bool processFrameStats(const ECOData& stats); + // Generate the latest session info if available. + ECOData generateLatestSessionInfoEcoData(); + std::atomic<bool> mStopThread; std::mutex mStatsQueueLock; std::deque<ECOData> mStatsQueue; // GUARDED_BY(mStatsQueueLock) - std::condition_variable mStatsQueueWaitCV; + std::condition_variable mWorkerWaitCV; + + bool mNewListenerAdded = false; constexpr static int32_t ENCODER_MIN_QP = 0; constexpr static int32_t ENCODER_MAX_QP = 51; @@ -142,21 +147,27 @@ private: // Whether the encoding is for camera recording. const bool mIsCameraRecording; + // Ouput width of the encoding session in number of pixels, -1 means not available. + int32_t mOutputWidth = -1; + + // Output height of the encoding session in number of pixels. -1 means not available. + int32_t mOutputHeight = -1; + // Encoder codec type of the encoding session. -1 means not available. - int32_t mCodecType; + int32_t mCodecType = -1; // Encoder codec profile. -1 means not available. - int32_t mCodecProfile; + int32_t mCodecProfile = -1; // Encoder codec level. -1 means not available. - int32_t mCodecLevel; + int32_t mCodecLevel = -1; // Target bitrate in bits per second. This should be provided by the provider. -1 means not // available. - int32_t mBitrateBps; + int32_t mBitrateBps = -1; // Key frame interval in number of frames. -1 means not available. - int32_t mKeyFrameIntervalFrames; + int32_t mKeyFrameIntervalFrames = -1; // Frame rate in frames per second. -1 means not available. float mFramerateFps; diff --git a/media/eco/tests/EcoSessionTest.cpp b/media/eco/tests/EcoSessionTest.cpp index 4538617..33a449d 100644 --- a/media/eco/tests/EcoSessionTest.cpp +++ b/media/eco/tests/EcoSessionTest.cpp @@ -291,8 +291,8 @@ TEST_F(EcoSessionTest, TestSessionWithProviderAndListenerSimpleTest) { EXPECT_TRUE(info.findString(KEY_INFO_TYPE, &infoType) == ECODataStatus::OK); EXPECT_EQ(infoType, VALUE_INFO_TYPE_FRAME); - int32_t frameType; - EXPECT_TRUE(info.findInt32(FRAME_TYPE, &frameType) == ECODataStatus::OK); + int8_t frameType; + EXPECT_TRUE(info.findInt8(FRAME_TYPE, &frameType) == ECODataStatus::OK); EXPECT_EQ(frameType, FrameTypeI); int32_t frameNum; @@ -336,7 +336,7 @@ TEST_F(EcoSessionTest, TestSessionWithProviderAndListenerSimpleTest) { EXPECT_TRUE(getInfo); EXPECT_TRUE(info.findString(KEY_INFO_TYPE, &infoType) == ECODataStatus::OK); EXPECT_EQ(infoType, VALUE_INFO_TYPE_FRAME); - EXPECT_TRUE(info.findInt32(FRAME_TYPE, &frameType) == ECODataStatus::OK); + EXPECT_TRUE(info.findInt8(FRAME_TYPE, &frameType) == ECODataStatus::OK); EXPECT_EQ(frameType, FrameTypeP); EXPECT_TRUE(info.findInt32(FRAME_NUM, &frameNum) == ECODataStatus::OK); EXPECT_EQ(frameNum, 3); @@ -372,7 +372,7 @@ TEST_F(EcoSessionTest, TestSessionWithProviderAndListenerSimpleTest) { EXPECT_TRUE(getInfo); EXPECT_TRUE(info.findString(KEY_INFO_TYPE, &infoType) == ECODataStatus::OK); EXPECT_EQ(infoType, VALUE_INFO_TYPE_FRAME); - EXPECT_TRUE(info.findInt32(FRAME_TYPE, &frameType) == ECODataStatus::OK); + EXPECT_TRUE(info.findInt8(FRAME_TYPE, &frameType) == ECODataStatus::OK); EXPECT_EQ(frameType, FrameTypeB); EXPECT_TRUE(info.findInt32(FRAME_NUM, &frameNum) == ECODataStatus::OK); EXPECT_EQ(frameNum, 5); @@ -396,7 +396,7 @@ TEST_F(EcoSessionTest, TestSessionWithProviderAndListenerSimpleTest) { EXPECT_TRUE(getInfo); EXPECT_TRUE(info.findString(KEY_INFO_TYPE, &infoType) == ECODataStatus::OK); EXPECT_EQ(infoType, VALUE_INFO_TYPE_FRAME); - EXPECT_TRUE(info.findInt32(FRAME_TYPE, &frameType) == ECODataStatus::OK); + EXPECT_TRUE(info.findInt8(FRAME_TYPE, &frameType) == ECODataStatus::OK); EXPECT_EQ(frameType, FrameTypeB); EXPECT_TRUE(info.findInt32(FRAME_NUM, &frameNum) == ECODataStatus::OK); EXPECT_EQ(frameNum, 6); @@ -505,6 +505,104 @@ TEST_F(EcoSessionTest, TestRemoveMisMatchListener) { EXPECT_FALSE(status.isOk()); } +// Test the listener connects to the ECOSession after provider sends the session info. Listener +// should recieve the session info right after adding itself to the ECOSession. +TEST_F(EcoSessionTest, TestAddListenerAferProviderStarts) { + // The time that listener needs to wait for the info from ECOService. + static constexpr int kServiceWaitTimeMs = 10; + + // Create the session. + sp<ECOSession> ecoSession = createSession(kTestWidth, kTestHeight, kIsCameraRecording); + + // Add provider. + sp<FakeECOServiceStatsProvider> fakeProvider = new FakeECOServiceStatsProvider( + kTestWidth, kTestHeight, kIsCameraRecording, kFrameRate, ecoSession); + ECOData providerConfig(ECOData::DATA_TYPE_STATS_PROVIDER_CONFIG, + systemTime(SYSTEM_TIME_BOOTTIME)); + providerConfig.setString(KEY_PROVIDER_NAME, "FakeECOServiceStatsProvider"); + providerConfig.setInt32(KEY_PROVIDER_TYPE, + ECOServiceStatsProvider::STATS_PROVIDER_TYPE_VIDEO_ENCODER); + bool res; + Status status = ecoSession->addStatsProvider(fakeProvider, providerConfig, &res); + + // Inject the session stats into the ECOSession through fakeProvider. + SimpleEncoderConfig sessionEncoderConfig("google-avc", CodecTypeAVC, AVCProfileHigh, AVCLevel52, + kTargetBitrateBps, kKeyFrameIntervalFrames, + kFrameRate); + fakeProvider->injectSessionStats(sessionEncoderConfig.toEcoData(ECOData::DATA_TYPE_STATS)); + + // Wait as ECOService may take some time to process. + std::this_thread::sleep_for(std::chrono::milliseconds(kServiceWaitTimeMs)); + + // ======================================================================================= + // Inject the frame stats with qp = 30. Expect receiving notification for the first frame. + SimpleEncodedFrameData frameStats(1 /* seq number */, FrameTypeI, 0 /* framePtsUs */, + 30 /* avg-qp */, 56 /* frameSize */); + + fakeProvider->injectFrameStats(frameStats.toEcoData(ECOData::DATA_TYPE_STATS)); + std::this_thread::sleep_for(std::chrono::milliseconds(kServiceWaitTimeMs)); + + // ======================================================================================= + // Create and add the listener to the ECOSession. Expect to receive the session infor right + // after addInfoListener. + sp<FakeECOServiceInfoListener> fakeListener = + new FakeECOServiceInfoListener(kTestWidth, kTestHeight, kIsCameraRecording, ecoSession); + + // Create the listener config. + ECOData listenerConfig(ECOData::DATA_TYPE_INFO_LISTENER_CONFIG, + systemTime(SYSTEM_TIME_BOOTTIME)); + listenerConfig.setString(KEY_LISTENER_NAME, "FakeECOServiceInfoListener"); + listenerConfig.setInt32(KEY_LISTENER_TYPE, ECOServiceInfoListener::INFO_LISTENER_TYPE_CAMERA); + + // Specify the qp thresholds for receiving notification. + listenerConfig.setInt32(KEY_LISTENER_QP_BLOCKINESS_THRESHOLD, 40); + listenerConfig.setInt32(KEY_LISTENER_QP_CHANGE_THRESHOLD, 5); + + ECOData info; + bool getInfo = false; + + // Set the getInfo flag to true and copy the info from fakeListener. + fakeListener->setInfoAvailableCallback( + [&info, &getInfo](const ::android::media::eco::ECOData& newInfo) { + getInfo = true; + info = newInfo; + }); + + status = ecoSession->addInfoListener(fakeListener, listenerConfig, &res); + + // Wait as ECOService may take some time to process. + std::this_thread::sleep_for(std::chrono::milliseconds(kServiceWaitTimeMs)); + + // Check the Session info matches with the session stats sent by provider. + EXPECT_TRUE(getInfo); + EXPECT_TRUE(info.getDataType() == ECOData::DATA_TYPE_INFO); + + std::string infoType; + EXPECT_TRUE(info.findString(KEY_INFO_TYPE, &infoType) == ECODataStatus::OK); + EXPECT_EQ(infoType, VALUE_INFO_TYPE_SESSION); + + // Check the session info matches the session stats provided by FakeECOServiceStatsProvider. + int32_t codecType; + EXPECT_TRUE(info.findInt32(ENCODER_TYPE, &codecType) == ECODataStatus::OK); + EXPECT_EQ(codecType, CodecTypeAVC); + + int32_t profile; + EXPECT_TRUE(info.findInt32(ENCODER_PROFILE, &profile) == ECODataStatus::OK); + EXPECT_EQ(profile, AVCProfileHigh); + + int32_t level; + EXPECT_TRUE(info.findInt32(ENCODER_LEVEL, &level) == ECODataStatus::OK); + EXPECT_EQ(level, AVCLevel52); + + int32_t bitrate; + EXPECT_TRUE(info.findInt32(ENCODER_TARGET_BITRATE_BPS, &bitrate) == ECODataStatus::OK); + EXPECT_EQ(bitrate, kTargetBitrateBps); + + int32_t kfi; + EXPECT_TRUE(info.findInt32(ENCODER_KFI_FRAMES, &kfi) == ECODataStatus::OK); + EXPECT_EQ(kfi, kKeyFrameIntervalFrames); +} + } // namespace eco } // namespace media } // namespace android |