Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
DShowVideo.cpp
1 #include "DShowVideo.hh"
2 #include <BIAS_DeclSpec.hh>
3 #include <Base/Debug/Exception.hh>
4 #include "SampleGrabberCallback.hh"
5 #include <Base/Debug/Debug.hh>
6 //#include <Base/Helper.hh>
7 
8 
9 
10 #ifdef BIAS_HAVE_DSHOW
11 # include <windows.h>
12 # include <atlbase.h>
13 # include <dshow.h>
14 ////see: http://social.msdn.microsoft.com/Forums/en-US/windowssdk/thread/ed097d2c-3d68-4f48-8448-277eaaf68252/
15 //# pragma include_alias( "dxtrans.h", "qedit.h" )
16 # define __IDxtCompositor_INTERFACE_DEFINED__
17 # define __IDxtAlphaSetter_INTERFACE_DEFINED__
18 # define __IDxtJpeg_INTERFACE_DEFINED__
19 # define __IDxtKey_INTERFACE_DEFINED__
20 # include <qedit.h>
21 
22 #endif
23 
24 namespace BIAS
25 {
26  class DShowStuff {
27  public:
28  DShowStuff(){};
29  ~DShowStuff(){};
30 #ifdef BIAS_HAVE_DSHOW
31  CComPtr< IMediaControl > pMediaControl_;
32  CComPtr< IMediaEventEx > pMediaEvent_;
33  CComPtr< IMediaSeeking > pMediaSeeking_;
34  CComPtr< ISampleGrabber > pSampleGrabber_;
35  CComPtr< IVideoFrameStep> pVideoFrameStep_; //test
36  CComPtr< IMediaFilter> pMediaFilter_;
37  CComPtr< IBaseFilter > pNullRenderer_; //stepping doesnt seem to work with nullrenderer
38  CComPtr< IGraphBuilder > pGraphBuilder_;
39  CComPtr< IBaseFilter > pSrcFilter_ ;
40  CComPtr< IPin > pSrcOutPin_;
41  CComPtr< IPin > pSampleGrabberOutPin_;
42  CComPtr< IPin > pSampleGrabberInPin_;
43  CComPtr< IPin > pNullRendererInPin_;
44 #endif
45  };
46 }
47 
48 using namespace BIAS;
49 using namespace std;
50 
51 #define RAISE(arg)\
52  { \
53  cout << "exception: " << arg << endl; \
54  throw BaseException(arg);\
55  }
56 #define CHECK_HR(hr,msg) { if (hr!=S_OK) { RAISE(msg); } }
57 
60 {
61  SGCB_ = sgcb;
62  DShowStuff_ = new DShowStuff;
63  Initialised_ = false;
64  Open_ = false;
65  FrameNum_ = 0;
66  IsRunning_ = false;
67  IsPaused_ = false;
68  FastNLazy_ = true; //TODO set to true as default
69  Width_ = Height_ = ChannelCount_ = 0;
70 }
71 
72 
75 {
76  Close();
77  if (Initialised_){
78 #ifdef BIAS_HAVE_DSHOW
79  CoUninitialize();
80 #endif
81  }
82 }
83 
84 bool DShowVideo::
86 {
87 #ifdef BIAS_HAVE_DSHOW
88  //sample code
89  //http://www.codeproject.com/KB/audio-video/framegrabber.aspx?fid=2584&df=90&mpp=25&noise=3&sort=Position&view=Quick&fr=101&select=193093
90  //und
91  //BIAS::VideoSource_Dshow
92 
93  if (!Initialised_){
94  // cout<<"DShowVideo::initializing"<<endl;
95  HRESULT hr; // initialize the COM library.
96  CoInitialize(0);
97  // Get DirectShow interfaces
98  // hr = GetInterfaces_();
99  //------------------------------
100  // Create the filter graph
101  hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
102  IID_IGraphBuilder,
103  (void **) &DShowStuff_->pGraphBuilder_);
104  CHECK_HR(hr,"CoCreateInstance GraphBuilder failed");
105 
106  // Obtain interfaces for media control and Video Window
107  hr = DShowStuff_->pGraphBuilder_->QueryInterface(IID_IMediaControl,
108  (LPVOID *) &DShowStuff_->pMediaControl_);
109  CHECK_HR(hr,"QueryInterface MediaControl failed");
110 
111 
112  hr = DShowStuff_->pGraphBuilder_->QueryInterface(IID_IMediaFilter,
113  (LPVOID *) &DShowStuff_->pMediaFilter_);
114  CHECK_HR(hr,"QueryInterface IMediaFilter failed");
115 
116 
117  //use IMediaSeeking for positioning
118 
119  hr = DShowStuff_->pGraphBuilder_->QueryInterface(IID_IMediaSeeking,
120  (LPVOID *) &DShowStuff_->pMediaSeeking_);
121  CHECK_HR(hr,"QueryInterface MediaSeeking failed");
122 
123  hr = DShowStuff_->pGraphBuilder_->QueryInterface(IID_IMediaEvent,
124  (LPVOID *) &DShowStuff_->pMediaEvent_);
125  CHECK_HR(hr,"QueryInterface MediaEvent failed");
126 
127  // Create NullRenderer Instance
128  hr = DShowStuff_->pNullRenderer_.CoCreateInstance(CLSID_NullRenderer);
129  CHECK_HR(hr,"CoCreateInstance NullRenderer failed");
130  hr = DShowStuff_->pGraphBuilder_->AddFilter(DShowStuff_->pNullRenderer_,
131  L"NullRenderer");
132  CHECK_HR(hr,"AddFilter(NullRenderer) failed");
133 
134  // Create SampleGrabber Instance and register callback for each frame
135  hr = DShowStuff_->pSampleGrabber_.CoCreateInstance(CLSID_SampleGrabber);
136  CHECK_HR(hr,"CoCreateInstance SampleGrabber failed");
137  {
138  CComQIPtr< IBaseFilter, &IID_IBaseFilter >
139  pGrabberBase( DShowStuff_->pSampleGrabber_ );
140  hr = DShowStuff_->pGraphBuilder_->AddFilter(pGrabberBase,L"SampleGrabber");
141  CHECK_HR(hr,"AddFilter(NullRenderer) failed");
142  pGrabberBase.Release();
143  }
144  // configure SampleGrabber
145  hr = DShowStuff_->pSampleGrabber_->SetBufferSamples(false);
146  CHECK_HR(hr,"SetBufferSample failed");
147  hr = DShowStuff_->pSampleGrabber_->SetOneShot(false); //was false
148  CHECK_HR(hr,"SetOneShot failed");
149  // TODO register callback
150  DShowStuff_->pSampleGrabber_->SetCallback(SGCB_,0);
151 
152  //
153  // can not connect OutPin of SampleGrabber with InPin of
154  // NullRenderer here First, they have to be configured according to
155  // media type of pSrcFilter which is creatd in Open()
156 
157  AM_MEDIA_TYPE mt;
158  ZeroMemory(&mt,sizeof(AM_MEDIA_TYPE));
159  mt.majortype = MEDIATYPE_Video;
160  mt.subtype = MEDIASUBTYPE_RGB24;
161  mt.formattype = FORMAT_VideoInfo;
162  hr = DShowStuff_->pSampleGrabber_->SetMediaType(&mt);
163  CHECK_HR(hr,"SetMediaType failed");
164  Initialised_ = true;
165  } else {
166  // this should not happen
167  }
168 #endif
169 
170  return true;
171 }
172 
173 
174 
175 bool DShowVideo::
176 Open(const string &filename)
177 {
178  cout<<"opening avi "<<filename<<endl;
179  Init_();
180 
181 #ifdef BIAS_HAVE_DSHOW
182  HRESULT hr;
183 
184  int length = MultiByteToWideChar(CP_ACP,0,filename.c_str() ,
185  filename.size()+1,NULL,0);
186  LPWSTR wc_filename = new WCHAR[length];
187  MultiByteToWideChar(CP_ACP,0,filename.c_str() ,filename.size()+1,
188  wc_filename,length);
189 
190  // Automatically generate graph nodes to decode file
191  hr = DShowStuff_->pGraphBuilder_->AddSourceFilter(wc_filename,L"SourceFilter",
192  &DShowStuff_->pSrcFilter_);
193  CHECK_HR(hr,"AddSourceFilter failed");
194 
195  // connect first out-pin of SrcFilter with in-pin of SampleGrabber
196  CComQIPtr< IBaseFilter, &IID_IBaseFilter > pGrabberBase( DShowStuff_->pSampleGrabber_ );
197  hr = pGrabberBase->FindPin(L"In",&DShowStuff_->pSampleGrabberInPin_);
198  CHECK_HR(hr,"Failed to find in-pin of SampleGrabber");
199 
200  IEnumPins *pEnum = NULL;
201  IPin *pPin = NULL;
202  hr = DShowStuff_->pSrcFilter_->EnumPins(&pEnum);
203  CHECK_HR(hr,"EnumPins failed on SrcFilter");
204  while(pEnum->Next(1, &pPin, 0) == S_OK) {
205  PIN_DIRECTION PinDirThis;
206  hr = pPin->QueryDirection(&PinDirThis);
207  if (FAILED(hr)) {
208  pPin->Release();
209  pEnum->Release();
210  pGrabberBase.Release();
211  return false;
212  }
213  LPWSTR pinName;
214  pPin->QueryId(&pinName);
215  if (PINDIR_OUTPUT == PinDirThis) {
216  DShowStuff_->pSrcOutPin_ = pPin;
217  pPin->Release();
218  break;
219  }
220  // Release the pin for the next time through the loop.
221  pPin->Release();
222  }
223  pEnum->Release();
224 
225  hr = DShowStuff_->pGraphBuilder_->Connect(DShowStuff_->pSrcOutPin_,
226  DShowStuff_->pSampleGrabberInPin_);
227  CHECK_HR(hr,"Failed to connect SrcFilter with SampleGrabber");
228  //cout<<"Succesfully connected SrcFilter and SampleGrabber Pins" << endl;
229 
230  // connect out-pin of SampleGrabber with in-pin of NullRenderer
231  hr = pGrabberBase->FindPin(L"Out",&DShowStuff_->pSampleGrabberOutPin_);
232  CHECK_HR(hr,"Failed to find out-pin of SampleGrabber");
233 
234  hr = DShowStuff_->pNullRenderer_->FindPin(L"In",
235  &DShowStuff_->pNullRendererInPin_);
236  CHECK_HR(hr,"Failed to find out-pin of SampleGrabber");
237 
238  hr = DShowStuff_->pGraphBuilder_->Connect(DShowStuff_->pSampleGrabberOutPin_,
239  DShowStuff_->pNullRendererInPin_);
240  CHECK_HR(hr,"Failed to connect SampleGrabber with NullRenderer");
241  //cout<<"Succesfully connected SampleGrabber and NullRenderer Pins" << endl;
242 
243  AM_MEDIA_TYPE MediaType;
244  ZeroMemory(&MediaType,sizeof(MediaType));
245  hr = DShowStuff_->pSampleGrabber_->GetConnectedMediaType(&MediaType);
246  CHECK_HR(hr,"GetConnectedMediaType failed");
247 
248  // Get a pointer to the video header.
249  VIDEOINFOHEADER *pVideoHeader = (VIDEOINFOHEADER*)MediaType.pbFormat;
250  if (pVideoHeader == NULL) {
251  pGrabberBase.Release();
252  return false;
253  }
254  // The video header contains the bitmap information.
255 
256  // Copy it into a BITMAPINFO structure.
257  BITMAPINFO BitmapInfo;
258  ZeroMemory(&BitmapInfo, sizeof(BitmapInfo));
259  CopyMemory(&BitmapInfo.bmiHeader, &(pVideoHeader->bmiHeader),
260  sizeof(BITMAPINFOHEADER));
261 
262  Width_ = BitmapInfo.bmiHeader.biWidth;
263  Height_ = BitmapInfo.bmiHeader.biHeight;
264  ChannelCount_ = BitmapInfo.bmiHeader.biBitCount/8;
265 
266  DShowStuff_->pMediaSeeking_->SetTimeFormat(&TIME_FORMAT_FRAME);
267  DShowStuff_->pMediaSeeking_->SetRate(128);
268  DShowStuff_->pSrcFilter_->SetSyncSource(NULL); //<-------------------
269  pGrabberBase->SetSyncSource(NULL);
270  pGrabberBase.Release();
271  DShowStuff_->pNullRenderer_->SetSyncSource(NULL);
272  //render as fast as possible dont sync graph
273  DShowStuff_->pMediaFilter_->SetSyncSource(NULL);
274 
275  long long currentPos,stopPos;
276  currentPos=0;
277  stopPos = 1;
278  DShowStuff_->pMediaSeeking_->SetPositions(&currentPos,
279  AM_SEEKING_AbsolutePositioning,
280  &stopPos,
281  AM_SEEKING_AbsolutePositioning );
282 
283  DShowStuff_->pMediaControl_->Pause();
284 #endif
285  Open_ = true;
286  IsRunning_ = false;
287  IsPaused_ = false;
288  FrameNum_=0;
289  return true;
290 }
291 
292 
293 void DShowVideo::
295 {
296  //cout << "frame "<<FrameNum_<<" requested\n";
297 
298 #ifdef BIAS_HAVE_DSHOW
299  long long currentPos,stopPos;
300  currentPos=FrameNum_;
301  stopPos = currentPos;
302  DShowStuff_->pMediaSeeking_->SetPositions(&currentPos,AM_SEEKING_AbsolutePositioning,
303  &stopPos,AM_SEEKING_AbsolutePositioning );
304 
305  SGCB_->SampleTriggerArm();
306  DShowStuff_->pMediaControl_->Run();
307  //while(DShowStuff_->pMediaControl_->Run()!=S_OK){USleep(2000);}; //ignore the result....
308  //OAFilterState fs;
309  //DShowStuff_->pMediaControl_->GetState(4 /*msecs timout*/, &fs);
310 
311  if (SGCB_->HasCallbackFunction()){
312  FrameNum_++;
313  return;
314  }
315 
316  unsigned timeoutcount=0; //counts loops without sampletrigger signal
317  unsigned paniclevel =0; //counter timeouts in nonfastnlazymode.
318  while (!SGCB_->SampleTriggered()) //wait until grabbercallback has been executed
319  {
320  Sleep(1000/1000);
321  timeoutcount++;
322  if(timeoutcount>30) //samplegrabbercallback timed out
323  {
324  //cout<<"sampling failed"<<endl;
325  if(FastNLazy_)
326  {
327  return; //timeout suggests that play has failed for some reason
328  }
329  else
330  {
331  timeoutcount = 0; //resest timeout counter
332  if(paniclevel>100) //read avi really really failed! we are doomed!
333  {
334  cout<<"avi read panic!"<<endl;
335  //TODO throw exception
336  return;
337  }
338  //retry reading
339  //cout<<"retrying"<<endl;
340  DShowStuff_->pMediaSeeking_->
341  SetPositions(&currentPos,AM_SEEKING_AbsolutePositioning,
342  &stopPos,AM_SEEKING_AbsolutePositioning );
343  DShowStuff_->pMediaControl_->Run();
344  paniclevel++;
345  }
346  }
347  }
348 
349  FrameNum_++;
350 #endif
351 
352 }
353 
354 void DShowVideo::
356 {
357 #ifdef BIAS_HAVE_DSHOW
358  HRESULT hr;
359  int tries = 0;
360  do {
361  hr = DShowStuff_->pMediaControl_->Run();
362  tries++;
363  if (hr != S_OK) Sleep(10);
364  else IsRunning_ = true;
365  } while (hr != S_OK && tries <10);
366 
367  CHECK_HR(hr,"DirectShow Run failed");
368 #endif
369 }
370 
371 
372 
373 void DShowVideo::
375 {
376  //cout <<"ReadAvi::Pause()"<<endl;
377 #ifdef BIAS_HAVE_DSHOW
378  HRESULT hr;
379  int tries = 0;
380  do {
381  hr = DShowStuff_->pMediaControl_->Stop();
382  tries++;
383  if (hr != S_OK) Sleep(1);
384  else IsRunning_ = true;
385  } while (hr != S_OK && tries <10);
386  CHECK_HR(hr,"Stop failed");
387  IsPaused_ = true;
388  long evCode;
389  hr = DShowStuff_->pMediaEvent_->WaitForCompletion(INFINITE, &evCode);
390  CHECK_HR(hr,"WaitForCompletion failed");
391 #endif
392 
393 }
394 
395 void DShowVideo::
396 GotoFrame(unsigned long long frameNo)
397 {
398 #ifdef BIAS_HAVE_DSHOW
399  //HRESULT hr;
400  int tries=0;
401  // TODO check pMedisControl for running
402  FrameNum_ = frameNo;
403  //do {
404  // hr = DShowStuff_->pMediaControl_->Stop();
405  // tries++;
406  // if (hr != S_OK) Sleep(1);
407  // else IsRunning_ = true;
408  // } while (hr != S_OK && tries <10);
409  // CHECK_HR(hr,"Stop failed");
410  // long long seekPos = frameNo;
411  // DShowStuff_->pMediaSeeking_->SetPositions(&seekPos,AM_SEEKING_AbsolutePositioning,
412  // NULL, AM_SEEKING_NoPositioning);
413 #endif
414 }
415 
416 
417 void DShowVideo::
419 {
420  if (Open_ && DShowStuff_) {
421 #ifdef BIAS_HAVE_DSHOW
422  HRESULT hr;
423  cout << "ReadAvi::Close()\n";
424  // Release all COM objects
425  if (DShowStuff_->pMediaControl_) {
426  DShowStuff_->pMediaControl_->Stop();
427  }
428  if (DShowStuff_->pGraphBuilder_){
429  // Automagically generate graph nodes to decode file
430  if (DShowStuff_->pSrcFilter_){
431  hr = DShowStuff_->pGraphBuilder_->
432  RemoveFilter(DShowStuff_->pSrcFilter_);
433  CHECK_HR(hr,"RemoveFilter failed");
434  }
435  if (DShowStuff_->pNullRenderer_){
436  hr = DShowStuff_->pGraphBuilder_->
437  RemoveFilter(DShowStuff_->pNullRenderer_);
438  CHECK_HR(hr,"RemoveFilter failed");
439  }
440  if (DShowStuff_->pSampleGrabber_){
441  CComQIPtr< IBaseFilter, &IID_IBaseFilter >
442  pGrabberBase( DShowStuff_->pSampleGrabber_ );
443  hr = DShowStuff_->pGraphBuilder_->RemoveFilter(pGrabberBase);
444  CHECK_HR(hr,"RemoveFilter failed");
445  pGrabberBase.Release();
446  }
447  }
448 
449  if (DShowStuff_->pMediaControl_){
450  DShowStuff_->pMediaControl_.Release();
451  }
452  if (DShowStuff_->pMediaEvent_){
453  DShowStuff_->pMediaEvent_.Release();
454  }
455  if (DShowStuff_->pMediaSeeking_){
456  DShowStuff_->pMediaSeeking_.Release();
457  }
458  if (DShowStuff_->pSrcOutPin_){
459  DShowStuff_->pSrcOutPin_.Release();
460  }
461  if (DShowStuff_->pSampleGrabberInPin_){
462  DShowStuff_->pSampleGrabberInPin_.Release();
463  }
464  if (DShowStuff_->pSampleGrabberOutPin_){
465  DShowStuff_->pSampleGrabberOutPin_.Release();
466  }
467  if (DShowStuff_->pNullRendererInPin_){
468  DShowStuff_->pNullRendererInPin_.Release();
469  }
470  if (DShowStuff_->pSrcFilter_){
471  DShowStuff_->pSrcFilter_.Release();
472  }
473  if (DShowStuff_->pSampleGrabber_){
474  DShowStuff_->pSampleGrabber_.Release();
475  }
476  if (DShowStuff_->pNullRenderer_){
477  DShowStuff_->pNullRenderer_.Release();
478  }
479  if (DShowStuff_->pMediaFilter_){
480  DShowStuff_->pMediaFilter_.Release();
481  }
482  if (DShowStuff_->pGraphBuilder_){
483  DShowStuff_->pGraphBuilder_.Release();
484  }
485 
486 #endif
487  Open_ = false;
488  Width_ = Height_ = ChannelCount_ = 0;
489  }
490 }
491 
492 bool DShowVideo::
493 GetImageSize(unsigned &width, unsigned &height,
494  unsigned &channel_count)
495 {
496  if (Width_==0 || Height_==0 || ChannelCount_==0) { return false; }
497  width = Width_;
498  height = Height_;
499  channel_count = ChannelCount_;
500  return true;
501 }
void GotoFrame(unsigned long long frameNo)
Definition: DShowVideo.cpp:396
bool Open(const std::string &filename)
open file, if not possible throw exception
Definition: DShowVideo.cpp:176
void PlayContinously()
Definition: DShowVideo.cpp:355
DShowVideo(SampleGrabberCallback *sgcb)
Definition: DShowVideo.cpp:59
bool GetImageSize(unsigned &width, unsigned &height, unsigned &channel_count)
returns the image size contained in the stream, only meaningfull results after call to Open() functio...
Definition: DShowVideo.cpp:493
sample grabber callback class for grabbing single frames only
void PlaySingleFrame()
Definition: DShowVideo.cpp:294