├── README.md ├── example └── example.js ├── lib └── main.js └── package.json /README.md: -------------------------------------------------------------------------------- 1 | # FFmpeg device list parser 2 | 3 | ### Supported Platforms 4 | * macOS (using AVFoundation) 5 | * Windows (using DirectShow) 6 | 7 | ## Usage 8 | ```sh 9 | npm install ffmpeg-device-list-parser 10 | ``` 11 | 12 | ```js 13 | const { parse } = require('ffmpeg-device-list-parser'); 14 | 15 | // FFmpegPath is customizable 16 | const options = { 17 | ffmpegPath: '/usr/local/bin/ffmpeg' 18 | } 19 | 20 | // Promise usage 21 | parse(options).then( 22 | (result) => console.log(result) 23 | ); 24 | 25 | // Callback usage 26 | parse(options, 27 | (result) => console.log(result) 28 | ); 29 | 30 | // Callback usage without option 31 | parse((result) => console.log(result)); 32 | ``` 33 | 34 | ## Output Example 35 | ```js 36 | // macOS 37 | { 38 | videoDevices: [ 39 | { id: 0, name: 'FaceTime HD Camera' }, 40 | { id: 1, name: 'Capture screen 0' } 41 | ], 42 | audioDevices: [ 43 | { id: 0, name: 'Built-in Microphone' } 44 | ] 45 | } 46 | 47 | // Windows 48 | { 49 | videoDevices: [ 50 | { 51 | name: 'Lenovo EasyCamera', 52 | alternativeName: '@device_pnp_\\\\?\\usb#vid_04f2&pid_b483&mi_00#6&30849109&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\\global' 53 | } 54 | ], 55 | audioDevices: [ 56 | { 57 | name: 'Microphone (Realtek High Definition Audio)', 58 | alternativeName: '@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\\wave_{A5E96CD9-7A60-406C-8E66-7C75CFDD006C}' 59 | } 60 | ] 61 | } 62 | 63 | ``` 64 | 65 | ## Author 66 | syumai 67 | 68 | ## License 69 | MIT 70 | -------------------------------------------------------------------------------- /example/example.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const parse = require('../lib/main.js').parse; 4 | 5 | // FFmpegPath is customizable 6 | const options = { 7 | ffmpegPath: null 8 | } 9 | 10 | // Promise usage 11 | parse(options).then( 12 | (result) => console.log(result) 13 | ); 14 | 15 | // Callback usage 16 | parse(options, 17 | (result) => console.log(result) 18 | ); 19 | 20 | // Callback usage without option 21 | parse((result) => console.log(result)); 22 | -------------------------------------------------------------------------------- /lib/main.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const exec = require('child_process').exec; 4 | const platform = process.platform; 5 | 6 | function parse(options, callback) { 7 | if(typeof options === 'function') { 8 | callback = options; 9 | options = null; 10 | } 11 | options = options || {}; 12 | const ffmpegPath = options.ffmpegPath || 'ffmpeg'; 13 | const callbackExists = typeof callback === 'function'; 14 | 15 | let inputDevice, prefix, audioSeparator, alternativeName, deviceParams; 16 | switch(platform) { 17 | case 'win32': 18 | inputDevice = 'dshow'; 19 | prefix = /\[dshow/; 20 | audioSeparator = /DirectShow\saudio\sdevices/; 21 | alternativeName = /Alternative\sname\s*?\"(.*?)\"/; 22 | deviceParams = /\"(.*?)\"/; 23 | break; 24 | case 'darwin': 25 | inputDevice = 'avfoundation'; 26 | prefix = /^\[AVFoundation/; 27 | audioSeparator = /AVFoundation\saudio\sdevices/; 28 | deviceParams = /^\[AVFoundation.*?\]\s\[(\d*?)\]\s(.*)$/; 29 | break; 30 | } 31 | 32 | const searchPrefix = (line) => (line.search(prefix) > -1); 33 | const searchAudioSeparator = (line) => isVideo && (line.search(audioSeparator) > -1); 34 | const searchAlternativeName = (line) => (platform === 'win32') && (line.search(/Alternative\sname/) > -1); 35 | 36 | const videoDevices = []; 37 | const audioDevices = []; 38 | let isVideo = true; 39 | 40 | const execute = (fulfill, reject) => { 41 | exec(`${ffmpegPath} -f ${inputDevice} -list_devices true -i ""`, (err, stdout, stderr) => { 42 | stderr.split("\n") 43 | .filter(searchPrefix) 44 | .forEach((line) => { 45 | const deviceList = isVideo ? videoDevices : audioDevices; 46 | if(searchAudioSeparator(line)) { 47 | isVideo = false; 48 | return; 49 | } 50 | if(searchAlternativeName(line)) { 51 | const lastDevice = deviceList[deviceList.length - 1]; 52 | lastDevice.alternativeName = line.match(alternativeName)[1]; 53 | return; 54 | } 55 | const params = line.match(deviceParams); 56 | if(params) { 57 | let device; 58 | switch(platform) { 59 | case 'win32': 60 | device = { 61 | name: params[1] 62 | }; 63 | break; 64 | case 'darwin': 65 | device = { 66 | id: parseInt(params[1]), 67 | name: params[2] 68 | }; 69 | break; 70 | } 71 | deviceList.push(device); 72 | } 73 | }); 74 | const result = { videoDevices, audioDevices }; 75 | if(callbackExists) { 76 | callback(result); 77 | } else { 78 | fulfill(result); 79 | } 80 | }); 81 | }; 82 | 83 | if(callbackExists) { 84 | execute(); 85 | } else { 86 | return new Promise(execute); 87 | } 88 | } 89 | 90 | module.exports = { parse }; 91 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ffmpeg-device-list-parser", 3 | "version": "0.1.0", 4 | "description": "Parser for FFmpeg device list", 5 | "main": "lib/main.js", 6 | "directories": { 7 | "example": "example" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/syumai/ffmpeg-device-list-parser.git" 12 | }, 13 | "author": "syumai", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/syumai/ffmpeg-device-list-parser/issues" 17 | }, 18 | "homepage": "https://github.com/syumai/ffmpeg-device-list-parser#readme" 19 | } 20 | --------------------------------------------------------------------------------