Nvv4l2h264enc Level attribute

Hello,

I’m using this pipeline to save a playable file from the camera capture:

gst-launch-1.0 --eos-on-shutdown nvarguscamerasrc sensor_id=0 ! 'video/x-raw(memory:NVMM), width=2712, height=1538, framerate=90/1' ! videorate max-rate=90 ! nvvidconv ! 'video/x-raw(memory:NVMM), format=(string)I420' ! queue leaky=downstream max-size-buffers=30 ! nvv4l2h264enc maxperf-enable=true bitrate=26500000 profile=High insert-aud=true insert-sps-pps=true insert-vui=true ! 'video/x-h264, stream-format=(string)byte-stream, alignment=(string)au, profile=(string)high, level=(string)4.1' ! h264parse config-interval=-1 ! queue leaky=downstream max-size-buffers=200 ! mp4mux name=mux ! filesink location=/home/jetson/test12.mp4 alsasrc buffer-time=100000 latency-time=10000 device=hw:1 ! 'audio/x-raw, format=S16LE, rate=48000, channels=2' ! queue ! opusenc bitrate=64000 frame-size=20 ! mux.

The thing is, I can see in the output

H264: Profile = 100, Level = 41
NVMEDIA_ENC: bBlitMode is set to TRUE

but the output file instead is Constrained High@L5.2

How can I force it to use the lower, custom level? Is it hardcoded in the source?

Thank you!
R

Hi,
It is set per resolution and framerate. according to
Advanced Video Coding - Wikipedia
It looks correct to set to level 5.2.

For 4.1, please try to encode in 1080p30.

Yes, I understand that, but when doing this from nvarguscamerasrc, we can put one caps in between the encoder and rtph264pay and the browser will get via webrtcbin the lower profile + asymmetry-allowed=1, allowing it to play just fine at this resolution, FPS & bitrate. I want to avoid transcoding and we need this quality… Is there any other way? Can’t we hint the encoder?

Hi,
You can add code in gst-v4l2 to overwrite level and rebuild the plugin. Beginning of SPS in encoded H264 stream of 2712x1538p30 looks like

00 00 00 01 67 64 0C 34 … …

And can use the logic to find SPS:
Xavier AGX : Video encoding crash - #15 by DaneLLL

0x67 & 0x1F = 7

0x64 is profile. 0x0C is constrained set flag. 0x34 is level. You can overwrite 0x34 to 0x29.

Wow, your suggestion worked like a charm!

One first needs to exact the h264 stream from the mp4:

ffmpeg -i test.mp4 -c:v copy -an input.h264

Here is the script I came up with ChatGPT:

def modify_sps(input_file, output_file):
    with open(input_file, "rb") as file:
        stream_data = bytearray(file.read())

    # Find the SPS start code: 00 00 00 01 67
    sps_start_code = b'\x00\x00\x00\x01\x67'
    sps_start_index = stream_data.find(sps_start_code)

    if sps_start_index != -1:
        # Offset to the profile, constraint flags, and level_idc position
        profile_index = sps_start_index + 5
        constraint_flags_index = profile_index + 1
        level_index = constraint_flags_index + 1

        # Read current profile, constraint flags, and level
        current_profile = stream_data[profile_index]
        current_constraint_flags = stream_data[constraint_flags_index]
        current_level = stream_data[level_index]

        print(f"Current Profile (Hex): {current_profile:02x}")
        print(f"Current Constraint Flags (Hex): {current_constraint_flags:02x}")
        print(f"Current Level (Hex): {current_level:02x}")

        # Directly modify the constraint flags and level
        stream_data[constraint_flags_index] = 0x00  # Reset constraint flags to 00
        stream_data[level_index] = 0x1F  # Change level to 3.1
        
        with open(output_file, "wb") as file:
            file.write(stream_data)
    else:
        print("SPS start code not found in the stream.")

# Example usage
modify_sps("input.h264", "output.h264")

Run the script and then repack in mp4 (to also copy the audio stream from the original file):

ffmpeg -i output.h264 -i test.mp4 -c:v copy -c:a copy -map 0:v:0 -map 1:a:0 test-hacked.mp4
1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.