forked from marfrit/libva-v4l2-request-fourier
h264: derive sps.level_idc from H.264 Annex A.3 MaxFS
Replaces patch 0013's hardcoded level_idc = 51 with a small lookup
that picks the smallest level whose MaxFS contains the encoded
frame size. Patch 0013's TODO is resolved by this change.
VAAPI does not expose level_idc on the decode side
(VAPictureParameterBufferH264 has no such field; only
VAEncSequenceParameterBufferH264 carries it). The H.264 SPS NAL is
parsed client-side by ffmpeg-vaapi and only slice data forwards in
VASliceDataBuffer, so a SPS-NAL byte parser is not viable from the
bitstream the libva-v4l2-request layer receives. We therefore
derive level_idc from picture dimensions, which VAAPI does provide
in VAPictureParameterBufferH264.picture_{width,height}_in_mbs_minus1.
Annex A.3 (Table A-1) MaxFS thresholds:
Level 1.0: 99 MBs ( 176×144 = 11×9 = 99 )
Level 1.1: 396 ( 352×288 = 22×18 = 396 )
Level 2.0: 396
Level 2.1: 792 ( 352×576 / 720×288 )
Level 2.2: 1620 ( 720×480 ≈ 1350; 720×576 = 1620 )
Level 3.0: 1620
Level 3.1: 3600 (1280×720 ≈ 3600 )
Level 3.2: 5120
Level 4.0: 8192 (1920×1088 = 8160 fits )
Level 4.1: 8192
Level 4.2: 8704
Level 5.0: 22080
Level 5.1: 36864 (3840×2176 = 32640 fits; 4K@8K-edge )
Level 5.2: 36864
Level 6.0: 139264 (8K )
V4L2 control encoding: level_idc = (level major × 10) + (level minor).
Level 4.1 → 41, Level 5.1 → 51, Level 6.0 → 60.
Picks for typical content:
1080p (1920×1088 = 8160 MBs) → Level 4.1 (level_idc = 41)
4K (3840×2176 = 32640 MBs) → Level 5.1 (level_idc = 51)
8K (7680×4352 = 130560 MBs) → Level 6.0 (level_idc = 60)
The previous hardcode of 51 was over-allocating for 1080p; with
this patch hantro can pre-allocate based on the actual frame size.
For our ohm corpus (1080p) this drops the requested DPB / MV
buffer sizing from level-5.1 generosity to level-4.1 right-sized.
Without VAAPI exposing framerate we cannot also check MaxMBPS /
MaxBR / MaxCPB. The frame-size-based pick is acceptable in
practice: temporally-dense streams almost always also push
spatially-large frames, so MaxFS captures the dominant
resource-sizing signal.
Cross-reference: H.264 spec Annex A, Table A-1 ("Level limits").
ext-ctrls-codec-stateless.rst V4L2_CID_STATELESS_H264_SPS lists
level_idc as required-userspace-input, no kernel-derives annotation.
Signed-off-by: Markus Fritsche <fritsche.markus@gmail.com>
This commit is contained in:
+57
-26
@@ -638,6 +638,55 @@ static inline __u8 h264_profile_to_idc(VAProfile profile)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Derive sps.level_idc from the encoded frame size in macroblocks per
|
||||
* H.264 Annex A.3 (Table A-1) MaxFS thresholds. Each level's MaxFS is
|
||||
* the maximum encoded frame size in MBs the level supports; we pick
|
||||
* the smallest level whose MaxFS contains the actual frame size.
|
||||
*
|
||||
* Level decoding for the V4L2 control: level_idc = level * 10
|
||||
* Level 1.0 → 10, Level 4.1 → 41, Level 5.1 → 51, Level 6.0 → 60.
|
||||
*
|
||||
* VAAPI does not expose the bitstream's actual level_idc on the
|
||||
* decode side (VAPictureParameterBufferH264 has no such field) — see
|
||||
* va.h. The H.264 SPS NAL is parsed client-side by ffmpeg-vaapi /
|
||||
* mpv and only slice data is forwarded in VASliceDataBuffer, so a
|
||||
* SPS-NAL byte parser is not viable at this layer.
|
||||
*
|
||||
* Without framerate we cannot also check MaxMBPS / MaxBR / MaxCPB.
|
||||
* That gap is acceptable in practice: consumers that push
|
||||
* temporally-dense streams (high MBPS) almost always also push
|
||||
* spatially-large frames (high MaxFS), so frame-size-based level
|
||||
* selection over-allocates on the temporal axis but never
|
||||
* under-allocates a level the consumer relies on for correct
|
||||
* decode-resource sizing.
|
||||
*
|
||||
* Picks for typical content:
|
||||
* 1080p (8160 MBs) → Level 4.1 (level_idc = 41)
|
||||
* 4K (32400 MBs) → Level 5.1 (level_idc = 51)
|
||||
* 8K (138240 MBs) → Level 6.0 (level_idc = 60)
|
||||
*
|
||||
* Replaces the hardcoded level_idc=51 from patch 0013.
|
||||
*/
|
||||
static inline __u8 h264_derive_level_idc(unsigned int width_in_mbs,
|
||||
unsigned int height_in_mbs)
|
||||
{
|
||||
const unsigned int frame_size_mbs = width_in_mbs * height_in_mbs;
|
||||
|
||||
if (frame_size_mbs <= 99) return 10; /* Level 1.0 */
|
||||
if (frame_size_mbs <= 396) return 11; /* Level 1.1 - 2.0 */
|
||||
if (frame_size_mbs <= 792) return 21; /* Level 2.1 */
|
||||
if (frame_size_mbs <= 1620) return 22; /* Level 2.2 - 3.0 */
|
||||
if (frame_size_mbs <= 3600) return 31; /* Level 3.1 */
|
||||
if (frame_size_mbs <= 5120) return 32; /* Level 3.2 */
|
||||
if (frame_size_mbs <= 8192) return 41; /* Level 4.0 - 4.1 */
|
||||
if (frame_size_mbs <= 8704) return 42; /* Level 4.2 */
|
||||
if (frame_size_mbs <= 22080) return 50; /* Level 5.0 */
|
||||
if (frame_size_mbs <= 36864) return 51; /* Level 5.1 - 5.2 */
|
||||
if (frame_size_mbs <= 139264) return 60; /* Level 6.0 - 6.2 */
|
||||
return 62; /* > Level 6 ceiling */
|
||||
}
|
||||
|
||||
int h264_set_controls(struct request_data *driver_data,
|
||||
struct object_context *context,
|
||||
VAProfile profile,
|
||||
@@ -705,33 +754,15 @@ int h264_set_controls(struct request_data *driver_data,
|
||||
sps.profile_idc = h264_profile_to_idc(profile);
|
||||
|
||||
/*
|
||||
* VAAPI's decode-side VAPictureParameterBufferH264 does not carry
|
||||
* level_idc — see va.h, the field exists only in
|
||||
* VAEncSequenceParameterBufferH264 on the encode path. The H.264
|
||||
* SPS NAL is also not included in VASliceDataBuffer (ffmpeg-vaapi
|
||||
* parses it client-side and forwards only slice data), so a
|
||||
* SPS-NAL byte extractor is not viable from the bitstream we
|
||||
* receive.
|
||||
*
|
||||
* Hantro and other stateless H.264 decoders use level_idc to
|
||||
* pre-allocate decoder resources (DPB, motion-vector buffers); a
|
||||
* zero-init level_idc=0 is invalid (lowest legal is 10 = Level
|
||||
* 1.0) and causes hantro to silently skip the decode hardware
|
||||
* dispatch.
|
||||
*
|
||||
* Hardcode level_idc = 51 (Level 5.1, max for 1080p/4K@30) as a
|
||||
* known-incomplete intermediate. This INTENTIONALLY OVER-ALLOCATES
|
||||
* decoder resources and is sufficient for any stream up to 4K@30.
|
||||
* It is corpus-correct, not contract-correct.
|
||||
*
|
||||
* TODO: derive level_idc from (VAProfile, picture_width_in_mbs,
|
||||
* picture_height_in_mbs) per H.264 Annex A.3 max-MB-per-second
|
||||
* thresholds. That is a small lookup table but requires also
|
||||
* mapping the consumer's framerate, which VAAPI doesn't provide
|
||||
* directly. For now the over-allocation is the upstreamable
|
||||
* compromise.
|
||||
* Derive level_idc from encoded frame size per H.264 Annex A.3.
|
||||
* VAAPI doesn't expose level_idc on the decode side (see
|
||||
* h264_derive_level_idc()'s docblock for the rationale); we pick
|
||||
* the smallest level whose MaxFS contains the picture dimensions.
|
||||
* Replaces patch 0013's intermediate hardcode of 51.
|
||||
*/
|
||||
sps.level_idc = 51;
|
||||
sps.level_idc = h264_derive_level_idc(
|
||||
(unsigned int)surface->params.h264.picture.picture_width_in_mbs_minus1 + 1u,
|
||||
(unsigned int)surface->params.h264.picture.picture_height_in_mbs_minus1 + 1u);
|
||||
|
||||
/*
|
||||
* Build the per-request control list incrementally:
|
||||
|
||||
Reference in New Issue
Block a user