Commit f833d0d
authored
Add MoQ Source for receiving broadcasts (#14)
* Add hang_source: MoQ video source plugin
Implement hang_source, a new OBS source that consumes MoQ streams from
a relay using the libmoq library.
Features:
- Configurable URL and BROADCAST fields in OBS source properties
- H.264 decoder-safe: waits for keyframes with SPS/PPS before decoding
- Realtime-first: drops stale frames to minimize latency
- Clean session handling: fully destroys and recreates context on
URL/broadcast changes to prevent stale frame processing
Files added:
- src/hang-source.c/cpp/h: Core source implementation
Files modified:
- CMakeLists.txt: Build integration for hang_source
- src/logger.h: Enhanced logging support
- src/moq-output.cpp/h: Output module updates
- src/obs-moq.cpp: Plugin registration
* Improve thread safety and remove per-frame debug logging
- Rename hang_source_disconnect -> hang_source_disconnect_locked and
hang_source_destroy_decoder -> hang_source_destroy_decoder_locked to
indicate they require the mutex
- Add mutex locking in hang_source_destroy()
- Add stale callback checks in on_session_status(), on_catalog(), and
on_video_frame() to ignore callbacks from disconnected sessions
- Handle generation changes in on_catalog() to clean up tracks if
reconnection happened during setup
- Add origin validity check in hang_source_start_consume()
- Refactor hang_source_init_decoder() to prepare new decoder state
outside the mutex, then swap atomically inside the mutex
- Add comprehensive mutex protection throughout hang_source_decode_frame()
with early exits on invalid decoder state
- Ensure ctx->frame.data[0] is set to NULL when frame buffer is freed
- Remove noisy per-frame LOG_DEBUG calls for video frame receive/output
* Fix API renames and race conditions in hang-source
API updates:
- moq_consume_video_track -> moq_consume_video_ordered
- moq_consume_video_track_close -> moq_consume_video_close
- moq_publish_media_init -> moq_publish_media_ordered
Thread safety fixes in hang-source.cpp:
- Add mutex protection for ctx->url and ctx->broadcast in hang_source_update
- Pass generation number through on_session_status to hang_source_start_consume
- Capture origin handle and broadcast copy while holding mutex in start_consume
- Verify generation hasn't changed after moq_origin_consume completes
- Create origin/session into local variables in hang_source_reconnect
- Re-verify generation before committing new handles to context
- Clean up stale resources if generation changed during reconnect setup
These fixes prevent race conditions when the user rapidly changes broadcast
settings, which could cause callbacks from old sessions to interfere with
new connections.
* debounced and smoothed out the video preview when changing hang_source broadcast (or URL)
* Fix segfault on shutdown by adding shutting_down flag
Add a volatile bool shutting_down flag to prevent use-after-free when
MoQ callbacks fire during destruction. The issue was that closing MoQ
handles triggers async callbacks, but by the time they fire the context
may already be freed.
Changes:
- Add shutting_down flag to hang_source struct
- Set flag at start of hang_source_destroy before disconnecting
- Add 100ms sleep after disconnect to let callbacks drain
- Add early-exit checks for shutting_down in all callbacks:
- on_session_status
- on_catalog
- on_video_frame
- hang_source_video_tick
- hang_source_decode_frame
Callbacks now check the flag while holding the mutex and exit
immediately if shutting down, avoiding access to freed memory.
* removed redundant hang-source.c file
* hang-source: Fix thread safety and dynamic resolution handling
Thread safety improvements:
- Replace volatile with std::atomic for shutting_down and generation fields
- Use proper atomic operations (.load()/.store()) for generation counter
- Copy url/broadcast while holding mutex before logging in video_tick
to prevent use-after-free race condition
Memory safety fixes:
- Use av_mallocz instead of av_malloc for codec extradata to ensure
padding bytes are zero-initialized
- Detect mid-stream resolution changes and reinitialize scaler context
and frame buffer to prevent out-of-bounds memory access
Documentation:
- Add detailed comment explaining the 100ms callback drain delay
limitation and suggest reference counting as a more robust solution
* hang-source: Remove hardcoded codec and format assumptions
Replace static H.264/YUV420P/1080p assumptions with dynamic detection
from moq_video_config and decoded frame properties.
Codec detection:
- Add codec_string_to_id() to map catalog codec strings to FFmpeg IDs
- Support H.264 (h264/avc/avc1), HEVC (hevc/h265/hev1/hvc1),
VP9 (vp9/vp09), AV1 (av1/av01), and VP8
- Read codec from config->codec/codec_len instead of hardcoding H.264
Pixel format handling:
- Add current_pix_fmt field to track actual decoded pixel format
- Query frame->format after decode instead of assuming YUV420P
- Recreate swscale context when pixel format changes
- Supports any format: YUV420P, YUV420P10LE, YUV444P, NV12, etc.
Resolution handling:
- Remove FRAME_WIDTH/FRAME_HEIGHT (1920x1080) constants
- Initialize frame dimensions to 0, set dynamically from stream
- Try to get dimensions from codec context after avcodec_open2()
if not available in moq_video_config
- Existing mid-stream resolution change handling preserved
Deferred initialization:
- Defer sws_ctx and frame_buffer allocation to first decoded frame
- Allows proper format detection before committing to scaler config
- Reduces wasted allocations when config dimensions are unavailable
Logging improvements:
- Include av_get_pix_fmt_name() for readable format names
- Log codec string, dimensions, and pixel format on initialization
- Log format/dimension changes when scaler is reinitialized
* updated defaults to localhost
* Simplify hang_source: remove debounce mechanism and reduce mutex contention
Major refactoring to simplify the hang_source plugin architecture:
Removed debounce mechanism:
- Removed pending_url, pending_broadcast, settings_changed_time, reconnect_pending fields
- Removed DEBOUNCE_DELAY_MS constant and video_tick polling function
- Settings now apply immediately when user clicks OK (not on every keystroke)
Simplified settings flow:
- hang_source_update() now detects if settings actually changed
- Auto-reconnects when settings change to valid values
- Auto-disconnects and blanks video when settings become invalid
- No more pending vs active settings distinction
Reduced mutex contention:
- Added fast-path shutting_down.load() checks before acquiring mutex in callbacks
- on_session_status, on_catalog, on_video_frame, hang_source_decode_frame all
check the atomic flag first for early exit without lock acquisition
Result: 62 fewer lines of code, cleaner architecture, same functionality.
* Rebranding:
Hang Source ➡️ MoQ Source
hang_source ➡️ moq_source
(filenames and variables too)
* removed redundant check, match all "avc" and "h264" to AV_CODEC_ID_H2641 parent c1bff71 commit f833d0d
File tree
6 files changed
+1039
-7
lines changed- src
6 files changed
+1039
-7
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
54 | 61 | | |
55 | 62 | | |
56 | 63 | | |
| 64 | + | |
57 | 65 | | |
58 | 66 | | |
59 | 67 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
4 | | - | |
5 | | - | |
6 | | - | |
7 | | - | |
8 | | - | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
84 | 84 | | |
85 | 85 | | |
86 | 86 | | |
87 | | - | |
| 87 | + | |
88 | 88 | | |
89 | 89 | | |
90 | 90 | | |
| |||
0 commit comments