← all articles

Best way to stop an scrcpy recording programmatically on Windows

taskkill /F on a live scrcpy --record=run.mp4 is the quickest way I know to get a video your player refuses to open. mp4 keeps its index at the end of the file, and a hard kill never lets scrcpy write it.

This list is for anyone starting scrcpy recordings from a script on Windows: a test harness, a scheduled capture job, a CI step, a batch file that films a phone while something else runs. The question behind scrcpy issue 818 is the one I want to answer head on. How do you stop a --record run from outside the process without killing it mid-write? Send scrcpy the same Ctrl+C console event a person at the keyboard would, wait a few seconds for it to finalize the file, then check the file. As of September 2026 I don’t know of a stop command or control socket in scrcpy’s command line, so the console event is the route.

Windows has no kill -INT. taskkill /F, Stop-Process and Python’s proc.kill() all end in TerminateProcess, and Python’s docs say kill() is just an alias for terminate() on Windows. The process never runs its shutdown code, so scrcpy’s own cleanup on the adb side gets skipped too. What the adb client, server and daemon each do explains where that state lives. One rule covers most of this: never kill it. I compared seven ways to end a recording and scored each on one thing first, whether the file plays afterwards. The usual reason to script this is evidence. If you’re chasing a flaky UI test, a video of the failing run is cheap to attach, and why Android UI tests are flaky covers the other suspects.

How I picked

  • does the file play afterwards, with no repair step
  • can a script do it alone, with no human at the keyboard
  • works on stock Windows 10 and 11 without an installer
  • headless (-N) and windowed runs both count, since test rigs often have no screen attached
  • what the script can see when it goes wrong: a timeout, an exit code, something to escalate on

A caveat before the picks. I’ve written these from how scrcpy, Windows and Android document their behaviour, not from a run against every scrcpy release. Try each on your own build and check the output file with ffprobe before it goes anywhere near a pipeline.

The picks

Python subprocess plus a ctypes Ctrl+C helper

This is my top pick and the direct answer to issue 818. Start scrcpy in its own console with CREATE_NEW_CONSOLE. To stop it, spawn a throwaway helper process that detaches from its own console, attaches to scrcpy’s, switches off its own Ctrl+C handling and fires CTRL_C_EVENT. The helper has to be a separate process because GenerateConsoleCtrlEvent acts on the caller’s console and, with group id 0, hits everything attached to it, the caller included.

import subprocess, sys, time

HELPER = r"""
import ctypes, sys
k32 = ctypes.windll.kernel32
k32.FreeConsole()
if not k32.AttachConsole(int(sys.argv[1])):
    sys.exit(2)
k32.SetConsoleCtrlHandler(None, True)
k32.GenerateConsoleCtrlEvent(0, 0)  # CTRL_C_EVENT to that console
"""

def stop_scrcpy(proc, timeout=20):
    subprocess.run([sys.executable, "-c", HELPER, str(proc.pid)])
    try:
        return proc.wait(timeout=timeout)
    except subprocess.TimeoutExpired:
        proc.kill()  # last resort, the file may not play
        return proc.wait()

proc = subprocess.Popen(
    ["scrcpy.exe", "-N", "--record=run01.mkv"],
    creationflags=subprocess.CREATE_NEW_CONSOLE,
)
time.sleep(30)  # your test runs here
print("exit code:", stop_scrcpy(proc))

The trap is the snippet you’ll find everywhere: CREATE_NEW_PROCESS_GROUP plus CTRL_BREAK_EVENT. A new process group has Ctrl+C disabled, so Break is the only event you can send, and as far as I know scrcpy’s Windows handler only acts on Ctrl+C. Microsoft’s GenerateConsoleCtrlEvent page documents the group-id behaviour.

Break then falls through to default termination, which is a kill with extra steps.

Call scrcpy.exe directly. Through a .bat or .cmd shim, cmd.exe answers the Ctrl+C with “Terminate batch job (Y/N)?” and waits for someone who isn’t there.

  • pro: scrcpy runs its ordinary shutdown path, the same one a human Ctrl+C triggers
  • pro: works with a window and with -N, and each scrcpy gets its own console, so parallel recordings don’t cross-fire
  • pro: the wait-then-escalate shape gives you a timeout you can log
  • con: about fifteen lines of console plumbing that you own
  • con: console behaviour can differ under Task Scheduler or a service wrapper, so test with the launch method you’ll actually deploy

pricing: free. Python is free and scrcpy is open source under Apache 2.0.

link: GenerateConsoleCtrlEvent on Microsoft Learn

PowerShell with an Add-Type helper

