39 ** |
39 ** |
40 ****************************************************************************/ |
40 ****************************************************************************/ |
41 |
41 |
42 #include "directshowsamplescheduler.h" |
42 #include "directshowsamplescheduler.h" |
43 |
43 |
|
44 #include <QtCore/qcoreapplication.h> |
44 #include <QtCore/qcoreevent.h> |
45 #include <QtCore/qcoreevent.h> |
45 |
46 |
46 class DirectShowTimedSample |
47 class DirectShowTimedSample |
47 { |
48 { |
48 public: |
49 public: |
113 } |
114 } |
114 return true; |
115 return true; |
115 } |
116 } |
116 |
117 |
117 DirectShowSampleScheduler::DirectShowSampleScheduler(IUnknown *pin, QObject *parent) |
118 DirectShowSampleScheduler::DirectShowSampleScheduler(IUnknown *pin, QObject *parent) |
118 : QWinEventNotifier(parent) |
119 : QObject(parent) |
119 , m_pin(pin) |
120 , m_pin(pin) |
120 , m_clock(0) |
121 , m_clock(0) |
121 , m_allocator(0) |
122 , m_allocator(0) |
122 , m_head(0) |
123 , m_head(0) |
123 , m_tail(0) |
124 , m_tail(0) |
124 , m_maximumSamples(2) |
125 , m_maximumSamples(1) |
125 , m_state(Stopped) |
126 , m_state(Stopped) |
126 , m_startTime(0) |
127 , m_startTime(0) |
127 , m_timeoutEvent(::CreateEvent(0, 0, 0, 0)) |
128 , m_timeoutEvent(::CreateEvent(0, 0, 0, 0)) |
|
129 , m_flushEvent(::CreateEvent(0, 0, 0, 0)) |
128 { |
130 { |
129 m_semaphore.release(m_maximumSamples); |
131 m_semaphore.release(m_maximumSamples); |
130 |
|
131 setHandle(m_timeoutEvent); |
|
132 setEnabled(true); |
|
133 } |
132 } |
134 |
133 |
135 DirectShowSampleScheduler::~DirectShowSampleScheduler() |
134 DirectShowSampleScheduler::~DirectShowSampleScheduler() |
136 { |
135 { |
137 setEnabled(false); |
|
138 |
|
139 ::CloseHandle(m_timeoutEvent); |
136 ::CloseHandle(m_timeoutEvent); |
|
137 ::CloseHandle(m_flushEvent); |
140 |
138 |
141 Q_ASSERT(!m_clock); |
139 Q_ASSERT(!m_clock); |
142 Q_ASSERT(!m_allocator); |
140 Q_ASSERT(!m_allocator); |
143 } |
141 } |
144 |
142 |
250 m_tail = timedSample; |
248 m_tail = timedSample; |
251 |
249 |
252 if (m_state == Running) { |
250 if (m_state == Running) { |
253 if (!timedSample->schedule(m_clock, m_startTime, m_timeoutEvent)) { |
251 if (!timedSample->schedule(m_clock, m_startTime, m_timeoutEvent)) { |
254 // Timing information is unavailable, so schedule frames immediately. |
252 // Timing information is unavailable, so schedule frames immediately. |
255 QMetaObject::invokeMethod(this, "timerActivated", Qt::QueuedConnection); |
253 QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest)); |
|
254 } else { |
|
255 locker.unlock(); |
|
256 HANDLE handles[] = { m_flushEvent, m_timeoutEvent }; |
|
257 DWORD result = ::WaitForMultipleObjects(2, handles, FALSE, INFINITE); |
|
258 locker.relock(); |
|
259 |
|
260 if (result == WAIT_OBJECT_0 + 1) |
|
261 QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest)); |
256 } |
262 } |
257 } else if (m_tail == m_head) { |
263 } else if (m_tail == m_head) { |
258 // If this is the first frame make is available. |
264 // If this is the first frame make it available. |
259 QMetaObject::invokeMethod(this, "timerActivated", Qt::QueuedConnection); |
265 QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest)); |
|
266 |
|
267 if (m_state == Paused) { |
|
268 ::ResetEvent(m_timeoutEvent); |
|
269 |
|
270 locker.unlock(); |
|
271 HANDLE handles[] = { m_flushEvent, m_timeoutEvent }; |
|
272 ::WaitForMultipleObjects(2, handles, FALSE, INFINITE); |
|
273 locker.relock(); |
|
274 } |
260 } |
275 } |
261 |
276 |
262 return S_OK; |
277 return S_OK; |
263 } |
278 } |
264 } |
279 } |
291 m_startTime = startTime; |
306 m_startTime = startTime; |
292 |
307 |
293 for (DirectShowTimedSample *sample = m_head; sample; sample = sample->nextSample()) { |
308 for (DirectShowTimedSample *sample = m_head; sample; sample = sample->nextSample()) { |
294 sample->schedule(m_clock, m_startTime, m_timeoutEvent); |
309 sample->schedule(m_clock, m_startTime, m_timeoutEvent); |
295 } |
310 } |
|
311 |
|
312 if (!(m_state & Flushing)) |
|
313 ::ResetEvent(m_flushEvent); |
|
314 |
|
315 if (!m_head) |
|
316 ::SetEvent(m_timeoutEvent); |
|
317 |
296 } |
318 } |
297 |
319 |
298 void DirectShowSampleScheduler::pause() |
320 void DirectShowSampleScheduler::pause() |
299 { |
321 { |
300 QMutexLocker locker(&m_mutex); |
322 QMutexLocker locker(&m_mutex); |
301 |
323 |
302 m_state = (m_state & Flushing) | Paused; |
324 m_state = (m_state & Flushing) | Paused; |
303 |
325 |
304 for (DirectShowTimedSample *sample = m_head; sample; sample = sample->nextSample()) |
326 for (DirectShowTimedSample *sample = m_head; sample; sample = sample->nextSample()) |
305 sample->unschedule(m_clock); |
327 sample->unschedule(m_clock); |
|
328 |
|
329 if (!(m_state & Flushing)) |
|
330 ::ResetEvent(m_flushEvent); |
306 } |
331 } |
307 |
332 |
308 void DirectShowSampleScheduler::stop() |
333 void DirectShowSampleScheduler::stop() |
309 { |
334 { |
310 QMutexLocker locker(&m_mutex); |
335 QMutexLocker locker(&m_mutex); |
363 |
395 |
364 if (m_head && m_head->isReady(m_clock)) { |
396 if (m_head && m_head->isReady(m_clock)) { |
365 IMediaSample *sample = m_head->sample(); |
397 IMediaSample *sample = m_head->sample(); |
366 sample->AddRef(); |
398 sample->AddRef(); |
367 |
399 |
368 if (m_state == Running) { |
400 *eos = m_head->isLast(); |
369 *eos = m_head->isLast(); |
401 |
370 |
402 m_head = m_head->remove(); |
371 m_head = m_head->remove(); |
403 |
372 |
404 if (!m_head) |
373 if (!m_head) |
405 m_tail = 0; |
374 m_tail = 0; |
406 |
375 |
407 m_semaphore.release(1); |
376 m_semaphore.release(1); |
|
377 } |
|
378 |
408 |
379 return sample; |
409 return sample; |
380 } else { |
410 } else { |
381 return 0; |
411 return 0; |
382 } |
412 } |