Fill in frame duration from sample meta
If sample duration is not available, use the average
frame duration of the sequence; if that's not available
default to 30fps.
bug: 120414514
bug: 139815242
test: test some 25fps heif sequence files, the reported
duration should be 40ms instead of the default 33ms.
Change-Id: I5ddf0a6cbfb44021dee2955badf3f2772586bb1e
diff --git a/include/private/media/VideoFrame.h b/include/private/media/VideoFrame.h
index 712f118..16e794a 100644
--- a/include/private/media/VideoFrame.h
+++ b/include/private/media/VideoFrame.h
@@ -41,7 +41,7 @@
uint32_t angle, uint32_t bpp, bool hasData, size_t iccSize):
mWidth(width), mHeight(height),
mDisplayWidth(displayWidth), mDisplayHeight(displayHeight),
- mTileWidth(tileWidth), mTileHeight(tileHeight),
+ mTileWidth(tileWidth), mTileHeight(tileHeight), mDurationUs(0),
mRotationAngle(angle), mBytesPerPixel(bpp), mRowBytes(bpp * width),
mSize(hasData ? (bpp * width * height) : 0),
mIccSize(iccSize), mReserved(0) {
@@ -78,6 +78,7 @@
uint32_t mDisplayHeight; // Display height before rotation
uint32_t mTileWidth; // Tile width (0 if image doesn't have grid)
uint32_t mTileHeight; // Tile height (0 if image doesn't have grid)
+ int64_t mDurationUs; // Frame duration in microseconds
int32_t mRotationAngle; // Rotation angle, clockwise, should be multiple of 90
uint32_t mBytesPerPixel; // Number of bytes per pixel
uint32_t mRowBytes; // Number of bytes per row before rotation
diff --git a/media/libheif/HeifDecoderImpl.cpp b/media/libheif/HeifDecoderImpl.cpp
index a7c0f84..bad4210 100644
--- a/media/libheif/HeifDecoderImpl.cpp
+++ b/media/libheif/HeifDecoderImpl.cpp
@@ -44,8 +44,7 @@
info->mHeight = videoFrame->mHeight;
info->mRotationAngle = videoFrame->mRotationAngle;
info->mBytesPerPixel = videoFrame->mBytesPerPixel;
- // TODO: retrieve per-frame duration from extractor/metadataretriever.
- info->mDurationUs = 33333;
+ info->mDurationUs = videoFrame->mDurationUs;
if (videoFrame->mIccSize > 0) {
info->mIccData.assign(
videoFrame->getFlattenedIccData(),
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index c6ec6de..f99dd1c 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -43,6 +43,7 @@
static const int64_t kBufferTimeOutUs = 10000LL; // 10 msec
static const size_t kRetryCount = 50; // must be >0
+static const int64_t kDefaultSampleDurationUs = 33333LL; // 33ms
sp<IMemory> allocVideoFrame(const sp<MetaData>& trackMeta,
int32_t width, int32_t height, int32_t tileWidth, int32_t tileHeight,
@@ -199,7 +200,19 @@
tileWidth = tileHeight = 0;
}
}
- return allocMetaFrame(trackMeta, width, height, tileWidth, tileHeight, dstBpp);
+
+ sp<IMemory> metaMem = allocMetaFrame(trackMeta, width, height, tileWidth, tileHeight, dstBpp);
+
+ // try to fill sequence meta's duration based on average frame rate,
+ // default to 33ms if frame rate is unavailable.
+ int32_t frameRate;
+ VideoFrame* meta = static_cast<VideoFrame*>(metaMem->pointer());
+ if (trackMeta->findInt32(kKeyFrameRate, &frameRate) && frameRate > 0) {
+ meta->mDurationUs = 1000000LL / frameRate;
+ } else {
+ meta->mDurationUs = kDefaultSampleDurationUs;
+ }
+ return metaMem;
}
FrameDecoder::FrameDecoder(
@@ -443,7 +456,8 @@
mFrame(NULL),
mIsAvcOrHevc(false),
mSeekMode(MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC),
- mTargetTimeUs(-1LL) {
+ mTargetTimeUs(-1LL),
+ mDefaultSampleDurationUs(0) {
}
sp<AMessage> VideoFrameDecoder::onGetFormatAndSeekOptions(
@@ -506,6 +520,13 @@
}
}
+ int32_t frameRate;
+ if (trackMeta()->findInt32(kKeyFrameRate, &frameRate) && frameRate > 0) {
+ mDefaultSampleDurationUs = 1000000LL / frameRate;
+ } else {
+ mDefaultSampleDurationUs = kDefaultSampleDurationUs;
+ }
+
return videoFormat;
}
@@ -526,6 +547,12 @@
// option, in which case we need to actually decode to targetTimeUs.
*flags |= MediaCodec::BUFFER_FLAG_EOS;
}
+ int64_t durationUs;
+ if (sampleMeta.findInt64(kKeyDuration, &durationUs)) {
+ mSampleDurations.push_back(durationUs);
+ } else {
+ mSampleDurations.push_back(mDefaultSampleDurationUs);
+ }
return OK;
}
@@ -533,6 +560,11 @@
const sp<MediaCodecBuffer> &videoFrameBuffer,
const sp<AMessage> &outputFormat,
int64_t timeUs, bool *done) {
+ int64_t durationUs = mDefaultSampleDurationUs;
+ if (!mSampleDurations.empty()) {
+ durationUs = *mSampleDurations.begin();
+ mSampleDurations.erase(mSampleDurations.begin());
+ }
bool shouldOutput = (mTargetTimeUs < 0LL) || (timeUs >= mTargetTimeUs);
// If this is not the target frame, skip color convert.
@@ -587,6 +619,8 @@
setFrame(frameMem);
}
+ mFrame->mDurationUs = durationUs;
+
if (mSurfaceControl != nullptr) {
return captureSurfaceControl();
}
diff --git a/media/libstagefright/include/FrameDecoder.h b/media/libstagefright/include/FrameDecoder.h
index 1af6276..8e42fcf 100644
--- a/media/libstagefright/include/FrameDecoder.h
+++ b/media/libstagefright/include/FrameDecoder.h
@@ -139,6 +139,8 @@
bool mIsAvcOrHevc;
MediaSource::ReadOptions::SeekMode mSeekMode;
int64_t mTargetTimeUs;
+ List<int64_t> mSampleDurations;
+ int64_t mDefaultSampleDurationUs;
sp<Surface> initSurfaceControl();
status_t captureSurfaceControl();