Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

encode2 (old) FFmpeg API affecting encoder latency #131

Open
bmegli opened this issue Mar 20, 2023 · 8 comments
Open

encode2 (old) FFmpeg API affecting encoder latency #131

bmegli opened this issue Mar 20, 2023 · 8 comments

Comments

@bmegli
Copy link

bmegli commented Mar 20, 2023

Short Description

FFmpeg introduced "new" API around 2016

The old API (encode2) generally can return only single packet per-frame (unless draining).

Cold encoder init may take a lot of time (100 ms order).

By the time we get first packet from encoder:

  • a few packets are are already queued and ready
  • but only one of them is returned on each encode
  • and the latency that sets initially is kept until end of encoding session
@bmegli
Copy link
Author

bmegli commented Mar 20, 2023

Above is only important for low-latency streaming (real-time)

@bmegli
Copy link
Author

bmegli commented Mar 20, 2023

Checking if you are affected

The easiest way is to dump number or ready packets waiting when FFmpeg asks for packet.

Add cerr << "ctx->packet_pools->size() = " << ctx->packet_pools->size() << endl;

Before popping next packet:

packet_index= ctx->packet_pools->front();

You will see how much packets are pending

  • e.g. 6 packets with 30 fps
  • means added ~200 ms latency (6 * 33.3(3) ms)

@bmegli
Copy link
Author

bmegli commented Mar 20, 2023

Side Effects

The fact that we are lagging a few packets behind makes #130 non-fatal

There is concurrency issue but it generally affects fresh data.

We are typically working on data lagging a few packets behind

@bmegli
Copy link
Author

bmegli commented Mar 20, 2023

Workarounds

Decrease ffmpeg-jetson num_capture_buffers through FFmpeg

-num_capture_buffers <int>        E..V..... Number of buffers in the capture context (from 1 to 32) (default 10)

This limits the number of pending packets possible

In L4T 5.1 with AGX Orin lowest safe value is 4 (see below).

Beware

Nvidia nvmpi doesn't respect all values.

In L4T 5.1 with AGX Orin requesting anything <= 3 results in

ctx->enc->capture_plane.getNumBuffers() = 3 ctx->enc->output_plane.getNumBuffers() = 4

You can check what happens for you by adding

  • cerr << "capture.getNumBuffers() = " << ctx->enc->capture_plane.getNumBuffers() << " output.getNumBuffers() = " << ctx->enc->output_plane.getNumBuffers() << endl;
  • after

ret = ctx->enc->capture_plane.setupPlane(V4L2_MEMORY_MMAP, ctx->packets_num, true, false);

Side Effects

jetson-ffmpeg

  • uses getNumBuffers() in some places
  • in other FFmpeg input stored in ctx->packets_num

When nvidia-nvmpi doesn't respect your request

  • those values become different

Exploit

Setting num_capture_buffers to 1 results in:

  • ctx->enc->capture_plane.getNumBuffers() = 3 ctx->enc->output_plane.getNumBuffers() = 4
  • and fresh packet always overwritten at first buf_index due to
    ctx->buf_index=(ctx->buf_index+1)%ctx->packets_num;

You will:

@bmegli
Copy link
Author

bmegli commented Mar 20, 2023

Improving Latency (sane way)

Implement jetson-ffmpeg with new FFmpeg API

  • send_frame and receive_packet

Which allows easily getting any pending packets (multiple packets per frame)

This task is non-trivial.

bmegli added a commit to Extend-Robotics/jetson-ffmpeg that referenced this issue Mar 20, 2023
- FFmpeg patch with new API implementation
- see patch for the details

Related to:
- jocover#131
bmegli added a commit to bmegli/jetson-ffmpeg that referenced this issue Mar 20, 2023
- FFmpeg patch with new API implementation
- see patch for the details

Fix for:
- jocover#131
@bmegli
Copy link
Author

bmegli commented Mar 20, 2023

Functional fix is in #132

  • fixes latency issues

It has other drawback - may miss last few packets in case of EOS.

Choose your poison.

Keylost added a commit to Keylost/jetson-ffmpeg that referenced this issue Mar 23, 2023
@Keylost
Copy link

Keylost commented Mar 23, 2023

No need to choose poison) I have added some measures to prevent packet loss

@bmegli
Copy link
Author

bmegli commented Mar 23, 2023

@Keylost

Your EOS handling looks reasonable

Looks like you ventured as far as to Nvidia V4L2 extensions docs

EOS Handling

The following sequence must be followed for sending EOS and recieving EOS from the encoder.

  1. Send EOS to encoder by queueing on the output plane a buffer with bytesused = 0 for the 0th plane (v4l2_buffer.m.planes[0].bytesused = 0).
  2. Dequeues buffers on the capture plane until it gets a buffer with bytesused = 0 for the 0th plane.

Or guessed it from their 2500 lines lump of code "example"

  • /usr/src/jetson_multimedia_api/samples/01_video_encode/video_encode_main.cpp

Anyway, your implementation looks like the one most ahead now

  • nv_buf_utils and NVUtils support (old L4T, new L4T)
  • fixed decoding performance in newer L4T + Jetpack
  • fixed encoder latency issue
  • FFmpeg 4, 5, 6 support
  • and a few other fixes

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

No branches or pull requests

2 participants