Skip to content

feat(linux): add zero-copy v4l2 encoder - #5717

Draft
GenshinImpactStarts wants to merge 6 commits into
LizardByte:masterfrom
GenshinImpactStarts:feat-v4l2-encoder
Draft

GenshinImpactStarts wants to merge 6 commits into
LizardByte:masterfrom
GenshinImpactStarts:feat-v4l2-encoder

Conversation

@GenshinImpactStarts

Copy link
Copy Markdown

Description

This PR introduces a zero-copy V4L2 hardware encoder path on Linux, targeting embedded devices such as Raspberry Pi. It currently supports baseline YUV420 8-bit encoding, integrates with existing capture backends, and syncs with the Web UI settings. The implementation follows the VAAPI approach: exporting DMA-BUF fds and using EGL for color conversion.

Implementation

  • Adds a new V4L2 encoder that exports DMA-BUF fds and performs EGL-based color conversion, mirroring the existing VAAPI path.
  • Wires the encoder into the existing capture backends and exposes the relevant options in the Web UI.
  • Initially supports YUV420 8-bit; additional formats can be added later.

Required AVCodec integration changes

The V4L2 M2M path differs from the existing AVCodec initialization and usage paths, so several supporting changes were necessary:

  • Added extra virtual functions to avcodec_encode_device_t:
    • load_opened_context: retrieves the AVCodec context during encoder initialization to extract V4L2 DMA-BUFs.
    • send_frame: V4L2 buffers are managed by FFmpeg, so additional metadata must be passed during encoding to interact with the FFmpeg patches.
  • AVCodec does not guarantee that a frame passed in immediately yields the encoded packet for that frame. This is especially true for embedded V4L2 encoders. Therefore, the validate_config path now manually passes a terminating packet (nullptr) to flush the encoder.
  • AVCodec also does not guarantee that the first frame is a single packet. On Raspberry Pi 4B, V4L2 first emits a separate SPS+PPS packet, then an IDR packet. This does not match Moonlight's expected format. To handle this, validate_config now records the packet count of the first frame and concatenates them when the actual packets are produced.
  • Some GL functions used by the current code are not available on older Raspberry Pi 4B drivers (eglCreateImage, eglDestroyImage, FramebufferTexture). Fallbacks are provided for these older drivers.
  • The H.264 test was changed from 60 fps to 30 fps, because the Raspberry Pi 4B V4L2 encoder cannot run 1080p at 60 fps.

Testing and limitations

Tested only on Raspberry Pi 4B running Debian 12. Due to limitations, I was unable to compile on Windows, so the impact on other codecs has not been tested. It would be helpful if CI could generate artifacts for further testing.

This PR is quite large, so I've roughly split the changes into logical commits; it's best reviewed commit by commit.

Note: This PR depends on LizardByte/build-deps#781, which adds the two required FFmpeg patches for V4L2 zero-copy support.

Screenshot

Issues Fixed or Closed

Roadmap Issues

Type of Change

  • feat: New feature (non-breaking change which adds functionality)
  • fix: Bug fix (non-breaking change which fixes an issue)
  • docs: Documentation only changes
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semicolons, etc.)
  • refactor: Code change that neither fixes a bug nor adds a feature
  • perf: Code change that improves performance
  • test: Adding missing tests or correcting existing tests
  • build: Changes that affect the build system or external dependencies
  • ci: Changes to CI configuration files and scripts
  • chore: Other changes that don't modify src or test files
  • revert: Reverts a previous commit
  • BREAKING CHANGE: Introduces a breaking change (can be combined with any type above)

Checklist

  • Code follows the style guidelines of this project
  • Code has been self-reviewed
  • Code has been commented, particularly in hard-to-understand areas
  • Code docstring/documentation-blocks for new or existing methods/components have been added or updated
  • Unit tests have been added or updated for any new or modified functionality

AI Usage

See our AI usage policy.

  • None: No AI tools were used in creating this PR
  • Light: AI provided minor assistance (formatting, simple suggestions)
  • Moderate: AI helped with code generation or debugging specific parts
  • Heavy: AI generated most or all of the code changes

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
36 New issues
3.4% Duplication on New Code (required ≤ 2%)
2 New Bugs (required ≤ 0)
E Reliability Rating on New Code (required ≥ A)
34 New Code Smells (required ≤ 0)
3 Duplicated Blocks on New Code (required ≤ 0)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant