Loading media/tests/benchmark/README.md +10 −0 Original line number Diff line number Diff line Loading @@ -28,3 +28,13 @@ The path to these files on the device is required to be given for the test. ``` adb shell /data/local/tmp/extractorTest -P /sdcard/res/ ``` ## Decoder The test decodes input stream and benchmarks the decoders available in NDK. Setup steps are same as extractor. ``` adb shell /data/local/tmp/decoderTest -P /sdcard/res/ ``` media/tests/benchmark/src/native/common/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ cc_library_static { ], srcs: [ "BenchmarkCommon.cpp", "Timer.cpp", ], Loading media/tests/benchmark/src/native/common/BenchmarkCommon.cpp 0 → 100644 +102 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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 "BenchmarkCommon" #include "BenchmarkCommon.h" #include <iostream> void CallBackHandle::ioThread() { ALOGV("In %s mIsDone : %d, mSawError : %d ", __func__, mIsDone, mSawError); while (!mIsDone && !mSawError) { auto task = mIOQueue.pop(); task(); } } void OnInputAvailableCB(AMediaCodec *codec, void *userdata, int32_t index) { ALOGV("OnInputAvailableCB: index(%d)", index); CallBackHandle *self = (CallBackHandle *)userdata; self->getTimer()->addInputTime(); self->mIOQueue.push([self, codec, index]() { self->onInputAvailable(codec, index); }); } void OnOutputAvailableCB(AMediaCodec *codec, void *userdata, int32_t index, AMediaCodecBufferInfo *bufferInfo) { ALOGV("OnOutputAvailableCB: index(%d), (%d, %d, %lld, 0x%x)", index, bufferInfo->offset, bufferInfo->size, (long long)bufferInfo->presentationTimeUs, bufferInfo->flags); CallBackHandle *self = (CallBackHandle *)userdata; self->getTimer()->addOutputTime(); AMediaCodecBufferInfo bufferInfoCopy = *bufferInfo; self->mIOQueue.push([self, codec, index, bufferInfoCopy]() { AMediaCodecBufferInfo bc = bufferInfoCopy; self->onOutputAvailable(codec, index, &bc); }); } void OnFormatChangedCB(AMediaCodec *codec, void *userdata, AMediaFormat *format) { ALOGV("OnFormatChangedCB: format(%s)", AMediaFormat_toString(format)); CallBackHandle *self = (CallBackHandle *)userdata; self->mIOQueue.push([self, codec, format]() { self->onFormatChanged(codec, format); }); } void OnErrorCB(AMediaCodec *codec, void *userdata, media_status_t err, int32_t actionCode, const char *detail) { (void)codec; ALOGV("OnErrorCB: err(%d), actionCode(%d), detail(%s)", err, actionCode, detail); CallBackHandle *self = (CallBackHandle *)userdata; self->mSawError = true; } AMediaCodec *createMediaCodec(AMediaFormat *format, const char *mime, string codecName, bool isEncoder) { ALOGV("In %s", __func__); if (!mime) { ALOGE("Please specify a mime type to create codec"); return nullptr; } AMediaCodec *codec; if (!codecName.empty()) { codec = AMediaCodec_createCodecByName(codecName.c_str()); if (!codec) { ALOGE("Unable to create codec by name: %s", codecName.c_str()); return nullptr; } } else { if (isEncoder) { codec = AMediaCodec_createEncoderByType(mime); } else { codec = AMediaCodec_createDecoderByType(mime); } if (!codec) { ALOGE("Unable to create codec by mime: %s", mime); return nullptr; } } /* Configure codec with the given format*/ const char *s = AMediaFormat_toString(format); ALOGV("Input format: %s\n", s); media_status_t status = AMediaCodec_configure(codec, format, nullptr, nullptr, isEncoder); if (status != AMEDIA_OK) { ALOGE("AMediaCodec_configure failed %d", status); return nullptr; } return codec; } No newline at end of file media/tests/benchmark/src/native/common/BenchmarkCommon.h +96 −0 Original line number Diff line number Diff line Loading @@ -19,11 +19,107 @@ #include <utils/Log.h> #include <inttypes.h> #include <mutex> #include <queue> #include <thread> #include <media/NdkMediaCodec.h> #include <media/NdkMediaError.h> #include "Timer.h" using namespace std; constexpr uint32_t kQueueDequeueTimeoutUs = 1000; constexpr uint32_t kMaxCSDStrlen = 16; constexpr uint32_t kMaxBufferSize = 1024 * 1024 * 16; template <typename T> class CallBackQueue { public: CallBackQueue() {} ~CallBackQueue() {} void push(T elem) { bool needsNotify = false; { lock_guard<mutex> lock(mMutex); needsNotify = mQueue.empty(); mQueue.push(move(elem)); } if (needsNotify) mQueueNotEmptyCondition.notify_one(); } T pop() { unique_lock<mutex> lock(mMutex); if (mQueue.empty()) { mQueueNotEmptyCondition.wait(lock, [this]() { return !mQueue.empty(); }); } auto result = mQueue.front(); mQueue.pop(); return result; } private: mutex mMutex; queue<T> mQueue; condition_variable mQueueNotEmptyCondition; }; class CallBackHandle { public: CallBackHandle() : mSawError(false), mIsDone(false), mTimer(nullptr) {} virtual ~CallBackHandle() { if (mIOThread.joinable()) mIOThread.join(); if (mTimer) delete mTimer; } void ioThread(); // Implementation in child class (Decoder/Encoder) virtual void onInputAvailable(AMediaCodec *codec, int32_t index) { (void)codec; (void)index; } virtual void onFormatChanged(AMediaCodec *codec, AMediaFormat *format) { (void)codec; (void)format; } virtual void onOutputAvailable(AMediaCodec *codec, int32_t index, AMediaCodecBufferInfo *bufferInfo) { (void)codec; (void)index; (void)bufferInfo; } virtual Timer *getTimer() { return mTimer; } // Keep a queue of all function callbacks. typedef function<void()> IOTask; CallBackQueue<IOTask> mIOQueue; thread mIOThread; bool mSawError; bool mIsDone; private: Timer *mTimer; }; // Async API's callback void OnInputAvailableCB(AMediaCodec *codec, void *userdata, int32_t index); void OnOutputAvailableCB(AMediaCodec *codec, void *userdata, int32_t index, AMediaCodecBufferInfo *bufferInfo); void OnFormatChangedCB(AMediaCodec *codec, void *userdata, AMediaFormat *format); void OnErrorCB(AMediaCodec *codec, void * /* userdata */, media_status_t err, int32_t actionCode, const char *detail); // Utility to create and configure AMediaCodec AMediaCodec *createMediaCodec(AMediaFormat *format, const char *mime, string codecName, bool isEncoder); #endif // __BENCHMARK_COMMON_H__ media/tests/benchmark/src/native/decoder/Android.bp 0 → 100644 +31 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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. */ cc_library_static { name: "libbenchmark_decoder", defaults: [ "libbenchmark_common-defaults", "libbenchmark_soft_sanitize_all-defaults", ], srcs: ["Decoder.cpp"], static_libs: ["libbenchmark_extractor"], export_include_dirs: ["."], ldflags: ["-Wl,-Bsymbolic"] } Loading
media/tests/benchmark/README.md +10 −0 Original line number Diff line number Diff line Loading @@ -28,3 +28,13 @@ The path to these files on the device is required to be given for the test. ``` adb shell /data/local/tmp/extractorTest -P /sdcard/res/ ``` ## Decoder The test decodes input stream and benchmarks the decoders available in NDK. Setup steps are same as extractor. ``` adb shell /data/local/tmp/decoderTest -P /sdcard/res/ ```
media/tests/benchmark/src/native/common/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ cc_library_static { ], srcs: [ "BenchmarkCommon.cpp", "Timer.cpp", ], Loading
media/tests/benchmark/src/native/common/BenchmarkCommon.cpp 0 → 100644 +102 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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 "BenchmarkCommon" #include "BenchmarkCommon.h" #include <iostream> void CallBackHandle::ioThread() { ALOGV("In %s mIsDone : %d, mSawError : %d ", __func__, mIsDone, mSawError); while (!mIsDone && !mSawError) { auto task = mIOQueue.pop(); task(); } } void OnInputAvailableCB(AMediaCodec *codec, void *userdata, int32_t index) { ALOGV("OnInputAvailableCB: index(%d)", index); CallBackHandle *self = (CallBackHandle *)userdata; self->getTimer()->addInputTime(); self->mIOQueue.push([self, codec, index]() { self->onInputAvailable(codec, index); }); } void OnOutputAvailableCB(AMediaCodec *codec, void *userdata, int32_t index, AMediaCodecBufferInfo *bufferInfo) { ALOGV("OnOutputAvailableCB: index(%d), (%d, %d, %lld, 0x%x)", index, bufferInfo->offset, bufferInfo->size, (long long)bufferInfo->presentationTimeUs, bufferInfo->flags); CallBackHandle *self = (CallBackHandle *)userdata; self->getTimer()->addOutputTime(); AMediaCodecBufferInfo bufferInfoCopy = *bufferInfo; self->mIOQueue.push([self, codec, index, bufferInfoCopy]() { AMediaCodecBufferInfo bc = bufferInfoCopy; self->onOutputAvailable(codec, index, &bc); }); } void OnFormatChangedCB(AMediaCodec *codec, void *userdata, AMediaFormat *format) { ALOGV("OnFormatChangedCB: format(%s)", AMediaFormat_toString(format)); CallBackHandle *self = (CallBackHandle *)userdata; self->mIOQueue.push([self, codec, format]() { self->onFormatChanged(codec, format); }); } void OnErrorCB(AMediaCodec *codec, void *userdata, media_status_t err, int32_t actionCode, const char *detail) { (void)codec; ALOGV("OnErrorCB: err(%d), actionCode(%d), detail(%s)", err, actionCode, detail); CallBackHandle *self = (CallBackHandle *)userdata; self->mSawError = true; } AMediaCodec *createMediaCodec(AMediaFormat *format, const char *mime, string codecName, bool isEncoder) { ALOGV("In %s", __func__); if (!mime) { ALOGE("Please specify a mime type to create codec"); return nullptr; } AMediaCodec *codec; if (!codecName.empty()) { codec = AMediaCodec_createCodecByName(codecName.c_str()); if (!codec) { ALOGE("Unable to create codec by name: %s", codecName.c_str()); return nullptr; } } else { if (isEncoder) { codec = AMediaCodec_createEncoderByType(mime); } else { codec = AMediaCodec_createDecoderByType(mime); } if (!codec) { ALOGE("Unable to create codec by mime: %s", mime); return nullptr; } } /* Configure codec with the given format*/ const char *s = AMediaFormat_toString(format); ALOGV("Input format: %s\n", s); media_status_t status = AMediaCodec_configure(codec, format, nullptr, nullptr, isEncoder); if (status != AMEDIA_OK) { ALOGE("AMediaCodec_configure failed %d", status); return nullptr; } return codec; } No newline at end of file
media/tests/benchmark/src/native/common/BenchmarkCommon.h +96 −0 Original line number Diff line number Diff line Loading @@ -19,11 +19,107 @@ #include <utils/Log.h> #include <inttypes.h> #include <mutex> #include <queue> #include <thread> #include <media/NdkMediaCodec.h> #include <media/NdkMediaError.h> #include "Timer.h" using namespace std; constexpr uint32_t kQueueDequeueTimeoutUs = 1000; constexpr uint32_t kMaxCSDStrlen = 16; constexpr uint32_t kMaxBufferSize = 1024 * 1024 * 16; template <typename T> class CallBackQueue { public: CallBackQueue() {} ~CallBackQueue() {} void push(T elem) { bool needsNotify = false; { lock_guard<mutex> lock(mMutex); needsNotify = mQueue.empty(); mQueue.push(move(elem)); } if (needsNotify) mQueueNotEmptyCondition.notify_one(); } T pop() { unique_lock<mutex> lock(mMutex); if (mQueue.empty()) { mQueueNotEmptyCondition.wait(lock, [this]() { return !mQueue.empty(); }); } auto result = mQueue.front(); mQueue.pop(); return result; } private: mutex mMutex; queue<T> mQueue; condition_variable mQueueNotEmptyCondition; }; class CallBackHandle { public: CallBackHandle() : mSawError(false), mIsDone(false), mTimer(nullptr) {} virtual ~CallBackHandle() { if (mIOThread.joinable()) mIOThread.join(); if (mTimer) delete mTimer; } void ioThread(); // Implementation in child class (Decoder/Encoder) virtual void onInputAvailable(AMediaCodec *codec, int32_t index) { (void)codec; (void)index; } virtual void onFormatChanged(AMediaCodec *codec, AMediaFormat *format) { (void)codec; (void)format; } virtual void onOutputAvailable(AMediaCodec *codec, int32_t index, AMediaCodecBufferInfo *bufferInfo) { (void)codec; (void)index; (void)bufferInfo; } virtual Timer *getTimer() { return mTimer; } // Keep a queue of all function callbacks. typedef function<void()> IOTask; CallBackQueue<IOTask> mIOQueue; thread mIOThread; bool mSawError; bool mIsDone; private: Timer *mTimer; }; // Async API's callback void OnInputAvailableCB(AMediaCodec *codec, void *userdata, int32_t index); void OnOutputAvailableCB(AMediaCodec *codec, void *userdata, int32_t index, AMediaCodecBufferInfo *bufferInfo); void OnFormatChangedCB(AMediaCodec *codec, void *userdata, AMediaFormat *format); void OnErrorCB(AMediaCodec *codec, void * /* userdata */, media_status_t err, int32_t actionCode, const char *detail); // Utility to create and configure AMediaCodec AMediaCodec *createMediaCodec(AMediaFormat *format, const char *mime, string codecName, bool isEncoder); #endif // __BENCHMARK_COMMON_H__
media/tests/benchmark/src/native/decoder/Android.bp 0 → 100644 +31 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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. */ cc_library_static { name: "libbenchmark_decoder", defaults: [ "libbenchmark_common-defaults", "libbenchmark_soft_sanitize_all-defaults", ], srcs: ["Decoder.cpp"], static_libs: ["libbenchmark_extractor"], export_include_dirs: ["."], ldflags: ["-Wl,-Bsymbolic"] }