Skip to content

Hevc vaapi encoder - #101

Open
Tahinli wants to merge 10 commits into
chromeos:mainfrom
Tahinli:hevc-vaapi-encoder
Open

Hevc vaapi encoder#101
Tahinli wants to merge 10 commits into
chromeos:mainfrom
Tahinli:hevc-vaapi-encoder

Conversation

@Tahinli

@Tahinli Tahinli commented Aug 14, 2026

Copy link
Copy Markdown

I don't know if you guys are active and want to add new things but here is hevc vaapi encoder

Tahinli added 10 commits August 13, 2026 07:06
0.0.13 is the current release of the safe libva bindings; nothing in this
crate needs adapting for it.

Note that neither 0.0.13 nor cros-libva git HEAD compiles against libva
1.22 or newer system headers: those moved seg_id_block_size and
va_reserved8 into VAEncPictureParameterBufferVP9, and cros-libva writes an
exhaustive struct literal for it, so the vaapi feature fails to build with
E0063 on such a system until that one-line cros-libva fix (submitted
separately) is released.
After emitting an emulation prevention byte, the byte that triggered it
was dropped from the two byte lookbehind, so a run of five or more zeroes
was only escaped once and the output contained a byte aligned 0x00 0x00
0x00 sequence, which 7.4.2 forbids.

Keep the triggering byte pending instead, so that it counts towards the
next pair, and cover the case in the unit test.
A bitstream writer with optional emulation prevention, mirroring the
H.264 one. The only difference is the NALU header, which is two bytes
long in H.265 (7.3.1.2).
Builders for the parameter sets an encoder produces, covering the syntax
elements it is expected to set and leaving everything else at its
specification default. SpsBuilder and PpsBuilder inherit what the
parameter set they refer to already decided, and their build() repeats
the derivations the parser performs, so that a built parameter set
compares equal to a parsed one.
Serializes VPS, SPS and PPS structures back into NALUs, following the
read order of the parser field for field. Multi-layer coding, the SCC
extension, non uniform tile spacing and inter RPS prediction are refused,
as the parser does not retain what they would need.

The unit tests build the parameter sets, synthesize them, parse them back
and compare, and re-synthesize the parameter sets of two test streams to
check the output against encoders other than this one.
Mirror the H.264 encoder configuration so that the rate control, framerate
and quality bounds a stream starts with can be given up front, and let
EncodeError carry a H.265 synthesizer error.
Add the stateless H.265 codec definition, its backend request and DPB entry
types, and the LowDelay prediction structure delegate. The delegate builds
the VPS, SPS and PPS with the builders from codec/h265 and synthesizes them
into the coded output when they change.

The backend request carries the slice type rather than a parsed slice header,
because codec/h265 has no slice header builder yet.
Fill VAEncSequenceParameterBufferHEVC, VAEncPictureParameterBufferHEVC and
VAEncSliceParameterBufferHEVC from the backend request and submit a single
slice segment covering the picture. Map Main and Main10 onto the matching VA
profiles and the rate control variants onto CQP and CBR, leaving it to the
driver to reject a combination it does not implement.
Let the C2 VAAPI encoder instantiate the stateless H.265 encoder, and teach
ccenc to ask for it with --codec h265. Like H.264, the elementary stream is
written as a plain Annex B byte stream rather than wrapped in IVF.
The synthesized parameter sets promised three things a VA-API backend does
not keep, each of which desyncs CABAC and leaves the rest of the picture read
as coefficient data:

  - max_transform_hierarchy_depth_intra/_inter defaulted to 0, which says
    split_transform_flag is never coded and a decoder infers no split. A
    hardware encoder splits transform trees wherever the residual asks for
    it, so its split flags were read as residual from the first CTU on.
  - cu_qp_delta_enabled_flag was off, so cu_qp_delta_abs had nowhere to be
    coded, while the driver's rate controller moves the QP between coding
    tree blocks and codes the delta regardless.
  - the picture was declared aligned to MinCbSizeY, so a 1080 line picture
    claimed a 56 line bottom CTB row where the encoder had coded a full 64.
    It is now declared at CtbSizeY and cropped back with the conformance
    window, as the reference VA-API encoders do.

Measured on radeonsi/VCN at 1080p, each in isolation against the source:
depth 0 scores SSIM 0.17 with 371 decoder complaints, cu_qp_delta off 0.17,
the MinCbSizeY alignment 0.22; all three fixed scores 0.98 with a silent
decoder. Flat synthetic input passes either way, which is why this was not
caught by a round trip that only counts frames.
@google-cla

google-cla Bot commented Aug 14, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@rosetta-jpn

Copy link
Copy Markdown
Collaborator

Hi, we already have HEVC VA-API encoder implementation in the Google internal branch.
I am thinking to publish the internal branch in the future but I cannot promise the timeline.
In the meantime, I would appreciate it if you are waiting for it.

We are actively developing cros-codecs in the internal branch.
Some features have already implemented. You could avoid a duplicated work by filing an issue. I will respond it whether it's been implemented.

I apologize for the inconvenience.

@Tahinli

Tahinli commented Aug 15, 2026

Copy link
Copy Markdown
Author

Hi, I understand. Thank you.

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.

2 participants