Fixed #1281:
Video device should now be able to open the device when provided with the default param.
Tested video device: dshow capture, qt, iOS, SDL
git-svn-id: https://svn.pjsip.org/repos/pjproject/branches/projects/2.0-dev@3654 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjmedia/src/pjmedia-videodev/dshow_dev.c b/pjmedia/src/pjmedia-videodev/dshow_dev.c
index 1ff9455..42989d7 100644
--- a/pjmedia/src/pjmedia-videodev/dshow_dev.c
+++ b/pjmedia/src/pjmedia-videodev/dshow_dev.c
@@ -227,6 +227,120 @@
return PJ_SUCCESS;
}
+static HRESULT get_cap_device(struct dshow_factory *df,
+ unsigned id,
+ IBaseFilter **filter)
+{
+ IBindCtx *pbc;
+ HRESULT hr;
+
+ hr = CreateBindCtx(0, &pbc);
+ if (SUCCEEDED (hr)) {
+ IMoniker *moniker;
+ DWORD pchEaten;
+
+ hr = MkParseDisplayName(pbc, df->dev_info[id].display_name,
+ &pchEaten, &moniker);
+ if (SUCCEEDED(hr)) {
+ hr = IMoniker_BindToObject(moniker, pbc, NULL,
+ &IID_IBaseFilter,
+ (LPVOID *)filter);
+ IMoniker_Release(moniker);
+ }
+ IBindCtx_Release(pbc);
+ }
+
+ return hr;
+}
+
+static void enum_dev_cap(IBaseFilter *filter,
+ pjmedia_dir dir,
+ const GUID *dshow_format,
+ AM_MEDIA_TYPE **pMediatype,
+ IPin **pSrcpin,
+ pj_bool_t *sup_fmt)
+{
+ IEnumPins *pEnum;
+ AM_MEDIA_TYPE *mediatype = NULL;
+ HRESULT hr;
+
+ if (pSrcpin)
+ *pSrcpin = NULL;
+ hr = IBaseFilter_EnumPins(filter, &pEnum);
+ if (SUCCEEDED(hr)) {
+ /* Loop through all the pins. */
+ IPin *pPin = NULL;
+
+ while (IEnumPins_Next(pEnum, 1, &pPin, NULL) == S_OK) {
+ PIN_DIRECTION pindirtmp;
+
+ hr = IPin_QueryDirection(pPin, &pindirtmp);
+ if (hr != S_OK || pindirtmp != PINDIR_OUTPUT) {
+ if (SUCCEEDED(hr))
+ IPin_Release(pPin);
+ continue;
+ }
+
+ if (dir == PJMEDIA_DIR_CAPTURE) {
+ IAMStreamConfig *streamcaps;
+
+ hr = IPin_QueryInterface(pPin, &IID_IAMStreamConfig,
+ (LPVOID *)&streamcaps);
+ if (SUCCEEDED(hr)) {
+ VIDEO_STREAM_CONFIG_CAPS vscc;
+ int i, isize, icount;
+
+ IAMStreamConfig_GetNumberOfCapabilities(streamcaps,
+ &icount, &isize);
+
+ for (i = 0; i < icount; i++) {
+ unsigned j, nformat;
+ RPC_STATUS rpcstatus, rpcstatus2;
+
+ hr = IAMStreamConfig_GetStreamCaps(streamcaps, i,
+ &mediatype,
+ (BYTE *)&vscc);
+ if (FAILED (hr))
+ continue;
+
+ nformat = (dshow_format? 1:
+ sizeof(dshow_fmts)/sizeof(dshow_fmts[0]));
+ for (j = 0; j < nformat; j++) {
+ if (!dshow_format || j > 0)
+ dshow_format = dshow_fmts[j].dshow_format;
+ if (UuidCompare(&mediatype->subtype,
+ (UUID*)dshow_format,
+ &rpcstatus) == 0 &&
+ rpcstatus == RPC_S_OK &&
+ UuidCompare(&mediatype->formattype,
+ (UUID*)&FORMAT_VideoInfo,
+ &rpcstatus2) == 0 &&
+ rpcstatus2 == RPC_S_OK)
+ {
+ if (sup_fmt)
+ sup_fmt[j] = PJ_TRUE;
+ if (pSrcpin) {
+ *pSrcpin = pPin;
+ *pMediatype = mediatype;
+ }
+ }
+ }
+ if (pSrcpin && *pSrcpin)
+ break;
+ }
+ IAMStreamConfig_Release(streamcaps);
+ }
+ } else {
+ *pSrcpin = pPin;
+ }
+ if (pSrcpin && *pSrcpin)
+ break;
+ IPin_Release(pPin);
+ }
+ IEnumPins_Release(pEnum);
+ }
+}
+
/* API: refresh the list of devices */
static pj_status_t dshow_factory_refresh(pjmedia_vid_dev_factory *f)
{
@@ -286,6 +400,7 @@
&var_name, NULL);
if (SUCCEEDED(hr) && var_name.bstrVal) {
WCHAR *wszDisplayName = NULL;
+ IBaseFilter *filter;
ddi = &df->dev_info[df->dev_count++];
pj_bzero(ddi, sizeof(*ddi));
@@ -310,8 +425,35 @@
/* Set the device capabilities here */
ddi->info.caps = PJMEDIA_VID_DEV_CAP_FORMAT;
- // TODO: Query the default width, height, fps, and
- // supported formats
+
+ hr = get_cap_device(df, df->dev_count-1, &filter);
+ if (SUCCEEDED(hr)) {
+ unsigned j;
+ pj_bool_t sup_fmt[sizeof(dshow_fmts)/sizeof(dshow_fmts[0])];
+
+ pj_bzero(sup_fmt, sizeof(sup_fmt));
+ enum_dev_cap(filter, ddi->info.dir, NULL, NULL, NULL, sup_fmt);
+
+ ddi->info.fmt_cnt = 0;
+ ddi->info.fmt = (pjmedia_format*)
+ pj_pool_calloc(df->dev_pool,
+ sizeof(dshow_fmts)/
+ sizeof(dshow_fmts[0]),
+ sizeof(pjmedia_format));
+
+ for (j = 0;
+ j < sizeof(dshow_fmts)/sizeof(dshow_fmts[0]);
+ j++)
+ {
+ if (!sup_fmt[j])
+ continue;
+ pjmedia_format_init_video(
+ &ddi->info.fmt[ddi->info.fmt_cnt++],
+ dshow_fmts[j].pjmedia_format,
+ DEFAULT_WIDTH, DEFAULT_HEIGHT,
+ DEFAULT_FPS, 1);
+ }
+ }
}
VariantClear(&var_name);
@@ -335,31 +477,15 @@
ddi->info.dir = PJMEDIA_DIR_RENDER;
ddi->info.has_callback = PJ_FALSE;
ddi->info.caps = PJMEDIA_VID_DEV_CAP_FORMAT;
-
- for (c = 0; c < df->dev_count; c++) {
- unsigned i;
-
- ddi = &df->dev_info[c];
- ddi->info.fmt_cnt = sizeof(dshow_fmts)/sizeof(dshow_fmts[0]);
- ddi->info.fmt = (pjmedia_format*)
- pj_pool_calloc(df->dev_pool, ddi->info.fmt_cnt,
- sizeof(pjmedia_format));
-
- for (i = 0; i < ddi->info.fmt_cnt; i++) {
- pjmedia_format *fmt = &ddi->info.fmt[i];
-
- if (ddi->info.dir == PJMEDIA_DIR_RENDER && i > 0)
- break;
- pjmedia_format_init_video(fmt, dshow_fmts[i].pjmedia_format,
- DEFAULT_WIDTH, DEFAULT_HEIGHT,
- DEFAULT_FPS, 1);
- }
- }
-#endif
-
-
// TODO:
-// ddi->info.caps = PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW;
+// ddi->info.caps |= PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW;
+
+ ddi->info.fmt_cnt = 1;
+ ddi->info.fmt = PJ_POOL_ZALLOC_T(df->dev_pool, pjmedia_format);
+ pjmedia_format_init_video(&ddi->info.fmt[0], dshow_fmts[0].pjmedia_format,
+ DEFAULT_WIDTH, DEFAULT_HEIGHT,
+ DEFAULT_FPS, 1);
+#endif
PJ_LOG(4, (THIS_FILE, "DShow has %d devices:",
df->dev_count));
@@ -532,25 +658,8 @@
}
if (dir == PJMEDIA_DIR_CAPTURE) {
- IBindCtx *pbc;
-
- hr = CreateBindCtx(0, &pbc);
- if (SUCCEEDED (hr)) {
- IMoniker *moniker;
- DWORD pchEaten;
-
- hr = MkParseDisplayName(pbc,
- df->dev_info[id].display_name,
- &pchEaten, &moniker);
- if (SUCCEEDED(hr)) {
- hr = IMoniker_BindToObject(moniker, pbc, NULL,
- &IID_IBaseFilter,
- (LPVOID *)&graph->source_filter);
- IMoniker_Release(moniker);
- }
- IBindCtx_Release(pbc);
- }
- if (FAILED(hr)) {
+ hr = get_cap_device(df, id, &graph->source_filter);
+ if (FAILED(hr)) {
goto on_error;
}
} else {
@@ -594,94 +703,37 @@
vfd = pjmedia_format_get_video_format_detail(&strm->param.fmt, PJ_TRUE);
- IBaseFilter_EnumPins(graph->source_filter, &pEnum);
- if (SUCCEEDED(hr)) {
- // Loop through all the pins
- IPin *pPin = NULL;
+ enum_dev_cap(graph->source_filter, dir,
+ get_dshow_format_info(strm->param.fmt.id)->dshow_format,
+ &mediatype, &srcpin, NULL);
+ graph->mediatype = mediatype;
- while (IEnumPins_Next(pEnum, 1, &pPin, NULL) == S_OK) {
- PIN_DIRECTION pindirtmp;
- const GUID *dshow_format;
-
- dshow_format = get_dshow_format_info(strm->param.fmt.id)->
- dshow_format;
+ if (srcpin && dir == PJMEDIA_DIR_RENDER) {
+ mediatype = graph->mediatype = &mtype;
- hr = IPin_QueryDirection(pPin, &pindirtmp);
- if (hr != S_OK || pindirtmp != PINDIR_OUTPUT) {
- if (SUCCEEDED(hr))
- IPin_Release(pPin);
- continue;
- }
+ memset (mediatype, 0, sizeof(AM_MEDIA_TYPE));
+ mediatype->majortype = MEDIATYPE_Video;
+ mediatype->subtype = *(get_dshow_format_info(strm->param.fmt.id)->
+ dshow_format);
+ mediatype->bFixedSizeSamples = TRUE;
+ mediatype->bTemporalCompression = FALSE;
- if (dir == PJMEDIA_DIR_CAPTURE) {
- IAMStreamConfig *streamcaps;
+ vi = (VIDEOINFOHEADER *)
+ CoTaskMemAlloc(sizeof(VIDEOINFOHEADER));
+ memset (vi, 0, sizeof(VIDEOINFOHEADER));
+ mediatype->formattype = FORMAT_VideoInfo;
+ mediatype->cbFormat = sizeof(VIDEOINFOHEADER);
+ mediatype->pbFormat = (BYTE *)vi;
- hr = IPin_QueryInterface(pPin, &IID_IAMStreamConfig,
- (LPVOID *)&streamcaps);
- if (SUCCEEDED(hr)) {
- VIDEO_STREAM_CONFIG_CAPS vscc;
- int i, isize, icount;
+ vi->rcSource.bottom = vfd->size.h;
+ vi->rcSource.right = vfd->size.w;
+ vi->rcTarget.bottom = vfd->size.h;
+ vi->rcTarget.right = vfd->size.w;
- IAMStreamConfig_GetNumberOfCapabilities(streamcaps,
- &icount, &isize);
-
- for (i = 0; i < icount; i++) {
- RPC_STATUS rpcstatus, rpcstatus2;
-
- hr = IAMStreamConfig_GetStreamCaps(streamcaps, i,
- &mediatype,
- (BYTE *)&vscc);
- if (FAILED (hr))
- continue;
-
- if (UuidCompare(&mediatype->subtype,
- (UUID*)dshow_format,
- &rpcstatus) == 0 &&
- rpcstatus == RPC_S_OK &&
- UuidCompare(&mediatype->formattype,
- (UUID*)&FORMAT_VideoInfo,
- &rpcstatus2) == 0 &&
- rpcstatus2 == RPC_S_OK)
- {
- srcpin = pPin;
- graph->mediatype = mediatype;
- break;
- }
- }
- IAMStreamConfig_Release(streamcaps);
- }
- } else {
- srcpin = pPin;
- mediatype = graph->mediatype = &mtype;
-
- memset (mediatype, 0, sizeof(AM_MEDIA_TYPE));
- mediatype->majortype = MEDIATYPE_Video;
- mediatype->subtype = *dshow_format;
- mediatype->bFixedSizeSamples = TRUE;
- mediatype->bTemporalCompression = FALSE;
-
- vi = (VIDEOINFOHEADER *)
- CoTaskMemAlloc(sizeof(VIDEOINFOHEADER));
- memset (vi, 0, sizeof(VIDEOINFOHEADER));
- mediatype->formattype = FORMAT_VideoInfo;
- mediatype->cbFormat = sizeof(VIDEOINFOHEADER);
- mediatype->pbFormat = (BYTE *)vi;
-
- vi->rcSource.bottom = vfd->size.h;
- vi->rcSource.right = vfd->size.w;
- vi->rcTarget.bottom = vfd->size.h;
- vi->rcTarget.right = vfd->size.w;
-
- vi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- vi->bmiHeader.biPlanes = 1;
- vi->bmiHeader.biBitCount = vfi->bpp;
- vi->bmiHeader.biCompression = strm->param.fmt.id;
- }
- if (srcpin)
- break;
- IPin_Release(pPin);
- }
- IEnumPins_Release(pEnum);
+ vi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ vi->bmiHeader.biPlanes = 1;
+ vi->bmiHeader.biBitCount = vfi->bpp;
+ vi->bmiHeader.biCompression = strm->param.fmt.id;
}
if (!srcpin || !sinkpin || !mediatype) {