fluent-ffmpeg / node-fluent-ffmpeg

A fluent API to FFMPEG (http://www.ffmpeg.org)
MIT License
7.94k stars 880 forks source link

What is the best way to list dshow and avfoundation device? #575

Closed odegraciajr closed 8 years ago

odegraciajr commented 8 years ago

I'm creating an Electron app to record webcam/screen input and I want user to have an option to select their available devices that they can use. I know that if you want to get the list of devices on Win: ffmpeg -list_devices true -f dshow -i dummy

My issue is how can I fetch output and list it as an array?

Thank you!

njoyard commented 8 years ago

That is currently unsupported as far as fluent-ffmpeg is concerned. You should spawn() ffmpeg yourself for this !

ricardopolo commented 4 years ago

Would be awesome if includes that please!

1001Josias commented 3 years ago

Is this already possible with fluent-ffmpeg in 2021?

mussacharles60 commented 1 year ago

Hey I tried to make my own parser by using child_process with exec command:

Here's how I did it:

First I created a listDevices function that executes ffprobe


const { exec } = require("child_process");

function listDevices() {
  return new Promise((resolve, reject) => {
    exec(
      "ffprobe -f dshow -list_devices true -i dummy",
      (error, stdout, stderr) => {
        // console.log("stdout:", stdout);
        // console.log("stderr:", stderr);
        if (stderr.length === 0) {
          if (error) {
            reject(error);
            return;
          }
        }
        try {
          const devices = parseDeviceOutput(stderr);
          resolve(devices);
        } catch (error) {
          reject(error);
        }
      }
    );
  });
}

Then the actual parser here:

function parseDeviceOutput(output = "") {
  const startIndex = output.indexOf("[dshow");
  const endIndex = output.indexOf("dummy: Immediate exit requested");
  const trimmedOutput = output.substring(startIndex, endIndex);

  // the reason above that code is, I want to get the desired position of the names and types which leads to the following `trimmedOutput` according to my machine:
  /*
  [dshow @ 0000019fbef76200] "HP Webcam" (video)
  [dshow @ 0000019fbef76200]   Alternative name "@device_pnp_\\?\usb#vid_0c45&pid_651b&mi_00#6&803188a&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global"
  [dshow @ 0000019fbef76200] "screen-capture-recorder" (video)
  [dshow @ 0000019fbef76200]   Alternative name "@device_sw_{860BB310-5D01-11D0-BD3B-00A0C911CE86}\{4EA69364-2C8A-4AE6-A561-56E4B5044439}"
  [dshow @ 0000019fbef76200] "OBS Virtual Camera" (none)
  [dshow @ 0000019fbef76200]   Alternative name "@device_sw_{860BB310-5D01-11D0-BD3B-00A0C911CE86}\{A3FCE0F5-3493-419F-958A-ABA1250EC20B}"
  [dshow @ 0000019fbef76200] "Stereo Mix (Realtek High Definition Audio)" (audio)
  [dshow @ 0000019fbef76200]   Alternative name "@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{B660D8FF-4D34-4BFD-B61D-82EC30C5101D}"
  [dshow @ 0000019fbef76200] "virtual-audio-capturer" (audio)
  [dshow @ 0000019fbef76200]   Alternative name "@device_sw_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\{8E146464-DB61-4309-AFA1-3578E927E935}"
  [dshow @ 0000019fbef76200] "Microphone (Realtek High Definition Audio)" (audio)
  [dshow @ 0000019fbef76200]   Alternative name "@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{37896D2E-D3C0-420B-AA17-884CC4C4E9C0}"
  [dshow @ 0000019fbef76200] "Mic in at front panel (black) (Realtek High Definition Audio)" (audio)
  [dshow @ 0000019fbef76200]   Alternative name "@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{D90DE78A-F65E-49AF-B52D-42FF454F7A49}"
  */

  const devices = [];

  for (let line of lines) {
    line = line.trim();
    if (line.endsWith('(audio)') || line.endsWith('(video)') || line.endsWith('(none)')) {
      const deviceStartIndex = line.indexOf('"') + 1;
      const deviceEndIndex = line.lastIndexOf('"');
      const deviceName = line.substring(deviceStartIndex, deviceEndIndex);
      const deviceType = line.substring(deviceEndIndex + 3, line.length - 1);
      const device = {
        name: deviceName,
        type: deviceType
      };
      devices.push(device);
    }
  }
  return devices;
}

And it works like idk, :) The reasons I haven't used regex is that I tried like the following

const regex = /\[dshow\s+@[^]]+]\s+"([^"]+)"\s+\((audio|video|none)\)/g;

Also this one

const regex = /\[dshow\s+@\s*[^]]+\]\s+"([^"]+)"\s+\(([^)]+)\)/;

But it never parse the output, so I did it manually.

I'm not good at using regex, I think.

Anyway: Now you can simply use it as follows:

listDevices()
  .then((devices) => {
    // Output device information
    console.log("// Available Devices:");
    console.log(devices);
  })
  .catch((error) => {
    console.error("Error listing devices:", error);
  });

output

// Available Devices:
[
  {
    name: "HP Webcam",
    type: "video",
  },
  {
    name: "screen-capture-recorder",
    type: "video",
  },
  {
    name: "OBS Virtual Camera",
    type: "none",
  },
  {
    name: "Stereo Mix (Realtek High Definition Audio)",
    type: "audio",
  },
  {
    name: "virtual-audio-capturer",
    type: "audio",
  },
  {
    name: "Microphone (Realtek High Definition Audio)",
    type: "audio",
  },
  {
    name: "Mic in at front panel (black) (Realtek High Definition Audio)",
    type: "audio",
  },
]
ffmpeg version N-92722-gf22fcd4483 Copyright (c) 2000-2018 the FFmpeg developers
  built with gcc 8.2.1 (GCC) 20181201

Hope this helps.