dshow: some devices only list themselves under "Video sources" but

actually have both video and audio output pins, so make the audio pins
accessible by video source name.

Signed-off-by: rogerdpack <rogerpack2005@gmail.com>
pull/105/head
rogerdpack 10 years ago
parent 5d72cf0f64
commit a35da0920d
  1. 81
      libavdevice/dshow.c
  2. 5
      libavdevice/dshow_capture.h

@ -203,7 +203,7 @@ fail:
*/ */
static int static int
dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum, dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum,
enum dshowDeviceType devtype, IBaseFilter **pfilter) enum dshowDeviceType devtype, enum dshowSourceFilterType sourcetype, IBaseFilter **pfilter)
{ {
struct dshow_ctx *ctx = avctx->priv_data; struct dshow_ctx *ctx = avctx->priv_data;
IBaseFilter *device_filter = NULL; IBaseFilter *device_filter = NULL;
@ -216,12 +216,13 @@ dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum,
const GUID *device_guid[2] = { &CLSID_VideoInputDeviceCategory, const GUID *device_guid[2] = { &CLSID_VideoInputDeviceCategory,
&CLSID_AudioInputDeviceCategory }; &CLSID_AudioInputDeviceCategory };
const char *devtypename = (devtype == VideoDevice) ? "video" : "audio"; const char *devtypename = (devtype == VideoDevice) ? "video" : "audio only";
const char *sourcetypename = (sourcetype == VideoSourceDevice) ? "video" : "audio";
r = ICreateDevEnum_CreateClassEnumerator(devenum, device_guid[devtype], r = ICreateDevEnum_CreateClassEnumerator(devenum, device_guid[sourcetype],
(IEnumMoniker **) &classenum, 0); (IEnumMoniker **) &classenum, 0);
if (r != S_OK) { if (r != S_OK) {
av_log(avctx, AV_LOG_ERROR, "Could not enumerate %s devices.\n", av_log(avctx, AV_LOG_ERROR, "Could not enumerate %s devices (or none found).\n",
devtypename); devtypename);
return AVERROR(EIO); return AVERROR(EIO);
} }
@ -253,7 +254,6 @@ dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum,
unique_name[i] = '_'; unique_name[i] = '_';
} }
r = IMoniker_BindToStorage(m, 0, 0, &IID_IPropertyBag, (void *) &bag); r = IMoniker_BindToStorage(m, 0, 0, &IID_IPropertyBag, (void *) &bag);
if (r != S_OK) if (r != S_OK)
goto fail1; goto fail1;
@ -262,10 +262,9 @@ dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum,
r = IPropertyBag_Read(bag, L"FriendlyName", &var, NULL); r = IPropertyBag_Read(bag, L"FriendlyName", &var, NULL);
if (r != S_OK) if (r != S_OK)
goto fail1; goto fail1;
friendly_name = dup_wchar_to_utf8(var.bstrVal); friendly_name = dup_wchar_to_utf8(var.bstrVal);
if (pfilter) { if (pfilter) {
if (strcmp(device_name, friendly_name) && strcmp(device_name, unique_name)) if (strcmp(device_name, friendly_name) && strcmp(device_name, unique_name))
goto fail1; goto fail1;
@ -291,15 +290,14 @@ fail1:
if (bag) if (bag)
IPropertyBag_Release(bag); IPropertyBag_Release(bag);
IMoniker_Release(m); IMoniker_Release(m);
} }
IEnumMoniker_Release(classenum); IEnumMoniker_Release(classenum);
if (pfilter) { if (pfilter) {
if (!device_filter) { if (!device_filter) {
av_log(avctx, AV_LOG_ERROR, "Could not find %s device.\n", av_log(avctx, AV_LOG_ERROR, "Could not find %s device with name [%s] among source devices of type %s.\n",
devtypename); devtypename, device_name, sourcetypename);
return AVERROR(EIO); return AVERROR(EIO);
} }
*pfilter = device_filter; *pfilter = device_filter;
@ -510,7 +508,7 @@ dshow_show_filter_properties(IBaseFilter *device_filter, AVFormatContext *avctx)
ISpecifyPropertyPages *property_pages = NULL; ISpecifyPropertyPages *property_pages = NULL;
IUnknown *device_filter_iunknown = NULL; IUnknown *device_filter_iunknown = NULL;
HRESULT hr; HRESULT hr;
FILTER_INFO filter_info = {0}; /* a warning on this line is false positive GCC bug 53119 */ FILTER_INFO filter_info = {0}; /* a warning on this line is false positive GCC bug 53119 AFAICT */
CAUUID ca_guid = {0}; CAUUID ca_guid = {0};
hr = IBaseFilter_QueryInterface(device_filter, &IID_ISpecifyPropertyPages, (void **)&property_pages); hr = IBaseFilter_QueryInterface(device_filter, &IID_ISpecifyPropertyPages, (void **)&property_pages);
@ -557,7 +555,7 @@ end:
*/ */
static int static int
dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype, dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype,
IBaseFilter *device_filter, IPin **ppin) enum dshowSourceFilterType sourcetype, IBaseFilter *device_filter, IPin **ppin)
{ {
struct dshow_ctx *ctx = avctx->priv_data; struct dshow_ctx *ctx = avctx->priv_data;
IEnumPins *pins = 0; IEnumPins *pins = 0;
@ -566,7 +564,8 @@ dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype,
int r; int r;
const GUID *mediatype[2] = { &MEDIATYPE_Video, &MEDIATYPE_Audio }; const GUID *mediatype[2] = { &MEDIATYPE_Video, &MEDIATYPE_Audio };
const char *devtypename = (devtype == VideoDevice) ? "video" : "audio"; const char *devtypename = (devtype == VideoDevice) ? "video" : "audio only";
const char *sourcetypename = (sourcetype == VideoSourceDevice) ? "video" : "audio";
int set_format = (devtype == VideoDevice && (ctx->framerate || int set_format = (devtype == VideoDevice && (ctx->framerate ||
(ctx->requested_width && ctx->requested_height) || (ctx->requested_width && ctx->requested_height) ||
@ -586,9 +585,10 @@ dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype,
} }
if (!ppin) { if (!ppin) {
av_log(avctx, AV_LOG_INFO, "DirectShow %s device options\n", av_log(avctx, AV_LOG_INFO, "DirectShow %s device options (from %s devices)\n",
devtypename); devtypename, sourcetypename);
} }
while (!device_pin && IEnumPins_Next(pins, 1, &pin, NULL) == S_OK) { while (!device_pin && IEnumPins_Next(pins, 1, &pin, NULL) == S_OK) {
IKsPropertySet *p = NULL; IKsPropertySet *p = NULL;
IEnumMediaTypes *types = NULL; IEnumMediaTypes *types = NULL;
@ -622,12 +622,12 @@ dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype,
} }
pin_buf = dup_wchar_to_utf8(pin_id); pin_buf = dup_wchar_to_utf8(pin_id);
if (!ppin) { if (!ppin) {
av_log(avctx, AV_LOG_INFO, " Pin \"%s\" (alternative pin name \"%s\")\n", name_buf, pin_buf); av_log(avctx, AV_LOG_INFO, " Pin \"%s\" (alternative pin name \"%s\")\n", name_buf, pin_buf);
dshow_cycle_formats(avctx, devtype, pin, NULL); dshow_cycle_formats(avctx, devtype, pin, NULL);
goto next; goto next;
} }
if (desired_pin_name) { if (desired_pin_name) {
if(strcmp(name_buf, desired_pin_name) && strcmp(pin_buf, desired_pin_name)) { if(strcmp(name_buf, desired_pin_name) && strcmp(pin_buf, desired_pin_name)) {
av_log(avctx, AV_LOG_DEBUG, "skipping pin \"%s\" (\"%s\") != requested \"%s\"\n", av_log(avctx, AV_LOG_DEBUG, "skipping pin \"%s\" (\"%s\") != requested \"%s\"\n",
@ -694,29 +694,30 @@ next:
} }
/** /**
* List options for device with type devtype. * List options for device with type devtype, source filter type sourcetype
* *
* @param devenum device enumerator used for accessing the device * @param devenum device enumerator used for accessing the device
*/ */
static int static int
dshow_list_device_options(AVFormatContext *avctx, ICreateDevEnum *devenum, dshow_list_device_options(AVFormatContext *avctx, ICreateDevEnum *devenum,
enum dshowDeviceType devtype) enum dshowDeviceType devtype, enum dshowSourceFilterType sourcetype)
{ {
struct dshow_ctx *ctx = avctx->priv_data; struct dshow_ctx *ctx = avctx->priv_data;
IBaseFilter *device_filter = NULL; IBaseFilter *device_filter = NULL;
int r; int r;
if ((r = dshow_cycle_devices(avctx, devenum, devtype, &device_filter)) < 0) if ((r = dshow_cycle_devices(avctx, devenum, devtype, sourcetype, &device_filter)) < 0)
return r; return r;
ctx->device_filter[devtype] = device_filter; ctx->device_filter[devtype] = device_filter;
if ((r = dshow_cycle_pins(avctx, devtype, device_filter, NULL)) < 0) if ((r = dshow_cycle_pins(avctx, devtype, sourcetype, device_filter, NULL)) < 0)
return r; return r;
return 0; return 0;
} }
static int static int
dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum, enum dshowDeviceType devtype) dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
enum dshowDeviceType devtype, enum dshowSourceFilterType sourcetype)
{ {
struct dshow_ctx *ctx = avctx->priv_data; struct dshow_ctx *ctx = avctx->priv_data;
IBaseFilter *device_filter = NULL; IBaseFilter *device_filter = NULL;
@ -730,7 +731,7 @@ dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum, enum dshowDev
const wchar_t *filter_name[2] = { L"Audio capture filter", L"Video capture filter" }; const wchar_t *filter_name[2] = { L"Audio capture filter", L"Video capture filter" };
if ((r = dshow_cycle_devices(avctx, devenum, devtype, &device_filter)) < 0) { if ((r = dshow_cycle_devices(avctx, devenum, devtype, sourcetype, &device_filter)) < 0) {
ret = r; ret = r;
goto error; goto error;
} }
@ -743,7 +744,7 @@ dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum, enum dshowDev
goto error; goto error;
} }
if ((r = dshow_cycle_pins(avctx, devtype, device_filter, &device_pin)) < 0) { if ((r = dshow_cycle_pins(avctx, devtype, sourcetype, device_filter, &device_pin)) < 0) {
ret = r; ret = r;
goto error; goto error;
} }
@ -1010,38 +1011,46 @@ static int dshow_read_header(AVFormatContext *avctx)
} }
if (ctx->list_devices) { if (ctx->list_devices) {
av_log(avctx, AV_LOG_INFO, "DirectShow video devices\n"); av_log(avctx, AV_LOG_INFO, "DirectShow video devices (some may be both video and audio devices)\n");
dshow_cycle_devices(avctx, devenum, VideoDevice, NULL); dshow_cycle_devices(avctx, devenum, VideoDevice, VideoSourceDevice, NULL);
av_log(avctx, AV_LOG_INFO, "DirectShow audio devices\n"); av_log(avctx, AV_LOG_INFO, "DirectShow audio devices\n");
dshow_cycle_devices(avctx, devenum, AudioDevice, NULL); dshow_cycle_devices(avctx, devenum, AudioDevice, AudioSourceDevice, NULL);
ret = AVERROR_EXIT; ret = AVERROR_EXIT;
goto error; goto error;
} }
if (ctx->list_options) { if (ctx->list_options) {
if (ctx->device_name[VideoDevice]) if (ctx->device_name[VideoDevice])
if ((r = dshow_list_device_options(avctx, devenum, VideoDevice))) { if ((r = dshow_list_device_options(avctx, devenum, VideoDevice, VideoSourceDevice))) {
ret = r; ret = r;
goto error; goto error;
} }
if (ctx->device_name[AudioDevice]) if (ctx->device_name[AudioDevice]) {
if ((r = dshow_list_device_options(avctx, devenum, AudioDevice))) { if (dshow_list_device_options(avctx, devenum, AudioDevice, AudioSourceDevice)) {
ret = r; /* show audio options from combined video+audio sources as fallback */
goto error; if ((r = dshow_list_device_options(avctx, devenum, AudioDevice, VideoSourceDevice))) {
ret = r;
goto error;
}
} }
}
} }
if (ctx->device_name[VideoDevice]) { if (ctx->device_name[VideoDevice]) {
if ((r = dshow_open_device(avctx, devenum, VideoDevice)) < 0 || if ((r = dshow_open_device(avctx, devenum, VideoDevice, VideoSourceDevice)) < 0 ||
(r = dshow_add_device(avctx, VideoDevice)) < 0) { (r = dshow_add_device(avctx, VideoDevice)) < 0) {
ret = r; ret = r;
goto error; goto error;
} }
} }
if (ctx->device_name[AudioDevice]) { if (ctx->device_name[AudioDevice]) {
if ((r = dshow_open_device(avctx, devenum, AudioDevice)) < 0 || if ((r = dshow_open_device(avctx, devenum, AudioDevice, AudioSourceDevice)) < 0 ||
(r = dshow_add_device(avctx, AudioDevice)) < 0) { (r = dshow_add_device(avctx, AudioDevice)) < 0) {
ret = r; av_log(avctx, AV_LOG_INFO, "Searching for audio device within video devices %s\n", ctx->device_name[AudioDevice]);
goto error; /* see if there's a video source with an audio pin with the given audio name */
if ((r = dshow_open_device(avctx, devenum, AudioDevice, VideoSourceDevice)) < 0 ||
(r = dshow_add_device(avctx, AudioDevice)) < 0) {
ret = r;
goto error;
}
} }
} }
if (ctx->list_options) { if (ctx->list_options) {

@ -65,6 +65,11 @@ enum dshowDeviceType {
AudioDevice = 1, AudioDevice = 1,
}; };
enum dshowSourceFilterType {
VideoSourceDevice = 0,
AudioSourceDevice = 1,
};
#define DECLARE_QUERYINTERFACE(class, ...) \ #define DECLARE_QUERYINTERFACE(class, ...) \
long WINAPI \ long WINAPI \
class##_QueryInterface(class *this, const GUID *riid, void **ppvObject) \ class##_QueryInterface(class *this, const GUID *riid, void **ppvObject) \

Loading…
Cancel
Save