Go to the documentation of this file.00001
00002
00003 #include "vidl_dshow_live_istream.h"
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <vidl/vidl_config.h>
00013 #include <vidl/vidl_dshow.h>
00014 #include <vcl_cassert.h>
00015 #include <vcl_cstring.h>
00016
00017
00018
00019 sample_grabber_cb::sample_grabber_cb(void)
00020 : busy_index_(-1)
00021 , curr_index_(-1)
00022 , next_index_(0)
00023 {
00024 mutex_ = CreateMutex(0, false ,0);
00025 }
00026
00027 STDMETHODIMP
00028 sample_grabber_cb::QueryInterface(REFIID riid, void **target)
00029 {
00030 if (target == 0) return E_POINTER;
00031 if (riid == __uuidof(IUnknown))
00032 {
00033 *target = static_cast<IUnknown*>(this);
00034 return S_OK;
00035 }
00036 if (riid == __uuidof(ISampleGrabberCB))
00037 {
00038 *target = static_cast<ISampleGrabberCB*>(this);
00039 return S_OK;
00040 }
00041 return E_NOTIMPL;
00042 }
00043
00044
00045 STDMETHODIMP
00046 sample_grabber_cb::SampleCB(double time, IMediaSample *sample)
00047 {
00048 assert(sample);
00049
00050 BYTE *buffer;
00051 DSHOW_ERROR_IF_FAILED(sample->GetPointer(&buffer));
00052
00053 return BufferCB(time, buffer, sample->GetSize());
00054 }
00055
00056
00057 STDMETHODIMP
00058 sample_grabber_cb::BufferCB(double time, BYTE* buffer, long buffer_size)
00059 {
00060 assert(buffer);
00061
00062
00063 const unsigned int i = next_index_;
00064 buffer_[i].resize(buffer_size);
00065 buffer_time_[i] = time;
00066
00067
00068 vcl_memcpy(&buffer_[i][0], buffer, buffer_size);
00069
00070
00071 WaitForSingleObject(mutex_, INFINITE);
00072 curr_index_ = next_index_;
00073 next_index_ = (next_index_ + 1) % 3;
00074 if (next_index_ == busy_index_)
00075 {
00076 next_index_ = (next_index_ + 1) % 3;
00077 }
00078 ReleaseMutex(mutex_);
00079
00080 return S_FALSE;
00081 }
00082
00083 void sample_grabber_cb::advance(void)
00084 {
00085 busy_index_ = -1;
00086 while (busy_index_ == -1)
00087 {
00088 WaitForSingleObject(mutex_, INFINITE);
00089 if (curr_index_ != -1)
00090 {
00091 busy_index_ = curr_index_;
00092 curr_index_ = -1;
00093 }
00094 ReleaseMutex(mutex_);
00095 Sleep(0);
00096 }
00097 }
00098
00099 vidl_frame_sptr sample_grabber_cb::current_frame(void)
00100 {
00101 return new vidl_shared_frame(&buffer_[busy_index_][0],
00102 buffer_[busy_index_].size(), 1,
00103 VIDL_PIXEL_FORMAT_UNKNOWN);
00104 }
00105
00106
00107
00108
00109
00110 template <class ParamsObject>
00111 vidl_dshow_live_istream<ParamsObject>::vidl_dshow_live_istream(void)
00112 : params_(ParamsObject())
00113 , register_(0)
00114 {
00115
00116 vcl_vector<vcl_string> names = vidl_dshow::get_capture_device_names();
00117 if (names.size() > 0)
00118 {
00119 params_.set_device_name(names[0]);
00120 connect();
00121 }
00122 else
00123 {
00124 vidl_exception_error(
00125 vidl_dshow_exception("No capture devices found."));
00126 }
00127 }
00128
00129
00130 template <class ParamsObject>
00131 vidl_dshow_live_istream<ParamsObject>
00132 ::vidl_dshow_live_istream(const vcl_string& device_name)
00133 : params_(ParamsObject().set_device_name(device_name))
00134 , register_(0)
00135 {
00136 connect();
00137 }
00138
00139
00140 template <class ParamsObject>
00141 vidl_dshow_live_istream<ParamsObject>
00142 ::vidl_dshow_live_istream(const ParamsObject& params)
00143 : params_(params)
00144 , register_(0)
00145 {
00146 connect();
00147 }
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158 template <class ParamsObject>
00159 void vidl_dshow_live_istream<ParamsObject>::connect(void)
00160 {
00161
00162
00163
00164
00165 moniker_ = vidl_dshow::get_capture_device_moniker(params_.device_name());
00166 if (!moniker_)
00167 {
00168 vidl_exception_error(vidl_exception("Requested device not found."));
00169 }
00170
00171
00172
00173 DSHOW_ERROR_IF_FAILED(filter_graph_.CoCreateInstance(CLSID_FilterGraph));
00174
00175
00176 CComPtr<ICaptureGraphBuilder2> graph_builder;
00177 DSHOW_ERROR_IF_FAILED(
00178 graph_builder.CoCreateInstance(CLSID_CaptureGraphBuilder2));
00179
00180
00181 graph_builder->SetFiltergraph(filter_graph_);
00182
00183
00184 CComPtr<IBaseFilter> source_filter;
00185 DSHOW_ERROR_IF_FAILED(filter_graph_->AddSourceFilterForMoniker(
00186 moniker_, 0, L"Source", &source_filter));
00187
00188
00189 params_.configure_filter(source_filter);
00190
00191
00192
00193
00194 CComPtr<ISampleGrabber> sample_grabber;
00195 DSHOW_ERROR_IF_FAILED(
00196 sample_grabber.CoCreateInstance(CLSID_SampleGrabber));
00197 sample_grabber->SetBufferSamples(false);
00198 sample_grabber->SetOneShot(false);
00199 sample_grabber->SetCallback(&sample_grabber_callback_, 0);
00200
00201
00202 if (params_.target_output_format() != GUID_NULL)
00203 {
00204 AM_MEDIA_TYPE media_type;
00205 ZeroMemory(&media_type, sizeof(AM_MEDIA_TYPE));
00206 media_type.majortype = MEDIATYPE_Video;
00207 media_type.subtype = params_.target_output_format();
00208 sample_grabber->SetMediaType(&media_type);
00209 }
00210
00211
00212 CComQIPtr<IBaseFilter> sample_grabber_filter(sample_grabber);
00213 DSHOW_ERROR_IF_FAILED(
00214 filter_graph_->AddFilter(sample_grabber_filter, L"Sample Grabber"));
00215
00216
00217 CComPtr<IBaseFilter> filter;
00218 if (params_.output_filename() == "")
00219 {
00220 DSHOW_ERROR_IF_FAILED(filter.CoCreateInstance(CLSID_NullRenderer));
00221 DSHOW_ERROR_IF_FAILED(filter_graph_->AddFilter(filter, L"Null Renderer"));
00222 }
00223 else
00224 {
00225 DSHOW_ERROR_IF_FAILED(graph_builder->SetOutputFileName(
00226 &MEDIASUBTYPE_Avi,
00227 CA2W(params_.output_filename().c_str()),
00228 &filter, 0));
00229 }
00230
00231
00232
00233
00234
00235
00236 DSHOW_ERROR_IF_FAILED(graph_builder->RenderStream(&PIN_CATEGORY_CAPTURE,
00237 &MEDIATYPE_Video,
00238 source_filter,
00239 sample_grabber_filter,
00240 filter));
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270 if (params_.save_graph_to() != "")
00271 {
00272 vidl_dshow::save_graph_to_file(filter_graph_, params_.save_graph_to());
00273 }
00274
00275
00276 AM_MEDIA_TYPE media_type;
00277 DSHOW_ERROR_IF_FAILED(
00278 sample_grabber->GetConnectedMediaType(&media_type));
00279 vidl_dshow::get_media_info(media_type,
00280 buffer_width_,
00281 buffer_height_,
00282 buffer_pixel_format_);
00283 vidl_dshow::delete_media_type(media_type);
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294 if (params_.register_in_rot())
00295 {
00296 vidl_dshow::register_in_rot(filter_graph_, register_);
00297 }
00298
00299 filter_graph_->QueryInterface(
00300 IID_IMediaControl, reinterpret_cast<void**>(&media_control_));
00301
00302 if (params_.run_when_ready())
00303 {
00304 run();
00305 }
00306 else
00307 {
00308 pause();
00309 }
00310 }
00311
00312 template <class ParamsObject>
00313 inline void vidl_dshow_live_istream<ParamsObject>::close(void)
00314 {
00315 stop();
00316
00317 if (register_ != 0)
00318 {
00319 vidl_dshow::remove_from_rot(register_);
00320 }
00321
00322 media_control_.Release();
00323 moniker_.Release();
00324 filter_graph_.Release();
00325 }
00326
00327
00328
00329
00330
00331 template <class ParamsObject>
00332 inline bool vidl_dshow_live_istream<ParamsObject>::advance_wait(void)
00333 {
00334 if (!advance_start()) { return false; }
00335 while (!is_frame_available()) { Sleep(0); }
00336 return true;
00337 }
00338
00339
00340 template <class ParamsObject>
00341 inline bool vidl_dshow_live_istream<ParamsObject>::advance_start(void)
00342 {
00343 sample_grabber_callback_.advance();
00344 return true;
00345 }
00346
00347
00348 template <class ParamsObject>
00349 inline bool
00350 vidl_dshow_live_istream<ParamsObject>::is_frame_available(void) const
00351 {
00352 return true;
00353 }
00354
00355
00356 template <class ParamsObject>
00357 inline vidl_frame_sptr
00358 vidl_dshow_live_istream<ParamsObject>::read_frame(void)
00359 {
00360 if (!advance_wait()) { return 0; }
00361 return current_frame();
00362 }
00363
00364
00365 template <class ParamsObject>
00366 inline vidl_frame_sptr
00367 vidl_dshow_live_istream<ParamsObject>::current_frame(void)
00368 {
00369 if (buffer_pixel_format_ == VIDL_PIXEL_FORMAT_UNKNOWN)
00370 {
00371 return sample_grabber_callback_.current_frame();
00372 }
00373 else
00374 {
00375 return new vidl_shared_frame(
00376 sample_grabber_callback_.current_frame()->data(),
00377 buffer_width_,
00378 buffer_height_,
00379 buffer_pixel_format_);
00380 }
00381 }
00382
00383 template <class ParamsObject>
00384 inline void vidl_dshow_live_istream<ParamsObject>
00385 ::wait_for_state_change(HRESULT hr)
00386 {
00387 if (hr == S_FALSE)
00388 {
00389 OAFilterState state;
00390 DSHOW_ERROR_IF_FAILED(media_control_->GetState(INFINITE, &state));
00391 }
00392 }
00393
00394 template <class ParamsObject>
00395 inline void vidl_dshow_live_istream<ParamsObject>::run(void)
00396 {
00397 wait_for_state_change(media_control_->Run());
00398 }
00399
00400 template <class ParamsObject>
00401 inline void vidl_dshow_live_istream<ParamsObject>::pause(void)
00402 {
00403 wait_for_state_change(media_control_->Pause());
00404 }
00405
00406 template <class ParamsObject>
00407 inline void vidl_dshow_live_istream<ParamsObject>::stop(void)
00408 {
00409 wait_for_state_change(media_control_->Stop());
00410 }
00411
00412
00413
00414
00415
00416
00417
00418
00419 #include <vidl/vidl_dshow_istream_params.h>
00420 template class vidl_dshow_live_istream<vidl_dshow_istream_params>;
00421
00422 #if VIDL_HAS_DSHOW_ESF
00423 #include <vidl/vidl_dshow_istream_params_esf.h>
00424 template class vidl_dshow_live_istream<vidl_dshow_istream_params_esf>;
00425 #endif // HAS_EURESYS_ESF