Building a Screen Recorder — DRM, Black Screens & Hard Decisions
A screen recorder developer's honest account: 340+ user bug reports, 3 failed technical solutions, and why we chose not to support DRM recording. Real test data, real decisions.
We’ve spent two years building a macOS screen recorder. This article has no ChatGPT flavor — just actual experiment data, killed feature ideas, App Store review battles, and why we ultimately decided against supporting DRM recording.
Why We're Writing This
Over the past year, the most common support ticket for Yfli Screen Recorder has been:
“The recording came out black. What’s going on?”
We categorized all of them:
~340 "black screen" tickets total
├── 38% — User was recording Netflix / Disney+ / Apple TV+
├── 27% — Browser video (hardware acceleration, mostly)
├── 22% — macOS screen recording permission not granted or got reset
├── 9% — Multiple recording tools open at once
└── 4% — Other (external display quirks, OS version bugs)
This article is our collective reply to all 340 tickets — from the technical, product, and legal angles, all in one place.
DRM in Two Sentences
DRM does exactly one thing: it makes sure video frames appear on your screen, and nowhere else. Not in your app’s memory. Not in a screen recording. Just the display.
If you understand that, everything else in this article will click.
The Three DRM Players
| System | Built by | Security level on Mac |
|---|---|---|
| FairPlay Streaming | Apple | Hardware-level |
| Widevine | L3 software-level | |
| PlayReady | Microsoft | Not on Mac |
We had a three-month internal misconception worth calling out.
Early on, we assumed Chrome would handle Netflix with the same iron grip as Safari. Turns out, Widevine on macOS Chrome runs at L3 (software-level) — decryption happens in user space, and frame data sits in system memory. Theoretically capturable.
Then we tested it. What we found: macOS intercepts at the WindowServer compositor layer. Whether it’s FairPlay or Widevine L3, any frame passing through the CoreMedia pipeline gets its protected flag checked during composition. Hit = blocked. The end result across both DRM systems is identical — black frames.
Nobody in the Chinese dev community has written about this publicly. It took us two late nights of controlled experiments to confirm.
How FairPlay Actually Works (The Short Version)
The key exchange boils down to one rule: the application process never sees the decryption key.
Player App / Safari
│ ① Requests key
▼
mediaserverd (system daemon)
│ ② Generates SPC (device-bound, replay-protected)
▼
License Server
│ ③ Returns CKC (wrapped key — only the target device can unwrap)
▼
mediaserverd → Secure Enclave / T2
│ ④ Hardware-level decryption → frames → Protected Memory Pool only
▼
GPU → Display controller → Physical screen
The critical part: step ④. From the moment a frame is decrypted to the moment it hits your display, it never exists in any memory your app can touch.
Every Solution We Tried (and Why Each One Failed)
We spent two weeks systematically testing three approaches. Here are the full experiment logs.
Setup
| Item | Config |
|---|---|
| Test device | MacBook Pro 14” (M2 Pro, 2023) |
| macOS | 14.5 Sonoma / 15.0 Sequoia (tested both) |
| Recorders | Yfli Screen Recorder, QuickTime, OBS Studio 30 |
| DRM sources | Apple TV+ native app, Netflix (Safari), Netflix (Chrome) |
| Measurement | In-house frame detection module (CMSampleBuffer metadata extraction) |
Attempt 1: Just Switch APIs
Hypothesis: Different capture APIs might take different paths — maybe one slips through.
Experiment: Same 30-second Netflix clip looped, recorded alternately through three different APIs.
Results:
CGDisplayStream (Yfli, deprecated API):
Frames: 900/900 (30fps × 30s)
Black frames: 900
Valid frames: 0
ScreenCaptureKit (Yfli, current API):
Frames: 900/900
Black frames: 900
Valid frames: 0
SCK-specific finding: CMSampleBuffer attachments contained
kCMSampleAttachmentKey_ProtectedContent = true
This key was absent during YouTube playback, 100% present during Netflix
QuickTime Player (Apple's own):
Frames: 900/900
Black frames: 900
Valid frames: 0
Verdict: Don’t bother. macOS intercepts at the WindowServer compositor, not the API layer. Switching APIs does nothing.
What we learned: kCMSampleAttachmentKey_ProtectedContent is macOS’s formal signal to apps — it’s essentially saying “I’m giving you black frames on purpose, don’t file a bug.” We later wired this detection into the product: when ProtectedContent markers are sustained, the recorder proactively tells the user the content can’t be recorded.
Attempt 2: Virtual Display Driver — The One We Actually Invested In
This was our most ambitious approach. The idea:
DRM content playing
│
▼
macOS detects output display → "This display says it doesn't support HDCP"
│
▼
System downgrades → routes to virtual display's regular framebuffer
│
▼
CGDisplayStream / SCK captures this framebuffer → Unencrypted data
What we actually built:
- Full architecture design (DriverKit Dext + custom EDID)
- Preliminary EDID data structure
- Research into macOS 15 Sequoia compositor behavior
Where we hit the wall:
Wall #1: GPU Protected Memory Pool. When macOS VideoToolbox decodes protected content, the output frames aren’t allocated in regular VRAM. They go into the GPU driver’s Protected Video Memory Pool. No user-space API — not CGDisplayStream, not SCK — can read from this pool. Even if you spin up a virtual display, frame routing happens before the compositor. By the time the compositor gets the frames, they’re already in the Protected Pool. The virtual display never sees them.
What actually happens:
Decoder → Protected Pool → WindowServer compositor
│
┌──────────┴──────────┐
│ │
DRM frames Normal frames
(never enter any (routed normally
capturable path) to all displays)
Wall #2: System Extension review. DriverKit extensions need Apple notarization. We found during research that Apple’s review of virtual display drivers is extremely strict — anything that “modifies system display behavior” triggers deep manual review. Getting approved would be nearly impossible.
Wall #3: macOS 15 changed the game. Before Sequoia, NSWindow.sharingType = .none could block a window from SCK capture. In Sequoia, the compositor merges all windows into one framebuffer, and SCK captures directly from that. sharingType is ignored. Apple is actively tightening screen capture boundaries — the virtual display window may already be closed.
Our conclusion: 2-3 months of development, extremely high rejection risk, and a technically insurmountable obstacle at the Protected Pool layer. This isn’t worth building. Users need a reliable screen recorder, not a hack that “might work in certain scenarios and might break with the next OS update.”
Attempt 3: DRM Detection + Auto-Pause — The Only Compliant Option
We studied screenpipe’s open-source implementation and evaluated integrating something similar.
How it works:
- Monitor foreground app changes through Accessibility API
- Maintain a list of known DRM apps (Netflix, Disney+, Apple TV, Prime Video, HBO Max, Hulu, Paramount+, Crunchyroll)
- When a DRM app gets focus → release all SCK handles completely → pause capture
- When a normal app gets focus → reinitialize SCK → resume capture
The problems we hit:
Latency. From a DRM app getting focus to our detector confirming it: ~180-220ms average. In that window, Netflix’s native app has rendered about 6 frames. Since the SCK session is still active, those frames come out black. Result: user switches to Netflix → first 6 frames are black → then recording pauses.
Recovery time. SCK reinitialization isn’t instant. SCStreamConfiguration recreation + SCShareableContent re-fetch + startCapture call takes ~640ms on our M2 Pro. You can’t cache this — the DRM app might have changed window layout while in the background.
UX disaster. This stop-start behavior produces audio-video desync in the output file. We tested a real workflow: “watch Netflix → switch to VS Code → switch to browser → switch to Netflix → switch to Terminal.” The resulting recording had five separate A/V sync offsets when played in VLC.
What we chose instead: No fancy auto-detection. Just a simple notice in the recording settings: “Protected content detected — recording may appear black. Learn more →” That link goes to our troubleshooting guide.
The team consensus was: better to be honest about where the boundary is than to ship a 95%-reliable half-solution that users will curse at.
Why We Ultimately Decided Against DRM Recording
1. Technically impossible (previous section covers this)
Three approaches. Three failures. There’s no legal path through.
2. Legal risk isn’t hypothetical — it’s specific
| Law | Actual risk |
|---|---|
| US DMCA §1201 | Bans circumventing technological protection measures. First offense: civil damages + injunction. Willful violation (you knew it was DRM and did it anyway): criminal liability |
| EU Copyright Directive 2019/790 | Member states have criminalized DRM circumvention. Germany: up to 3 years |
| China Copyright Law Art. 49 | Intentional circumvention of technical protection measures: 1-5× illegal revenue in fines |
Screen recorder developers are in a weird spot: if you add a “bypass DRM” feature, you go from “neutral tool provider” to “circumvention device provider.” That’s a different legal category with different consequences.
3. App Store review: it’s not about passing — it’s about what passing even means
One of our earlier builds (v3.x) got rejected. Apple’s automated testing detected that our recording module was still producing frame capture logs while Apple TV+ was playing — even though the frames were black.
The review team’s note, paraphrased:
“Your app attempted to capture content from a protected playback session. While the captured frames were blank, the capture attempt itself raises concerns under Guideline 5.2.2.”
It took three weeks of back-and-forth. We got through not by changing code, but by adding explicit user-facing notices: “Protected content will appear as black screen.”
What we learned: Apple doesn’t want you to bypass DRM. They want you to prove you know DRM exists and respect it.
4. The business math
We did a rough internal estimate:
Building the virtual display approach:
Dev time: 2-3 months (2 people)
Review risk: ~90% rejection chance
Maintenance: needs adaptation every major macOS release
Potential upside: maybe 3-5% of users pay because they can "record Netflix"
Instead, putting those resources into other features:
Annotation tools, mouse effects, multi-format export, scheduled recording
Each feature: 10-30% user scenario coverage
Conclusion: Same dev hours on compliant features = 5-10× ROI
This math applies to every small-to-mid-sized screen recording team. Big companies can afford a dedicated team and legal department to spar with Apple. We can’t.
5. The whole industry made the same call
| Tool | DRM handling | We verified |
|---|---|---|
| QuickTime Player | Black frames, system default | ✅ |
| OBS Studio | Black frames + log warning | ✅ |
| CleanShot X | Black frames + recording pause notice | ✅ |
| Snagit | Black frames + user prompt | — |
| Loom | Black frames | ✅ |
| Kap | Black frames | ✅ |
| screenpipe | DRM detection + SCK handle release | ✅ |
Nobody has figured this out — not because we’re all stupid, but because Apple left no backdoor.
So What Did We Build Instead
We stopped fighting DRM and focused on being great at the stuff people actually record every day:
- Annotation toolbar — rectangles, circles, arrows, text, freehand drawing with undo/redo
- Webcam picture-in-picture — free, drag anywhere, toggle anytime
- Mouse click effects — Ripple, Pulse Ring, Glow, or your own custom GIF
- Scheduled recording — set start and end time, it handles itself
- Dual-channel audio — microphone + system audio mixed in one track
- 15 audio output formats — MP3 unlimited and free
- All recording modes free — screen, audio, camera, no time caps on basics
We believe: users aren’t stupid. Build a good product, be honest about what it can’t do, and people will respect that.
Related Articles
Mac Screen Recording Shows Black Screen? Here’s How to Fix It → — A practical troubleshooting guide for users. Send this to anyone who hits a black screen.
DRM Protection and macOS Screen Recording — A Technical Reference → — Full technical deep-dive on FairPlay, HDCP, and the macOS capture pipeline.
Ready to Try Yfli Screen Recorder?
Free download on the Mac App Store. No account required, no ads, no watermark.
John Li
macOS engineer with 15 years of experience in C/C++ native development. Builds high-performance media tools from the metal up.