Same technique for people who live in .ps1 files and Task Scheduler and would rather not add Python. Save this as stop-console.ps1. It has to run as its own powershell.exe, for the same reason as before: FreeConsole would otherwise cut your own console loose.

param([Parameter(Mandatory)][uint32]$TargetPid)
Add-Type -Namespace Win -Name Con -MemberDefinition @'
[DllImport("kernel32.dll")] public static extern bool FreeConsole();
[DllImport("kernel32.dll")] public static extern bool AttachConsole(uint pid);
[DllImport("kernel32.dll")] public static extern bool SetConsoleCtrlHandler(IntPtr h, bool add);
[DllImport("kernel32.dll")] public static extern bool GenerateConsoleCtrlEvent(uint evt, uint group);
'@
[void][Win.Con]::FreeConsole()
if (-not [Win.Con]::AttachConsole($TargetPid)) { exit 2 }
[void][Win.Con]::SetConsoleCtrlHandler([IntPtr]::Zero, $true)
[void][Win.Con]::GenerateConsoleCtrlEvent(0, 0)

The caller starts scrcpy, waits, then shells out to the helper:

$p = Start-Process scrcpy.exe -ArgumentList '-N','--record=run01.mkv' -PassThru
Start-Sleep 30
powershell -NoProfile -File .\stop-console.ps1 -TargetPid $p.Id
if (-not $p.WaitForExit(20000)) { $p.Kill() }   # last resort

If the same rig also drives the phone, Android RPA with adb and uiautomator2 covers that side.

  • pro: nothing to install, Windows PowerShell 5.1 ships with Windows 10 and 11
  • pro: same clean shutdown as the Python version
  • pro: drops into an existing scheduled task without a new runtime
  • con: Add-Type compiles C# at run time, and Constrained Language Mode or a strict policy on locked-down machines can block it

pricing: free, ships with Windows.

link: Android RPA with adb and uiautomator2

scrcpy –time-limit

scrcpy -N --record=run01.mkv --time-limit=60 and scrcpy stops itself after 60 seconds. No signals, no helper. It’s what I’d use first when the capture length is known in advance. -N is the short flag for headless runs, but its long name has changed between releases (older builds say --no-display), so check scrcpy --help on yours. scrcpy’s recording doc covers the record flags.

It’s a ceiling, not a stop button. If your test ends at second 20 the recording runs to 60 anyway, and if the test runs to 90 you lose the last 30. I keep it on as a watchdog under the Ctrl+C methods, so a crashed script can’t leave a recording going all night.

  • pro: scrcpy ends itself, so its own shutdown finalizes the file
  • pro: no Windows console handling at all
  • pro: works as a safety ceiling beside any other pick
  • con: fixed duration only, it can’t react to your script finishing early
  • con: the clock starts with scrcpy, so allow for startup and check the real duration with ffprobe

pricing: free, part of scrcpy.

link: scrcpy recording doc

taskkill without /F

With a scrcpy window open, taskkill /IM scrcpy.exe without /F posts a close request to the window. My understanding is that SDL turns that into a quit event and scrcpy shuts down the normal way, same as clicking the X. With several phones, give each a title, --window-title=phone1, and target it with taskkill /FI "WINDOWTITLE eq phone1".

taskkill prints SUCCESS: Sent termination signal the moment the request is posted, not when the file is closed. Poll for the process to exit before you touch the file.

  • pro: ships with Windows, nothing to write
  • pro: one line from a batch file
  • pro: the title filter picks one phone out of several
  • con: needs a window, and in -N mode taskkill typically answers that the process can only be terminated forcefully
  • con: returns before the file is finished, so you still need your own wait

pricing: free, built into Windows.

link: none needed, taskkill /? prints the flags.

windows-kill

A small third-party tool that sends signals to a process by PID, so windows-kill -SIGINT 1234 gets you an interrupt from cmd without any attach code of your own. It suits batch files where a helper script feels like too much. Check its README for the exact flags.

My hesitation: tools that reach into other processes on Windows tend to draw antivirus attention, and I haven’t re-checked whether the project is still maintained for this article. Read the source, pin a release, and confirm the file plays with your scrcpy build. And here’s the bit someone will argue with: I’d take ten lines of Python I can read over a binary I can’t.

  • pro: one command from cmd or a batch file
  • pro: takes a PID straight from tasklist
  • pro: no console attach code in your own script
  • con: a third-party binary to vet and keep updated
  • con: whether its interrupt gives your scrcpy build a clean stop is yours to test

pricing: free, open source.

link: none, search GitHub for windows-kill and read the README and source first.

MKV recording plus an ffmpeg remux

