Skip to content

Instantly share code, notes, and snippets.

@glebov21
Created December 7, 2023 11:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save glebov21/8aa8ff606cf92263272e65df1fa259e5 to your computer and use it in GitHub Desktop.
Save glebov21/8aa8ff606cf92263272e65df1fa259e5 to your computer and use it in GitHub Desktop.
ffmpeg c# capture application with multiple monitors (screens) (no black screen)
private string AppName = "MyApp";
public void StartRecording()
{
StopRecording();
WinProcess.OnGetAllWindowsResult += WinProcess_OnGetAllWindowsResult;
WinProcess.GetAllWindows(); //user32 EnumWindows
}
private void WinProcess_OnGetAllWindowsResult()
{
WinProcess.OnGetAllWindowsResult -= WinProcess_OnGetAllWindowsResult;
WinProcessRECT rect = new WinProcessRECT();
var primaryScreenDPI = PresentationSource.FromVisual(this).CompositionTarget.TransformToDevice.M11;
var primaryScreenWidth = (int)(SystemParameters.PrimaryScreenWidth * primaryScreenDPI);
var primaryScreenHeight = (int)(SystemParameters.PrimaryScreenHeight * primaryScreenDPI);
double appScreenDPI = primaryScreenDPI; //default
Rect appScreenBounds = new Rect(0, 0, primaryScreenWidth, primaryScreenHeight); //default
bool isAutogrammaFound = false;
WinProcess.WinProc autogrammaWindow = default(WinProcess.WinProc);
foreach (var wnd in WinProcess.GetAllWindowsResult)
{
if (wnd.Title == AppName)
{
autogrammaWindow = wnd;
WinProcess.GetWindowExtenedeFrameBounds(wnd.Handle, ref rect); //Note: windows without invisible borders
//=> dwmapi.dll DwmGetWindowAttribute(handle, (int)DwmWindowAttribute.DWMWA_EXTENDED_FRAME_BOUNDS, out lpRect, size);
WinProcess.MonitorInfoEx appMonitorInfo = new WinProcess.MonitorInfoEx();
var hMonitor = GetNearestMonitorToWindow(wnd.Handle); // => user32.dll MonitorFromWindow(hwnd, 0x00000002);
WinProcess.GetMonitorInfo(hMonitor, appMonitorInfo); // => user32.dll GetMonitorInfo
appScreenDPI = WinProcess.GetDisplayScaleFactor(wnd.Handle); // => user32.dll GetDpiForWindow(windowHandle) / 96f
var dpiKoeff = appScreenDPI / primaryScreenDPI;
appScreenBounds = new Rect(
(int)(appMonitorInfo.WorkArea.Left * dpiKoeff),
(int)(appMonitorInfo.WorkArea.Top * dpiKoeff),
(int)((appMonitorInfo.WorkArea.Right - appMonitorInfo.WorkArea.Left) * dpiKoeff),
(int)((appMonitorInfo.WorkArea.Bottom - appMonitorInfo.WorkArea.Top) * dpiKoeff));
if (rect.Left < -10000) //minimized
{
;
}
else
{
isAutogrammaFound = true;
}
break;
}
}
if (!isAutogrammaFound)
{
_errorMessage = "Окно "+AppName+" не найдено";
StopRecording();
}
else
{
//Clamp
rect.Right = (int)Clamp(rect.Right, appScreenBounds.Left, appScreenBounds.Right);
rect.Left = (int)Clamp(rect.Left, appScreenBounds.Left, appScreenBounds.Right);
rect.Bottom = (int)Clamp(rect.Bottom, appScreenBounds.Top, appScreenBounds.Bottom);
rect.Top = (int)Clamp(rect.Top, appScreenBounds.Top, appScreenBounds.Bottom);
WinProcess.SetForegroundWindow(autogrammaWindow.Handle);
StartRecording(rect);
}
}
private void StartRecording(WinProcessRECT rect)
{
StopRecording();
IsRecordingNow = true;
var captureApp = "desktop";
//var captureApp = "title=MyApp"; //note: black screen
var width = rect.Right - rect.Left - 1;
var height = rect.Bottom - rect.Top - 1;
//need div 2 size (or error)
if (width % 2 != 0)
width -= 1;
if (height % 2 != 0)
height -= 1;
_currentVideoPath = SaveFilePathWithDate;
var args = $" -y -f gdigrab -offset_x {rect.Left} -offset_y {rect.Top} -video_size {width}x{height} -i {captureApp} {_vcodec} -vf \"setpts={(1f / _speed).ToString(CultureInfo.InvariantCulture)}*PTS\" \"{_currentVideoPath}\"";
try
{
var processStartString = _recordingExeFilePath + args;
Debug.WriteLine(processStartString);
_recordingProcess = WinProcess.Start(processStartString, Path.GetDirectoryName(_recordingExeFilePath), true); //DEBUG
}
catch (Exception ex)
{
Debug.WriteLine(ex);
_errorMessage = "Ошибка записи";
StopRecording();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment