Transcoder: Improve AV transcoding speed by enforcing sequential sample access.
MediaSampleReader was bottlenecking the transcoding pipeline due to
non-sequential sample access. This commit adds an option to the sample
reader to enforce sequential sample access by blocking reads until
the underlying extractor advances to that specific track.
Follow-up: b/165374867 Make MediaSampleWriter robust against buffering track transcoders
Fixes: 160268606
Test: Transcoder unit tests, and benchmark tests.
Change-Id: Id2a363d06df927ea3e547462c52803594e0511e1
diff --git a/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp
index 323e5ae..e8acd48 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp
@@ -26,10 +26,14 @@
#include <gtest/gtest.h>
#include <media/MediaSampleReaderNDK.h>
#include <utils/Timers.h>
-
#include <cmath>
+#include <mutex>
+#include <thread>
// TODO(b/153453392): Test more asset types and validate sample data from readSampleDataForTrack.
+// TODO(b/153453392): Test for sequential and parallel (single thread and multi thread) access.
+// TODO(b/153453392): Test for switching between sequential and parallel access in different points
+// of time.
namespace android {
@@ -121,48 +125,47 @@
MediaSampleReaderNDK::createFromFd(mSourceFd, 0, mFileSize);
ASSERT_TRUE(sampleReader);
- MediaSampleInfo info;
- int trackEosCount = 0;
- std::vector<bool> trackReachedEos(mTrackCount, false);
- std::vector<std::vector<int64_t>> readerTimestamps(mTrackCount);
+ for (int trackIndex = 0; trackIndex < mTrackCount; trackIndex++) {
+ EXPECT_EQ(sampleReader->selectTrack(trackIndex), AMEDIA_OK);
+ }
// Initialize the extractor timestamps.
initExtractorTimestamps();
- // Read 5s of each track at a time.
- const int64_t chunkDurationUs = SEC_TO_USEC(5);
- int64_t chunkEndTimeUs = chunkDurationUs;
+ std::mutex timestampMutex;
+ std::vector<std::thread> trackThreads;
+ std::vector<std::vector<int64_t>> readerTimestamps(mTrackCount);
- // Loop until all tracks have reached End Of Stream.
- while (trackEosCount < mTrackCount) {
- for (int trackIndex = 0; trackIndex < mTrackCount; trackIndex++) {
- if (trackReachedEos[trackIndex]) continue;
-
- // Advance current track to next chunk end time.
- do {
+ for (int trackIndex = 0; trackIndex < mTrackCount; trackIndex++) {
+ trackThreads.emplace_back([sampleReader, trackIndex, ×tampMutex, &readerTimestamps] {
+ MediaSampleInfo info;
+ while (true) {
media_status_t status = sampleReader->getSampleInfoForTrack(trackIndex, &info);
if (status != AMEDIA_OK) {
- ASSERT_EQ(status, AMEDIA_ERROR_END_OF_STREAM);
- ASSERT_TRUE((info.flags & SAMPLE_FLAG_END_OF_STREAM) != 0);
- trackReachedEos[trackIndex] = true;
- trackEosCount++;
+ EXPECT_EQ(status, AMEDIA_ERROR_END_OF_STREAM);
+ EXPECT_TRUE((info.flags & SAMPLE_FLAG_END_OF_STREAM) != 0);
break;
}
ASSERT_TRUE((info.flags & SAMPLE_FLAG_END_OF_STREAM) == 0);
+ timestampMutex.lock();
readerTimestamps[trackIndex].push_back(info.presentationTimeUs);
+ timestampMutex.unlock();
sampleReader->advanceTrack(trackIndex);
- } while (info.presentationTimeUs < chunkEndTimeUs);
- }
- chunkEndTimeUs += chunkDurationUs;
+ }
+ });
+ }
+
+ for (auto& thread : trackThreads) {
+ thread.join();
}
for (int trackIndex = 0; trackIndex < mTrackCount; trackIndex++) {
LOG(DEBUG) << "Track " << trackIndex << ", comparing "
<< readerTimestamps[trackIndex].size() << " samples.";
- ASSERT_EQ(readerTimestamps[trackIndex].size(), mExtractorTimestamps[trackIndex].size());
+ EXPECT_EQ(readerTimestamps[trackIndex].size(), mExtractorTimestamps[trackIndex].size());
for (size_t sampleIndex = 0; sampleIndex < readerTimestamps[trackIndex].size();
sampleIndex++) {
- ASSERT_EQ(readerTimestamps[trackIndex][sampleIndex],
+ EXPECT_EQ(readerTimestamps[trackIndex][sampleIndex],
mExtractorTimestamps[trackIndex][sampleIndex]);
}
}
@@ -178,6 +181,8 @@
std::vector<int32_t> actualTrackBitrates = getTrackBitrates();
for (int trackIndex = 0; trackIndex < mTrackCount; ++trackIndex) {
+ EXPECT_EQ(sampleReader->selectTrack(trackIndex), AMEDIA_OK);
+
int32_t bitrate;
EXPECT_EQ(sampleReader->getEstimatedBitrateForTrack(trackIndex, &bitrate), AMEDIA_OK);
EXPECT_GT(bitrate, 0);