blob: 8062fcf924737b47161f7dafd3fac31d4d4182cd [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
Chong Zhangb55c5452020-06-26 14:32:12 -070059static AMediaFormat* getVideoFormat(
60 const char* originalMime,
61 const std::optional<TranscodingVideoTrackFormat>& requestedFormat) {
62 if (requestedFormat == std::nullopt) {
63 return nullptr;
64 }
65
66 AMediaFormat* format = AMediaFormat_new();
67 bool changed = false;
68 if (requestedFormat->codecType == TranscodingVideoCodecType::kHevc &&
69 strcmp(originalMime, AMEDIA_MIMETYPE_VIDEO_HEVC)) {
70 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_HEVC);
71 changed = true;
72 } else if (requestedFormat->codecType == TranscodingVideoCodecType::kAvc &&
73 strcmp(originalMime, AMEDIA_MIMETYPE_VIDEO_AVC)) {
74 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_AVC);
75 changed = true;
76 }
77 if (requestedFormat->bitrateBps > 0) {
78 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, requestedFormat->bitrateBps);
79 changed = true;
80 }
81 // TODO: translate other fields from requestedFormat to the format for MediaTranscoder.
82 // Also need to determine more settings to expose in TranscodingVideoTrackFormat.
83 if (!changed) {
84 AMediaFormat_delete(format);
85 // Use null format for passthru.
86 format = nullptr;
87 }
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;
116 default:
117 return "(unknown)";
Chong Zhang66469272020-06-04 16:51:55 -0700118 }
Chong Zhangf9077512020-09-21 21:02:06 -0700119 std::string result;
120 result = "job {" + std::to_string(event.clientId) + "," + std::to_string(event.jobId) +
121 "}: " + typeStr;
122 if (event.type == Event::Error || event.type == Event::Progress) {
123 result += " " + std::to_string(event.arg);
124 }
125 return result;
Chong Zhang66469272020-06-04 16:51:55 -0700126}
127
128class TranscoderWrapper::CallbackImpl : public MediaTranscoder::CallbackInterface {
129public:
130 CallbackImpl(const std::shared_ptr<TranscoderWrapper>& owner, ClientIdType clientId,
131 JobIdType jobId)
132 : mOwner(owner), mClientId(clientId), mJobId(jobId) {}
133
134 virtual void onFinished(const MediaTranscoder* transcoder __unused) override {
135 auto owner = mOwner.lock();
136 if (owner != nullptr) {
137 owner->onFinish(mClientId, mJobId);
138 }
139 }
140
141 virtual void onError(const MediaTranscoder* transcoder __unused,
142 media_status_t error) override {
143 auto owner = mOwner.lock();
144 if (owner != nullptr) {
Chong Zhangf9077512020-09-21 21:02:06 -0700145 owner->onError(mClientId, mJobId, error);
Chong Zhang66469272020-06-04 16:51:55 -0700146 }
147 }
148
149 virtual void onProgressUpdate(const MediaTranscoder* transcoder __unused,
150 int32_t progress) override {
Chong Zhang98b8a372020-07-08 17:27:37 -0700151 auto owner = mOwner.lock();
152 if (owner != nullptr) {
153 owner->onProgress(mClientId, mJobId, progress);
154 }
Chong Zhang66469272020-06-04 16:51:55 -0700155 }
156
157 virtual void onCodecResourceLost(const MediaTranscoder* transcoder __unused,
Chong Zhangb55c5452020-06-26 14:32:12 -0700158 const std::shared_ptr<const Parcel>& pausedState
Chong Zhang66469272020-06-04 16:51:55 -0700159 __unused) override {
160 ALOGV("%s: job {%lld, %d}", __FUNCTION__, (long long)mClientId, mJobId);
161 }
162
163private:
164 std::weak_ptr<TranscoderWrapper> mOwner;
165 ClientIdType mClientId;
166 JobIdType mJobId;
167};
168
169TranscoderWrapper::TranscoderWrapper() : mCurrentClientId(0), mCurrentJobId(-1) {
170 std::thread(&TranscoderWrapper::threadLoop, this).detach();
171}
172
173void TranscoderWrapper::setCallback(const std::shared_ptr<TranscoderCallbackInterface>& cb) {
174 mCallback = cb;
175}
176
Chong Zhangf9077512020-09-21 21:02:06 -0700177static bool isResourceError(media_status_t err) {
178 return err == AMEDIACODEC_ERROR_RECLAIMED || err == AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE;
179}
180
181void TranscoderWrapper::reportError(ClientIdType clientId, JobIdType jobId, media_status_t err) {
182 auto callback = mCallback.lock();
183 if (callback != nullptr) {
184 if (isResourceError(err)) {
185 // Add a placeholder pause state to mPausedStateMap. This is required when resuming.
186 // TODO: remove this when transcoder pause/resume logic is ready. New logic will
187 // no longer use the pause states.
188 auto it = mPausedStateMap.find(JobKeyType(clientId, jobId));
189 if (it == mPausedStateMap.end()) {
190 mPausedStateMap.emplace(JobKeyType(clientId, jobId),
191 std::shared_ptr<const Parcel>());
192 }
193
194 callback->onResourceLost();
195 } else {
196 callback->onError(clientId, jobId, toTranscodingError(err));
197 }
198 }
199}
200
Chong Zhang66469272020-06-04 16:51:55 -0700201void TranscoderWrapper::start(ClientIdType clientId, JobIdType jobId,
202 const TranscodingRequestParcel& request,
Chong Zhangb55c5452020-06-26 14:32:12 -0700203 const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
Chong Zhang66469272020-06-04 16:51:55 -0700204 queueEvent(Event::Start, clientId, jobId, [=] {
Chong Zhangf9077512020-09-21 21:02:06 -0700205 media_status_t err = handleStart(clientId, jobId, request, clientCb);
Chong Zhang66469272020-06-04 16:51:55 -0700206
Chong Zhangf9077512020-09-21 21:02:06 -0700207 if (err != AMEDIA_OK) {
Chong Zhang66469272020-06-04 16:51:55 -0700208 cleanup();
Chong Zhangf9077512020-09-21 21:02:06 -0700209 reportError(clientId, jobId, err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700210 } else {
Chong Zhangf9077512020-09-21 21:02:06 -0700211 auto callback = mCallback.lock();
Chong Zhangb55c5452020-06-26 14:32:12 -0700212 if (callback != nullptr) {
213 callback->onStarted(clientId, jobId);
214 }
Chong Zhang66469272020-06-04 16:51:55 -0700215 }
216 });
217}
218
219void TranscoderWrapper::pause(ClientIdType clientId, JobIdType jobId) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700220 queueEvent(Event::Pause, clientId, jobId, [=] {
Chong Zhangf9077512020-09-21 21:02:06 -0700221 media_status_t err = handlePause(clientId, jobId);
Chong Zhangb55c5452020-06-26 14:32:12 -0700222
223 cleanup();
224
Chong Zhangf9077512020-09-21 21:02:06 -0700225 if (err != AMEDIA_OK) {
226 reportError(clientId, jobId, err);
227 } else {
228 auto callback = mCallback.lock();
229 if (callback != nullptr) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700230 callback->onPaused(clientId, jobId);
231 }
232 }
233 });
Chong Zhang66469272020-06-04 16:51:55 -0700234}
235
Chong Zhangb55c5452020-06-26 14:32:12 -0700236void TranscoderWrapper::resume(ClientIdType clientId, JobIdType jobId,
237 const TranscodingRequestParcel& request,
238 const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
239 queueEvent(Event::Resume, clientId, jobId, [=] {
Chong Zhangf9077512020-09-21 21:02:06 -0700240 media_status_t err = handleResume(clientId, jobId, request, clientCb);
Chong Zhangb55c5452020-06-26 14:32:12 -0700241
Chong Zhangf9077512020-09-21 21:02:06 -0700242 if (err != AMEDIA_OK) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700243 cleanup();
Chong Zhangf9077512020-09-21 21:02:06 -0700244 reportError(clientId, jobId, err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700245 } else {
Chong Zhangf9077512020-09-21 21:02:06 -0700246 auto callback = mCallback.lock();
Chong Zhangb55c5452020-06-26 14:32:12 -0700247 if (callback != nullptr) {
248 callback->onResumed(clientId, jobId);
249 }
250 }
251 });
Chong Zhang66469272020-06-04 16:51:55 -0700252}
253
254void TranscoderWrapper::stop(ClientIdType clientId, JobIdType jobId) {
255 queueEvent(Event::Stop, clientId, jobId, [=] {
Chong Zhangb55c5452020-06-26 14:32:12 -0700256 if (mTranscoder != nullptr && clientId == mCurrentClientId && jobId == mCurrentJobId) {
257 // Cancelling the currently running job.
258 media_status_t err = mTranscoder->cancel();
259 if (err != AMEDIA_OK) {
Chong Zhangf9077512020-09-21 21:02:06 -0700260 ALOGW("failed to stop transcoder: %d", err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700261 } else {
262 ALOGI("transcoder stopped");
263 }
264 cleanup();
Chong Zhang66469272020-06-04 16:51:55 -0700265 } else {
Chong Zhangb55c5452020-06-26 14:32:12 -0700266 // For jobs that's not currently running, release any pausedState for the job.
267 mPausedStateMap.erase(JobKeyType(clientId, jobId));
Chong Zhang66469272020-06-04 16:51:55 -0700268 }
Chong Zhangb55c5452020-06-26 14:32:12 -0700269 // No callback needed for stop.
Chong Zhang66469272020-06-04 16:51:55 -0700270 });
271}
272
273void TranscoderWrapper::onFinish(ClientIdType clientId, JobIdType jobId) {
274 queueEvent(Event::Finish, clientId, jobId, [=] {
Chong Zhangb55c5452020-06-26 14:32:12 -0700275 if (mTranscoder != nullptr && clientId == mCurrentClientId && jobId == mCurrentJobId) {
276 cleanup();
277 }
Chong Zhang66469272020-06-04 16:51:55 -0700278
279 auto callback = mCallback.lock();
280 if (callback != nullptr) {
281 callback->onFinish(clientId, jobId);
282 }
283 });
284}
285
Chong Zhangf9077512020-09-21 21:02:06 -0700286void TranscoderWrapper::onError(ClientIdType clientId, JobIdType jobId, media_status_t error) {
287 queueEvent(
288 Event::Error, clientId, jobId,
289 [=] {
290 if (mTranscoder != nullptr && clientId == mCurrentClientId &&
291 jobId == mCurrentJobId) {
292 cleanup();
293 }
294 reportError(clientId, jobId, error);
295 },
296 error);
Chong Zhang66469272020-06-04 16:51:55 -0700297}
298
Chong Zhang98b8a372020-07-08 17:27:37 -0700299void TranscoderWrapper::onProgress(ClientIdType clientId, JobIdType jobId, int32_t progress) {
Chong Zhangf9077512020-09-21 21:02:06 -0700300 queueEvent(
301 Event::Progress, clientId, jobId,
302 [=] {
303 auto callback = mCallback.lock();
304 if (callback != nullptr) {
305 callback->onProgressUpdate(clientId, jobId, progress);
306 }
307 },
308 progress);
Chong Zhang98b8a372020-07-08 17:27:37 -0700309}
310
Chong Zhangf9077512020-09-21 21:02:06 -0700311media_status_t TranscoderWrapper::setupTranscoder(
Chong Zhang66469272020-06-04 16:51:55 -0700312 ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
Chong Zhangb55c5452020-06-26 14:32:12 -0700313 const std::shared_ptr<ITranscodingClientCallback>& clientCb,
314 const std::shared_ptr<const Parcel>& pausedState) {
Chong Zhang66469272020-06-04 16:51:55 -0700315 if (clientCb == nullptr) {
316 ALOGE("client callback is null");
Chong Zhangf9077512020-09-21 21:02:06 -0700317 return AMEDIA_ERROR_INVALID_PARAMETER;
Chong Zhang66469272020-06-04 16:51:55 -0700318 }
319
320 if (mTranscoder != nullptr) {
321 ALOGE("transcoder already running");
Chong Zhangf9077512020-09-21 21:02:06 -0700322 return AMEDIA_ERROR_INVALID_OPERATION;
Chong Zhang66469272020-06-04 16:51:55 -0700323 }
324
325 Status status;
326 ::ndk::ScopedFileDescriptor srcFd, dstFd;
327 status = clientCb->openFileDescriptor(request.sourceFilePath, "r", &srcFd);
328 if (!status.isOk() || srcFd.get() < 0) {
329 ALOGE("failed to open source");
Chong Zhangf9077512020-09-21 21:02:06 -0700330 return AMEDIA_ERROR_IO;
Chong Zhang66469272020-06-04 16:51:55 -0700331 }
332
Chong Zhangb55c5452020-06-26 14:32:12 -0700333 // Open dest file with "rw", as the transcoder could potentially reuse part of it
334 // for resume case. We might want the further differentiate and open with "w" only
335 // for start.
336 status = clientCb->openFileDescriptor(request.destinationFilePath, "rw", &dstFd);
Chong Zhang66469272020-06-04 16:51:55 -0700337 if (!status.isOk() || dstFd.get() < 0) {
338 ALOGE("failed to open destination");
Chong Zhangf9077512020-09-21 21:02:06 -0700339 return AMEDIA_ERROR_IO;
Chong Zhang66469272020-06-04 16:51:55 -0700340 }
341
342 mCurrentClientId = clientId;
343 mCurrentJobId = jobId;
344 mTranscoderCb = std::make_shared<CallbackImpl>(shared_from_this(), clientId, jobId);
Chong Zhangb55c5452020-06-26 14:32:12 -0700345 mTranscoder = MediaTranscoder::create(mTranscoderCb, pausedState);
Chong Zhang66469272020-06-04 16:51:55 -0700346 if (mTranscoder == nullptr) {
347 ALOGE("failed to create transcoder");
Chong Zhangf9077512020-09-21 21:02:06 -0700348 return AMEDIA_ERROR_UNKNOWN;
Chong Zhang66469272020-06-04 16:51:55 -0700349 }
350
351 media_status_t err = mTranscoder->configureSource(srcFd.get());
352 if (err != AMEDIA_OK) {
353 ALOGE("failed to configure source: %d", err);
Chong Zhangf9077512020-09-21 21:02:06 -0700354 return err;
Chong Zhang66469272020-06-04 16:51:55 -0700355 }
356
357 std::vector<std::shared_ptr<AMediaFormat>> trackFormats = mTranscoder->getTrackFormats();
358 if (trackFormats.size() == 0) {
359 ALOGE("failed to get track formats!");
Chong Zhangf9077512020-09-21 21:02:06 -0700360 return AMEDIA_ERROR_MALFORMED;
Chong Zhang66469272020-06-04 16:51:55 -0700361 }
362
363 for (int i = 0; i < trackFormats.size(); ++i) {
364 AMediaFormat* format = nullptr;
365 const char* mime = nullptr;
366 AMediaFormat_getString(trackFormats[i].get(), AMEDIAFORMAT_KEY_MIME, &mime);
367
368 if (!strncmp(mime, "video/", 6)) {
369 format = getVideoFormat(mime, request.requestedVideoTrackFormat);
370 }
371
372 err = mTranscoder->configureTrackFormat(i, format);
373 if (format != nullptr) {
374 AMediaFormat_delete(format);
375 }
376 if (err != AMEDIA_OK) {
377 ALOGE("failed to configure track format for track %d: %d", i, err);
Chong Zhangf9077512020-09-21 21:02:06 -0700378 return err;
Chong Zhang66469272020-06-04 16:51:55 -0700379 }
380 }
381
382 err = mTranscoder->configureDestination(dstFd.get());
383 if (err != AMEDIA_OK) {
384 ALOGE("failed to configure dest: %d", err);
Chong Zhangf9077512020-09-21 21:02:06 -0700385 return err;
Chong Zhang66469272020-06-04 16:51:55 -0700386 }
387
Chong Zhangf9077512020-09-21 21:02:06 -0700388 return AMEDIA_OK;
Chong Zhangb55c5452020-06-26 14:32:12 -0700389}
390
Chong Zhangf9077512020-09-21 21:02:06 -0700391media_status_t TranscoderWrapper::handleStart(
Chong Zhangb55c5452020-06-26 14:32:12 -0700392 ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
393 const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
Chong Zhangf9077512020-09-21 21:02:06 -0700394 ALOGI("%s: setting up transcoder for start", __FUNCTION__);
395 media_status_t err = setupTranscoder(clientId, jobId, request, clientCb);
396 if (err != AMEDIA_OK) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700397 ALOGI("%s: failed to setup transcoder", __FUNCTION__);
398 return err;
Chong Zhang66469272020-06-04 16:51:55 -0700399 }
400
Chong Zhangf9077512020-09-21 21:02:06 -0700401 err = mTranscoder->start();
402 if (err != AMEDIA_OK) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700403 ALOGE("%s: failed to start transcoder: %d", __FUNCTION__, err);
Chong Zhangf9077512020-09-21 21:02:06 -0700404 return err;
Chong Zhangb55c5452020-06-26 14:32:12 -0700405 }
406
407 ALOGI("%s: transcoder started", __FUNCTION__);
Chong Zhangf9077512020-09-21 21:02:06 -0700408 return AMEDIA_OK;
Chong Zhangb55c5452020-06-26 14:32:12 -0700409}
410
Chong Zhangf9077512020-09-21 21:02:06 -0700411media_status_t TranscoderWrapper::handlePause(ClientIdType clientId, JobIdType jobId) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700412 if (mTranscoder == nullptr) {
413 ALOGE("%s: transcoder is not running", __FUNCTION__);
Chong Zhangf9077512020-09-21 21:02:06 -0700414 return AMEDIA_ERROR_INVALID_OPERATION;
Chong Zhangb55c5452020-06-26 14:32:12 -0700415 }
416
417 if (clientId != mCurrentClientId || jobId != mCurrentJobId) {
418 ALOGW("%s: stopping job {%lld, %d} that's not current job {%lld, %d}", __FUNCTION__,
419 (long long)clientId, jobId, (long long)mCurrentClientId, mCurrentJobId);
420 }
421
Chong Zhangf9077512020-09-21 21:02:06 -0700422 ALOGI("%s: pausing transcoder", __FUNCTION__);
423
Chong Zhangb55c5452020-06-26 14:32:12 -0700424 std::shared_ptr<const Parcel> pauseStates;
425 media_status_t err = mTranscoder->pause(&pauseStates);
426 if (err != AMEDIA_OK) {
427 ALOGE("%s: failed to pause transcoder: %d", __FUNCTION__, err);
Chong Zhangf9077512020-09-21 21:02:06 -0700428 return err;
Chong Zhangb55c5452020-06-26 14:32:12 -0700429 }
430 mPausedStateMap[JobKeyType(clientId, jobId)] = pauseStates;
431
432 ALOGI("%s: transcoder paused", __FUNCTION__);
Chong Zhangf9077512020-09-21 21:02:06 -0700433 return AMEDIA_OK;
Chong Zhangb55c5452020-06-26 14:32:12 -0700434}
435
Chong Zhangf9077512020-09-21 21:02:06 -0700436media_status_t TranscoderWrapper::handleResume(
Chong Zhangb55c5452020-06-26 14:32:12 -0700437 ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
438 const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
439 std::shared_ptr<const Parcel> pausedState;
440 auto it = mPausedStateMap.find(JobKeyType(clientId, jobId));
441 if (it != mPausedStateMap.end()) {
442 pausedState = it->second;
443 mPausedStateMap.erase(it);
444 } else {
445 ALOGE("%s: can't find paused state", __FUNCTION__);
Chong Zhangf9077512020-09-21 21:02:06 -0700446 return AMEDIA_ERROR_INVALID_OPERATION;
Chong Zhangb55c5452020-06-26 14:32:12 -0700447 }
448
Chong Zhangf9077512020-09-21 21:02:06 -0700449 ALOGI("%s: setting up transcoder for resume", __FUNCTION__);
450 media_status_t err = setupTranscoder(clientId, jobId, request, clientCb, pausedState);
451 if (err != AMEDIA_OK) {
452 ALOGE("%s: failed to setup transcoder: %d", __FUNCTION__, err);
Chong Zhangb55c5452020-06-26 14:32:12 -0700453 return err;
454 }
455
Chong Zhangf9077512020-09-21 21:02:06 -0700456 err = mTranscoder->resume();
457 if (err != AMEDIA_OK) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700458 ALOGE("%s: failed to resume transcoder: %d", __FUNCTION__, err);
Chong Zhangf9077512020-09-21 21:02:06 -0700459 return err;
Chong Zhangb55c5452020-06-26 14:32:12 -0700460 }
461
462 ALOGI("%s: transcoder resumed", __FUNCTION__);
Chong Zhangf9077512020-09-21 21:02:06 -0700463 return AMEDIA_OK;
Chong Zhang66469272020-06-04 16:51:55 -0700464}
465
466void TranscoderWrapper::cleanup() {
467 mCurrentClientId = 0;
468 mCurrentJobId = -1;
469 mTranscoderCb = nullptr;
470 mTranscoder = nullptr;
471}
472
473void TranscoderWrapper::queueEvent(Event::Type type, ClientIdType clientId, JobIdType jobId,
Chong Zhangf9077512020-09-21 21:02:06 -0700474 const std::function<void()> runnable, int32_t arg) {
Chong Zhang66469272020-06-04 16:51:55 -0700475 std::scoped_lock lock{mLock};
476
Chong Zhangf9077512020-09-21 21:02:06 -0700477 mQueue.push_back({type, clientId, jobId, runnable, arg});
Chong Zhang66469272020-06-04 16:51:55 -0700478 mCondition.notify_one();
479}
480
481void TranscoderWrapper::threadLoop() {
482 std::unique_lock<std::mutex> lock{mLock};
483 // TranscoderWrapper currently lives in the transcoding service, as long as
484 // MediaTranscodingService itself.
485 while (true) {
486 // Wait for the next event.
487 while (mQueue.empty()) {
488 mCondition.wait(lock);
489 }
490
491 Event event = *mQueue.begin();
492 mQueue.pop_front();
493
Chong Zhangf9077512020-09-21 21:02:06 -0700494 ALOGD("%s: %s", __FUNCTION__, toString(event).c_str());
Chong Zhang66469272020-06-04 16:51:55 -0700495
Chong Zhangb55c5452020-06-26 14:32:12 -0700496 lock.unlock();
Chong Zhang66469272020-06-04 16:51:55 -0700497 event.runnable();
Chong Zhangb55c5452020-06-26 14:32:12 -0700498 lock.lock();
Chong Zhang66469272020-06-04 16:51:55 -0700499 }
500}
501
502} // namespace android