You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
226 lines
7.1 KiB
226 lines
7.1 KiB
/*
|
|
* 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.
|
|
*/
|
|
|
|
#include <media/MediaTrackTranscoder.h>
|
|
#include <media/MediaTrackTranscoderCallback.h>
|
|
#include <media/MediaTranscoder.h>
|
|
|
|
#include <condition_variable>
|
|
#include <memory>
|
|
#include <mutex>
|
|
|
|
namespace android {
|
|
|
|
//
|
|
// This file contains transcoding test utilities.
|
|
//
|
|
|
|
namespace TranscoderTestUtils {
|
|
|
|
std::shared_ptr<AMediaFormat> GetVideoFormat(const std::string& path,
|
|
std::string* mimeOut = nullptr) {
|
|
int fd = open(path.c_str(), O_RDONLY);
|
|
EXPECT_GT(fd, 0);
|
|
ssize_t fileSize = lseek(fd, 0, SEEK_END);
|
|
lseek(fd, 0, SEEK_SET);
|
|
|
|
auto sampleReader = MediaSampleReaderNDK::createFromFd(fd, 0, fileSize);
|
|
EXPECT_NE(sampleReader, nullptr);
|
|
|
|
for (size_t i = 0; i < sampleReader->getTrackCount(); ++i) {
|
|
AMediaFormat* format = sampleReader->getTrackFormat(i);
|
|
|
|
const char* mime = nullptr;
|
|
AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime);
|
|
if (strncmp(mime, "video/", 6) == 0) {
|
|
if (mimeOut != nullptr) {
|
|
mimeOut->assign(mime);
|
|
}
|
|
return std::shared_ptr<AMediaFormat>(format, &AMediaFormat_delete);
|
|
}
|
|
|
|
AMediaFormat_delete(format);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
}; // namespace TranscoderTestUtils
|
|
|
|
class TrackTranscoderTestUtils {
|
|
public:
|
|
static std::shared_ptr<AMediaFormat> getDefaultVideoDestinationFormat(
|
|
AMediaFormat* sourceFormat, bool includeBitrate = true) {
|
|
// Default video destination format setup.
|
|
static constexpr float kFrameRate = 30.0f;
|
|
static constexpr int32_t kBitRate = 2 * 1000 * 1000;
|
|
|
|
AMediaFormat* destinationFormat = AMediaFormat_new();
|
|
AMediaFormat_copy(destinationFormat, sourceFormat);
|
|
AMediaFormat_setFloat(destinationFormat, AMEDIAFORMAT_KEY_FRAME_RATE, kFrameRate);
|
|
if (includeBitrate) {
|
|
AMediaFormat_setInt32(destinationFormat, AMEDIAFORMAT_KEY_BIT_RATE, kBitRate);
|
|
}
|
|
|
|
return std::shared_ptr<AMediaFormat>(destinationFormat, &AMediaFormat_delete);
|
|
}
|
|
};
|
|
|
|
class TestTrackTranscoderCallback : public MediaTrackTranscoderCallback {
|
|
public:
|
|
TestTrackTranscoderCallback() = default;
|
|
~TestTrackTranscoderCallback() = default;
|
|
|
|
// MediaTrackTranscoderCallback
|
|
void onTrackFormatAvailable(const MediaTrackTranscoder* transcoder __unused) {
|
|
std::unique_lock<std::mutex> lock(mMutex);
|
|
mTrackFormatAvailable = true;
|
|
mTrackFormatAvailableCondition.notify_all();
|
|
}
|
|
|
|
void onTrackFinished(const MediaTrackTranscoder* transcoder __unused) {
|
|
std::unique_lock<std::mutex> lock(mMutex);
|
|
mTranscodingFinished = true;
|
|
mTranscodingFinishedCondition.notify_all();
|
|
}
|
|
|
|
virtual void onTrackStopped(const MediaTrackTranscoder* transcoder __unused) override {
|
|
std::unique_lock<std::mutex> lock(mMutex);
|
|
mTranscodingFinished = true;
|
|
mTranscodingStopped = true;
|
|
mTranscodingFinishedCondition.notify_all();
|
|
}
|
|
|
|
void onTrackError(const MediaTrackTranscoder* transcoder __unused, media_status_t status) {
|
|
std::unique_lock<std::mutex> lock(mMutex);
|
|
mTranscodingFinished = true;
|
|
mStatus = status;
|
|
mTranscodingFinishedCondition.notify_all();
|
|
}
|
|
// ~MediaTrackTranscoderCallback
|
|
|
|
media_status_t waitUntilFinished() {
|
|
std::unique_lock<std::mutex> lock(mMutex);
|
|
while (!mTranscodingFinished) {
|
|
mTranscodingFinishedCondition.wait(lock);
|
|
}
|
|
return mStatus;
|
|
}
|
|
|
|
void waitUntilTrackFormatAvailable() {
|
|
std::unique_lock<std::mutex> lock(mMutex);
|
|
while (!mTrackFormatAvailable) {
|
|
mTrackFormatAvailableCondition.wait(lock);
|
|
}
|
|
}
|
|
|
|
bool transcodingWasStopped() const { return mTranscodingFinished && mTranscodingStopped; }
|
|
bool transcodingFinished() const {
|
|
return mTranscodingFinished && !mTranscodingStopped && mStatus == AMEDIA_OK;
|
|
}
|
|
|
|
private:
|
|
media_status_t mStatus = AMEDIA_OK;
|
|
std::mutex mMutex;
|
|
std::condition_variable mTranscodingFinishedCondition;
|
|
std::condition_variable mTrackFormatAvailableCondition;
|
|
bool mTranscodingFinished = false;
|
|
bool mTranscodingStopped = false;
|
|
bool mTrackFormatAvailable = false;
|
|
};
|
|
|
|
class TestTranscoderCallbacks : public MediaTranscoder::CallbackInterface {
|
|
public:
|
|
virtual void onFinished(const MediaTranscoder* transcoder __unused) override {
|
|
std::unique_lock<std::mutex> lock(mMutex);
|
|
EXPECT_FALSE(mFinished);
|
|
mFinished = true;
|
|
mCondition.notify_all();
|
|
}
|
|
|
|
virtual void onError(const MediaTranscoder* transcoder __unused,
|
|
media_status_t error) override {
|
|
std::unique_lock<std::mutex> lock(mMutex);
|
|
EXPECT_NE(error, AMEDIA_OK);
|
|
EXPECT_FALSE(mFinished);
|
|
mFinished = true;
|
|
mStatus = error;
|
|
mCondition.notify_all();
|
|
}
|
|
|
|
virtual void onProgressUpdate(const MediaTranscoder* transcoder __unused,
|
|
int32_t progress) override {
|
|
std::unique_lock<std::mutex> lock(mMutex);
|
|
if (progress > 0 && !mProgressMade) {
|
|
mProgressMade = true;
|
|
mCondition.notify_all();
|
|
}
|
|
}
|
|
|
|
virtual void onHeartBeat(const MediaTranscoder* transcoder __unused) override {
|
|
std::unique_lock<std::mutex> lock(mMutex);
|
|
mHeartBeatCount++;
|
|
}
|
|
|
|
virtual void onCodecResourceLost(const MediaTranscoder* transcoder __unused,
|
|
const std::shared_ptr<ndk::ScopedAParcel>& pausedState
|
|
__unused) override {}
|
|
|
|
void waitForTranscodingFinished() {
|
|
std::unique_lock<std::mutex> lock(mMutex);
|
|
while (!mFinished) {
|
|
mCondition.wait(lock);
|
|
}
|
|
}
|
|
|
|
void waitForProgressMade() {
|
|
std::unique_lock<std::mutex> lock(mMutex);
|
|
while (!mProgressMade && !mFinished) {
|
|
mCondition.wait(lock);
|
|
}
|
|
}
|
|
media_status_t mStatus = AMEDIA_OK;
|
|
bool mFinished = false;
|
|
int32_t mHeartBeatCount = 0;
|
|
|
|
private:
|
|
std::mutex mMutex;
|
|
std::condition_variable mCondition;
|
|
bool mProgressMade = false;
|
|
};
|
|
|
|
class OneShotSemaphore {
|
|
public:
|
|
void wait() {
|
|
std::unique_lock<std::mutex> lock(mMutex);
|
|
while (!mSignaled) {
|
|
mCondition.wait(lock);
|
|
}
|
|
}
|
|
|
|
void signal() {
|
|
std::unique_lock<std::mutex> lock(mMutex);
|
|
mSignaled = true;
|
|
mCondition.notify_all();
|
|
}
|
|
|
|
private:
|
|
std::mutex mMutex;
|
|
std::condition_variable mCondition;
|
|
bool mSignaled = false;
|
|
};
|
|
|
|
}; // namespace android
|