| Linus Nilsson | 52df71c | 2021-03-08 13:01:11 -0800 | [diff] [blame^] | 1 | /* | 
|  | 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 | #include <media/MediaTrackTranscoder.h> | 
|  | 18 | #include <media/MediaTrackTranscoderCallback.h> | 
|  | 19 | #include <media/MediaTranscoder.h> | 
|  | 20 |  | 
|  | 21 | #include <condition_variable> | 
|  | 22 | #include <memory> | 
|  | 23 | #include <mutex> | 
|  | 24 |  | 
|  | 25 | namespace android { | 
|  | 26 |  | 
|  | 27 | // | 
|  | 28 | // This file contains transcoding test utilities. | 
|  | 29 | // | 
|  | 30 |  | 
|  | 31 | namespace TranscoderTestUtils { | 
|  | 32 |  | 
|  | 33 | std::shared_ptr<AMediaFormat> GetVideoFormat(const std::string& path, | 
|  | 34 | std::string* mimeOut = nullptr) { | 
|  | 35 | int fd = open(path.c_str(), O_RDONLY); | 
|  | 36 | EXPECT_GT(fd, 0); | 
|  | 37 | ssize_t fileSize = lseek(fd, 0, SEEK_END); | 
|  | 38 | lseek(fd, 0, SEEK_SET); | 
|  | 39 |  | 
|  | 40 | auto sampleReader = MediaSampleReaderNDK::createFromFd(fd, 0, fileSize); | 
|  | 41 | EXPECT_NE(sampleReader, nullptr); | 
|  | 42 |  | 
|  | 43 | for (size_t i = 0; i < sampleReader->getTrackCount(); ++i) { | 
|  | 44 | AMediaFormat* format = sampleReader->getTrackFormat(i); | 
|  | 45 |  | 
|  | 46 | const char* mime = nullptr; | 
|  | 47 | AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime); | 
|  | 48 | if (strncmp(mime, "video/", 6) == 0) { | 
|  | 49 | if (mimeOut != nullptr) { | 
|  | 50 | mimeOut->assign(mime); | 
|  | 51 | } | 
|  | 52 | return std::shared_ptr<AMediaFormat>(format, &AMediaFormat_delete); | 
|  | 53 | } | 
|  | 54 |  | 
|  | 55 | AMediaFormat_delete(format); | 
|  | 56 | } | 
|  | 57 | return nullptr; | 
|  | 58 | } | 
|  | 59 |  | 
|  | 60 | };  // namespace TranscoderTestUtils | 
|  | 61 |  | 
|  | 62 | class TrackTranscoderTestUtils { | 
|  | 63 | public: | 
|  | 64 | static std::shared_ptr<AMediaFormat> getDefaultVideoDestinationFormat( | 
|  | 65 | AMediaFormat* sourceFormat, bool includeBitrate = true) { | 
|  | 66 | // Default video destination format setup. | 
|  | 67 | static constexpr float kFrameRate = 30.0f; | 
|  | 68 | static constexpr int32_t kBitRate = 2 * 1000 * 1000; | 
|  | 69 |  | 
|  | 70 | AMediaFormat* destinationFormat = AMediaFormat_new(); | 
|  | 71 | AMediaFormat_copy(destinationFormat, sourceFormat); | 
|  | 72 | AMediaFormat_setFloat(destinationFormat, AMEDIAFORMAT_KEY_FRAME_RATE, kFrameRate); | 
|  | 73 | if (includeBitrate) { | 
|  | 74 | AMediaFormat_setInt32(destinationFormat, AMEDIAFORMAT_KEY_BIT_RATE, kBitRate); | 
|  | 75 | } | 
|  | 76 |  | 
|  | 77 | return std::shared_ptr<AMediaFormat>(destinationFormat, &AMediaFormat_delete); | 
|  | 78 | } | 
|  | 79 | }; | 
|  | 80 |  | 
|  | 81 | class TestTrackTranscoderCallback : public MediaTrackTranscoderCallback { | 
|  | 82 | public: | 
|  | 83 | TestTrackTranscoderCallback() = default; | 
|  | 84 | ~TestTrackTranscoderCallback() = default; | 
|  | 85 |  | 
|  | 86 | // MediaTrackTranscoderCallback | 
|  | 87 | void onTrackFormatAvailable(const MediaTrackTranscoder* transcoder __unused) { | 
|  | 88 | std::unique_lock<std::mutex> lock(mMutex); | 
|  | 89 | mTrackFormatAvailable = true; | 
|  | 90 | mTrackFormatAvailableCondition.notify_all(); | 
|  | 91 | } | 
|  | 92 |  | 
|  | 93 | void onTrackFinished(const MediaTrackTranscoder* transcoder __unused) { | 
|  | 94 | std::unique_lock<std::mutex> lock(mMutex); | 
|  | 95 | mTranscodingFinished = true; | 
|  | 96 | mTranscodingFinishedCondition.notify_all(); | 
|  | 97 | } | 
|  | 98 |  | 
|  | 99 | virtual void onTrackStopped(const MediaTrackTranscoder* transcoder __unused) override { | 
|  | 100 | std::unique_lock<std::mutex> lock(mMutex); | 
|  | 101 | mTranscodingFinished = true; | 
|  | 102 | mTranscodingStopped = true; | 
|  | 103 | mTranscodingFinishedCondition.notify_all(); | 
|  | 104 | } | 
|  | 105 |  | 
|  | 106 | void onTrackError(const MediaTrackTranscoder* transcoder __unused, media_status_t status) { | 
|  | 107 | std::unique_lock<std::mutex> lock(mMutex); | 
|  | 108 | mTranscodingFinished = true; | 
|  | 109 | mStatus = status; | 
|  | 110 | mTranscodingFinishedCondition.notify_all(); | 
|  | 111 | } | 
|  | 112 | // ~MediaTrackTranscoderCallback | 
|  | 113 |  | 
|  | 114 | media_status_t waitUntilFinished() { | 
|  | 115 | std::unique_lock<std::mutex> lock(mMutex); | 
|  | 116 | while (!mTranscodingFinished) { | 
|  | 117 | mTranscodingFinishedCondition.wait(lock); | 
|  | 118 | } | 
|  | 119 | return mStatus; | 
|  | 120 | } | 
|  | 121 |  | 
|  | 122 | void waitUntilTrackFormatAvailable() { | 
|  | 123 | std::unique_lock<std::mutex> lock(mMutex); | 
|  | 124 | while (!mTrackFormatAvailable) { | 
|  | 125 | mTrackFormatAvailableCondition.wait(lock); | 
|  | 126 | } | 
|  | 127 | } | 
|  | 128 |  | 
|  | 129 | bool transcodingWasStopped() const { return mTranscodingFinished && mTranscodingStopped; } | 
|  | 130 | bool transcodingFinished() const { | 
|  | 131 | return mTranscodingFinished && !mTranscodingStopped && mStatus == AMEDIA_OK; | 
|  | 132 | } | 
|  | 133 |  | 
|  | 134 | private: | 
|  | 135 | media_status_t mStatus = AMEDIA_OK; | 
|  | 136 | std::mutex mMutex; | 
|  | 137 | std::condition_variable mTranscodingFinishedCondition; | 
|  | 138 | std::condition_variable mTrackFormatAvailableCondition; | 
|  | 139 | bool mTranscodingFinished = false; | 
|  | 140 | bool mTranscodingStopped = false; | 
|  | 141 | bool mTrackFormatAvailable = false; | 
|  | 142 | }; | 
|  | 143 |  | 
|  | 144 | class TestTranscoderCallbacks : public MediaTranscoder::CallbackInterface { | 
|  | 145 | public: | 
|  | 146 | virtual void onFinished(const MediaTranscoder* transcoder __unused) override { | 
|  | 147 | std::unique_lock<std::mutex> lock(mMutex); | 
|  | 148 | EXPECT_FALSE(mFinished); | 
|  | 149 | mFinished = true; | 
|  | 150 | mCondition.notify_all(); | 
|  | 151 | } | 
|  | 152 |  | 
|  | 153 | virtual void onError(const MediaTranscoder* transcoder __unused, | 
|  | 154 | media_status_t error) override { | 
|  | 155 | std::unique_lock<std::mutex> lock(mMutex); | 
|  | 156 | EXPECT_NE(error, AMEDIA_OK); | 
|  | 157 | EXPECT_FALSE(mFinished); | 
|  | 158 | mFinished = true; | 
|  | 159 | mStatus = error; | 
|  | 160 | mCondition.notify_all(); | 
|  | 161 | } | 
|  | 162 |  | 
|  | 163 | virtual void onProgressUpdate(const MediaTranscoder* transcoder __unused, | 
|  | 164 | int32_t progress) override { | 
|  | 165 | std::unique_lock<std::mutex> lock(mMutex); | 
|  | 166 | if (progress > 0 && !mProgressMade) { | 
|  | 167 | mProgressMade = true; | 
|  | 168 | mCondition.notify_all(); | 
|  | 169 | } | 
|  | 170 | } | 
|  | 171 |  | 
|  | 172 | virtual void onHeartBeat(const MediaTranscoder* transcoder __unused) override { | 
|  | 173 | std::unique_lock<std::mutex> lock(mMutex); | 
|  | 174 | mHeartBeatCount++; | 
|  | 175 | } | 
|  | 176 |  | 
|  | 177 | virtual void onCodecResourceLost(const MediaTranscoder* transcoder __unused, | 
|  | 178 | const std::shared_ptr<ndk::ScopedAParcel>& pausedState | 
|  | 179 | __unused) override {} | 
|  | 180 |  | 
|  | 181 | void waitForTranscodingFinished() { | 
|  | 182 | std::unique_lock<std::mutex> lock(mMutex); | 
|  | 183 | while (!mFinished) { | 
|  | 184 | mCondition.wait(lock); | 
|  | 185 | } | 
|  | 186 | } | 
|  | 187 |  | 
|  | 188 | void waitForProgressMade() { | 
|  | 189 | std::unique_lock<std::mutex> lock(mMutex); | 
|  | 190 | while (!mProgressMade && !mFinished) { | 
|  | 191 | mCondition.wait(lock); | 
|  | 192 | } | 
|  | 193 | } | 
|  | 194 | media_status_t mStatus = AMEDIA_OK; | 
|  | 195 | bool mFinished = false; | 
|  | 196 | int32_t mHeartBeatCount = 0; | 
|  | 197 |  | 
|  | 198 | private: | 
|  | 199 | std::mutex mMutex; | 
|  | 200 | std::condition_variable mCondition; | 
|  | 201 | bool mProgressMade = false; | 
|  | 202 | }; | 
|  | 203 |  | 
|  | 204 | class OneShotSemaphore { | 
|  | 205 | public: | 
|  | 206 | void wait() { | 
|  | 207 | std::unique_lock<std::mutex> lock(mMutex); | 
|  | 208 | while (!mSignaled) { | 
|  | 209 | mCondition.wait(lock); | 
|  | 210 | } | 
|  | 211 | } | 
|  | 212 |  | 
|  | 213 | void signal() { | 
|  | 214 | std::unique_lock<std::mutex> lock(mMutex); | 
|  | 215 | mSignaled = true; | 
|  | 216 | mCondition.notify_all(); | 
|  | 217 | } | 
|  | 218 |  | 
|  | 219 | private: | 
|  | 220 | std::mutex mMutex; | 
|  | 221 | std::condition_variable mCondition; | 
|  | 222 | bool mSignaled = false; | 
|  | 223 | }; | 
|  | 224 |  | 
|  | 225 | };  // namespace android |