+
+#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