OSVR Framework (Internal Development Docs)  0.6-1962-g59773924
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
directx_samplegrabber_callback.cpp
Go to the documentation of this file.
1 
11 // Copyright 2015 Sensics, Inc.
12 //
13 // Licensed under the Apache License, Version 2.0 (the "License");
14 // you may not use this file except in compliance with the License.
15 // You may obtain a copy of the License at
16 //
17 // http://www.apache.org/licenses/LICENSE-2.0
18 //
19 // Unless required by applicable law or agreed to in writing, software
20 // distributed under the License is distributed on an "AS IS" BASIS,
21 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 // See the License for the specific language governing permissions and
23 // limitations under the License.
24 
25 // Internal Includes
27 
28 // Library/third-party includes
29 #include <boost/assert.hpp>
30 
31 // Standard includes
32 #include <chrono>
33 
34 static const auto WAIT_FOR_CONSUMER_TIMEOUT = std::chrono::milliseconds{50};
35 
36 //--------------------------------------------------------------------------------------------
37 // This section implements the callback handler that gets frames from the
38 // SampleGrabber filter.
39 directx_samplegrabber_callback::directx_samplegrabber_callback(
40  MediaSampleExchangePtr const &exchange)
41  : sampleExchange_(exchange) {}
42 
43 directx_samplegrabber_callback::~directx_samplegrabber_callback() {
44  // Make sure the other thread knows that it is okay to return the
45  // buffer and wait until it has had time to do so.
46  shutdown();
47 };
48 
50  _stayAlive = false;
53  Sleep(100);
54 }
55 HRESULT directx_samplegrabber_callback::QueryInterface(
56  REFIID interfaceRequested, void **handleToInterfaceRequested) {
57  if (handleToInterfaceRequested == nullptr) {
58  return E_POINTER;
59  }
60  if (interfaceRequested == IID_IUnknown) {
61  *handleToInterfaceRequested = static_cast<IUnknown *>(this);
62  } else if (interfaceRequested == IID_ISampleGrabberCB) {
63  *handleToInterfaceRequested = static_cast<ISampleGrabberCB *>(this);
64  } else {
65  return E_NOINTERFACE;
66  }
67  AddRef();
68  return S_OK;
69 }
70 
71 // This is the routine that processes each sample. It gets the information
72 // about the sample (one frame) from the SampleGrabber, then marks itself as
73 // being ready to process the sample. It then blocks until the sample has been
74 // processed by the associated camera server. The hand-off is handled by using
75 // two Windows system events, acting somewhat like semaphores, in
76 // MediaSampleExchange.
77 //
78 // The directx camera must be sure to free an open sample (if any) after
79 // changing the state of the filter graph, so that this doesn't block
80 // indefinitely. This means that the destructor for any object using this
81 // callback object has to destroy this object. The destructor sets _stayAlive
82 // to false to make sure this thread terminates.
83 //
84 // The discussion below relates more closely to an earlier implementation that
85 // used booleans as crude semaphore substitutes: it has been left for its
86 // instructive value.
87 // The first semaphore (imageReady) controls access to the callback handler's
88 // buffer so that the application thread will only read it when it is full. The
89 // second sempaphore (imageDone) controls when the handler routine can release a
90 // sample; it makes sure that the sample is not released before the application
91 // thread is done processing it.
92 
93 HRESULT directx_samplegrabber_callback::SampleCB(double time,
94  IMediaSample *sample) {
95  // Point the image sample to the media sample we have and then set the flag
96  // to tell the application it can process it.
97  BOOST_ASSERT_MSG(_stayAlive, "Should be alive when samplecb is called");
98  sampleExchange_->signalSampleProduced(sample);
99 
100  // Wait for either this object to be destroyed/shutdown (_stayAlive ==
101  // false), or for the application/consumer to finish with this sample (which
102  // would return true from the wait function, rather than false as a timeout
103  // does).
104  while (_stayAlive &&
105  !sampleExchange_->waitForSampleConsumed(WAIT_FOR_CONSUMER_TIMEOUT)) {
106  }
107 
108  return S_OK;
109 }