Skip to content

Commit 07eedd5

Browse files
authored
Merge pull request #17 from Parallel-7/claude/fix-ffmpeg-detection-macos-011CUm8npn4fdAGQ1kdSN1s5
fix: enhance ffmpeg detection for macOS and cross-platform support
2 parents 9ee3341 + 0bbd3d0 commit 07eedd5

1 file changed

Lines changed: 87 additions & 18 deletions

File tree

src/services/RtspStreamService.ts

Lines changed: 87 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -136,28 +136,97 @@ export class RtspStreamService extends EventEmitter {
136136

137137
/**
138138
* Check if ffmpeg is available on the system
139+
* On macOS, Electron apps don't inherit user PATH, so check common install locations explicitly
140+
* Also checks common paths on Linux (Snap, Flatpak, etc.) and Windows
139141
*/
140142
private async checkFfmpegAvailability(): Promise<void> {
141-
try {
142-
const { stdout } = await execAsync('ffmpeg -version');
143-
const versionMatch = stdout.match(/ffmpeg version ([^\s]+)/);
144-
const version = versionMatch ? versionMatch[1] : 'unknown';
145-
146-
this.ffmpegStatus = {
147-
available: true,
148-
version
149-
};
150-
151-
console.log(`[RtspStreamService] ffmpeg found: version ${version}`);
152-
} catch (error) {
153-
const errorMessage = error instanceof Error ? error.message : String(error);
154-
this.ffmpegStatus = {
155-
available: false,
156-
error: errorMessage
157-
};
143+
// Common ffmpeg installation paths across platforms
144+
// Order matters: try PATH first, then check platform-specific locations
145+
const ffmpegPaths = [
146+
'ffmpeg', // Try PATH first (works if launched from terminal or properly configured)
147+
148+
// ===== macOS =====
149+
// Homebrew (most common on macOS)
150+
'/opt/homebrew/bin/ffmpeg', // Homebrew on Apple Silicon (M1/M2/M3)
151+
'/usr/local/bin/ffmpeg', // Homebrew on Intel Mac
152+
'/opt/local/bin/ffmpeg', // MacPorts
153+
154+
// ===== Linux =====
155+
// Standard package manager locations (usually in PATH, but checking explicitly doesn't hurt)
156+
'/usr/bin/ffmpeg', // apt (Debian/Ubuntu), yum/dnf (Fedora/RHEL), pacman (Arch)
157+
158+
// Universal package managers (often not in Electron's PATH)
159+
'/snap/bin/ffmpeg', // Snap packages
160+
'/var/lib/flatpak/exports/bin/ffmpeg', // Flatpak system-wide
161+
'~/.local/share/flatpak/exports/bin/ffmpeg', // Flatpak user install
162+
163+
// Manual/compiled installations
164+
'/usr/local/bin/ffmpeg', // Common manual install location
165+
'~/bin/ffmpeg', // User home bin directory
166+
167+
// ===== Windows =====
168+
'C:\\ffmpeg\\bin\\ffmpeg.exe', // Common manual install
169+
'C:\\Program Files\\ffmpeg\\bin\\ffmpeg.exe', // Program Files install
170+
'C:\\Program Files (x86)\\ffmpeg\\bin\\ffmpeg.exe', // 32-bit on 64-bit system
171+
];
172+
173+
let lastError = '';
174+
175+
// Try each path in order
176+
for (const ffmpegPath of ffmpegPaths) {
177+
try {
178+
// Expand ~ to home directory if present
179+
const expandedPath = ffmpegPath.replace(/^~/, process.env.HOME || process.env.USERPROFILE || '');
180+
181+
// Quote the path to handle spaces
182+
const { stdout } = await execAsync(`"${expandedPath}" -version`);
183+
const versionMatch = stdout.match(/ffmpeg version ([^\s]+)/);
184+
const version = versionMatch ? versionMatch[1] : 'unknown';
185+
186+
this.ffmpegStatus = {
187+
available: true,
188+
version
189+
};
190+
191+
// Add ffmpeg directory to PATH so node-rtsp-stream can spawn it
192+
// This is critical for macOS GUI launches where PATH doesn't include Homebrew paths
193+
if (expandedPath !== 'ffmpeg') { // Only for explicit paths, not PATH-based
194+
const lastSlashIndex = expandedPath.lastIndexOf('/');
195+
const lastBackslashIndex = expandedPath.lastIndexOf('\\');
196+
const separatorIndex = Math.max(lastSlashIndex, lastBackslashIndex);
197+
198+
if (separatorIndex > 0) {
199+
const ffmpegDir = expandedPath.substring(0, separatorIndex);
200+
const pathSep = process.platform === 'win32' ? ';' : ':';
201+
202+
// Add to beginning of PATH so it takes precedence
203+
process.env.PATH = `${ffmpegDir}${pathSep}${process.env.PATH || ''}`;
204+
console.log(`[RtspStreamService] Added ${ffmpegDir} to PATH for node-rtsp-stream`);
205+
}
206+
}
158207

159-
console.warn('[RtspStreamService] ffmpeg not found:', errorMessage);
208+
console.log(`[RtspStreamService] ffmpeg found at ${expandedPath}: version ${version}`);
209+
return; // Success! Exit the function
210+
} catch (error) {
211+
lastError = error instanceof Error ? error.message : String(error);
212+
// Continue to next path
213+
}
160214
}
215+
216+
// If we get here, ffmpeg wasn't found in any location
217+
this.ffmpegStatus = {
218+
available: false,
219+
error: `ffmpeg not found in any common location. Last error: ${lastError}`
220+
};
221+
222+
console.warn('[RtspStreamService] ffmpeg not found in any location');
223+
console.warn('[RtspStreamService] Searched paths:', ffmpegPaths);
224+
console.warn('[RtspStreamService] Install ffmpeg to enable RTSP camera viewing:');
225+
console.warn('[RtspStreamService] - macOS: brew install ffmpeg');
226+
console.warn('[RtspStreamService] - Ubuntu/Debian: sudo apt install ffmpeg');
227+
console.warn('[RtspStreamService] - Fedora/RHEL: sudo dnf install ffmpeg');
228+
console.warn('[RtspStreamService] - Arch: sudo pacman -S ffmpeg');
229+
console.warn('[RtspStreamService] - Windows: Download from ffmpeg.org');
161230
}
162231

163232
// ============================================================================

0 commit comments

Comments
 (0)