transcoding: hooking up real transcoder in service
bug: 154734285
test: unit testing.
Change-Id: Id7de72f86cac75f634276395d4b4be359f44dbc2
diff --git a/media/libmediatranscoding/Android.bp b/media/libmediatranscoding/Android.bp
index b6dca8d..bd6621a 100644
--- a/media/libmediatranscoding/Android.bp
+++ b/media/libmediatranscoding/Android.bp
@@ -48,6 +48,8 @@
"TranscodingClientManager.cpp",
"TranscodingJobScheduler.cpp",
"TranscodingUidPolicy.cpp",
+ "TranscoderWrapper.cpp",
+ "NdkCommon.cpp",
],
shared_libs: [
@@ -57,6 +59,7 @@
"libutils",
"libmediatranscoder",
"libbinder",
+ "libmediandk",
],
export_include_dirs: ["include"],
diff --git a/media/libmediatranscoding/NdkCommon.cpp b/media/libmediatranscoding/NdkCommon.cpp
new file mode 100644
index 0000000..0461a90
--- /dev/null
+++ b/media/libmediatranscoding/NdkCommon.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NdkCommon"
+#include <log/log.h>
+#include <media/NdkCommon.h>
+
+#include <cstdio>
+#include <cstring>
+#include <utility>
+
+/* TODO(b/153592281)
+ * Note: constants used by the native media tests but not available in media ndk api
+ */
+const char* AMEDIA_MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
+const char* AMEDIA_MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
+const char* AMEDIA_MIMETYPE_VIDEO_AV1 = "video/av01";
+const char* AMEDIA_MIMETYPE_VIDEO_AVC = "video/avc";
+const char* AMEDIA_MIMETYPE_VIDEO_HEVC = "video/hevc";
+const char* AMEDIA_MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es";
+const char* AMEDIA_MIMETYPE_VIDEO_H263 = "video/3gpp";
+
+/* TODO(b/153592281) */
+const char* TBD_AMEDIACODEC_PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
+const char* TBD_AMEDIACODEC_PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
+const char* TBD_AMEDIACODEC_PARAMETER_KEY_MAX_B_FRAMES = "max-bframes";
+const char* TBD_AMEDIAFORMAT_KEY_BIT_RATE_MODE = "bitrate-mode";
diff --git a/media/libmediatranscoding/TranscoderWrapper.cpp b/media/libmediatranscoding/TranscoderWrapper.cpp
new file mode 100644
index 0000000..86cb86a
--- /dev/null
+++ b/media/libmediatranscoding/TranscoderWrapper.cpp
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "TranscoderWrapper"
+
+#include <aidl/android/media/TranscodingErrorCode.h>
+#include <aidl/android/media/TranscodingRequestParcel.h>
+#include <media/MediaTranscoder.h>
+#include <media/NdkCommon.h>
+#include <media/TranscoderWrapper.h>
+#include <utils/Log.h>
+
+#include <thread>
+
+namespace android {
+using Status = ::ndk::ScopedAStatus;
+using ::aidl::android::media::TranscodingErrorCode;
+using ::aidl::android::media::TranscodingVideoCodecType;
+using ::aidl::android::media::TranscodingVideoTrackFormat;
+
+static TranscodingErrorCode toTranscodingError(media_status_t status) {
+ switch (status) {
+ case AMEDIA_OK:
+ return TranscodingErrorCode::kNoError;
+ case AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE: // FALLTHRU
+ case AMEDIACODEC_ERROR_RECLAIMED:
+ return TranscodingErrorCode::kInsufficientResources;
+ case AMEDIA_ERROR_MALFORMED:
+ return TranscodingErrorCode::kMalformed;
+ case AMEDIA_ERROR_UNSUPPORTED:
+ return TranscodingErrorCode::kUnsupported;
+ case AMEDIA_ERROR_INVALID_OBJECT: // FALLTHRU
+ case AMEDIA_ERROR_INVALID_PARAMETER:
+ return TranscodingErrorCode::kInvalidParameter;
+ case AMEDIA_ERROR_INVALID_OPERATION:
+ return TranscodingErrorCode::kInvalidOperation;
+ case AMEDIA_ERROR_IO:
+ return TranscodingErrorCode::kErrorIO;
+ case AMEDIA_ERROR_UNKNOWN: // FALLTHRU
+ default:
+ return TranscodingErrorCode::kUnknown;
+ }
+}
+
+//static
+const char* TranscoderWrapper::toString(Event::Type type) {
+ switch (type) {
+ case Event::Start:
+ return "Start";
+ case Event::Pause:
+ return "Pause";
+ case Event::Resume:
+ return "Resume";
+ case Event::Stop:
+ return "Stop";
+ case Event::Finish:
+ return "Finish";
+ case Event::Error:
+ return "Error";
+ default:
+ break;
+ }
+ return "(unknown)";
+}
+
+class TranscoderWrapper::CallbackImpl : public MediaTranscoder::CallbackInterface {
+public:
+ CallbackImpl(const std::shared_ptr<TranscoderWrapper>& owner, ClientIdType clientId,
+ JobIdType jobId)
+ : mOwner(owner), mClientId(clientId), mJobId(jobId) {}
+
+ virtual void onFinished(const MediaTranscoder* transcoder __unused) override {
+ auto owner = mOwner.lock();
+ if (owner != nullptr) {
+ owner->onFinish(mClientId, mJobId);
+ }
+ }
+
+ virtual void onError(const MediaTranscoder* transcoder __unused,
+ media_status_t error) override {
+ auto owner = mOwner.lock();
+ if (owner != nullptr) {
+ owner->onError(mClientId, mJobId, toTranscodingError(error));
+ }
+ }
+
+ virtual void onProgressUpdate(const MediaTranscoder* transcoder __unused,
+ int32_t progress) override {
+ ALOGV("%s: job {%lld, %d}, progress %d", __FUNCTION__, (long long)mClientId, mJobId,
+ progress);
+ }
+
+ virtual void onCodecResourceLost(const MediaTranscoder* transcoder __unused,
+ const std::shared_ptr<const Parcelable>& pausedState
+ __unused) override {
+ ALOGV("%s: job {%lld, %d}", __FUNCTION__, (long long)mClientId, mJobId);
+ }
+
+private:
+ std::weak_ptr<TranscoderWrapper> mOwner;
+ ClientIdType mClientId;
+ JobIdType mJobId;
+};
+
+TranscoderWrapper::TranscoderWrapper() : mCurrentClientId(0), mCurrentJobId(-1) {
+ std::thread(&TranscoderWrapper::threadLoop, this).detach();
+}
+
+void TranscoderWrapper::setCallback(const std::shared_ptr<TranscoderCallbackInterface>& cb) {
+ mCallback = cb;
+}
+
+void TranscoderWrapper::start(ClientIdType clientId, JobIdType jobId,
+ const TranscodingRequestParcel& request,
+ const std::shared_ptr<ITranscodingClientCallback>& callback) {
+ queueEvent(Event::Start, clientId, jobId, [=] {
+ TranscodingErrorCode err = handleStart(clientId, jobId, request, callback);
+
+ if (err != TranscodingErrorCode::kNoError) {
+ cleanup();
+
+ auto callback = mCallback.lock();
+ if (callback != nullptr) {
+ callback->onError(clientId, jobId, err);
+ }
+ }
+ });
+}
+
+void TranscoderWrapper::pause(ClientIdType clientId, JobIdType jobId) {
+ queueEvent(Event::Pause, clientId, jobId, [] {});
+}
+
+void TranscoderWrapper::resume(ClientIdType clientId, JobIdType jobId) {
+ queueEvent(Event::Resume, clientId, jobId, [] {});
+}
+
+void TranscoderWrapper::stop(ClientIdType clientId, JobIdType jobId) {
+ queueEvent(Event::Stop, clientId, jobId, [=] {
+ if (clientId != mCurrentClientId || jobId != mCurrentJobId) {
+ ALOGW("Stopping job {%lld, %d} that's not current job {%lld, %d}", (long long)clientId,
+ jobId, (long long)mCurrentClientId, mCurrentJobId);
+ }
+
+ // stop transcoder.
+ media_status_t err = mTranscoder->cancel();
+ if (err != AMEDIA_OK) {
+ ALOGE("failed to stop transcoder: %d", err);
+ } else {
+ ALOGI("transcoder stopped");
+ }
+
+ cleanup();
+ });
+}
+
+void TranscoderWrapper::onFinish(ClientIdType clientId, JobIdType jobId) {
+ queueEvent(Event::Finish, clientId, jobId, [=] {
+ cleanup();
+
+ auto callback = mCallback.lock();
+ if (callback != nullptr) {
+ callback->onFinish(clientId, jobId);
+ }
+ });
+}
+
+void TranscoderWrapper::onError(ClientIdType clientId, JobIdType jobId,
+ TranscodingErrorCode error) {
+ queueEvent(Event::Error, clientId, jobId, [=] {
+ cleanup();
+
+ auto callback = mCallback.lock();
+ if (callback != nullptr) {
+ callback->onError(clientId, jobId, error);
+ }
+ });
+}
+
+static AMediaFormat* getVideoFormat(
+ const char* originalMime,
+ const std::optional<TranscodingVideoTrackFormat>& requestedFormat) {
+ if (requestedFormat == std::nullopt) {
+ return nullptr;
+ }
+
+ AMediaFormat* format = AMediaFormat_new();
+ bool changed = false;
+ if (requestedFormat->codecType == TranscodingVideoCodecType::kHevc
+ && strcmp(originalMime, AMEDIA_MIMETYPE_VIDEO_HEVC)) {
+ AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_HEVC);
+ changed = true;
+ } else if (requestedFormat->codecType == TranscodingVideoCodecType::kAvc
+ && strcmp(originalMime, AMEDIA_MIMETYPE_VIDEO_AVC)) {
+ AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_AVC);
+ changed = true;
+ }
+ if (requestedFormat->bitrateBps > 0) {
+ AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, requestedFormat->bitrateBps);
+ changed = true;
+ }
+ // TODO: translate other fields from requestedFormat to the format for MediaTranscoder.
+ // Also need to determine more settings to expose in TranscodingVideoTrackFormat.
+ if (!changed) {
+ AMediaFormat_delete(format);
+ // Use null format for passthru.
+ format = nullptr;
+ }
+ return format;
+}
+
+TranscodingErrorCode TranscoderWrapper::handleStart(
+ ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
+ const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
+ if (clientCb == nullptr) {
+ ALOGE("client callback is null");
+ return TranscodingErrorCode::kInvalidParameter;
+ }
+
+ if (mTranscoder != nullptr) {
+ ALOGE("transcoder already running");
+ return TranscodingErrorCode::kInvalidOperation;
+ }
+
+ Status status;
+ ::ndk::ScopedFileDescriptor srcFd, dstFd;
+ status = clientCb->openFileDescriptor(request.sourceFilePath, "r", &srcFd);
+ if (!status.isOk() || srcFd.get() < 0) {
+ ALOGE("failed to open source");
+ return TranscodingErrorCode::kErrorIO;
+ }
+
+ status = clientCb->openFileDescriptor(request.destinationFilePath, "w", &dstFd);
+ if (!status.isOk() || dstFd.get() < 0) {
+ ALOGE("failed to open destination");
+ return TranscodingErrorCode::kErrorIO;
+ }
+
+ mCurrentClientId = clientId;
+ mCurrentJobId = jobId;
+ mTranscoderCb = std::make_shared<CallbackImpl>(shared_from_this(), clientId, jobId);
+ mTranscoder = MediaTranscoder::create(mTranscoderCb, nullptr);
+ if (mTranscoder == nullptr) {
+ ALOGE("failed to create transcoder");
+ return TranscodingErrorCode::kUnknown;
+ }
+
+ media_status_t err = mTranscoder->configureSource(srcFd.get());
+ if (err != AMEDIA_OK) {
+ ALOGE("failed to configure source: %d", err);
+ return toTranscodingError(err);
+ }
+
+ std::vector<std::shared_ptr<AMediaFormat>> trackFormats = mTranscoder->getTrackFormats();
+ if (trackFormats.size() == 0) {
+ ALOGE("failed to get track formats!");
+ return TranscodingErrorCode::kMalformed;
+ }
+
+ for (int i = 0; i < trackFormats.size(); ++i) {
+ AMediaFormat* format = nullptr;
+ const char* mime = nullptr;
+ AMediaFormat_getString(trackFormats[i].get(), AMEDIAFORMAT_KEY_MIME, &mime);
+
+ if (!strncmp(mime, "video/", 6)) {
+ format = getVideoFormat(mime, request.requestedVideoTrackFormat);
+ }
+
+ err = mTranscoder->configureTrackFormat(i, format);
+ if (format != nullptr) {
+ AMediaFormat_delete(format);
+ }
+ if (err != AMEDIA_OK) {
+ ALOGE("failed to configure track format for track %d: %d", i, err);
+ return toTranscodingError(err);
+ }
+ }
+
+ err = mTranscoder->configureDestination(dstFd.get());
+ if (err != AMEDIA_OK) {
+ ALOGE("failed to configure dest: %d", err);
+ return toTranscodingError(err);
+ }
+
+ err = mTranscoder->start();
+ if (err != AMEDIA_OK) {
+ ALOGE("failed to start transcoder: %d", err);
+ return toTranscodingError(err);
+ }
+
+ ALOGI("transcoder started");
+ return TranscodingErrorCode::kNoError;
+}
+
+void TranscoderWrapper::cleanup() {
+ mCurrentClientId = 0;
+ mCurrentJobId = -1;
+ mTranscoderCb = nullptr;
+ mTranscoder = nullptr;
+}
+
+void TranscoderWrapper::queueEvent(Event::Type type, ClientIdType clientId, JobIdType jobId,
+ const std::function<void()> runnable) {
+ ALOGV("%s: job {%lld, %d}: %s", __FUNCTION__, (long long)clientId, jobId, toString(type));
+
+ std::scoped_lock lock{mLock};
+
+ mQueue.push_back({type, clientId, jobId, runnable});
+ mCondition.notify_one();
+}
+
+void TranscoderWrapper::threadLoop() {
+ std::unique_lock<std::mutex> lock{mLock};
+ // TranscoderWrapper currently lives in the transcoding service, as long as
+ // MediaTranscodingService itself.
+ while (true) {
+ // Wait for the next event.
+ while (mQueue.empty()) {
+ mCondition.wait(lock);
+ }
+
+ Event event = *mQueue.begin();
+ mQueue.pop_front();
+
+ ALOGD("%s: job {%lld, %d}: %s", __FUNCTION__, (long long)event.clientId, event.jobId,
+ toString(event.type));
+
+ event.runnable();
+ }
+}
+
+} // namespace android
diff --git a/media/libmediatranscoding/TranscodingJobScheduler.cpp b/media/libmediatranscoding/TranscodingJobScheduler.cpp
index d5ae2a3..3256384 100644
--- a/media/libmediatranscoding/TranscodingJobScheduler.cpp
+++ b/media/libmediatranscoding/TranscodingJobScheduler.cpp
@@ -76,7 +76,8 @@
// the topJob now.
if (!mResourceLost) {
if (topJob->state == Job::NOT_STARTED) {
- mTranscoder->start(topJob->key.first, topJob->key.second, topJob->request);
+ mTranscoder->start(topJob->key.first, topJob->key.second, topJob->request,
+ topJob->callback.lock());
} else if (topJob->state == Job::PAUSED) {
mTranscoder->resume(topJob->key.first, topJob->key.second);
}
@@ -349,7 +350,8 @@
{
auto clientCallback = mJobMap[jobKey].callback.lock();
if (clientCallback != nullptr) {
- clientCallback->onTranscodingFinished(jobId, TranscodingResultParcel({jobId, -1 /*actualBitrateBps*/}));
+ clientCallback->onTranscodingFinished(
+ jobId, TranscodingResultParcel({jobId, -1 /*actualBitrateBps*/}));
}
}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl
index 7f47fdc..b044d41 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl
@@ -23,11 +23,12 @@
*/
@Backing(type = "int")
enum TranscodingErrorCode {
- kUnknown = 0,
- kUnsupported = 1,
- kDecoderError = 2,
- kEncoderError = 3,
- kExtractorError = 4,
- kMuxerError = 5,
- kInvalidBitstream = 6
+ kNoError = 0,
+ kUnknown = 1,
+ kMalformed = 2,
+ kUnsupported = 3,
+ kInvalidParameter = 4,
+ kInvalidOperation = 5,
+ kErrorIO = 6,
+ kInsufficientResources = 7,
}
\ No newline at end of file
diff --git a/media/libmediatranscoding/include/media/NdkCommon.h b/media/libmediatranscoding/include/media/NdkCommon.h
new file mode 100644
index 0000000..63bee58
--- /dev/null
+++ b/media/libmediatranscoding/include/media/NdkCommon.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_TRANSCODING_NDK_COMMON_H
+#define ANDROID_MEDIA_TRANSCODING_NDK_COMMON_H
+
+#include <media/NdkMediaFormat.h>
+
+extern const char* AMEDIA_MIMETYPE_VIDEO_VP8;
+extern const char* AMEDIA_MIMETYPE_VIDEO_VP9;
+extern const char* AMEDIA_MIMETYPE_VIDEO_AV1;
+extern const char* AMEDIA_MIMETYPE_VIDEO_AVC;
+extern const char* AMEDIA_MIMETYPE_VIDEO_HEVC;
+extern const char* AMEDIA_MIMETYPE_VIDEO_MPEG4;
+extern const char* AMEDIA_MIMETYPE_VIDEO_H263;
+
+// TODO(b/146420990)
+// TODO: make MediaTranscoder use the consts from this header.
+typedef enum {
+ OUTPUT_FORMAT_START = 0,
+ OUTPUT_FORMAT_MPEG_4 = OUTPUT_FORMAT_START,
+ OUTPUT_FORMAT_WEBM = OUTPUT_FORMAT_START + 1,
+ OUTPUT_FORMAT_THREE_GPP = OUTPUT_FORMAT_START + 2,
+ OUTPUT_FORMAT_HEIF = OUTPUT_FORMAT_START + 3,
+ OUTPUT_FORMAT_OGG = OUTPUT_FORMAT_START + 4,
+ OUTPUT_FORMAT_LIST_END = OUTPUT_FORMAT_START + 4,
+} MuxerFormat;
+
+// Color formats supported by encoder - should mirror supportedColorList
+// from MediaCodecConstants.h (are these going to be deprecated)
+static constexpr int COLOR_FormatYUV420SemiPlanar = 21;
+static constexpr int COLOR_FormatYUV420Flexible = 0x7F420888;
+static constexpr int COLOR_FormatSurface = 0x7f000789;
+
+// constants not defined in NDK
+extern const char* TBD_AMEDIACODEC_PARAMETER_KEY_REQUEST_SYNC_FRAME;
+extern const char* TBD_AMEDIACODEC_PARAMETER_KEY_VIDEO_BITRATE;
+extern const char* TBD_AMEDIACODEC_PARAMETER_KEY_MAX_B_FRAMES;
+extern const char* TBD_AMEDIAFORMAT_KEY_BIT_RATE_MODE;
+static constexpr int TBD_AMEDIACODEC_BUFFER_FLAG_KEY_FRAME = 0x1;
+
+static constexpr int kBitrateModeConstant = 2;
+
+#endif // ANDROID_MEDIA_TRANSCODING_NDK_COMMON_H
diff --git a/media/libmediatranscoding/include/media/TranscoderInterface.h b/media/libmediatranscoding/include/media/TranscoderInterface.h
index 97b7126..85e0164 100644
--- a/media/libmediatranscoding/include/media/TranscoderInterface.h
+++ b/media/libmediatranscoding/include/media/TranscoderInterface.h
@@ -17,12 +17,14 @@
#ifndef ANDROID_MEDIA_TRANSCODER_INTERFACE_H
#define ANDROID_MEDIA_TRANSCODER_INTERFACE_H
+#include <aidl/android/media/ITranscodingClientCallback.h>
#include <aidl/android/media/TranscodingErrorCode.h>
#include <aidl/android/media/TranscodingRequestParcel.h>
#include <media/TranscodingDefs.h>
namespace android {
+using ::aidl::android::media::ITranscodingClientCallback;
using ::aidl::android::media::TranscodingErrorCode;
using ::aidl::android::media::TranscodingRequestParcel;
class TranscoderCallbackInterface;
@@ -34,7 +36,8 @@
// For now, always pass in clientId&jobId.
virtual void setCallback(const std::shared_ptr<TranscoderCallbackInterface>& cb) = 0;
virtual void start(ClientIdType clientId, JobIdType jobId,
- const TranscodingRequestParcel& request) = 0;
+ const TranscodingRequestParcel& request,
+ const std::shared_ptr<ITranscodingClientCallback>& clientCallback) = 0;
virtual void pause(ClientIdType clientId, JobIdType jobId) = 0;
virtual void resume(ClientIdType clientId, JobIdType jobId) = 0;
virtual void stop(ClientIdType clientId, JobIdType jobId) = 0;
diff --git a/media/libmediatranscoding/include/media/TranscoderWrapper.h b/media/libmediatranscoding/include/media/TranscoderWrapper.h
new file mode 100644
index 0000000..3da05b2
--- /dev/null
+++ b/media/libmediatranscoding/include/media/TranscoderWrapper.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_TRANSCODER_WRAPPER_H
+#define ANDROID_TRANSCODER_WRAPPER_H
+
+#include <android-base/thread_annotations.h>
+#include <media/TranscoderInterface.h>
+
+#include <list>
+#include <mutex>
+
+namespace android {
+
+class MediaTranscoder;
+
+/*
+ * Wrapper class around MediaTranscoder.
+ * Implements TranscoderInterface for TranscodingJobScheduler to use.
+ */
+class TranscoderWrapper : public TranscoderInterface,
+ public std::enable_shared_from_this<TranscoderWrapper> {
+public:
+ TranscoderWrapper();
+
+ virtual void setCallback(const std::shared_ptr<TranscoderCallbackInterface>& cb) override;
+ virtual void start(ClientIdType clientId, JobIdType jobId,
+ const TranscodingRequestParcel& request,
+ const std::shared_ptr<ITranscodingClientCallback>& clientCallback) override;
+ virtual void pause(ClientIdType clientId, JobIdType jobId) override;
+ virtual void resume(ClientIdType clientId, JobIdType jobId) override;
+ virtual void stop(ClientIdType clientId, JobIdType jobId) override;
+
+private:
+ class CallbackImpl;
+ struct Event {
+ enum Type { NoEvent, Start, Pause, Resume, Stop, Finish, Error } type;
+ ClientIdType clientId;
+ JobIdType jobId;
+ std::function<void()> runnable;
+ };
+ std::shared_ptr<CallbackImpl> mTranscoderCb;
+ std::shared_ptr<MediaTranscoder> mTranscoder;
+ std::weak_ptr<TranscoderCallbackInterface> mCallback;
+ std::mutex mLock;
+ std::condition_variable mCondition;
+ std::list<Event> mQueue; // GUARDED_BY(mLock);
+ ClientIdType mCurrentClientId;
+ JobIdType mCurrentJobId;
+
+ static const char* toString(Event::Type type);
+ void onFinish(ClientIdType clientId, JobIdType jobId);
+ void onError(ClientIdType clientId, JobIdType jobId, TranscodingErrorCode error);
+
+ TranscodingErrorCode handleStart(ClientIdType clientId, JobIdType jobId,
+ const TranscodingRequestParcel& request,
+ const std::shared_ptr<ITranscodingClientCallback>& callback);
+
+ void cleanup();
+ void queueEvent(Event::Type type, ClientIdType clientId, JobIdType jobId,
+ const std::function<void()> runnable);
+ void threadLoop();
+};
+
+} // namespace android
+#endif // ANDROID_TRANSCODER_WRAPPER_H
diff --git a/media/libmediatranscoding/include/media/TranscodingRequest.h b/media/libmediatranscoding/include/media/TranscodingRequest.h
index 6bc9db6..63de1fb 100644
--- a/media/libmediatranscoding/include/media/TranscodingRequest.h
+++ b/media/libmediatranscoding/include/media/TranscodingRequest.h
@@ -38,6 +38,7 @@
sourceFilePath = parcel.sourceFilePath;
destinationFilePath = parcel.destinationFilePath;
transcodingType = parcel.transcodingType;
+ requestedVideoTrackFormat = parcel.requestedVideoTrackFormat;
priority = parcel.priority;
requestProgressUpdate = parcel.requestProgressUpdate;
requestJobEventUpdate = parcel.requestJobEventUpdate;
diff --git a/media/libmediatranscoding/tests/TranscodingJobScheduler_tests.cpp b/media/libmediatranscoding/tests/TranscodingJobScheduler_tests.cpp
index b9bebac..1931a0e 100644
--- a/media/libmediatranscoding/tests/TranscodingJobScheduler_tests.cpp
+++ b/media/libmediatranscoding/tests/TranscodingJobScheduler_tests.cpp
@@ -87,8 +87,8 @@
// TranscoderInterface
void setCallback(const std::shared_ptr<TranscoderCallbackInterface>& /*cb*/) override {}
- void start(ClientIdType clientId, JobIdType jobId,
- const TranscodingRequestParcel& /*request*/) override {
+ void start(ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& /*request*/,
+ const std::shared_ptr<ITranscodingClientCallback>& /*clientCallback*/) override {
mEventQueue.push_back(Start(clientId, jobId));
}
void pause(ClientIdType clientId, JobIdType jobId) override {
@@ -433,9 +433,9 @@
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
// Fail running offline job, and test error code propagation.
- mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kInvalidBitstream);
+ mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kInvalidOperation);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), JOB(0)));
- EXPECT_EQ(mTranscoder->getLastError(), TranscodingErrorCode::kInvalidBitstream);
+ EXPECT_EQ(mTranscoder->getLastError(), TranscodingErrorCode::kInvalidOperation);
// Duplicate fail for last job, should be ignored.
mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kUnknown);
diff --git a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
index 3db7455..cee3702 100644
--- a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
@@ -95,8 +95,7 @@
// Transcoding is done and the callback to the client has been sent, so tear down the
// pipeline but do it asynchronously to avoid deadlocks. If an error occurred, client
// should clean up the file.
- std::thread asyncCancelThread{
- [self = shared_from_this()] { self->cancel(); }};
+ std::thread asyncCancelThread{[self = shared_from_this()] { self->cancel(); }};
asyncCancelThread.detach();
}
}
@@ -116,7 +115,7 @@
}
MediaTranscoder::MediaTranscoder(const std::shared_ptr<CallbackInterface>& callbacks)
- : mCallbacks(callbacks) {}
+ : mCallbacks(callbacks) {}
std::shared_ptr<MediaTranscoder> MediaTranscoder::create(
const std::shared_ptr<CallbackInterface>& callbacks,