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.
238 lines
7.3 KiB
238 lines
7.3 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.
|
|
*/
|
|
|
|
// Unit Test for MediaSampleQueue
|
|
|
|
// #define LOG_NDEBUG 0
|
|
#define LOG_TAG "MediaSampleQueueTests"
|
|
|
|
#include <android-base/logging.h>
|
|
#include <gtest/gtest.h>
|
|
#include <media/MediaSampleQueue.h>
|
|
|
|
#include <thread>
|
|
|
|
namespace android {
|
|
|
|
/** Duration to use when delaying threads to order operations. */
|
|
static constexpr int64_t kThreadDelayDurationMs = 100;
|
|
|
|
class MediaSampleQueueTests : public ::testing::Test {
|
|
public:
|
|
MediaSampleQueueTests() { LOG(DEBUG) << "MediaSampleQueueTests created"; }
|
|
~MediaSampleQueueTests() { LOG(DEBUG) << "MediaSampleQueueTests destroyed"; }
|
|
};
|
|
|
|
static std::shared_ptr<MediaSample> newSample(uint32_t id) {
|
|
return MediaSample::createWithReleaseCallback(nullptr /* buffer */, 0 /* offset */, id,
|
|
nullptr /* callback */);
|
|
}
|
|
|
|
TEST_F(MediaSampleQueueTests, TestSequentialDequeueOrder) {
|
|
LOG(DEBUG) << "TestSequentialDequeueOrder Starts";
|
|
|
|
static constexpr int kNumSamples = 4;
|
|
MediaSampleQueue sampleQueue;
|
|
EXPECT_TRUE(sampleQueue.isEmpty());
|
|
|
|
// Enqueue loop.
|
|
for (int i = 0; i < kNumSamples; ++i) {
|
|
sampleQueue.enqueue(newSample(i));
|
|
EXPECT_FALSE(sampleQueue.isEmpty());
|
|
}
|
|
|
|
// Dequeue loop.
|
|
for (int i = 0; i < kNumSamples; ++i) {
|
|
std::shared_ptr<MediaSample> sample;
|
|
bool aborted = sampleQueue.dequeue(&sample);
|
|
EXPECT_NE(sample, nullptr);
|
|
EXPECT_EQ(sample->bufferId, i);
|
|
EXPECT_FALSE(aborted);
|
|
}
|
|
EXPECT_TRUE(sampleQueue.isEmpty());
|
|
}
|
|
|
|
TEST_F(MediaSampleQueueTests, TestInterleavedDequeueOrder) {
|
|
LOG(DEBUG) << "TestInterleavedDequeueOrder Starts";
|
|
|
|
static constexpr int kNumSamples = 4;
|
|
MediaSampleQueue sampleQueue;
|
|
|
|
// Enqueue and dequeue.
|
|
for (int i = 0; i < kNumSamples; ++i) {
|
|
sampleQueue.enqueue(newSample(i));
|
|
EXPECT_FALSE(sampleQueue.isEmpty());
|
|
|
|
std::shared_ptr<MediaSample> sample;
|
|
bool aborted = sampleQueue.dequeue(&sample);
|
|
EXPECT_NE(sample, nullptr);
|
|
EXPECT_EQ(sample->bufferId, i);
|
|
EXPECT_FALSE(aborted);
|
|
EXPECT_TRUE(sampleQueue.isEmpty());
|
|
}
|
|
}
|
|
|
|
TEST_F(MediaSampleQueueTests, TestBlockingDequeue) {
|
|
LOG(DEBUG) << "TestBlockingDequeue Starts";
|
|
|
|
MediaSampleQueue sampleQueue;
|
|
|
|
std::thread enqueueThread([&sampleQueue] {
|
|
// Note: This implementation is a bit racy. Any amount of sleep will not guarantee that the
|
|
// main thread will be blocked on the sample queue by the time this thread calls enqueue.
|
|
// But we can say with high confidence that it will and the test will not fail regardless.
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(kThreadDelayDurationMs));
|
|
sampleQueue.enqueue(newSample(1));
|
|
});
|
|
|
|
std::shared_ptr<MediaSample> sample;
|
|
bool aborted = sampleQueue.dequeue(&sample);
|
|
EXPECT_NE(sample, nullptr);
|
|
EXPECT_EQ(sample->bufferId, 1);
|
|
EXPECT_FALSE(aborted);
|
|
EXPECT_TRUE(sampleQueue.isEmpty());
|
|
|
|
enqueueThread.join();
|
|
}
|
|
|
|
TEST_F(MediaSampleQueueTests, TestDequeueBufferRelease) {
|
|
LOG(DEBUG) << "TestDequeueBufferRelease Starts";
|
|
|
|
static constexpr int kNumSamples = 4;
|
|
std::vector<bool> bufferReleased(kNumSamples, false);
|
|
|
|
MediaSample::OnSampleReleasedCallback callback = [&bufferReleased](MediaSample* sample) {
|
|
bufferReleased[sample->bufferId] = true;
|
|
};
|
|
|
|
MediaSampleQueue sampleQueue;
|
|
for (int i = 0; i < kNumSamples; ++i) {
|
|
bool aborted = sampleQueue.enqueue(
|
|
MediaSample::createWithReleaseCallback(nullptr, 0, i, callback));
|
|
EXPECT_FALSE(aborted);
|
|
}
|
|
|
|
for (int i = 0; i < kNumSamples; ++i) {
|
|
EXPECT_FALSE(bufferReleased[i]);
|
|
}
|
|
|
|
for (int i = 0; i < kNumSamples; ++i) {
|
|
{
|
|
std::shared_ptr<MediaSample> sample;
|
|
bool aborted = sampleQueue.dequeue(&sample);
|
|
EXPECT_NE(sample, nullptr);
|
|
EXPECT_EQ(sample->bufferId, i);
|
|
EXPECT_FALSE(bufferReleased[i]);
|
|
EXPECT_FALSE(aborted);
|
|
}
|
|
|
|
for (int j = 0; j < kNumSamples; ++j) {
|
|
EXPECT_EQ(bufferReleased[j], j <= i);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_F(MediaSampleQueueTests, TestAbortBufferRelease) {
|
|
LOG(DEBUG) << "TestAbortBufferRelease Starts";
|
|
|
|
static constexpr int kNumSamples = 4;
|
|
std::vector<bool> bufferReleased(kNumSamples, false);
|
|
|
|
MediaSample::OnSampleReleasedCallback callback = [&bufferReleased](MediaSample* sample) {
|
|
bufferReleased[sample->bufferId] = true;
|
|
};
|
|
|
|
MediaSampleQueue sampleQueue;
|
|
for (int i = 0; i < kNumSamples; ++i) {
|
|
bool aborted = sampleQueue.enqueue(
|
|
MediaSample::createWithReleaseCallback(nullptr, 0, i, callback));
|
|
EXPECT_FALSE(aborted);
|
|
}
|
|
|
|
for (int i = 0; i < kNumSamples; ++i) {
|
|
EXPECT_FALSE(bufferReleased[i]);
|
|
}
|
|
|
|
EXPECT_FALSE(sampleQueue.isEmpty());
|
|
sampleQueue.abort();
|
|
EXPECT_TRUE(sampleQueue.isEmpty());
|
|
|
|
for (int i = 0; i < kNumSamples; ++i) {
|
|
EXPECT_TRUE(bufferReleased[i]);
|
|
}
|
|
}
|
|
|
|
TEST_F(MediaSampleQueueTests, TestNonEmptyAbort) {
|
|
LOG(DEBUG) << "TestNonEmptyAbort Starts";
|
|
|
|
MediaSampleQueue sampleQueue;
|
|
bool aborted = sampleQueue.enqueue(newSample(1));
|
|
EXPECT_FALSE(aborted);
|
|
|
|
sampleQueue.abort();
|
|
|
|
std::shared_ptr<MediaSample> sample;
|
|
aborted = sampleQueue.dequeue(&sample);
|
|
EXPECT_TRUE(aborted);
|
|
EXPECT_EQ(sample, nullptr);
|
|
|
|
aborted = sampleQueue.enqueue(sample);
|
|
EXPECT_TRUE(aborted);
|
|
}
|
|
|
|
TEST_F(MediaSampleQueueTests, TestEmptyAbort) {
|
|
LOG(DEBUG) << "TestEmptyAbort Starts";
|
|
|
|
MediaSampleQueue sampleQueue;
|
|
sampleQueue.abort();
|
|
|
|
std::shared_ptr<MediaSample> sample;
|
|
bool aborted = sampleQueue.dequeue(&sample);
|
|
EXPECT_TRUE(aborted);
|
|
EXPECT_EQ(sample, nullptr);
|
|
|
|
aborted = sampleQueue.enqueue(sample);
|
|
EXPECT_TRUE(aborted);
|
|
}
|
|
|
|
TEST_F(MediaSampleQueueTests, TestBlockingAbort) {
|
|
LOG(DEBUG) << "TestBlockingAbort Starts";
|
|
|
|
MediaSampleQueue sampleQueue;
|
|
|
|
std::thread abortingThread([&sampleQueue] {
|
|
// Note: This implementation is a bit racy. Any amount of sleep will not guarantee that the
|
|
// main thread will be blocked on the sample queue by the time this thread calls abort.
|
|
// But we can say with high confidence that it will and the test will not fail regardless.
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(kThreadDelayDurationMs));
|
|
sampleQueue.abort();
|
|
});
|
|
|
|
std::shared_ptr<MediaSample> sample;
|
|
bool aborted = sampleQueue.dequeue(&sample);
|
|
EXPECT_TRUE(aborted);
|
|
EXPECT_EQ(sample, nullptr);
|
|
|
|
abortingThread.join();
|
|
}
|
|
|
|
} // namespace android
|
|
|
|
int main(int argc, char** argv) {
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
return RUN_ALL_TESTS();
|
|
}
|