blob: 5e4c671f73e482aa6726171ecd229a4cf2ad1be2 [file] [log] [blame]
Chong Zhang66469272020-06-04 16:51:55 -07001/*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "TranscoderWrapper"
19
20#include <aidl/android/media/TranscodingErrorCode.h>
21#include <aidl/android/media/TranscodingRequestParcel.h>
22#include <media/MediaTranscoder.h>
23#include <media/NdkCommon.h>
24#include <media/TranscoderWrapper.h>
Linus Nilsson1cbc22c2021-03-19 12:21:07 -070025#include <media/TranscodingRequest.h>
Chong Zhang45a31632021-04-22 16:15:19 -070026#include <utils/AndroidThreads.h>
Chong Zhang66469272020-06-04 16:51:55 -070027#include <utils/Log.h>
28
29#include <thread>
30
31namespace android {
32using Status = ::ndk::ScopedAStatus;
33using ::aidl::android::media::TranscodingErrorCode;
34using ::aidl::android::media::TranscodingVideoCodecType;
35using ::aidl::android::media::TranscodingVideoTrackFormat;
36
37static TranscodingErrorCode toTranscodingError(media_status_t status) {
38 switch (status) {
39 case AMEDIA_OK:
40 return TranscodingErrorCode::kNoError;
41 case AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE: // FALLTHRU
42 case AMEDIACODEC_ERROR_RECLAIMED:
43 return TranscodingErrorCode::kInsufficientResources;
44 case AMEDIA_ERROR_MALFORMED:
45 return TranscodingErrorCode::kMalformed;
46 case AMEDIA_ERROR_UNSUPPORTED:
47 return TranscodingErrorCode::kUnsupported;
48 case AMEDIA_ERROR_INVALID_OBJECT: // FALLTHRU
49 case AMEDIA_ERROR_INVALID_PARAMETER:
50 return TranscodingErrorCode::kInvalidParameter;
51 case AMEDIA_ERROR_INVALID_OPERATION:
52 return TranscodingErrorCode::kInvalidOperation;
53 case AMEDIA_ERROR_IO:
54 return TranscodingErrorCode::kErrorIO;
55 case AMEDIA_ERROR_UNKNOWN: // FALLTHRU
56 default:
57 return TranscodingErrorCode::kUnknown;
58 }
59}
60
Linus Nilssona99f4042021-02-25 15:49:43 -080061static std::shared_ptr<AMediaFormat> getVideoFormat(
Chong Zhangb55c5452020-06-26 14:32:12 -070062 const char* originalMime,
63 const std::optional<TranscodingVideoTrackFormat>& requestedFormat) {
64 if (requestedFormat == std::nullopt) {
65 return nullptr;
66 }
67
Linus Nilssona99f4042021-02-25 15:49:43 -080068 std::shared_ptr<AMediaFormat> format =
69 std::shared_ptr<AMediaFormat>(AMediaFormat_new(), &AMediaFormat_delete);
Chong Zhangb55c5452020-06-26 14:32:12 -070070 bool changed = false;
71 if (requestedFormat->codecType == TranscodingVideoCodecType::kHevc &&
72 strcmp(originalMime, AMEDIA_MIMETYPE_VIDEO_HEVC)) {
Linus Nilssona99f4042021-02-25 15:49:43 -080073 AMediaFormat_setString(format.get(), AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_HEVC);
Chong Zhangb55c5452020-06-26 14:32:12 -070074 changed = true;
75 } else if (requestedFormat->codecType == TranscodingVideoCodecType::kAvc &&
76 strcmp(originalMime, AMEDIA_MIMETYPE_VIDEO_AVC)) {
Linus Nilssona99f4042021-02-25 15:49:43 -080077 AMediaFormat_setString(format.get(), AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_AVC);
Chong Zhangb55c5452020-06-26 14:32:12 -070078 changed = true;
79 }
80 if (requestedFormat->bitrateBps > 0) {
Linus Nilssona99f4042021-02-25 15:49:43 -080081 AMediaFormat_setInt32(format.get(), AMEDIAFORMAT_KEY_BIT_RATE, requestedFormat->bitrateBps);
Chong Zhangb55c5452020-06-26 14:32:12 -070082 changed = true;
83 }
84 // TODO: translate other fields from requestedFormat to the format for MediaTranscoder.
85 // Also need to determine more settings to expose in TranscodingVideoTrackFormat.
86 if (!changed) {
Chong Zhangb55c5452020-06-26 14:32:12 -070087 // Use null format for passthru.
Linus Nilssona99f4042021-02-25 15:49:43 -080088 format.reset();
Chong Zhangb55c5452020-06-26 14:32:12 -070089 }
90 return format;
91}
92
Chong Zhang66469272020-06-04 16:51:55 -070093//static
Chong Zhangf9077512020-09-21 21:02:06 -070094std::string TranscoderWrapper::toString(const Event& event) {
95 std::string typeStr;
96 switch (event.type) {
Chong Zhang66469272020-06-04 16:51:55 -070097 case Event::Start:
Chong Zhangf9077512020-09-21 21:02:06 -070098 typeStr = "Start";
Chong Zhang66469272020-06-04 16:51:55 -070099 break;
Chong Zhangf9077512020-09-21 21:02:06 -0700100 case Event::Pause:
101 typeStr = "Pause";
102 break;
103 case Event::Resume:
104 typeStr = "Resume";
105 break;
106 case Event::Stop:
107 typeStr = "Stop";
108 break;
109 case Event::Finish:
110 typeStr = "Finish";
111 break;
112 case Event::Error:
113 typeStr = "Error";
114 break;
115 case Event::Progress:
116 typeStr = "Progress";
117 break;
Chong Zhang457c6892021-02-01 15:34:20 -0800118 case Event::HeartBeat:
119 typeStr = "HeartBeat";
120 break;
121 case Event::Abandon:
122 typeStr = "Abandon";
123 break;
Chong Zhangf9077512020-09-21 21:02:06 -0700124 default:
125 return "(unknown)";
Chong Zhang66469272020-06-04 16:51:55 -0700126 }
Chong Zhangf9077512020-09-21 21:02:06 -0700127 std::string result;
Chong Zhangbc062482020-10-14 16:43:53 -0700128 result = "session {" + std::to_string(event.clientId) + "," + std::to_string(event.sessionId) +
Chong Zhangf9077512020-09-21 21:02:06 -0700129 "}: " + typeStr;
130 if (event.type == Event::Error || event.type == Event::Progress) {
131 result += " " + std::to_string(event.arg);
132 }
133 return result;
Chong Zhang66469272020-06-04 16:51:55 -0700134}
135
136class TranscoderWrapper::CallbackImpl : public MediaTranscoder::CallbackInterface {
137public:
138 CallbackImpl(const std::shared_ptr<TranscoderWrapper>& owner, ClientIdType clientId,
Chong Zhangbc062482020-10-14 16:43:53 -0700139 SessionIdType sessionId)
140 : mOwner(owner), mClientId(clientId), mSessionId(sessionId) {}
Chong Zhang66469272020-06-04 16:51:55 -0700141
142 virtual void onFinished(const MediaTranscoder* transcoder __unused) override {
143 auto owner = mOwner.lock();
144 if (owner != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700145 owner->onFinish(mClientId, mSessionId);
Chong Zhang66469272020-06-04 16:51:55 -0700146 }
147 }
148
149 virtual void onError(const MediaTranscoder* transcoder __unused,
150 media_status_t error) override {
151 auto owner = mOwner.lock();
152 if (owner != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700153 owner->onError(mClientId, mSessionId, error);
Chong Zhang66469272020-06-04 16:51:55 -0700154 }
155 }
156
157 virtual void onProgressUpdate(const MediaTranscoder* transcoder __unused,
158 int32_t progress) override {
Chong Zhang98b8a372020-07-08 17:27:37 -0700159 auto owner = mOwner.lock();
160 if (owner != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700161 owner->onProgress(mClientId, mSessionId, progress);
Chong Zhang98b8a372020-07-08 17:27:37 -0700162 }
Chong Zhang66469272020-06-04 16:51:55 -0700163 }
164
Chong Zhang457c6892021-02-01 15:34:20 -0800165 virtual void onHeartBeat(const MediaTranscoder* transcoder __unused) override {
166 auto owner = mOwner.lock();
167 if (owner != nullptr) {
168 owner->onHeartBeat(mClientId, mSessionId);
169 }
170 }
171
Chong Zhang66469272020-06-04 16:51:55 -0700172 virtual void onCodecResourceLost(const MediaTranscoder* transcoder __unused,
Chong Zhange4e088f2020-10-21 19:10:42 -0700173 const std::shared_ptr<ndk::ScopedAParcel>& pausedState
Chong Zhang66469272020-06-04 16:51:55 -0700174 __unused) override {
Chong Zhangbc062482020-10-14 16:43:53 -0700175 ALOGV("%s: session {%lld, %d}", __FUNCTION__, (long long)mClientId, mSessionId);
Chong Zhang66469272020-06-04 16:51:55 -0700176 }
177
178private:
179 std::weak_ptr<TranscoderWrapper> mOwner;
180 ClientIdType mClientId;
Chong Zhangbc062482020-10-14 16:43:53 -0700181 SessionIdType mSessionId;
Chong Zhang66469272020-06-04 16:51:55 -0700182};
183
Chong Zhang457c6892021-02-01 15:34:20 -0800184TranscoderWrapper::TranscoderWrapper(const std::shared_ptr<TranscoderCallbackInterface>& cb,
Linus Nilssona99f4042021-02-25 15:49:43 -0800185 const std::shared_ptr<TranscodingLogger>& logger,
Chong Zhang457c6892021-02-01 15:34:20 -0800186 int64_t heartBeatIntervalUs)
187 : mCallback(cb),
Linus Nilssona99f4042021-02-25 15:49:43 -0800188 mLogger(logger),
Chong Zhang457c6892021-02-01 15:34:20 -0800189 mHeartBeatIntervalUs(heartBeatIntervalUs),
190 mCurrentClientId(0),
191 mCurrentSessionId(-1),
192 mLooperReady(false) {
193 ALOGV("TranscoderWrapper CTOR: %p", this);
Chong Zhang66469272020-06-04 16:51:55 -0700194}
195
Chong Zhang457c6892021-02-01 15:34:20 -0800196TranscoderWrapper::~TranscoderWrapper() {
197 ALOGV("TranscoderWrapper DTOR: %p", this);
Chong Zhang66469272020-06-04 16:51:55 -0700198}
199
Chong Zhangf9077512020-09-21 21:02:06 -0700200static bool isResourceError(media_status_t err) {
201 return err == AMEDIACODEC_ERROR_RECLAIMED || err == AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE;
202}
203
Chong Zhangbc062482020-10-14 16:43:53 -0700204void TranscoderWrapper::reportError(ClientIdType clientId, SessionIdType sessionId,
205 media_status_t err) {
Chong Zhangf9077512020-09-21 21:02:06 -0700206 auto callback = mCallback.lock();
207 if (callback != nullptr) {
208 if (isResourceError(err)) {
209 // Add a placeholder pause state to mPausedStateMap. This is required when resuming.
210 // TODO: remove this when transcoder pause/resume logic is ready. New logic will
211 // no longer use the pause states.
Chong Zhangbc062482020-10-14 16:43:53 -0700212 auto it = mPausedStateMap.find(SessionKeyType(clientId, sessionId));
Chong Zhangf9077512020-09-21 21:02:06 -0700213 if (it == mPausedStateMap.end()) {
Chong Zhangbc062482020-10-14 16:43:53 -0700214 mPausedStateMap.emplace(SessionKeyType(clientId, sessionId),
Chong Zhange4e088f2020-10-21 19:10:42 -0700215 new ndk::ScopedAParcel());
Chong Zhangf9077512020-09-21 21:02:06 -0700216 }
217
Chong Zhangeffd8962020-12-02 14:29:09 -0800218 callback->onResourceLost(clientId, sessionId);
Chong Zhangf9077512020-09-21 21:02:06 -0700219 } else {
Chong Zhangbc062482020-10-14 16:43:53 -0700220 callback->onError(clientId, sessionId, toTranscodingError(err));
Chong Zhangf9077512020-09-21 21:02:06 -0700221 }
222 }
223}
224
Chong Zhangbc062482020-10-14 16:43:53 -0700225void TranscoderWrapper::start(ClientIdType clientId, SessionIdType sessionId,
Linus Nilsson1cbc22c2021-03-19 12:21:07 -0700226 const TranscodingRequestParcel& requestParcel, uid_t callingUid,
Chong Zhangb55c5452020-06-26 14:32:12 -0700227 const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
Linus Nilsson1cbc22c2021-03-19 12:21:07 -0700228 TranscodingRequest request{requestParcel};
229 queueEvent(Event::Start, clientId, sessionId, [=] {
Linus Nilssona99f4042021-02-25 15:49:43 -0800230 media_status_t err = handleStart(clientId, sessionId, request, callingUid, clientCb);
Chong Zhangf9077512020-09-21 21:02:06 -0700231 if (err != AMEDIA_OK) {
Chong Zhang66469272020-06-04 16:51:55 -0700232 cleanup();
Chong Zhangbc062482020-10-14 16:43:53 -0700233 reportError(clientId, sessionId, err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700234 } else {
Chong Zhangf9077512020-09-21 21:02:06 -0700235 auto callback = mCallback.lock();
Chong Zhangb55c5452020-06-26 14:32:12 -0700236 if (callback != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700237 callback->onStarted(clientId, sessionId);
Chong Zhangb55c5452020-06-26 14:32:12 -0700238 }
Chong Zhang66469272020-06-04 16:51:55 -0700239 }
240 });
241}
242
Chong Zhangbc062482020-10-14 16:43:53 -0700243void TranscoderWrapper::pause(ClientIdType clientId, SessionIdType sessionId) {
244 queueEvent(Event::Pause, clientId, sessionId, [=] {
245 media_status_t err = handlePause(clientId, sessionId);
Chong Zhangb55c5452020-06-26 14:32:12 -0700246
247 cleanup();
248
Chong Zhangf9077512020-09-21 21:02:06 -0700249 if (err != AMEDIA_OK) {
Chong Zhangbc062482020-10-14 16:43:53 -0700250 reportError(clientId, sessionId, err);
Chong Zhangf9077512020-09-21 21:02:06 -0700251 } else {
252 auto callback = mCallback.lock();
253 if (callback != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700254 callback->onPaused(clientId, sessionId);
Chong Zhangb55c5452020-06-26 14:32:12 -0700255 }
256 }
257 });
Chong Zhang66469272020-06-04 16:51:55 -0700258}
259
Chong Zhangbc062482020-10-14 16:43:53 -0700260void TranscoderWrapper::resume(ClientIdType clientId, SessionIdType sessionId,
Linus Nilsson1cbc22c2021-03-19 12:21:07 -0700261 const TranscodingRequestParcel& requestParcel, uid_t callingUid,
Chong Zhangb55c5452020-06-26 14:32:12 -0700262 const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
Linus Nilsson1cbc22c2021-03-19 12:21:07 -0700263 TranscodingRequest request{requestParcel};
264 queueEvent(Event::Resume, clientId, sessionId, [=] {
Linus Nilssona99f4042021-02-25 15:49:43 -0800265 media_status_t err = handleResume(clientId, sessionId, request, callingUid, clientCb);
Chong Zhangf9077512020-09-21 21:02:06 -0700266 if (err != AMEDIA_OK) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700267 cleanup();
Chong Zhangbc062482020-10-14 16:43:53 -0700268 reportError(clientId, sessionId, err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700269 } else {
Chong Zhangf9077512020-09-21 21:02:06 -0700270 auto callback = mCallback.lock();
Chong Zhangb55c5452020-06-26 14:32:12 -0700271 if (callback != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700272 callback->onResumed(clientId, sessionId);
Chong Zhangb55c5452020-06-26 14:32:12 -0700273 }
274 }
275 });
Chong Zhang66469272020-06-04 16:51:55 -0700276}
277
Chong Zhang457c6892021-02-01 15:34:20 -0800278void TranscoderWrapper::stop(ClientIdType clientId, SessionIdType sessionId, bool abandon) {
Chong Zhangbc062482020-10-14 16:43:53 -0700279 queueEvent(Event::Stop, clientId, sessionId, [=] {
280 if (mTranscoder != nullptr && clientId == mCurrentClientId &&
281 sessionId == mCurrentSessionId) {
282 // Cancelling the currently running session.
Chong Zhangb55c5452020-06-26 14:32:12 -0700283 media_status_t err = mTranscoder->cancel();
284 if (err != AMEDIA_OK) {
Chong Zhangf9077512020-09-21 21:02:06 -0700285 ALOGW("failed to stop transcoder: %d", err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700286 } else {
287 ALOGI("transcoder stopped");
288 }
Linus Nilssona99f4042021-02-25 15:49:43 -0800289 logSessionEnded(TranscodingLogger::SessionEndedReason::CANCELLED, err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700290 cleanup();
Chong Zhang66469272020-06-04 16:51:55 -0700291 } else {
Chong Zhangbc062482020-10-14 16:43:53 -0700292 // For sessions that's not currently running, release any pausedState for the session.
293 mPausedStateMap.erase(SessionKeyType(clientId, sessionId));
Chong Zhang66469272020-06-04 16:51:55 -0700294 }
Chong Zhangb55c5452020-06-26 14:32:12 -0700295 // No callback needed for stop.
Chong Zhang66469272020-06-04 16:51:55 -0700296 });
Chong Zhang457c6892021-02-01 15:34:20 -0800297
298 if (abandon) {
299 queueEvent(Event::Abandon, 0, 0, nullptr);
300 }
Chong Zhang66469272020-06-04 16:51:55 -0700301}
302
Chong Zhangbc062482020-10-14 16:43:53 -0700303void TranscoderWrapper::onFinish(ClientIdType clientId, SessionIdType sessionId) {
304 queueEvent(Event::Finish, clientId, sessionId, [=] {
305 if (mTranscoder != nullptr && clientId == mCurrentClientId &&
306 sessionId == mCurrentSessionId) {
Linus Nilssona99f4042021-02-25 15:49:43 -0800307 logSessionEnded(TranscodingLogger::SessionEndedReason::FINISHED, AMEDIA_OK);
Chong Zhangb55c5452020-06-26 14:32:12 -0700308 cleanup();
309 }
Chong Zhang66469272020-06-04 16:51:55 -0700310
311 auto callback = mCallback.lock();
312 if (callback != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700313 callback->onFinish(clientId, sessionId);
Chong Zhang66469272020-06-04 16:51:55 -0700314 }
315 });
316}
317
Chong Zhangbc062482020-10-14 16:43:53 -0700318void TranscoderWrapper::onError(ClientIdType clientId, SessionIdType sessionId,
319 media_status_t error) {
Chong Zhangf9077512020-09-21 21:02:06 -0700320 queueEvent(
Chong Zhangbc062482020-10-14 16:43:53 -0700321 Event::Error, clientId, sessionId,
Chong Zhangf9077512020-09-21 21:02:06 -0700322 [=] {
323 if (mTranscoder != nullptr && clientId == mCurrentClientId &&
Chong Zhangbc062482020-10-14 16:43:53 -0700324 sessionId == mCurrentSessionId) {
Linus Nilssona99f4042021-02-25 15:49:43 -0800325 logSessionEnded(TranscodingLogger::SessionEndedReason::ERROR, error);
Chong Zhangf9077512020-09-21 21:02:06 -0700326 cleanup();
327 }
Chong Zhangbc062482020-10-14 16:43:53 -0700328 reportError(clientId, sessionId, error);
Chong Zhangf9077512020-09-21 21:02:06 -0700329 },
330 error);
Chong Zhang66469272020-06-04 16:51:55 -0700331}
332
Chong Zhangbc062482020-10-14 16:43:53 -0700333void TranscoderWrapper::onProgress(ClientIdType clientId, SessionIdType sessionId,
334 int32_t progress) {
Chong Zhangf9077512020-09-21 21:02:06 -0700335 queueEvent(
Chong Zhangbc062482020-10-14 16:43:53 -0700336 Event::Progress, clientId, sessionId,
Chong Zhangf9077512020-09-21 21:02:06 -0700337 [=] {
338 auto callback = mCallback.lock();
339 if (callback != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700340 callback->onProgressUpdate(clientId, sessionId, progress);
Chong Zhangf9077512020-09-21 21:02:06 -0700341 }
342 },
343 progress);
Chong Zhang98b8a372020-07-08 17:27:37 -0700344}
345
Chong Zhang457c6892021-02-01 15:34:20 -0800346void TranscoderWrapper::onHeartBeat(ClientIdType clientId, SessionIdType sessionId) {
347 queueEvent(Event::HeartBeat, clientId, sessionId, [=] {
348 auto callback = mCallback.lock();
349 if (callback != nullptr) {
350 callback->onHeartBeat(clientId, sessionId);
351 }
352 });
353}
354
Chong Zhangf9077512020-09-21 21:02:06 -0700355media_status_t TranscoderWrapper::setupTranscoder(
Chong Zhangbc062482020-10-14 16:43:53 -0700356 ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
Linus Nilssona99f4042021-02-25 15:49:43 -0800357 uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& clientCb,
358 TranscodingLogger::SessionEndedReason* failureReason,
Chong Zhange4e088f2020-10-21 19:10:42 -0700359 const std::shared_ptr<ndk::ScopedAParcel>& pausedState) {
Chong Zhang66469272020-06-04 16:51:55 -0700360 if (clientCb == nullptr) {
361 ALOGE("client callback is null");
Chong Zhangf9077512020-09-21 21:02:06 -0700362 return AMEDIA_ERROR_INVALID_PARAMETER;
Chong Zhang66469272020-06-04 16:51:55 -0700363 }
364
365 if (mTranscoder != nullptr) {
366 ALOGE("transcoder already running");
Chong Zhangf9077512020-09-21 21:02:06 -0700367 return AMEDIA_ERROR_INVALID_OPERATION;
Chong Zhang66469272020-06-04 16:51:55 -0700368 }
369
Linus Nilssond2bef932021-03-23 21:55:33 -0700370 // Unwrap the callback and send heartbeats to the client after each operation during setup.
371 auto callback = mCallback.lock();
372 if (callback == nullptr) {
373 return AMEDIA_ERROR_INVALID_OPERATION;
374 }
375
Chong Zhang66469272020-06-04 16:51:55 -0700376 Status status;
377 ::ndk::ScopedFileDescriptor srcFd, dstFd;
hkuang34377c32020-09-24 22:28:27 -0700378 int srcFdInt = request.sourceFd.get();
379 if (srcFdInt < 0) {
380 status = clientCb->openFileDescriptor(request.sourceFilePath, "r", &srcFd);
381 if (!status.isOk() || srcFd.get() < 0) {
382 ALOGE("failed to open source");
Linus Nilssona99f4042021-02-25 15:49:43 -0800383 *failureReason = TranscodingLogger::SessionEndedReason::OPEN_SRC_FD_FAILED;
hkuang34377c32020-09-24 22:28:27 -0700384 return AMEDIA_ERROR_IO;
385 }
386 srcFdInt = srcFd.get();
Chong Zhang66469272020-06-04 16:51:55 -0700387 }
388
Linus Nilssond2bef932021-03-23 21:55:33 -0700389 callback->onHeartBeat(clientId, sessionId);
390
hkuang34377c32020-09-24 22:28:27 -0700391 int dstFdInt = request.destinationFd.get();
392 if (dstFdInt < 0) {
393 // Open dest file with "rw", as the transcoder could potentially reuse part of it
394 // for resume case. We might want the further differentiate and open with "w" only
395 // for start.
396 status = clientCb->openFileDescriptor(request.destinationFilePath, "rw", &dstFd);
397 if (!status.isOk() || dstFd.get() < 0) {
398 ALOGE("failed to open destination");
Linus Nilssona99f4042021-02-25 15:49:43 -0800399 *failureReason = TranscodingLogger::SessionEndedReason::OPEN_DST_FD_FAILED;
hkuang34377c32020-09-24 22:28:27 -0700400 return AMEDIA_ERROR_IO;
401 }
402 dstFdInt = dstFd.get();
Chong Zhang66469272020-06-04 16:51:55 -0700403 }
404
Linus Nilssond2bef932021-03-23 21:55:33 -0700405 callback->onHeartBeat(clientId, sessionId);
406
Chong Zhang66469272020-06-04 16:51:55 -0700407 mCurrentClientId = clientId;
Chong Zhangbc062482020-10-14 16:43:53 -0700408 mCurrentSessionId = sessionId;
Linus Nilssona99f4042021-02-25 15:49:43 -0800409 mCurrentCallingUid = callingUid;
Chong Zhangbc062482020-10-14 16:43:53 -0700410 mTranscoderCb = std::make_shared<CallbackImpl>(shared_from_this(), clientId, sessionId);
Chong Zhang457c6892021-02-01 15:34:20 -0800411 mTranscoder = MediaTranscoder::create(mTranscoderCb, mHeartBeatIntervalUs, request.clientPid,
412 request.clientUid, pausedState);
Chong Zhang66469272020-06-04 16:51:55 -0700413 if (mTranscoder == nullptr) {
414 ALOGE("failed to create transcoder");
Linus Nilssona99f4042021-02-25 15:49:43 -0800415 *failureReason = TranscodingLogger::SessionEndedReason::CREATE_FAILED;
Chong Zhangf9077512020-09-21 21:02:06 -0700416 return AMEDIA_ERROR_UNKNOWN;
Chong Zhang66469272020-06-04 16:51:55 -0700417 }
418
Linus Nilssond2bef932021-03-23 21:55:33 -0700419 callback->onHeartBeat(clientId, sessionId);
420
hkuang34377c32020-09-24 22:28:27 -0700421 media_status_t err = mTranscoder->configureSource(srcFdInt);
Chong Zhang66469272020-06-04 16:51:55 -0700422 if (err != AMEDIA_OK) {
423 ALOGE("failed to configure source: %d", err);
Linus Nilssona99f4042021-02-25 15:49:43 -0800424 *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_SRC_FAILED;
Chong Zhangf9077512020-09-21 21:02:06 -0700425 return err;
Chong Zhang66469272020-06-04 16:51:55 -0700426 }
427
Linus Nilssond2bef932021-03-23 21:55:33 -0700428 callback->onHeartBeat(clientId, sessionId);
429
Chong Zhang66469272020-06-04 16:51:55 -0700430 std::vector<std::shared_ptr<AMediaFormat>> trackFormats = mTranscoder->getTrackFormats();
431 if (trackFormats.size() == 0) {
432 ALOGE("failed to get track formats!");
Linus Nilssona99f4042021-02-25 15:49:43 -0800433 *failureReason = TranscodingLogger::SessionEndedReason::NO_TRACKS;
Chong Zhangf9077512020-09-21 21:02:06 -0700434 return AMEDIA_ERROR_MALFORMED;
Chong Zhang66469272020-06-04 16:51:55 -0700435 }
436
Linus Nilssond2bef932021-03-23 21:55:33 -0700437 callback->onHeartBeat(clientId, sessionId);
438
Chong Zhang66469272020-06-04 16:51:55 -0700439 for (int i = 0; i < trackFormats.size(); ++i) {
Linus Nilssona99f4042021-02-25 15:49:43 -0800440 std::shared_ptr<AMediaFormat> format;
Chong Zhang66469272020-06-04 16:51:55 -0700441 const char* mime = nullptr;
442 AMediaFormat_getString(trackFormats[i].get(), AMEDIAFORMAT_KEY_MIME, &mime);
443
444 if (!strncmp(mime, "video/", 6)) {
445 format = getVideoFormat(mime, request.requestedVideoTrackFormat);
Linus Nilssona99f4042021-02-25 15:49:43 -0800446
447 mSrcFormat = trackFormats[i];
448 mDstFormat = format;
Chong Zhang66469272020-06-04 16:51:55 -0700449 }
450
Linus Nilssona99f4042021-02-25 15:49:43 -0800451 err = mTranscoder->configureTrackFormat(i, format.get());
Chong Zhang66469272020-06-04 16:51:55 -0700452 if (err != AMEDIA_OK) {
453 ALOGE("failed to configure track format for track %d: %d", i, err);
Linus Nilssona99f4042021-02-25 15:49:43 -0800454 *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_TRACK_FAILED;
Chong Zhangf9077512020-09-21 21:02:06 -0700455 return err;
Chong Zhang66469272020-06-04 16:51:55 -0700456 }
Linus Nilssond2bef932021-03-23 21:55:33 -0700457
458 callback->onHeartBeat(clientId, sessionId);
Chong Zhang66469272020-06-04 16:51:55 -0700459 }
460
hkuang34377c32020-09-24 22:28:27 -0700461 err = mTranscoder->configureDestination(dstFdInt);
Chong Zhang66469272020-06-04 16:51:55 -0700462 if (err != AMEDIA_OK) {
463 ALOGE("failed to configure dest: %d", err);
Linus Nilssona99f4042021-02-25 15:49:43 -0800464 *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_DST_FAILED;
Chong Zhangf9077512020-09-21 21:02:06 -0700465 return err;
Chong Zhang66469272020-06-04 16:51:55 -0700466 }
467
Linus Nilssond2bef932021-03-23 21:55:33 -0700468 callback->onHeartBeat(clientId, sessionId);
469
Chong Zhangf9077512020-09-21 21:02:06 -0700470 return AMEDIA_OK;
Chong Zhangb55c5452020-06-26 14:32:12 -0700471}
472
Chong Zhangf9077512020-09-21 21:02:06 -0700473media_status_t TranscoderWrapper::handleStart(
Chong Zhangbc062482020-10-14 16:43:53 -0700474 ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
Linus Nilssona99f4042021-02-25 15:49:43 -0800475 uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
Chong Zhangf9077512020-09-21 21:02:06 -0700476 ALOGI("%s: setting up transcoder for start", __FUNCTION__);
Linus Nilssona99f4042021-02-25 15:49:43 -0800477 TranscodingLogger::SessionEndedReason reason = TranscodingLogger::SessionEndedReason::UNKNOWN;
478 media_status_t err =
479 setupTranscoder(clientId, sessionId, request, callingUid, clientCb, &reason);
Chong Zhangf9077512020-09-21 21:02:06 -0700480 if (err != AMEDIA_OK) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700481 ALOGI("%s: failed to setup transcoder", __FUNCTION__);
Linus Nilssona99f4042021-02-25 15:49:43 -0800482 logSessionEnded(reason, err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700483 return err;
Chong Zhang66469272020-06-04 16:51:55 -0700484 }
485
Linus Nilssona99f4042021-02-25 15:49:43 -0800486 mTranscodeStartTime = std::chrono::steady_clock::now();
487
Chong Zhangf9077512020-09-21 21:02:06 -0700488 err = mTranscoder->start();
489 if (err != AMEDIA_OK) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700490 ALOGE("%s: failed to start transcoder: %d", __FUNCTION__, err);
Linus Nilssona99f4042021-02-25 15:49:43 -0800491 logSessionEnded(TranscodingLogger::SessionEndedReason::START_FAILED, err);
Chong Zhangf9077512020-09-21 21:02:06 -0700492 return err;
Chong Zhangb55c5452020-06-26 14:32:12 -0700493 }
494
495 ALOGI("%s: transcoder started", __FUNCTION__);
Chong Zhangf9077512020-09-21 21:02:06 -0700496 return AMEDIA_OK;
Chong Zhangb55c5452020-06-26 14:32:12 -0700497}
498
Chong Zhangbc062482020-10-14 16:43:53 -0700499media_status_t TranscoderWrapper::handlePause(ClientIdType clientId, SessionIdType sessionId) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700500 if (mTranscoder == nullptr) {
501 ALOGE("%s: transcoder is not running", __FUNCTION__);
Chong Zhangf9077512020-09-21 21:02:06 -0700502 return AMEDIA_ERROR_INVALID_OPERATION;
Chong Zhangb55c5452020-06-26 14:32:12 -0700503 }
504
Chong Zhangbc062482020-10-14 16:43:53 -0700505 if (clientId != mCurrentClientId || sessionId != mCurrentSessionId) {
506 ALOGW("%s: stopping session {%lld, %d} that's not current session {%lld, %d}", __FUNCTION__,
507 (long long)clientId, sessionId, (long long)mCurrentClientId, mCurrentSessionId);
Chong Zhangb55c5452020-06-26 14:32:12 -0700508 }
509
Chong Zhangf9077512020-09-21 21:02:06 -0700510 ALOGI("%s: pausing transcoder", __FUNCTION__);
511
Chong Zhange4e088f2020-10-21 19:10:42 -0700512 std::shared_ptr<ndk::ScopedAParcel> pauseStates;
Chong Zhangb55c5452020-06-26 14:32:12 -0700513 media_status_t err = mTranscoder->pause(&pauseStates);
Linus Nilssona99f4042021-02-25 15:49:43 -0800514 logSessionEnded(TranscodingLogger::SessionEndedReason::PAUSED, err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700515 if (err != AMEDIA_OK) {
516 ALOGE("%s: failed to pause transcoder: %d", __FUNCTION__, err);
Chong Zhangf9077512020-09-21 21:02:06 -0700517 return err;
Chong Zhangb55c5452020-06-26 14:32:12 -0700518 }
Chong Zhangbc062482020-10-14 16:43:53 -0700519 mPausedStateMap[SessionKeyType(clientId, sessionId)] = pauseStates;
Chong Zhangb55c5452020-06-26 14:32:12 -0700520
521 ALOGI("%s: transcoder paused", __FUNCTION__);
Chong Zhangf9077512020-09-21 21:02:06 -0700522 return AMEDIA_OK;
Chong Zhangb55c5452020-06-26 14:32:12 -0700523}
524
Chong Zhangf9077512020-09-21 21:02:06 -0700525media_status_t TranscoderWrapper::handleResume(
Chong Zhangbc062482020-10-14 16:43:53 -0700526 ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
Linus Nilssona99f4042021-02-25 15:49:43 -0800527 uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
Chong Zhange4e088f2020-10-21 19:10:42 -0700528 std::shared_ptr<ndk::ScopedAParcel> pausedState;
Chong Zhangbc062482020-10-14 16:43:53 -0700529 auto it = mPausedStateMap.find(SessionKeyType(clientId, sessionId));
Chong Zhangb55c5452020-06-26 14:32:12 -0700530 if (it != mPausedStateMap.end()) {
531 pausedState = it->second;
532 mPausedStateMap.erase(it);
533 } else {
534 ALOGE("%s: can't find paused state", __FUNCTION__);
Chong Zhangf9077512020-09-21 21:02:06 -0700535 return AMEDIA_ERROR_INVALID_OPERATION;
Chong Zhangb55c5452020-06-26 14:32:12 -0700536 }
537
Chong Zhangf9077512020-09-21 21:02:06 -0700538 ALOGI("%s: setting up transcoder for resume", __FUNCTION__);
Linus Nilssona99f4042021-02-25 15:49:43 -0800539 TranscodingLogger::SessionEndedReason reason = TranscodingLogger::SessionEndedReason::UNKNOWN;
540 media_status_t err = setupTranscoder(clientId, sessionId, request, callingUid, clientCb,
541 &reason, pausedState);
Chong Zhangf9077512020-09-21 21:02:06 -0700542 if (err != AMEDIA_OK) {
543 ALOGE("%s: failed to setup transcoder: %d", __FUNCTION__, err);
Linus Nilssona99f4042021-02-25 15:49:43 -0800544 logSessionEnded(reason, err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700545 return err;
546 }
547
Linus Nilssona99f4042021-02-25 15:49:43 -0800548 // Note: For now resume() will just restart transcoding from the beginning, so there is no need
549 // to distinguish between resume and start from a performance perspective.
550 mTranscodeStartTime = std::chrono::steady_clock::now();
551
Chong Zhangf9077512020-09-21 21:02:06 -0700552 err = mTranscoder->resume();
553 if (err != AMEDIA_OK) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700554 ALOGE("%s: failed to resume transcoder: %d", __FUNCTION__, err);
Linus Nilssona99f4042021-02-25 15:49:43 -0800555 logSessionEnded(TranscodingLogger::SessionEndedReason::RESUME_FAILED, err);
Chong Zhangf9077512020-09-21 21:02:06 -0700556 return err;
Chong Zhangb55c5452020-06-26 14:32:12 -0700557 }
558
559 ALOGI("%s: transcoder resumed", __FUNCTION__);
Chong Zhangf9077512020-09-21 21:02:06 -0700560 return AMEDIA_OK;
Chong Zhang66469272020-06-04 16:51:55 -0700561}
562
563void TranscoderWrapper::cleanup() {
564 mCurrentClientId = 0;
Chong Zhangbc062482020-10-14 16:43:53 -0700565 mCurrentSessionId = -1;
Linus Nilssona99f4042021-02-25 15:49:43 -0800566 mCurrentCallingUid = -1;
Chong Zhang66469272020-06-04 16:51:55 -0700567 mTranscoderCb = nullptr;
568 mTranscoder = nullptr;
Linus Nilssona99f4042021-02-25 15:49:43 -0800569 mSrcFormat = nullptr;
570 mDstFormat = nullptr;
571}
572
573void TranscoderWrapper::logSessionEnded(const TranscodingLogger::SessionEndedReason& reason,
574 int error) {
575 std::chrono::microseconds transcodeDuration(-1);
576 if (reason == TranscodingLogger::SessionEndedReason::FINISHED && error == AMEDIA_OK) {
577 transcodeDuration = std::chrono::duration_cast<std::chrono::microseconds>(
578 std::chrono::steady_clock::now() - mTranscodeStartTime);
579 }
580
581 mLogger->logSessionEnded(reason, mCurrentCallingUid, error, transcodeDuration, mSrcFormat.get(),
582 mDstFormat.get());
Chong Zhang66469272020-06-04 16:51:55 -0700583}
584
Chong Zhangbc062482020-10-14 16:43:53 -0700585void TranscoderWrapper::queueEvent(Event::Type type, ClientIdType clientId, SessionIdType sessionId,
Chong Zhangf9077512020-09-21 21:02:06 -0700586 const std::function<void()> runnable, int32_t arg) {
Chong Zhang66469272020-06-04 16:51:55 -0700587 std::scoped_lock lock{mLock};
588
Chong Zhang457c6892021-02-01 15:34:20 -0800589 if (!mLooperReady) {
590 // A shared_ptr to ourselves is given to the thread's stack, so that the TranscoderWrapper
591 // object doesn't go away until the thread exits. When a watchdog timeout happens, this
592 // allows the session controller to release its reference to the TranscoderWrapper object
593 // without blocking on the thread exits.
594 std::thread([owner = shared_from_this()]() { owner->threadLoop(); }).detach();
595 mLooperReady = true;
596 }
597
Chong Zhangbc062482020-10-14 16:43:53 -0700598 mQueue.push_back({type, clientId, sessionId, runnable, arg});
Chong Zhang66469272020-06-04 16:51:55 -0700599 mCondition.notify_one();
600}
601
602void TranscoderWrapper::threadLoop() {
Chong Zhang45a31632021-04-22 16:15:19 -0700603 androidSetThreadPriority(0 /*tid (0 = current) */, ANDROID_PRIORITY_BACKGROUND);
Chong Zhang66469272020-06-04 16:51:55 -0700604 std::unique_lock<std::mutex> lock{mLock};
605 // TranscoderWrapper currently lives in the transcoding service, as long as
606 // MediaTranscodingService itself.
607 while (true) {
608 // Wait for the next event.
609 while (mQueue.empty()) {
610 mCondition.wait(lock);
611 }
612
613 Event event = *mQueue.begin();
614 mQueue.pop_front();
615
Chong Zhangf9077512020-09-21 21:02:06 -0700616 ALOGD("%s: %s", __FUNCTION__, toString(event).c_str());
Chong Zhang66469272020-06-04 16:51:55 -0700617
Chong Zhang457c6892021-02-01 15:34:20 -0800618 if (event.type == Event::Abandon) {
619 break;
620 }
621
Chong Zhangb55c5452020-06-26 14:32:12 -0700622 lock.unlock();
Chong Zhang66469272020-06-04 16:51:55 -0700623 event.runnable();
Chong Zhangb55c5452020-06-26 14:32:12 -0700624 lock.lock();
Chong Zhang66469272020-06-04 16:51:55 -0700625 }
626}
Chong Zhang66469272020-06-04 16:51:55 -0700627} // namespace android