mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 11:25:00 +00:00
Bug 1294154: Handle case where WMF is unable to determine time and duration. r=mattwoodrow
The WMF decoder doesn't handle well the case where a single frame was given to decode. When draining, the output is a correctly decoded frame but with a time of 0 and a duration set at 1/30th. This is a workaround MozReview-Commit-ID: JbjgNmPXKIM --HG-- extra : rebase_source : f25a1fd503678383265ec5053b41f3116ff52da0
This commit is contained in:
parent
d98e95abb8
commit
747d2faea4
@ -37,12 +37,13 @@ public:
|
|||||||
virtual HRESULT Output(int64_t aStreamOffset,
|
virtual HRESULT Output(int64_t aStreamOffset,
|
||||||
RefPtr<MediaData>& aOutput) = 0;
|
RefPtr<MediaData>& aOutput) = 0;
|
||||||
|
|
||||||
void Flush() {
|
virtual void Flush()
|
||||||
|
{
|
||||||
mDecoder->Flush();
|
mDecoder->Flush();
|
||||||
mSeekTargetThreshold.reset();
|
mSeekTargetThreshold.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Drain()
|
virtual void Drain()
|
||||||
{
|
{
|
||||||
if (FAILED(mDecoder->SendMFTMessage(MFT_MESSAGE_COMMAND_DRAIN, 0))) {
|
if (FAILED(mDecoder->SendMFTMessage(MFT_MESSAGE_COMMAND_DRAIN, 0))) {
|
||||||
NS_WARNING("Failed to send DRAIN command to MFT");
|
NS_WARNING("Failed to send DRAIN command to MFT");
|
||||||
|
@ -525,6 +525,8 @@ WMFVideoMFTManager::Input(MediaRawData* aSample)
|
|||||||
NS_ENSURE_TRUE(SUCCEEDED(hr) && mLastInput != nullptr, hr);
|
NS_ENSURE_TRUE(SUCCEEDED(hr) && mLastInput != nullptr, hr);
|
||||||
|
|
||||||
mLastDuration = aSample->mDuration;
|
mLastDuration = aSample->mDuration;
|
||||||
|
mLastTime = aSample->mTime;
|
||||||
|
mSamplesCount++;
|
||||||
|
|
||||||
// Forward sample data to the decoder.
|
// Forward sample data to the decoder.
|
||||||
return mDecoder->Input(mLastInput);
|
return mDecoder->Input(mLastInput);
|
||||||
@ -832,6 +834,15 @@ WMFVideoMFTManager::Output(int64_t aStreamOffset,
|
|||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
aOutData = nullptr;
|
aOutData = nullptr;
|
||||||
int typeChangeCount = 0;
|
int typeChangeCount = 0;
|
||||||
|
bool wasDraining = mDraining;
|
||||||
|
int64_t sampleCount = mSamplesCount;
|
||||||
|
if (wasDraining) {
|
||||||
|
mSamplesCount = 0;
|
||||||
|
mDraining = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
media::TimeUnit pts;
|
||||||
|
media::TimeUnit duration;
|
||||||
|
|
||||||
// Loop until we decode a sample, or an unexpected error that we can't
|
// Loop until we decode a sample, or an unexpected error that we can't
|
||||||
// handle occurs.
|
// handle occurs.
|
||||||
@ -873,12 +884,21 @@ WMFVideoMFTManager::Output(int64_t aStreamOffset,
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
pts = GetSampleTime(sample);
|
||||||
|
duration = GetSampleDuration(sample);
|
||||||
|
if (!pts.IsValid() || !duration.IsValid()) {
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
if (wasDraining && sampleCount == 1 && pts == media::TimeUnit()) {
|
||||||
|
// WMF is unable to calculate a duration if only a single sample
|
||||||
|
// was parsed. Additionally, the pts always comes out at 0 under those
|
||||||
|
// circumstances.
|
||||||
|
// Seeing that we've only fed the decoder a single frame, the pts
|
||||||
|
// and duration are known, it's of the last sample.
|
||||||
|
pts = media::TimeUnit::FromMicroseconds(mLastTime);
|
||||||
|
duration = media::TimeUnit::FromMicroseconds(mLastDuration);
|
||||||
|
}
|
||||||
if (mSeekTargetThreshold.isSome()) {
|
if (mSeekTargetThreshold.isSome()) {
|
||||||
media::TimeUnit pts = GetSampleTime(sample);
|
|
||||||
media::TimeUnit duration = GetSampleDuration(sample);
|
|
||||||
if (!pts.IsValid() || !duration.IsValid()) {
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
if ((pts + duration) < mSeekTargetThreshold.ref()) {
|
if ((pts + duration) < mSeekTargetThreshold.ref()) {
|
||||||
LOG("Dropping video frame which pts is smaller than seek target.");
|
LOG("Dropping video frame which pts is smaller than seek target.");
|
||||||
// It is necessary to clear the pointer to release the previous output
|
// It is necessary to clear the pointer to release the previous output
|
||||||
@ -907,6 +927,9 @@ WMFVideoMFTManager::Output(int64_t aStreamOffset,
|
|||||||
NS_ENSURE_TRUE(frame, E_FAIL);
|
NS_ENSURE_TRUE(frame, E_FAIL);
|
||||||
|
|
||||||
aOutData = frame;
|
aOutData = frame;
|
||||||
|
// Set the potentially corrected pts and duration.
|
||||||
|
aOutData->mTime = pts.ToMicroseconds();
|
||||||
|
aOutData->mDuration = duration.ToMicroseconds();
|
||||||
|
|
||||||
if (mNullOutputCount) {
|
if (mNullOutputCount) {
|
||||||
mGotValidOutputAfterNullOutput = true;
|
mGotValidOutputAfterNullOutput = true;
|
||||||
|
@ -49,6 +49,19 @@ public:
|
|||||||
? "wmf hardware video decoder" : "wmf software video decoder";
|
? "wmf hardware video decoder" : "wmf software video decoder";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Flush() override
|
||||||
|
{
|
||||||
|
MFTManager::Flush();
|
||||||
|
mDraining = false;
|
||||||
|
mSamplesCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Drain() override
|
||||||
|
{
|
||||||
|
MFTManager::Drain();
|
||||||
|
mDraining = true;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool ValidateVideoInfo();
|
bool ValidateVideoInfo();
|
||||||
@ -81,6 +94,9 @@ private:
|
|||||||
|
|
||||||
RefPtr<IMFSample> mLastInput;
|
RefPtr<IMFSample> mLastInput;
|
||||||
float mLastDuration;
|
float mLastDuration;
|
||||||
|
int64_t mLastTime = 0;
|
||||||
|
bool mDraining = false;
|
||||||
|
int64_t mSamplesCount = 0;
|
||||||
|
|
||||||
bool mDXVAEnabled;
|
bool mDXVAEnabled;
|
||||||
const layers::LayersBackend mLayersBackend;
|
const layers::LayersBackend mLayersBackend;
|
||||||
|
Loading…
Reference in New Issue
Block a user