Move the sources to trunk
[opencv] / filters / SyncFilter / SyncFilter.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 #include "CV.h"
43 #include <windows.h>
44 #include <cvstreams.h>
45 #include <initguid.h>
46 #include <stdlib.h>
47 #include "syncfilter.h"
48 #include "syncfilteruids.h"
49 #include "isyncfilter.h"
50
51 const AMOVIESETUP_MEDIATYPE sudPinTypes =
52 {
53   &MEDIATYPE_Video,            // major type
54   &MEDIASUBTYPE_NULL           // minor type
55 };
56
57 const AMOVIESETUP_PIN sudpPins[] =
58 {
59     {
60         L"Input1",          // String pin name
61         FALSE,              // Is it rendered
62         FALSE,              // Is it an output
63         FALSE,              // Allowed none
64         FALSE,              // Allowed many
65         &CLSID_NULL,        // Connects to filter
66         L"Output1",         // Connects to pin
67         1,                  // Number of types
68         &sudPinTypes        // The pin details
69     },
70     {
71         L"Input2",          // String pin name
72         FALSE,              // Is it rendered
73         FALSE,              // Is it an output
74         FALSE,              // Allowed none
75         FALSE,              // Allowed many
76         &CLSID_NULL,        // Connects to filter
77         L"Output2",         // Connects to pin
78         1,                  // Number of types
79         &sudPinTypes        // The pin details
80     },
81     {
82         L"Input3",          // String pin name
83         FALSE,              // Is it rendered
84         FALSE,              // Is it an output
85         FALSE,              // Allowed none
86         FALSE,              // Allowed many
87         &CLSID_NULL,        // Connects to filter
88         L"Output3",         // Connects to pin
89         1,                  // Number of types
90         &sudPinTypes        // The pin details
91     },
92     {
93         L"Input4",          // String pin name
94         FALSE,              // Is it rendered
95         FALSE,              // Is it an output
96         FALSE,              // Allowed none
97         FALSE,              // Allowed many
98         &CLSID_NULL,        // Connects to filter
99         L"Output4",         // Connects to pin
100         1,                  // Number of types
101         &sudPinTypes        // The pin details
102     },
103
104     {
105         L"Output1",         // String pin name
106         TRUE,               // Is it rendered
107         TRUE,               // Is it an output
108         FALSE,              // Allowed none
109         FALSE,              // Allowed many
110         &CLSID_NULL,        // Connects to filter
111         L"Input1",          // Connects to pin
112         1,                  // Number of types
113         &sudPinTypes        // The pin details
114     },
115     {
116         L"Output2",         // String pin name
117         TRUE,               // Is it rendered
118         TRUE,               // Is it an output
119         FALSE,              // Allowed none
120         FALSE,              // Allowed many
121         &CLSID_NULL,        // Connects to filter
122         L"Input2",          // Connects to pin
123         1,                  // Number of types
124         &sudPinTypes        // The pin details
125     },
126     {
127         L"Output3",         // String pin name
128         TRUE,               // Is it rendered
129         TRUE,               // Is it an output
130         FALSE,              // Allowed none
131         FALSE,              // Allowed many
132         &CLSID_NULL,        // Connects to filter
133         L"Input3",          // Connects to pin
134         1,                  // Number of types
135         &sudPinTypes        // The pin details
136     },
137     {
138         L"Output4",         // String pin name
139         TRUE,               // Is it rendered
140         TRUE,               // Is it an output
141         FALSE,              // Allowed none
142         FALSE,              // Allowed many
143         &CLSID_NULL,        // Connects to filter
144         L"Input4",          // Connects to pin
145         1,                  // Number of types
146         &sudPinTypes        // The pin details
147     }
148 };
149
150 const AMOVIESETUP_FILTER  sudMyFilter =
151 {
152     &CLSID_SyncFilter                           // clsID
153     , L"VideoSync Extended Filter for OpenCV"   // strName
154     , MERIT_DO_NOT_USE                          // dwMerit
155     , 4                                         // nPins
156     , sudpPins                                  // lpPin
157 };
158
159 SyncFilter::SyncFilter(TCHAR *tszName, LPUNKNOWN punk, HRESULT *phr)
160     :m_csFilter(), CBaseFilter(tszName, punk, &m_csFilter, CLSID_SyncFilter), m_NbConnected(0), m_callback2(NULL), m_callback3(NULL), m_callback4(NULL)
161 {
162     m_ip[0] = new cvSyncInputPin(NAME ( "1-st input pin"),
163                                this,
164                                &m_csFilter,
165                                &m_hr,
166                                L"Input1");
167     m_ip[1] = new cvSyncInputPin(NAME ( "2-nd input pin"),
168                                this,
169                                &m_csFilter,
170                                &m_hr,
171                                L"Input2");
172     m_ip[2] = new cvSyncInputPin(NAME ( "3-rd input pin"),
173                                this,
174                                &m_csFilter,
175                                &m_hr,
176                                L"Input3");
177     m_ip[3] = new cvSyncInputPin(NAME ( "4-th input pin"),
178                                this,
179                                &m_csFilter,
180                                &m_hr,
181                                L"Input4");
182
183     m_op[0] = new cvSyncOutputPin(NAME("1-st output pin"),
184                                this,
185                                &m_csFilter,
186                                &m_hr,
187                                L"Output1");
188     m_op[1] = new cvSyncOutputPin(NAME("2-nd output pin"),
189                                this,
190                                &m_csFilter,
191                                &m_hr,
192                                L"Output2");
193     m_op[2] = new cvSyncOutputPin(NAME("3-rd output pin"),
194                                this,
195                                &m_csFilter,
196                                &m_hr,
197                                L"Output3");
198     m_op[3] = new cvSyncOutputPin(NAME("4-th output pin"),
199                                this,
200                                &m_csFilter,
201                                &m_hr,
202                                L"Output4");
203
204     for (int i=0;i<4;i++)
205     {
206         m_ip[i]->m_op = m_op[i];
207         m_op[i]->m_ip = m_ip[i];
208     }
209 }
210
211 CUnknown * WINAPI SyncFilter::CreateInstance(LPUNKNOWN punk, HRESULT *phr)
212 {
213     SyncFilter *pNewObject = new SyncFilter(NAME("VideoSync Extended Filter for OpenCV"), punk, phr );
214
215     if (pNewObject == NULL)
216     {
217         *phr = E_OUTOFMEMORY;
218     }
219
220     return pNewObject;
221 }
222
223 int SyncFilter::GetPinCount(void)
224 {
225     return 8;
226 }
227
228 CBasePin* SyncFilter::GetPin(int n)
229 {
230     if(n==0)
231         return m_ip[0];
232     if(n==1)
233         return m_ip[1];
234     if(n==2)
235         return m_ip[2];
236     if(n==3)
237         return m_ip[3];
238     if(n==4)
239         return m_op[0];
240     if(n==5)
241         return m_op[1];
242     if(n==6)
243         return m_op[2];
244     if(n==7)
245         return m_op[3];
246
247     return NULL;
248 }
249
250 HRESULT cvSyncOutputPin::CheckMediaType(const CMediaType* pmt)
251 {
252     // Check this is a VIDEOINFO type
253
254     if (*pmt->FormatType() != FORMAT_VideoInfo)
255     {
256         return E_INVALIDARG;
257     }
258
259     VIDEOINFO* vi = (VIDEOINFO*)pmt->Format();
260     if(vi->bmiHeader.biBitCount != 24)
261     {
262         return E_INVALIDARG;
263     }
264
265     return NOERROR;
266 }
267
268 CFactoryTemplate g_Templates[]=
269
270 {
271     { L"SyncFilter"
272             , &CLSID_SyncFilter
273             , SyncFilter::CreateInstance  // function called by class factory
274             , NULL
275             , &sudMyFilter }     // address of the AMOVIESETUP_FILTER structure,
276                                  //   or NULL if no structure exists
277 };
278
279 int g_cTemplates = sizeof(g_Templates)/sizeof(g_Templates[0]);
280
281 //
282 // DllRegisterServer
283 //
284 // Handle registration of this filter
285 //
286 STDAPI DllRegisterServer()
287 {
288     return AMovieDllRegisterServer2( TRUE );
289
290 } // DllRegisterServer
291
292 //
293 // DllUnregisterServer
294 //
295 STDAPI DllUnregisterServer()
296 {
297    return AMovieDllRegisterServer2( FALSE );
298
299 } // DllUnregisterServer
300
301 SyncFilter::~SyncFilter()
302 {
303     for (int i=0;i<4;i++)
304     {
305         delete m_ip[i];
306         delete m_op[i];
307     }
308 }
309
310 HRESULT cvSyncInputPin::BeginFlush()
311 {
312     CAutoLock lock_it(m_pLock);
313     HRESULT hr = NOERROR;
314     hr = m_op->DeliverBeginFlush();
315     if (FAILED(hr))
316         return hr;
317
318     return CBaseInputPin::BeginFlush();
319 }
320
321 HRESULT cvSyncInputPin::BreakConnect()
322 {
323     // Release any allocator that we are holding
324
325     if(m_pAllocator)
326     {
327         m_pAllocator->Release();
328
329         m_pAllocator = NULL;
330     }
331
332     return NOERROR;
333 }
334
335 HRESULT cvSyncInputPin::CompleteConnect(IPin *pReceivePin)
336 {
337     HRESULT hr = CBaseInputPin::CompleteConnect(pReceivePin);
338
339     if (FAILED(hr))
340     {
341         return hr;
342     }
343
344     if (m_op->m_Connected != NULL)
345     {
346         if (m_mt != m_op->m_mt)
347             m_pFilter->ReconnectPin(m_op, &m_mt);
348     }
349     else
350     {
351         m_op->m_mt = m_mt;
352     }
353
354     m_Connected->QueryInterface(IID_IAMStreamConfig,(void**)&m_pVSC);
355
356     if(!(m_pVSC.is_valid()))
357         return E_UNEXPECTED;
358
359     return S_OK;
360 }
361
362 HRESULT cvSyncInputPin::EndFlush()
363 {
364     CAutoLock lock_it(m_pLock);
365     HRESULT hr = NOERROR;
366     hr = m_op->DeliverEndFlush();
367     if (FAILED(hr))
368         return hr;
369
370     return CBaseInputPin::EndFlush();
371 }
372
373 HRESULT cvSyncInputPin::EndOfStream()
374 {
375     CAutoLock lock_it(m_pLock);
376     HRESULT hr = NOERROR;
377
378     hr = m_op->DeliverEndOfStream();
379     if (FAILED(hr))
380         return hr;
381
382     return(NOERROR);
383 }
384
385 HRESULT cvSyncInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
386 {
387     CAutoLock lock_it(m_pLock);
388     HRESULT hr = NOERROR;
389     hr = m_op->DeliverNewSegment(tStart, tStop, dRate);
390     if (FAILED(hr))
391         return hr;
392     return CBaseInputPin::NewSegment(tStart, tStop, dRate);
393 }
394
395 STDMETHODIMP cvSyncInputPin::Receive(IMediaSample *pSample)
396 {
397     CAutoLock lock_it(m_pLock);
398
399     // Check that all is well with the base class
400
401     if(m_pSample.value() == NULL)
402     {
403         m_pSample = pSample;
404         m_pSample->AddRef();
405     }
406
407     HRESULT hr = NOERROR;
408
409     hr = CBaseInputPin::Receive(pSample);
410
411     if (hr != NOERROR)
412         return hr;
413
414     m_pFilter->Receive();
415
416     return NOERROR;
417 }
418
419 STDMETHODIMP cvSyncInputPin::NotifyAllocator(IMemAllocator *pAllocator, BOOL bReadOnly)
420 {
421     CAutoLock lock_it(m_pLock);
422     if (pAllocator == NULL)
423         return E_FAIL;
424
425     // Free the old allocator if any
426     if(m_pAllocator)
427     {
428         m_pAllocator->Release();
429         m_pAllocator = NULL;
430     }
431
432     // Store away the new allocator
433
434     pAllocator->AddRef();
435     m_pAllocator = pAllocator;
436
437     // Notify the base class about the allocator
438     return CBaseInputPin::NotifyAllocator(pAllocator,bReadOnly);
439 }
440
441 HRESULT cvSyncOutputPin::Active()
442 {
443     CAutoLock lock_it(m_pLock);
444     //CAutoLock lock_it_to(m_ip->m_pFilter->m_pLock);
445     HRESULT hr = NOERROR;
446
447     // Make sure that the pin is connected
448     if (m_Connected == NULL)
449         return NOERROR;
450
451     // Create the output queue if we have to
452     if ((!(HIWORD(m_pOutputQueue))||(LOWORD(m_pOutputQueue))))
453     {
454
455         m_pOutputQueue = new COutputQueue(m_Connected, &hr, TRUE, FALSE);
456         if (m_pOutputQueue == NULL)
457             return E_OUTOFMEMORY;
458
459         // Make sure that the constructor did not return any error
460         if (FAILED(hr))
461         {
462             delete m_pOutputQueue;
463             m_pOutputQueue = NULL;
464             return hr;
465         }
466     }
467
468     // Pass the call on to the base class
469     CBaseOutputPin::Active();
470     return NOERROR;
471 }
472
473 HRESULT cvSyncOutputPin::CompleteConnect(IPin *pReceivePin)
474 {
475     CAutoLock lock_it(m_pLock);
476     ASSERT(m_Connected == pReceivePin);
477     HRESULT hr = NOERROR;
478
479     hr = CBaseOutputPin::CompleteConnect(pReceivePin);
480     if (FAILED(hr))
481         return hr;
482
483     // If the type is not the same as that stored for the input
484     // pin then force the input pins peer to be reconnected
485
486     if (m_mt != m_ip->m_mt)
487     {
488         hr = m_ip->m_pFilter->ReconnectPin(m_ip->m_Connected, &m_mt);
489
490         if(FAILED(hr))
491         {
492             return hr;
493         }
494     }
495
496     return NOERROR;
497 }
498
499 HRESULT cvSyncOutputPin::DecideAllocator(IMemInputPin *pPin, IMemAllocator **ppAlloc)
500 {
501     *ppAlloc = NULL;
502
503     // Tell the pin about our allocator, set by the input pin.
504     HRESULT hr = NOERROR;
505     hr = pPin->NotifyAllocator(m_ip->m_pAllocator,FALSE);
506     if (FAILED(hr))
507         return hr;
508
509     // Return the allocator
510     *ppAlloc = m_ip->m_pAllocator;
511     m_ip->m_pAllocator->AddRef();
512     return NOERROR;
513 }
514
515 HRESULT cvSyncOutputPin::Deliver(IMediaSample *pMediaSample)
516 {
517     CAutoLock lock_it(m_pLock);
518     pMediaSample->AddRef();
519
520     // Make sure that we have an output queue
521     if (!((HIWORD(m_pOutputQueue))&&(LOWORD(m_pOutputQueue))))
522         return NOERROR;
523     //MessageBox(NULL,"we have queue","", MB_OK);
524
525     HRESULT hr =m_pOutputQueue->Receive(pMediaSample);
526
527     return hr;
528 }
529
530 HRESULT cvSyncOutputPin::DeliverBeginFlush()
531 {
532     // Make sure that we have an output queue
533     if (!((HIWORD(m_pOutputQueue))&&(LOWORD(m_pOutputQueue))))
534         return NOERROR;
535
536     m_pOutputQueue->BeginFlush();
537     return NOERROR;
538 }
539
540 HRESULT cvSyncOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
541 {
542     // Make sure that we have an output queue
543     if (!((HIWORD(m_pOutputQueue))&&(LOWORD(m_pOutputQueue))))
544         return NOERROR;
545
546     m_pOutputQueue->NewSegment(tStart, tStop, dRate);
547     return NOERROR;
548 }
549
550 HRESULT cvSyncOutputPin::SetMediaType(const CMediaType *pmt)
551 {
552     // Make sure that we have an input connected
553     if (m_ip->m_Connected == NULL)
554         return VFW_E_NOT_CONNECTED;
555
556     // Make sure that the base class likes it
557     HRESULT hr = NOERROR;
558     hr = CBaseOutputPin::SetMediaType(pmt);
559     if (FAILED(hr))
560         return hr;
561
562     return NOERROR;
563 }
564
565 STDMETHODIMP cvSyncOutputPin::EnumMediaTypes(IEnumMediaTypes **ppEnum)
566 {
567     CAutoLock lock_it(m_pLock);
568     ASSERT(ppEnum);
569
570     // Make sure that we are connected
571     if (m_ip->m_Connected == NULL)
572         return VFW_E_NOT_CONNECTED;
573
574     // We will simply return the enumerator of our input pin's peer
575     return m_ip->m_Connected->EnumMediaTypes(ppEnum);
576
577 }
578
579 HRESULT cvSyncOutputPin::DeliverEndFlush()
580 {
581     // Make sure that we have an output queue
582     if (!((HIWORD(m_pOutputQueue))&&(LOWORD(m_pOutputQueue))))
583         return NOERROR;
584
585     m_pOutputQueue->EndFlush();
586     return NOERROR;
587 }
588
589 HRESULT cvSyncOutputPin::DeliverEndOfStream()
590 {
591     // Make sure that we have an output queue
592     if (!((HIWORD(m_pOutputQueue))&&(LOWORD(m_pOutputQueue))))
593         return NOERROR;
594
595     m_pOutputQueue->EOS();
596
597     return NOERROR;
598 }
599
600 HRESULT cvSyncOutputPin::Inactive()
601 {
602     CAutoLock lock_it(m_pLock);
603     //CAutoLock lock_it_to(m_ip->m_pFilter->m_pLock);
604
605     // Delete the output queus associated with the pin.
606     if ((HIWORD(m_pOutputQueue))&&(LOWORD(m_pOutputQueue)))
607     {
608         //m_pOutputQueue->FreeSamples();
609
610         delete m_pOutputQueue;
611         m_pOutputQueue = NULL;
612     }
613
614     CBaseOutputPin::Inactive();
615
616     return NOERROR;
617 }
618
619 cvSyncInputPin::~cvSyncInputPin()
620 {
621         m_pVSC=NULL;
622 }
623
624 HRESULT SyncFilter::Receive()
625 {
626     CAutoLock lock_it(m_pLock);
627     REFERENCE_TIME te[4], ts[4]; //timestamps
628     static REFERENCE_TIME MediaTime1, MediaTime2 = 1;
629     IMediaSample *pims[4];
630     HRESULT hr = NOERROR;
631     int i;
632
633     for (i=0;i<m_NbConnected;i++)
634         if(!m_ip[i]->m_pSample.is_valid())
635             return NOERROR;
636
637     for (i=0;i<m_NbConnected;i++)
638     {
639         hr = m_ip[i]->m_pSample->GetTime(&ts[i], &te[i]);
640
641         if FAILED(hr)
642         {
643             m_ip[i]->m_pSample=NULL;
644             return hr;
645         }
646     }
647
648     for (i=0;i<m_NbConnected;i++)
649     {
650         hr = m_ip[i]->m_pSample->SetMediaTime(&MediaTime1,&MediaTime2);
651         if FAILED(hr)
652         {
653             m_ip[i]->m_pSample=NULL;
654             return hr;
655         }
656     }
657
658     for (i=0;i<m_NbConnected;i++)
659         pims[i]=m_ip[i]->m_pSample.value();
660     Transform(pims);
661
662     for (i=0;i<m_NbConnected;i++)
663     {
664         hr = m_op[i]->Deliver(m_ip[i]->m_pSample.value());
665         if(FAILED(hr))
666             m_ip[i]->m_pSample = NULL;
667     }
668
669     MediaTime1++;
670     MediaTime2++;
671
672     for (i=0;i<m_NbConnected;i++)
673         m_ip[i]->m_pSample = NULL;
674
675     return NOERROR;
676 }
677
678 STDMETHODIMP SyncFilter::Stop()
679 {
680     CAutoLock lock_it(m_pLock);
681
682     CBaseFilter::Stop();
683     m_State = State_Stopped;
684
685     return NOERROR;
686 }
687
688 STDMETHODIMP SyncFilter::Pause()
689 {
690     CAutoLock cObjectLock(m_pLock);
691     HRESULT hr = CBaseFilter::Pause();
692     bool NotConnected=false;
693     int i;
694
695     for (i=0;i<m_NbConnected;i++)
696         if (m_ip[i]->IsConnected() == FALSE)
697         {
698             NotConnected=true;
699             break;
700         }
701
702     if (NotConnected)
703         for (i=0;i<m_NbConnected;i++)
704             m_ip[0]->EndOfStream();
705
706     for (i=0;i<m_NbConnected;i++)
707         m_ip[i]->m_pSample = NULL;
708
709     return hr;
710 }
711
712 STDMETHODIMP SyncFilter::Run(REFERENCE_TIME tStart)
713 {
714     CAutoLock cObjectLock(m_pLock);
715     HRESULT hr = CBaseFilter::Run(tStart);
716     bool NotConnected=false;
717     int i;
718
719     for (i=0;i<m_NbConnected;i++)
720         if (m_ip[i]->IsConnected() == FALSE)
721         {
722             NotConnected=true;
723             break;
724         }
725
726     if (NotConnected)
727         for (i=0;i<m_NbConnected;i++)
728             m_ip[0]->EndOfStream();
729
730     return hr;
731 }
732
733 HRESULT cvSyncInputPin::Inactive()
734 {
735     m_pSample = NULL;
736
737     return CBaseInputPin::Inactive();
738 }
739
740 STDMETHODIMP SyncFilter::SetCallBack(void (__cdecl *func)(void *,void *))
741 {
742     return SetCallBack2(func);
743 }
744
745 STDMETHODIMP SyncFilter::SetCallBack2(void (__cdecl *func)(void *,void *))
746 {
747     m_callback2 = func;
748     m_NbConnected=2;
749     return S_OK;
750 }
751
752 STDMETHODIMP SyncFilter::SetCallBack3(void (__cdecl *func)(void *,void *,void *))
753 {
754     m_callback3 = func;
755     m_NbConnected=3;
756     return S_OK;
757 }
758
759 STDMETHODIMP SyncFilter::SetCallBack4(void (__cdecl *func)(void *,void *,void *,void *))
760 {
761     m_callback4 = func;
762     m_NbConnected=4;
763     return S_OK;
764 }
765
766 STDMETHODIMP SyncFilter::NonDelegatingQueryInterface(REFIID riid, void **ppv)
767 {
768     CheckPointer(ppv,E_POINTER);
769
770     if (riid == IID_ISyncFilter)
771     {
772         return GetInterface((ISyncFilter *) this, ppv);
773     }
774     else
775     {
776         return CBaseFilter::NonDelegatingQueryInterface(riid, ppv);
777     }
778 }
779
780 HRESULT SyncFilter::Transform(IMediaSample *pims[4])
781 {
782     BYTE*    pData[4];
783     IplImage image[4];
784     AM_MEDIA_TYPE* pType[4];
785     VIDEOINFOHEADER *pvi[4];
786     int cxImage[4];
787     int cyImage[4];
788     int stride[4];
789
790     for (int i=0;i<m_NbConnected;i++)
791     {
792         pims[i]->GetPointer(&pData[i]);
793         pType[i] = &m_ip[i]->m_mt;
794         pvi[i] = (VIDEOINFOHEADER *) pType[i]->pbFormat;
795
796         if (pvi[i]->bmiHeader.biBitCount != 24)
797             return NOERROR;
798
799         cxImage[i]    = pvi[i]->bmiHeader.biWidth;
800         cyImage[i]    = abs(pvi[i]->bmiHeader.biHeight);
801         stride[i]     = (cxImage[i] * sizeof( RGBTRIPLE ) + 3) & -4;
802
803         cvInitImageHeader( &image[i], cvSize(cxImage[i], cyImage[i]), 8, 3, IPL_ORIGIN_BL, 4 );
804         image[i].widthStep = stride[i];
805
806         cvSetImageData( &image[i], pData[i], stride[i] );
807     }
808
809     if (2==m_NbConnected)
810         m_callback2(&image[0], &image[1]);
811     else if (3==m_NbConnected)
812         m_callback3(&image[0], &image[1], &image[2]);
813     else if (4==m_NbConnected)
814         m_callback4(&image[0], &image[1], &image[2], &image[3]);
815
816     return S_OK;
817 }