WMF: fix some issues with our custom video sink.
- When scrubbing, request frames only one at a time. - Discard frames when too late or too much in advance - Fix integer overflow causing undefined behavior [ChangeLog][QtMultimedia][Windows] Fixed video playback playing at twice the normal rate after reaching 3:34. [ChangeLog][QtMultimedia][Windows] Fixed video playback that could freeze after seeking to a different position. Task-number: QTBUG-31800 Change-Id: Ie620c684c58ee790537969ffc40f01610b6745ea Reviewed-by: Christian Stromme <christian.stromme@digia.com>
This commit is contained in:
committed by
The Qt Project
parent
4855707ed7
commit
04edeafade
@@ -257,6 +257,7 @@ namespace
|
|||||||
, m_bufferStartTime(-1)
|
, m_bufferStartTime(-1)
|
||||||
, m_bufferDuration(-1)
|
, m_bufferDuration(-1)
|
||||||
, m_presentationClock(0)
|
, m_presentationClock(0)
|
||||||
|
, m_sampleRequested(false)
|
||||||
, m_currentMediaType(0)
|
, m_currentMediaType(0)
|
||||||
, m_prerolling(false)
|
, m_prerolling(false)
|
||||||
, m_prerollTargetTime(0)
|
, m_prerollTargetTime(0)
|
||||||
@@ -854,6 +855,15 @@ namespace
|
|||||||
schedulePresentation(true);
|
schedulePresentation(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clearScheduledFrame()
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_mutex);
|
||||||
|
if (m_scheduledBuffer) {
|
||||||
|
m_scheduledBuffer->Release();
|
||||||
|
m_scheduledBuffer = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
StartSurface = QEvent::User,
|
StartSurface = QEvent::User,
|
||||||
@@ -871,7 +881,7 @@ namespace
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int targetTime()
|
MFTIME targetTime()
|
||||||
{
|
{
|
||||||
return m_time;
|
return m_time;
|
||||||
}
|
}
|
||||||
@@ -1317,6 +1327,8 @@ namespace
|
|||||||
|
|
||||||
HRESULT processSampleData(IMFSample *pSample)
|
HRESULT processSampleData(IMFSample *pSample)
|
||||||
{
|
{
|
||||||
|
m_sampleRequested = false;
|
||||||
|
|
||||||
LONGLONG time, duration = -1;
|
LONGLONG time, duration = -1;
|
||||||
HRESULT hr = pSample->GetSampleTime(&time);
|
HRESULT hr = pSample->GetSampleTime(&time);
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
@@ -1406,13 +1418,16 @@ namespace
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (requestSample && m_bufferCache.size() < BUFFER_CACHE_SIZE)
|
if (requestSample && !m_sampleRequested && m_bufferCache.size() < BUFFER_CACHE_SIZE) {
|
||||||
|
m_sampleRequested = true;
|
||||||
queueEvent(MEStreamSinkRequestSample, GUID_NULL, S_OK, NULL);
|
queueEvent(MEStreamSinkRequestSample, GUID_NULL, S_OK, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
IMFMediaBuffer *m_scheduledBuffer;
|
IMFMediaBuffer *m_scheduledBuffer;
|
||||||
MFTIME m_bufferStartTime;
|
MFTIME m_bufferStartTime;
|
||||||
MFTIME m_bufferDuration;
|
MFTIME m_bufferDuration;
|
||||||
IMFPresentationClock *m_presentationClock;
|
IMFPresentationClock *m_presentationClock;
|
||||||
|
bool m_sampleRequested;
|
||||||
float m_rate;
|
float m_rate;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1480,6 +1495,14 @@ namespace
|
|||||||
m_stream->present();
|
m_stream->present();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clearScheduledFrame()
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_mutex);
|
||||||
|
if (m_shutdown)
|
||||||
|
return;
|
||||||
|
m_stream->clearScheduledFrame();
|
||||||
|
}
|
||||||
|
|
||||||
MFTIME getTime()
|
MFTIME getTime()
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&m_mutex);
|
QMutexLocker locker(&m_mutex);
|
||||||
@@ -2066,6 +2089,14 @@ namespace
|
|||||||
m_sink->present();
|
m_sink->present();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clearScheduledFrame()
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_mutex);
|
||||||
|
if (!m_sink)
|
||||||
|
return;
|
||||||
|
m_sink->clearScheduledFrame();
|
||||||
|
}
|
||||||
|
|
||||||
MFTIME getTime()
|
MFTIME getTime()
|
||||||
{
|
{
|
||||||
if (m_sink)
|
if (m_sink)
|
||||||
@@ -2170,10 +2201,16 @@ void MFVideoRendererControl::customEvent(QEvent *event)
|
|||||||
MFTIME targetTime = static_cast<MediaStream::PresentEvent*>(event)->targetTime();
|
MFTIME targetTime = static_cast<MediaStream::PresentEvent*>(event)->targetTime();
|
||||||
MFTIME currentTime = static_cast<VideoRendererActivate*>(m_currentActivate)->getTime();
|
MFTIME currentTime = static_cast<VideoRendererActivate*>(m_currentActivate)->getTime();
|
||||||
float playRate = static_cast<VideoRendererActivate*>(m_currentActivate)->getPlayRate();
|
float playRate = static_cast<VideoRendererActivate*>(m_currentActivate)->getPlayRate();
|
||||||
if (playRate > 0.0001f && targetTime > currentTime)
|
if (!qFuzzyIsNull(playRate)) {
|
||||||
QTimer::singleShot(int((float)((targetTime - currentTime) / 10000) / playRate), this, SLOT(present()));
|
// If the scheduled frame is too late or too much in advance, skip it
|
||||||
else
|
const int diff = (targetTime - currentTime) / 10000;
|
||||||
|
if (diff < 0 || diff > 500)
|
||||||
|
static_cast<VideoRendererActivate*>(m_currentActivate)->clearScheduledFrame();
|
||||||
|
else
|
||||||
|
QTimer::singleShot(diff / playRate, this, SLOT(present()));
|
||||||
|
} else {
|
||||||
present();
|
present();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (event->type() >= MediaStream::StartSurface) {
|
if (event->type() >= MediaStream::StartSurface) {
|
||||||
|
|||||||
Reference in New Issue
Block a user