opts: add list device sources/sinks options
Allows to list sources/sinks of the devices that implement that functionality. Signed-off-by: Lukasz Marek <lukasz.m.luki2@gmail.com>
This commit is contained in:
parent
1cff908589
commit
5f55819850
181
cmdutils.c
181
cmdutils.c
@ -2055,3 +2055,184 @@ void *grow_array(void *array, int elem_size, int *size, int new_size)
|
|||||||
}
|
}
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_AVDEVICE
|
||||||
|
static int print_device_sources(AVInputFormat *fmt, AVDictionary *opts)
|
||||||
|
{
|
||||||
|
int ret, i;
|
||||||
|
AVFormatContext *dev = NULL;
|
||||||
|
AVDeviceInfoList *device_list = NULL;
|
||||||
|
AVDictionary *tmp_opts = NULL;
|
||||||
|
|
||||||
|
if (!fmt || !fmt->priv_class || !AV_IS_INPUT_DEVICE(fmt->priv_class->category))
|
||||||
|
return AVERROR(EINVAL);
|
||||||
|
|
||||||
|
printf("Audo-detected sources for %s:\n", fmt->name);
|
||||||
|
if (!fmt->get_device_list) {
|
||||||
|
ret = AVERROR(ENOSYS);
|
||||||
|
printf("Cannot list sources. Not implemented.\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: avformat_open_input calls read_header callback which is not necessary.
|
||||||
|
Function like avformat_alloc_output_context2 for input could be helpful here. */
|
||||||
|
av_dict_copy(&tmp_opts, opts, 0);
|
||||||
|
if ((ret = avformat_open_input(&dev, NULL, fmt, &tmp_opts)) < 0) {
|
||||||
|
printf("Cannot open device: %s.\n", fmt->name);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = avdevice_list_devices(dev, &device_list)) < 0) {
|
||||||
|
printf("Cannot list sources.\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < device_list->nb_devices; i++) {
|
||||||
|
printf("%s %s [%s]\n", device_list->default_device == i ? "*" : " ",
|
||||||
|
device_list->devices[i]->device_name, device_list->devices[i]->device_description);
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
av_dict_free(&tmp_opts);
|
||||||
|
avdevice_free_list_devices(&device_list);
|
||||||
|
avformat_close_input(&dev);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int print_device_sinks(AVOutputFormat *fmt, AVDictionary *opts)
|
||||||
|
{
|
||||||
|
int ret, i;
|
||||||
|
AVFormatContext *dev = NULL;
|
||||||
|
AVDeviceInfoList *device_list = NULL;
|
||||||
|
AVDictionary *tmp_opts = NULL;
|
||||||
|
|
||||||
|
if (!fmt || !fmt->priv_class || !AV_IS_OUTPUT_DEVICE(fmt->priv_class->category))
|
||||||
|
return AVERROR(EINVAL);
|
||||||
|
|
||||||
|
printf("Audo-detected sinks for %s:\n", fmt->name);
|
||||||
|
if (!fmt->get_device_list) {
|
||||||
|
ret = AVERROR(ENOSYS);
|
||||||
|
printf("Cannot list sinks. Not implemented.\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = avformat_alloc_output_context2(&dev, fmt, NULL, NULL)) < 0) {
|
||||||
|
printf("Cannot open device: %s.\n", fmt->name);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
av_dict_copy(&tmp_opts, opts, 0);
|
||||||
|
av_opt_set_dict2(dev, &tmp_opts, AV_OPT_SEARCH_CHILDREN);
|
||||||
|
|
||||||
|
if ((ret = avdevice_list_devices(dev, &device_list)) < 0) {
|
||||||
|
printf("Cannot list sinks.\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < device_list->nb_devices; i++) {
|
||||||
|
printf("%s %s [%s]\n", device_list->default_device == i ? "*" : " ",
|
||||||
|
device_list->devices[i]->device_name, device_list->devices[i]->device_description);
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
av_dict_free(&tmp_opts);
|
||||||
|
avdevice_free_list_devices(&device_list);
|
||||||
|
avformat_free_context(dev);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int show_sinks_sources_parse_arg(const char *arg, char **dev, AVDictionary **opts)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
if (arg) {
|
||||||
|
char *opts_str = NULL;
|
||||||
|
av_assert0(dev && opts);
|
||||||
|
*dev = av_strdup(arg);
|
||||||
|
if (!*dev)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
if ((opts_str = strchr(*dev, ','))) {
|
||||||
|
*(opts_str++) = '\0';
|
||||||
|
if (opts_str[0] && ((ret = av_dict_parse_string(opts, opts_str, "=", ":", 0)) < 0)) {
|
||||||
|
av_freep(dev);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
printf("\nDevice name is not provided.\n"
|
||||||
|
"You can pass devicename[,opt1=val1[,opt2=val2...]] as an argument.\n\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int show_sources(void *optctx, const char *opt, const char *arg)
|
||||||
|
{
|
||||||
|
AVInputFormat *fmt = NULL;
|
||||||
|
char *dev = NULL;
|
||||||
|
AVDictionary *opts = NULL;
|
||||||
|
int ret = 0;
|
||||||
|
int error_level = av_log_get_level();
|
||||||
|
|
||||||
|
av_log_set_level(AV_LOG_ERROR);
|
||||||
|
|
||||||
|
if ((ret = show_sinks_sources_parse_arg(arg, &dev, &opts)) < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
do {
|
||||||
|
fmt = av_input_audio_device_next(fmt);
|
||||||
|
if (fmt) {
|
||||||
|
if (!strcmp(fmt->name, "lavfi"))
|
||||||
|
continue; //it's pointless to probe lavfi
|
||||||
|
if (dev && strcmp(fmt->name, dev))
|
||||||
|
continue;
|
||||||
|
print_device_sources(fmt, opts);
|
||||||
|
}
|
||||||
|
} while (fmt);
|
||||||
|
do {
|
||||||
|
fmt = av_input_video_device_next(fmt);
|
||||||
|
if (fmt) {
|
||||||
|
if (dev && strcmp(fmt->name, dev))
|
||||||
|
continue;
|
||||||
|
print_device_sources(fmt, opts);
|
||||||
|
}
|
||||||
|
} while (fmt);
|
||||||
|
fail:
|
||||||
|
av_dict_free(&opts);
|
||||||
|
av_free(dev);
|
||||||
|
av_log_set_level(error_level);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int show_sinks(void *optctx, const char *opt, const char *arg)
|
||||||
|
{
|
||||||
|
AVOutputFormat *fmt = NULL;
|
||||||
|
char *dev = NULL;
|
||||||
|
AVDictionary *opts = NULL;
|
||||||
|
int ret = 0;
|
||||||
|
int error_level = av_log_get_level();
|
||||||
|
|
||||||
|
av_log_set_level(AV_LOG_ERROR);
|
||||||
|
|
||||||
|
if ((ret = show_sinks_sources_parse_arg(arg, &dev, &opts)) < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
do {
|
||||||
|
fmt = av_output_audio_device_next(fmt);
|
||||||
|
if (fmt) {
|
||||||
|
if (dev && strcmp(fmt->name, dev))
|
||||||
|
continue;
|
||||||
|
print_device_sinks(fmt, opts);
|
||||||
|
}
|
||||||
|
} while (fmt);
|
||||||
|
do {
|
||||||
|
fmt = av_output_video_device_next(fmt);
|
||||||
|
if (fmt) {
|
||||||
|
if (dev && strcmp(fmt->name, dev))
|
||||||
|
continue;
|
||||||
|
print_device_sinks(fmt, opts);
|
||||||
|
}
|
||||||
|
} while (fmt);
|
||||||
|
fail:
|
||||||
|
av_dict_free(&opts);
|
||||||
|
av_free(dev);
|
||||||
|
av_log_set_level(error_level);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
14
cmdutils.h
14
cmdutils.h
@ -443,6 +443,20 @@ int show_formats(void *optctx, const char *opt, const char *arg);
|
|||||||
*/
|
*/
|
||||||
int show_devices(void *optctx, const char *opt, const char *arg);
|
int show_devices(void *optctx, const char *opt, const char *arg);
|
||||||
|
|
||||||
|
#if CONFIG_AVDEVICE
|
||||||
|
/**
|
||||||
|
* Print a listing containing audodetected sinks of the output device.
|
||||||
|
* Device name with options may be passed as an argument to limit results.
|
||||||
|
*/
|
||||||
|
int show_sinks(void *optctx, const char *opt, const char *arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print a listing containing audodetected sources of the input device.
|
||||||
|
* Device name with options may be passed as an argument to limit results.
|
||||||
|
*/
|
||||||
|
int show_sources(void *optctx, const char *opt, const char *arg);
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print a listing containing all the codecs supported by the
|
* Print a listing containing all the codecs supported by the
|
||||||
* program.
|
* program.
|
||||||
|
@ -27,3 +27,9 @@
|
|||||||
{ "opencl_bench", OPT_EXIT, {.func_arg = opt_opencl_bench}, "run benchmark on all OpenCL devices and show results" },
|
{ "opencl_bench", OPT_EXIT, {.func_arg = opt_opencl_bench}, "run benchmark on all OpenCL devices and show results" },
|
||||||
{ "opencl_options", HAS_ARG, {.func_arg = opt_opencl}, "set OpenCL environment options" },
|
{ "opencl_options", HAS_ARG, {.func_arg = opt_opencl}, "set OpenCL environment options" },
|
||||||
#endif
|
#endif
|
||||||
|
#if CONFIG_AVDEVICE
|
||||||
|
{ "sources" , OPT_EXIT | HAS_ARG, { .func_arg = show_sources },
|
||||||
|
"list sources of the input device", "device" },
|
||||||
|
{ "sinks" , OPT_EXIT | HAS_ARG, { .func_arg = show_sinks },
|
||||||
|
"list sinks of the output device", "device" },
|
||||||
|
#endif
|
||||||
|
@ -141,6 +141,22 @@ Show channel names and standard channel layouts.
|
|||||||
@item -colors
|
@item -colors
|
||||||
Show recognized color names.
|
Show recognized color names.
|
||||||
|
|
||||||
|
@item -sources @var{device}[,@var{opt1}=@var{val1}[,@var{opt2}=@var{val2}]...]
|
||||||
|
Show autodetected sources of the intput device.
|
||||||
|
Some devices may provide system-dependent source names that cannot be autodetected.
|
||||||
|
The returned list cannot be assumed to be always complete.
|
||||||
|
@example
|
||||||
|
ffmpeg -sources pulse,server=192.168.0.4
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@item -sinks @var{device}[,@var{opt1}=@var{val1}[,@var{opt2}=@var{val2}]...]
|
||||||
|
Show autodetected sinks of the output device.
|
||||||
|
Some devices may provide system-dependent sink names that cannot be autodetected.
|
||||||
|
The returned list cannot be assumed to be always complete.
|
||||||
|
@example
|
||||||
|
ffmpeg -sinks pulse,server=192.168.0.4
|
||||||
|
@end example
|
||||||
|
|
||||||
@item -loglevel [repeat+]@var{loglevel} | -v [repeat+]@var{loglevel}
|
@item -loglevel [repeat+]@var{loglevel} | -v [repeat+]@var{loglevel}
|
||||||
Set the logging level used by the library.
|
Set the logging level used by the library.
|
||||||
Adding "repeat+" indicates that repeated log output should not be compressed
|
Adding "repeat+" indicates that repeated log output should not be compressed
|
||||||
|
Loading…
x
Reference in New Issue
Block a user