Transcoding: Log transcoder level metrics.
- Add transcoder-level metric logging through west world,
to monitor performance and failures.
- Add new unit tests for TranscodingLogger class.
Bug: 179274112
Test: New and existing unit tests.
Change-Id: Ie8d9bc589c714a7b8be8f4f298c4fa75a81a6e56
diff --git a/media/libmediatranscoding/Android.bp b/media/libmediatranscoding/Android.bp
index 534fa91..042850c 100644
--- a/media/libmediatranscoding/Android.bp
+++ b/media/libmediatranscoding/Android.bp
@@ -82,6 +82,7 @@
srcs: [
"TranscoderWrapper.cpp",
"TranscodingClientManager.cpp",
+ "TranscodingLogger.cpp",
"TranscodingResourcePolicy.cpp",
"TranscodingSessionController.cpp",
"TranscodingThermalPolicy.cpp",
@@ -96,6 +97,7 @@
"libutils",
"libmediatranscoder",
"libmediandk",
+ "libstatssocket#30",
],
export_shared_lib_headers: [
"libmediandk",
@@ -106,6 +108,7 @@
static_libs: [
"mediatranscoding_aidl_interface-ndk_platform",
"resourceobserver_aidl_interface-V1-ndk_platform",
+ "libstatslog_media",
],
cflags: [
@@ -126,3 +129,43 @@
cfi: true,
},
}
+
+cc_library_static {
+ name: "libstatslog_media",
+ generated_sources: ["statslog_media.cpp"],
+ generated_headers: ["statslog_media.h"],
+ min_sdk_version: "29",
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ export_generated_headers: ["statslog_media.h"],
+ apex_available: [
+ "com.android.media",
+ "test_com.android.media",
+ ],
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ "libstatssocket#30",
+ "libutils",
+ ],
+}
+
+genrule {
+ name: "statslog_media.h",
+ tools: ["stats-log-api-gen"],
+ cmd: "$(location stats-log-api-gen) --header $(genDir)/statslog_media.h --module media --namespace android,media,stats",
+ out: [
+ "statslog_media.h",
+ ],
+}
+
+genrule {
+ name: "statslog_media.cpp",
+ tools: ["stats-log-api-gen"],
+ cmd: "$(location stats-log-api-gen) --cpp $(genDir)/statslog_media.cpp --module media --namespace android,media,stats --importHeader statslog_media.h",
+ out: [
+ "statslog_media.cpp",
+ ],
+}
\ No newline at end of file
diff --git a/media/libmediatranscoding/TranscoderWrapper.cpp b/media/libmediatranscoding/TranscoderWrapper.cpp
index 4bd4105..d9c98c6 100644
--- a/media/libmediatranscoding/TranscoderWrapper.cpp
+++ b/media/libmediatranscoding/TranscoderWrapper.cpp
@@ -56,34 +56,34 @@
}
}
-static AMediaFormat* getVideoFormat(
+static std::shared_ptr<AMediaFormat> getVideoFormat(
const char* originalMime,
const std::optional<TranscodingVideoTrackFormat>& requestedFormat) {
if (requestedFormat == std::nullopt) {
return nullptr;
}
- AMediaFormat* format = AMediaFormat_new();
+ std::shared_ptr<AMediaFormat> format =
+ std::shared_ptr<AMediaFormat>(AMediaFormat_new(), &AMediaFormat_delete);
bool changed = false;
if (requestedFormat->codecType == TranscodingVideoCodecType::kHevc &&
strcmp(originalMime, AMEDIA_MIMETYPE_VIDEO_HEVC)) {
- AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_HEVC);
+ AMediaFormat_setString(format.get(), AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_HEVC);
changed = true;
} else if (requestedFormat->codecType == TranscodingVideoCodecType::kAvc &&
strcmp(originalMime, AMEDIA_MIMETYPE_VIDEO_AVC)) {
- AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_AVC);
+ AMediaFormat_setString(format.get(), AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_AVC);
changed = true;
}
if (requestedFormat->bitrateBps > 0) {
- AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, requestedFormat->bitrateBps);
+ AMediaFormat_setInt32(format.get(), AMEDIAFORMAT_KEY_BIT_RATE, requestedFormat->bitrateBps);
changed = true;
}
// TODO: translate other fields from requestedFormat to the format for MediaTranscoder.
// Also need to determine more settings to expose in TranscodingVideoTrackFormat.
if (!changed) {
- AMediaFormat_delete(format);
// Use null format for passthru.
- format = nullptr;
+ format.reset();
}
return format;
}
@@ -180,8 +180,10 @@
};
TranscoderWrapper::TranscoderWrapper(const std::shared_ptr<TranscoderCallbackInterface>& cb,
+ const std::shared_ptr<TranscodingLogger>& logger,
int64_t heartBeatIntervalUs)
: mCallback(cb),
+ mLogger(logger),
mHeartBeatIntervalUs(heartBeatIntervalUs),
mCurrentClientId(0),
mCurrentSessionId(-1),
@@ -219,10 +221,10 @@
}
void TranscoderWrapper::start(ClientIdType clientId, SessionIdType sessionId,
- const TranscodingRequestParcel& request,
+ const TranscodingRequestParcel& request, uid_t callingUid,
const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
queueEvent(Event::Start, clientId, sessionId, [=, &request] {
- media_status_t err = handleStart(clientId, sessionId, request, clientCb);
+ media_status_t err = handleStart(clientId, sessionId, request, callingUid, clientCb);
if (err != AMEDIA_OK) {
cleanup();
reportError(clientId, sessionId, err);
@@ -253,10 +255,10 @@
}
void TranscoderWrapper::resume(ClientIdType clientId, SessionIdType sessionId,
- const TranscodingRequestParcel& request,
+ const TranscodingRequestParcel& request, uid_t callingUid,
const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
queueEvent(Event::Resume, clientId, sessionId, [=, &request] {
- media_status_t err = handleResume(clientId, sessionId, request, clientCb);
+ media_status_t err = handleResume(clientId, sessionId, request, callingUid, clientCb);
if (err != AMEDIA_OK) {
cleanup();
reportError(clientId, sessionId, err);
@@ -280,6 +282,7 @@
} else {
ALOGI("transcoder stopped");
}
+ logSessionEnded(TranscodingLogger::SessionEndedReason::CANCELLED, err);
cleanup();
} else {
// For sessions that's not currently running, release any pausedState for the session.
@@ -297,6 +300,7 @@
queueEvent(Event::Finish, clientId, sessionId, [=] {
if (mTranscoder != nullptr && clientId == mCurrentClientId &&
sessionId == mCurrentSessionId) {
+ logSessionEnded(TranscodingLogger::SessionEndedReason::FINISHED, AMEDIA_OK);
cleanup();
}
@@ -314,6 +318,7 @@
[=] {
if (mTranscoder != nullptr && clientId == mCurrentClientId &&
sessionId == mCurrentSessionId) {
+ logSessionEnded(TranscodingLogger::SessionEndedReason::ERROR, error);
cleanup();
}
reportError(clientId, sessionId, error);
@@ -345,7 +350,8 @@
media_status_t TranscoderWrapper::setupTranscoder(
ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
- const std::shared_ptr<ITranscodingClientCallback>& clientCb,
+ uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& clientCb,
+ TranscodingLogger::SessionEndedReason* failureReason,
const std::shared_ptr<ndk::ScopedAParcel>& pausedState) {
if (clientCb == nullptr) {
ALOGE("client callback is null");
@@ -364,6 +370,7 @@
status = clientCb->openFileDescriptor(request.sourceFilePath, "r", &srcFd);
if (!status.isOk() || srcFd.get() < 0) {
ALOGE("failed to open source");
+ *failureReason = TranscodingLogger::SessionEndedReason::OPEN_SRC_FD_FAILED;
return AMEDIA_ERROR_IO;
}
srcFdInt = srcFd.get();
@@ -377,6 +384,7 @@
status = clientCb->openFileDescriptor(request.destinationFilePath, "rw", &dstFd);
if (!status.isOk() || dstFd.get() < 0) {
ALOGE("failed to open destination");
+ *failureReason = TranscodingLogger::SessionEndedReason::OPEN_DST_FD_FAILED;
return AMEDIA_ERROR_IO;
}
dstFdInt = dstFd.get();
@@ -384,41 +392,46 @@
mCurrentClientId = clientId;
mCurrentSessionId = sessionId;
+ mCurrentCallingUid = callingUid;
mTranscoderCb = std::make_shared<CallbackImpl>(shared_from_this(), clientId, sessionId);
mTranscoder = MediaTranscoder::create(mTranscoderCb, mHeartBeatIntervalUs, request.clientPid,
request.clientUid, pausedState);
if (mTranscoder == nullptr) {
ALOGE("failed to create transcoder");
+ *failureReason = TranscodingLogger::SessionEndedReason::CREATE_FAILED;
return AMEDIA_ERROR_UNKNOWN;
}
media_status_t err = mTranscoder->configureSource(srcFdInt);
if (err != AMEDIA_OK) {
ALOGE("failed to configure source: %d", err);
+ *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_SRC_FAILED;
return err;
}
std::vector<std::shared_ptr<AMediaFormat>> trackFormats = mTranscoder->getTrackFormats();
if (trackFormats.size() == 0) {
ALOGE("failed to get track formats!");
+ *failureReason = TranscodingLogger::SessionEndedReason::NO_TRACKS;
return AMEDIA_ERROR_MALFORMED;
}
for (int i = 0; i < trackFormats.size(); ++i) {
- AMediaFormat* format = nullptr;
+ std::shared_ptr<AMediaFormat> format;
const char* mime = nullptr;
AMediaFormat_getString(trackFormats[i].get(), AMEDIAFORMAT_KEY_MIME, &mime);
if (!strncmp(mime, "video/", 6)) {
format = getVideoFormat(mime, request.requestedVideoTrackFormat);
+
+ mSrcFormat = trackFormats[i];
+ mDstFormat = format;
}
- err = mTranscoder->configureTrackFormat(i, format);
- if (format != nullptr) {
- AMediaFormat_delete(format);
- }
+ err = mTranscoder->configureTrackFormat(i, format.get());
if (err != AMEDIA_OK) {
ALOGE("failed to configure track format for track %d: %d", i, err);
+ *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_TRACK_FAILED;
return err;
}
}
@@ -426,6 +439,7 @@
err = mTranscoder->configureDestination(dstFdInt);
if (err != AMEDIA_OK) {
ALOGE("failed to configure dest: %d", err);
+ *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_DST_FAILED;
return err;
}
@@ -434,17 +448,23 @@
media_status_t TranscoderWrapper::handleStart(
ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
- const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
+ uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
ALOGI("%s: setting up transcoder for start", __FUNCTION__);
- media_status_t err = setupTranscoder(clientId, sessionId, request, clientCb);
+ TranscodingLogger::SessionEndedReason reason = TranscodingLogger::SessionEndedReason::UNKNOWN;
+ media_status_t err =
+ setupTranscoder(clientId, sessionId, request, callingUid, clientCb, &reason);
if (err != AMEDIA_OK) {
ALOGI("%s: failed to setup transcoder", __FUNCTION__);
+ logSessionEnded(reason, err);
return err;
}
+ mTranscodeStartTime = std::chrono::steady_clock::now();
+
err = mTranscoder->start();
if (err != AMEDIA_OK) {
ALOGE("%s: failed to start transcoder: %d", __FUNCTION__, err);
+ logSessionEnded(TranscodingLogger::SessionEndedReason::START_FAILED, err);
return err;
}
@@ -467,6 +487,7 @@
std::shared_ptr<ndk::ScopedAParcel> pauseStates;
media_status_t err = mTranscoder->pause(&pauseStates);
+ logSessionEnded(TranscodingLogger::SessionEndedReason::PAUSED, err);
if (err != AMEDIA_OK) {
ALOGE("%s: failed to pause transcoder: %d", __FUNCTION__, err);
return err;
@@ -479,7 +500,7 @@
media_status_t TranscoderWrapper::handleResume(
ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
- const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
+ uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
std::shared_ptr<ndk::ScopedAParcel> pausedState;
auto it = mPausedStateMap.find(SessionKeyType(clientId, sessionId));
if (it != mPausedStateMap.end()) {
@@ -491,15 +512,23 @@
}
ALOGI("%s: setting up transcoder for resume", __FUNCTION__);
- media_status_t err = setupTranscoder(clientId, sessionId, request, clientCb, pausedState);
+ TranscodingLogger::SessionEndedReason reason = TranscodingLogger::SessionEndedReason::UNKNOWN;
+ media_status_t err = setupTranscoder(clientId, sessionId, request, callingUid, clientCb,
+ &reason, pausedState);
if (err != AMEDIA_OK) {
ALOGE("%s: failed to setup transcoder: %d", __FUNCTION__, err);
+ logSessionEnded(reason, err);
return err;
}
+ // Note: For now resume() will just restart transcoding from the beginning, so there is no need
+ // to distinguish between resume and start from a performance perspective.
+ mTranscodeStartTime = std::chrono::steady_clock::now();
+
err = mTranscoder->resume();
if (err != AMEDIA_OK) {
ALOGE("%s: failed to resume transcoder: %d", __FUNCTION__, err);
+ logSessionEnded(TranscodingLogger::SessionEndedReason::RESUME_FAILED, err);
return err;
}
@@ -510,8 +539,23 @@
void TranscoderWrapper::cleanup() {
mCurrentClientId = 0;
mCurrentSessionId = -1;
+ mCurrentCallingUid = -1;
mTranscoderCb = nullptr;
mTranscoder = nullptr;
+ mSrcFormat = nullptr;
+ mDstFormat = nullptr;
+}
+
+void TranscoderWrapper::logSessionEnded(const TranscodingLogger::SessionEndedReason& reason,
+ int error) {
+ std::chrono::microseconds transcodeDuration(-1);
+ if (reason == TranscodingLogger::SessionEndedReason::FINISHED && error == AMEDIA_OK) {
+ transcodeDuration = std::chrono::duration_cast<std::chrono::microseconds>(
+ std::chrono::steady_clock::now() - mTranscodeStartTime);
+ }
+
+ mLogger->logSessionEnded(reason, mCurrentCallingUid, error, transcodeDuration, mSrcFormat.get(),
+ mDstFormat.get());
}
void TranscoderWrapper::queueEvent(Event::Type type, ClientIdType clientId, SessionIdType sessionId,
@@ -555,5 +599,4 @@
lock.lock();
}
}
-
} // namespace android
diff --git a/media/libmediatranscoding/TranscodingClientManager.cpp b/media/libmediatranscoding/TranscodingClientManager.cpp
index 76bb33e..06c5421 100644
--- a/media/libmediatranscoding/TranscodingClientManager.cpp
+++ b/media/libmediatranscoding/TranscodingClientManager.cpp
@@ -162,8 +162,8 @@
int32_t sessionId = mNextSessionId.fetch_add(1);
- *_aidl_return = owner->mSessionController->submit(mClientId, sessionId, in_clientUid,
- in_request, mClientCallback);
+ *_aidl_return = owner->mSessionController->submit(mClientId, sessionId, callingUid,
+ in_clientUid, in_request, mClientCallback);
if (*_aidl_return) {
out_session->sessionId = sessionId;
diff --git a/media/libmediatranscoding/TranscodingLogger.cpp b/media/libmediatranscoding/TranscodingLogger.cpp
new file mode 100644
index 0000000..29a52b0
--- /dev/null
+++ b/media/libmediatranscoding/TranscodingLogger.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "TranscodingLogger"
+
+#include <media/NdkCommon.h>
+#include <media/TranscodingLogger.h>
+#include <statslog_media.h>
+#include <utils/Log.h>
+
+#include <cmath>
+#include <string>
+
+namespace android {
+
+static_assert(TranscodingLogger::UNKNOWN ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__UNKNOWN,
+ "Session event mismatch");
+static_assert(TranscodingLogger::FINISHED ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__FINISHED,
+ "Session event mismatch");
+static_assert(TranscodingLogger::ERROR ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__ERROR,
+ "Session event mismatch");
+static_assert(TranscodingLogger::PAUSED ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__PAUSED,
+ "Session event mismatch");
+static_assert(TranscodingLogger::CANCELLED ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__CANCELLED,
+ "Session event mismatch");
+static_assert(TranscodingLogger::START_FAILED ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__START_FAILED,
+ "Session event mismatch");
+static_assert(TranscodingLogger::RESUME_FAILED ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__RESUME_FAILED,
+ "Session event mismatch");
+static_assert(TranscodingLogger::CREATE_FAILED ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__CREATE_FAILED,
+ "Session event mismatch");
+static_assert(
+ TranscodingLogger::CONFIG_SRC_FAILED ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__CONFIG_SRC_FAILED,
+ "Session event mismatch");
+static_assert(
+ TranscodingLogger::CONFIG_DST_FAILED ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__CONFIG_DST_FAILED,
+ "Session event mismatch");
+static_assert(
+ TranscodingLogger::CONFIG_TRACK_FAILED ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__CONFIG_TRACK_FAILED,
+ "Session event mismatch");
+static_assert(
+ TranscodingLogger::OPEN_SRC_FD_FAILED ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__OPEN_SRC_FD_FAILED,
+ "Session event mismatch");
+static_assert(
+ TranscodingLogger::OPEN_DST_FD_FAILED ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__OPEN_DST_FD_FAILED,
+ "Session event mismatch");
+static_assert(TranscodingLogger::NO_TRACKS ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__NO_TRACKS,
+ "Session event mismatch");
+
+static inline int32_t getInt32(AMediaFormat* fmt, const char* key, int32_t defaultValue = -1) {
+ int32_t value;
+ if (fmt == nullptr || !AMediaFormat_getInt32(fmt, key, &value)) {
+ ALOGW("Unable to get %s", key);
+ value = defaultValue;
+ }
+ return value;
+}
+
+// Note: returned string is owned by format and only valid until the next getString.
+static inline const char* getString(AMediaFormat* fmt, const char* key,
+ const char* defaultValue = "(null)") {
+ const char* value;
+ if (fmt == nullptr || !AMediaFormat_getString(fmt, key, &value)) {
+ ALOGW("Unable to get %s", key);
+ value = defaultValue;
+ }
+ return value;
+}
+
+TranscodingLogger::TranscodingLogger()
+ : mSessionEndedAtomWriter(&android::media::stats::stats_write) {}
+
+void TranscodingLogger::logSessionEnded(enum SessionEndedReason reason, uid_t callingUid,
+ int status, std::chrono::microseconds duration,
+ AMediaFormat* srcFormat, AMediaFormat* dstFormat) {
+ logSessionEnded(std::chrono::steady_clock::now(), reason, callingUid, status, duration,
+ srcFormat, dstFormat);
+}
+
+void TranscodingLogger::logSessionEnded(const std::chrono::steady_clock::time_point& now,
+ enum SessionEndedReason reason, uid_t callingUid,
+ int status, std::chrono::microseconds duration,
+ AMediaFormat* srcFormat, AMediaFormat* dstFormat) {
+ if (srcFormat == nullptr) {
+ ALOGE("Source format is null. Dropping event.");
+ return;
+ }
+
+ if (!shouldLogAtom(now, status)) {
+ ALOGD("Maximum logged event count reached. Dropping event.");
+ return;
+ }
+
+ // Extract the pieces of information to log.
+ const int32_t srcWidth = getInt32(srcFormat, AMEDIAFORMAT_KEY_WIDTH);
+ const int32_t srcHeight = getInt32(srcFormat, AMEDIAFORMAT_KEY_HEIGHT);
+ const char* srcMime = getString(srcFormat, AMEDIAFORMAT_KEY_MIME);
+ const int32_t srcProfile = getInt32(srcFormat, AMEDIAFORMAT_KEY_PROFILE);
+ const int32_t srcLevel = getInt32(srcFormat, AMEDIAFORMAT_KEY_LEVEL);
+ const int32_t srcFrameRate = getInt32(srcFormat, AMEDIAFORMAT_KEY_FRAME_RATE);
+ const int32_t srcFrameCount = getInt32(srcFormat, AMEDIAFORMAT_KEY_FRAME_COUNT);
+ const bool srcIsHdr = AMediaFormatUtils::VideoIsHdr(srcFormat);
+
+ int32_t dstWidth = getInt32(dstFormat, AMEDIAFORMAT_KEY_WIDTH, srcWidth);
+ int32_t dstHeight = getInt32(dstFormat, AMEDIAFORMAT_KEY_HEIGHT, srcHeight);
+ const char* dstMime = dstFormat == nullptr
+ ? "passthrough"
+ : getString(dstFormat, AMEDIAFORMAT_KEY_MIME, srcMime);
+ const bool dstIsHdr = false; // Transcoder always request SDR output.
+
+ int64_t tmpDurationUs;
+ const int32_t srcDurationMs =
+ AMediaFormat_getInt64(srcFormat, AMEDIAFORMAT_KEY_DURATION, &tmpDurationUs)
+ ? static_cast<int32_t>(tmpDurationUs / 1000)
+ : -1;
+
+ int32_t transcodeFrameRate = -1;
+ if (status == 0 && srcFrameCount > 0 && duration.count() > 0) {
+ std::chrono::duration<double> seconds{duration};
+ transcodeFrameRate = static_cast<int32_t>(
+ std::round(static_cast<double>(srcFrameCount) / seconds.count()));
+ }
+
+ // Write the atom.
+ mSessionEndedAtomWriter(android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED,
+ static_cast<int>(reason), callingUid, status, transcodeFrameRate,
+ srcWidth, srcHeight, srcMime, srcProfile, srcLevel, srcFrameRate,
+ srcDurationMs, srcIsHdr, dstWidth, dstHeight, dstMime, dstIsHdr);
+}
+
+bool TranscodingLogger::shouldLogAtom(const std::chrono::steady_clock::time_point& now,
+ int status) {
+ std::scoped_lock lock{mLock};
+ static const std::chrono::hours oneDay(24);
+
+ // Remove events older than one day.
+ while (mLastLoggedAtoms.size() > 0 && (now - mLastLoggedAtoms.front().first) >= oneDay) {
+ if (mLastLoggedAtoms.front().second == AMEDIA_OK) {
+ --mSuccessfulCount;
+ }
+ mLastLoggedAtoms.pop();
+ }
+
+ // Don't log if maximum number of events is reached.
+ if (mLastLoggedAtoms.size() >= kMaxAtomsPerDay) {
+ return false;
+ }
+
+ // Don't log if the event is successful and the maximum number of successful events is reached.
+ if (status == AMEDIA_OK && mSuccessfulCount >= kMaxSuccessfulAtomsPerDay) {
+ return false;
+ }
+
+ // Record the event.
+ if (status == AMEDIA_OK) {
+ ++mSuccessfulCount;
+ }
+ mLastLoggedAtoms.emplace(now, status);
+ return true;
+}
+
+void TranscodingLogger::setSessionEndedAtomWriter(const SessionEndedAtomWriter& writer) {
+ mSessionEndedAtomWriter = writer;
+}
+
+} // namespace android
diff --git a/media/libmediatranscoding/TranscodingSessionController.cpp b/media/libmediatranscoding/TranscodingSessionController.cpp
index d12af21..54357bd 100644
--- a/media/libmediatranscoding/TranscodingSessionController.cpp
+++ b/media/libmediatranscoding/TranscodingSessionController.cpp
@@ -372,10 +372,12 @@
if (shouldBeRunning) {
if (topSession->getState() == Session::NOT_STARTED) {
mTranscoder->start(topSession->key.first, topSession->key.second,
- topSession->request, topSession->callback.lock());
+ topSession->request, topSession->callingUid,
+ topSession->callback.lock());
} else if (topSession->getState() == Session::PAUSED) {
mTranscoder->resume(topSession->key.first, topSession->key.second,
- topSession->request, topSession->callback.lock());
+ topSession->request, topSession->callingUid,
+ topSession->callback.lock());
}
setSessionState_l(topSession, Session::RUNNING);
}
@@ -393,7 +395,7 @@
}
// Remove session from uid's queue.
- const uid_t uid = mSessionMap[sessionKey].uid;
+ const uid_t uid = mSessionMap[sessionKey].clientUid;
SessionQueueType& sessionQueue = mSessionQueues[uid];
auto it = std::find(sessionQueue.begin(), sessionQueue.end(), sessionKey);
if (it == sessionQueue.end()) {
@@ -482,13 +484,13 @@
}
bool TranscodingSessionController::submit(
- ClientIdType clientId, SessionIdType sessionId, uid_t uid,
+ ClientIdType clientId, SessionIdType sessionId, uid_t callingUid, uid_t clientUid,
const TranscodingRequestParcel& request,
const std::weak_ptr<ITranscodingClientCallback>& callback) {
SessionKeyType sessionKey = std::make_pair(clientId, sessionId);
ALOGV("%s: session %s, uid %d, prioirty %d", __FUNCTION__, sessionToString(sessionKey).c_str(),
- uid, (int32_t)request.priority);
+ clientUid, (int32_t)request.priority);
std::scoped_lock lock{mLock};
@@ -498,19 +500,20 @@
}
// Add the uid package name to the store of package names we already know.
- if (mUidPackageNames.count(uid) == 0) {
- mUidPackageNames.emplace(uid, request.clientPackageName);
+ if (mUidPackageNames.count(clientUid) == 0) {
+ mUidPackageNames.emplace(clientUid, request.clientPackageName);
}
// TODO(chz): only support offline vs real-time for now. All kUnspecified sessions
// go to offline queue.
if (request.priority == TranscodingSessionPriority::kUnspecified) {
- uid = OFFLINE_UID;
+ clientUid = OFFLINE_UID;
}
// Add session to session map.
mSessionMap[sessionKey].key = sessionKey;
- mSessionMap[sessionKey].uid = uid;
+ mSessionMap[sessionKey].clientUid = clientUid;
+ mSessionMap[sessionKey].callingUid = callingUid;
mSessionMap[sessionKey].lastProgress = 0;
mSessionMap[sessionKey].pauseCount = 0;
mSessionMap[sessionKey].request = request;
@@ -520,25 +523,25 @@
// If it's an offline session, the queue was already added in constructor.
// If it's a real-time sessions, check if a queue is already present for the uid,
// and add a new queue if needed.
- if (uid != OFFLINE_UID) {
- if (mSessionQueues.count(uid) == 0) {
- mUidPolicy->registerMonitorUid(uid);
- if (mUidPolicy->isUidOnTop(uid)) {
- mUidSortedList.push_front(uid);
+ if (clientUid != OFFLINE_UID) {
+ if (mSessionQueues.count(clientUid) == 0) {
+ mUidPolicy->registerMonitorUid(clientUid);
+ if (mUidPolicy->isUidOnTop(clientUid)) {
+ mUidSortedList.push_front(clientUid);
} else {
// Shouldn't be submitting real-time requests from non-top app,
// put it in front of the offline queue.
- mUidSortedList.insert(mOfflineUidIterator, uid);
+ mUidSortedList.insert(mOfflineUidIterator, clientUid);
}
- } else if (uid != *mUidSortedList.begin()) {
- if (mUidPolicy->isUidOnTop(uid)) {
- mUidSortedList.remove(uid);
- mUidSortedList.push_front(uid);
+ } else if (clientUid != *mUidSortedList.begin()) {
+ if (mUidPolicy->isUidOnTop(clientUid)) {
+ mUidSortedList.remove(clientUid);
+ mUidSortedList.push_front(clientUid);
}
}
}
// Append this session to the uid's queue.
- mSessionQueues[uid].push_back(sessionKey);
+ mSessionQueues[clientUid].push_back(sessionKey);
updateCurrentSession_l();
@@ -557,7 +560,7 @@
if (sessionId < 0) {
for (auto it = mSessionMap.begin(); it != mSessionMap.end(); ++it) {
- if (it->first.first == clientId && it->second.uid != OFFLINE_UID) {
+ if (it->first.first == clientId && it->second.clientUid != OFFLINE_UID) {
sessionsToRemove.push_back(it->first);
}
}
diff --git a/media/libmediatranscoding/include/media/ControllerClientInterface.h b/media/libmediatranscoding/include/media/ControllerClientInterface.h
index 3fd4f0c..0d13607 100644
--- a/media/libmediatranscoding/include/media/ControllerClientInterface.h
+++ b/media/libmediatranscoding/include/media/ControllerClientInterface.h
@@ -36,8 +36,8 @@
* Returns true on success and false on failure. This call will fail is a session identified
* by <clientId, sessionId> already exists.
*/
- virtual bool submit(ClientIdType clientId, SessionIdType sessionId, uid_t uid,
- const TranscodingRequestParcel& request,
+ virtual bool submit(ClientIdType clientId, SessionIdType sessionId, uid_t callingUid,
+ uid_t clientUid, const TranscodingRequestParcel& request,
const std::weak_ptr<ITranscodingClientCallback>& clientCallback) = 0;
/**
diff --git a/media/libmediatranscoding/include/media/TranscoderInterface.h b/media/libmediatranscoding/include/media/TranscoderInterface.h
index 5f27d82..3b0bd3b 100644
--- a/media/libmediatranscoding/include/media/TranscoderInterface.h
+++ b/media/libmediatranscoding/include/media/TranscoderInterface.h
@@ -33,11 +33,11 @@
class TranscoderInterface {
public:
virtual void start(ClientIdType clientId, SessionIdType sessionId,
- const TranscodingRequestParcel& request,
+ const TranscodingRequestParcel& request, uid_t callingUid,
const std::shared_ptr<ITranscodingClientCallback>& clientCallback) = 0;
virtual void pause(ClientIdType clientId, SessionIdType sessionId) = 0;
virtual void resume(ClientIdType clientId, SessionIdType sessionId,
- const TranscodingRequestParcel& request,
+ const TranscodingRequestParcel& request, uid_t callingUid,
const std::shared_ptr<ITranscodingClientCallback>& clientCallback) = 0;
// Stop the specified session. If abandon is true, the transcoder wrapper will be discarded
// after the session stops.
diff --git a/media/libmediatranscoding/include/media/TranscoderWrapper.h b/media/libmediatranscoding/include/media/TranscoderWrapper.h
index 7935bbe..d3d4c86 100644
--- a/media/libmediatranscoding/include/media/TranscoderWrapper.h
+++ b/media/libmediatranscoding/include/media/TranscoderWrapper.h
@@ -18,8 +18,11 @@
#define ANDROID_TRANSCODER_WRAPPER_H
#include <media/NdkMediaError.h>
+#include <media/NdkMediaFormat.h>
#include <media/TranscoderInterface.h>
+#include <media/TranscodingLogger.h>
+#include <chrono>
#include <list>
#include <map>
#include <mutex>
@@ -37,16 +40,17 @@
public std::enable_shared_from_this<TranscoderWrapper> {
public:
TranscoderWrapper(const std::shared_ptr<TranscoderCallbackInterface>& cb,
+ const std::shared_ptr<TranscodingLogger>& logger,
int64_t heartBeatIntervalUs);
~TranscoderWrapper();
// TranscoderInterface
void start(ClientIdType clientId, SessionIdType sessionId,
- const TranscodingRequestParcel& request,
+ const TranscodingRequestParcel& request, uid_t callingUid,
const std::shared_ptr<ITranscodingClientCallback>& clientCallback) override;
void pause(ClientIdType clientId, SessionIdType sessionId) override;
void resume(ClientIdType clientId, SessionIdType sessionId,
- const TranscodingRequestParcel& request,
+ const TranscodingRequestParcel& request, uid_t callingUid,
const std::shared_ptr<ITranscodingClientCallback>& clientCallback) override;
void stop(ClientIdType clientId, SessionIdType sessionId, bool abandon = false) override;
// ~TranscoderInterface
@@ -76,6 +80,9 @@
std::shared_ptr<CallbackImpl> mTranscoderCb;
std::shared_ptr<MediaTranscoder> mTranscoder;
std::weak_ptr<TranscoderCallbackInterface> mCallback;
+ std::shared_ptr<TranscodingLogger> mLogger;
+ std::shared_ptr<AMediaFormat> mSrcFormat;
+ std::shared_ptr<AMediaFormat> mDstFormat;
int64_t mHeartBeatIntervalUs;
std::mutex mLock;
std::condition_variable mCondition;
@@ -83,6 +90,9 @@
std::map<SessionKeyType, std::shared_ptr<ndk::ScopedAParcel>> mPausedStateMap;
ClientIdType mCurrentClientId;
SessionIdType mCurrentSessionId;
+ uid_t mCurrentCallingUid;
+ std::chrono::steady_clock::time_point mTranscodeStartTime;
+
// Whether the looper has been created.
bool mLooperReady;
@@ -93,18 +103,20 @@
void onHeartBeat(ClientIdType clientId, SessionIdType sessionId);
media_status_t handleStart(ClientIdType clientId, SessionIdType sessionId,
- const TranscodingRequestParcel& request,
+ const TranscodingRequestParcel& request, uid_t callingUid,
const std::shared_ptr<ITranscodingClientCallback>& callback);
media_status_t handlePause(ClientIdType clientId, SessionIdType sessionId);
media_status_t handleResume(ClientIdType clientId, SessionIdType sessionId,
- const TranscodingRequestParcel& request,
+ const TranscodingRequestParcel& request, uid_t callingUid,
const std::shared_ptr<ITranscodingClientCallback>& callback);
media_status_t setupTranscoder(
ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
- const std::shared_ptr<ITranscodingClientCallback>& callback,
+ uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& callback,
+ TranscodingLogger::SessionEndedReason* failureReason /* nonnull */,
const std::shared_ptr<ndk::ScopedAParcel>& pausedState = nullptr);
void cleanup();
+ void logSessionEnded(const TranscodingLogger::SessionEndedReason& reason, int error);
void reportError(ClientIdType clientId, SessionIdType sessionId, media_status_t err);
void queueEvent(Event::Type type, ClientIdType clientId, SessionIdType sessionId,
const std::function<void()> runnable, int32_t arg = 0);
diff --git a/media/libmediatranscoding/include/media/TranscodingLogger.h b/media/libmediatranscoding/include/media/TranscodingLogger.h
new file mode 100644
index 0000000..dc24551
--- /dev/null
+++ b/media/libmediatranscoding/include/media/TranscodingLogger.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_TRANSCODING_LOGGER_H
+#define ANDROID_MEDIA_TRANSCODING_LOGGER_H
+
+#include <media/NdkMediaFormat.h>
+#include <utils/Condition.h>
+
+#include <chrono>
+#include <memory>
+#include <mutex>
+#include <queue>
+
+namespace android {
+
+/** Class for logging transcoding events. */
+class TranscodingLogger {
+public:
+ /** The maximum number of atoms pushed to statsd per day. */
+ static constexpr int kMaxAtomsPerDay = 50;
+
+ /** The maximum number of successful transcoding atoms pushed to statsd per day. */
+ static constexpr int kMaxSuccessfulAtomsPerDay = 35;
+
+ /** Reason transcoding session ended. Maps to MediaTranscodingSessionEnded atom's Reason. */
+ enum SessionEndedReason {
+ UNKNOWN = 0,
+ FINISHED,
+ ERROR,
+ PAUSED,
+ CANCELLED,
+ START_FAILED,
+ RESUME_FAILED,
+ CREATE_FAILED,
+ CONFIG_SRC_FAILED,
+ CONFIG_DST_FAILED,
+ CONFIG_TRACK_FAILED,
+ OPEN_SRC_FD_FAILED,
+ OPEN_DST_FD_FAILED,
+ NO_TRACKS,
+ };
+
+ TranscodingLogger();
+ ~TranscodingLogger() = default;
+
+ /**
+ * Logs a transcoding session ended event (MediaTranscodingSessionEnded atom).
+ * @param reason Reason for the transcoding session to end.
+ * @param callingUid UID of the caller connecting to the transcoding service.
+ * @param status Status (error code) of the transcoding session.
+ * @param duration Duration of the transcoding session.
+ * @param srcFormat The source video track format.
+ * @param dstFormat The destination video track format.
+ */
+ void logSessionEnded(enum SessionEndedReason reason, uid_t callingUid, int status,
+ std::chrono::microseconds duration, AMediaFormat* srcFormat,
+ AMediaFormat* dstFormat);
+
+private:
+ friend class TranscodingLoggerTest;
+
+ // Function prototype for writing out the session ended atom.
+ using SessionEndedAtomWriter = std::function<int(
+ int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, char const*, int32_t,
+ int32_t, int32_t, int32_t, bool arg12, int32_t, int32_t, char const*, bool)>;
+
+ std::mutex mLock;
+ std::queue<std::pair<std::chrono::steady_clock::time_point, int>> mLastLoggedAtoms
+ GUARDED_BY(mLock);
+ uint32_t mSuccessfulCount = 0;
+ SessionEndedAtomWriter mSessionEndedAtomWriter;
+
+ void logSessionEnded(const std::chrono::steady_clock::time_point& now,
+ enum SessionEndedReason reason, uid_t callingUid, int status,
+ std::chrono::microseconds duration, AMediaFormat* srcFormat,
+ AMediaFormat* dstFormat);
+ bool shouldLogAtom(const std::chrono::steady_clock::time_point& now, int status);
+ // Used for testing to validate what gets sent to statsd.
+ void setSessionEndedAtomWriter(const SessionEndedAtomWriter& writer);
+};
+
+} // namespace android
+#endif // ANDROID_MEDIA_TRANSCODING_LOGGER_H
diff --git a/media/libmediatranscoding/include/media/TranscodingSessionController.h b/media/libmediatranscoding/include/media/TranscodingSessionController.h
index 34e9506..cfa2f13 100644
--- a/media/libmediatranscoding/include/media/TranscodingSessionController.h
+++ b/media/libmediatranscoding/include/media/TranscodingSessionController.h
@@ -48,7 +48,7 @@
virtual ~TranscodingSessionController();
// ControllerClientInterface
- bool submit(ClientIdType clientId, SessionIdType sessionId, uid_t uid,
+ bool submit(ClientIdType clientId, SessionIdType sessionId, uid_t callingUid, uid_t clientUid,
const TranscodingRequestParcel& request,
const std::weak_ptr<ITranscodingClientCallback>& clientCallback) override;
bool cancel(ClientIdType clientId, SessionIdType sessionId) override;
@@ -108,7 +108,8 @@
ERROR,
};
SessionKeyType key;
- uid_t uid;
+ uid_t clientUid;
+ uid_t callingUid;
int32_t lastProgress;
int32_t pauseCount;
std::chrono::time_point<std::chrono::system_clock> stateEnterTime;
diff --git a/media/libmediatranscoding/tests/Android.bp b/media/libmediatranscoding/tests/Android.bp
index 06b9b17..603611a 100644
--- a/media/libmediatranscoding/tests/Android.bp
+++ b/media/libmediatranscoding/tests/Android.bp
@@ -72,3 +72,15 @@
srcs: ["AdjustableMaxPriorityQueue_tests.cpp"],
}
+
+//
+// TranscodingLogger unit test
+//
+cc_test {
+ name: "TranscodingLogger_tests",
+ defaults: ["libmediatranscoding_test_defaults"],
+ shared_libs: ["libmediandk", "libstatssocket#30"],
+ static_libs: ["libmediatranscoder", "libstatslog_media"],
+
+ srcs: ["TranscodingLogger_tests.cpp"],
+}
diff --git a/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp b/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp
index 1a50923..57a2e27 100644
--- a/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp
+++ b/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp
@@ -135,7 +135,7 @@
virtual ~TestController() { ALOGI("TestController Destroyed"); }
- bool submit(ClientIdType clientId, SessionIdType sessionId, uid_t /*uid*/,
+ bool submit(ClientIdType clientId, SessionIdType sessionId, uid_t /*callingUid*/, uid_t /*uid*/,
const TranscodingRequestParcel& request,
const std::weak_ptr<ITranscodingClientCallback>& clientCallback) override {
SessionKeyType sessionKey = std::make_pair(clientId, sessionId);
diff --git a/media/libmediatranscoding/tests/TranscodingLogger_tests.cpp b/media/libmediatranscoding/tests/TranscodingLogger_tests.cpp
new file mode 100644
index 0000000..39e5cd4
--- /dev/null
+++ b/media/libmediatranscoding/tests/TranscodingLogger_tests.cpp
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Unit Test for TranscodingLogger
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "TranscodingLoggerTest"
+
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <media/NdkCommon.h>
+#include <media/TranscodingLogger.h>
+#include <statslog_media.h>
+#include <utils/Log.h>
+
+#include <chrono>
+
+namespace android {
+
+using Reason = TranscodingLogger::SessionEndedReason;
+
+// Data structure corresponding to MediaTranscodingEnded atom.
+struct SessionEndedAtom {
+ SessionEndedAtom(int32_t atomCode, int32_t reason, int32_t callingUid, int32_t status,
+ int32_t transcoderFps, int32_t srcWidth, int32_t srcHeight,
+ char const* srcMime, int32_t srcProfile, int32_t srcLevel, int32_t srcFps,
+ int32_t srcDurationMs, bool srcIsHdr, int32_t dstWidth, int32_t dstHeight,
+ char const* dstMime, bool dstIsHdr)
+ : atomCode(atomCode),
+ reason(reason),
+ callingUid(callingUid),
+ status(status),
+ transcoderFps(transcoderFps),
+ srcWidth(srcWidth),
+ srcHeight(srcHeight),
+ srcMime(srcMime),
+ srcProfile(srcProfile),
+ srcLevel(srcLevel),
+ srcFps(srcFps),
+ srcDurationMs(srcDurationMs),
+ srcIsHdr(srcIsHdr),
+ dstWidth(dstWidth),
+ dstHeight(dstHeight),
+ dstMime(dstMime),
+ dstIsHdr(dstIsHdr) {}
+
+ int32_t atomCode;
+ int32_t reason;
+ int32_t callingUid;
+ int32_t status;
+ int32_t transcoderFps;
+ int32_t srcWidth;
+ int32_t srcHeight;
+ std::string srcMime;
+ int32_t srcProfile;
+ int32_t srcLevel;
+ int32_t srcFps;
+ int32_t srcDurationMs;
+ bool srcIsHdr;
+ int32_t dstWidth;
+ int32_t dstHeight;
+ std::string dstMime;
+ bool dstIsHdr;
+};
+
+// Default configuration values.
+static constexpr int32_t kDefaultCallingUid = 1;
+static constexpr std::chrono::microseconds kDefaultTranscodeDuration = std::chrono::seconds{2};
+
+static constexpr int32_t kDefaultSrcWidth = 1920;
+static constexpr int32_t kDefaultSrcHeight = 1080;
+static const std::string kDefaultSrcMime{AMEDIA_MIMETYPE_VIDEO_HEVC};
+static constexpr int32_t kDefaultSrcProfile = 1; // HEVC Main
+static constexpr int32_t kDefaultSrcLevel = 65536; // HEVCMainTierLevel51
+static constexpr int32_t kDefaultSrcFps = 30;
+static constexpr int32_t kDefaultSrcFrameCount = 120;
+static constexpr int64_t kDefaultSrcDurationUs = 1000000 * kDefaultSrcFrameCount / kDefaultSrcFps;
+
+static constexpr int32_t kDefaultDstWidth = 1280;
+static constexpr int32_t kDefaultDstHeight = 720;
+static const std::string kDefaultDstMime{AMEDIA_MIMETYPE_VIDEO_AVC};
+
+// Util for creating a default source video format.
+static AMediaFormat* CreateSrcFormat() {
+ AMediaFormat* fmt = AMediaFormat_new();
+ AMediaFormat_setInt32(fmt, AMEDIAFORMAT_KEY_WIDTH, kDefaultSrcWidth);
+ AMediaFormat_setInt32(fmt, AMEDIAFORMAT_KEY_HEIGHT, kDefaultSrcHeight);
+ AMediaFormat_setString(fmt, AMEDIAFORMAT_KEY_MIME, kDefaultSrcMime.c_str());
+ AMediaFormat_setInt32(fmt, AMEDIAFORMAT_KEY_PROFILE, kDefaultSrcProfile);
+ AMediaFormat_setInt32(fmt, AMEDIAFORMAT_KEY_LEVEL, kDefaultSrcLevel);
+ AMediaFormat_setInt32(fmt, AMEDIAFORMAT_KEY_FRAME_RATE, kDefaultSrcFps);
+ AMediaFormat_setInt32(fmt, AMEDIAFORMAT_KEY_FRAME_COUNT, kDefaultSrcFrameCount);
+ AMediaFormat_setInt64(fmt, AMEDIAFORMAT_KEY_DURATION, kDefaultSrcDurationUs);
+ return fmt;
+}
+
+// Util for creating a default destination video format.
+static AMediaFormat* CreateDstFormat() {
+ AMediaFormat* fmt = AMediaFormat_new();
+ AMediaFormat_setInt32(fmt, AMEDIAFORMAT_KEY_WIDTH, kDefaultDstWidth);
+ AMediaFormat_setInt32(fmt, AMEDIAFORMAT_KEY_HEIGHT, kDefaultDstHeight);
+ AMediaFormat_setString(fmt, AMEDIAFORMAT_KEY_MIME, kDefaultDstMime.c_str());
+ return fmt;
+}
+
+class TranscodingLoggerTest : public ::testing::Test {
+public:
+ TranscodingLoggerTest() { ALOGI("TranscodingLoggerTest created"); }
+
+ void SetUp() override {
+ ALOGI("TranscodingLoggerTest set up");
+ mLogger.reset(new TranscodingLogger());
+ mLoggedAtoms.clear();
+ mSrcFormat.reset();
+ mDstFormat.reset();
+
+ // Set a custom atom writer that saves all data, so the test can validate it afterwards.
+ mLogger->setSessionEndedAtomWriter(
+ [=](int32_t atomCode, int32_t reason, int32_t callingUid, int32_t status,
+ int32_t transcoderFps, int32_t srcWidth, int32_t srcHeight, char const* srcMime,
+ int32_t srcProfile, int32_t srcLevel, int32_t srcFps, int32_t srcDurationMs,
+ bool srcIsHdr, int32_t dstWidth, int32_t dstHeight, char const* dstMime,
+ bool dstIsHdr) -> int {
+ mLoggedAtoms.emplace_back(atomCode, reason, callingUid, status, transcoderFps,
+ srcWidth, srcHeight, srcMime, srcProfile, srcLevel,
+ srcFps, srcDurationMs, srcIsHdr, dstWidth, dstHeight,
+ dstMime, dstIsHdr);
+ return 0;
+ });
+ }
+
+ void logSession(const std::chrono::steady_clock::time_point& time, Reason reason, int status,
+ AMediaFormat* srcFormat, AMediaFormat* dstFormat) {
+ mLogger->logSessionEnded(time, reason, kDefaultCallingUid, status,
+ kDefaultTranscodeDuration, srcFormat, dstFormat);
+ }
+
+ void logSession(const std::chrono::steady_clock::time_point& time, Reason reason, int status) {
+ if (!mSrcFormat) {
+ mSrcFormat = std::shared_ptr<AMediaFormat>(CreateSrcFormat(), &AMediaFormat_delete);
+ }
+ if (!mDstFormat) {
+ mDstFormat = std::shared_ptr<AMediaFormat>(CreateDstFormat(), &AMediaFormat_delete);
+ }
+ logSession(time, reason, status, mSrcFormat.get(), mDstFormat.get());
+ }
+
+ void logSessionFinished(const std::chrono::steady_clock::time_point& time) {
+ logSession(time, Reason::FINISHED, 0);
+ }
+
+ void logSessionFailed(const std::chrono::steady_clock::time_point& time) {
+ logSession(time, Reason::ERROR, AMEDIA_ERROR_UNKNOWN);
+ }
+
+ int logCount() const { return mLoggedAtoms.size(); }
+
+ void validateLatestAtom(Reason reason, int status, bool passthrough = false) {
+ const SessionEndedAtom& atom = mLoggedAtoms.back();
+
+ EXPECT_EQ(atom.atomCode, android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED);
+ EXPECT_EQ(atom.reason, static_cast<int>(reason));
+ EXPECT_EQ(atom.callingUid, kDefaultCallingUid);
+ EXPECT_EQ(atom.status, status);
+ EXPECT_EQ(atom.srcWidth, kDefaultSrcWidth);
+ EXPECT_EQ(atom.srcHeight, kDefaultSrcHeight);
+ EXPECT_EQ(atom.srcMime, kDefaultSrcMime);
+ EXPECT_EQ(atom.srcProfile, kDefaultSrcProfile);
+ EXPECT_EQ(atom.srcLevel, kDefaultSrcLevel);
+ EXPECT_EQ(atom.srcFps, kDefaultSrcFps);
+ EXPECT_EQ(atom.srcDurationMs, kDefaultSrcDurationUs / 1000);
+ EXPECT_FALSE(atom.srcIsHdr);
+ EXPECT_EQ(atom.dstWidth, passthrough ? kDefaultSrcWidth : kDefaultDstWidth);
+ EXPECT_EQ(atom.dstHeight, passthrough ? kDefaultSrcHeight : kDefaultDstHeight);
+ EXPECT_EQ(atom.dstMime, passthrough ? "passthrough" : kDefaultDstMime);
+ EXPECT_FALSE(atom.dstIsHdr);
+
+ // Transcoder frame rate is only present on successful sessions.
+ if (status == AMEDIA_OK) {
+ std::chrono::duration<double> seconds{kDefaultTranscodeDuration};
+ const int32_t transcoderFps =
+ static_cast<int32_t>(kDefaultSrcFrameCount / seconds.count());
+ EXPECT_EQ(atom.transcoderFps, transcoderFps);
+ } else {
+ EXPECT_EQ(atom.transcoderFps, -1);
+ }
+ }
+
+ void TearDown() override { ALOGI("TranscodingLoggerTest tear down"); }
+ ~TranscodingLoggerTest() { ALOGD("TranscodingLoggerTest destroyed"); }
+
+ std::shared_ptr<TranscodingLogger> mLogger;
+ std::vector<SessionEndedAtom> mLoggedAtoms;
+
+ std::shared_ptr<AMediaFormat> mSrcFormat;
+ std::shared_ptr<AMediaFormat> mDstFormat;
+};
+
+TEST_F(TranscodingLoggerTest, TestDailyLogQuota) {
+ ALOGD("TestDailyLogQuota");
+ auto start = std::chrono::steady_clock::now();
+
+ EXPECT_LT(TranscodingLogger::kMaxSuccessfulAtomsPerDay, TranscodingLogger::kMaxAtomsPerDay);
+
+ // 1. Check that the first kMaxSuccessfulAtomsPerDay successful atoms are logged.
+ for (int i = 0; i < TranscodingLogger::kMaxSuccessfulAtomsPerDay; ++i) {
+ logSessionFinished(start + std::chrono::seconds{i});
+ EXPECT_EQ(logCount(), i + 1);
+ }
+
+ // 2. Check that subsequent successful atoms within the same 24h interval are not logged.
+ for (int i = 1; i < 24; ++i) {
+ logSessionFinished(start + std::chrono::hours{i});
+ EXPECT_EQ(logCount(), TranscodingLogger::kMaxSuccessfulAtomsPerDay);
+ }
+
+ // 3. Check that failed atoms are logged up to kMaxAtomsPerDay.
+ for (int i = TranscodingLogger::kMaxSuccessfulAtomsPerDay;
+ i < TranscodingLogger::kMaxAtomsPerDay; ++i) {
+ logSessionFailed(start + std::chrono::seconds{i});
+ EXPECT_EQ(logCount(), i + 1);
+ }
+
+ // 4. Check that subsequent failed atoms within the same 24h interval are not logged.
+ for (int i = 1; i < 24; ++i) {
+ logSessionFailed(start + std::chrono::hours{i});
+ EXPECT_EQ(logCount(), TranscodingLogger::kMaxAtomsPerDay);
+ }
+
+ // 5. Check that failed and successful atoms are logged again after 24h.
+ logSessionFinished(start + std::chrono::hours{24});
+ EXPECT_EQ(logCount(), TranscodingLogger::kMaxAtomsPerDay + 1);
+
+ logSessionFailed(start + std::chrono::hours{24} + std::chrono::seconds{1});
+ EXPECT_EQ(logCount(), TranscodingLogger::kMaxAtomsPerDay + 2);
+}
+
+TEST_F(TranscodingLoggerTest, TestNullFormats) {
+ ALOGD("TestNullFormats");
+ auto srcFormat = std::shared_ptr<AMediaFormat>(CreateSrcFormat(), &AMediaFormat_delete);
+ auto dstFormat = std::shared_ptr<AMediaFormat>(CreateDstFormat(), &AMediaFormat_delete);
+ auto now = std::chrono::steady_clock::now();
+
+ // Source format null, should not log.
+ logSession(now, Reason::FINISHED, AMEDIA_OK, nullptr /*srcFormat*/, dstFormat.get());
+ EXPECT_EQ(logCount(), 0);
+
+ // Both formats null, should not log.
+ logSession(now, Reason::FINISHED, AMEDIA_OK, nullptr /*srcFormat*/, nullptr /*dstFormat*/);
+ EXPECT_EQ(logCount(), 0);
+
+ // Destination format null (passthrough mode), should log.
+ logSession(now, Reason::FINISHED, AMEDIA_OK, srcFormat.get(), nullptr /*dstFormat*/);
+ EXPECT_EQ(logCount(), 1);
+ validateLatestAtom(Reason::FINISHED, AMEDIA_OK, true /*passthrough*/);
+}
+
+TEST_F(TranscodingLoggerTest, TestAtomContentCorrectness) {
+ ALOGD("TestAtomContentCorrectness");
+ auto now = std::chrono::steady_clock::now();
+
+ // Log and validate a failure.
+ logSession(now, Reason::ERROR, AMEDIA_ERROR_MALFORMED);
+ EXPECT_EQ(logCount(), 1);
+ validateLatestAtom(Reason::ERROR, AMEDIA_ERROR_MALFORMED);
+
+ // Log and validate a success.
+ logSession(now, Reason::FINISHED, AMEDIA_OK);
+ EXPECT_EQ(logCount(), 2);
+ validateLatestAtom(Reason::FINISHED, AMEDIA_OK);
+}
+
+} // namespace android
diff --git a/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp b/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
index 2e9daee..3cd9112 100644
--- a/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
+++ b/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
@@ -123,7 +123,7 @@
// TranscoderInterface
void start(ClientIdType clientId, SessionIdType sessionId,
- const TranscodingRequestParcel& /*request*/,
+ const TranscodingRequestParcel& /*request*/, uid_t /*callingUid*/,
const std::shared_ptr<ITranscodingClientCallback>& /*clientCallback*/) override {
append(Start(clientId, sessionId));
}
@@ -131,7 +131,7 @@
append(Pause(clientId, sessionId));
}
void resume(ClientIdType clientId, SessionIdType sessionId,
- const TranscodingRequestParcel& /*request*/,
+ const TranscodingRequestParcel& /*request*/, uid_t /*callingUid*/,
const std::shared_ptr<ITranscodingClientCallback>& /*clientCallback*/) override {
append(Resume(clientId, sessionId));
}
@@ -349,32 +349,32 @@
// Submit offline session to CLIENT(0) in UID(0).
// Should start immediately (because this is the only session).
- mController->submit(CLIENT(0), SESSION(0), UID(0), mOfflineRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(0), UID(0), UID(0), mOfflineRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), 0));
// Submit real-time session to CLIENT(0).
// Should pause offline session and start new session, even if UID(0) is not on top.
- mController->submit(CLIENT(0), SESSION(1), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(1), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(1)));
// Submit real-time session to CLIENT(0), should be queued after the previous session.
- mController->submit(CLIENT(0), SESSION(2), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(2), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Submit real-time session to CLIENT(1) in same uid, should be queued after the previous
// session.
- mController->submit(CLIENT(1), SESSION(0), UID(0), mRealtimeRequest, mClientCallback1);
+ mController->submit(CLIENT(1), SESSION(0), UID(1), UID(0), mRealtimeRequest, mClientCallback1);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Submit real-time session to CLIENT(2) in UID(1).
// Should pause previous session and start new session, because UID(1) is (has been) top.
- mController->submit(CLIENT(2), SESSION(0), UID(1), mRealtimeRequest, mClientCallback2);
+ mController->submit(CLIENT(2), SESSION(0), UID(2), UID(1), mRealtimeRequest, mClientCallback2);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(1)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), SESSION(0)));
// Submit offline session, shouldn't generate any event.
- mController->submit(CLIENT(2), SESSION(1), UID(1), mOfflineRequest, mClientCallback2);
+ mController->submit(CLIENT(2), SESSION(1), UID(2), UID(1), mOfflineRequest, mClientCallback2);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Bring UID(0) to top.
@@ -388,15 +388,15 @@
ALOGD("TestCancelSession");
// Submit real-time session SESSION(0), should start immediately.
- mController->submit(CLIENT(0), SESSION(0), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(0), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
// Submit real-time session SESSION(1), should not start.
- mController->submit(CLIENT(0), SESSION(1), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(1), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Submit offline session SESSION(2), should not start.
- mController->submit(CLIENT(0), SESSION(2), UID(0), mOfflineRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(2), UID(0), UID(0), mOfflineRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Cancel queued real-time session.
@@ -408,7 +408,7 @@
EXPECT_TRUE(mController->cancel(CLIENT(0), SESSION(2)));
// Submit offline session SESSION(3), shouldn't cause any event.
- mController->submit(CLIENT(0), SESSION(3), UID(0), mOfflineRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(3), UID(0), UID(0), mOfflineRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Cancel running real-time session SESSION(0).
@@ -420,7 +420,7 @@
// Submit real-time session SESSION(4), offline SESSION(3) should pause and SESSION(4)
// should start.
- mController->submit(CLIENT(0), SESSION(4), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(4), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(3)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(4)));
@@ -438,16 +438,16 @@
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Submit offline session SESSION(0), should start immediately.
- mController->submit(CLIENT(0), SESSION(0), UID(0), mOfflineRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(0), UID(0), UID(0), mOfflineRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
// Submit real-time session SESSION(1), should pause offline session and start immediately.
- mController->submit(CLIENT(0), SESSION(1), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(1), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(1)));
// Submit real-time session SESSION(2), should not start.
- mController->submit(CLIENT(0), SESSION(2), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(2), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Finish when the session never started, should be ignored.
@@ -458,7 +458,7 @@
mUidPolicy->setTop(UID(1));
// Submit real-time session to CLIENT(1) in UID(1), should pause previous session and start
// new session.
- mController->submit(CLIENT(1), SESSION(0), UID(1), mRealtimeRequest, mClientCallback1);
+ mController->submit(CLIENT(1), SESSION(0), UID(1), UID(1), mRealtimeRequest, mClientCallback1);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(1)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), SESSION(0)));
@@ -495,16 +495,16 @@
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Submit offline session SESSION(0), should start immediately.
- mController->submit(CLIENT(0), SESSION(0), UID(0), mOfflineRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(0), UID(0), UID(0), mOfflineRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
// Submit real-time session SESSION(1), should pause offline session and start immediately.
- mController->submit(CLIENT(0), SESSION(1), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(1), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(1)));
// Submit real-time session SESSION(2), should not start.
- mController->submit(CLIENT(0), SESSION(2), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(2), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Fail when the session never started, should be ignored.
@@ -515,7 +515,7 @@
mUidPolicy->setTop(UID(1));
// Submit real-time session to CLIENT(1) in UID(1), should pause previous session and start
// new session.
- mController->submit(CLIENT(1), SESSION(0), UID(1), mRealtimeRequest, mClientCallback1);
+ mController->submit(CLIENT(1), SESSION(0), UID(1), UID(1), mRealtimeRequest, mClientCallback1);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(1)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), SESSION(0)));
@@ -549,11 +549,11 @@
// Start with unspecified top UID.
// Submit real-time session to CLIENT(0), session should start immediately.
- mController->submit(CLIENT(0), SESSION(0), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(0), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
// Submit offline session to CLIENT(0), should not start.
- mController->submit(CLIENT(1), SESSION(0), UID(0), mOfflineRequest, mClientCallback1);
+ mController->submit(CLIENT(1), SESSION(0), UID(1), UID(0), mOfflineRequest, mClientCallback1);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Move UID(1) to top.
@@ -562,7 +562,7 @@
// Submit real-time session to CLIENT(2) in different uid UID(1).
// Should pause previous session and start new session.
- mController->submit(CLIENT(2), SESSION(0), UID(1), mRealtimeRequest, mClientCallback2);
+ mController->submit(CLIENT(2), SESSION(0), UID(2), UID(1), mRealtimeRequest, mClientCallback2);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), SESSION(0)));
@@ -591,11 +591,11 @@
// Start with unspecified top UID.
// Submit real-time session to CLIENT(0), session should start immediately.
- mController->submit(CLIENT(0), SESSION(0), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(0), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
// Submit offline session to CLIENT(0), should not start.
- mController->submit(CLIENT(1), SESSION(0), UID(0), mOfflineRequest, mClientCallback1);
+ mController->submit(CLIENT(1), SESSION(0), UID(1), UID(0), mOfflineRequest, mClientCallback1);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Set UID(0), UID(1) to top set.
@@ -605,7 +605,7 @@
// Submit real-time session to CLIENT(2) in different uid UID(1).
// UID(0) should pause and UID(1) should start.
- mController->submit(CLIENT(2), SESSION(0), UID(1), mRealtimeRequest, mClientCallback2);
+ mController->submit(CLIENT(2), SESSION(0), UID(2), UID(1), mRealtimeRequest, mClientCallback2);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), SESSION(0)));
@@ -647,12 +647,12 @@
// Start with unspecified top UID.
// Submit real-time session to CLIENT(0), session should start immediately.
mRealtimeRequest.clientPid = PID(0);
- mController->submit(CLIENT(0), SESSION(0), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(0), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
// Submit offline session to CLIENT(0), should not start.
mOfflineRequest.clientPid = PID(0);
- mController->submit(CLIENT(1), SESSION(0), UID(0), mOfflineRequest, mClientCallback1);
+ mController->submit(CLIENT(1), SESSION(0), UID(1), UID(0), mOfflineRequest, mClientCallback1);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Move UID(1) to top.
@@ -662,7 +662,7 @@
// Submit real-time session to CLIENT(2) in different uid UID(1).
// Should pause previous session and start new session.
mRealtimeRequest.clientPid = PID(1);
- mController->submit(CLIENT(2), SESSION(0), UID(1), mRealtimeRequest, mClientCallback2);
+ mController->submit(CLIENT(2), SESSION(0), UID(2), UID(1), mRealtimeRequest, mClientCallback2);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), SESSION(0)));
@@ -719,7 +719,7 @@
// Submit real-time session to CLIENT(3) in UID(2), session shouldn't start due to no resource.
mRealtimeRequest.clientPid = PID(2);
- mController->submit(CLIENT(3), SESSION(0), UID(2), mRealtimeRequest, mClientCallback3);
+ mController->submit(CLIENT(3), SESSION(0), UID(3), UID(2), mRealtimeRequest, mClientCallback3);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Signal resource available, CLIENT(3)'s session should start.
@@ -734,12 +734,12 @@
// Start with unspecified top UID.
// Submit real-time session to CLIENT(0), session should start immediately.
mRealtimeRequest.clientPid = PID(0);
- mController->submit(CLIENT(0), SESSION(0), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(0), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
// Submit offline session to CLIENT(0), should not start.
mOfflineRequest.clientPid = PID(0);
- mController->submit(CLIENT(1), SESSION(0), UID(0), mOfflineRequest, mClientCallback1);
+ mController->submit(CLIENT(1), SESSION(0), UID(1), UID(0), mOfflineRequest, mClientCallback1);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Move UID(1) to top.
@@ -749,7 +749,7 @@
// Submit real-time session to CLIENT(2) in different uid UID(1).
// Should pause previous session and start new session.
mRealtimeRequest.clientPid = PID(1);
- mController->submit(CLIENT(2), SESSION(0), UID(1), mRealtimeRequest, mClientCallback2);
+ mController->submit(CLIENT(2), SESSION(0), UID(2), UID(1), mRealtimeRequest, mClientCallback2);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), SESSION(0)));
@@ -788,7 +788,7 @@
mUidPolicy->setTop(UID(2));
// Submit real-time session to CLIENT(3) in UID(2), session shouldn't start during throttling.
mRealtimeRequest.clientPid = PID(2);
- mController->submit(CLIENT(3), SESSION(0), UID(2), mRealtimeRequest, mClientCallback3);
+ mController->submit(CLIENT(3), SESSION(0), UID(3), UID(2), mRealtimeRequest, mClientCallback3);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Throttling stops, CLIENT(3)'s session should start.
mController->onThrottlingStopped();
@@ -802,12 +802,12 @@
// Start with unspecified top UID.
// Submit real-time session to CLIENT(0), session should start immediately.
mRealtimeRequest.clientPid = PID(0);
- mController->submit(CLIENT(0), SESSION(0), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(0), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
// Submit offline session to CLIENT(0), should not start.
mOfflineRequest.clientPid = PID(0);
- mController->submit(CLIENT(1), SESSION(0), UID(0), mOfflineRequest, mClientCallback1);
+ mController->submit(CLIENT(1), SESSION(0), UID(1), UID(0), mOfflineRequest, mClientCallback1);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Move UID(1) to top.
@@ -817,7 +817,7 @@
// Submit real-time session to CLIENT(2) in different uid UID(1).
// Should pause previous session and start new session.
mRealtimeRequest.clientPid = PID(1);
- mController->submit(CLIENT(2), SESSION(0), UID(1), mRealtimeRequest, mClientCallback2);
+ mController->submit(CLIENT(2), SESSION(0), UID(2), UID(1), mRealtimeRequest, mClientCallback2);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), SESSION(0)));
@@ -859,7 +859,7 @@
// Submit session to CLIENT(0) in UID(0).
// Should start immediately (because this is the only session).
- mController->submit(CLIENT(0), SESSION(0), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(0), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
int32_t expectedGen = 2;
@@ -867,7 +867,7 @@
expectTimeout(CLIENT(0), SESSION(0), expectedGen++);
// Test 2: No timeout as long as keep-alive coming; timeout after keep-alive stops.
- mController->submit(CLIENT(0), SESSION(1), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(1), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(1)));
for (int i = 0; i < 5; i++) {
EXPECT_EQ(mTranscoder->popEvent(1000000), TestTranscoder::NoEvent);
@@ -876,7 +876,7 @@
expectTimeout(CLIENT(0), SESSION(1), expectedGen++);
// Test 3a: No timeout for paused session even if no keep-alive is sent.
- mController->submit(CLIENT(0), SESSION(2), UID(0), mOfflineRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(2), UID(0), UID(0), mOfflineRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(2)));
// Trigger a pause by sending a resource lost.
mController->onResourceLost(CLIENT(0), SESSION(2));
@@ -886,12 +886,12 @@
expectTimeout(CLIENT(0), SESSION(2), expectedGen++);
// Test 3b: No timeout for paused session even if no keep-alive is sent.
- mController->submit(CLIENT(0), SESSION(3), UID(0), mOfflineRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(3), UID(0), UID(0), mOfflineRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(3)));
// Let the session run almost to timeout, to test timeout reset after pause.
EXPECT_EQ(mTranscoder->popEvent(2900000), TestTranscoder::NoEvent);
// Trigger a pause by submitting a higher-priority request.
- mController->submit(CLIENT(0), SESSION(4), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(4), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(3)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(4)));
// Finish the higher-priority session, lower-priority session should resume,
diff --git a/media/libmediatranscoding/tests/build_and_run_all_unit_tests.sh b/media/libmediatranscoding/tests/build_and_run_all_unit_tests.sh
index 5db9258..3cbf1dd 100644
--- a/media/libmediatranscoding/tests/build_and_run_all_unit_tests.sh
+++ b/media/libmediatranscoding/tests/build_and_run_all_unit_tests.sh
@@ -32,3 +32,7 @@
echo "testing TranscodingSessionController"
#adb shell /data/nativetest64/TranscodingSessionController_tests/TranscodingSessionController_tests
adb shell /data/nativetest/TranscodingSessionController_tests/TranscodingSessionController_tests
+
+echo "testing TranscodingLogger"
+#adb shell /data/nativetest64/TranscodingLogger_tests/TranscodingLogger_tests
+adb shell /data/nativetest/TranscodingLogger_tests/TranscodingLogger_tests
diff --git a/media/libmediatranscoding/transcoder/NdkCommon.cpp b/media/libmediatranscoding/transcoder/NdkCommon.cpp
index f5c9594..fb909b2 100644
--- a/media/libmediatranscoding/transcoder/NdkCommon.cpp
+++ b/media/libmediatranscoding/transcoder/NdkCommon.cpp
@@ -90,4 +90,29 @@
DEFINE_SET_DEFAULT_FORMAT_VALUE_FUNC(float, Float);
DEFINE_SET_DEFAULT_FORMAT_VALUE_FUNC(int32_t, Int32);
-} // namespace AMediaFormatUtils
\ No newline at end of file
+// Determines whether a track format describes HDR video content or not. The
+// logic is based on isHdr() in libstagefright/Utils.cpp.
+bool VideoIsHdr(AMediaFormat* format) {
+ // If VUI signals HDR content, this internal flag is set by the extractor.
+ int32_t isHdr;
+ if (AMediaFormat_getInt32(format, "android._is-hdr", &isHdr)) {
+ return isHdr;
+ }
+
+ // If container supplied HDR static info without transfer set, assume HDR.
+ const char* hdrInfo;
+ int32_t transfer;
+ if ((AMediaFormat_getString(format, AMEDIAFORMAT_KEY_HDR_STATIC_INFO, &hdrInfo) ||
+ AMediaFormat_getString(format, "hdr10-plus-info", &hdrInfo)) &&
+ !AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_COLOR_TRANSFER, &transfer)) {
+ return true;
+ }
+
+ // Otherwise, check if an HDR transfer function is set.
+ if (AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_COLOR_TRANSFER, &transfer)) {
+ return transfer == COLOR_TRANSFER_ST2084 || transfer == COLOR_TRANSFER_HLG;
+ }
+
+ return false;
+}
+} // namespace AMediaFormatUtils
diff --git a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
index 04a513e..acf5f6c 100644
--- a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
@@ -51,32 +51,6 @@
// Default frame rate.
static constexpr int32_t kDefaultFrameRate = 30;
-// Determines whether a track format describes HDR video content or not. The
-// logic is based on isHdr() in libstagefright/Utils.cpp.
-static bool isHdr(AMediaFormat* format) {
- // If VUI signals HDR content, this internal flag is set by the extractor.
- int32_t isHdr;
- if (AMediaFormat_getInt32(format, "android._is-hdr", &isHdr)) {
- return isHdr;
- }
-
- // If container supplied HDR static info without transfer set, assume HDR.
- const char* hdrInfo;
- int32_t transfer;
- if ((AMediaFormat_getString(format, AMEDIAFORMAT_KEY_HDR_STATIC_INFO, &hdrInfo) ||
- AMediaFormat_getString(format, "hdr10-plus-info", &hdrInfo)) &&
- !AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_COLOR_TRANSFER, &transfer)) {
- return true;
- }
-
- // Otherwise, check if an HDR transfer function is set.
- if (AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_COLOR_TRANSFER, &transfer)) {
- return transfer == COLOR_TRANSFER_ST2084 || transfer == COLOR_TRANSFER_HLG;
- }
-
- return false;
-}
-
template <typename T>
void VideoTrackTranscoder::BlockingQueue<T>::push(T const& value, bool front) {
{
@@ -347,7 +321,7 @@
}
// Request decoder to convert HDR content to SDR.
- const bool sourceIsHdr = isHdr(mSourceFormat.get());
+ const bool sourceIsHdr = VideoIsHdr(mSourceFormat.get());
if (sourceIsHdr) {
AMediaFormat_setInt32(decoderFormat.get(),
TBD_AMEDIACODEC_PARAMETER_KEY_COLOR_TRANSFER_REQUEST,
diff --git a/media/libmediatranscoding/transcoder/include/media/NdkCommon.h b/media/libmediatranscoding/transcoder/include/media/NdkCommon.h
index cc3399a..a7ed6a7 100644
--- a/media/libmediatranscoding/transcoder/include/media/NdkCommon.h
+++ b/media/libmediatranscoding/transcoder/include/media/NdkCommon.h
@@ -88,5 +88,7 @@
bool SetDefaultFormatValueFloat(const char* key, AMediaFormat* format, float value);
bool SetDefaultFormatValueInt32(const char* key, AMediaFormat* format, int32_t value);
+bool VideoIsHdr(AMediaFormat* format);
+
} // namespace AMediaFormatUtils
#endif // ANDROID_MEDIA_TRANSCODING_NDK_COMMON_H