Loading media/libmediatranscoding/Android.bp +43 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,7 @@ cc_library { srcs: [ "TranscoderWrapper.cpp", "TranscodingClientManager.cpp", "TranscodingLogger.cpp", "TranscodingResourcePolicy.cpp", "TranscodingSessionController.cpp", "TranscodingThermalPolicy.cpp", Loading @@ -96,6 +97,7 @@ cc_library { "libutils", "libmediatranscoder", "libmediandk", "libstatssocket#30", ], export_shared_lib_headers: [ "libmediandk", Loading @@ -106,6 +108,7 @@ cc_library { static_libs: [ "mediatranscoding_aidl_interface-ndk_platform", "resourceobserver_aidl_interface-V1-ndk_platform", "libstatslog_media", ], cflags: [ Loading @@ -126,3 +129,43 @@ cc_library { 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 media/libmediatranscoding/TranscoderWrapper.cpp +65 −22 Original line number Diff line number Diff line Loading @@ -56,34 +56,34 @@ static TranscodingErrorCode toTranscodingError(media_status_t status) { } } 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; } Loading Loading @@ -180,8 +180,10 @@ private: }; 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), Loading Loading @@ -219,10 +221,10 @@ void TranscoderWrapper::reportError(ClientIdType clientId, SessionIdType session } 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); Loading Loading @@ -253,10 +255,10 @@ void TranscoderWrapper::pause(ClientIdType clientId, SessionIdType sessionId) { } 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); Loading @@ -280,6 +282,7 @@ void TranscoderWrapper::stop(ClientIdType clientId, SessionIdType sessionId, boo } else { ALOGI("transcoder stopped"); } logSessionEnded(TranscodingLogger::SessionEndedReason::CANCELLED, err); cleanup(); } else { // For sessions that's not currently running, release any pausedState for the session. Loading @@ -297,6 +300,7 @@ void TranscoderWrapper::onFinish(ClientIdType clientId, SessionIdType sessionId) queueEvent(Event::Finish, clientId, sessionId, [=] { if (mTranscoder != nullptr && clientId == mCurrentClientId && sessionId == mCurrentSessionId) { logSessionEnded(TranscodingLogger::SessionEndedReason::FINISHED, AMEDIA_OK); cleanup(); } Loading @@ -314,6 +318,7 @@ void TranscoderWrapper::onError(ClientIdType clientId, SessionIdType sessionId, [=] { if (mTranscoder != nullptr && clientId == mCurrentClientId && sessionId == mCurrentSessionId) { logSessionEnded(TranscodingLogger::SessionEndedReason::ERROR, error); cleanup(); } reportError(clientId, sessionId, error); Loading Loading @@ -345,7 +350,8 @@ void TranscoderWrapper::onHeartBeat(ClientIdType clientId, SessionIdType session 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"); Loading @@ -364,6 +370,7 @@ media_status_t TranscoderWrapper::setupTranscoder( 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(); Loading @@ -377,6 +384,7 @@ media_status_t TranscoderWrapper::setupTranscoder( 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(); Loading @@ -384,41 +392,46 @@ media_status_t TranscoderWrapper::setupTranscoder( 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); } err = mTranscoder->configureTrackFormat(i, format); if (format != nullptr) { AMediaFormat_delete(format); mSrcFormat = trackFormats[i]; mDstFormat = 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; } } Loading @@ -426,6 +439,7 @@ media_status_t TranscoderWrapper::setupTranscoder( err = mTranscoder->configureDestination(dstFdInt); if (err != AMEDIA_OK) { ALOGE("failed to configure dest: %d", err); *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_DST_FAILED; return err; } Loading @@ -434,17 +448,23 @@ media_status_t TranscoderWrapper::setupTranscoder( 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; } Loading @@ -467,6 +487,7 @@ media_status_t TranscoderWrapper::handlePause(ClientIdType clientId, SessionIdTy 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; Loading @@ -479,7 +500,7 @@ media_status_t TranscoderWrapper::handlePause(ClientIdType clientId, SessionIdTy 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()) { Loading @@ -491,15 +512,23 @@ media_status_t TranscoderWrapper::handleResume( } 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; } Loading @@ -510,8 +539,23 @@ media_status_t TranscoderWrapper::handleResume( 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, Loading Loading @@ -555,5 +599,4 @@ void TranscoderWrapper::threadLoop() { lock.lock(); } } } // namespace android media/libmediatranscoding/TranscodingClientManager.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -162,8 +162,8 @@ Status TranscodingClientManager::ClientImpl::submitRequest( 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; Loading media/libmediatranscoding/TranscodingLogger.cpp 0 → 100644 +194 −0 Original line number Diff line number Diff line /* * 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 media/libmediatranscoding/TranscodingSessionController.cpp +24 −21 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
media/libmediatranscoding/Android.bp +43 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,7 @@ cc_library { srcs: [ "TranscoderWrapper.cpp", "TranscodingClientManager.cpp", "TranscodingLogger.cpp", "TranscodingResourcePolicy.cpp", "TranscodingSessionController.cpp", "TranscodingThermalPolicy.cpp", Loading @@ -96,6 +97,7 @@ cc_library { "libutils", "libmediatranscoder", "libmediandk", "libstatssocket#30", ], export_shared_lib_headers: [ "libmediandk", Loading @@ -106,6 +108,7 @@ cc_library { static_libs: [ "mediatranscoding_aidl_interface-ndk_platform", "resourceobserver_aidl_interface-V1-ndk_platform", "libstatslog_media", ], cflags: [ Loading @@ -126,3 +129,43 @@ cc_library { 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
media/libmediatranscoding/TranscoderWrapper.cpp +65 −22 Original line number Diff line number Diff line Loading @@ -56,34 +56,34 @@ static TranscodingErrorCode toTranscodingError(media_status_t status) { } } 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; } Loading Loading @@ -180,8 +180,10 @@ private: }; 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), Loading Loading @@ -219,10 +221,10 @@ void TranscoderWrapper::reportError(ClientIdType clientId, SessionIdType session } 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); Loading Loading @@ -253,10 +255,10 @@ void TranscoderWrapper::pause(ClientIdType clientId, SessionIdType sessionId) { } 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); Loading @@ -280,6 +282,7 @@ void TranscoderWrapper::stop(ClientIdType clientId, SessionIdType sessionId, boo } else { ALOGI("transcoder stopped"); } logSessionEnded(TranscodingLogger::SessionEndedReason::CANCELLED, err); cleanup(); } else { // For sessions that's not currently running, release any pausedState for the session. Loading @@ -297,6 +300,7 @@ void TranscoderWrapper::onFinish(ClientIdType clientId, SessionIdType sessionId) queueEvent(Event::Finish, clientId, sessionId, [=] { if (mTranscoder != nullptr && clientId == mCurrentClientId && sessionId == mCurrentSessionId) { logSessionEnded(TranscodingLogger::SessionEndedReason::FINISHED, AMEDIA_OK); cleanup(); } Loading @@ -314,6 +318,7 @@ void TranscoderWrapper::onError(ClientIdType clientId, SessionIdType sessionId, [=] { if (mTranscoder != nullptr && clientId == mCurrentClientId && sessionId == mCurrentSessionId) { logSessionEnded(TranscodingLogger::SessionEndedReason::ERROR, error); cleanup(); } reportError(clientId, sessionId, error); Loading Loading @@ -345,7 +350,8 @@ void TranscoderWrapper::onHeartBeat(ClientIdType clientId, SessionIdType session 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"); Loading @@ -364,6 +370,7 @@ media_status_t TranscoderWrapper::setupTranscoder( 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(); Loading @@ -377,6 +384,7 @@ media_status_t TranscoderWrapper::setupTranscoder( 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(); Loading @@ -384,41 +392,46 @@ media_status_t TranscoderWrapper::setupTranscoder( 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); } err = mTranscoder->configureTrackFormat(i, format); if (format != nullptr) { AMediaFormat_delete(format); mSrcFormat = trackFormats[i]; mDstFormat = 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; } } Loading @@ -426,6 +439,7 @@ media_status_t TranscoderWrapper::setupTranscoder( err = mTranscoder->configureDestination(dstFdInt); if (err != AMEDIA_OK) { ALOGE("failed to configure dest: %d", err); *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_DST_FAILED; return err; } Loading @@ -434,17 +448,23 @@ media_status_t TranscoderWrapper::setupTranscoder( 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; } Loading @@ -467,6 +487,7 @@ media_status_t TranscoderWrapper::handlePause(ClientIdType clientId, SessionIdTy 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; Loading @@ -479,7 +500,7 @@ media_status_t TranscoderWrapper::handlePause(ClientIdType clientId, SessionIdTy 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()) { Loading @@ -491,15 +512,23 @@ media_status_t TranscoderWrapper::handleResume( } 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; } Loading @@ -510,8 +539,23 @@ media_status_t TranscoderWrapper::handleResume( 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, Loading Loading @@ -555,5 +599,4 @@ void TranscoderWrapper::threadLoop() { lock.lock(); } } } // namespace android
media/libmediatranscoding/TranscodingClientManager.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -162,8 +162,8 @@ Status TranscodingClientManager::ClientImpl::submitRequest( 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; Loading
media/libmediatranscoding/TranscodingLogger.cpp 0 → 100644 +194 −0 Original line number Diff line number Diff line /* * 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
media/libmediatranscoding/TranscodingSessionController.cpp +24 −21 File changed.Preview size limit exceeded, changes collapsed. Show changes