fix: reallocate RAM decode buffer on resolution changes - #46
Conversation
Unreference the cached software frame when decoded dimensions change, so hardware frame transfers allocate a correctly sized output buffer. Signed-off-by: 21pages <sunboeasy@gmail.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (1)
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughThe hardware-acceleration decoder now preserves a newly allocated software frame on the first decode. A new example tests repeated 720p, 360p, and 1080p transitions across available decoders. ChangesHardware frame resolution handling
Priority: ⬇️ Low Estimated code review effort: 2 (Simple) | ~10 minutes Change: Bug fix 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Signed-off-by: 21pages <sunboeasy@gmail.com>
|
For a release that needs this resolution-change fix while retaining the SDK backends and leaving out repeat encoding, create a separate branch in This proposed branch should start from the SDK-preserving code before #43 and include #46's RAM resolution-change fix and validation example, plus 76ca0d7 — fix: close MFX decoder before reallocating surfaces. The additional Intel SDK fix is separate from #46. After that branch is created, RustDesk can reference it in [dependencies.hwcodec]
git = "https://github.com/rustdesk-org/hwcodec"
branch = "fix/ram-decoder-resolution-change"
optional = trueUpdate RustDesk's Native SDK VRAM decoding was tested on Windows by explicitly selecting each SDK backend and retaining one hwcodec decoder instance throughout
The Intel fix closes the SDK decoder before freeing and reallocating its surface pool, releasing the SDK's references so the allocator cannot reuse an old pool with too few surfaces. AMF H.265 is disabled in normal SDK availability enumeration; its result above comes from explicitly selecting that backend and does not change that policy. Adapter entries are not counts of physical GPUs. |
Related to rustdesk/rustdesk#16275
The RAM hardware decoder reuses a software frame whose dimensions can become stale when the stream resolution changes.
RustDesk normally masks this issue: when the controlled device's resolution changes, it sends a
SwitchDisplaymessage that resets and recreates the decoder on the controlling side. However, hwcodec should also handle resolution changes without requiring callers to recreate the decoder, consistent with the other tested decoder paths.To reproduce in RustDesk without this fix, use RAM hardware decoding and connect to a controlled device with at least two displays:
Display 1 shows a black screen. Switching back to single-display mode restores the picture.
Unref the cached software frame when its width or height changes, allowing
av_hwframe_transfer_data()to allocate a buffer with the correct dimensions.The change is limited to the hardware-to-RAM transfer path in
cpp/ffmpeg_ram/ffmpeg_ram_decode.cpp.Validation
Resolution changes were tested while reusing a single decoder instance:
Passed with this fixdenotes dimension checks run with this RAM hardware-transfer fix applied. Software decoding does not use the changed transfer path.An additional resolution-switching check reused each decoder for 100 rounds, without resetting or recreating it between frames or rounds:
31.0.12044.47003.Earlier stress testing on the Intel/NVIDIA machine also covered:
macOS (Apple M1)
Tested commit
df3a224on Apple M1 (arm64), macOS 14.5 (23F79) with the checked-indecode_resolutionexample. Each configuration reused one hwcodec decoder instance for the entire resolution sequence and all rounds, without an explicit reset or recreation.1280x720 -> 640x360 -> 1920x1080 -> 1280x720.leakswith allocation stack logging and reported 0 leaks, 0 total leaked bytes. Physical footprint was 21.5M, with a 28.0M peak, as reported by the tool. No leaks were detected in this run.Linux (AMD VAAPI)
Tested commit
df3a224on AMD Ryzen 7 5800H with Radeon Graphics, Ubuntu 22.04.5 (x86_64), kernel7.2.6-070206-generic, Mesa23.2.1-1ubuntu3.1~22.04.4(radeonsi), and libavcodec61.19.101.The checked-in example reused one hwcodec decoder instance per configuration for the full
1280x720 -> 640x360 -> 1920x1080 -> 1280x720sequence and all rounds.All 4/4 available configurations passed the dimension checks in both runs: 1,600 + 16,000 = 17,600 frames, with exactly one correctly sized frame per packet.
The Linux VAAPI memory check reported leaks. GCC 11 LeakSanitizer reported 944,184 bytes in 13,019 allocations after 1,000 rounds; the process exited with the configured sanitizer status 23 after all dimension checks passed. The allocation stacks point into
radeonsi_drv_video.soandlibdrm_amdgpu.so.1. The detector was validated with a known leaking control program.The changing-resolution workload reported 9,120 bytes after 1 round, 101,784 bytes after 100 rounds, and 944,184 bytes after 1,000 rounds. Additional 100-round controls produced:
Both comparisons show the same 93,456-byte increase over their fixed-resolution controls. The direct FFmpeg control does not use hwcodec,
sw_frame_, orav_hwframe_transfer_data(), and releases its packets, frames, codec contexts, and device references. This reproduces the growing leak report independently of this RAM-transfer fix. The precise cause within the FFmpeg/VAAPI/driver path remains unresolved.A software-only fixed-720p control, bypassing hardware capability probing, completed 1,000 rounds with no reported leaks and exit status 0. One initial fixed-size direct FFmpeg control exited with SIGSEGV without diagnostics; a repeat completed both codecs and produced the 4,200-byte result above. The cause of that initial failure was not established.
LeakSanitizer build and run:
Linux (Intel VAAPI + NVIDIA NVDEC)
Tested commit
df3a224on Intel Core i5-12400, Intel iGPU8086:4682, and NVIDIA GeForce GTX 1650, running Ubuntu 22.04.4 (x86_64), kernel6.5.0-26-generic. The NVIDIA driver was535.161.07; VAAPI used libva2.15.0and Intel iHD media driver22.3.1. hwcodec linked against vcpkg FFmpeg7.1.1(libavcodec61.19.101).The checked-in example reused one decoder instance per backend/codec configuration for every packet in all rounds, without an explicit reset or recreation. Every packet was required to produce exactly one frame with the expected dimensions for:
On Linux,
available_decoders()probes CUDA before VAAPI and removes later entries for a codec format that already succeeded. The normal pass therefore enumerated NVDEC H.264/HEVC plus software H.264/HEVC. A second pass blocked only the dynamic loading oflibcuda.so, without changing hwcodec, so the sameavailable_decoders()API exercised its VAAPI fallback plus software H.264/HEVC. Explicit VAAPI contexts were also tested independently and produced the same result.Across the six unique backend/codec configurations, this checked 2,400 packets at 100 rounds and 24,000 packets at 1,000 rounds. Every packet produced exactly one correctly sized frame.
Valgrind
3.18.1was first validated with a known leaking program; it correctly reported a deliberately leaked 12,345-byte allocation as definitely lost and returned the configured nonzero status.The CUDA
possibly lostandstill reachablerecords point into NVIDIAlibcuda.so.535.161.07and have identical byte/block totals at 100 and 1,000 rounds. The CUDA run also contains one glibc dynamic-loadermalloc(0)record classified as a zero-byte definitely-lost block, so its configured Valgrind error exit was nonzero despite zero positive bytes in the definite and indirect categories. The VAAPI runs exited with status 0 and zero Valgrind errors.This machine did not reproduce the 944,184-byte growing leak seen on the AMD VAAPI system. Because no positive-byte definite or indirect leak was found, the conditional fixed-720p and direct-FFmpeg comparisons were not needed. Pure software H.264/HEVC was nevertheless included in the 1,000-round Valgrind run. RSS values above are recorded only as operational data; the leak conclusion is based on Valgrind's end-of-process heap scan.
Linux RAM decoding was built without
--features vram; enabling that Windows-oriented feature on Linux currently attempts to compile D3D11 code and fails on the missingd3d11.hheader.Summary by CodeRabbit
Bug Fixes
Tests