This one doesn’t stop scrcpy. It makes a bad stop survivable. Record with --record=run01.mkv instead of mp4. Matroska is written as a stream, so a cut-off file usually still opens, sometimes without a duration or seek bar. Then ffmpeg -i run01.mkv -c copy run01.mp4 rewrites the container in seconds with no re-encode. To check a file, ffprobe -v error -show_entries format=duration -of default=nw=1:nk=1 run01.mkv should print a number.

My default for scripted runs is mkv, including the ones I expect to stop cleanly, because it costs one extra command. Bitrate and fps flags change the file size, and the scrcpy lag and stuttering settings are where I’d start for those.

  • pro: a botched stop usually still leaves something playable
  • pro: the remux is a copy, so no quality loss
  • pro: combines with every other pick
  • con: an extra step and an ffmpeg dependency
  • con: an unclean mkv can lack duration and seek info until you remux it

pricing: free, ffmpeg is open source.

link: scrcpy recording doc

adb shell screenrecord with SIGINT

The way around scrcpy entirely. Android’s own recorder runs on the device: adb shell screenrecord /sdcard/run01.mp4, stopped by sending SIGINT to the device-side process, for example adb shell pkill -SIGINT screenrecord, then adb pull /sdcard/run01.mp4. pkill isn’t on every Android build, so check your device before you build on it. Android’s adb documentation covers the command, and as of September 2026 it lists a three-minute cap per recording.

  • pro: no dependency on scrcpy or Windows console behaviour
  • pro: SIGINT is the normal way to end it, so the file is finalized on the device
  • pro: pulling the file afterwards is a plain copy
  • con: three-minute cap per file as of September 2026, so long runs need chaining
  • con: no mirroring and no audio

pricing: free, part of Android platform-tools.

link: Android adb documentation

Comparison table

pick price primary strength primary weakness
Python plus ctypes Ctrl+C helper free clean stop on demand, headless or windowed console plumbing you maintain
PowerShell Add-Type helper free nothing to install on Windows Add-Type can be blocked on locked-down machines
scrcpy –time-limit free no signalling at all fixed duration only
taskkill without /F free one line, ships with Windows needs a window, returns before the file is closed
windows-kill free one command from cmd third-party binary to vet
MKV plus ffmpeg remux free a bad stop stays playable extra step, stops nothing itself
adb shell screenrecord free independent of scrcpy three-minute cap, no audio

How to choose

If your script decides when the recording ends, use the Python or PowerShell helper, whichever language the rest of the pipeline is already in. If you know the duration up front, use --time-limit and stop there. Most rigs I’d build use both: Ctrl+C for the normal end, and --time-limit set well above the longest expected run, so a hung test can’t leave a recording going all night.

Whatever you choose, wait for the process to exit, then check the file. An exit code alone doesn’t prove the video plays, so run ffprobe and treat an error or an empty duration as a failed capture. Keep the recording of a failed run next to its logs. The logcat guide and adb bugreport capture pair well with it: video shows what the screen did, logs show why.

For several devices at once, give each scrcpy its own console (CREATE_NEW_CONSOLE does this), its own -s SERIAL, its own output name and its own window title. Ctrl+C goes to one console at a time, so stopping phone 1 doesn’t touch phone 2. Past a handful of phones the recording is the smaller problem, and the open-source Android device farm tools are where I’d look.

Record only devices and apps you own or are authorised to test. A screen recording captures notifications, messages and whatever else lands on screen, so store the files as carefully as you would the device. This is not legal advice.

Verdict / top pick

The Python helper, or the PowerShell one if your pipeline already lives in .ps1 files. Pair it with --time-limit as a ceiling and mkv as the container. That’s my answer to issue 818: don’t kill it, send it Ctrl+C from a separate helper process, wait, and check the file with ffprobe. More scrcpy and adb write-ups are in the blog index.

Written by Xavier Fok

disclosure: this article may contain affiliate links. if you buy through them we may earn a commission at no extra cost to you. verdicts are independent of payouts. last reviewed by Xavier Fok on 2026-09-25.

free download
The adb and scrcpy command cheat sheet

The commands we reach for on a rack of real phones, on one printable page. Leave your email and we will also tell you when we publish a new guide, a few times a month at most.

from the team behind cloudf.one
Passes on the emulator, fails on a real phone?

cloudf.one rents real Android phones in Singapore that you control from the browser, each on a persistent Singapore mobile IP. Real hardware, a real OEM build and a real carrier network, without buying and racking the phones yourself.

test on a real phone →
read on
More from ADB Handbook

adb commands, scrcpy flags, automation frameworks, and why a test passes on one phone and fails on the next.

browse all articles →