summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHangyu Kuang <hkuang@google.com>2019-04-28 21:18:48 -0700
committerHangyu Kuang <hkuang@google.com>2019-05-06 15:44:36 -0700
commit9c4de66caf0b87745bc83860c22174412d5af1b7 (patch)
tree0304bc6681c1a4ee5c2a5ff2e847e27128e03154
parent28aeb9e1a83027199b4e406418c6dcb351a7765a (diff)
downloadav-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.cpp77
-rw-r--r--media/eco/include/eco/ECOSession.h23
-rw-r--r--media/eco/tests/EcoSessionTest.cpp108
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