xref: /aosp_15_r20/frameworks/av/media/module/libmediatranscoding/TranscodingLogger.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker  * Copyright (C) 2021 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker  *
4*ec779b8eSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker  *
8*ec779b8eSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker  *
10*ec779b8eSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker  * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker  */
16*ec779b8eSAndroid Build Coastguard Worker 
17*ec779b8eSAndroid Build Coastguard Worker // #define LOG_NDEBUG 0
18*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "TranscodingLogger"
19*ec779b8eSAndroid Build Coastguard Worker 
20*ec779b8eSAndroid Build Coastguard Worker #include <media/NdkCommon.h>
21*ec779b8eSAndroid Build Coastguard Worker #include <media/TranscodingLogger.h>
22*ec779b8eSAndroid Build Coastguard Worker #include <statslog_media.h>
23*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
24*ec779b8eSAndroid Build Coastguard Worker 
25*ec779b8eSAndroid Build Coastguard Worker #include <cmath>
26*ec779b8eSAndroid Build Coastguard Worker #include <string>
27*ec779b8eSAndroid Build Coastguard Worker 
28*ec779b8eSAndroid Build Coastguard Worker namespace android {
29*ec779b8eSAndroid Build Coastguard Worker 
30*ec779b8eSAndroid Build Coastguard Worker static_assert(TranscodingLogger::UNKNOWN ==
31*ec779b8eSAndroid Build Coastguard Worker                       android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__UNKNOWN,
32*ec779b8eSAndroid Build Coastguard Worker               "Session event mismatch");
33*ec779b8eSAndroid Build Coastguard Worker static_assert(TranscodingLogger::FINISHED ==
34*ec779b8eSAndroid Build Coastguard Worker                       android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__FINISHED,
35*ec779b8eSAndroid Build Coastguard Worker               "Session event mismatch");
36*ec779b8eSAndroid Build Coastguard Worker static_assert(TranscodingLogger::ERROR ==
37*ec779b8eSAndroid Build Coastguard Worker                       android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__ERROR,
38*ec779b8eSAndroid Build Coastguard Worker               "Session event mismatch");
39*ec779b8eSAndroid Build Coastguard Worker static_assert(TranscodingLogger::PAUSED ==
40*ec779b8eSAndroid Build Coastguard Worker                       android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__PAUSED,
41*ec779b8eSAndroid Build Coastguard Worker               "Session event mismatch");
42*ec779b8eSAndroid Build Coastguard Worker static_assert(TranscodingLogger::CANCELLED ==
43*ec779b8eSAndroid Build Coastguard Worker                       android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__CANCELLED,
44*ec779b8eSAndroid Build Coastguard Worker               "Session event mismatch");
45*ec779b8eSAndroid Build Coastguard Worker static_assert(TranscodingLogger::START_FAILED ==
46*ec779b8eSAndroid Build Coastguard Worker                       android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__START_FAILED,
47*ec779b8eSAndroid Build Coastguard Worker               "Session event mismatch");
48*ec779b8eSAndroid Build Coastguard Worker static_assert(TranscodingLogger::RESUME_FAILED ==
49*ec779b8eSAndroid Build Coastguard Worker                       android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__RESUME_FAILED,
50*ec779b8eSAndroid Build Coastguard Worker               "Session event mismatch");
51*ec779b8eSAndroid Build Coastguard Worker static_assert(TranscodingLogger::CREATE_FAILED ==
52*ec779b8eSAndroid Build Coastguard Worker                       android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__CREATE_FAILED,
53*ec779b8eSAndroid Build Coastguard Worker               "Session event mismatch");
54*ec779b8eSAndroid Build Coastguard Worker static_assert(
55*ec779b8eSAndroid Build Coastguard Worker         TranscodingLogger::CONFIG_SRC_FAILED ==
56*ec779b8eSAndroid Build Coastguard Worker                 android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__CONFIG_SRC_FAILED,
57*ec779b8eSAndroid Build Coastguard Worker         "Session event mismatch");
58*ec779b8eSAndroid Build Coastguard Worker static_assert(
59*ec779b8eSAndroid Build Coastguard Worker         TranscodingLogger::CONFIG_DST_FAILED ==
60*ec779b8eSAndroid Build Coastguard Worker                 android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__CONFIG_DST_FAILED,
61*ec779b8eSAndroid Build Coastguard Worker         "Session event mismatch");
62*ec779b8eSAndroid Build Coastguard Worker static_assert(
63*ec779b8eSAndroid Build Coastguard Worker         TranscodingLogger::CONFIG_TRACK_FAILED ==
64*ec779b8eSAndroid Build Coastguard Worker                 android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__CONFIG_TRACK_FAILED,
65*ec779b8eSAndroid Build Coastguard Worker         "Session event mismatch");
66*ec779b8eSAndroid Build Coastguard Worker static_assert(
67*ec779b8eSAndroid Build Coastguard Worker         TranscodingLogger::OPEN_SRC_FD_FAILED ==
68*ec779b8eSAndroid Build Coastguard Worker                 android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__OPEN_SRC_FD_FAILED,
69*ec779b8eSAndroid Build Coastguard Worker         "Session event mismatch");
70*ec779b8eSAndroid Build Coastguard Worker static_assert(
71*ec779b8eSAndroid Build Coastguard Worker         TranscodingLogger::OPEN_DST_FD_FAILED ==
72*ec779b8eSAndroid Build Coastguard Worker                 android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__OPEN_DST_FD_FAILED,
73*ec779b8eSAndroid Build Coastguard Worker         "Session event mismatch");
74*ec779b8eSAndroid Build Coastguard Worker static_assert(TranscodingLogger::NO_TRACKS ==
75*ec779b8eSAndroid Build Coastguard Worker                       android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__NO_TRACKS,
76*ec779b8eSAndroid Build Coastguard Worker               "Session event mismatch");
77*ec779b8eSAndroid Build Coastguard Worker 
getInt32(AMediaFormat * fmt,const char * key,int32_t defaultValue=-1)78*ec779b8eSAndroid Build Coastguard Worker static inline int32_t getInt32(AMediaFormat* fmt, const char* key, int32_t defaultValue = -1) {
79*ec779b8eSAndroid Build Coastguard Worker     int32_t value;
80*ec779b8eSAndroid Build Coastguard Worker     if (fmt == nullptr || !AMediaFormat_getInt32(fmt, key, &value)) {
81*ec779b8eSAndroid Build Coastguard Worker         ALOGW("Unable to get %s", key);
82*ec779b8eSAndroid Build Coastguard Worker         value = defaultValue;
83*ec779b8eSAndroid Build Coastguard Worker     }
84*ec779b8eSAndroid Build Coastguard Worker     return value;
85*ec779b8eSAndroid Build Coastguard Worker }
86*ec779b8eSAndroid Build Coastguard Worker 
87*ec779b8eSAndroid Build Coastguard Worker // Note: returned string is owned by format and only valid until the next getString.
getString(AMediaFormat * fmt,const char * key,const char * defaultValue="(null)")88*ec779b8eSAndroid Build Coastguard Worker static inline const char* getString(AMediaFormat* fmt, const char* key,
89*ec779b8eSAndroid Build Coastguard Worker                                     const char* defaultValue = "(null)") {
90*ec779b8eSAndroid Build Coastguard Worker     const char* value;
91*ec779b8eSAndroid Build Coastguard Worker     if (fmt == nullptr || !AMediaFormat_getString(fmt, key, &value)) {
92*ec779b8eSAndroid Build Coastguard Worker         ALOGW("Unable to get %s", key);
93*ec779b8eSAndroid Build Coastguard Worker         value = defaultValue;
94*ec779b8eSAndroid Build Coastguard Worker     }
95*ec779b8eSAndroid Build Coastguard Worker     return value;
96*ec779b8eSAndroid Build Coastguard Worker }
97*ec779b8eSAndroid Build Coastguard Worker 
TranscodingLogger()98*ec779b8eSAndroid Build Coastguard Worker TranscodingLogger::TranscodingLogger()
99*ec779b8eSAndroid Build Coastguard Worker       : mSessionEndedAtomWriter(&android::media::stats::stats_write) {}
100*ec779b8eSAndroid Build Coastguard Worker 
logSessionEnded(enum SessionEndedReason reason,uid_t callingUid,int status,std::chrono::microseconds duration,AMediaFormat * srcFormat,AMediaFormat * dstFormat)101*ec779b8eSAndroid Build Coastguard Worker void TranscodingLogger::logSessionEnded(enum SessionEndedReason reason, uid_t callingUid,
102*ec779b8eSAndroid Build Coastguard Worker                                         int status, std::chrono::microseconds duration,
103*ec779b8eSAndroid Build Coastguard Worker                                         AMediaFormat* srcFormat, AMediaFormat* dstFormat) {
104*ec779b8eSAndroid Build Coastguard Worker     logSessionEnded(std::chrono::steady_clock::now(), reason, callingUid, status, duration,
105*ec779b8eSAndroid Build Coastguard Worker                     srcFormat, dstFormat);
106*ec779b8eSAndroid Build Coastguard Worker }
107*ec779b8eSAndroid Build Coastguard Worker 
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)108*ec779b8eSAndroid Build Coastguard Worker void TranscodingLogger::logSessionEnded(const std::chrono::steady_clock::time_point& now,
109*ec779b8eSAndroid Build Coastguard Worker                                         enum SessionEndedReason reason, uid_t callingUid,
110*ec779b8eSAndroid Build Coastguard Worker                                         int status, std::chrono::microseconds duration,
111*ec779b8eSAndroid Build Coastguard Worker                                         AMediaFormat* srcFormat, AMediaFormat* dstFormat) {
112*ec779b8eSAndroid Build Coastguard Worker     if (srcFormat == nullptr) {
113*ec779b8eSAndroid Build Coastguard Worker         ALOGE("Source format is null. Dropping event.");
114*ec779b8eSAndroid Build Coastguard Worker         return;
115*ec779b8eSAndroid Build Coastguard Worker     }
116*ec779b8eSAndroid Build Coastguard Worker 
117*ec779b8eSAndroid Build Coastguard Worker     if (!shouldLogAtom(now, status)) {
118*ec779b8eSAndroid Build Coastguard Worker         ALOGD("Maximum logged event count reached. Dropping event.");
119*ec779b8eSAndroid Build Coastguard Worker         return;
120*ec779b8eSAndroid Build Coastguard Worker     }
121*ec779b8eSAndroid Build Coastguard Worker 
122*ec779b8eSAndroid Build Coastguard Worker     // Extract the pieces of information to log.
123*ec779b8eSAndroid Build Coastguard Worker     const int32_t srcWidth = getInt32(srcFormat, AMEDIAFORMAT_KEY_WIDTH);
124*ec779b8eSAndroid Build Coastguard Worker     const int32_t srcHeight = getInt32(srcFormat, AMEDIAFORMAT_KEY_HEIGHT);
125*ec779b8eSAndroid Build Coastguard Worker     const char* srcMime = getString(srcFormat, AMEDIAFORMAT_KEY_MIME);
126*ec779b8eSAndroid Build Coastguard Worker     const int32_t srcProfile = getInt32(srcFormat, AMEDIAFORMAT_KEY_PROFILE);
127*ec779b8eSAndroid Build Coastguard Worker     const int32_t srcLevel = getInt32(srcFormat, AMEDIAFORMAT_KEY_LEVEL);
128*ec779b8eSAndroid Build Coastguard Worker     const int32_t srcFrameRate = getInt32(srcFormat, AMEDIAFORMAT_KEY_FRAME_RATE);
129*ec779b8eSAndroid Build Coastguard Worker     const int32_t srcFrameCount = getInt32(srcFormat, AMEDIAFORMAT_KEY_FRAME_COUNT);
130*ec779b8eSAndroid Build Coastguard Worker     const bool srcIsHdr = AMediaFormatUtils::VideoIsHdr(srcFormat);
131*ec779b8eSAndroid Build Coastguard Worker 
132*ec779b8eSAndroid Build Coastguard Worker     int32_t dstWidth = getInt32(dstFormat, AMEDIAFORMAT_KEY_WIDTH, srcWidth);
133*ec779b8eSAndroid Build Coastguard Worker     int32_t dstHeight = getInt32(dstFormat, AMEDIAFORMAT_KEY_HEIGHT, srcHeight);
134*ec779b8eSAndroid Build Coastguard Worker     const char* dstMime = dstFormat == nullptr
135*ec779b8eSAndroid Build Coastguard Worker                                   ? "passthrough"
136*ec779b8eSAndroid Build Coastguard Worker                                   : getString(dstFormat, AMEDIAFORMAT_KEY_MIME, srcMime);
137*ec779b8eSAndroid Build Coastguard Worker     const bool dstIsHdr = false;  // Transcoder always request SDR output.
138*ec779b8eSAndroid Build Coastguard Worker 
139*ec779b8eSAndroid Build Coastguard Worker     int64_t tmpDurationUs;
140*ec779b8eSAndroid Build Coastguard Worker     const int32_t srcDurationMs =
141*ec779b8eSAndroid Build Coastguard Worker             AMediaFormat_getInt64(srcFormat, AMEDIAFORMAT_KEY_DURATION, &tmpDurationUs)
142*ec779b8eSAndroid Build Coastguard Worker                     ? static_cast<int32_t>(tmpDurationUs / 1000)
143*ec779b8eSAndroid Build Coastguard Worker                     : -1;
144*ec779b8eSAndroid Build Coastguard Worker 
145*ec779b8eSAndroid Build Coastguard Worker     int32_t transcodeFrameRate = -1;
146*ec779b8eSAndroid Build Coastguard Worker     if (status == 0 && srcFrameCount > 0 && duration.count() > 0) {
147*ec779b8eSAndroid Build Coastguard Worker         std::chrono::duration<double> seconds{duration};
148*ec779b8eSAndroid Build Coastguard Worker         transcodeFrameRate = static_cast<int32_t>(
149*ec779b8eSAndroid Build Coastguard Worker                 std::round(static_cast<double>(srcFrameCount) / seconds.count()));
150*ec779b8eSAndroid Build Coastguard Worker     }
151*ec779b8eSAndroid Build Coastguard Worker 
152*ec779b8eSAndroid Build Coastguard Worker     // Write the atom.
153*ec779b8eSAndroid Build Coastguard Worker     mSessionEndedAtomWriter(android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED,
154*ec779b8eSAndroid Build Coastguard Worker                             static_cast<int>(reason), callingUid, status, transcodeFrameRate,
155*ec779b8eSAndroid Build Coastguard Worker                             srcWidth, srcHeight, srcMime, srcProfile, srcLevel, srcFrameRate,
156*ec779b8eSAndroid Build Coastguard Worker                             srcDurationMs, srcIsHdr, dstWidth, dstHeight, dstMime, dstIsHdr);
157*ec779b8eSAndroid Build Coastguard Worker }
158*ec779b8eSAndroid Build Coastguard Worker 
shouldLogAtom(const std::chrono::steady_clock::time_point & now,int status)159*ec779b8eSAndroid Build Coastguard Worker bool TranscodingLogger::shouldLogAtom(const std::chrono::steady_clock::time_point& now,
160*ec779b8eSAndroid Build Coastguard Worker                                       int status) {
161*ec779b8eSAndroid Build Coastguard Worker     std::scoped_lock lock{mLock};
162*ec779b8eSAndroid Build Coastguard Worker     static const std::chrono::hours oneDay(24);
163*ec779b8eSAndroid Build Coastguard Worker 
164*ec779b8eSAndroid Build Coastguard Worker     // Remove events older than one day.
165*ec779b8eSAndroid Build Coastguard Worker     while (mLastLoggedAtoms.size() > 0 && (now - mLastLoggedAtoms.front().first) >= oneDay) {
166*ec779b8eSAndroid Build Coastguard Worker         if (mLastLoggedAtoms.front().second == AMEDIA_OK) {
167*ec779b8eSAndroid Build Coastguard Worker             --mSuccessfulCount;
168*ec779b8eSAndroid Build Coastguard Worker         }
169*ec779b8eSAndroid Build Coastguard Worker         mLastLoggedAtoms.pop();
170*ec779b8eSAndroid Build Coastguard Worker     }
171*ec779b8eSAndroid Build Coastguard Worker 
172*ec779b8eSAndroid Build Coastguard Worker     // Don't log if maximum number of events is reached.
173*ec779b8eSAndroid Build Coastguard Worker     if (mLastLoggedAtoms.size() >= kMaxAtomsPerDay) {
174*ec779b8eSAndroid Build Coastguard Worker         return false;
175*ec779b8eSAndroid Build Coastguard Worker     }
176*ec779b8eSAndroid Build Coastguard Worker 
177*ec779b8eSAndroid Build Coastguard Worker     // Don't log if the event is successful and the maximum number of successful events is reached.
178*ec779b8eSAndroid Build Coastguard Worker     if (status == AMEDIA_OK && mSuccessfulCount >= kMaxSuccessfulAtomsPerDay) {
179*ec779b8eSAndroid Build Coastguard Worker         return false;
180*ec779b8eSAndroid Build Coastguard Worker     }
181*ec779b8eSAndroid Build Coastguard Worker 
182*ec779b8eSAndroid Build Coastguard Worker     // Record the event.
183*ec779b8eSAndroid Build Coastguard Worker     if (status == AMEDIA_OK) {
184*ec779b8eSAndroid Build Coastguard Worker         ++mSuccessfulCount;
185*ec779b8eSAndroid Build Coastguard Worker     }
186*ec779b8eSAndroid Build Coastguard Worker     mLastLoggedAtoms.emplace(now, status);
187*ec779b8eSAndroid Build Coastguard Worker     return true;
188*ec779b8eSAndroid Build Coastguard Worker }
189*ec779b8eSAndroid Build Coastguard Worker 
setSessionEndedAtomWriter(const SessionEndedAtomWriter & writer)190*ec779b8eSAndroid Build Coastguard Worker void TranscodingLogger::setSessionEndedAtomWriter(const SessionEndedAtomWriter& writer) {
191*ec779b8eSAndroid Build Coastguard Worker     mSessionEndedAtomWriter = writer;
192*ec779b8eSAndroid Build Coastguard Worker }
193*ec779b8eSAndroid Build Coastguard Worker 
194*ec779b8eSAndroid Build Coastguard Worker }  // namespace android
195