blob: b19e7115889e724f7e2b41974565635bfeb124e1 [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 Zhang66469272020-06-04 16:51:55 -070026#include <utils/Log.h>
27
28#include <thread>
29
30namespace android {
31using Status = ::ndk::ScopedAStatus;
32using ::aidl::android::media::TranscodingErrorCode;
33using ::aidl::android::media::TranscodingVideoCodecType;
34using ::aidl::android::media::TranscodingVideoTrackFormat;
35
36static TranscodingErrorCode toTranscodingError(media_status_t status) {
37 switch (status) {
38 case AMEDIA_OK:
39 return TranscodingErrorCode::kNoError;
40 case AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE: // FALLTHRU
41 case AMEDIACODEC_ERROR_RECLAIMED:
42 return TranscodingErrorCode::kInsufficientResources;
43 case AMEDIA_ERROR_MALFORMED:
44 return TranscodingErrorCode::kMalformed;
45 case AMEDIA_ERROR_UNSUPPORTED:
46 return TranscodingErrorCode::kUnsupported;
47 case AMEDIA_ERROR_INVALID_OBJECT: // FALLTHRU
48 case AMEDIA_ERROR_INVALID_PARAMETER:
49 return TranscodingErrorCode::kInvalidParameter;
50 case AMEDIA_ERROR_INVALID_OPERATION:
51 return TranscodingErrorCode::kInvalidOperation;
52 case AMEDIA_ERROR_IO:
53 return TranscodingErrorCode::kErrorIO;
54 case AMEDIA_ERROR_UNKNOWN: // FALLTHRU
55 default:
56 return TranscodingErrorCode::kUnknown;
57 }
58}
59
Linus Nilssona99f4042021-02-25 15:49:43 -080060static std::shared_ptr<AMediaFormat> getVideoFormat(
Chong Zhangb55c5452020-06-26 14:32:12 -070061 const char* originalMime,
62 const std::optional<TranscodingVideoTrackFormat>& requestedFormat) {
63 if (requestedFormat == std::nullopt) {
64 return nullptr;
65 }
66
Linus Nilssona99f4042021-02-25 15:49:43 -080067 std::shared_ptr<AMediaFormat> format =
68 std::shared_ptr<AMediaFormat>(AMediaFormat_new(), &AMediaFormat_delete);
Chong Zhangb55c5452020-06-26 14:32:12 -070069 bool changed = false;
70 if (requestedFormat->codecType == TranscodingVideoCodecType::kHevc &&
71 strcmp(originalMime, AMEDIA_MIMETYPE_VIDEO_HEVC)) {
Linus Nilssona99f4042021-02-25 15:49:43 -080072 AMediaFormat_setString(format.get(), AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_HEVC);
Chong Zhangb55c5452020-06-26 14:32:12 -070073 changed = true;
74 } else if (requestedFormat->codecType == TranscodingVideoCodecType::kAvc &&
75 strcmp(originalMime, AMEDIA_MIMETYPE_VIDEO_AVC)) {
Linus Nilssona99f4042021-02-25 15:49:43 -080076 AMediaFormat_setString(format.get(), AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_AVC);
Chong Zhangb55c5452020-06-26 14:32:12 -070077 changed = true;
78 }
79 if (requestedFormat->bitrateBps > 0) {
Linus Nilssona99f4042021-02-25 15:49:43 -080080 AMediaFormat_setInt32(format.get(), AMEDIAFORMAT_KEY_BIT_RATE, requestedFormat->bitrateBps);
Chong Zhangb55c5452020-06-26 14:32:12 -070081 changed = true;
82 }
83 // TODO: translate other fields from requestedFormat to the format for MediaTranscoder.
84 // Also need to determine more settings to expose in TranscodingVideoTrackFormat.
85 if (!changed) {
Chong Zhangb55c5452020-06-26 14:32:12 -070086 // Use null format for passthru.
Linus Nilssona99f4042021-02-25 15:49:43 -080087 format.reset();
Chong Zhangb55c5452020-06-26 14:32:12 -070088 }
89 return format;
90}
91
Chong Zhang66469272020-06-04 16:51:55 -070092//static
Chong Zhangf9077512020-09-21 21:02:06 -070093std::string TranscoderWrapper::toString(const Event& event) {
94 std::string typeStr;
95 switch (event.type) {
Chong Zhang66469272020-06-04 16:51:55 -070096 case Event::Start:
Chong Zhangf9077512020-09-21 21:02:06 -070097 typeStr = "Start";
Chong Zhang66469272020-06-04 16:51:55 -070098 break;
Chong Zhangf9077512020-09-21 21:02:06 -070099 case Event::Pause:
100 typeStr = "Pause";
101 break;
102 case Event::Resume:
103 typeStr = "Resume";
104 break;
105 case Event::Stop:
106 typeStr = "Stop";
107 break;
108 case Event::Finish:
109 typeStr = "Finish";
110 break;
111 case Event::Error:
112 typeStr = "Error";
113 break;
114 case Event::Progress:
115 typeStr = "Progress";
116 break;
Chong Zhang457c6892021-02-01 15:34:20 -0800117 case Event::HeartBeat:
118 typeStr = "HeartBeat";
119 break;
120 case Event::Abandon:
121 typeStr = "Abandon";
122 break;
Chong Zhangf9077512020-09-21 21:02:06 -0700123 default:
124 return "(unknown)";
Chong Zhang66469272020-06-04 16:51:55 -0700125 }
Chong Zhangf9077512020-09-21 21:02:06 -0700126 std::string result;
Chong Zhangbc062482020-10-14 16:43:53 -0700127 result = "session {" + std::to_string(event.clientId) + "," + std::to_string(event.sessionId) +
Chong Zhangf9077512020-09-21 21:02:06 -0700128 "}: " + typeStr;
129 if (event.type == Event::Error || event.type == Event::Progress) {
130 result += " " + std::to_string(event.arg);
131 }
132 return result;
Chong Zhang66469272020-06-04 16:51:55 -0700133}
134
135class TranscoderWrapper::CallbackImpl : public MediaTranscoder::CallbackInterface {
136public:
137 CallbackImpl(const std::shared_ptr<TranscoderWrapper>& owner, ClientIdType clientId,
Chong Zhangbc062482020-10-14 16:43:53 -0700138 SessionIdType sessionId)
139 : mOwner(owner), mClientId(clientId), mSessionId(sessionId) {}
Chong Zhang66469272020-06-04 16:51:55 -0700140
141 virtual void onFinished(const MediaTranscoder* transcoder __unused) override {
142 auto owner = mOwner.lock();
143 if (owner != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700144 owner->onFinish(mClientId, mSessionId);
Chong Zhang66469272020-06-04 16:51:55 -0700145 }
146 }
147
148 virtual void onError(const MediaTranscoder* transcoder __unused,
149 media_status_t error) override {
150 auto owner = mOwner.lock();
151 if (owner != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700152 owner->onError(mClientId, mSessionId, error);
Chong Zhang66469272020-06-04 16:51:55 -0700153 }
154 }
155
156 virtual void onProgressUpdate(const MediaTranscoder* transcoder __unused,
157 int32_t progress) override {
Chong Zhang98b8a372020-07-08 17:27:37 -0700158 auto owner = mOwner.lock();
159 if (owner != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700160 owner->onProgress(mClientId, mSessionId, progress);
Chong Zhang98b8a372020-07-08 17:27:37 -0700161 }
Chong Zhang66469272020-06-04 16:51:55 -0700162 }
163
Chong Zhang457c6892021-02-01 15:34:20 -0800164 virtual void onHeartBeat(const MediaTranscoder* transcoder __unused) override {
165 auto owner = mOwner.lock();
166 if (owner != nullptr) {
167 owner->onHeartBeat(mClientId, mSessionId);
168 }
169 }
170
Chong Zhang66469272020-06-04 16:51:55 -0700171 virtual void onCodecResourceLost(const MediaTranscoder* transcoder __unused,
Chong Zhange4e088f2020-10-21 19:10:42 -0700172 const std::shared_ptr<ndk::ScopedAParcel>& pausedState
Chong Zhang66469272020-06-04 16:51:55 -0700173 __unused) override {
Chong Zhangbc062482020-10-14 16:43:53 -0700174 ALOGV("%s: session {%lld, %d}", __FUNCTION__, (long long)mClientId, mSessionId);
Chong Zhang66469272020-06-04 16:51:55 -0700175 }
176
177private:
178 std::weak_ptr<TranscoderWrapper> mOwner;
179 ClientIdType mClientId;
Chong Zhangbc062482020-10-14 16:43:53 -0700180 SessionIdType mSessionId;
Chong Zhang66469272020-06-04 16:51:55 -0700181};
182
Chong Zhang457c6892021-02-01 15:34:20 -0800183TranscoderWrapper::TranscoderWrapper(const std::shared_ptr<TranscoderCallbackInterface>& cb,
Linus Nilssona99f4042021-02-25 15:49:43 -0800184 const std::shared_ptr<TranscodingLogger>& logger,
Chong Zhang457c6892021-02-01 15:34:20 -0800185 int64_t heartBeatIntervalUs)
186 : mCallback(cb),
Linus Nilssona99f4042021-02-25 15:49:43 -0800187 mLogger(logger),
Chong Zhang457c6892021-02-01 15:34:20 -0800188 mHeartBeatIntervalUs(heartBeatIntervalUs),
189 mCurrentClientId(0),
190 mCurrentSessionId(-1),
191 mLooperReady(false) {
192 ALOGV("TranscoderWrapper CTOR: %p", this);
Chong Zhang66469272020-06-04 16:51:55 -0700193}
194
Chong Zhang457c6892021-02-01 15:34:20 -0800195TranscoderWrapper::~TranscoderWrapper() {
196 ALOGV("TranscoderWrapper DTOR: %p", this);
Chong Zhang66469272020-06-04 16:51:55 -0700197}
198
Chong Zhangf9077512020-09-21 21:02:06 -0700199static bool isResourceError(media_status_t err) {
200 return err == AMEDIACODEC_ERROR_RECLAIMED || err == AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE;
201}
202
Chong Zhangbc062482020-10-14 16:43:53 -0700203void TranscoderWrapper::reportError(ClientIdType clientId, SessionIdType sessionId,
204 media_status_t err) {
Chong Zhangf9077512020-09-21 21:02:06 -0700205 auto callback = mCallback.lock();
206 if (callback != nullptr) {
207 if (isResourceError(err)) {
208 // Add a placeholder pause state to mPausedStateMap. This is required when resuming.
209 // TODO: remove this when transcoder pause/resume logic is ready. New logic will
210 // no longer use the pause states.
Chong Zhangbc062482020-10-14 16:43:53 -0700211 auto it = mPausedStateMap.find(SessionKeyType(clientId, sessionId));
Chong Zhangf9077512020-09-21 21:02:06 -0700212 if (it == mPausedStateMap.end()) {
Chong Zhangbc062482020-10-14 16:43:53 -0700213 mPausedStateMap.emplace(SessionKeyType(clientId, sessionId),
Chong Zhange4e088f2020-10-21 19:10:42 -0700214 new ndk::ScopedAParcel());
Chong Zhangf9077512020-09-21 21:02:06 -0700215 }
216
Chong Zhangeffd8962020-12-02 14:29:09 -0800217 callback->onResourceLost(clientId, sessionId);
Chong Zhangf9077512020-09-21 21:02:06 -0700218 } else {
Chong Zhangbc062482020-10-14 16:43:53 -0700219 callback->onError(clientId, sessionId, toTranscodingError(err));
Chong Zhangf9077512020-09-21 21:02:06 -0700220 }
221 }
222}
223
Chong Zhangbc062482020-10-14 16:43:53 -0700224void TranscoderWrapper::start(ClientIdType clientId, SessionIdType sessionId,
Linus Nilsson1cbc22c2021-03-19 12:21:07 -0700225 const TranscodingRequestParcel& requestParcel, uid_t callingUid,
Chong Zhangb55c5452020-06-26 14:32:12 -0700226 const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
Linus Nilsson1cbc22c2021-03-19 12:21:07 -0700227 TranscodingRequest request{requestParcel};
228 queueEvent(Event::Start, clientId, sessionId, [=] {
Linus Nilssona99f4042021-02-25 15:49:43 -0800229 media_status_t err = handleStart(clientId, sessionId, request, callingUid, clientCb);
Chong Zhangf9077512020-09-21 21:02:06 -0700230 if (err != AMEDIA_OK) {
Chong Zhang66469272020-06-04 16:51:55 -0700231 cleanup();
Chong Zhangbc062482020-10-14 16:43:53 -0700232 reportError(clientId, sessionId, err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700233 } else {
Chong Zhangf9077512020-09-21 21:02:06 -0700234 auto callback = mCallback.lock();
Chong Zhangb55c5452020-06-26 14:32:12 -0700235 if (callback != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700236 callback->onStarted(clientId, sessionId);
Chong Zhangb55c5452020-06-26 14:32:12 -0700237 }
Chong Zhang66469272020-06-04 16:51:55 -0700238 }
239 });
240}
241
Chong Zhangbc062482020-10-14 16:43:53 -0700242void TranscoderWrapper::pause(ClientIdType clientId, SessionIdType sessionId) {
243 queueEvent(Event::Pause, clientId, sessionId, [=] {
244 media_status_t err = handlePause(clientId, sessionId);
Chong Zhangb55c5452020-06-26 14:32:12 -0700245
246 cleanup();
247
Chong Zhangf9077512020-09-21 21:02:06 -0700248 if (err != AMEDIA_OK) {
Chong Zhangbc062482020-10-14 16:43:53 -0700249 reportError(clientId, sessionId, err);
Chong Zhangf9077512020-09-21 21:02:06 -0700250 } else {
251 auto callback = mCallback.lock();
252 if (callback != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700253 callback->onPaused(clientId, sessionId);
Chong Zhangb55c5452020-06-26 14:32:12 -0700254 }
255 }
256 });
Chong Zhang66469272020-06-04 16:51:55 -0700257}
258
Chong Zhangbc062482020-10-14 16:43:53 -0700259void TranscoderWrapper::resume(ClientIdType clientId, SessionIdType sessionId,
Linus Nilsson1cbc22c2021-03-19 12:21:07 -0700260 const TranscodingRequestParcel& requestParcel, uid_t callingUid,
Chong Zhangb55c5452020-06-26 14:32:12 -0700261 const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
Linus Nilsson1cbc22c2021-03-19 12:21:07 -0700262 TranscodingRequest request{requestParcel};
263 queueEvent(Event::Resume, clientId, sessionId, [=] {
Linus Nilssona99f4042021-02-25 15:49:43 -0800264 media_status_t err = handleResume(clientId, sessionId, request, callingUid, clientCb);
Chong Zhangf9077512020-09-21 21:02:06 -0700265 if (err != AMEDIA_OK) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700266 cleanup();
Chong Zhangbc062482020-10-14 16:43:53 -0700267 reportError(clientId, sessionId, err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700268 } else {
Chong Zhangf9077512020-09-21 21:02:06 -0700269 auto callback = mCallback.lock();
Chong Zhangb55c5452020-06-26 14:32:12 -0700270 if (callback != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700271 callback->onResumed(clientId, sessionId);
Chong Zhangb55c5452020-06-26 14:32:12 -0700272 }
273 }
274 });
Chong Zhang66469272020-06-04 16:51:55 -0700275}
276
Chong Zhang457c6892021-02-01 15:34:20 -0800277void TranscoderWrapper::stop(ClientIdType clientId, SessionIdType sessionId, bool abandon) {
Chong Zhangbc062482020-10-14 16:43:53 -0700278 queueEvent(Event::Stop, clientId, sessionId, [=] {
279 if (mTranscoder != nullptr && clientId == mCurrentClientId &&
280 sessionId == mCurrentSessionId) {
281 // Cancelling the currently running session.
Chong Zhangb55c5452020-06-26 14:32:12 -0700282 media_status_t err = mTranscoder->cancel();
283 if (err != AMEDIA_OK) {
Chong Zhangf9077512020-09-21 21:02:06 -0700284 ALOGW("failed to stop transcoder: %d", err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700285 } else {
286 ALOGI("transcoder stopped");
287 }
Linus Nilssona99f4042021-02-25 15:49:43 -0800288 logSessionEnded(TranscodingLogger::SessionEndedReason::CANCELLED, err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700289 cleanup();
Chong Zhang66469272020-06-04 16:51:55 -0700290 } else {
Chong Zhangbc062482020-10-14 16:43:53 -0700291 // For sessions that's not currently running, release any pausedState for the session.
292 mPausedStateMap.erase(SessionKeyType(clientId, sessionId));
Chong Zhang66469272020-06-04 16:51:55 -0700293 }
Chong Zhangb55c5452020-06-26 14:32:12 -0700294 // No callback needed for stop.
Chong Zhang66469272020-06-04 16:51:55 -0700295 });
Chong Zhang457c6892021-02-01 15:34:20 -0800296
297 if (abandon) {
298 queueEvent(Event::Abandon, 0, 0, nullptr);
299 }
Chong Zhang66469272020-06-04 16:51:55 -0700300}
301
Chong Zhangbc062482020-10-14 16:43:53 -0700302void TranscoderWrapper::onFinish(ClientIdType clientId, SessionIdType sessionId) {
303 queueEvent(Event::Finish, clientId, sessionId, [=] {
304 if (mTranscoder != nullptr && clientId == mCurrentClientId &&
305 sessionId == mCurrentSessionId) {
Linus Nilssona99f4042021-02-25 15:49:43 -0800306 logSessionEnded(TranscodingLogger::SessionEndedReason::FINISHED, AMEDIA_OK);
Chong Zhangb55c5452020-06-26 14:32:12 -0700307 cleanup();
308 }
Chong Zhang66469272020-06-04 16:51:55 -0700309
310 auto callback = mCallback.lock();
311 if (callback != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700312 callback->onFinish(clientId, sessionId);
Chong Zhang66469272020-06-04 16:51:55 -0700313 }
314 });
315}
316
Chong Zhangbc062482020-10-14 16:43:53 -0700317void TranscoderWrapper::onError(ClientIdType clientId, SessionIdType sessionId,
318 media_status_t error) {
Chong Zhangf9077512020-09-21 21:02:06 -0700319 queueEvent(
Chong Zhangbc062482020-10-14 16:43:53 -0700320 Event::Error, clientId, sessionId,
Chong Zhangf9077512020-09-21 21:02:06 -0700321 [=] {
322 if (mTranscoder != nullptr && clientId == mCurrentClientId &&
Chong Zhangbc062482020-10-14 16:43:53 -0700323 sessionId == mCurrentSessionId) {
Linus Nilssona99f4042021-02-25 15:49:43 -0800324 logSessionEnded(TranscodingLogger::SessionEndedReason::ERROR, error);
Chong Zhangf9077512020-09-21 21:02:06 -0700325 cleanup();
326 }
Chong Zhangbc062482020-10-14 16:43:53 -0700327 reportError(clientId, sessionId, error);
Chong Zhangf9077512020-09-21 21:02:06 -0700328 },
329 error);
Chong Zhang66469272020-06-04 16:51:55 -0700330}
331
Chong Zhangbc062482020-10-14 16:43:53 -0700332void TranscoderWrapper::onProgress(ClientIdType clientId, SessionIdType sessionId,
333 int32_t progress) {
Chong Zhangf9077512020-09-21 21:02:06 -0700334 queueEvent(
Chong Zhangbc062482020-10-14 16:43:53 -0700335 Event::Progress, clientId, sessionId,
Chong Zhangf9077512020-09-21 21:02:06 -0700336 [=] {
337 auto callback = mCallback.lock();
338 if (callback != nullptr) {
Chong Zhangbc062482020-10-14 16:43:53 -0700339 callback->onProgressUpdate(clientId, sessionId, progress);
Chong Zhangf9077512020-09-21 21:02:06 -0700340 }
341 },
342 progress);
Chong Zhang98b8a372020-07-08 17:27:37 -0700343}
344
Chong Zhang457c6892021-02-01 15:34:20 -0800345void TranscoderWrapper::onHeartBeat(ClientIdType clientId, SessionIdType sessionId) {
346 queueEvent(Event::HeartBeat, clientId, sessionId, [=] {
347 auto callback = mCallback.lock();
348 if (callback != nullptr) {
349 callback->onHeartBeat(clientId, sessionId);
350 }
351 });
352}
353
Chong Zhangf9077512020-09-21 21:02:06 -0700354media_status_t TranscoderWrapper::setupTranscoder(
Chong Zhangbc062482020-10-14 16:43:53 -0700355 ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
Linus Nilssona99f4042021-02-25 15:49:43 -0800356 uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& clientCb,
357 TranscodingLogger::SessionEndedReason* failureReason,
Chong Zhange4e088f2020-10-21 19:10:42 -0700358 const std::shared_ptr<ndk::ScopedAParcel>& pausedState) {
Chong Zhang66469272020-06-04 16:51:55 -0700359 if (clientCb == nullptr) {
360 ALOGE("client callback is null");
Chong Zhangf9077512020-09-21 21:02:06 -0700361 return AMEDIA_ERROR_INVALID_PARAMETER;
Chong Zhang66469272020-06-04 16:51:55 -0700362 }
363
364 if (mTranscoder != nullptr) {
365 ALOGE("transcoder already running");
Chong Zhangf9077512020-09-21 21:02:06 -0700366 return AMEDIA_ERROR_INVALID_OPERATION;
Chong Zhang66469272020-06-04 16:51:55 -0700367 }
368
Linus Nilssond2bef932021-03-23 21:55:33 -0700369 // Unwrap the callback and send heartbeats to the client after each operation during setup.
370 auto callback = mCallback.lock();
371 if (callback == nullptr) {
372 return AMEDIA_ERROR_INVALID_OPERATION;
373 }
374
Chong Zhang66469272020-06-04 16:51:55 -0700375 Status status;
376 ::ndk::ScopedFileDescriptor srcFd, dstFd;
hkuang34377c32020-09-24 22:28:27 -0700377 int srcFdInt = request.sourceFd.get();
378 if (srcFdInt < 0) {
379 status = clientCb->openFileDescriptor(request.sourceFilePath, "r", &srcFd);
380 if (!status.isOk() || srcFd.get() < 0) {
381 ALOGE("failed to open source");
Linus Nilssona99f4042021-02-25 15:49:43 -0800382 *failureReason = TranscodingLogger::SessionEndedReason::OPEN_SRC_FD_FAILED;
hkuang34377c32020-09-24 22:28:27 -0700383 return AMEDIA_ERROR_IO;
384 }
385 srcFdInt = srcFd.get();
Chong Zhang66469272020-06-04 16:51:55 -0700386 }
387
Linus Nilssond2bef932021-03-23 21:55:33 -0700388 callback->onHeartBeat(clientId, sessionId);
389
hkuang34377c32020-09-24 22:28:27 -0700390 int dstFdInt = request.destinationFd.get();
391 if (dstFdInt < 0) {
392 // Open dest file with "rw", as the transcoder could potentially reuse part of it
393 // for resume case. We might want the further differentiate and open with "w" only
394 // for start.
395 status = clientCb->openFileDescriptor(request.destinationFilePath, "rw", &dstFd);
396 if (!status.isOk() || dstFd.get() < 0) {
397 ALOGE("failed to open destination");
Linus Nilssona99f4042021-02-25 15:49:43 -0800398 *failureReason = TranscodingLogger::SessionEndedReason::OPEN_DST_FD_FAILED;
hkuang34377c32020-09-24 22:28:27 -0700399 return AMEDIA_ERROR_IO;
400 }
401 dstFdInt = dstFd.get();
Chong Zhang66469272020-06-04 16:51:55 -0700402 }
403
Linus Nilssond2bef932021-03-23 21:55:33 -0700404 callback->onHeartBeat(clientId, sessionId);
405
Chong Zhang66469272020-06-04 16:51:55 -0700406 mCurrentClientId = clientId;
Chong Zhangbc062482020-10-14 16:43:53 -0700407 mCurrentSessionId = sessionId;
Linus Nilssona99f4042021-02-25 15:49:43 -0800408 mCurrentCallingUid = callingUid;
Chong Zhangbc062482020-10-14 16:43:53 -0700409 mTranscoderCb = std::make_shared<CallbackImpl>(shared_from_this(), clientId, sessionId);
Chong Zhang457c6892021-02-01 15:34:20 -0800410 mTranscoder = MediaTranscoder::create(mTranscoderCb, mHeartBeatIntervalUs, request.clientPid,
411 request.clientUid, pausedState);
Chong Zhang66469272020-06-04 16:51:55 -0700412 if (mTranscoder == nullptr) {
413 ALOGE("failed to create transcoder");
Linus Nilssona99f4042021-02-25 15:49:43 -0800414 *failureReason = TranscodingLogger::SessionEndedReason::CREATE_FAILED;
Chong Zhangf9077512020-09-21 21:02:06 -0700415 return AMEDIA_ERROR_UNKNOWN;
Chong Zhang66469272020-06-04 16:51:55 -0700416 }
417
Linus Nilssond2bef932021-03-23 21:55:33 -0700418 callback->onHeartBeat(clientId, sessionId);
419
hkuang34377c32020-09-24 22:28:27 -0700420 media_status_t err = mTranscoder->configureSource(srcFdInt);
Chong Zhang66469272020-06-04 16:51:55 -0700421 if (err != AMEDIA_OK) {
422 ALOGE("failed to configure source: %d", err);
Linus Nilssona99f4042021-02-25 15:49:43 -0800423 *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_SRC_FAILED;
Chong Zhangf9077512020-09-21 21:02:06 -0700424 return err;
Chong Zhang66469272020-06-04 16:51:55 -0700425 }
426
Linus Nilssond2bef932021-03-23 21:55:33 -0700427 callback->onHeartBeat(clientId, sessionId);
428
Chong Zhang66469272020-06-04 16:51:55 -0700429 std::vector<std::shared_ptr<AMediaFormat>> trackFormats = mTranscoder->getTrackFormats();
430 if (trackFormats.size() == 0) {
431 ALOGE("failed to get track formats!");
Linus Nilssona99f4042021-02-25 15:49:43 -0800432 *failureReason = TranscodingLogger::SessionEndedReason::NO_TRACKS;
Chong Zhangf9077512020-09-21 21:02:06 -0700433 return AMEDIA_ERROR_MALFORMED;
Chong Zhang66469272020-06-04 16:51:55 -0700434 }
435
Linus Nilssond2bef932021-03-23 21:55:33 -0700436 callback->onHeartBeat(clientId, sessionId);
437
Chong Zhang66469272020-06-04 16:51:55 -0700438 for (int i = 0; i < trackFormats.size(); ++i) {
Linus Nilssona99f4042021-02-25 15:49:43 -0800439 std::shared_ptr<AMediaFormat> format;
Chong Zhang66469272020-06-04 16:51:55 -0700440 const char* mime = nullptr;
441 AMediaFormat_getString(trackFormats[i].get(), AMEDIAFORMAT_KEY_MIME, &mime);
442
443 if (!strncmp(mime, "video/", 6)) {
444 format = getVideoFormat(mime, request.requestedVideoTrackFormat);
Linus Nilssona99f4042021-02-25 15:49:43 -0800445
446 mSrcFormat = trackFormats[i];
447 mDstFormat = format;
Chong Zhang66469272020-06-04 16:51:55 -0700448 }
449
Linus Nilssona99f4042021-02-25 15:49:43 -0800450 err = mTranscoder->configureTrackFormat(i, format.get());
Chong Zhang66469272020-06-04 16:51:55 -0700451 if (err != AMEDIA_OK) {
452 ALOGE("failed to configure track format for track %d: %d", i, err);
Linus Nilssona99f4042021-02-25 15:49:43 -0800453 *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_TRACK_FAILED;
Chong Zhangf9077512020-09-21 21:02:06 -0700454 return err;
Chong Zhang66469272020-06-04 16:51:55 -0700455 }
Linus Nilssond2bef932021-03-23 21:55:33 -0700456
457 callback->onHeartBeat(clientId, sessionId);
Chong Zhang66469272020-06-04 16:51:55 -0700458 }
459
hkuang34377c32020-09-24 22:28:27 -0700460 err = mTranscoder->configureDestination(dstFdInt);
Chong Zhang66469272020-06-04 16:51:55 -0700461 if (err != AMEDIA_OK) {
462 ALOGE("failed to configure dest: %d", err);
Linus Nilssona99f4042021-02-25 15:49:43 -0800463 *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_DST_FAILED;
Chong Zhangf9077512020-09-21 21:02:06 -0700464 return err;
Chong Zhang66469272020-06-04 16:51:55 -0700465 }
466
Linus Nilssond2bef932021-03-23 21:55:33 -0700467 callback->onHeartBeat(clientId, sessionId);
468
Chong Zhangf9077512020-09-21 21:02:06 -0700469 return AMEDIA_OK;
Chong Zhangb55c5452020-06-26 14:32:12 -0700470}
471
Chong Zhangf9077512020-09-21 21:02:06 -0700472media_status_t TranscoderWrapper::handleStart(
Chong Zhangbc062482020-10-14 16:43:53 -0700473 ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
Linus Nilssona99f4042021-02-25 15:49:43 -0800474 uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
Chong Zhangf9077512020-09-21 21:02:06 -0700475 ALOGI("%s: setting up transcoder for start", __FUNCTION__);
Linus Nilssona99f4042021-02-25 15:49:43 -0800476 TranscodingLogger::SessionEndedReason reason = TranscodingLogger::SessionEndedReason::UNKNOWN;
477 media_status_t err =
478 setupTranscoder(clientId, sessionId, request, callingUid, clientCb, &reason);
Chong Zhangf9077512020-09-21 21:02:06 -0700479 if (err != AMEDIA_OK) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700480 ALOGI("%s: failed to setup transcoder", __FUNCTION__);
Linus Nilssona99f4042021-02-25 15:49:43 -0800481 logSessionEnded(reason, err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700482 return err;
Chong Zhang66469272020-06-04 16:51:55 -0700483 }
484
Linus Nilssona99f4042021-02-25 15:49:43 -0800485 mTranscodeStartTime = std::chrono::steady_clock::now();
486
Chong Zhangf9077512020-09-21 21:02:06 -0700487 err = mTranscoder->start();
488 if (err != AMEDIA_OK) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700489 ALOGE("%s: failed to start transcoder: %d", __FUNCTION__, err);
Linus Nilssona99f4042021-02-25 15:49:43 -0800490 logSessionEnded(TranscodingLogger::SessionEndedReason::START_FAILED, err);
Chong Zhangf9077512020-09-21 21:02:06 -0700491 return err;
Chong Zhangb55c5452020-06-26 14:32:12 -0700492 }
493
494 ALOGI("%s: transcoder started", __FUNCTION__);
Chong Zhangf9077512020-09-21 21:02:06 -0700495 return AMEDIA_OK;
Chong Zhangb55c5452020-06-26 14:32:12 -0700496}
497
Chong Zhangbc062482020-10-14 16:43:53 -0700498media_status_t TranscoderWrapper::handlePause(ClientIdType clientId, SessionIdType sessionId) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700499 if (mTranscoder == nullptr) {
500 ALOGE("%s: transcoder is not running", __FUNCTION__);
Chong Zhangf9077512020-09-21 21:02:06 -0700501 return AMEDIA_ERROR_INVALID_OPERATION;
Chong Zhangb55c5452020-06-26 14:32:12 -0700502 }
503
Chong Zhangbc062482020-10-14 16:43:53 -0700504 if (clientId != mCurrentClientId || sessionId != mCurrentSessionId) {
505 ALOGW("%s: stopping session {%lld, %d} that's not current session {%lld, %d}", __FUNCTION__,
506 (long long)clientId, sessionId, (long long)mCurrentClientId, mCurrentSessionId);
Chong Zhangb55c5452020-06-26 14:32:12 -0700507 }
508
Chong Zhangf9077512020-09-21 21:02:06 -0700509 ALOGI("%s: pausing transcoder", __FUNCTION__);
510
Chong Zhange4e088f2020-10-21 19:10:42 -0700511 std::shared_ptr<ndk::ScopedAParcel> pauseStates;
Chong Zhangb55c5452020-06-26 14:32:12 -0700512 media_status_t err = mTranscoder->pause(&pauseStates);
Linus Nilssona99f4042021-02-25 15:49:43 -0800513 logSessionEnded(TranscodingLogger::SessionEndedReason::PAUSED, err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700514 if (err != AMEDIA_OK) {
515 ALOGE("%s: failed to pause transcoder: %d", __FUNCTION__, err);
Chong Zhangf9077512020-09-21 21:02:06 -0700516 return err;
Chong Zhangb55c5452020-06-26 14:32:12 -0700517 }
Chong Zhangbc062482020-10-14 16:43:53 -0700518 mPausedStateMap[SessionKeyType(clientId, sessionId)] = pauseStates;
Chong Zhangb55c5452020-06-26 14:32:12 -0700519
520 ALOGI("%s: transcoder paused", __FUNCTION__);
Chong Zhangf9077512020-09-21 21:02:06 -0700521 return AMEDIA_OK;
Chong Zhangb55c5452020-06-26 14:32:12 -0700522}
523
Chong Zhangf9077512020-09-21 21:02:06 -0700524media_status_t TranscoderWrapper::handleResume(
Chong Zhangbc062482020-10-14 16:43:53 -0700525 ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
Linus Nilssona99f4042021-02-25 15:49:43 -0800526 uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
Chong Zhange4e088f2020-10-21 19:10:42 -0700527 std::shared_ptr<ndk::ScopedAParcel> pausedState;
Chong Zhangbc062482020-10-14 16:43:53 -0700528 auto it = mPausedStateMap.find(SessionKeyType(clientId, sessionId));
Chong Zhangb55c5452020-06-26 14:32:12 -0700529 if (it != mPausedStateMap.end()) {
530 pausedState = it->second;
531 mPausedStateMap.erase(it);
532 } else {
533 ALOGE("%s: can't find paused state", __FUNCTION__);
Chong Zhangf9077512020-09-21 21:02:06 -0700534 return AMEDIA_ERROR_INVALID_OPERATION;
Chong Zhangb55c5452020-06-26 14:32:12 -0700535 }
536
Chong Zhangf9077512020-09-21 21:02:06 -0700537 ALOGI("%s: setting up transcoder for resume", __FUNCTION__);
Linus Nilssona99f4042021-02-25 15:49:43 -0800538 TranscodingLogger::SessionEndedReason reason = TranscodingLogger::SessionEndedReason::UNKNOWN;
539 media_status_t err = setupTranscoder(clientId, sessionId, request, callingUid, clientCb,
540 &reason, pausedState);
Chong Zhangf9077512020-09-21 21:02:06 -0700541 if (err != AMEDIA_OK) {
542 ALOGE("%s: failed to setup transcoder: %d", __FUNCTION__, err);
Linus Nilssona99f4042021-02-25 15:49:43 -0800543 logSessionEnded(reason, err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700544 return err;
545 }
546
Linus Nilssona99f4042021-02-25 15:49:43 -0800547 // Note: For now resume() will just restart transcoding from the beginning, so there is no need
548 // to distinguish between resume and start from a performance perspective.
549 mTranscodeStartTime = std::chrono::steady_clock::now();
550
Chong Zhangf9077512020-09-21 21:02:06 -0700551 err = mTranscoder->resume();
552 if (err != AMEDIA_OK) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700553 ALOGE("%s: failed to resume transcoder: %d", __FUNCTION__, err);
Linus Nilssona99f4042021-02-25 15:49:43 -0800554 logSessionEnded(TranscodingLogger::SessionEndedReason::RESUME_FAILED, err);
Chong Zhangf9077512020-09-21 21:02:06 -0700555 return err;
Chong Zhangb55c5452020-06-26 14:32:12 -0700556 }
557
558 ALOGI("%s: transcoder resumed", __FUNCTION__);
Chong Zhangf9077512020-09-21 21:02:06 -0700559 return AMEDIA_OK;
Chong Zhang66469272020-06-04 16:51:55 -0700560}
561
562void TranscoderWrapper::cleanup() {
563 mCurrentClientId = 0;
Chong Zhangbc062482020-10-14 16:43:53 -0700564 mCurrentSessionId = -1;
Linus Nilssona99f4042021-02-25 15:49:43 -0800565 mCurrentCallingUid = -1;
Chong Zhang66469272020-06-04 16:51:55 -0700566 mTranscoderCb = nullptr;
567 mTranscoder = nullptr;
Linus Nilssona99f4042021-02-25 15:49:43 -0800568 mSrcFormat = nullptr;
569 mDstFormat = nullptr;
570}
571
572void TranscoderWrapper::logSessionEnded(const TranscodingLogger::SessionEndedReason& reason,
573 int error) {
574 std::chrono::microseconds transcodeDuration(-1);
575 if (reason == TranscodingLogger::SessionEndedReason::FINISHED && error == AMEDIA_OK) {
576 transcodeDuration = std::chrono::duration_cast<std::chrono::microseconds>(
577 std::chrono::steady_clock::now() - mTranscodeStartTime);
578 }
579
580 mLogger->logSessionEnded(reason, mCurrentCallingUid, error, transcodeDuration, mSrcFormat.get(),
581 mDstFormat.get());
Chong Zhang66469272020-06-04 16:51:55 -0700582}
583
Chong Zhangbc062482020-10-14 16:43:53 -0700584void TranscoderWrapper::queueEvent(Event::Type type, ClientIdType clientId, SessionIdType sessionId,
Chong Zhangf9077512020-09-21 21:02:06 -0700585 const std::function<void()> runnable, int32_t arg) {
Chong Zhang66469272020-06-04 16:51:55 -0700586 std::scoped_lock lock{mLock};
587
Chong Zhang457c6892021-02-01 15:34:20 -0800588 if (!mLooperReady) {
589 // A shared_ptr to ourselves is given to the thread's stack, so that the TranscoderWrapper
590 // object doesn't go away until the thread exits. When a watchdog timeout happens, this
591 // allows the session controller to release its reference to the TranscoderWrapper object
592 // without blocking on the thread exits.
593 std::thread([owner = shared_from_this()]() { owner->threadLoop(); }).detach();
594 mLooperReady = true;
595 }
596
Chong Zhangbc062482020-10-14 16:43:53 -0700597 mQueue.push_back({type, clientId, sessionId, runnable, arg});
Chong Zhang66469272020-06-04 16:51:55 -0700598 mCondition.notify_one();
599}
600
601void TranscoderWrapper::threadLoop() {
602 std::unique_lock<std::mutex> lock{mLock};
603 // TranscoderWrapper currently lives in the transcoding service, as long as
604 // MediaTranscodingService itself.
605 while (true) {
606 // Wait for the next event.
607 while (mQueue.empty()) {
608 mCondition.wait(lock);
609 }
610
611 Event event = *mQueue.begin();
612 mQueue.pop_front();
613
Chong Zhangf9077512020-09-21 21:02:06 -0700614 ALOGD("%s: %s", __FUNCTION__, toString(event).c_str());
Chong Zhang66469272020-06-04 16:51:55 -0700615
Chong Zhang457c6892021-02-01 15:34:20 -0800616 if (event.type == Event::Abandon) {
617 break;
618 }
619
Chong Zhangb55c5452020-06-26 14:32:12 -0700620 lock.unlock();
Chong Zhang66469272020-06-04 16:51:55 -0700621 event.runnable();
Chong Zhangb55c5452020-06-26 14:32:12 -0700622 lock.lock();
Chong Zhang66469272020-06-04 16:51:55 -0700623 }
624}
Chong Zhang66469272020-06-04 16:51:55 -0700625} // namespace android