blob: 0b1d2da1662fdcf5742165c0efc1837ea894e275 [file] [log] [blame]
Benny Prijonoc45d9512010-12-10 11:04:30 +00001/* $Id$ */
2/*
Nanang Izzuddinfad6f692011-08-19 09:35:25 +00003 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
Benny Prijonoc45d9512010-12-10 11:04:30 +00004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include <pjmedia-videodev/videodev_imp.h>
20#include <pj/assert.h>
21#include <pj/log.h>
22#include <pj/os.h>
23#include <pj/unicode.h>
24
Nanang Izzuddin63b3c132011-07-19 11:11:07 +000025
26#if defined(PJMEDIA_VIDEO_DEV_HAS_DSHOW) && PJMEDIA_VIDEO_DEV_HAS_DSHOW != 0
27
Benny Prijonoc45d9512010-12-10 11:04:30 +000028
29#ifdef _MSC_VER
30# pragma warning(push, 3)
31#endif
32
33#include <windows.h>
34#define COBJMACROS
35#include <DShow.h>
36
37#ifdef _MSC_VER
38# pragma warning(pop)
39#endif
40
41#pragma comment(lib, "Strmiids.lib")
42#pragma comment(lib, "Rpcrt4.lib")
Benny Prijono63a894d2011-04-07 07:22:35 +000043#pragma comment(lib, "Quartz.lib")
Benny Prijonoc45d9512010-12-10 11:04:30 +000044
45#define THIS_FILE "dshow_dev.c"
Sauw Ming8e799122010-12-30 16:31:16 +000046#define DEFAULT_CLOCK_RATE 90000
Benny Prijonoc45d9512010-12-10 11:04:30 +000047#define DEFAULT_WIDTH 640
48#define DEFAULT_HEIGHT 480
49#define DEFAULT_FPS 25
50
Nanang Izzuddin030aa2b2011-07-15 04:36:06 +000051/* Temporarily disable DirectShow renderer (VMR) */
52#define HAS_VMR 0
53
Benny Prijonoc45d9512010-12-10 11:04:30 +000054typedef void (*input_callback)(void *user_data, IMediaSample *pMediaSample);
55typedef struct NullRenderer NullRenderer;
56IBaseFilter* NullRenderer_Create(input_callback input_cb,
57 void *user_data);
58typedef struct SourceFilter SourceFilter;
59IBaseFilter* SourceFilter_Create(SourceFilter **pSrc);
60HRESULT SourceFilter_Deliver(SourceFilter *src, void *buf, long size);
Sauw Minga8e08622011-06-13 11:48:37 +000061void SourceFilter_SetMediaType(SourceFilter *src, AM_MEDIA_TYPE *pmt);
Benny Prijonoc45d9512010-12-10 11:04:30 +000062
63typedef struct dshow_fmt_info
64{
65 pjmedia_format_id pjmedia_format;
66 const GUID *dshow_format;
67} dshow_fmt_info;
68
69static dshow_fmt_info dshow_fmts[] =
70{
71 {PJMEDIA_FORMAT_YUY2, &MEDIASUBTYPE_YUY2} ,
72 {PJMEDIA_FORMAT_RGB24, &MEDIASUBTYPE_RGB24} ,
Sauw Minga8e08622011-06-13 11:48:37 +000073 {PJMEDIA_FORMAT_RGB32, &MEDIASUBTYPE_RGB32} ,
74 {PJMEDIA_FORMAT_IYUV, &MEDIASUBTYPE_IYUV} ,
Benny Prijonoc45d9512010-12-10 11:04:30 +000075};
76
77/* dshow_ device info */
78struct dshow_dev_info
79{
80 pjmedia_vid_dev_info info;
81 unsigned dev_id;
82 WCHAR display_name[192];
83};
84
85/* dshow_ factory */
86struct dshow_factory
87{
88 pjmedia_vid_dev_factory base;
89 pj_pool_t *pool;
Sauw Ming7f7c5bd2011-06-21 09:33:01 +000090 pj_pool_t *dev_pool;
Benny Prijonoc45d9512010-12-10 11:04:30 +000091 pj_pool_factory *pf;
92
93 unsigned dev_count;
94 struct dshow_dev_info *dev_info;
95};
96
97/* Video stream. */
98struct dshow_stream
99{
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000100 pjmedia_vid_dev_stream base; /**< Base stream */
Sauw Ming5291a2d2011-07-15 07:52:44 +0000101 pjmedia_vid_dev_param param; /**< Settings */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000102 pj_pool_t *pool; /**< Memory pool. */
Benny Prijonoc45d9512010-12-10 11:04:30 +0000103
Sauw Ming5291a2d2011-07-15 07:52:44 +0000104 pjmedia_vid_dev_cb vid_cb; /**< Stream callback. */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000105 void *user_data; /**< Application data. */
Benny Prijonoc45d9512010-12-10 11:04:30 +0000106
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000107 pj_bool_t quit_flag;
108 pj_bool_t rend_thread_exited;
109 pj_bool_t cap_thread_exited;
110 pj_bool_t cap_thread_initialized;
111 pj_thread_desc cap_thread_desc;
112 pj_thread_t *cap_thread;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000113
114 struct dshow_graph
115 {
116 IFilterGraph *filter_graph;
117 IMediaFilter *media_filter;
118 SourceFilter *csource_filter;
119 IBaseFilter *source_filter;
120 IBaseFilter *rend_filter;
121 AM_MEDIA_TYPE *mediatype;
Sauw Ming83db7d62011-06-09 04:08:47 +0000122 } dgraph;
Benny Prijono349037b2011-03-17 11:25:19 +0000123
124 pj_timestamp cap_ts;
125 unsigned cap_ts_inc;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000126};
127
128
129/* Prototypes */
130static pj_status_t dshow_factory_init(pjmedia_vid_dev_factory *f);
131static pj_status_t dshow_factory_destroy(pjmedia_vid_dev_factory *f);
Sauw Ming7f7c5bd2011-06-21 09:33:01 +0000132static pj_status_t dshow_factory_refresh(pjmedia_vid_dev_factory *f);
Benny Prijonoc45d9512010-12-10 11:04:30 +0000133static unsigned dshow_factory_get_dev_count(pjmedia_vid_dev_factory *f);
134static pj_status_t dshow_factory_get_dev_info(pjmedia_vid_dev_factory *f,
135 unsigned index,
136 pjmedia_vid_dev_info *info);
137static pj_status_t dshow_factory_default_param(pj_pool_t *pool,
138 pjmedia_vid_dev_factory *f,
139 unsigned index,
Sauw Ming5291a2d2011-07-15 07:52:44 +0000140 pjmedia_vid_dev_param *param);
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000141static pj_status_t dshow_factory_create_stream(
142 pjmedia_vid_dev_factory *f,
Sauw Ming5291a2d2011-07-15 07:52:44 +0000143 pjmedia_vid_dev_param *param,
144 const pjmedia_vid_dev_cb *cb,
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000145 void *user_data,
146 pjmedia_vid_dev_stream **p_vid_strm);
Benny Prijonoc45d9512010-12-10 11:04:30 +0000147
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000148static pj_status_t dshow_stream_get_param(pjmedia_vid_dev_stream *strm,
Sauw Ming5291a2d2011-07-15 07:52:44 +0000149 pjmedia_vid_dev_param *param);
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000150static pj_status_t dshow_stream_get_cap(pjmedia_vid_dev_stream *strm,
Benny Prijonoc45d9512010-12-10 11:04:30 +0000151 pjmedia_vid_dev_cap cap,
152 void *value);
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000153static pj_status_t dshow_stream_set_cap(pjmedia_vid_dev_stream *strm,
Benny Prijonoc45d9512010-12-10 11:04:30 +0000154 pjmedia_vid_dev_cap cap,
155 const void *value);
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000156static pj_status_t dshow_stream_start(pjmedia_vid_dev_stream *strm);
157static pj_status_t dshow_stream_put_frame(pjmedia_vid_dev_stream *strm,
Benny Prijonoc45d9512010-12-10 11:04:30 +0000158 const pjmedia_frame *frame);
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000159static pj_status_t dshow_stream_stop(pjmedia_vid_dev_stream *strm);
160static pj_status_t dshow_stream_destroy(pjmedia_vid_dev_stream *strm);
Benny Prijonoc45d9512010-12-10 11:04:30 +0000161
162/* Operations */
163static pjmedia_vid_dev_factory_op factory_op =
164{
165 &dshow_factory_init,
166 &dshow_factory_destroy,
167 &dshow_factory_get_dev_count,
168 &dshow_factory_get_dev_info,
169 &dshow_factory_default_param,
Sauw Ming7f7c5bd2011-06-21 09:33:01 +0000170 &dshow_factory_create_stream,
171 &dshow_factory_refresh
Benny Prijonoc45d9512010-12-10 11:04:30 +0000172};
173
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000174static pjmedia_vid_dev_stream_op stream_op =
Benny Prijonoc45d9512010-12-10 11:04:30 +0000175{
176 &dshow_stream_get_param,
177 &dshow_stream_get_cap,
178 &dshow_stream_set_cap,
179 &dshow_stream_start,
180 NULL,
181 &dshow_stream_put_frame,
182 &dshow_stream_stop,
183 &dshow_stream_destroy
184};
185
186
187/****************************************************************************
188 * Factory operations
189 */
190/*
191 * Init dshow_ video driver.
192 */
193pjmedia_vid_dev_factory* pjmedia_dshow_factory(pj_pool_factory *pf)
194{
195 struct dshow_factory *f;
196 pj_pool_t *pool;
197
198 pool = pj_pool_create(pf, "dshow video", 1000, 1000, NULL);
199 f = PJ_POOL_ZALLOC_T(pool, struct dshow_factory);
200 f->pf = pf;
201 f->pool = pool;
202 f->base.op = &factory_op;
203
204 return &f->base;
205}
206
207/* API: init factory */
208static pj_status_t dshow_factory_init(pjmedia_vid_dev_factory *f)
209{
Sauw Ming7f7c5bd2011-06-21 09:33:01 +0000210 CoInitializeEx(NULL, COINIT_MULTITHREADED);
211
212 return dshow_factory_refresh(f);
213}
214
215/* API: destroy factory */
216static pj_status_t dshow_factory_destroy(pjmedia_vid_dev_factory *f)
217{
218 struct dshow_factory *df = (struct dshow_factory*)f;
219 pj_pool_t *pool = df->pool;
220
221 df->pool = NULL;
222 if (df->dev_pool)
223 pj_pool_release(df->dev_pool);
224 if (pool)
225 pj_pool_release(pool);
226
227 CoUninitialize();
228
229 return PJ_SUCCESS;
230}
231
Sauw Mingaa08ef62011-07-15 06:42:11 +0000232static HRESULT get_cap_device(struct dshow_factory *df,
233 unsigned id,
234 IBaseFilter **filter)
235{
236 IBindCtx *pbc;
237 HRESULT hr;
238
239 hr = CreateBindCtx(0, &pbc);
240 if (SUCCEEDED (hr)) {
241 IMoniker *moniker;
242 DWORD pchEaten;
243
244 hr = MkParseDisplayName(pbc, df->dev_info[id].display_name,
245 &pchEaten, &moniker);
246 if (SUCCEEDED(hr)) {
247 hr = IMoniker_BindToObject(moniker, pbc, NULL,
248 &IID_IBaseFilter,
249 (LPVOID *)filter);
250 IMoniker_Release(moniker);
251 }
252 IBindCtx_Release(pbc);
253 }
254
255 return hr;
256}
257
258static void enum_dev_cap(IBaseFilter *filter,
259 pjmedia_dir dir,
260 const GUID *dshow_format,
261 AM_MEDIA_TYPE **pMediatype,
262 IPin **pSrcpin,
263 pj_bool_t *sup_fmt)
264{
265 IEnumPins *pEnum;
266 AM_MEDIA_TYPE *mediatype = NULL;
267 HRESULT hr;
268
269 if (pSrcpin)
270 *pSrcpin = NULL;
271 hr = IBaseFilter_EnumPins(filter, &pEnum);
272 if (SUCCEEDED(hr)) {
273 /* Loop through all the pins. */
274 IPin *pPin = NULL;
275
276 while (IEnumPins_Next(pEnum, 1, &pPin, NULL) == S_OK) {
277 PIN_DIRECTION pindirtmp;
278
279 hr = IPin_QueryDirection(pPin, &pindirtmp);
280 if (hr != S_OK || pindirtmp != PINDIR_OUTPUT) {
281 if (SUCCEEDED(hr))
282 IPin_Release(pPin);
283 continue;
284 }
285
286 if (dir == PJMEDIA_DIR_CAPTURE) {
287 IAMStreamConfig *streamcaps;
288
289 hr = IPin_QueryInterface(pPin, &IID_IAMStreamConfig,
290 (LPVOID *)&streamcaps);
291 if (SUCCEEDED(hr)) {
292 VIDEO_STREAM_CONFIG_CAPS vscc;
293 int i, isize, icount;
294
295 IAMStreamConfig_GetNumberOfCapabilities(streamcaps,
296 &icount, &isize);
297
298 for (i = 0; i < icount; i++) {
299 unsigned j, nformat;
300 RPC_STATUS rpcstatus, rpcstatus2;
301
302 hr = IAMStreamConfig_GetStreamCaps(streamcaps, i,
303 &mediatype,
304 (BYTE *)&vscc);
305 if (FAILED (hr))
306 continue;
307
308 nformat = (dshow_format? 1:
309 sizeof(dshow_fmts)/sizeof(dshow_fmts[0]));
310 for (j = 0; j < nformat; j++) {
311 if (!dshow_format || j > 0)
312 dshow_format = dshow_fmts[j].dshow_format;
313 if (UuidCompare(&mediatype->subtype,
314 (UUID*)dshow_format,
315 &rpcstatus) == 0 &&
316 rpcstatus == RPC_S_OK &&
317 UuidCompare(&mediatype->formattype,
318 (UUID*)&FORMAT_VideoInfo,
319 &rpcstatus2) == 0 &&
320 rpcstatus2 == RPC_S_OK)
321 {
322 if (sup_fmt)
323 sup_fmt[j] = PJ_TRUE;
324 if (pSrcpin) {
325 *pSrcpin = pPin;
326 *pMediatype = mediatype;
327 }
328 }
329 }
330 if (pSrcpin && *pSrcpin)
331 break;
332 }
333 IAMStreamConfig_Release(streamcaps);
334 }
335 } else {
336 *pSrcpin = pPin;
337 }
338 if (pSrcpin && *pSrcpin)
339 break;
340 IPin_Release(pPin);
341 }
342 IEnumPins_Release(pEnum);
343 }
344}
345
Sauw Ming7f7c5bd2011-06-21 09:33:01 +0000346/* API: refresh the list of devices */
347static pj_status_t dshow_factory_refresh(pjmedia_vid_dev_factory *f)
348{
Benny Prijonoc45d9512010-12-10 11:04:30 +0000349 struct dshow_factory *df = (struct dshow_factory*)f;
350 struct dshow_dev_info *ddi;
351 int dev_count = 0;
Nanang Izzuddin030aa2b2011-07-15 04:36:06 +0000352 unsigned c;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000353 ICreateDevEnum *dev_enum = NULL;
354 IEnumMoniker *enum_cat = NULL;
355 IMoniker *moniker = NULL;
356 HRESULT hr;
357 ULONG fetched;
358
Sauw Ming7f7c5bd2011-06-21 09:33:01 +0000359 if (df->dev_pool) {
360 pj_pool_release(df->dev_pool);
361 df->dev_pool = NULL;
362 }
Benny Prijonoc45d9512010-12-10 11:04:30 +0000363
Sauw Ming7f7c5bd2011-06-21 09:33:01 +0000364 df->dev_count = 0;
365 df->dev_pool = pj_pool_create(df->pf, "dshow video", 500, 500, NULL);
Benny Prijonoc45d9512010-12-10 11:04:30 +0000366
367 hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL,
368 CLSCTX_INPROC_SERVER, &IID_ICreateDevEnum,
369 (void**)&dev_enum);
370 if (FAILED(hr) ||
371 ICreateDevEnum_CreateClassEnumerator(dev_enum,
372 &CLSID_VideoInputDeviceCategory, &enum_cat, 0) != S_OK)
373 {
374 PJ_LOG(4,(THIS_FILE, "Windows found no video input devices"));
375 if (dev_enum)
376 ICreateDevEnum_Release(dev_enum);
377 dev_count = 0;
378 } else {
379 while (IEnumMoniker_Next(enum_cat, 1, &moniker, &fetched) == S_OK) {
380 dev_count++;
381 }
382 }
383
384 /* Add renderer device */
385 dev_count += 1;
386 df->dev_info = (struct dshow_dev_info*)
Sauw Ming7f7c5bd2011-06-21 09:33:01 +0000387 pj_pool_calloc(df->dev_pool, dev_count,
Benny Prijonoc45d9512010-12-10 11:04:30 +0000388 sizeof(struct dshow_dev_info));
389
390 if (dev_count > 1) {
391 IEnumMoniker_Reset(enum_cat);
392 while (IEnumMoniker_Next(enum_cat, 1, &moniker, &fetched) == S_OK) {
393 IPropertyBag *prop_bag;
394
395 hr = IMoniker_BindToStorage(moniker, 0, 0, &IID_IPropertyBag,
396 (void**)&prop_bag);
397 if (SUCCEEDED(hr)) {
398 VARIANT var_name;
399
400 VariantInit(&var_name);
401 hr = IPropertyBag_Read(prop_bag, L"FriendlyName",
402 &var_name, NULL);
403 if (SUCCEEDED(hr) && var_name.bstrVal) {
404 WCHAR *wszDisplayName = NULL;
Sauw Mingaa08ef62011-07-15 06:42:11 +0000405 IBaseFilter *filter;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000406
407 ddi = &df->dev_info[df->dev_count++];
408 pj_bzero(ddi, sizeof(*ddi));
409 pj_unicode_to_ansi(var_name.bstrVal,
410 wcslen(var_name.bstrVal),
411 ddi->info.name,
412 sizeof(ddi->info.name));
413
414 hr = IMoniker_GetDisplayName(moniker, NULL, NULL,
415 &wszDisplayName);
416 if (hr == S_OK && wszDisplayName) {
417 pj_memcpy(ddi->display_name, wszDisplayName,
418 (wcslen(wszDisplayName)+1) * sizeof(WCHAR));
419 CoTaskMemFree(wszDisplayName);
420 }
421
422 strncpy(ddi->info.driver, "dshow",
423 sizeof(ddi->info.driver));
424 ddi->info.driver[sizeof(ddi->info.driver)-1] = '\0';
425 ddi->info.dir = PJMEDIA_DIR_CAPTURE;
426 ddi->info.has_callback = PJ_TRUE;
427
428 /* Set the device capabilities here */
429 ddi->info.caps = PJMEDIA_VID_DEV_CAP_FORMAT;
Sauw Mingaa08ef62011-07-15 06:42:11 +0000430
431 hr = get_cap_device(df, df->dev_count-1, &filter);
432 if (SUCCEEDED(hr)) {
433 unsigned j;
434 pj_bool_t sup_fmt[sizeof(dshow_fmts)/sizeof(dshow_fmts[0])];
435
436 pj_bzero(sup_fmt, sizeof(sup_fmt));
437 enum_dev_cap(filter, ddi->info.dir, NULL, NULL, NULL, sup_fmt);
438
439 ddi->info.fmt_cnt = 0;
Sauw Mingaa08ef62011-07-15 06:42:11 +0000440 for (j = 0;
441 j < sizeof(dshow_fmts)/sizeof(dshow_fmts[0]);
442 j++)
443 {
444 if (!sup_fmt[j])
445 continue;
446 pjmedia_format_init_video(
447 &ddi->info.fmt[ddi->info.fmt_cnt++],
448 dshow_fmts[j].pjmedia_format,
449 DEFAULT_WIDTH, DEFAULT_HEIGHT,
450 DEFAULT_FPS, 1);
451 }
452 }
Benny Prijonoc45d9512010-12-10 11:04:30 +0000453 }
454 VariantClear(&var_name);
455
456 IPropertyBag_Release(prop_bag);
457 }
458 IMoniker_Release(moniker);
459 }
460
461 IEnumMoniker_Release(enum_cat);
462 ICreateDevEnum_Release(dev_enum);
463 }
464
Nanang Izzuddin030aa2b2011-07-15 04:36:06 +0000465#if HAS_VMR
Benny Prijonoc45d9512010-12-10 11:04:30 +0000466 ddi = &df->dev_info[df->dev_count++];
467 pj_bzero(ddi, sizeof(*ddi));
Benny Prijono349037b2011-03-17 11:25:19 +0000468 pj_ansi_strncpy(ddi->info.name, "Video Mixing Renderer",
469 sizeof(ddi->info.name));
Benny Prijonoc45d9512010-12-10 11:04:30 +0000470 ddi->info.name[sizeof(ddi->info.name)-1] = '\0';
Benny Prijono349037b2011-03-17 11:25:19 +0000471 pj_ansi_strncpy(ddi->info.driver, "dshow", sizeof(ddi->info.driver));
Benny Prijonoc45d9512010-12-10 11:04:30 +0000472 ddi->info.driver[sizeof(ddi->info.driver)-1] = '\0';
473 ddi->info.dir = PJMEDIA_DIR_RENDER;
474 ddi->info.has_callback = PJ_FALSE;
475 ddi->info.caps = PJMEDIA_VID_DEV_CAP_FORMAT;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000476// TODO:
Sauw Mingaa08ef62011-07-15 06:42:11 +0000477// ddi->info.caps |= PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW;
478
479 ddi->info.fmt_cnt = 1;
Sauw Mingaa08ef62011-07-15 06:42:11 +0000480 pjmedia_format_init_video(&ddi->info.fmt[0], dshow_fmts[0].pjmedia_format,
481 DEFAULT_WIDTH, DEFAULT_HEIGHT,
482 DEFAULT_FPS, 1);
483#endif
Benny Prijonoc45d9512010-12-10 11:04:30 +0000484
Sauw Ming7f7c5bd2011-06-21 09:33:01 +0000485 PJ_LOG(4, (THIS_FILE, "DShow has %d devices:",
Benny Prijonoc45d9512010-12-10 11:04:30 +0000486 df->dev_count));
487 for (c = 0; c < df->dev_count; ++c) {
488 PJ_LOG(4, (THIS_FILE, " dev_id %d: %s (%s)",
489 c,
490 df->dev_info[c].info.name,
491 df->dev_info[c].info.dir & PJMEDIA_DIR_CAPTURE ?
492 "capture" : "render"));
493 }
494
495 return PJ_SUCCESS;
496}
497
Benny Prijonoc45d9512010-12-10 11:04:30 +0000498/* API: get number of devices */
499static unsigned dshow_factory_get_dev_count(pjmedia_vid_dev_factory *f)
500{
501 struct dshow_factory *df = (struct dshow_factory*)f;
502 return df->dev_count;
503}
504
505/* API: get device info */
506static pj_status_t dshow_factory_get_dev_info(pjmedia_vid_dev_factory *f,
507 unsigned index,
508 pjmedia_vid_dev_info *info)
509{
510 struct dshow_factory *df = (struct dshow_factory*)f;
511
512 PJ_ASSERT_RETURN(index < df->dev_count, PJMEDIA_EVID_INVDEV);
513
514 pj_memcpy(info, &df->dev_info[index].info, sizeof(*info));
515
516 return PJ_SUCCESS;
517}
518
519/* API: create default device parameter */
520static pj_status_t dshow_factory_default_param(pj_pool_t *pool,
521 pjmedia_vid_dev_factory *f,
522 unsigned index,
Sauw Ming5291a2d2011-07-15 07:52:44 +0000523 pjmedia_vid_dev_param *param)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000524{
525 struct dshow_factory *df = (struct dshow_factory*)f;
526 struct dshow_dev_info *di = &df->dev_info[index];
527
528 PJ_ASSERT_RETURN(index < df->dev_count, PJMEDIA_EVID_INVDEV);
529
530 PJ_UNUSED_ARG(pool);
531
532 pj_bzero(param, sizeof(*param));
Sauw Ming83db7d62011-06-09 04:08:47 +0000533 if (di->info.dir & PJMEDIA_DIR_CAPTURE) {
Benny Prijonoc45d9512010-12-10 11:04:30 +0000534 param->dir = PJMEDIA_DIR_CAPTURE;
535 param->cap_id = index;
536 param->rend_id = PJMEDIA_VID_INVALID_DEV;
537 } else if (di->info.dir & PJMEDIA_DIR_RENDER) {
538 param->dir = PJMEDIA_DIR_RENDER;
539 param->rend_id = index;
540 param->cap_id = PJMEDIA_VID_INVALID_DEV;
541 } else {
542 return PJMEDIA_EVID_INVDEV;
543 }
544
545 /* Set the device capabilities here */
Sauw Ming8e799122010-12-30 16:31:16 +0000546 param->clock_rate = DEFAULT_CLOCK_RATE;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000547 param->flags = PJMEDIA_VID_DEV_CAP_FORMAT;
548
549 pjmedia_format_copy(&param->fmt, &di->info.fmt[0]);
550
551 return PJ_SUCCESS;
552}
553
554static void input_cb(void *user_data, IMediaSample *pMediaSample)
555{
556 struct dshow_stream *strm = (struct dshow_stream*)user_data;
557 unsigned char *buffer;
Benny Prijono349037b2011-03-17 11:25:19 +0000558 pjmedia_frame frame = {0};
Benny Prijonoc45d9512010-12-10 11:04:30 +0000559
560 if (strm->quit_flag) {
561 strm->cap_thread_exited = PJ_TRUE;
562 return;
563 }
564
565 if (strm->cap_thread_initialized == 0 || !pj_thread_is_registered())
566 {
567 pj_status_t status;
568
569 status = pj_thread_register("ds_cap", strm->cap_thread_desc,
570 &strm->cap_thread);
571 if (status != PJ_SUCCESS)
572 return;
573 strm->cap_thread_initialized = 1;
574 PJ_LOG(5,(THIS_FILE, "Capture thread started"));
575 }
576
577 IMediaSample_GetPointer(pMediaSample, &buffer);
578
579 frame.type = PJMEDIA_TYPE_VIDEO;
580 IMediaSample_GetPointer(pMediaSample, (BYTE **)&frame.buf);
581 frame.size = IMediaSample_GetActualDataLength(pMediaSample);
582 frame.bit_info = 0;
Benny Prijono349037b2011-03-17 11:25:19 +0000583 frame.timestamp = strm->cap_ts;
584 strm->cap_ts.u64 += strm->cap_ts_inc;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000585 if (strm->vid_cb.capture_cb)
586 (*strm->vid_cb.capture_cb)(&strm->base, strm->user_data, &frame);
587}
588
589/* API: Put frame from stream */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000590static pj_status_t dshow_stream_put_frame(pjmedia_vid_dev_stream *strm,
Benny Prijonoc45d9512010-12-10 11:04:30 +0000591 const pjmedia_frame *frame)
592{
593 struct dshow_stream *stream = (struct dshow_stream*)strm;
Sauw Ming83db7d62011-06-09 04:08:47 +0000594 HRESULT hr;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000595
596 if (stream->quit_flag) {
597 stream->rend_thread_exited = PJ_TRUE;
598 return PJ_SUCCESS;
599 }
600
Sauw Ming83db7d62011-06-09 04:08:47 +0000601 hr = SourceFilter_Deliver(stream->dgraph.csource_filter,
602 frame->buf, frame->size);
603 if (FAILED(hr))
604 return hr;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000605
606 return PJ_SUCCESS;
607}
608
609static dshow_fmt_info* get_dshow_format_info(pjmedia_format_id id)
610{
611 unsigned i;
612
613 for (i = 0; i < sizeof(dshow_fmts)/sizeof(dshow_fmts[0]); i++) {
614 if (dshow_fmts[i].pjmedia_format == id)
615 return &dshow_fmts[i];
616 }
617
618 return NULL;
619}
620
621static pj_status_t create_filter_graph(pjmedia_dir dir,
622 unsigned id,
Sauw Ming0531a722011-04-07 08:27:27 +0000623 pj_bool_t use_def_size,
624 pj_bool_t use_def_fps,
Benny Prijonoc45d9512010-12-10 11:04:30 +0000625 struct dshow_factory *df,
626 struct dshow_stream *strm,
627 struct dshow_graph *graph)
628{
629 HRESULT hr;
630 IEnumPins *pEnum;
631 IPin *srcpin = NULL;
632 IPin *sinkpin = NULL;
633 AM_MEDIA_TYPE *mediatype= NULL, mtype;
634 VIDEOINFOHEADER *video_info, *vi = NULL;
635 pjmedia_video_format_detail *vfd;
636 const pjmedia_video_format_info *vfi;
637
638 vfi = pjmedia_get_video_format_info(pjmedia_video_format_mgr_instance(),
639 strm->param.fmt.id);
640 if (!vfi)
641 return PJMEDIA_EVID_BADFORMAT;
642
643 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC,
644 &IID_IFilterGraph, (LPVOID *)&graph->filter_graph);
645 if (FAILED(hr)) {
646 goto on_error;
647 }
648
649 hr = IFilterGraph_QueryInterface(graph->filter_graph, &IID_IMediaFilter,
650 (LPVOID *)&graph->media_filter);
651 if (FAILED(hr)) {
652 goto on_error;
653 }
654
655 if (dir == PJMEDIA_DIR_CAPTURE) {
Sauw Mingaa08ef62011-07-15 06:42:11 +0000656 hr = get_cap_device(df, id, &graph->source_filter);
657 if (FAILED(hr)) {
Benny Prijonoc45d9512010-12-10 11:04:30 +0000658 goto on_error;
659 }
660 } else {
661 graph->source_filter = SourceFilter_Create(&graph->csource_filter);
662 }
663
664 hr = IFilterGraph_AddFilter(graph->filter_graph, graph->source_filter,
665 L"capture");
666 if (FAILED(hr)) {
667 goto on_error;
668 }
669
670 if (dir == PJMEDIA_DIR_CAPTURE) {
671 graph->rend_filter = NullRenderer_Create(input_cb, strm);
672 } else {
673 hr = CoCreateInstance(&CLSID_VideoMixingRenderer, NULL,
674 CLSCTX_INPROC, &IID_IBaseFilter,
675 (LPVOID *)&graph->rend_filter);
676 if (FAILED (hr)) {
677 goto on_error;
678 }
679 }
680
681 IBaseFilter_EnumPins(graph->rend_filter, &pEnum);
682 if (SUCCEEDED(hr)) {
683 // Loop through all the pins
684 IPin *pPin = NULL;
685
686 while (IEnumPins_Next(pEnum, 1, &pPin, NULL) == S_OK) {
687 PIN_DIRECTION pindirtmp;
688
689 hr = IPin_QueryDirection(pPin, &pindirtmp);
690 if (hr == S_OK && pindirtmp == PINDIR_INPUT) {
691 sinkpin = pPin;
692 break;
693 }
694 IPin_Release(pPin);
695 }
696 IEnumPins_Release(pEnum);
697 }
698
699 vfd = pjmedia_format_get_video_format_detail(&strm->param.fmt, PJ_TRUE);
700
Sauw Mingaa08ef62011-07-15 06:42:11 +0000701 enum_dev_cap(graph->source_filter, dir,
702 get_dshow_format_info(strm->param.fmt.id)->dshow_format,
703 &mediatype, &srcpin, NULL);
704 graph->mediatype = mediatype;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000705
Sauw Mingaa08ef62011-07-15 06:42:11 +0000706 if (srcpin && dir == PJMEDIA_DIR_RENDER) {
707 mediatype = graph->mediatype = &mtype;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000708
Sauw Mingaa08ef62011-07-15 06:42:11 +0000709 memset (mediatype, 0, sizeof(AM_MEDIA_TYPE));
710 mediatype->majortype = MEDIATYPE_Video;
711 mediatype->subtype = *(get_dshow_format_info(strm->param.fmt.id)->
712 dshow_format);
713 mediatype->bFixedSizeSamples = TRUE;
714 mediatype->bTemporalCompression = FALSE;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000715
Sauw Mingaa08ef62011-07-15 06:42:11 +0000716 vi = (VIDEOINFOHEADER *)
717 CoTaskMemAlloc(sizeof(VIDEOINFOHEADER));
718 memset (vi, 0, sizeof(VIDEOINFOHEADER));
719 mediatype->formattype = FORMAT_VideoInfo;
720 mediatype->cbFormat = sizeof(VIDEOINFOHEADER);
721 mediatype->pbFormat = (BYTE *)vi;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000722
Sauw Mingaa08ef62011-07-15 06:42:11 +0000723 vi->rcSource.bottom = vfd->size.h;
724 vi->rcSource.right = vfd->size.w;
725 vi->rcTarget.bottom = vfd->size.h;
726 vi->rcTarget.right = vfd->size.w;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000727
Sauw Mingaa08ef62011-07-15 06:42:11 +0000728 vi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
729 vi->bmiHeader.biPlanes = 1;
730 vi->bmiHeader.biBitCount = vfi->bpp;
731 vi->bmiHeader.biCompression = strm->param.fmt.id;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000732 }
733
734 if (!srcpin || !sinkpin || !mediatype) {
Nanang Izzuddinfd600af2011-07-15 02:12:25 +0000735 hr = VFW_E_TYPE_NOT_ACCEPTED;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000736 goto on_error;
737 }
738 video_info = (VIDEOINFOHEADER *) mediatype->pbFormat;
Sauw Ming0531a722011-04-07 08:27:27 +0000739 if (!use_def_size) {
740 video_info->bmiHeader.biWidth = vfd->size.w;
741 video_info->bmiHeader.biHeight = vfd->size.h;
742 }
743 if (!use_def_fps && vfd->fps.num != 0)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000744 video_info->AvgTimePerFrame = (LONGLONG) (10000000 *
Nanang Izzuddin63b01ab2011-03-22 09:46:04 +0000745 (double)vfd->fps.denum /
746 vfd->fps.num);
Benny Prijonoc45d9512010-12-10 11:04:30 +0000747 video_info->bmiHeader.biSizeImage = DIBSIZE(video_info->bmiHeader);
748 mediatype->lSampleSize = DIBSIZE(video_info->bmiHeader);
749 if (graph->csource_filter)
Sauw Minga8e08622011-06-13 11:48:37 +0000750 SourceFilter_SetMediaType(graph->csource_filter,
751 mediatype);
Benny Prijonoc45d9512010-12-10 11:04:30 +0000752
753 hr = IFilterGraph_AddFilter(graph->filter_graph,
754 (IBaseFilter *)graph->rend_filter,
755 L"renderer");
756 if (FAILED(hr))
757 goto on_error;
758
759 hr = IFilterGraph_ConnectDirect(graph->filter_graph, srcpin, sinkpin,
760 mediatype);
Sauw Minge098c592011-04-08 04:14:00 +0000761 if (SUCCEEDED(hr) && (use_def_size || use_def_fps)) {
Sauw Ming0531a722011-04-07 08:27:27 +0000762 pjmedia_format_init_video(&strm->param.fmt, strm->param.fmt.id,
763 video_info->bmiHeader.biWidth,
764 video_info->bmiHeader.biHeight,
765 10000000,
766 (unsigned)video_info->AvgTimePerFrame);
767 }
Benny Prijonoc45d9512010-12-10 11:04:30 +0000768
769on_error:
770 if (srcpin)
771 IPin_Release(srcpin);
772 if (sinkpin)
773 IPin_Release(sinkpin);
774 if (vi)
775 CoTaskMemFree(vi);
Benny Prijono63a894d2011-04-07 07:22:35 +0000776 if (FAILED(hr)) {
777 char msg[80];
778 if (AMGetErrorText(hr, msg, sizeof(msg))) {
779 PJ_LOG(4,(THIS_FILE, "Error creating filter graph: %s (hr=0x%x)",
780 msg, hr));
781 }
782 return PJ_EUNKNOWN;
783 }
Benny Prijonoc45d9512010-12-10 11:04:30 +0000784
785 return PJ_SUCCESS;
786}
787
Sauw Ming0531a722011-04-07 08:27:27 +0000788static void destroy_filter_graph(struct dshow_stream * stream)
789{
Sauw Ming83db7d62011-06-09 04:08:47 +0000790 if (stream->dgraph.source_filter) {
791 IBaseFilter_Release(stream->dgraph.source_filter);
792 stream->dgraph.source_filter = NULL;
793 }
794 if (stream->dgraph.rend_filter) {
795 IBaseFilter_Release(stream->dgraph.rend_filter);
796 stream->dgraph.rend_filter = NULL;
797 }
798 if (stream->dgraph.media_filter) {
799 IMediaFilter_Release(stream->dgraph.media_filter);
800 stream->dgraph.media_filter = NULL;
801 }
802 if (stream->dgraph.filter_graph) {
803 IFilterGraph_Release(stream->dgraph.filter_graph);
804 stream->dgraph.filter_graph = NULL;
Sauw Ming0531a722011-04-07 08:27:27 +0000805 }
806}
807
Benny Prijonoc45d9512010-12-10 11:04:30 +0000808/* API: create stream */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000809static pj_status_t dshow_factory_create_stream(
810 pjmedia_vid_dev_factory *f,
Sauw Ming5291a2d2011-07-15 07:52:44 +0000811 pjmedia_vid_dev_param *param,
812 const pjmedia_vid_dev_cb *cb,
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000813 void *user_data,
814 pjmedia_vid_dev_stream **p_vid_strm)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000815{
816 struct dshow_factory *df = (struct dshow_factory*)f;
817 pj_pool_t *pool;
818 struct dshow_stream *strm;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000819 pj_status_t status;
820
Sauw Ming83db7d62011-06-09 04:08:47 +0000821 PJ_ASSERT_RETURN(param->dir == PJMEDIA_DIR_CAPTURE ||
822 param->dir == PJMEDIA_DIR_RENDER, PJ_EINVAL);
823
Benny Prijonoc45d9512010-12-10 11:04:30 +0000824 if (!get_dshow_format_info(param->fmt.id))
825 return PJMEDIA_EVID_BADFORMAT;
826
827 /* Create and Initialize stream descriptor */
828 pool = pj_pool_create(df->pf, "dshow-dev", 1000, 1000, NULL);
829 PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
830
831 strm = PJ_POOL_ZALLOC_T(pool, struct dshow_stream);
832 pj_memcpy(&strm->param, param, sizeof(*param));
833 strm->pool = pool;
834 pj_memcpy(&strm->vid_cb, cb, sizeof(*cb));
835 strm->user_data = user_data;
Nanang Izzuddina6efd6e2011-07-15 02:00:37 +0000836 pjmedia_event_publisher_init(&strm->base.epub, PJMEDIA_SIG_VID_DEV_DSHOW);
Benny Prijonoc45d9512010-12-10 11:04:30 +0000837
Benny Prijonoc45d9512010-12-10 11:04:30 +0000838 if (param->dir & PJMEDIA_DIR_CAPTURE) {
Benny Prijono349037b2011-03-17 11:25:19 +0000839 const pjmedia_video_format_detail *vfd;
840
Sauw Ming83db7d62011-06-09 04:08:47 +0000841 /* Create capture stream here */
Benny Prijonoc45d9512010-12-10 11:04:30 +0000842 status = create_filter_graph(PJMEDIA_DIR_CAPTURE, param->cap_id,
Sauw Ming0531a722011-04-07 08:27:27 +0000843 PJ_FALSE, PJ_FALSE, df, strm,
Sauw Ming83db7d62011-06-09 04:08:47 +0000844 &strm->dgraph);
Sauw Ming0531a722011-04-07 08:27:27 +0000845 if (status != PJ_SUCCESS) {
846 destroy_filter_graph(strm);
847 /* Try to use default fps */
848 PJ_LOG(4,(THIS_FILE, "Trying to open dshow dev with default fps"));
849 status = create_filter_graph(PJMEDIA_DIR_CAPTURE, param->cap_id,
850 PJ_FALSE, PJ_TRUE, df, strm,
Sauw Ming83db7d62011-06-09 04:08:47 +0000851 &strm->dgraph);
Sauw Ming0531a722011-04-07 08:27:27 +0000852
853 if (status != PJ_SUCCESS) {
854 /* Still failed, now try to use default fps and size */
855 destroy_filter_graph(strm);
856 /* Try to use default fps */
857 PJ_LOG(4,(THIS_FILE, "Trying to open dshow dev with default "
858 "size & fps"));
859 status = create_filter_graph(PJMEDIA_DIR_CAPTURE,
860 param->cap_id,
861 PJ_TRUE, PJ_TRUE, df, strm,
Sauw Ming83db7d62011-06-09 04:08:47 +0000862 &strm->dgraph);
Sauw Ming0531a722011-04-07 08:27:27 +0000863 }
864
865 if (status != PJ_SUCCESS)
866 goto on_error;
867 pj_memcpy(param, &strm->param, sizeof(*param));
868 }
Benny Prijono349037b2011-03-17 11:25:19 +0000869
870 vfd = pjmedia_format_get_video_format_detail(&param->fmt, PJ_TRUE);
871 strm->cap_ts_inc = PJMEDIA_SPF2(param->clock_rate, &vfd->fps, 1);
Sauw Ming83db7d62011-06-09 04:08:47 +0000872 } else if (param->dir & PJMEDIA_DIR_RENDER) {
873 /* Create render stream here */
Benny Prijonoc45d9512010-12-10 11:04:30 +0000874 status = create_filter_graph(PJMEDIA_DIR_RENDER, param->rend_id,
Sauw Ming0531a722011-04-07 08:27:27 +0000875 PJ_FALSE, PJ_FALSE, df, strm,
Sauw Ming83db7d62011-06-09 04:08:47 +0000876 &strm->dgraph);
Benny Prijonoc45d9512010-12-10 11:04:30 +0000877 if (status != PJ_SUCCESS)
878 goto on_error;
879 }
880
881 /* Apply the remaining settings */
882 if (param->flags & PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW) {
883 dshow_stream_set_cap(&strm->base,
884 PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW,
885 &param->window);
886 }
887
888 /* Done */
889 strm->base.op = &stream_op;
890 *p_vid_strm = &strm->base;
891
892 return PJ_SUCCESS;
893
894on_error:
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000895 dshow_stream_destroy((pjmedia_vid_dev_stream *)strm);
Benny Prijono63a894d2011-04-07 07:22:35 +0000896 return status;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000897}
898
899/* API: Get stream info. */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000900static pj_status_t dshow_stream_get_param(pjmedia_vid_dev_stream *s,
Sauw Ming5291a2d2011-07-15 07:52:44 +0000901 pjmedia_vid_dev_param *pi)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000902{
903 struct dshow_stream *strm = (struct dshow_stream*)s;
904
905 PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
906
907 pj_memcpy(pi, &strm->param, sizeof(*pi));
908
909 if (dshow_stream_get_cap(s, PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW,
910 &pi->window) == PJ_SUCCESS)
911 {
912 pi->flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW;
913 }
914
915 return PJ_SUCCESS;
916}
917
918/* API: get capability */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000919static pj_status_t dshow_stream_get_cap(pjmedia_vid_dev_stream *s,
Benny Prijonoc45d9512010-12-10 11:04:30 +0000920 pjmedia_vid_dev_cap cap,
921 void *pval)
922{
923 struct dshow_stream *strm = (struct dshow_stream*)s;
924
925 PJ_UNUSED_ARG(strm);
926
927 PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
928
929 if (cap==PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW)
930 {
931 *(unsigned*)pval = 0;
932 return PJ_SUCCESS;
933 } else {
934 return PJMEDIA_EVID_INVCAP;
935 }
936}
937
938/* API: set capability */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000939static pj_status_t dshow_stream_set_cap(pjmedia_vid_dev_stream *s,
Benny Prijonoc45d9512010-12-10 11:04:30 +0000940 pjmedia_vid_dev_cap cap,
941 const void *pval)
942{
943 struct dshow_stream *strm = (struct dshow_stream*)s;
944
945 PJ_UNUSED_ARG(strm);
946
947 PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
948
949 if (cap==PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW)
950 {
951 // set renderer's window here
952 return PJ_SUCCESS;
953 }
954
955 return PJMEDIA_EVID_INVCAP;
956}
957
958/* API: Start stream. */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000959static pj_status_t dshow_stream_start(pjmedia_vid_dev_stream *strm)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000960{
961 struct dshow_stream *stream = (struct dshow_stream*)strm;
Sauw Ming83db7d62011-06-09 04:08:47 +0000962 HRESULT hr;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000963
964 stream->quit_flag = PJ_FALSE;
965 stream->cap_thread_exited = PJ_FALSE;
966 stream->rend_thread_exited = PJ_FALSE;
967
Sauw Ming83db7d62011-06-09 04:08:47 +0000968 hr = IMediaFilter_Run(stream->dgraph.media_filter, 0);
969 if (FAILED(hr)) {
970 char msg[80];
971 if (AMGetErrorText(hr, msg, sizeof(msg))) {
972 PJ_LOG(4,(THIS_FILE, "Error starting media: %s", msg));
Benny Prijonoc45d9512010-12-10 11:04:30 +0000973 }
Sauw Ming83db7d62011-06-09 04:08:47 +0000974 return PJ_EUNKNOWN;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000975 }
976
977 PJ_LOG(4, (THIS_FILE, "Starting dshow video stream"));
978
979 return PJ_SUCCESS;
980}
981
982/* API: Stop stream. */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000983static pj_status_t dshow_stream_stop(pjmedia_vid_dev_stream *strm)
Benny Prijonoc45d9512010-12-10 11:04:30 +0000984{
985 struct dshow_stream *stream = (struct dshow_stream*)strm;
986 unsigned i;
987
988 stream->quit_flag = PJ_TRUE;
989 if (stream->cap_thread) {
990 for (i=0; !stream->cap_thread_exited && i<100; ++i)
991 pj_thread_sleep(10);
992 }
993 for (i=0; !stream->rend_thread_exited && i<100; ++i)
994 pj_thread_sleep(10);
995
Sauw Ming83db7d62011-06-09 04:08:47 +0000996 IMediaFilter_Stop(stream->dgraph.media_filter);
Benny Prijonoc45d9512010-12-10 11:04:30 +0000997
998 PJ_LOG(4, (THIS_FILE, "Stopping dshow video stream"));
999
1000 return PJ_SUCCESS;
1001}
1002
Benny Prijonoc45d9512010-12-10 11:04:30 +00001003/* API: Destroy stream. */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001004static pj_status_t dshow_stream_destroy(pjmedia_vid_dev_stream *strm)
Benny Prijonoc45d9512010-12-10 11:04:30 +00001005{
1006 struct dshow_stream *stream = (struct dshow_stream*)strm;
Benny Prijonoc45d9512010-12-10 11:04:30 +00001007
1008 PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
1009
1010 dshow_stream_stop(strm);
Sauw Ming0531a722011-04-07 08:27:27 +00001011 destroy_filter_graph(stream);
Benny Prijonoc45d9512010-12-10 11:04:30 +00001012
1013 pj_pool_release(stream->pool);
1014
1015 return PJ_SUCCESS;
1016}
1017
1018#endif /* PJMEDIA_VIDEO_DEV_HAS_DSHOW */