fix streaming crash when canvas video pipeline isn't initialized#1710
Merged
Conversation
obs_get_video() unconditionally dereferences main_canvas->mix->video. When obs_reset_video fails at startup (e.g. DXGI_ERROR_DEVICE_REMOVED during initial texture creation), canvas->mix is left NULL and the next SimpleStreaming::Start crashes here -- seen in Sentry crashing osn::SimpleStreaming::UpdateEncoders at osn-simple-streaming.cpp:302 with EXCEPTION_ACCESS_VIOLATION_READ. - Switch SimpleStreaming/AdvancedStreaming UpdateEncoders to obs_video_mix_get(GetCanvas(), mode) + obs_video_mix_get_video(mix), which is canvas-scoped and NULL-safe. - Add a NULL-mix guard in both Start handlers so we return a clean CriticalError instead of crashing if the canvas video never came up. - Make osn::Video::set propagate IPC errors via ValidateResponse so SetVideoContext failures reach the JS layer instead of being silently dropped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4 tasks
The canvas-video lookup in UpdateEncoders / Start was open-coded four times across SimpleStreaming and AdvancedStreaming. Each site also had to know that osn::Output::GetCanvas() returns obs_video_info* (the osn "canvas") rather than libobs's obs_canvas_t -- which is easy to miss since the libobs API obs_canvas_get_video() takes the latter. Hide the juggling behind one helper on the Output base class that takes a rendering mode and returns a video_t* (or NULL when the canvas video mix isn't ready). Call sites collapse to a single readable line, and future callers don't have to re-discover the type mismatch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR hardens streaming start/update logic against cases where the OBS video pipeline (canvas video mix) was not successfully initialized (e.g., GPU/device lost during startup), preventing null-dereference crashes and surfacing IPC errors back to the JS layer.
Changes:
- Simple/Advanced streaming: replace
obs_get_video()usage inUpdateEncoders()with canvas-scoped video lookup and add a start-time guard that returns aCriticalErrorwhen no canvas video mix exists. - Server: add
Output::GetCanvasVideo(mode)helper to centralize canvas→mix→video lookup. - Client: propagate
SetVideoContextIPC failures viaValidateResponseso initialization errors are observable in JS.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| obs-studio-server/source/osn-simple-streaming.cpp | Use canvas-scoped video output in UpdateEncoders(); fail fast in Start() when no video mix exists. |
| obs-studio-server/source/osn-advanced-streaming.cpp | Same crash-avoidance pattern as SimpleStreaming for advanced mode. |
| obs-studio-server/source/osn-output.hpp | Declare Output::GetCanvasVideo() helper API. |
| obs-studio-server/source/osn-output.cpp | Implement Output::GetCanvasVideo() helper. |
| obs-studio-client/source/video.cpp | Add ValidateResponse handling for SetVideoContext IPC call. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| video_t *osn::Output::GetCanvasVideo(obs_video_rendering_mode mode) | ||
| { | ||
| return obs_video_mix_get_video(obs_video_mix_get(m_canvas, mode)); |
Match the pattern in osn-video.cpp: return nullptr when the mix lookup fails instead of dereferencing it. Without this, the helper crashes in exactly the scenario this PR targets (no canvas video mix), defeating the Start() guards that call it. Also apply clang-format-13 fixes flagged by CI. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the Sentry-reported
EXCEPTION_ACCESS_VIOLATION_READatosn::SimpleStreaming::UpdateEncoders(osn-simple-streaming.cpp:302), and the equivalent latent crash inAdvancedStreaming::UpdateEncoders(osn-advanced-streaming.cpp:391).Root cause
obs_get_video()unconditionally dereferencesobs->data.main_canvas->mix->video. Whenobs_reset_videofails at app startup (e.g. when D3D11 returnsDXGI_ERROR_DEVICE_REMOVED/DXGI_ERROR_DEVICE_HUNGduring initial texture creation),obs_canvas_clear_mixhas already setcanvas->mix = NULL, and the failedobs_create_video_mixleaves it that way. On Go-Live,UpdateEncoderscallsobs_get_video()and crashes.The original Sentry report's OBS log shows the textbook sequence — 4× failed
SetVideoContextwithresult: -1andDevice Removed Reason: 887A0006— followed immediately by the SimpleStreaming::Create … Start chain.Changes
osn-simple-streaming.cpp/osn-advanced-streaming.cpp:UpdateEncodersswitches fromobs_get_video()(main-canvas, unguarded) toobs_video_mix_get(this->GetCanvas(), mode)+obs_video_mix_get_video(mix)— canvas-scoped and NULL-safe. Falls back toVIDEO_FORMAT_NV12when video is unavailable, which the existing switch already treats as the default.Startgains a defense-in-depth guard: if the streaming canvas has no video mix, returnErrorCode::CriticalErrorwith a clear message rather than lettingUpdateEncodersget there.obs-studio-client/source/video.cpp:osn::Video::setnow callsValidateResponseafter theSetVideoContextIPC call. Previously the server returnedErrorCode::Erroron failure but the client dropped it on the floor, leaving JS with no way to know the video context never came up. Pairs with the desktop-side change below.Pairs with
fix_streaming_crash_no_video) — the desktop side needs this PR's IPC error to escape to JS. The desktop change is inert without this PR; this PR is useful on its own (the crash guard works regardless).Deferred / out of scope
nodeobs_service.cpp:2222andnodeobs_autoconfig.cpp:1072also call unguardedobs_get_video()— same pattern, separate audit.device_rebuild()onSetVideoContextfailure would actually recover from transient device-removed; tracked as a follow-up.Test plan
CriticalErrorinstead of crashing.ValidateResponsechange doesn't surface false errors during normal startup flow.🤖 Generated with Claude Code