|
|
|
@@ -40,6 +40,8 @@ struct dshow_ctx { |
|
|
|
int list_options; |
|
|
|
int list_devices; |
|
|
|
int audio_buffer_size; |
|
|
|
char *video_pin_name; |
|
|
|
char *audio_pin_name; |
|
|
|
|
|
|
|
IBaseFilter *device_filter[2]; |
|
|
|
IPin *device_pin[2]; |
|
|
|
@@ -269,8 +271,31 @@ dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum, |
|
|
|
|
|
|
|
while (!device_filter && IEnumMoniker_Next(classenum, 1, &m, NULL) == S_OK) { |
|
|
|
IPropertyBag *bag = NULL; |
|
|
|
char *buf = NULL; |
|
|
|
char *friendly_name = NULL; |
|
|
|
char *unique_name = NULL; |
|
|
|
VARIANT var; |
|
|
|
IBindCtx *bind_ctx = NULL; |
|
|
|
LPOLESTR olestr = NULL; |
|
|
|
LPMALLOC co_malloc = NULL; |
|
|
|
int i; |
|
|
|
|
|
|
|
r = CoGetMalloc(1, &co_malloc); |
|
|
|
if (r = S_OK) |
|
|
|
goto fail1; |
|
|
|
r = CreateBindCtx(0, &bind_ctx); |
|
|
|
if (r != S_OK) |
|
|
|
goto fail1; |
|
|
|
/* GetDisplayname works for both video and audio, DevicePath doesn't */ |
|
|
|
r = IMoniker_GetDisplayName(m, bind_ctx, NULL, &olestr); |
|
|
|
if (r != S_OK) |
|
|
|
goto fail1; |
|
|
|
unique_name = dup_wchar_to_utf8(olestr); |
|
|
|
/* replace ':' with '_' since we use : to delineate between sources */ |
|
|
|
for (i = 0; i < strlen(unique_name); i++) { |
|
|
|
if (unique_name[i] == ':') |
|
|
|
unique_name[i] = '_'; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
r = IMoniker_BindToStorage(m, 0, 0, &IID_IPropertyBag, (void *) &bag); |
|
|
|
if (r != S_OK) |
|
|
|
@@ -281,23 +306,35 @@ dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum, |
|
|
|
if (r != S_OK) |
|
|
|
goto fail1; |
|
|
|
|
|
|
|
buf = dup_wchar_to_utf8(var.bstrVal); |
|
|
|
friendly_name = dup_wchar_to_utf8(var.bstrVal); |
|
|
|
|
|
|
|
if (pfilter) { |
|
|
|
if (strcmp(device_name, buf)) |
|
|
|
if (pfilter) { |
|
|
|
if (strcmp(device_name, friendly_name) && strcmp(device_name, unique_name)) |
|
|
|
goto fail1; |
|
|
|
|
|
|
|
if (!skip--) |
|
|
|
IMoniker_BindToObject(m, 0, 0, &IID_IBaseFilter, (void *) &device_filter); |
|
|
|
if (!skip--) { |
|
|
|
r = IMoniker_BindToObject(m, 0, 0, &IID_IBaseFilter, (void *) &device_filter); |
|
|
|
if (r != S_OK) { |
|
|
|
av_log(avctx, AV_LOG_ERROR, "Unable to BindToObject for %s\n", device_name); |
|
|
|
goto fail1; |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
av_log(avctx, AV_LOG_INFO, " \"%s\"\n", buf); |
|
|
|
av_log(avctx, AV_LOG_INFO, " \"%s\"\n", friendly_name); |
|
|
|
av_log(avctx, AV_LOG_INFO, " Alternative name \"%s\"\n", unique_name); |
|
|
|
} |
|
|
|
|
|
|
|
fail1: |
|
|
|
av_free(buf); |
|
|
|
if (olestr && co_malloc) |
|
|
|
IMalloc_Free(co_malloc, olestr); |
|
|
|
if (bind_ctx) |
|
|
|
IBindCtx_Release(bind_ctx); |
|
|
|
av_free(friendly_name); |
|
|
|
av_free(unique_name); |
|
|
|
if (bag) |
|
|
|
IPropertyBag_Release(bag); |
|
|
|
IMoniker_Release(m); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
IEnumMoniker_Release(classenum); |
|
|
|
@@ -550,6 +587,10 @@ dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype, |
|
|
|
AM_MEDIA_TYPE *type; |
|
|
|
GUID category; |
|
|
|
DWORD r2; |
|
|
|
char *name_buf = NULL; |
|
|
|
wchar_t *pin_id = NULL; |
|
|
|
char *pin_buf = NULL; |
|
|
|
char *desired_pin_name = devtype == VideoDevice ? ctx->video_pin_name : ctx->audio_pin_name; |
|
|
|
|
|
|
|
IPin_QueryPinInfo(pin, &info); |
|
|
|
IBaseFilter_Release(info.pFilter); |
|
|
|
@@ -563,14 +604,29 @@ dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype, |
|
|
|
goto next; |
|
|
|
if (!IsEqualGUID(&category, &PIN_CATEGORY_CAPTURE)) |
|
|
|
goto next; |
|
|
|
name_buf = dup_wchar_to_utf8(info.achName); |
|
|
|
|
|
|
|
r = IPin_QueryId(pin, &pin_id); |
|
|
|
if (r != S_OK) { |
|
|
|
av_log(avctx, AV_LOG_ERROR, "Could not query pin id\n"); |
|
|
|
return AVERROR(EIO); |
|
|
|
} |
|
|
|
pin_buf = dup_wchar_to_utf8(pin_id); |
|
|
|
|
|
|
|
|
|
|
|
if (!ppin) { |
|
|
|
char *buf = dup_wchar_to_utf8(info.achName); |
|
|
|
av_log(avctx, AV_LOG_INFO, " Pin \"%s\"\n", buf); |
|
|
|
av_free(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); |
|
|
|
goto next; |
|
|
|
} |
|
|
|
if (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", |
|
|
|
name_buf, pin_buf, desired_pin_name); |
|
|
|
goto next; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (set_format) { |
|
|
|
dshow_cycle_formats(avctx, devtype, pin, &format_set); |
|
|
|
if (!format_set) { |
|
|
|
@@ -590,6 +646,7 @@ dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype, |
|
|
|
while (!device_pin && IEnumMediaTypes_Next(types, 1, &type, NULL) == S_OK) { |
|
|
|
if (IsEqualGUID(&type->majortype, mediatype[devtype])) { |
|
|
|
device_pin = pin; |
|
|
|
av_log(avctx, AV_LOG_DEBUG, "Selecting pin %s on %s\n", name_buf, devtypename); |
|
|
|
goto next; |
|
|
|
} |
|
|
|
CoTaskMemFree(type); |
|
|
|
@@ -602,6 +659,11 @@ next: |
|
|
|
IKsPropertySet_Release(p); |
|
|
|
if (device_pin != pin) |
|
|
|
IPin_Release(pin); |
|
|
|
av_free(name_buf); |
|
|
|
av_free(pin_buf); |
|
|
|
if (pin_id) |
|
|
|
CoTaskMemFree(pin_id); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
IEnumPins_Release(pins); |
|
|
|
@@ -1066,6 +1128,7 @@ static const AVOption options[] = { |
|
|
|
{ "sample_rate", "set audio sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC }, |
|
|
|
{ "sample_size", "set audio sample size", OFFSET(sample_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 16, DEC }, |
|
|
|
{ "channels", "set number of audio channels, such as 1 or 2", OFFSET(channels), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC }, |
|
|
|
{ "audio_buffer_size", "set audio device buffer latency size in milliseconds (default is the device's default)", OFFSET(audio_buffer_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC }, |
|
|
|
{ "list_devices", "list available devices", OFFSET(list_devices), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, DEC, "list_devices" }, |
|
|
|
{ "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, DEC, "list_devices" }, |
|
|
|
{ "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, DEC, "list_devices" }, |
|
|
|
@@ -1074,7 +1137,8 @@ static const AVOption options[] = { |
|
|
|
{ "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, DEC, "list_options" }, |
|
|
|
{ "video_device_number", "set video device number for devices with same name (starts at 0)", OFFSET(video_device_number), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC }, |
|
|
|
{ "audio_device_number", "set audio device number for devices with same name (starts at 0)", OFFSET(audio_device_number), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC }, |
|
|
|
{ "audio_buffer_size", "set audio device buffer latency size in milliseconds (default is the device's default)", OFFSET(audio_buffer_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC }, |
|
|
|
{ "video_pin_name", "select video capture pin by name", OFFSET(video_pin_name),AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM }, |
|
|
|
{ "audio_pin_name", "select audio capture pin by name", OFFSET(audio_pin_name),AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM }, |
|
|
|
{ NULL }, |
|
|
|
}; |
|
|
|
|
|
|
|
|