blob: d9c98c6f5eb41d468209c4974769a15a0bfa53e1 [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>
25#include <utils/Log.h>
26
27#include <thread>
28
29namespace android {
30using Status = ::ndk::ScopedAStatus;
31using ::aidl::android::media::TranscodingErrorCode;
32using ::aidl::android::media::TranscodingVideoCodecType;
33using ::aidl::android::media::TranscodingVideoTrackFormat;
34
35static TranscodingErrorCode toTranscodingError(media_status_t status) {
36 switch (status) {
37 case AMEDIA_OK:
38 return TranscodingErrorCode::kNoError;
39 case AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE: // FALLTHRU
40 case AMEDIACODEC_ERROR_RECLAIMED:
41 return TranscodingErrorCode::kInsufficientResources;
42 case AMEDIA_ERROR_MALFORMED:
43 return TranscodingErrorCode::kMalformed;
44 case AMEDIA_ERROR_UNSUPPORTED:
45 return TranscodingErrorCode::kUnsupported;
46 case AMEDIA_ERROR_INVALID_OBJECT: // FALLTHRU
47 case AMEDIA_ERROR_INVALID_PARAMETER:
48 return TranscodingErrorCode::kInvalidParameter;
49 case AMEDIA_ERROR_INVALID_OPERATION:
50 return TranscodingErrorCode::kInvalidOperation;
51 case AMEDIA_ERROR_IO:
52 return TranscodingErrorCode::kErrorIO;
53 case AMEDIA_ERROR_UNKNOWN: // FALLTHRU
54 default:
55 return TranscodingErrorCode::kUnknown;
56 }
57}
58
Linus Nilssona99f4042021-02-25 15:49:43 -080059static std::shared_ptr<AMediaFormat> getVideoFormat(
Chong Zhangb55c5452020-06-26 14:32:12 -070060 const char* originalMime,
61 const std::optional<TranscodingVideoTrackFormat>& requestedFormat) {
62 if (requestedFormat == std::nullopt) {
63 return nullptr;
64 }
65
Linus Nilssona99f4042021-02-25 15:49:43 -080066 std::shared_ptr<AMediaFormat> format =
67 std::shared_ptr<AMediaFormat>(AMediaFormat_new(), &AMediaFormat_delete);
Chong Zhangb55c5452020-06-26 14:32:12 -070068 bool changed = false;
69 if (requestedFormat->codecType == TranscodingVideoCodecType::kHevc &&
70 strcmp(originalMime, AMEDIA_MIMETYPE_VIDEO_HEVC)) {
Linus Nilssona99f4042021-02-25 15:49:43 -080071 AMediaFormat_setString(format.get(), AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_HEVC);
Chong Zhangb55c5452020-06-26 14:32:12 -070072 changed = true;
73 } else if (requestedFormat->codecType == TranscodingVideoCodecType::kAvc &&
74 strcmp(originalMime, AMEDIA_MIMETYPE_VIDEO_AVC)) {
Linus Nilssona99f4042021-02-25 15:49:43 -080075 AMediaFormat_setString(format.get(), AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_AVC);
Chong Zhangb55c5452020-06-26 14:32:12 -070076 changed = true;
77 }
78 if (requestedFormat->bitrateBps > 0) {
Linus Nilssona99f4042021-02-25 15:49:43 -080079 AMediaFormat_setInt32(format.get(), AMEDIAFORMAT_KEY_BIT_RATE, requestedFormat->bitrateBps);
Chong Zhangb55c5452020-06-26 14:32:12 -070080 changed = true;
81 }
82 // TODO: translate other fields from requestedFormat to the format for MediaTranscoder.
83 // Also need to determine more settings to expose in TranscodingVideoTrackFormat.
84 if (!changed) {
Chong Zhangb55c5452020-06-26 14:32:12 -070085 // Use null format for passthru.
Linus Nilssona99f4042021-02-25 15:49:43 -080086 format.reset();
Chong Zhangb55c5452020-06-26 14:32:12 -070087 }
88 return format;
89}
90
Chong Zhang66469272020-06-04 16:51:55 -070091//static
Chong Zhangf9077512020-09-21 21:02:06 -070092std::string TranscoderWrapper::toString(const Event& event) {
93 std::string typeStr;
94 switch (event.type) {
Chong Zhang66469272020-06-04 16:51:55 -070095 case Event::Start:
Chong Zhangf9077512020-09-21 21:02:06 -070096 typeStr = "Start";
Chong Zhang66469272020-06-04 16:51:55 -070097 break;
Chong Zhangf9077512020-09-21 21:02:06 -070098 case Event::Pause:
99 typeStr = "Pause";
100 break;
101 case Event::Resume:
102 typeStr = "Resume";
103 break;
104 case Event::Stop:
105 typeStr = "Stop";
106 break;
107 case Event::Finish:
108 typeStr = "Finish";
109 break;
110 case Event::Error:
111 typeStr = "Error";
112 break;
113 case Event::Progress:
114 typeStr = "Progress";
115 break;
Chong Zhang457c6892021-02-01 15:34:20 -0800116 case Event::HeartBeat:
117 typeStr = "HeartBeat";
118 break;
119 case Event::Abandon:
120 typeStr = "Abandon";
121 break;
Chong Zhangf9077512020-09-21 21:02:06 -0700122 default:
123 return "(unknown)";
Chong Zhang66469272020-06-04 16:51:55 -0700124 }
Chong Zhangf9077512020-09-21 21:02:06 -0700125 std::string result;
Chong Zhangbc062482020-10-14 16:43:53 -0700126 result = "session {" + std::to_string(event.clientId) + "," + std::to_string(event.sessionId) +
Chong Zhangf9077512020-09-21 21:02:06 -0700127 "}: " + typeStr;
128 if (event.type == Event::Error || event.type == Event::Progress) {
129 result += " " + std::to_string(event.arg);
130 }
131 return result;
Chong Zhang66469272020-06-04 16:51:55 -0700132}
133
134class TranscoderWrapper::CallbackImpl : public MediaTranscoder::CallbackInterface {
135public:
136 CallbackImpl(const std::shared_ptr<TranscoderWrapper>& owner, ClientIdType clientId,
Chong Zhangbc062482020-10-14 16:43:53 -0700137 SessionIdType sessionId)
138 : mOwner(owner), mClientId(clientId), mSessionId(sessionId) {}
Chong Zhang66469272020-06-04 16:51:55 -0700139
140 virtual void onFinished(const MediaTranscoder* transcoder __unused) override {
141 auto owner = mOwner.lock();
142 if (owner != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700143 owner->onFinish(mClientId, mSessionId);
Chong Zhang66469272020-06-04 16:51:55 -0700144 }
145 }
146
147 virtual void onError(const MediaTranscoder* transcoder __unused,
148 media_status_t error) override {
149 auto owner = mOwner.lock();
150 if (owner != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700151 owner->onError(mClientId, mSessionId, error);
Chong Zhang66469272020-06-04 16:51:55 -0700152 }
153 }
154
155 virtual void onProgressUpdate(const MediaTranscoder* transcoder __unused,
156 int32_t progress) override {
Chong Zhang98b8a372020-07-08 17:27:37 -0700157 auto owner = mOwner.lock();
158 if (owner != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700159 owner->onProgress(mClientId, mSessionId, progress);
Chong Zhang98b8a372020-07-08 17:27:37 -0700160 }
Chong Zhang66469272020-06-04 16:51:55 -0700161 }
162
Chong Zhang457c6892021-02-01 15:34:20 -0800163 virtual void onHeartBeat(const MediaTranscoder* transcoder __unused) override {
164 auto owner = mOwner.lock();
165 if (owner != nullptr) {
166 owner->onHeartBeat(mClientId, mSessionId);
167 }
168 }
169
Chong Zhang66469272020-06-04 16:51:55 -0700170 virtual void onCodecResourceLost(const MediaTranscoder* transcoder __unused,
Chong Zhange4e088f2020-10-21 19:10:42 -0700171 const std::shared_ptr<ndk::ScopedAParcel>& pausedState
Chong Zhang66469272020-06-04 16:51:55 -0700172 __unused) override {
Chong Zhangbc062482020-10-14 16:43:53 -0700173 ALOGV("%s: session {%lld, %d}", __FUNCTION__, (long long)mClientId, mSessionId);
Chong Zhang66469272020-06-04 16:51:55 -0700174 }
175
176private:
177 std::weak_ptr<TranscoderWrapper> mOwner;
178 ClientIdType mClientId;
Chong Zhangbc062482020-10-14 16:43:53 -0700179 SessionIdType mSessionId;
Chong Zhang66469272020-06-04 16:51:55 -0700180};
181
Chong Zhang457c6892021-02-01 15:34:20 -0800182TranscoderWrapper::TranscoderWrapper(const std::shared_ptr<TranscoderCallbackInterface>& cb,
Linus Nilssona99f4042021-02-25 15:49:43 -0800183 const std::shared_ptr<TranscodingLogger>& logger,
Chong Zhang457c6892021-02-01 15:34:20 -0800184 int64_t heartBeatIntervalUs)
185 : mCallback(cb),
Linus Nilssona99f4042021-02-25 15:49:43 -0800186 mLogger(logger),
Chong Zhang457c6892021-02-01 15:34:20 -0800187 mHeartBeatIntervalUs(heartBeatIntervalUs),
188 mCurrentClientId(0),
189 mCurrentSessionId(-1),
190 mLooperReady(false) {
191 ALOGV("TranscoderWrapper CTOR: %p", this);
Chong Zhang66469272020-06-04 16:51:55 -0700192}
193
Chong Zhang457c6892021-02-01 15:34:20 -0800194TranscoderWrapper::~TranscoderWrapper() {
195 ALOGV("TranscoderWrapper DTOR: %p", this);
Chong Zhang66469272020-06-04 16:51:55 -0700196}
197
Chong Zhangf9077512020-09-21 21:02:06 -0700198static bool isResourceError(media_status_t err) {
199 return err == AMEDIACODEC_ERROR_RECLAIMED || err == AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE;
200}
201
Chong Zhangbc062482020-10-14 16:43:53 -0700202void TranscoderWrapper::reportError(ClientIdType clientId, SessionIdType sessionId,
203 media_status_t err) {
Chong Zhangf9077512020-09-21 21:02:06 -0700204 auto callback = mCallback.lock();
205 if (callback != nullptr) {
206 if (isResourceError(err)) {
207 // Add a placeholder pause state to mPausedStateMap. This is required when resuming.
208 // TODO: remove this when transcoder pause/resume logic is ready. New logic will
209 // no longer use the pause states.
Chong Zhangbc062482020-10-14 16:43:53 -0700210 auto it = mPausedStateMap.find(SessionKeyType(clientId, sessionId));
Chong Zhangf9077512020-09-21 21:02:06 -0700211 if (it == mPausedStateMap.end()) {
Chong Zhangbc062482020-10-14 16:43:53 -0700212 mPausedStateMap.emplace(SessionKeyType(clientId, sessionId),
Chong Zhange4e088f2020-10-21 19:10:42 -0700213 new ndk::ScopedAParcel());
Chong Zhangf9077512020-09-21 21:02:06 -0700214 }
215
Chong Zhangeffd8962020-12-02 14:29:09 -0800216 callback->onResourceLost(clientId, sessionId);
Chong Zhangf9077512020-09-21 21:02:06 -0700217 } else {
Chong Zhangbc062482020-10-14 16:43:53 -0700218 callback->onError(clientId, sessionId, toTranscodingError(err));
Chong Zhangf9077512020-09-21 21:02:06 -0700219 }
220 }
221}
222
Chong Zhangbc062482020-10-14 16:43:53 -0700223void TranscoderWrapper::start(ClientIdType clientId, SessionIdType sessionId,
Linus Nilssona99f4042021-02-25 15:49:43 -0800224 const TranscodingRequestParcel& request, uid_t callingUid,
Chong Zhangb55c5452020-06-26 14:32:12 -0700225 const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
hkuang34377c32020-09-24 22:28:27 -0700226 queueEvent(Event::Start, clientId, sessionId, [=, &request] {
Linus Nilssona99f4042021-02-25 15:49:43 -0800227 media_status_t err = handleStart(clientId, sessionId, request, callingUid, clientCb);
Chong Zhangf9077512020-09-21 21:02:06 -0700228 if (err != AMEDIA_OK) {
Chong Zhang66469272020-06-04 16:51:55 -0700229 cleanup();
Chong Zhangbc062482020-10-14 16:43:53 -0700230 reportError(clientId, sessionId, err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700231 } else {
Chong Zhangf9077512020-09-21 21:02:06 -0700232 auto callback = mCallback.lock();
Chong Zhangb55c5452020-06-26 14:32:12 -0700233 if (callback != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700234 callback->onStarted(clientId, sessionId);
Chong Zhangb55c5452020-06-26 14:32:12 -0700235 }
Chong Zhang66469272020-06-04 16:51:55 -0700236 }
237 });
238}
239
Chong Zhangbc062482020-10-14 16:43:53 -0700240void TranscoderWrapper::pause(ClientIdType clientId, SessionIdType sessionId) {
241 queueEvent(Event::Pause, clientId, sessionId, [=] {
242 media_status_t err = handlePause(clientId, sessionId);
Chong Zhangb55c5452020-06-26 14:32:12 -0700243
244 cleanup();
245
Chong Zhangf9077512020-09-21 21:02:06 -0700246 if (err != AMEDIA_OK) {
Chong Zhangbc062482020-10-14 16:43:53 -0700247 reportError(clientId, sessionId, err);
Chong Zhangf9077512020-09-21 21:02:06 -0700248 } else {
249 auto callback = mCallback.lock();
250 if (callback != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700251 callback->onPaused(clientId, sessionId);
Chong Zhangb55c5452020-06-26 14:32:12 -0700252 }
253 }
254 });
Chong Zhang66469272020-06-04 16:51:55 -0700255}
256
Chong Zhangbc062482020-10-14 16:43:53 -0700257void TranscoderWrapper::resume(ClientIdType clientId, SessionIdType sessionId,
Linus Nilssona99f4042021-02-25 15:49:43 -0800258 const TranscodingRequestParcel& request, uid_t callingUid,
Chong Zhangb55c5452020-06-26 14:32:12 -0700259 const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
hkuang34377c32020-09-24 22:28:27 -0700260 queueEvent(Event::Resume, clientId, sessionId, [=, &request] {
Linus Nilssona99f4042021-02-25 15:49:43 -0800261 media_status_t err = handleResume(clientId, sessionId, request, callingUid, clientCb);
Chong Zhangf9077512020-09-21 21:02:06 -0700262 if (err != AMEDIA_OK) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700263 cleanup();
Chong Zhangbc062482020-10-14 16:43:53 -0700264 reportError(clientId, sessionId, err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700265 } else {
Chong Zhangf9077512020-09-21 21:02:06 -0700266 auto callback = mCallback.lock();
Chong Zhangb55c5452020-06-26 14:32:12 -0700267 if (callback != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700268 callback->onResumed(clientId, sessionId);
Chong Zhangb55c5452020-06-26 14:32:12 -0700269 }
270 }
271 });
Chong Zhang66469272020-06-04 16:51:55 -0700272}
273
Chong Zhang457c6892021-02-01 15:34:20 -0800274void TranscoderWrapper::stop(ClientIdType clientId, SessionIdType sessionId, bool abandon) {
Chong Zhangbc062482020-10-14 16:43:53 -0700275 queueEvent(Event::Stop, clientId, sessionId, [=] {
276 if (mTranscoder != nullptr && clientId == mCurrentClientId &&
277 sessionId == mCurrentSessionId) {
278 // Cancelling the currently running session.
Chong Zhangb55c5452020-06-26 14:32:12 -0700279 media_status_t err = mTranscoder->cancel();
280 if (err != AMEDIA_OK) {
Chong Zhangf9077512020-09-21 21:02:06 -0700281 ALOGW("failed to stop transcoder: %d", err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700282 } else {
283 ALOGI("transcoder stopped");
284 }
Linus Nilssona99f4042021-02-25 15:49:43 -0800285 logSessionEnded(TranscodingLogger::SessionEndedReason::CANCELLED, err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700286 cleanup();
Chong Zhang66469272020-06-04 16:51:55 -0700287 } else {
Chong Zhangbc062482020-10-14 16:43:53 -0700288 // For sessions that's not currently running, release any pausedState for the session.
289 mPausedStateMap.erase(SessionKeyType(clientId, sessionId));
Chong Zhang66469272020-06-04 16:51:55 -0700290 }
Chong Zhangb55c5452020-06-26 14:32:12 -0700291 // No callback needed for stop.
Chong Zhang66469272020-06-04 16:51:55 -0700292 });
Chong Zhang457c6892021-02-01 15:34:20 -0800293
294 if (abandon) {
295 queueEvent(Event::Abandon, 0, 0, nullptr);
296 }
Chong Zhang66469272020-06-04 16:51:55 -0700297}
298
Chong Zhangbc062482020-10-14 16:43:53 -0700299void TranscoderWrapper::onFinish(ClientIdType clientId, SessionIdType sessionId) {
300 queueEvent(Event::Finish, clientId, sessionId, [=] {
301 if (mTranscoder != nullptr && clientId == mCurrentClientId &&
302 sessionId == mCurrentSessionId) {
Linus Nilssona99f4042021-02-25 15:49:43 -0800303 logSessionEnded(TranscodingLogger::SessionEndedReason::FINISHED, AMEDIA_OK);
Chong Zhangb55c5452020-06-26 14:32:12 -0700304 cleanup();
305 }
Chong Zhang66469272020-06-04 16:51:55 -0700306
307 auto callback = mCallback.lock();
308 if (callback != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700309 callback->onFinish(clientId, sessionId);
Chong Zhang66469272020-06-04 16:51:55 -0700310 }
311 });
312}
313
Chong Zhangbc062482020-10-14 16:43:53 -0700314void TranscoderWrapper::onError(ClientIdType clientId, SessionIdType sessionId,
315 media_status_t error) {
Chong Zhangf9077512020-09-21 21:02:06 -0700316 queueEvent(
Chong Zhangbc062482020-10-14 16:43:53 -0700317 Event::Error, clientId, sessionId,
Chong Zhangf9077512020-09-21 21:02:06 -0700318 [=] {
319 if (mTranscoder != nullptr && clientId == mCurrentClientId &&
Chong Zhangbc062482020-10-14 16:43:53 -0700320 sessionId == mCurrentSessionId) {
Linus Nilssona99f4042021-02-25 15:49:43 -0800321 logSessionEnded(TranscodingLogger::SessionEndedReason::ERROR, error);
Chong Zhangf9077512020-09-21 21:02:06 -0700322 cleanup();
323 }
Chong Zhangbc062482020-10-14 16:43:53 -0700324 reportError(clientId, sessionId, error);
Chong Zhangf9077512020-09-21 21:02:06 -0700325 },
326 error);
Chong Zhang66469272020-06-04 16:51:55 -0700327}
328
Chong Zhangbc062482020-10-14 16:43:53 -0700329void TranscoderWrapper::onProgress(ClientIdType clientId, SessionIdType sessionId,
330 int32_t progress) {
Chong Zhangf9077512020-09-21 21:02:06 -0700331 queueEvent(
Chong Zhangbc062482020-10-14 16:43:53 -0700332 Event::Progress, clientId, sessionId,
Chong Zhangf9077512020-09-21 21:02:06 -0700333 [=] {
334 auto callback = mCallback.lock();
335 if (callback != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700336 callback->onProgressUpdate(clientId, sessionId, progress);
Chong Zhangf9077512020-09-21 21:02:06 -0700337 }
338 },
339 progress);
Chong Zhang98b8a372020-07-08 17:27:37 -0700340}
341
Chong Zhang457c6892021-02-01 15:34:20 -0800342void TranscoderWrapper::onHeartBeat(ClientIdType clientId, SessionIdType sessionId) {
343 queueEvent(Event::HeartBeat, clientId, sessionId, [=] {
344 auto callback = mCallback.lock();
345 if (callback != nullptr) {
346 callback->onHeartBeat(clientId, sessionId);
347 }
348 });
349}
350
Chong Zhangf9077512020-09-21 21:02:06 -0700351media_status_t TranscoderWrapper::setupTranscoder(
Chong Zhangbc062482020-10-14 16:43:53 -0700352 ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
Linus Nilssona99f4042021-02-25 15:49:43 -0800353 uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& clientCb,
354 TranscodingLogger::SessionEndedReason* failureReason,
Chong Zhange4e088f2020-10-21 19:10:42 -0700355 const std::shared_ptr<ndk::ScopedAParcel>& pausedState) {
Chong Zhang66469272020-06-04 16:51:55 -0700356 if (clientCb == nullptr) {
357 ALOGE("client callback is null");
Chong Zhangf9077512020-09-21 21:02:06 -0700358 return AMEDIA_ERROR_INVALID_PARAMETER;
Chong Zhang66469272020-06-04 16:51:55 -0700359 }
360
361 if (mTranscoder != nullptr) {
362 ALOGE("transcoder already running");
Chong Zhangf9077512020-09-21 21:02:06 -0700363 return AMEDIA_ERROR_INVALID_OPERATION;
Chong Zhang66469272020-06-04 16:51:55 -0700364 }
365
366 Status status;
367 ::ndk::ScopedFileDescriptor srcFd, dstFd;
hkuang34377c32020-09-24 22:28:27 -0700368 int srcFdInt = request.sourceFd.get();
369 if (srcFdInt < 0) {
370 status = clientCb->openFileDescriptor(request.sourceFilePath, "r", &srcFd);
371 if (!status.isOk() || srcFd.get() < 0) {
372 ALOGE("failed to open source");
Linus Nilssona99f4042021-02-25 15:49:43 -0800373 *failureReason = TranscodingLogger::SessionEndedReason::OPEN_SRC_FD_FAILED;
hkuang34377c32020-09-24 22:28:27 -0700374 return AMEDIA_ERROR_IO;
375 }
376 srcFdInt = srcFd.get();
Chong Zhang66469272020-06-04 16:51:55 -0700377 }
378
hkuang34377c32020-09-24 22:28:27 -0700379 int dstFdInt = request.destinationFd.get();
380 if (dstFdInt < 0) {
381 // Open dest file with "rw", as the transcoder could potentially reuse part of it
382 // for resume case. We might want the further differentiate and open with "w" only
383 // for start.
384 status = clientCb->openFileDescriptor(request.destinationFilePath, "rw", &dstFd);
385 if (!status.isOk() || dstFd.get() < 0) {
386 ALOGE("failed to open destination");
Linus Nilssona99f4042021-02-25 15:49:43 -0800387 *failureReason = TranscodingLogger::SessionEndedReason::OPEN_DST_FD_FAILED;
hkuang34377c32020-09-24 22:28:27 -0700388 return AMEDIA_ERROR_IO;
389 }
390 dstFdInt = dstFd.get();
Chong Zhang66469272020-06-04 16:51:55 -0700391 }
392
393 mCurrentClientId = clientId;
Chong Zhangbc062482020-10-14 16:43:53 -0700394 mCurrentSessionId = sessionId;
Linus Nilssona99f4042021-02-25 15:49:43 -0800395 mCurrentCallingUid = callingUid;
Chong Zhangbc062482020-10-14 16:43:53 -0700396 mTranscoderCb = std::make_shared<CallbackImpl>(shared_from_this(), clientId, sessionId);
Chong Zhang457c6892021-02-01 15:34:20 -0800397 mTranscoder = MediaTranscoder::create(mTranscoderCb, mHeartBeatIntervalUs, request.clientPid,
398 request.clientUid, pausedState);
Chong Zhang66469272020-06-04 16:51:55 -0700399 if (mTranscoder == nullptr) {
400 ALOGE("failed to create transcoder");
Linus Nilssona99f4042021-02-25 15:49:43 -0800401 *failureReason = TranscodingLogger::SessionEndedReason::CREATE_FAILED;
Chong Zhangf9077512020-09-21 21:02:06 -0700402 return AMEDIA_ERROR_UNKNOWN;
Chong Zhang66469272020-06-04 16:51:55 -0700403 }
404
hkuang34377c32020-09-24 22:28:27 -0700405 media_status_t err = mTranscoder->configureSource(srcFdInt);
Chong Zhang66469272020-06-04 16:51:55 -0700406 if (err != AMEDIA_OK) {
407 ALOGE("failed to configure source: %d", err);
Linus Nilssona99f4042021-02-25 15:49:43 -0800408 *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_SRC_FAILED;
Chong Zhangf9077512020-09-21 21:02:06 -0700409 return err;
Chong Zhang66469272020-06-04 16:51:55 -0700410 }
411
412 std::vector<std::shared_ptr<AMediaFormat>> trackFormats = mTranscoder->getTrackFormats();
413 if (trackFormats.size() == 0) {
414 ALOGE("failed to get track formats!");
Linus Nilssona99f4042021-02-25 15:49:43 -0800415 *failureReason = TranscodingLogger::SessionEndedReason::NO_TRACKS;
Chong Zhangf9077512020-09-21 21:02:06 -0700416 return AMEDIA_ERROR_MALFORMED;
Chong Zhang66469272020-06-04 16:51:55 -0700417 }
418
419 for (int i = 0; i < trackFormats.size(); ++i) {
Linus Nilssona99f4042021-02-25 15:49:43 -0800420 std::shared_ptr<AMediaFormat> format;
Chong Zhang66469272020-06-04 16:51:55 -0700421 const char* mime = nullptr;
422 AMediaFormat_getString(trackFormats[i].get(), AMEDIAFORMAT_KEY_MIME, &mime);
423
424 if (!strncmp(mime, "video/", 6)) {
425 format = getVideoFormat(mime, request.requestedVideoTrackFormat);
Linus Nilssona99f4042021-02-25 15:49:43 -0800426
427 mSrcFormat = trackFormats[i];
428 mDstFormat = format;
Chong Zhang66469272020-06-04 16:51:55 -0700429 }
430
Linus Nilssona99f4042021-02-25 15:49:43 -0800431 err = mTranscoder->configureTrackFormat(i, format.get());
Chong Zhang66469272020-06-04 16:51:55 -0700432 if (err != AMEDIA_OK) {
433 ALOGE("failed to configure track format for track %d: %d", i, err);
Linus Nilssona99f4042021-02-25 15:49:43 -0800434 *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_TRACK_FAILED;
Chong Zhangf9077512020-09-21 21:02:06 -0700435 return err;
Chong Zhang66469272020-06-04 16:51:55 -0700436 }
437 }
438
hkuang34377c32020-09-24 22:28:27 -0700439 err = mTranscoder->configureDestination(dstFdInt);
Chong Zhang66469272020-06-04 16:51:55 -0700440 if (err != AMEDIA_OK) {
441 ALOGE("failed to configure dest: %d", err);
Linus Nilssona99f4042021-02-25 15:49:43 -0800442 *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_DST_FAILED;
Chong Zhangf9077512020-09-21 21:02:06 -0700443 return err;
Chong Zhang66469272020-06-04 16:51:55 -0700444 }
445
Chong Zhangf9077512020-09-21 21:02:06 -0700446 return AMEDIA_OK;
Chong Zhangb55c5452020-06-26 14:32:12 -0700447}
448
Chong Zhangf9077512020-09-21 21:02:06 -0700449media_status_t TranscoderWrapper::handleStart(
Chong Zhangbc062482020-10-14 16:43:53 -0700450 ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
Linus Nilssona99f4042021-02-25 15:49:43 -0800451 uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
Chong Zhangf9077512020-09-21 21:02:06 -0700452 ALOGI("%s: setting up transcoder for start", __FUNCTION__);
Linus Nilssona99f4042021-02-25 15:49:43 -0800453 TranscodingLogger::SessionEndedReason reason = TranscodingLogger::SessionEndedReason::UNKNOWN;
454 media_status_t err =
455 setupTranscoder(clientId, sessionId, request, callingUid, clientCb, &reason);
Chong Zhangf9077512020-09-21 21:02:06 -0700456 if (err != AMEDIA_OK) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700457 ALOGI("%s: failed to setup transcoder", __FUNCTION__);
Linus Nilssona99f4042021-02-25 15:49:43 -0800458 logSessionEnded(reason, err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700459 return err;
Chong Zhang66469272020-06-04 16:51:55 -0700460 }
461
Linus Nilssona99f4042021-02-25 15:49:43 -0800462 mTranscodeStartTime = std::chrono::steady_clock::now();
463
Chong Zhangf9077512020-09-21 21:02:06 -0700464 err = mTranscoder->start();
465 if (err != AMEDIA_OK) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700466 ALOGE("%s: failed to start transcoder: %d", __FUNCTION__, err);
Linus Nilssona99f4042021-02-25 15:49:43 -0800467 logSessionEnded(TranscodingLogger::SessionEndedReason::START_FAILED, err);
Chong Zhangf9077512020-09-21 21:02:06 -0700468 return err;
Chong Zhangb55c5452020-06-26 14:32:12 -0700469 }
470
471 ALOGI("%s: transcoder started", __FUNCTION__);
Chong Zhangf9077512020-09-21 21:02:06 -0700472 return AMEDIA_OK;
Chong Zhangb55c5452020-06-26 14:32:12 -0700473}
474
Chong Zhangbc062482020-10-14 16:43:53 -0700475media_status_t TranscoderWrapper::handlePause(ClientIdType clientId, SessionIdType sessionId) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700476 if (mTranscoder == nullptr) {
477 ALOGE("%s: transcoder is not running", __FUNCTION__);
Chong Zhangf9077512020-09-21 21:02:06 -0700478 return AMEDIA_ERROR_INVALID_OPERATION;
Chong Zhangb55c5452020-06-26 14:32:12 -0700479 }
480
Chong Zhangbc062482020-10-14 16:43:53 -0700481 if (clientId != mCurrentClientId || sessionId != mCurrentSessionId) {
482 ALOGW("%s: stopping session {%lld, %d} that's not current session {%lld, %d}", __FUNCTION__,
483 (long long)clientId, sessionId, (long long)mCurrentClientId, mCurrentSessionId);
Chong Zhangb55c5452020-06-26 14:32:12 -0700484 }
485
Chong Zhangf9077512020-09-21 21:02:06 -0700486 ALOGI("%s: pausing transcoder", __FUNCTION__);
487
Chong Zhange4e088f2020-10-21 19:10:42 -0700488 std::shared_ptr<ndk::ScopedAParcel> pauseStates;
Chong Zhangb55c5452020-06-26 14:32:12 -0700489 media_status_t err = mTranscoder->pause(&pauseStates);
Linus Nilssona99f4042021-02-25 15:49:43 -0800490 logSessionEnded(TranscodingLogger::SessionEndedReason::PAUSED, err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700491 if (err != AMEDIA_OK) {
492 ALOGE("%s: failed to pause transcoder: %d", __FUNCTION__, err);
Chong Zhangf9077512020-09-21 21:02:06 -0700493 return err;
Chong Zhangb55c5452020-06-26 14:32:12 -0700494 }
Chong Zhangbc062482020-10-14 16:43:53 -0700495 mPausedStateMap[SessionKeyType(clientId, sessionId)] = pauseStates;
Chong Zhangb55c5452020-06-26 14:32:12 -0700496
497 ALOGI("%s: transcoder paused", __FUNCTION__);
Chong Zhangf9077512020-09-21 21:02:06 -0700498 return AMEDIA_OK;
Chong Zhangb55c5452020-06-26 14:32:12 -0700499}
500
Chong Zhangf9077512020-09-21 21:02:06 -0700501media_status_t TranscoderWrapper::handleResume(
Chong Zhangbc062482020-10-14 16:43:53 -0700502 ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
Linus Nilssona99f4042021-02-25 15:49:43 -0800503 uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
Chong Zhange4e088f2020-10-21 19:10:42 -0700504 std::shared_ptr<ndk::ScopedAParcel> pausedState;
Chong Zhangbc062482020-10-14 16:43:53 -0700505 auto it = mPausedStateMap.find(SessionKeyType(clientId, sessionId));
Chong Zhangb55c5452020-06-26 14:32:12 -0700506 if (it != mPausedStateMap.end()) {
507 pausedState = it->second;
508 mPausedStateMap.erase(it);
509 } else {
510 ALOGE("%s: can't find paused state", __FUNCTION__);
Chong Zhangf9077512020-09-21 21:02:06 -0700511 return AMEDIA_ERROR_INVALID_OPERATION;
Chong Zhangb55c5452020-06-26 14:32:12 -0700512 }
513
Chong Zhangf9077512020-09-21 21:02:06 -0700514 ALOGI("%s: setting up transcoder for resume", __FUNCTION__);
Linus Nilssona99f4042021-02-25 15:49:43 -0800515 TranscodingLogger::SessionEndedReason reason = TranscodingLogger::SessionEndedReason::UNKNOWN;
516 media_status_t err = setupTranscoder(clientId, sessionId, request, callingUid, clientCb,
517 &reason, pausedState);
Chong Zhangf9077512020-09-21 21:02:06 -0700518 if (err != AMEDIA_OK) {
519 ALOGE("%s: failed to setup transcoder: %d", __FUNCTION__, err);
Linus Nilssona99f4042021-02-25 15:49:43 -0800520 logSessionEnded(reason, err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700521 return err;
522 }
523
Linus Nilssona99f4042021-02-25 15:49:43 -0800524 // Note: For now resume() will just restart transcoding from the beginning, so there is no need
525 // to distinguish between resume and start from a performance perspective.
526 mTranscodeStartTime = std::chrono::steady_clock::now();
527
Chong Zhangf9077512020-09-21 21:02:06 -0700528 err = mTranscoder->resume();
529 if (err != AMEDIA_OK) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700530 ALOGE("%s: failed to resume transcoder: %d", __FUNCTION__, err);
Linus Nilssona99f4042021-02-25 15:49:43 -0800531 logSessionEnded(TranscodingLogger::SessionEndedReason::RESUME_FAILED, err);
Chong Zhangf9077512020-09-21 21:02:06 -0700532 return err;
Chong Zhangb55c5452020-06-26 14:32:12 -0700533 }
534
535 ALOGI("%s: transcoder resumed", __FUNCTION__);
Chong Zhangf9077512020-09-21 21:02:06 -0700536 return AMEDIA_OK;
Chong Zhang66469272020-06-04 16:51:55 -0700537}
538
539void TranscoderWrapper::cleanup() {
540 mCurrentClientId = 0;
Chong Zhangbc062482020-10-14 16:43:53 -0700541 mCurrentSessionId = -1;
Linus Nilssona99f4042021-02-25 15:49:43 -0800542 mCurrentCallingUid = -1;
Chong Zhang66469272020-06-04 16:51:55 -0700543 mTranscoderCb = nullptr;
544 mTranscoder = nullptr;
Linus Nilssona99f4042021-02-25 15:49:43 -0800545 mSrcFormat = nullptr;
546 mDstFormat = nullptr;
547}
548
549void TranscoderWrapper::logSessionEnded(const TranscodingLogger::SessionEndedReason& reason,
550 int error) {
551 std::chrono::microseconds transcodeDuration(-1);
552 if (reason == TranscodingLogger::SessionEndedReason::FINISHED && error == AMEDIA_OK) {
553 transcodeDuration = std::chrono::duration_cast<std::chrono::microseconds>(
554 std::chrono::steady_clock::now() - mTranscodeStartTime);
555 }
556
557 mLogger->logSessionEnded(reason, mCurrentCallingUid, error, transcodeDuration, mSrcFormat.get(),
558 mDstFormat.get());
Chong Zhang66469272020-06-04 16:51:55 -0700559}
560
Chong Zhangbc062482020-10-14 16:43:53 -0700561void TranscoderWrapper::queueEvent(Event::Type type, ClientIdType clientId, SessionIdType sessionId,
Chong Zhangf9077512020-09-21 21:02:06 -0700562 const std::function<void()> runnable, int32_t arg) {
Chong Zhang66469272020-06-04 16:51:55 -0700563 std::scoped_lock lock{mLock};
564
Chong Zhang457c6892021-02-01 15:34:20 -0800565 if (!mLooperReady) {
566 // A shared_ptr to ourselves is given to the thread's stack, so that the TranscoderWrapper
567 // object doesn't go away until the thread exits. When a watchdog timeout happens, this
568 // allows the session controller to release its reference to the TranscoderWrapper object
569 // without blocking on the thread exits.
570 std::thread([owner = shared_from_this()]() { owner->threadLoop(); }).detach();
571 mLooperReady = true;
572 }
573
Chong Zhangbc062482020-10-14 16:43:53 -0700574 mQueue.push_back({type, clientId, sessionId, runnable, arg});
Chong Zhang66469272020-06-04 16:51:55 -0700575 mCondition.notify_one();
576}
577
578void TranscoderWrapper::threadLoop() {
579 std::unique_lock<std::mutex> lock{mLock};
580 // TranscoderWrapper currently lives in the transcoding service, as long as
581 // MediaTranscodingService itself.
582 while (true) {
583 // Wait for the next event.
584 while (mQueue.empty()) {
585 mCondition.wait(lock);
586 }
587
588 Event event = *mQueue.begin();
589 mQueue.pop_front();
590
Chong Zhangf9077512020-09-21 21:02:06 -0700591 ALOGD("%s: %s", __FUNCTION__, toString(event).c_str());
Chong Zhang66469272020-06-04 16:51:55 -0700592
Chong Zhang457c6892021-02-01 15:34:20 -0800593 if (event.type == Event::Abandon) {
594 break;
595 }
596
Chong Zhangb55c5452020-06-26 14:32:12 -0700597 lock.unlock();
Chong Zhang66469272020-06-04 16:51:55 -0700598 event.runnable();
Chong Zhangb55c5452020-06-26 14:32:12 -0700599 lock.lock();
Chong Zhang66469272020-06-04 16:51:55 -0700600 }
601}
Chong Zhang66469272020-06-04 16:51:55 -0700602} // namespace android