1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker * Copyright (C) 2020 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker *
4*ec779b8eSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker *
8*ec779b8eSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker *
10*ec779b8eSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker */
16*ec779b8eSAndroid Build Coastguard Worker
17*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
18*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "TranscoderWrapper"
19*ec779b8eSAndroid Build Coastguard Worker
20*ec779b8eSAndroid Build Coastguard Worker #include <aidl/android/media/TranscodingErrorCode.h>
21*ec779b8eSAndroid Build Coastguard Worker #include <aidl/android/media/TranscodingRequestParcel.h>
22*ec779b8eSAndroid Build Coastguard Worker #include <media/MediaTranscoder.h>
23*ec779b8eSAndroid Build Coastguard Worker #include <media/NdkCommon.h>
24*ec779b8eSAndroid Build Coastguard Worker #include <media/TranscoderWrapper.h>
25*ec779b8eSAndroid Build Coastguard Worker #include <media/TranscodingRequest.h>
26*ec779b8eSAndroid Build Coastguard Worker #include <utils/AndroidThreads.h>
27*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
28*ec779b8eSAndroid Build Coastguard Worker
29*ec779b8eSAndroid Build Coastguard Worker #include <thread>
30*ec779b8eSAndroid Build Coastguard Worker
31*ec779b8eSAndroid Build Coastguard Worker namespace android {
32*ec779b8eSAndroid Build Coastguard Worker using Status = ::ndk::ScopedAStatus;
33*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::media::TranscodingErrorCode;
34*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::media::TranscodingVideoCodecType;
35*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::media::TranscodingVideoTrackFormat;
36*ec779b8eSAndroid Build Coastguard Worker
toTranscodingError(media_status_t status)37*ec779b8eSAndroid Build Coastguard Worker static TranscodingErrorCode toTranscodingError(media_status_t status) {
38*ec779b8eSAndroid Build Coastguard Worker switch (status) {
39*ec779b8eSAndroid Build Coastguard Worker case AMEDIA_OK:
40*ec779b8eSAndroid Build Coastguard Worker return TranscodingErrorCode::kNoError;
41*ec779b8eSAndroid Build Coastguard Worker case AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE: // FALLTHRU
42*ec779b8eSAndroid Build Coastguard Worker case AMEDIACODEC_ERROR_RECLAIMED:
43*ec779b8eSAndroid Build Coastguard Worker return TranscodingErrorCode::kInsufficientResources;
44*ec779b8eSAndroid Build Coastguard Worker case AMEDIA_ERROR_MALFORMED:
45*ec779b8eSAndroid Build Coastguard Worker return TranscodingErrorCode::kMalformed;
46*ec779b8eSAndroid Build Coastguard Worker case AMEDIA_ERROR_UNSUPPORTED:
47*ec779b8eSAndroid Build Coastguard Worker return TranscodingErrorCode::kUnsupported;
48*ec779b8eSAndroid Build Coastguard Worker case AMEDIA_ERROR_INVALID_OBJECT: // FALLTHRU
49*ec779b8eSAndroid Build Coastguard Worker case AMEDIA_ERROR_INVALID_PARAMETER:
50*ec779b8eSAndroid Build Coastguard Worker return TranscodingErrorCode::kInvalidParameter;
51*ec779b8eSAndroid Build Coastguard Worker case AMEDIA_ERROR_INVALID_OPERATION:
52*ec779b8eSAndroid Build Coastguard Worker return TranscodingErrorCode::kInvalidOperation;
53*ec779b8eSAndroid Build Coastguard Worker case AMEDIA_ERROR_IO:
54*ec779b8eSAndroid Build Coastguard Worker return TranscodingErrorCode::kErrorIO;
55*ec779b8eSAndroid Build Coastguard Worker case AMEDIA_ERROR_UNKNOWN: // FALLTHRU
56*ec779b8eSAndroid Build Coastguard Worker default:
57*ec779b8eSAndroid Build Coastguard Worker return TranscodingErrorCode::kUnknown;
58*ec779b8eSAndroid Build Coastguard Worker }
59*ec779b8eSAndroid Build Coastguard Worker }
60*ec779b8eSAndroid Build Coastguard Worker
getVideoFormat(const char * originalMime,const std::optional<TranscodingVideoTrackFormat> & requestedFormat)61*ec779b8eSAndroid Build Coastguard Worker static std::shared_ptr<AMediaFormat> getVideoFormat(
62*ec779b8eSAndroid Build Coastguard Worker const char* originalMime,
63*ec779b8eSAndroid Build Coastguard Worker const std::optional<TranscodingVideoTrackFormat>& requestedFormat) {
64*ec779b8eSAndroid Build Coastguard Worker if (requestedFormat == std::nullopt) {
65*ec779b8eSAndroid Build Coastguard Worker return nullptr;
66*ec779b8eSAndroid Build Coastguard Worker }
67*ec779b8eSAndroid Build Coastguard Worker
68*ec779b8eSAndroid Build Coastguard Worker std::shared_ptr<AMediaFormat> format =
69*ec779b8eSAndroid Build Coastguard Worker std::shared_ptr<AMediaFormat>(AMediaFormat_new(), &AMediaFormat_delete);
70*ec779b8eSAndroid Build Coastguard Worker bool changed = false;
71*ec779b8eSAndroid Build Coastguard Worker if (requestedFormat->codecType == TranscodingVideoCodecType::kHevc &&
72*ec779b8eSAndroid Build Coastguard Worker strcmp(originalMime, AMEDIA_MIMETYPE_VIDEO_HEVC)) {
73*ec779b8eSAndroid Build Coastguard Worker AMediaFormat_setString(format.get(), AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_HEVC);
74*ec779b8eSAndroid Build Coastguard Worker changed = true;
75*ec779b8eSAndroid Build Coastguard Worker } else if (requestedFormat->codecType == TranscodingVideoCodecType::kAvc &&
76*ec779b8eSAndroid Build Coastguard Worker strcmp(originalMime, AMEDIA_MIMETYPE_VIDEO_AVC)) {
77*ec779b8eSAndroid Build Coastguard Worker AMediaFormat_setString(format.get(), AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_AVC);
78*ec779b8eSAndroid Build Coastguard Worker changed = true;
79*ec779b8eSAndroid Build Coastguard Worker }
80*ec779b8eSAndroid Build Coastguard Worker if (requestedFormat->bitrateBps > 0) {
81*ec779b8eSAndroid Build Coastguard Worker AMediaFormat_setInt32(format.get(), AMEDIAFORMAT_KEY_BIT_RATE, requestedFormat->bitrateBps);
82*ec779b8eSAndroid Build Coastguard Worker changed = true;
83*ec779b8eSAndroid Build Coastguard Worker }
84*ec779b8eSAndroid Build Coastguard Worker // TODO: translate other fields from requestedFormat to the format for MediaTranscoder.
85*ec779b8eSAndroid Build Coastguard Worker // Also need to determine more settings to expose in TranscodingVideoTrackFormat.
86*ec779b8eSAndroid Build Coastguard Worker if (!changed) {
87*ec779b8eSAndroid Build Coastguard Worker // Use null format for passthru.
88*ec779b8eSAndroid Build Coastguard Worker format.reset();
89*ec779b8eSAndroid Build Coastguard Worker }
90*ec779b8eSAndroid Build Coastguard Worker return format;
91*ec779b8eSAndroid Build Coastguard Worker }
92*ec779b8eSAndroid Build Coastguard Worker
93*ec779b8eSAndroid Build Coastguard Worker //static
toString(const Event & event)94*ec779b8eSAndroid Build Coastguard Worker std::string TranscoderWrapper::toString(const Event& event) {
95*ec779b8eSAndroid Build Coastguard Worker std::string typeStr;
96*ec779b8eSAndroid Build Coastguard Worker switch (event.type) {
97*ec779b8eSAndroid Build Coastguard Worker case Event::Start:
98*ec779b8eSAndroid Build Coastguard Worker typeStr = "Start";
99*ec779b8eSAndroid Build Coastguard Worker break;
100*ec779b8eSAndroid Build Coastguard Worker case Event::Pause:
101*ec779b8eSAndroid Build Coastguard Worker typeStr = "Pause";
102*ec779b8eSAndroid Build Coastguard Worker break;
103*ec779b8eSAndroid Build Coastguard Worker case Event::Resume:
104*ec779b8eSAndroid Build Coastguard Worker typeStr = "Resume";
105*ec779b8eSAndroid Build Coastguard Worker break;
106*ec779b8eSAndroid Build Coastguard Worker case Event::Stop:
107*ec779b8eSAndroid Build Coastguard Worker typeStr = "Stop";
108*ec779b8eSAndroid Build Coastguard Worker break;
109*ec779b8eSAndroid Build Coastguard Worker case Event::Finish:
110*ec779b8eSAndroid Build Coastguard Worker typeStr = "Finish";
111*ec779b8eSAndroid Build Coastguard Worker break;
112*ec779b8eSAndroid Build Coastguard Worker case Event::Error:
113*ec779b8eSAndroid Build Coastguard Worker typeStr = "Error";
114*ec779b8eSAndroid Build Coastguard Worker break;
115*ec779b8eSAndroid Build Coastguard Worker case Event::Progress:
116*ec779b8eSAndroid Build Coastguard Worker typeStr = "Progress";
117*ec779b8eSAndroid Build Coastguard Worker break;
118*ec779b8eSAndroid Build Coastguard Worker case Event::HeartBeat:
119*ec779b8eSAndroid Build Coastguard Worker typeStr = "HeartBeat";
120*ec779b8eSAndroid Build Coastguard Worker break;
121*ec779b8eSAndroid Build Coastguard Worker case Event::Abandon:
122*ec779b8eSAndroid Build Coastguard Worker typeStr = "Abandon";
123*ec779b8eSAndroid Build Coastguard Worker break;
124*ec779b8eSAndroid Build Coastguard Worker default:
125*ec779b8eSAndroid Build Coastguard Worker return "(unknown)";
126*ec779b8eSAndroid Build Coastguard Worker }
127*ec779b8eSAndroid Build Coastguard Worker std::string result;
128*ec779b8eSAndroid Build Coastguard Worker result = "session {" + std::to_string(event.clientId) + "," + std::to_string(event.sessionId) +
129*ec779b8eSAndroid Build Coastguard Worker "}: " + typeStr;
130*ec779b8eSAndroid Build Coastguard Worker if (event.type == Event::Error || event.type == Event::Progress) {
131*ec779b8eSAndroid Build Coastguard Worker result += " " + std::to_string(event.arg);
132*ec779b8eSAndroid Build Coastguard Worker }
133*ec779b8eSAndroid Build Coastguard Worker return result;
134*ec779b8eSAndroid Build Coastguard Worker }
135*ec779b8eSAndroid Build Coastguard Worker
136*ec779b8eSAndroid Build Coastguard Worker class TranscoderWrapper::CallbackImpl : public MediaTranscoder::CallbackInterface {
137*ec779b8eSAndroid Build Coastguard Worker public:
CallbackImpl(const std::shared_ptr<TranscoderWrapper> & owner,ClientIdType clientId,SessionIdType sessionId)138*ec779b8eSAndroid Build Coastguard Worker CallbackImpl(const std::shared_ptr<TranscoderWrapper>& owner, ClientIdType clientId,
139*ec779b8eSAndroid Build Coastguard Worker SessionIdType sessionId)
140*ec779b8eSAndroid Build Coastguard Worker : mOwner(owner), mClientId(clientId), mSessionId(sessionId) {}
141*ec779b8eSAndroid Build Coastguard Worker
onFinished(const MediaTranscoder * transcoder __unused)142*ec779b8eSAndroid Build Coastguard Worker virtual void onFinished(const MediaTranscoder* transcoder __unused) override {
143*ec779b8eSAndroid Build Coastguard Worker auto owner = mOwner.lock();
144*ec779b8eSAndroid Build Coastguard Worker if (owner != nullptr) {
145*ec779b8eSAndroid Build Coastguard Worker owner->onFinish(mClientId, mSessionId);
146*ec779b8eSAndroid Build Coastguard Worker }
147*ec779b8eSAndroid Build Coastguard Worker }
148*ec779b8eSAndroid Build Coastguard Worker
onError(const MediaTranscoder * transcoder __unused,media_status_t error)149*ec779b8eSAndroid Build Coastguard Worker virtual void onError(const MediaTranscoder* transcoder __unused,
150*ec779b8eSAndroid Build Coastguard Worker media_status_t error) override {
151*ec779b8eSAndroid Build Coastguard Worker auto owner = mOwner.lock();
152*ec779b8eSAndroid Build Coastguard Worker if (owner != nullptr) {
153*ec779b8eSAndroid Build Coastguard Worker owner->onError(mClientId, mSessionId, error);
154*ec779b8eSAndroid Build Coastguard Worker }
155*ec779b8eSAndroid Build Coastguard Worker }
156*ec779b8eSAndroid Build Coastguard Worker
onProgressUpdate(const MediaTranscoder * transcoder __unused,int32_t progress)157*ec779b8eSAndroid Build Coastguard Worker virtual void onProgressUpdate(const MediaTranscoder* transcoder __unused,
158*ec779b8eSAndroid Build Coastguard Worker int32_t progress) override {
159*ec779b8eSAndroid Build Coastguard Worker auto owner = mOwner.lock();
160*ec779b8eSAndroid Build Coastguard Worker if (owner != nullptr) {
161*ec779b8eSAndroid Build Coastguard Worker owner->onProgress(mClientId, mSessionId, progress);
162*ec779b8eSAndroid Build Coastguard Worker }
163*ec779b8eSAndroid Build Coastguard Worker }
164*ec779b8eSAndroid Build Coastguard Worker
onHeartBeat(const MediaTranscoder * transcoder __unused)165*ec779b8eSAndroid Build Coastguard Worker virtual void onHeartBeat(const MediaTranscoder* transcoder __unused) override {
166*ec779b8eSAndroid Build Coastguard Worker auto owner = mOwner.lock();
167*ec779b8eSAndroid Build Coastguard Worker if (owner != nullptr) {
168*ec779b8eSAndroid Build Coastguard Worker owner->onHeartBeat(mClientId, mSessionId);
169*ec779b8eSAndroid Build Coastguard Worker }
170*ec779b8eSAndroid Build Coastguard Worker }
171*ec779b8eSAndroid Build Coastguard Worker
onCodecResourceLost(const MediaTranscoder * transcoder __unused,const std::shared_ptr<ndk::ScopedAParcel> & pausedState __unused)172*ec779b8eSAndroid Build Coastguard Worker virtual void onCodecResourceLost(const MediaTranscoder* transcoder __unused,
173*ec779b8eSAndroid Build Coastguard Worker const std::shared_ptr<ndk::ScopedAParcel>& pausedState
174*ec779b8eSAndroid Build Coastguard Worker __unused) override {
175*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s: session {%lld, %d}", __FUNCTION__, (long long)mClientId, mSessionId);
176*ec779b8eSAndroid Build Coastguard Worker }
177*ec779b8eSAndroid Build Coastguard Worker
178*ec779b8eSAndroid Build Coastguard Worker private:
179*ec779b8eSAndroid Build Coastguard Worker std::weak_ptr<TranscoderWrapper> mOwner;
180*ec779b8eSAndroid Build Coastguard Worker ClientIdType mClientId;
181*ec779b8eSAndroid Build Coastguard Worker SessionIdType mSessionId;
182*ec779b8eSAndroid Build Coastguard Worker };
183*ec779b8eSAndroid Build Coastguard Worker
TranscoderWrapper(const std::shared_ptr<TranscoderCallbackInterface> & cb,const std::shared_ptr<TranscodingLogger> & logger,int64_t heartBeatIntervalUs)184*ec779b8eSAndroid Build Coastguard Worker TranscoderWrapper::TranscoderWrapper(const std::shared_ptr<TranscoderCallbackInterface>& cb,
185*ec779b8eSAndroid Build Coastguard Worker const std::shared_ptr<TranscodingLogger>& logger,
186*ec779b8eSAndroid Build Coastguard Worker int64_t heartBeatIntervalUs)
187*ec779b8eSAndroid Build Coastguard Worker : mCallback(cb),
188*ec779b8eSAndroid Build Coastguard Worker mLogger(logger),
189*ec779b8eSAndroid Build Coastguard Worker mHeartBeatIntervalUs(heartBeatIntervalUs),
190*ec779b8eSAndroid Build Coastguard Worker mCurrentClientId(0),
191*ec779b8eSAndroid Build Coastguard Worker mCurrentSessionId(-1),
192*ec779b8eSAndroid Build Coastguard Worker mLooperReady(false) {
193*ec779b8eSAndroid Build Coastguard Worker ALOGV("TranscoderWrapper CTOR: %p", this);
194*ec779b8eSAndroid Build Coastguard Worker }
195*ec779b8eSAndroid Build Coastguard Worker
~TranscoderWrapper()196*ec779b8eSAndroid Build Coastguard Worker TranscoderWrapper::~TranscoderWrapper() {
197*ec779b8eSAndroid Build Coastguard Worker ALOGV("TranscoderWrapper DTOR: %p", this);
198*ec779b8eSAndroid Build Coastguard Worker }
199*ec779b8eSAndroid Build Coastguard Worker
isResourceError(media_status_t err)200*ec779b8eSAndroid Build Coastguard Worker static bool isResourceError(media_status_t err) {
201*ec779b8eSAndroid Build Coastguard Worker return err == AMEDIACODEC_ERROR_RECLAIMED || err == AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE;
202*ec779b8eSAndroid Build Coastguard Worker }
203*ec779b8eSAndroid Build Coastguard Worker
reportError(ClientIdType clientId,SessionIdType sessionId,media_status_t err)204*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::reportError(ClientIdType clientId, SessionIdType sessionId,
205*ec779b8eSAndroid Build Coastguard Worker media_status_t err) {
206*ec779b8eSAndroid Build Coastguard Worker auto callback = mCallback.lock();
207*ec779b8eSAndroid Build Coastguard Worker if (callback != nullptr) {
208*ec779b8eSAndroid Build Coastguard Worker if (isResourceError(err)) {
209*ec779b8eSAndroid Build Coastguard Worker // Add a placeholder pause state to mPausedStateMap. This is required when resuming.
210*ec779b8eSAndroid Build Coastguard Worker // TODO: remove this when transcoder pause/resume logic is ready. New logic will
211*ec779b8eSAndroid Build Coastguard Worker // no longer use the pause states.
212*ec779b8eSAndroid Build Coastguard Worker auto it = mPausedStateMap.find(SessionKeyType(clientId, sessionId));
213*ec779b8eSAndroid Build Coastguard Worker if (it == mPausedStateMap.end()) {
214*ec779b8eSAndroid Build Coastguard Worker mPausedStateMap.emplace(SessionKeyType(clientId, sessionId),
215*ec779b8eSAndroid Build Coastguard Worker new ndk::ScopedAParcel());
216*ec779b8eSAndroid Build Coastguard Worker }
217*ec779b8eSAndroid Build Coastguard Worker
218*ec779b8eSAndroid Build Coastguard Worker callback->onResourceLost(clientId, sessionId);
219*ec779b8eSAndroid Build Coastguard Worker } else {
220*ec779b8eSAndroid Build Coastguard Worker callback->onError(clientId, sessionId, toTranscodingError(err));
221*ec779b8eSAndroid Build Coastguard Worker }
222*ec779b8eSAndroid Build Coastguard Worker }
223*ec779b8eSAndroid Build Coastguard Worker }
224*ec779b8eSAndroid Build Coastguard Worker
start(ClientIdType clientId,SessionIdType sessionId,const TranscodingRequestParcel & requestParcel,uid_t callingUid,const std::shared_ptr<ITranscodingClientCallback> & clientCb)225*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::start(ClientIdType clientId, SessionIdType sessionId,
226*ec779b8eSAndroid Build Coastguard Worker const TranscodingRequestParcel& requestParcel, uid_t callingUid,
227*ec779b8eSAndroid Build Coastguard Worker const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
228*ec779b8eSAndroid Build Coastguard Worker TranscodingRequest request{requestParcel};
229*ec779b8eSAndroid Build Coastguard Worker queueEvent(Event::Start, clientId, sessionId, [=] {
230*ec779b8eSAndroid Build Coastguard Worker media_status_t err = handleStart(clientId, sessionId, request, callingUid, clientCb);
231*ec779b8eSAndroid Build Coastguard Worker if (err != AMEDIA_OK) {
232*ec779b8eSAndroid Build Coastguard Worker cleanup();
233*ec779b8eSAndroid Build Coastguard Worker reportError(clientId, sessionId, err);
234*ec779b8eSAndroid Build Coastguard Worker } else {
235*ec779b8eSAndroid Build Coastguard Worker auto callback = mCallback.lock();
236*ec779b8eSAndroid Build Coastguard Worker if (callback != nullptr) {
237*ec779b8eSAndroid Build Coastguard Worker callback->onStarted(clientId, sessionId);
238*ec779b8eSAndroid Build Coastguard Worker }
239*ec779b8eSAndroid Build Coastguard Worker }
240*ec779b8eSAndroid Build Coastguard Worker });
241*ec779b8eSAndroid Build Coastguard Worker }
242*ec779b8eSAndroid Build Coastguard Worker
pause(ClientIdType clientId,SessionIdType sessionId)243*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::pause(ClientIdType clientId, SessionIdType sessionId) {
244*ec779b8eSAndroid Build Coastguard Worker queueEvent(Event::Pause, clientId, sessionId, [=] {
245*ec779b8eSAndroid Build Coastguard Worker media_status_t err = handlePause(clientId, sessionId);
246*ec779b8eSAndroid Build Coastguard Worker
247*ec779b8eSAndroid Build Coastguard Worker cleanup();
248*ec779b8eSAndroid Build Coastguard Worker
249*ec779b8eSAndroid Build Coastguard Worker if (err != AMEDIA_OK) {
250*ec779b8eSAndroid Build Coastguard Worker reportError(clientId, sessionId, err);
251*ec779b8eSAndroid Build Coastguard Worker } else {
252*ec779b8eSAndroid Build Coastguard Worker auto callback = mCallback.lock();
253*ec779b8eSAndroid Build Coastguard Worker if (callback != nullptr) {
254*ec779b8eSAndroid Build Coastguard Worker callback->onPaused(clientId, sessionId);
255*ec779b8eSAndroid Build Coastguard Worker }
256*ec779b8eSAndroid Build Coastguard Worker }
257*ec779b8eSAndroid Build Coastguard Worker });
258*ec779b8eSAndroid Build Coastguard Worker }
259*ec779b8eSAndroid Build Coastguard Worker
resume(ClientIdType clientId,SessionIdType sessionId,const TranscodingRequestParcel & requestParcel,uid_t callingUid,const std::shared_ptr<ITranscodingClientCallback> & clientCb)260*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::resume(ClientIdType clientId, SessionIdType sessionId,
261*ec779b8eSAndroid Build Coastguard Worker const TranscodingRequestParcel& requestParcel, uid_t callingUid,
262*ec779b8eSAndroid Build Coastguard Worker const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
263*ec779b8eSAndroid Build Coastguard Worker TranscodingRequest request{requestParcel};
264*ec779b8eSAndroid Build Coastguard Worker queueEvent(Event::Resume, clientId, sessionId, [=] {
265*ec779b8eSAndroid Build Coastguard Worker media_status_t err = handleResume(clientId, sessionId, request, callingUid, clientCb);
266*ec779b8eSAndroid Build Coastguard Worker if (err != AMEDIA_OK) {
267*ec779b8eSAndroid Build Coastguard Worker cleanup();
268*ec779b8eSAndroid Build Coastguard Worker reportError(clientId, sessionId, err);
269*ec779b8eSAndroid Build Coastguard Worker } else {
270*ec779b8eSAndroid Build Coastguard Worker auto callback = mCallback.lock();
271*ec779b8eSAndroid Build Coastguard Worker if (callback != nullptr) {
272*ec779b8eSAndroid Build Coastguard Worker callback->onResumed(clientId, sessionId);
273*ec779b8eSAndroid Build Coastguard Worker }
274*ec779b8eSAndroid Build Coastguard Worker }
275*ec779b8eSAndroid Build Coastguard Worker });
276*ec779b8eSAndroid Build Coastguard Worker }
277*ec779b8eSAndroid Build Coastguard Worker
stop(ClientIdType clientId,SessionIdType sessionId,bool abandon)278*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::stop(ClientIdType clientId, SessionIdType sessionId, bool abandon) {
279*ec779b8eSAndroid Build Coastguard Worker queueEvent(Event::Stop, clientId, sessionId, [=] {
280*ec779b8eSAndroid Build Coastguard Worker if (mTranscoder != nullptr && clientId == mCurrentClientId &&
281*ec779b8eSAndroid Build Coastguard Worker sessionId == mCurrentSessionId) {
282*ec779b8eSAndroid Build Coastguard Worker // Cancelling the currently running session.
283*ec779b8eSAndroid Build Coastguard Worker media_status_t err = mTranscoder->cancel();
284*ec779b8eSAndroid Build Coastguard Worker if (err != AMEDIA_OK) {
285*ec779b8eSAndroid Build Coastguard Worker ALOGW("failed to stop transcoder: %d", err);
286*ec779b8eSAndroid Build Coastguard Worker } else {
287*ec779b8eSAndroid Build Coastguard Worker ALOGI("transcoder stopped");
288*ec779b8eSAndroid Build Coastguard Worker }
289*ec779b8eSAndroid Build Coastguard Worker logSessionEnded(TranscodingLogger::SessionEndedReason::CANCELLED, err);
290*ec779b8eSAndroid Build Coastguard Worker cleanup();
291*ec779b8eSAndroid Build Coastguard Worker } else {
292*ec779b8eSAndroid Build Coastguard Worker // For sessions that's not currently running, release any pausedState for the session.
293*ec779b8eSAndroid Build Coastguard Worker mPausedStateMap.erase(SessionKeyType(clientId, sessionId));
294*ec779b8eSAndroid Build Coastguard Worker }
295*ec779b8eSAndroid Build Coastguard Worker // No callback needed for stop.
296*ec779b8eSAndroid Build Coastguard Worker });
297*ec779b8eSAndroid Build Coastguard Worker
298*ec779b8eSAndroid Build Coastguard Worker if (abandon) {
299*ec779b8eSAndroid Build Coastguard Worker queueEvent(Event::Abandon, 0, 0, nullptr);
300*ec779b8eSAndroid Build Coastguard Worker }
301*ec779b8eSAndroid Build Coastguard Worker }
302*ec779b8eSAndroid Build Coastguard Worker
onFinish(ClientIdType clientId,SessionIdType sessionId)303*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::onFinish(ClientIdType clientId, SessionIdType sessionId) {
304*ec779b8eSAndroid Build Coastguard Worker queueEvent(Event::Finish, clientId, sessionId, [=] {
305*ec779b8eSAndroid Build Coastguard Worker if (mTranscoder != nullptr && clientId == mCurrentClientId &&
306*ec779b8eSAndroid Build Coastguard Worker sessionId == mCurrentSessionId) {
307*ec779b8eSAndroid Build Coastguard Worker logSessionEnded(TranscodingLogger::SessionEndedReason::FINISHED, AMEDIA_OK);
308*ec779b8eSAndroid Build Coastguard Worker cleanup();
309*ec779b8eSAndroid Build Coastguard Worker }
310*ec779b8eSAndroid Build Coastguard Worker
311*ec779b8eSAndroid Build Coastguard Worker auto callback = mCallback.lock();
312*ec779b8eSAndroid Build Coastguard Worker if (callback != nullptr) {
313*ec779b8eSAndroid Build Coastguard Worker callback->onFinish(clientId, sessionId);
314*ec779b8eSAndroid Build Coastguard Worker }
315*ec779b8eSAndroid Build Coastguard Worker });
316*ec779b8eSAndroid Build Coastguard Worker }
317*ec779b8eSAndroid Build Coastguard Worker
onError(ClientIdType clientId,SessionIdType sessionId,media_status_t error)318*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::onError(ClientIdType clientId, SessionIdType sessionId,
319*ec779b8eSAndroid Build Coastguard Worker media_status_t error) {
320*ec779b8eSAndroid Build Coastguard Worker queueEvent(
321*ec779b8eSAndroid Build Coastguard Worker Event::Error, clientId, sessionId,
322*ec779b8eSAndroid Build Coastguard Worker [=] {
323*ec779b8eSAndroid Build Coastguard Worker if (mTranscoder != nullptr && clientId == mCurrentClientId &&
324*ec779b8eSAndroid Build Coastguard Worker sessionId == mCurrentSessionId) {
325*ec779b8eSAndroid Build Coastguard Worker logSessionEnded(TranscodingLogger::SessionEndedReason::ERROR, error);
326*ec779b8eSAndroid Build Coastguard Worker cleanup();
327*ec779b8eSAndroid Build Coastguard Worker }
328*ec779b8eSAndroid Build Coastguard Worker reportError(clientId, sessionId, error);
329*ec779b8eSAndroid Build Coastguard Worker },
330*ec779b8eSAndroid Build Coastguard Worker error);
331*ec779b8eSAndroid Build Coastguard Worker }
332*ec779b8eSAndroid Build Coastguard Worker
onProgress(ClientIdType clientId,SessionIdType sessionId,int32_t progress)333*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::onProgress(ClientIdType clientId, SessionIdType sessionId,
334*ec779b8eSAndroid Build Coastguard Worker int32_t progress) {
335*ec779b8eSAndroid Build Coastguard Worker queueEvent(
336*ec779b8eSAndroid Build Coastguard Worker Event::Progress, clientId, sessionId,
337*ec779b8eSAndroid Build Coastguard Worker [=] {
338*ec779b8eSAndroid Build Coastguard Worker auto callback = mCallback.lock();
339*ec779b8eSAndroid Build Coastguard Worker if (callback != nullptr) {
340*ec779b8eSAndroid Build Coastguard Worker callback->onProgressUpdate(clientId, sessionId, progress);
341*ec779b8eSAndroid Build Coastguard Worker }
342*ec779b8eSAndroid Build Coastguard Worker },
343*ec779b8eSAndroid Build Coastguard Worker progress);
344*ec779b8eSAndroid Build Coastguard Worker }
345*ec779b8eSAndroid Build Coastguard Worker
onHeartBeat(ClientIdType clientId,SessionIdType sessionId)346*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::onHeartBeat(ClientIdType clientId, SessionIdType sessionId) {
347*ec779b8eSAndroid Build Coastguard Worker queueEvent(Event::HeartBeat, clientId, sessionId, [=] {
348*ec779b8eSAndroid Build Coastguard Worker auto callback = mCallback.lock();
349*ec779b8eSAndroid Build Coastguard Worker if (callback != nullptr) {
350*ec779b8eSAndroid Build Coastguard Worker callback->onHeartBeat(clientId, sessionId);
351*ec779b8eSAndroid Build Coastguard Worker }
352*ec779b8eSAndroid Build Coastguard Worker });
353*ec779b8eSAndroid Build Coastguard Worker }
354*ec779b8eSAndroid Build Coastguard Worker
setupTranscoder(ClientIdType clientId,SessionIdType sessionId,const TranscodingRequestParcel & request,uid_t callingUid,const std::shared_ptr<ITranscodingClientCallback> & clientCb,TranscodingLogger::SessionEndedReason * failureReason,const std::shared_ptr<ndk::ScopedAParcel> & pausedState)355*ec779b8eSAndroid Build Coastguard Worker media_status_t TranscoderWrapper::setupTranscoder(
356*ec779b8eSAndroid Build Coastguard Worker ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
357*ec779b8eSAndroid Build Coastguard Worker uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& clientCb,
358*ec779b8eSAndroid Build Coastguard Worker TranscodingLogger::SessionEndedReason* failureReason,
359*ec779b8eSAndroid Build Coastguard Worker const std::shared_ptr<ndk::ScopedAParcel>& pausedState) {
360*ec779b8eSAndroid Build Coastguard Worker if (clientCb == nullptr) {
361*ec779b8eSAndroid Build Coastguard Worker ALOGE("client callback is null");
362*ec779b8eSAndroid Build Coastguard Worker return AMEDIA_ERROR_INVALID_PARAMETER;
363*ec779b8eSAndroid Build Coastguard Worker }
364*ec779b8eSAndroid Build Coastguard Worker
365*ec779b8eSAndroid Build Coastguard Worker if (mTranscoder != nullptr) {
366*ec779b8eSAndroid Build Coastguard Worker ALOGE("transcoder already running");
367*ec779b8eSAndroid Build Coastguard Worker return AMEDIA_ERROR_INVALID_OPERATION;
368*ec779b8eSAndroid Build Coastguard Worker }
369*ec779b8eSAndroid Build Coastguard Worker
370*ec779b8eSAndroid Build Coastguard Worker // Unwrap the callback and send heartbeats to the client after each operation during setup.
371*ec779b8eSAndroid Build Coastguard Worker auto callback = mCallback.lock();
372*ec779b8eSAndroid Build Coastguard Worker if (callback == nullptr) {
373*ec779b8eSAndroid Build Coastguard Worker return AMEDIA_ERROR_INVALID_OPERATION;
374*ec779b8eSAndroid Build Coastguard Worker }
375*ec779b8eSAndroid Build Coastguard Worker
376*ec779b8eSAndroid Build Coastguard Worker Status status;
377*ec779b8eSAndroid Build Coastguard Worker ::ndk::ScopedFileDescriptor srcFd, dstFd;
378*ec779b8eSAndroid Build Coastguard Worker int srcFdInt = request.sourceFd.get();
379*ec779b8eSAndroid Build Coastguard Worker if (srcFdInt < 0) {
380*ec779b8eSAndroid Build Coastguard Worker status = clientCb->openFileDescriptor(request.sourceFilePath, "r", &srcFd);
381*ec779b8eSAndroid Build Coastguard Worker if (!status.isOk() || srcFd.get() < 0) {
382*ec779b8eSAndroid Build Coastguard Worker ALOGE("failed to open source");
383*ec779b8eSAndroid Build Coastguard Worker *failureReason = TranscodingLogger::SessionEndedReason::OPEN_SRC_FD_FAILED;
384*ec779b8eSAndroid Build Coastguard Worker return AMEDIA_ERROR_IO;
385*ec779b8eSAndroid Build Coastguard Worker }
386*ec779b8eSAndroid Build Coastguard Worker srcFdInt = srcFd.get();
387*ec779b8eSAndroid Build Coastguard Worker }
388*ec779b8eSAndroid Build Coastguard Worker
389*ec779b8eSAndroid Build Coastguard Worker callback->onHeartBeat(clientId, sessionId);
390*ec779b8eSAndroid Build Coastguard Worker
391*ec779b8eSAndroid Build Coastguard Worker int dstFdInt = request.destinationFd.get();
392*ec779b8eSAndroid Build Coastguard Worker if (dstFdInt < 0) {
393*ec779b8eSAndroid Build Coastguard Worker // Open dest file with "rw", as the transcoder could potentially reuse part of it
394*ec779b8eSAndroid Build Coastguard Worker // for resume case. We might want the further differentiate and open with "w" only
395*ec779b8eSAndroid Build Coastguard Worker // for start.
396*ec779b8eSAndroid Build Coastguard Worker status = clientCb->openFileDescriptor(request.destinationFilePath, "rw", &dstFd);
397*ec779b8eSAndroid Build Coastguard Worker if (!status.isOk() || dstFd.get() < 0) {
398*ec779b8eSAndroid Build Coastguard Worker ALOGE("failed to open destination");
399*ec779b8eSAndroid Build Coastguard Worker *failureReason = TranscodingLogger::SessionEndedReason::OPEN_DST_FD_FAILED;
400*ec779b8eSAndroid Build Coastguard Worker return AMEDIA_ERROR_IO;
401*ec779b8eSAndroid Build Coastguard Worker }
402*ec779b8eSAndroid Build Coastguard Worker dstFdInt = dstFd.get();
403*ec779b8eSAndroid Build Coastguard Worker }
404*ec779b8eSAndroid Build Coastguard Worker
405*ec779b8eSAndroid Build Coastguard Worker callback->onHeartBeat(clientId, sessionId);
406*ec779b8eSAndroid Build Coastguard Worker
407*ec779b8eSAndroid Build Coastguard Worker mCurrentClientId = clientId;
408*ec779b8eSAndroid Build Coastguard Worker mCurrentSessionId = sessionId;
409*ec779b8eSAndroid Build Coastguard Worker mCurrentCallingUid = callingUid;
410*ec779b8eSAndroid Build Coastguard Worker mTranscoderCb = std::make_shared<CallbackImpl>(shared_from_this(), clientId, sessionId);
411*ec779b8eSAndroid Build Coastguard Worker mTranscoder = MediaTranscoder::create(mTranscoderCb, mHeartBeatIntervalUs, request.clientPid,
412*ec779b8eSAndroid Build Coastguard Worker request.clientUid, pausedState);
413*ec779b8eSAndroid Build Coastguard Worker if (mTranscoder == nullptr) {
414*ec779b8eSAndroid Build Coastguard Worker ALOGE("failed to create transcoder");
415*ec779b8eSAndroid Build Coastguard Worker *failureReason = TranscodingLogger::SessionEndedReason::CREATE_FAILED;
416*ec779b8eSAndroid Build Coastguard Worker return AMEDIA_ERROR_UNKNOWN;
417*ec779b8eSAndroid Build Coastguard Worker }
418*ec779b8eSAndroid Build Coastguard Worker
419*ec779b8eSAndroid Build Coastguard Worker callback->onHeartBeat(clientId, sessionId);
420*ec779b8eSAndroid Build Coastguard Worker
421*ec779b8eSAndroid Build Coastguard Worker media_status_t err = mTranscoder->configureSource(srcFdInt);
422*ec779b8eSAndroid Build Coastguard Worker if (err != AMEDIA_OK) {
423*ec779b8eSAndroid Build Coastguard Worker ALOGE("failed to configure source: %d", err);
424*ec779b8eSAndroid Build Coastguard Worker *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_SRC_FAILED;
425*ec779b8eSAndroid Build Coastguard Worker return err;
426*ec779b8eSAndroid Build Coastguard Worker }
427*ec779b8eSAndroid Build Coastguard Worker
428*ec779b8eSAndroid Build Coastguard Worker callback->onHeartBeat(clientId, sessionId);
429*ec779b8eSAndroid Build Coastguard Worker
430*ec779b8eSAndroid Build Coastguard Worker std::vector<std::shared_ptr<AMediaFormat>> trackFormats = mTranscoder->getTrackFormats();
431*ec779b8eSAndroid Build Coastguard Worker if (trackFormats.size() == 0) {
432*ec779b8eSAndroid Build Coastguard Worker ALOGE("failed to get track formats!");
433*ec779b8eSAndroid Build Coastguard Worker *failureReason = TranscodingLogger::SessionEndedReason::NO_TRACKS;
434*ec779b8eSAndroid Build Coastguard Worker return AMEDIA_ERROR_MALFORMED;
435*ec779b8eSAndroid Build Coastguard Worker }
436*ec779b8eSAndroid Build Coastguard Worker
437*ec779b8eSAndroid Build Coastguard Worker callback->onHeartBeat(clientId, sessionId);
438*ec779b8eSAndroid Build Coastguard Worker
439*ec779b8eSAndroid Build Coastguard Worker for (int i = 0; i < trackFormats.size(); ++i) {
440*ec779b8eSAndroid Build Coastguard Worker std::shared_ptr<AMediaFormat> format;
441*ec779b8eSAndroid Build Coastguard Worker const char* mime = nullptr;
442*ec779b8eSAndroid Build Coastguard Worker AMediaFormat_getString(trackFormats[i].get(), AMEDIAFORMAT_KEY_MIME, &mime);
443*ec779b8eSAndroid Build Coastguard Worker
444*ec779b8eSAndroid Build Coastguard Worker if (!strncmp(mime, "video/", 6)) {
445*ec779b8eSAndroid Build Coastguard Worker format = getVideoFormat(mime, request.requestedVideoTrackFormat);
446*ec779b8eSAndroid Build Coastguard Worker
447*ec779b8eSAndroid Build Coastguard Worker mSrcFormat = trackFormats[i];
448*ec779b8eSAndroid Build Coastguard Worker mDstFormat = format;
449*ec779b8eSAndroid Build Coastguard Worker }
450*ec779b8eSAndroid Build Coastguard Worker
451*ec779b8eSAndroid Build Coastguard Worker err = mTranscoder->configureTrackFormat(i, format.get());
452*ec779b8eSAndroid Build Coastguard Worker if (err != AMEDIA_OK) {
453*ec779b8eSAndroid Build Coastguard Worker ALOGE("failed to configure track format for track %d: %d", i, err);
454*ec779b8eSAndroid Build Coastguard Worker *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_TRACK_FAILED;
455*ec779b8eSAndroid Build Coastguard Worker return err;
456*ec779b8eSAndroid Build Coastguard Worker }
457*ec779b8eSAndroid Build Coastguard Worker
458*ec779b8eSAndroid Build Coastguard Worker callback->onHeartBeat(clientId, sessionId);
459*ec779b8eSAndroid Build Coastguard Worker }
460*ec779b8eSAndroid Build Coastguard Worker
461*ec779b8eSAndroid Build Coastguard Worker err = mTranscoder->configureDestination(dstFdInt);
462*ec779b8eSAndroid Build Coastguard Worker if (err != AMEDIA_OK) {
463*ec779b8eSAndroid Build Coastguard Worker ALOGE("failed to configure dest: %d", err);
464*ec779b8eSAndroid Build Coastguard Worker *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_DST_FAILED;
465*ec779b8eSAndroid Build Coastguard Worker return err;
466*ec779b8eSAndroid Build Coastguard Worker }
467*ec779b8eSAndroid Build Coastguard Worker
468*ec779b8eSAndroid Build Coastguard Worker callback->onHeartBeat(clientId, sessionId);
469*ec779b8eSAndroid Build Coastguard Worker
470*ec779b8eSAndroid Build Coastguard Worker return AMEDIA_OK;
471*ec779b8eSAndroid Build Coastguard Worker }
472*ec779b8eSAndroid Build Coastguard Worker
handleStart(ClientIdType clientId,SessionIdType sessionId,const TranscodingRequestParcel & request,uid_t callingUid,const std::shared_ptr<ITranscodingClientCallback> & clientCb)473*ec779b8eSAndroid Build Coastguard Worker media_status_t TranscoderWrapper::handleStart(
474*ec779b8eSAndroid Build Coastguard Worker ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
475*ec779b8eSAndroid Build Coastguard Worker uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
476*ec779b8eSAndroid Build Coastguard Worker ALOGI("%s: setting up transcoder for start", __FUNCTION__);
477*ec779b8eSAndroid Build Coastguard Worker TranscodingLogger::SessionEndedReason reason = TranscodingLogger::SessionEndedReason::UNKNOWN;
478*ec779b8eSAndroid Build Coastguard Worker media_status_t err =
479*ec779b8eSAndroid Build Coastguard Worker setupTranscoder(clientId, sessionId, request, callingUid, clientCb, &reason);
480*ec779b8eSAndroid Build Coastguard Worker if (err != AMEDIA_OK) {
481*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s: failed to setup transcoder", __FUNCTION__);
482*ec779b8eSAndroid Build Coastguard Worker logSessionEnded(reason, err);
483*ec779b8eSAndroid Build Coastguard Worker return err;
484*ec779b8eSAndroid Build Coastguard Worker }
485*ec779b8eSAndroid Build Coastguard Worker
486*ec779b8eSAndroid Build Coastguard Worker mTranscodeStartTime = std::chrono::steady_clock::now();
487*ec779b8eSAndroid Build Coastguard Worker
488*ec779b8eSAndroid Build Coastguard Worker err = mTranscoder->start();
489*ec779b8eSAndroid Build Coastguard Worker if (err != AMEDIA_OK) {
490*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s: failed to start transcoder: %d", __FUNCTION__, err);
491*ec779b8eSAndroid Build Coastguard Worker logSessionEnded(TranscodingLogger::SessionEndedReason::START_FAILED, err);
492*ec779b8eSAndroid Build Coastguard Worker return err;
493*ec779b8eSAndroid Build Coastguard Worker }
494*ec779b8eSAndroid Build Coastguard Worker
495*ec779b8eSAndroid Build Coastguard Worker ALOGI("%s: transcoder started", __FUNCTION__);
496*ec779b8eSAndroid Build Coastguard Worker return AMEDIA_OK;
497*ec779b8eSAndroid Build Coastguard Worker }
498*ec779b8eSAndroid Build Coastguard Worker
handlePause(ClientIdType clientId,SessionIdType sessionId)499*ec779b8eSAndroid Build Coastguard Worker media_status_t TranscoderWrapper::handlePause(ClientIdType clientId, SessionIdType sessionId) {
500*ec779b8eSAndroid Build Coastguard Worker if (mTranscoder == nullptr) {
501*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s: transcoder is not running", __FUNCTION__);
502*ec779b8eSAndroid Build Coastguard Worker return AMEDIA_ERROR_INVALID_OPERATION;
503*ec779b8eSAndroid Build Coastguard Worker }
504*ec779b8eSAndroid Build Coastguard Worker
505*ec779b8eSAndroid Build Coastguard Worker if (clientId != mCurrentClientId || sessionId != mCurrentSessionId) {
506*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s: stopping session {%lld, %d} that's not current session {%lld, %d}", __FUNCTION__,
507*ec779b8eSAndroid Build Coastguard Worker (long long)clientId, sessionId, (long long)mCurrentClientId, mCurrentSessionId);
508*ec779b8eSAndroid Build Coastguard Worker }
509*ec779b8eSAndroid Build Coastguard Worker
510*ec779b8eSAndroid Build Coastguard Worker ALOGI("%s: pausing transcoder", __FUNCTION__);
511*ec779b8eSAndroid Build Coastguard Worker
512*ec779b8eSAndroid Build Coastguard Worker std::shared_ptr<ndk::ScopedAParcel> pauseStates;
513*ec779b8eSAndroid Build Coastguard Worker media_status_t err = mTranscoder->pause(&pauseStates);
514*ec779b8eSAndroid Build Coastguard Worker logSessionEnded(TranscodingLogger::SessionEndedReason::PAUSED, err);
515*ec779b8eSAndroid Build Coastguard Worker if (err != AMEDIA_OK) {
516*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s: failed to pause transcoder: %d", __FUNCTION__, err);
517*ec779b8eSAndroid Build Coastguard Worker return err;
518*ec779b8eSAndroid Build Coastguard Worker }
519*ec779b8eSAndroid Build Coastguard Worker mPausedStateMap[SessionKeyType(clientId, sessionId)] = pauseStates;
520*ec779b8eSAndroid Build Coastguard Worker
521*ec779b8eSAndroid Build Coastguard Worker ALOGI("%s: transcoder paused", __FUNCTION__);
522*ec779b8eSAndroid Build Coastguard Worker return AMEDIA_OK;
523*ec779b8eSAndroid Build Coastguard Worker }
524*ec779b8eSAndroid Build Coastguard Worker
handleResume(ClientIdType clientId,SessionIdType sessionId,const TranscodingRequestParcel & request,uid_t callingUid,const std::shared_ptr<ITranscodingClientCallback> & clientCb)525*ec779b8eSAndroid Build Coastguard Worker media_status_t TranscoderWrapper::handleResume(
526*ec779b8eSAndroid Build Coastguard Worker ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
527*ec779b8eSAndroid Build Coastguard Worker uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
528*ec779b8eSAndroid Build Coastguard Worker std::shared_ptr<ndk::ScopedAParcel> pausedState;
529*ec779b8eSAndroid Build Coastguard Worker auto it = mPausedStateMap.find(SessionKeyType(clientId, sessionId));
530*ec779b8eSAndroid Build Coastguard Worker if (it != mPausedStateMap.end()) {
531*ec779b8eSAndroid Build Coastguard Worker pausedState = it->second;
532*ec779b8eSAndroid Build Coastguard Worker mPausedStateMap.erase(it);
533*ec779b8eSAndroid Build Coastguard Worker } else {
534*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s: can't find paused state", __FUNCTION__);
535*ec779b8eSAndroid Build Coastguard Worker return AMEDIA_ERROR_INVALID_OPERATION;
536*ec779b8eSAndroid Build Coastguard Worker }
537*ec779b8eSAndroid Build Coastguard Worker
538*ec779b8eSAndroid Build Coastguard Worker ALOGI("%s: setting up transcoder for resume", __FUNCTION__);
539*ec779b8eSAndroid Build Coastguard Worker TranscodingLogger::SessionEndedReason reason = TranscodingLogger::SessionEndedReason::UNKNOWN;
540*ec779b8eSAndroid Build Coastguard Worker media_status_t err = setupTranscoder(clientId, sessionId, request, callingUid, clientCb,
541*ec779b8eSAndroid Build Coastguard Worker &reason, pausedState);
542*ec779b8eSAndroid Build Coastguard Worker if (err != AMEDIA_OK) {
543*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s: failed to setup transcoder: %d", __FUNCTION__, err);
544*ec779b8eSAndroid Build Coastguard Worker logSessionEnded(reason, err);
545*ec779b8eSAndroid Build Coastguard Worker return err;
546*ec779b8eSAndroid Build Coastguard Worker }
547*ec779b8eSAndroid Build Coastguard Worker
548*ec779b8eSAndroid Build Coastguard Worker // Note: For now resume() will just restart transcoding from the beginning, so there is no need
549*ec779b8eSAndroid Build Coastguard Worker // to distinguish between resume and start from a performance perspective.
550*ec779b8eSAndroid Build Coastguard Worker mTranscodeStartTime = std::chrono::steady_clock::now();
551*ec779b8eSAndroid Build Coastguard Worker
552*ec779b8eSAndroid Build Coastguard Worker err = mTranscoder->resume();
553*ec779b8eSAndroid Build Coastguard Worker if (err != AMEDIA_OK) {
554*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s: failed to resume transcoder: %d", __FUNCTION__, err);
555*ec779b8eSAndroid Build Coastguard Worker logSessionEnded(TranscodingLogger::SessionEndedReason::RESUME_FAILED, err);
556*ec779b8eSAndroid Build Coastguard Worker return err;
557*ec779b8eSAndroid Build Coastguard Worker }
558*ec779b8eSAndroid Build Coastguard Worker
559*ec779b8eSAndroid Build Coastguard Worker ALOGI("%s: transcoder resumed", __FUNCTION__);
560*ec779b8eSAndroid Build Coastguard Worker return AMEDIA_OK;
561*ec779b8eSAndroid Build Coastguard Worker }
562*ec779b8eSAndroid Build Coastguard Worker
cleanup()563*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::cleanup() {
564*ec779b8eSAndroid Build Coastguard Worker mCurrentClientId = 0;
565*ec779b8eSAndroid Build Coastguard Worker mCurrentSessionId = -1;
566*ec779b8eSAndroid Build Coastguard Worker mCurrentCallingUid = -1;
567*ec779b8eSAndroid Build Coastguard Worker mTranscoderCb = nullptr;
568*ec779b8eSAndroid Build Coastguard Worker mTranscoder = nullptr;
569*ec779b8eSAndroid Build Coastguard Worker mSrcFormat = nullptr;
570*ec779b8eSAndroid Build Coastguard Worker mDstFormat = nullptr;
571*ec779b8eSAndroid Build Coastguard Worker }
572*ec779b8eSAndroid Build Coastguard Worker
logSessionEnded(const TranscodingLogger::SessionEndedReason & reason,int error)573*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::logSessionEnded(const TranscodingLogger::SessionEndedReason& reason,
574*ec779b8eSAndroid Build Coastguard Worker int error) {
575*ec779b8eSAndroid Build Coastguard Worker std::chrono::microseconds transcodeDuration(-1);
576*ec779b8eSAndroid Build Coastguard Worker if (reason == TranscodingLogger::SessionEndedReason::FINISHED && error == AMEDIA_OK) {
577*ec779b8eSAndroid Build Coastguard Worker transcodeDuration = std::chrono::duration_cast<std::chrono::microseconds>(
578*ec779b8eSAndroid Build Coastguard Worker std::chrono::steady_clock::now() - mTranscodeStartTime);
579*ec779b8eSAndroid Build Coastguard Worker }
580*ec779b8eSAndroid Build Coastguard Worker
581*ec779b8eSAndroid Build Coastguard Worker mLogger->logSessionEnded(reason, mCurrentCallingUid, error, transcodeDuration, mSrcFormat.get(),
582*ec779b8eSAndroid Build Coastguard Worker mDstFormat.get());
583*ec779b8eSAndroid Build Coastguard Worker }
584*ec779b8eSAndroid Build Coastguard Worker
queueEvent(Event::Type type,ClientIdType clientId,SessionIdType sessionId,const std::function<void ()> runnable,int32_t arg)585*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::queueEvent(Event::Type type, ClientIdType clientId, SessionIdType sessionId,
586*ec779b8eSAndroid Build Coastguard Worker const std::function<void()> runnable, int32_t arg) {
587*ec779b8eSAndroid Build Coastguard Worker std::scoped_lock lock{mLock};
588*ec779b8eSAndroid Build Coastguard Worker
589*ec779b8eSAndroid Build Coastguard Worker if (!mLooperReady) {
590*ec779b8eSAndroid Build Coastguard Worker // A shared_ptr to ourselves is given to the thread's stack, so that the TranscoderWrapper
591*ec779b8eSAndroid Build Coastguard Worker // object doesn't go away until the thread exits. When a watchdog timeout happens, this
592*ec779b8eSAndroid Build Coastguard Worker // allows the session controller to release its reference to the TranscoderWrapper object
593*ec779b8eSAndroid Build Coastguard Worker // without blocking on the thread exits.
594*ec779b8eSAndroid Build Coastguard Worker std::thread([owner = shared_from_this()]() { owner->threadLoop(); }).detach();
595*ec779b8eSAndroid Build Coastguard Worker mLooperReady = true;
596*ec779b8eSAndroid Build Coastguard Worker }
597*ec779b8eSAndroid Build Coastguard Worker
598*ec779b8eSAndroid Build Coastguard Worker mQueue.push_back({type, clientId, sessionId, runnable, arg});
599*ec779b8eSAndroid Build Coastguard Worker mCondition.notify_one();
600*ec779b8eSAndroid Build Coastguard Worker }
601*ec779b8eSAndroid Build Coastguard Worker
threadLoop()602*ec779b8eSAndroid Build Coastguard Worker void TranscoderWrapper::threadLoop() {
603*ec779b8eSAndroid Build Coastguard Worker androidSetThreadPriority(0 /*tid (0 = current) */, ANDROID_PRIORITY_BACKGROUND);
604*ec779b8eSAndroid Build Coastguard Worker std::unique_lock<std::mutex> lock{mLock};
605*ec779b8eSAndroid Build Coastguard Worker // TranscoderWrapper currently lives in the transcoding service, as long as
606*ec779b8eSAndroid Build Coastguard Worker // MediaTranscodingService itself.
607*ec779b8eSAndroid Build Coastguard Worker while (true) {
608*ec779b8eSAndroid Build Coastguard Worker // Wait for the next event.
609*ec779b8eSAndroid Build Coastguard Worker while (mQueue.empty()) {
610*ec779b8eSAndroid Build Coastguard Worker mCondition.wait(lock);
611*ec779b8eSAndroid Build Coastguard Worker }
612*ec779b8eSAndroid Build Coastguard Worker
613*ec779b8eSAndroid Build Coastguard Worker Event event = *mQueue.begin();
614*ec779b8eSAndroid Build Coastguard Worker mQueue.pop_front();
615*ec779b8eSAndroid Build Coastguard Worker
616*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s: %s", __FUNCTION__, toString(event).c_str());
617*ec779b8eSAndroid Build Coastguard Worker
618*ec779b8eSAndroid Build Coastguard Worker if (event.type == Event::Abandon) {
619*ec779b8eSAndroid Build Coastguard Worker break;
620*ec779b8eSAndroid Build Coastguard Worker }
621*ec779b8eSAndroid Build Coastguard Worker
622*ec779b8eSAndroid Build Coastguard Worker lock.unlock();
623*ec779b8eSAndroid Build Coastguard Worker event.runnable();
624*ec779b8eSAndroid Build Coastguard Worker lock.lock();
625*ec779b8eSAndroid Build Coastguard Worker }
626*ec779b8eSAndroid Build Coastguard Worker }
627*ec779b8eSAndroid Build Coastguard Worker } // namespace android
628