diff mbox series

[FFmpeg-devel,10/35] fftools: provide media type info for devices

Message ID 20210607230414.612-11-dcnieho@gmail.com
State Superseded, archived
Headers show
Series avdevice (mostly dshow) enhancements
Related show

Checks

Context Check Description
andriy/x86_make success Make finished
andriy/x86_make_fate success Make fate finished
andriy/PPC64_make success Make finished
andriy/PPC64_make_fate success Make fate finished

Commit Message

Diederick C. Niehorster June 7, 2021, 11:03 p.m. UTC
fftools now print info about what media type(s), if any, are provided by sink and source avdevices. Furthermore, printing is done with av_log instead of printf as the latter doesn't handle characters in some device names correctly (e.g. "Microphone Array (Intel® Smart Sound Technology (Intel® SST))" is printed incorrectly).

Signed-off-by: Diederick Niehorster <dcnieho@gmail.com>
---
 fftools/cmdutils.c | 41 +++++++++++++++++++++++++++++++----------
 1 file changed, 31 insertions(+), 10 deletions(-)

Comments

Nicolas George June 8, 2021, 11:57 a.m. UTC | #1
Diederick Niehorster (12021-06-08):
> fftools now print info about what media type(s), if any, are provided
> by sink and source avdevices. Furthermore, printing is done with
> av_log instead of printf as the latter doesn't handle characters in
> some device names correctly (e.g. "Microphone Array (Intel® Smart
> Sound Technology (Intel® SST))" is printed incorrectly).
> 
> Signed-off-by: Diederick Niehorster <dcnieho@gmail.com>
> ---
>  fftools/cmdutils.c | 41 +++++++++++++++++++++++++++++++----------
>  1 file changed, 31 insertions(+), 10 deletions(-)

The feature looks useful. But the printing must go to stdout, not to
logging, because it is meant to be readable by scripts.

Regards,
Diederick C. Niehorster June 8, 2021, 8:10 p.m. UTC | #2
On Tue, Jun 8, 2021 at 1:57 PM Nicolas George <george@nsup.org> wrote:
>
> The feature looks useful. But the printing must go to stdout, not to
> logging, because it is meant to be readable by scripts.


Done. Only problem is that now a device of mine that should be called
"Microphone Array (Intel® Smart Sound Technology (Intel® SST))" is
instead printed as "Intel® Smart Sound Technology (Intel® SST)".
Since devices are selected by name for some avdevices (dshow), thats
an issue.

