Transcoder: Add support for progress updates.
Progress updates are delivered as long as any track
in the file has a valid duration.
Fixes: 160277443
Test: MediaSampleWriter and MediaTranscoder unit tests.
Change-Id: I52bbf55cfd2445b98dfc4d9c9ae09bcf7de86a86
diff --git a/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp b/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
index 91dbf78..3676d73 100644
--- a/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
+++ b/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
@@ -78,14 +78,14 @@
}
}
-bool MediaSampleWriter::init(int fd, const OnWritingFinishedCallback& callback) {
- return init(DefaultMuxer::create(fd), callback);
+bool MediaSampleWriter::init(int fd, const std::weak_ptr<CallbackInterface>& callbacks) {
+ return init(DefaultMuxer::create(fd), callbacks);
}
bool MediaSampleWriter::init(const std::shared_ptr<MediaSampleWriterMuxerInterface>& muxer,
- const OnWritingFinishedCallback& callback) {
- if (callback == nullptr) {
- LOG(ERROR) << "Callback cannot be null";
+ const std::weak_ptr<CallbackInterface>& callbacks) {
+ if (callbacks.lock() == nullptr) {
+ LOG(ERROR) << "Callback object cannot be null";
return false;
} else if (muxer == nullptr) {
LOG(ERROR) << "Muxer cannot be null";
@@ -100,7 +100,7 @@
mState = INITIALIZED;
mMuxer = muxer;
- mWritingFinishedCallback = callback;
+ mCallbacks = callbacks;
return true;
}
@@ -127,7 +127,11 @@
durationUs = 0;
}
- mTracks.emplace_back(sampleQueue, static_cast<size_t>(trackIndex), durationUs);
+ const char* mime = nullptr;
+ const bool isVideo = AMediaFormat_getString(trackFormat.get(), AMEDIAFORMAT_KEY_MIME, &mime) &&
+ (strncmp(mime, "video/", 6) == 0);
+
+ mTracks.emplace_back(sampleQueue, static_cast<size_t>(trackIndex), durationUs, isVideo);
return true;
}
@@ -144,7 +148,9 @@
mThread = std::thread([this] {
media_status_t status = writeSamples();
- mWritingFinishedCallback(status);
+ if (auto callbacks = mCallbacks.lock()) {
+ callbacks->onFinished(this, status);
+ }
});
mState = STARTED;
return true;
@@ -191,6 +197,18 @@
AMediaCodecBufferInfo bufferInfo;
uint32_t segmentEndTimeUs = mTrackSegmentLengthUs;
bool samplesLeft = true;
+ int32_t lastProgressUpdate = 0;
+
+ // Set the "primary" track that will be used to determine progress to the track with longest
+ // duration.
+ int primaryTrackIndex = -1;
+ int64_t longestDurationUs = 0;
+ for (int trackIndex = 0; trackIndex < mTracks.size(); ++trackIndex) {
+ if (mTracks[trackIndex].mDurationUs > longestDurationUs) {
+ primaryTrackIndex = trackIndex;
+ longestDurationUs = mTracks[trackIndex].mDurationUs;
+ }
+ }
while (samplesLeft) {
samplesLeft = false;
@@ -216,9 +234,10 @@
samplesLeft = true;
}
- // Record the first sample's timestamp in order to translate duration to EOS time
- // for tracks that does not start at 0.
+ track.mPrevSampleTimeUs = sample->info.presentationTimeUs;
if (!track.mFirstSampleTimeSet) {
+ // Record the first sample's timestamp in order to translate duration to EOS
+ // time for tracks that does not start at 0.
track.mFirstSampleTimeUs = sample->info.presentationTimeUs;
track.mFirstSampleTimeSet = true;
}
@@ -238,6 +257,22 @@
} while (sample->info.presentationTimeUs < segmentEndTimeUs && !track.mReachedEos);
}
+ // TODO(lnilsson): Add option to toggle progress reporting on/off.
+ if (primaryTrackIndex >= 0) {
+ const TrackRecord& track = mTracks[primaryTrackIndex];
+
+ const int64_t elapsed = track.mPrevSampleTimeUs - track.mFirstSampleTimeUs;
+ int32_t progress = (elapsed * 100) / track.mDurationUs;
+ progress = std::clamp(progress, 0, 100);
+
+ if (progress > lastProgressUpdate) {
+ if (auto callbacks = mCallbacks.lock()) {
+ callbacks->onProgressUpdate(this, progress);
+ }
+ lastProgressUpdate = progress;
+ }
+ }
+
segmentEndTimeUs += mTrackSegmentLengthUs;
}