Avionics
Dropship Simulator
Webcam.cpp
Go to the documentation of this file.
1 #include "Webcam.h"
2 
3 #include <Shlwapi.h>
4 
5 namespace Devices
6 {
8  {
9  initialized = false;
10 
11  videoDevices = nullptr;
12  audioDevices = nullptr;
13 
14  pVideoActivate = nullptr;
15  pAudioActivate = nullptr;
16 
17  pVideoSource = nullptr;
18  pAudioSource = nullptr;
19  pSource = nullptr;
20 
21  m_pReader = nullptr;
22  m_pWriter = nullptr;
23 
24  InitializeCriticalSection(&m_critsec);
25  }
26 
28  {
29  DeleteCriticalSection(&m_critsec);
30  }
31 
32  ULONG Webcam::AddRef()
33  {
34  return InterlockedIncrement(&m_nRefCount);
35  }
36 
37  ULONG Webcam::Release()
38  {
39  ULONG uCount = InterlockedDecrement(&m_nRefCount);
40  if (uCount == 0)
41  {
42  //delete this;
43  }
44  return uCount;
45  }
46 
47  HRESULT Webcam::QueryInterface(REFIID riid, void** ppv)
48  {
49  static const QITAB qit[] = {QITABENT(Webcam, IMFSourceReaderCallback),{nullptr},};
50  return QISearch(this, qit, riid, ppv);
51  }
52 
53  HRESULT Webcam::OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWORD dwStreamFlags, LONGLONG llTimeStamp, IMFSample* pSample)
54  {
55  EnterCriticalSection(&m_critsec);
56 
57  if (!IsCapturing())
58  {
59  LeaveCriticalSection(&m_critsec);
60  return S_OK;
61  }
62 
63  HRESULT hr = S_OK;
64 
65  if (FAILED(hrStatus))
66  {
67  hr = hrStatus;
68  goto done;
69  }
70 
71  if (dwStreamIndex == 0)
72  {
73  if (pSample)
74  {
76  {
77  m_llVideoBaseTime = llTimeStamp;
78  m_bVideoFirstSample = FALSE;
79  }
80 
81  // rebase the time stamp
82  llTimeStamp -= m_llVideoBaseTime;
83 
84  hr = pSample->SetSampleTime(llTimeStamp);
85 
86  if (FAILED(hr))
87  {
88  goto done;
89  }
90 
91  hr = m_pWriter->WriteSample(sink_video_stream, pSample);
92 
93  if (FAILED(hr))
94  {
95  goto done;
96  }
97  }
98 
99  // Read another sample.
100  hr = m_pReader->ReadSample(static_cast<DWORD>(MF_SOURCE_READER_ANY_STREAM), 0, nullptr, nullptr, nullptr, nullptr);
101  }
102  else
103  {
104  if (pSample)
105  {
107  {
108  m_llAudioBaseTime = llTimeStamp;
109  m_bAudioFirstSample = FALSE;
110  }
111 
112  // rebase the time stamp
113  llTimeStamp -= m_llAudioBaseTime;
114 
115  hr = pSample->SetSampleTime(llTimeStamp);
116 
117  if (FAILED(hr))
118  {
119  goto done;
120  }
121 
122  hr = m_pWriter->WriteSample(sink_audio_stream, pSample);
123 
124  if (FAILED(hr))
125  {
126  goto done;
127  }
128  }
129 
130  // Read another sample.
131  hr = m_pReader->ReadSample(static_cast<DWORD>(MF_SOURCE_READER_ANY_STREAM), 0, nullptr, nullptr, nullptr, nullptr);
132  }
133 
134  done:
135  LeaveCriticalSection(&m_critsec);
136  return hr;
137  }
138 
139 
140  HRESULT Webcam::CreateAggregatedSource(IMFMediaSource* pSource1, IMFMediaSource* pSource2, IMFMediaSource** ppAggSource) const
141  {
142  *ppAggSource = nullptr;
143 
144  IMFCollection* pCollection = nullptr;
145  HRESULT hr;
146 
147  if (FAILED(hr = MFCreateCollection(&pCollection)))
148  {
149  logger->Log("Webcam::CreateAggregatedSource MFCreateCollection failed!", Logger::Error, hr);
150  return hr;
151  }
152 
153  if (FAILED(hr = pCollection->AddElement(pSource1)))
154  {
155  logger->Log("Webcam::CreateAggregatedSource AddElement video failed!", Logger::Error, hr);
156  return hr;
157  }
158 
159  if (FAILED(hr = pCollection->AddElement(pSource2)))
160  {
161  logger->Log("Webcam::CreateAggregatedSource AddElement audio failed!", Logger::Error, hr);
162  return hr;
163  }
164 
165  if (FAILED(hr = MFCreateAggregateSource(pCollection, ppAggSource)))
166  {
167  logger->Log("Webcam::CreateAggregatedSource MFCreateAggregateSource failed!", Logger::Error, hr);
168  return hr;
169  }
170 
171  SAFE_RELEASE(pCollection);
172  return hr;
173  }
174 
175  HRESULT Webcam::OpenMediaSource(IMFMediaSource* pSource)
176  {
177  IMFAttributes* pAttributes = nullptr;
178  HRESULT hr;
179 
180  if (FAILED(hr = MFCreateAttributes(&pAttributes, 2)))
181  {
182  logger->Log("Webcam::OpenMediaSource MFCreateAttributes failed!", Logger::Error, hr);
183  return hr;
184  }
185 
186  if (FAILED(hr = pAttributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, this)))
187  {
188  logger->Log("Webcam::OpenMediaSource SetUnknown failed!", Logger::Error, hr);
189  SAFE_RELEASE(pAttributes);
190  return hr;
191  }
192 
193  if (FAILED(hr = MFCreateSourceReaderFromMediaSource(pSource, pAttributes, &m_pReader)))
194  {
195  logger->Log("Webcam::OpenMediaSource MFCreateSourceReaderFromMediaSource failed!", Logger::Error, hr);
196  }
197 
198  SAFE_RELEASE(pAttributes);
199  return hr;
200  }
201 
203  {
204  HRESULT hr;
205 
206  IMFMediaType* pVideoNativeMediaType = nullptr;
207  IMFMediaType* pVideoTargetMediaType = nullptr;
208  IMFMediaType* pAudioNativeMediaType = nullptr;
209  IMFMediaType* pAudioTargetMediaType = nullptr;
210 
211 #pragma region Configure Video
212 
213  // Get Native Media Type for Video
214  if (FAILED(hr = m_pReader->GetNativeMediaType(static_cast<DWORD>(MF_SOURCE_READER_FIRST_VIDEO_STREAM), 0, &pVideoNativeMediaType)))
215  {
216  logger->Log("Webcam::ConfigureCapture GetNativeMediaType video failed!", Logger::Error, hr);
217  return hr;
218  }
219 
220  // Create Video Target Media Type
221  if (FAILED(hr = CreateTargetVideoMediaType(pVideoNativeMediaType, &pVideoTargetMediaType)))
222  {
223  logger->Log("Webcam::ConfigureCapture CreateTargetVideoMediaType failed!", Logger::Error, hr);
224  return hr;
225  }
226 
227  // Add Video stream to output file
228  if (FAILED(hr = m_pWriter->AddStream(pVideoTargetMediaType, &sink_video_stream)))
229  {
230  logger->Log("Webcam::ConfigureCapture AddStream video failed!", Logger::Error, hr);
231  return hr;
232  }
233 
234  // Negotiate
236  {
237  logger->Log("Webcam::ConfigureCapture NegotiateVideoStreamFormat failed!", Logger::Error, hr);
238  return hr;
239  }
240 
241 #pragma endregion
242 
243 #pragma region Configure Audio
244 
245  // Get Natvie Media Type for Audio
246  if (FAILED(hr = m_pReader->GetNativeMediaType(static_cast<DWORD>(MF_SOURCE_READER_FIRST_AUDIO_STREAM), 0, &pAudioNativeMediaType)))
247  {
248  logger->Log("Webcam::ConfigureCapture GetNativeMediaType audio failed!", Logger::Error, hr);
249  return hr;
250  }
251 
252  // Create Audio Media Type Target
253  if (FAILED(hr = CreateTargetAudioMediaType(pAudioNativeMediaType, &pAudioTargetMediaType)))
254  {
255  logger->Log("Webcam::ConfigureCapture CreateTargetAudioMediaType failed!", Logger::Error, hr);
256  return hr;
257  }
258 
259  // Add audio stream to output file
260  if (FAILED(hr = m_pWriter->AddStream(pAudioTargetMediaType, &sink_audio_stream)))
261  {
262  logger->Log("Webcam::ConfigureCapture AddStream audio failed!", Logger::Error, hr);
263  return hr;
264  }
265 
266  // Negotiate Audio
268  {
269  logger->Log("Webcam::ConfigureCapture NegotiateAudioStreamFormat failed!", Logger::Error, hr);
270  return hr;
271  }
272 
273 #pragma endregion
274 
275  // Begin writing ------------------------------------------
276  if (FAILED(hr = m_pWriter->BeginWriting()))
277  {
278  logger->Log("Webcam::ConfigureCapture BeginWriting failed!", Logger::Error, hr);
279  return hr;
280  }
281 
282  SAFE_RELEASE(pVideoTargetMediaType);
283  SAFE_RELEASE(pVideoNativeMediaType);
284  SAFE_RELEASE(pAudioTargetMediaType);
285  SAFE_RELEASE(pAudioNativeMediaType);
286 
287  return hr;
288  }
289 
291  HRESULT Webcam::CreateTargetVideoMediaType(__in IMFMediaType* pNativeMediaType, __out IMFMediaType** ppTargetMediaType) const
292  {
293  IMFMediaType* pTargetMediaType = nullptr;
294 
295  UINT32 unWidth = 0;
296  UINT32 unHeight = 0;
297  UINT32 unNumerator;
298  UINT32 unDenominator;
299  UINT32 unAspectX;
300  UINT32 unAspectY;
301  UINT32 unInterlaceMode;
302  UINT32 unBitrate;
303 
304  *ppTargetMediaType = nullptr;
305 
306  HRESULT hr = MFCreateMediaType(&pTargetMediaType);
307  if (SUCCEEDED(hr))
308  {
309  hr = pTargetMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
310  }
311 
312  if (SUCCEEDED(hr))
313  {
314  hr = pTargetMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264);
315  }
316 
317  if (SUCCEEDED(hr))
318  {
319  hr = MFGetAttributeSize(pNativeMediaType, MF_MT_FRAME_SIZE, &unWidth, &unHeight);
320  }
321 
322  if (SUCCEEDED(hr))
323  {
324  char msg[99];
325  sprintf_s(msg, 99, "Webcam::CreateTargetVideoMediaType Native unWidth: %i unHeight: %i", unWidth, unHeight);
326  logger->Log(msg);
327 
328  unWidth = config->width;
329  unHeight = config->height;
330  // hr = MFSetAttributeSize(pNativeMediaType, MF_MT_FRAME_SIZE, unWidth, unHeight);
331  }
332 
333  if (SUCCEEDED(hr))
334  {
335  hr = MFGetAttributeRatio(pNativeMediaType, MF_MT_FRAME_RATE, &unNumerator, &unDenominator);
336  }
337 
338  if (SUCCEEDED(hr))
339  {
340  char msg[99];
341  sprintf_s(msg, 99, "Webcam::CreateTargetVideoMediaType Native unNumerator: %i unDenominator: %i", unNumerator, unDenominator);
342  logger->Log(msg);
343 
344  unNumerator = config->numerator;
345  unDenominator = config->denominator;
346  hr = MFSetAttributeRatio(pNativeMediaType, MF_MT_FRAME_RATE, unNumerator, unDenominator);
347  }
348 
349  if (SUCCEEDED(hr))
350  {
351  hr = MFGetAttributeRatio(pNativeMediaType, MF_MT_PIXEL_ASPECT_RATIO, &unAspectX, &unAspectY);
352  }
353 
354  if (SUCCEEDED(hr))
355  {
356  hr = pNativeMediaType->GetUINT32(MF_MT_INTERLACE_MODE, &unInterlaceMode);
357  char msg[99];
358  sprintf_s(msg, 99, "Webcam::CreateTargetVideoMediaType Native GetUINT32 MF_MT_INTERLACE_MODE: %i", unInterlaceMode);
359  logger->Log(msg);
360  }
361 
362  if (SUCCEEDED(hr))
363  {
364  // unInterlaceMode = MFVideoInterlace_Progressive;
365  // hr = pNativeMediaType->SetUINT32(MF_MT_INTERLACE_MODE, unInterlaceMode);
366  }
367 
368  if (SUCCEEDED(hr))
369  {
370  hr = pNativeMediaType->GetUINT32(MF_MT_AVG_BITRATE, &unBitrate);
371  char msg[99];
372  sprintf_s(msg, 99, "Webcam::CreateTargetVideoMediaType Native unBitrate: %i", unBitrate);
373  logger->Log(msg);
374  }
375 
376  if (SUCCEEDED(hr))
377  {
378  //unBitrate = 5000000; // based on 720p
379  //hr = pNativeMediaType->SetUINT32(MF_MT_AVG_BITRATE, unBitrate);
380  }
381 
382 
383  //Videotypes
384 
385  if (SUCCEEDED(hr))
386  {
387  hr = MFSetAttributeSize(pTargetMediaType, MF_MT_FRAME_SIZE, unWidth, unHeight);
388  }
389 
390  if (SUCCEEDED(hr))
391  {
392  hr = MFSetAttributeRatio(pTargetMediaType, MF_MT_FRAME_RATE, unNumerator, unDenominator);
393  }
394  if (SUCCEEDED(hr))
395  {
396  hr = MFSetAttributeRatio(pTargetMediaType, MF_MT_PIXEL_ASPECT_RATIO, unAspectX, unAspectY);
397  }
398 
399  if (SUCCEEDED(hr))
400  {
401  hr = pTargetMediaType->SetUINT32(MF_MT_INTERLACE_MODE, unInterlaceMode);
402  }
403 
404  if (SUCCEEDED(hr))
405  {
406  hr = pTargetMediaType->SetUINT32(MF_MT_AVG_BITRATE, unBitrate);
407  }
408  *ppTargetMediaType = pTargetMediaType;
409  pTargetMediaType = nullptr;
410 
411  SAFE_RELEASE(pTargetMediaType);
412 
413  return hr;
414  }
415 
417  HRESULT Webcam::CreateTargetAudioMediaType(__in IMFMediaType* pNativeMediaType, __out IMFMediaType** ppTargetMediaType) const
418  {
419  HRESULT hr;
420 
421  IMFMediaType* pTargetMediaType = nullptr;
422  IMFCollection* pAvailableTypes = nullptr;
423  IUnknown* punkObject = nullptr;
424  IMFMediaType* pMediaType = nullptr;
425 
426  DWORD dwAvailableTypes = 0;
427 
428  UINT32 unNumChannels;
429  UINT32 unSampleRate;
430 
431  BOOL fFoundMediaType = FALSE;
432 
433  *ppTargetMediaType = nullptr;
434 
435  // get a list of available media types by subtype
436  // tried hardware encoding filter, no dice... tried transcode_only and it didn't remove any results (32 total)
437  if (FAILED(hr = MFTranscodeGetAudioOutputAvailableTypes(MFAudioFormat_AAC, MFT_ENUM_FLAG_ALL, nullptr, &pAvailableTypes)))
438  {
439  logger->Log("Webcam::CreateTargetAudioMediaType MFTranscodeGetAudioOutputAvailableTypes failed!", Logger::Error, hr);
440  return hr;
441  }
442 
443  if (FAILED(hr = pAvailableTypes->GetElementCount(&dwAvailableTypes)))
444  {
445  logger->Log("Webcam::CreateTargetAudioMediaType GetElementCount failed!", Logger::Error, hr);
446  return hr;
447  }
448 
449  //
450  // loop through the available media types looking for one that
451  // matches the desired number of channels and sampling rate
452  //
453  for (DWORD ii = 0; ii < dwAvailableTypes; ii++)
454  {
455  SAFE_RELEASE(punkObject);
456  SAFE_RELEASE(pMediaType);
457 
458  if (FAILED(hr = pAvailableTypes->GetElement(ii, &punkObject)))
459  {
460  logger->Log("Webcam::CreateTargetAudioMediaType GetElement failed!", Logger::Error, hr);
461  return hr;
462  }
463 
464  if (FAILED(hr = punkObject->QueryInterface(IID_PPV_ARGS(&pMediaType))))
465  {
466  logger->Log("Webcam::CreateTargetAudioMediaType QueryInterface failed!", Logger::Error, hr);
467  return hr;
468  }
469 
470  if (FAILED(hr = pMediaType->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &unNumChannels)))
471  {
472  logger->Log("Webcam::CreateTargetAudioMediaType MF_MT_AUDIO_NUM_CHANNELS failed!", Logger::Error, hr);
473  return hr;
474  }
475 
476  if (FAILED(hr = pMediaType->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &unSampleRate)))
477  {
478  logger->Log("Webcam::CreateTargetAudioMediaType MF_MT_AUDIO_SAMPLES_PER_SECOND failed!", Logger::Error, hr);
479  return hr;
480  }
481 
482  if (unNumChannels == config->channels && unSampleRate == config->frequency)
483  {
484  fFoundMediaType = TRUE;
485  break;
486  }
487  }
488 
489  if (!fFoundMediaType)
490  {
491  logger->Log("Webcam::CreateTargetAudioMediaType Did not find media type!", Logger::Error, hr);
492  return E_FAIL;
493  }
494 
495  if (FAILED(hr = MFCreateMediaType(&pTargetMediaType)))
496  {
497  logger->Log("Webcam::CreateTargetAudioMediaType MFCreateMediaType failed!", Logger::Error, hr);
498  return hr;
499  }
500 
501  if (FAILED(hr = pMediaType->CopyAllItems(pTargetMediaType)))
502  {
503  logger->Log("Webcam::CreateTargetAudioMediaType CopyAllItems failed!", Logger::Error, hr);
504  return hr;
505  }
506 
507  *ppTargetMediaType = pTargetMediaType;
508 
509  pTargetMediaType = nullptr;
510 
511  SAFE_RELEASE(pTargetMediaType);
512  SAFE_RELEASE(pAvailableTypes);
513  SAFE_RELEASE(punkObject);
514  SAFE_RELEASE(pMediaType);
515 
516  return (hr);
517  }
518 
519  HRESULT Webcam::NegotiateStreamFormat(__in DWORD dwStreamIndex, __in REFGUID guidMajorType, __in DWORD cFormats, __in_ecount(cFormats) const GUID** paFormats) const
520  {
521  HRESULT hr;
522 
523  IMFMediaType* pPartialMediaType = nullptr;
524  IMFMediaType* pFullMediaType = nullptr;
525 
526  BOOL fConfigured = FALSE;
527 
528  if (FAILED(hr = MFCreateMediaType(&pPartialMediaType)))
529  {
530  logger->Log("Webcam::NegotiateStreamFormat MFCreateMediaType failed!", Logger::Error, hr);
531  return hr;
532  }
533 
534  if (FAILED(hr = pPartialMediaType->SetGUID(MF_MT_MAJOR_TYPE, guidMajorType)))
535  {
536  logger->Log("Webcam::NegotiateStreamFormat MF_MT_MAJOR_TYPE failed!", Logger::Error, hr);
537  return hr;
538  }
539 
540  if (dwStreamIndex == sink_video_stream)
541  {
542  char msg[99];
543  sprintf_s(msg, 99, "Webcam::NegotiateStreamFormat sink_video_stream cFormats count: %i", cFormats);
544  logger->Log(msg);
545  }
546 
547  for (DWORD ii = 0; ii < cFormats; ii++)
548  {
549  SAFE_RELEASE(pFullMediaType);
550 
551  if (FAILED(hr = pPartialMediaType->SetGUID(MF_MT_SUBTYPE, *paFormats[ii])))
552  {
553  logger->Log("Webcam::NegotiateStreamFormat MF_MT_SUBTYPE failed!", Logger::Error, hr);
554  return hr;
555  }
556 
557 
558  // ***
559  if (dwStreamIndex == sink_video_stream)
560  {
561  if (FAILED(hr = MFSetAttributeSize(pPartialMediaType, MF_MT_FRAME_SIZE, config->width, config->height)))
562  {
563  logger->Log("Webcam::NegotiateStreamFormat MF_MT_FRAME_SIZE failed!", Logger::Error, hr);
564  return hr;
565  }
566  }
567 
568 
569  // try to set the partial media type on the source reader
570  if (dwStreamIndex == sink_video_stream)
571  {
572  hr = m_pReader->SetCurrentMediaType(static_cast<DWORD>(MF_SOURCE_READER_FIRST_VIDEO_STREAM), nullptr, pPartialMediaType);
573  }
574  else
575  {
576  hr = m_pReader->SetCurrentMediaType(static_cast<DWORD>(MF_SOURCE_READER_FIRST_AUDIO_STREAM), nullptr, pPartialMediaType);
577  }
578 
579  if (S_OK != hr)
580  {
581  // format is not supported by the source reader, try the next on the list
582  hr = S_OK;
583  continue;
584  }
585 
586  // get the full media type from the source reader
587  if (dwStreamIndex == sink_video_stream)
588  {
589  hr = m_pReader->GetCurrentMediaType(static_cast<DWORD>(MF_SOURCE_READER_FIRST_VIDEO_STREAM), &pFullMediaType);
590  }
591  else
592  {
593  hr = m_pReader->GetCurrentMediaType(static_cast<DWORD>(MF_SOURCE_READER_FIRST_AUDIO_STREAM), &pFullMediaType);
594  }
595 
596  // try to set the input media type on the sink writer
597  if (SUCCEEDED(hr))
598  {
599  hr = m_pWriter->SetInputMediaType(dwStreamIndex, pFullMediaType, nullptr);
600  }
601 
602  if (S_OK != hr)
603  {
604  // format is not supported by the sink writer, try the next on the list
605  hr = S_OK;
606  continue;
607  }
608 
609  fConfigured = TRUE;
610  break;
611  }
612 
613  if (!fConfigured)
614  {
615  hr = E_FAIL;
616  }
617 
618  SAFE_RELEASE(pPartialMediaType);
619  SAFE_RELEASE(pFullMediaType);
620 
621  return (hr);
622  }
623 
624  HRESULT Webcam::NegotiateVideoStreamFormat(__in DWORD dwStreamIndex) const
625  {
627  /*
628  MFVideoFormat_I420
629  MFVideoFormat_IYUV
630  MFVideoFormat_NV12
631  MFVideoFormat_YUY2
632  MFVideoFormat_YV12
633  */
634  static const GUID* aVideoFormats[] =
635  {
636  &MFVideoFormat_NV12,
637  &MFVideoFormat_YV12,
638  &MFVideoFormat_YUY2,
639  &MFVideoFormat_RGB32,
640  &MFVideoFormat_UYVY,
641  &MFVideoFormat_RGB24,
642  &MFVideoFormat_IYUV,
643  };
644 
645  return NegotiateStreamFormat(dwStreamIndex, MFMediaType_Video, ARRAYSIZE(aVideoFormats), aVideoFormats);
646  }
647 
648  HRESULT Webcam::NegotiateAudioStreamFormat(__in DWORD dwStreamIndex) const
649  {
650  static const GUID* aAudioFormats[] =
651  {
652  &MFAudioFormat_Float,
653  &MFAudioFormat_PCM,
654  };
655 
656  return NegotiateStreamFormat(dwStreamIndex, MFMediaType_Audio, ARRAYSIZE(aAudioFormats), aAudioFormats);
657  }
658 
660  {
661  EnterCriticalSection(&m_critsec);
662 
663  BOOL bIsCapturing = (m_pWriter != nullptr);
664 
665  LeaveCriticalSection(&m_critsec);
666 
667  return bIsCapturing;
668  }
669 
670  void Webcam::Initialize(Logger* prmLogger, WebcamConfig* prmConfig, Bus* prmBus)
671  {
672  if (!prmConfig->enabled) return;
673 
674  initialized = false;
675  prmConfig->enabled = false;
676 
677  logger = prmLogger;
678  config = prmConfig;
679  bus = prmBus;
680 
681  CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
682  MFStartup(MF_VERSION);
683 
684  initialized = true;
685  prmConfig->enabled = true;
686  }
687 
689  {
690  logger->Log("Webcam::StartRecord Entering...");
691 
692  if (initialized == false)
693  {
694  logger->Log("Webcam::StartRecord Not initialized!", Logger::Error);
695  return;
696  }
697 
698  if (IsCapturing())
699  {
700  logger->Log("Webcam::StartRecord Already recording!", Logger::Error);
701  return;
702  }
703 
704  HRESULT hr;
705 
706  EnterCriticalSection(&m_critsec);
707 
708 
709  videoDevices = new DeviceList(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
710  if (FAILED(hr = videoDevices->EnumerateDevices(logger, config)) || videoDevices->Count() == 0)
711  {
712  logger->Log("Webcam::Initialize No video device or EnumerateDevices failed!", Logger::Error, hr);
713  return;
714  }
715 
716  audioDevices = new DeviceList(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID);
717  if (FAILED(hr = audioDevices->EnumerateDevices(logger, config)) || audioDevices->Count() == 0)
718  {
719  logger->Log("Webcam::Initialize No audio device or EnumerateDevices failed!", Logger::Error, hr);
720  return;
721  }
722 
723  char msg[199];
724 
725  sprintf_s(msg, 199, "Webcam::Initialize Searching for video device: %S", config->videoDevice.c_str());
726  logger->Log(msg);
728  {
729  logger->Log("Webcam::Initialize GetDevicebyID video failed!", Logger::Error, hr);
730  return;
731  }
732 
733  sprintf_s(msg, 199, "Webcam::Initialize Searching for audio device: %S", config->audioDevice.c_str());
734  logger->Log(msg);
736  {
737  logger->Log("Webcam::Initialize GetDevicebyID audio failed!", Logger::Error, hr);
738  return;
739  }
740 
741  // Create the media source for the device.
743  if (FAILED(hr = pVideoActivate->ActivateObject(__uuidof(IMFMediaSource), reinterpret_cast<void**>(&pVideoSource))))
744  {
745  logger->Log("Webcam::StartRecord ActivateObject failed video!", Logger::Error, hr);
746  LeaveCriticalSection(&m_critsec);
747  return;
748  }
749 
750  if (FAILED(hr = pAudioActivate->ActivateObject(__uuidof(IMFMediaSource), reinterpret_cast<void**>(&pAudioSource))))
751  {
752  logger->Log("Webcam::StartRecord ActivateObject failed audio!", Logger::Error, hr);
753  LeaveCriticalSection(&m_critsec);
754  return;
755  }
756 
758  {
759  LeaveCriticalSection(&m_critsec);
760  return;
761  }
762 
764  if (FAILED(hr = OpenMediaSource(pSource)))
765  {
766  LeaveCriticalSection(&m_critsec);
767  return;
768  }
769 
770 
771  // create unique filename based on timestamp
772  WCHAR fileName[99];
773  char fileNameA[99];
774 
775  recordingNumber++;
776 
777  swprintf_s(fileName, 99, L"%S %i %.0f.mp4", bus->receiptNumber.c_str(), recordingNumber, bus->ScenarioScore);
778  sprintf_s(fileNameA, 99, "%s %i %.0f.mp4", bus->receiptNumber.c_str(), recordingNumber, bus->ScenarioScore);
779  pathAndFileName = fileName;
780  pathAndFileNameA = fileNameA;
781 
782  if (FAILED(hr = MFCreateSinkWriterFromURL(pathAndFileName.c_str(), NULL, NULL, &m_pWriter)))
783  {
784  logger->Log("Webcam::StartRecord MFCreateSinkWriterFromURL failed!", Logger::Error, hr);
785  LeaveCriticalSection(&m_critsec);
786  return;
787  }
788 
789  // Set up the encoding parameters.
790  if (FAILED(hr = ConfigureCapture()))
791  {
792  logger->Log("Webcam::StartRecord ConfigureCapture failed!", Logger::Error, hr);
793  LeaveCriticalSection(&m_critsec);
794  return;
795  }
796 
797  m_bVideoFirstSample = TRUE;
798  m_bAudioFirstSample = TRUE;
799  m_llVideoBaseTime = 0;
800  m_llAudioBaseTime = 0;
801 
802  // Request the first frame.
803  if (FAILED(hr = m_pReader->ReadSample(static_cast<DWORD>(MF_SOURCE_READER_ANY_STREAM), 0, nullptr, nullptr, nullptr, nullptr)))
804  {
805  logger->Log("Webcam::StartRecord ReadSample!", Logger::Error, hr);
806  LeaveCriticalSection(&m_critsec);
807  return;
808  }
809 
810  SAFE_RELEASE(pVideoSource);
811  SAFE_RELEASE(pAudioSource);
812  SAFE_RELEASE(pSource);
813 
814  LeaveCriticalSection(&m_critsec);
815 
816  logger->Log("Webcam::StartRecord Successful!");
817  }
818 
820  {
821  logger->Log("Webcam::StopRecord Entering...");
822 
823  if (!IsCapturing())
824  {
825  logger->Log("Webcam::StopRecord Was not capturing!", Logger::Error);
826  return;
827  }
828 
829  EnterCriticalSection(&m_critsec);
830 
831  HRESULT hr;
832  if (FAILED(hr = m_pWriter->Finalize()))
833  {
834  if (hr == 0xc00d4a44)
835  logger->Log("Webcam::StopRecord Finalize failed because no samples were processed by the sink!", Logger::Error, hr);
836  else
837  logger->Log("Webcam::StopRecord Finalize failed!", Logger::Error, hr);
838 
839  LeaveCriticalSection(&m_critsec);
840  return;
841  }
842 
843  SAFE_DELETE(videoDevices);
844  SAFE_DELETE(audioDevices);
845 
846  SAFE_RELEASE(pVideoActivate);
847  SAFE_RELEASE(pAudioActivate);
848 
849  SAFE_RELEASE(pVideoSource);
850  SAFE_RELEASE(pAudioSource);
851  SAFE_RELEASE(pSource);
852 
853  SAFE_RELEASE(m_pReader);
854  SAFE_RELEASE(m_pWriter);
855 
856  LeaveCriticalSection(&m_critsec);
857 
858  // log filename
859  char msg[99];
860  sprintf_s(msg, 99, "Webcam::StopRecord Success, returning: %s", pathAndFileNameA.c_str());
861  logger->Log(msg);
862  }
863 
865  {
866  if (IsCapturing())
867  {
868  StopRecord();
869  }
870 
871  MFShutdown();
872  CoUninitialize();
873  }
874 
875  DeviceList::DeviceList(GUID guidDevice): m_cDevices(0), m_ppDevices(nullptr)
876  {
877  m_guidDevice = guidDevice;
878  }
879 
881  {
882  for (UINT32 i = 0; i < m_cDevices; i++)
883  {
884  SAFE_RELEASE(m_ppDevices[i]);
885  }
886  CoTaskMemFree(m_ppDevices);
887  m_ppDevices = nullptr;
888 
889  m_cDevices = 0;
890  }
891 
893  {
894  HRESULT hr;
895  IMFAttributes* pAttributes = nullptr;
896 
897  Clear();
898 
899  // Initialize an attribute store. We will use this to
900  // specify the enumeration parameters.
901 
902  if (FAILED(hr = MFCreateAttributes(&pAttributes, 1)))
903  {
904  logger->Log("Webcam::DeviceList::EnumerateDevices MFCreateAttributes failed!", Logger::Error, hr);
905  return hr;
906  }
907 
908  // Ask for source type = video capture devices
909  if (FAILED(hr = pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, m_guidDevice)))
910  {
911  logger->Log("Webcam::DeviceList::EnumerateDevices SetGUID MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE failed!", Logger::Error, hr);
912  return hr;
913  }
914 
915  // Enumerate devices.
916  if (FAILED(hr = MFEnumDeviceSources(pAttributes, &m_ppDevices, &m_cDevices)))
917  {
918  logger->Log("Webcam::DeviceList::EnumerateDevices MFEnumDeviceSources failed!", Logger::Error, hr);
919  return hr;
920  }
921 
922  SAFE_RELEASE(pAttributes);
923 
924  for (DWORD i = 0; i < m_cDevices; i++)
925  {
926  UINT32 cchName;
927 
928  // Try to get the display name.
929  WCHAR* szFriendlyName = nullptr;
930  if (FAILED(hr = m_ppDevices[i]->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &szFriendlyName, &cchName)))
931  {
932  logger->Log("Webcam::DeviceList::EnumerateDevices GetAllocatedString MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME failed!", Logger::Error, hr);
933  return hr;
934  }
935 
936  // Try to get the guid.
937  WCHAR* szFriendlyName2 = nullptr;
938  if (m_guidDevice == MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID)
939  hr = m_ppDevices[i]->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &szFriendlyName2, &cchName);
940  else
941  hr = m_ppDevices[i]->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID, &szFriendlyName2, &cchName);
942  if (FAILED(hr))
943  {
944  logger->Log("Webcam::DeviceList::EnumerateDevices GetAllocatedString m_guidDevice failed!", Logger::Error, hr);
945  return hr;
946  }
947 
948  char msg[199];
949  if (m_guidDevice == MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID)
950  sprintf_s(msg, 199, "WebCam::DeviceList::EnumerateDevices Available video capture device %S: %S", szFriendlyName, szFriendlyName2);
951  else
952  sprintf_s(msg, 199, "WebCam::DeviceList::EnumerateDevices Available audio capture device %S: %S", szFriendlyName, szFriendlyName2);
953  logger->Log(msg);
954 
955  if (m_guidDevice == MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID)
956  {
957  if (config->videoDevice.empty())
958  {
959  config->videoDevice = szFriendlyName2;
960  sprintf_s(msg, 199, "WebCam::DeviceList::EnumerateDevices Defaulted video capture device %S", config->videoDevice.c_str());
961  }
962  }
963  else
964  {
965  if (config->audioDevice.empty())
966  {
967  config->audioDevice = szFriendlyName2;
968  sprintf_s(msg, 199, "WebCam::DeviceList::EnumerateDevices Defaulted audio capture device %S", config->audioDevice.c_str());
969  }
970  }
971 
972  CoTaskMemFree(szFriendlyName);
973  CoTaskMemFree(szFriendlyName2);
974  }
975 
976  return hr;
977  }
978 
979  HRESULT DeviceList::GetDevicebyID(std::wstring id, IMFActivate** ppActivate) const
980  {
981  if (m_guidDevice == MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID)
982  {
983  for (UINT i = 0; i < Count(); i++)
984  {
985  WCHAR* sympolicLink = nullptr;
986  m_ppDevices[i]->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &sympolicLink, nullptr);
987  if (id == sympolicLink)
988  {
989  *ppActivate = m_ppDevices[i];
990  (*ppActivate)->AddRef();
991  return S_OK;
992  }
993  }
994  }
995  else if (m_guidDevice == MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID)
996  {
997  for (UINT i = 0; i < Count(); i++)
998  {
999  WCHAR* emdPointID = nullptr;
1000  m_ppDevices[i]->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID, &emdPointID, nullptr);
1001  if (id == emdPointID)
1002  {
1003  *ppActivate = m_ppDevices[i];
1004  (*ppActivate)->AddRef();
1005  return S_OK;
1006  }
1007  }
1008  }
1009  return E_FAIL;
1010  }
1011 
1013  {
1014  for (UINT i = 0; i < bus->commandStream.size(); i++)
1015  {
1016  Command command = bus->commandStream.at(i);
1017  if (command.delay != 0.0f) continue;
1018 
1019  if (command.name == "StartRecord")
1020  {
1021  StartRecord();
1022  bus->commandStream.erase(bus->commandStream.begin() + i);
1023  break;
1024  }
1025  else if (command.name == "StopRecord")
1026  {
1027  StopRecord();
1028  bus->commandStream.erase(bus->commandStream.begin() + i);
1029  break;
1030  }
1031  }
1032  }
1033 }
STDMETHODIMP QueryInterface(REFIID iid, void **ppv)
IUnknown methods below can be moved where?
Definition: Webcam.cpp:47
Bus * bus
Definition: Webcam.h:62
HRESULT NegotiateAudioStreamFormat(DWORD dwStreamIndex) const
Definition: Webcam.cpp:648
std::wstring videoDevice
Definition: Webcam.h:21
std::vector< Command > commandStream
Definition: Bus.h:20
IMFMediaSource * pVideoSource
Definition: Webcam.h:74
void Destroy()
Definition: Webcam.cpp:864
Definition: Logger.h:5
std::string pathAndFileNameA
Definition: Webcam.h:66
IMFActivate * pAudioActivate
Definition: Webcam.h:72
IMFActivate ** m_ppDevices
Definition: Webcam.h:36
WebcamConfig * config
Definition: Webcam.h:61
IMFActivate * pVideoActivate
Definition: Webcam.h:71
bool initialized
Definition: Webcam.h:64
HRESULT NegotiateStreamFormat(DWORD dwStreamIndex, REFGUID guidMajorType, DWORD cFormats, const GUID **paFormats) const
Definition: Webcam.cpp:519
HRESULT CreateTargetAudioMediaType(IMFMediaType *pNativeMediaType, IMFMediaType **ppTargetMediaType) const
Definition: Webcam.cpp:417
std::wstring audioDevice
Definition: Webcam.h:22
UINT32 Count() const
Definition: Webcam.h:47
IMFMediaSource * pSource
Definition: Webcam.h:76
okay, the portable keyboard numbers don&#39;t work like the outside keypad because the outside keypad is ...
Definition: Analog.cpp:3
Config config
Definition: Avionics.cpp:22
HRESULT CreateAggregatedSource(IMFMediaSource *pSource1, IMFMediaSource *pSource2, IMFMediaSource **ppAggSource) const
Definition: Webcam.cpp:140
Logger * logger
Definition: Webcam.h:60
Definition: Bus.h:12
std::string name
command name
Definition: Command.h:11
Logger logger
Definition: Avionics.cpp:17
std::wstring pathAndFileName
Definition: Webcam.h:65
void StartRecord()
Definition: Webcam.cpp:688
HRESULT OpenMediaSource(IMFMediaSource *pSource)
Definition: Webcam.cpp:175
virtual ~Webcam()
Definition: Webcam.cpp:27
IMFMediaSource * pAudioSource
Definition: Webcam.h:75
DeviceList * videoDevices
Definition: Webcam.h:68
HRESULT NegotiateVideoStreamFormat(DWORD dwStreamIndex) const
Definition: Webcam.cpp:624
DeviceList(GUID guidDevice)
Definition: Webcam.cpp:875
HRESULT ConfigureCapture()
Definition: Webcam.cpp:202
IMFSourceReader * m_pReader
Definition: Webcam.h:81
Definition: Command.h:5
HRESULT GetDevicebyID(std::wstring id, IMFActivate **ppActivate) const
Definition: Webcam.cpp:979
LONGLONG m_llVideoBaseTime
Definition: Webcam.h:86
HRESULT CreateTargetVideoMediaType(IMFMediaType *pNativeMediaType, IMFMediaType **ppTargetMediaType) const
Definition: Webcam.cpp:291
void StopRecord()
Definition: Webcam.cpp:819
STDMETHODIMP OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample *pSample)
Definition: Webcam.cpp:53
long m_nRefCount
Definition: Webcam.h:78
void Log(const char *msg, Level level=Info, int errorCode=0)
These have to be in this order.
Definition: Logger.cpp:16
DWORD sink_video_stream
Definition: Webcam.h:88
HRESULT EnumerateDevices(Logger *logger, WebcamConfig *config)
Definition: Webcam.cpp:892
std::string receiptNumber
Definition: Bus.h:293
BOOL IsCapturing()
Definition: Webcam.cpp:659
BOOL m_bVideoFirstSample
Definition: Webcam.h:84
UINT32 m_cDevices
Definition: Webcam.h:35
BOOL m_bAudioFirstSample
Definition: Webcam.h:85
void FrameMove()
Definition: Webcam.cpp:1012
LONGLONG m_llAudioBaseTime
Definition: Webcam.h:87
DWORD sink_audio_stream
Definition: Webcam.h:89
IMFSinkWriter * m_pWriter
Definition: Webcam.h:82
DeviceList * audioDevices
Definition: Webcam.h:69
void Initialize(Logger *prmLogger, WebcamConfig *prmConfig, Bus *prmBus)
Definition: Webcam.cpp:670
float delay
wait number of seconds before executing command
Definition: Command.h:8
float ScenarioScore
Definition: Bus.h:294
CRITICAL_SECTION m_critsec
Definition: Webcam.h:79
int recordingNumber
Definition: Webcam.h:133