Googling tells me that printing UTF-8 (which is whats returned by
dshow's get_device_list) with printf is complicated to say the least
on Windows. It all works when logging because log.c has implemented
win_console_puts(), which looks like it would be easy to make
available more broadly.

Do you see a solution that would allow printing the device name correctly?

Thanks!
Dee
Nicolas George June 9, 2021, 11:15 a.m. UTC | #3
Diederick C. Niehorster (12021-06-08):
> Done. Only problem is that now a device of mine that should be called
> "Microphone Array (Intel® Smart Sound Technology (Intel® SST))" is
> instead printed as "Intel® Smart Sound Technology (Intel® SST)".
> Since devices are selected by name for some avdevices (dshow), thats
> an issue.
> 
> Googling tells me that printing UTF-8 (which is whats returned by
> dshow's get_device_list) with printf is complicated to say the least
> on Windows. It all works when logging because log.c has implemented
> win_console_puts(), which looks like it would be easy to make
> available more broadly.
> 
> Do you see a solution that would allow printing the device name correctly?

What matters is not what you see in the console but what data is really
written on the stream. Programs that read from the ffmpeg process and
use the output to build a command line, all in a binary-clean way,
should succeed.

You can test with Perl (you can probably achieve the same with any
language, but I know Perl, and I know it will not automagically mess
things up):

my $out = `ffmpeg -devices`;
my $dev = $out =~ /(Microphone.*)/;
print "Using \"$dev\"\n";
system "ffmpeg", "-f", "dshow", "-i", $dev;

If the “Using "..."” message is mangled but the command line succeeds,
then the issue is not ffmpeg's problem.

Another test you can run: take a Matroska file with accents in the
metadata, make sure it standard-compliant, and see what ffprobe
-show_stream prints about it.

Regards,
Diederick C. Niehorster June 9, 2021, 6:08 p.m. UTC | #4
On Wed, Jun 9, 2021 at 1:15 PM Nicolas George <george@nsup.org> wrote:
>
> What matters is not what you see in the console but what data is really
> written on the stream. Programs that read from the ffmpeg process and
> use the output to build a command line, all in a binary-clean way,
> should succeed.
>
> You can test with Perl (you can probably achieve the same with any
> language, but I know Perl, and I know it will not automagically mess
> things up):
>
> my $out = `ffmpeg -devices`;
> my $dev = $out =~ /(Microphone.*)/;
> print "Using \"$dev\"\n";
> system "ffmpeg", "-f", "dshow", "-i", $dev;
>
> If the “Using "..."” message is mangled but the command line succeeds,
> then the issue is not ffmpeg's problem.

I don't know perl well, but after modifying the program a bit i got it
to capture the device name and call ffmpeg with it:
my $out = `ffmpeg -sources dshow`;
($dev) = ( $out =~ /(Microphone.*) \[/);
print "Using \"$dev\"\n";
system "ffmpeg", "-f", "dshow", "-i", "audio=\"$dev\"";

The regex looks the way it does because the full output line is:
"Microphone Array (Intel® Smart Sound Technology (Intel® SST))
[@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{A6F097A2-0BFA-4F4C-BF22-D4531781DA10}]
(audio)"

Running that perl script, i get the following output (skipping ffmpeg header):
Using "Microphone Array (Intel® Smart Sound Technology (Intel® SST))"
[dshow @ 000001B93364A7C0] Could not find audio only device with name
[Microphone Array (Intel® Smart Sound Technology (Intel® SST))]
among source devices of type audio.
[dshow @ 000001B93364A7C0] Searching for audio device within video
devices for Microphone Array (Intel® Smart Sound Technology (Intel®
SST))
[dshow @ 000001B93364A7C0] Could not find audio only device with name
[Microphone Array (Intel® Smart Sound Technology (Intel® SST))]
among source devices of type video.
audio=Microphone Array (Intel® Smart Sound Technology (Intel® SST)): I/O error

So something isn't going quite right there. To be sure, running
ffmpeg -f dshow -i audio="Microphone Array (Intel® Smart Sound
Technology (Intel® SST))"
directly from cmd does work.

Did i make a perl error, or is there an ffmpeg problem?

Thanks,
Dee
diff mbox series

Patch

diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c
index 4148285971..b7018b7dab 100644
--- a/fftools/cmdutils.c
+++ b/fftools/cmdutils.c
@@ -2205,9 +2205,36 @@  double get_rotation(AVStream *st)
 }
 
 #if CONFIG_AVDEVICE
+static void print_device_list(AVDeviceInfoList *device_list)
+{
+    int i, error_level = av_log_get_level();
+    // reset log level such that info messages are displayed
+    // we need to use av_log instead of printf as it handles
+    // unicode better
+    av_log_set_level(AV_LOG_INFO);
+    // print devices
+    for (i = 0; i < device_list->nb_devices; i++) {
+        av_log(NULL, AV_LOG_INFO, "%s %s [%s]", device_list->default_device == i ? "*" : " ",
+            device_list->devices[i]->device_name, device_list->devices[i]->device_description);
+        if (device_list->devices[i]->nb_media_types > 0 && device_list->devices[i]->media_types) {
+            const char* media_type = av_get_media_type_string(device_list->devices[i]->media_types[0]);
+            av_log(NULL, AV_LOG_INFO, " (%s", media_type ? media_type : "unknown");
+            for (int i = 1; i < device_list->devices[i]->nb_media_types; ++i) {
+                media_type = av_get_media_type_string(device_list->devices[i]->media_types[i]);
+                av_log(NULL, AV_LOG_INFO, ", %s", media_type ? media_type : "unknown");
+            }
+            av_log(NULL, AV_LOG_INFO, ")");
+        } else {
+            av_log(NULL, AV_LOG_INFO, " (none)");
+        }
+        av_log(NULL, AV_LOG_INFO, "\n");
+    }
+
+    av_log_set_level(error_level);
+}
 static int print_device_sources(const AVInputFormat *fmt, AVDictionary *opts)
 {
-    int ret, i;
+    int ret;
     AVDeviceInfoList *device_list = NULL;
 
     if (!fmt || !fmt->priv_class  || !AV_IS_INPUT_DEVICE(fmt->priv_class->category))
@@ -2225,10 +2252,7 @@  static int print_device_sources(const AVInputFormat *fmt, AVDictionary *opts)
         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);
-    }
+    print_device_list(device_list);
 
   fail:
     avdevice_free_list_devices(&device_list);
@@ -2237,7 +2261,7 @@  static int print_device_sources(const AVInputFormat *fmt, AVDictionary *opts)
 
 static int print_device_sinks(const AVOutputFormat *fmt, AVDictionary *opts)
 {
-    int ret, i;
+    int ret;
     AVDeviceInfoList *device_list = NULL;
 
     if (!fmt || !fmt->priv_class  || !AV_IS_OUTPUT_DEVICE(fmt->priv_class->category))
@@ -2255,10 +2279,7 @@  static int print_device_sinks(const AVOutputFormat *fmt, AVDictionary *opts)
         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);
-    }
+    print_device_list(device_list);
 
   fail:
     avdevice_free_list_devices(&device_list);