You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
My use case requires me to decode multiple video streams at the same time. The source files can be of extremely high bitrate, 4K videos, so I would like to be mindful of how I use the GPU.
My root issue is that I cannot find any guarantee of when I might receive a frame or when I need to send more data to the decoder. If I investigate the packets and check the P or B frames, I see no reason why a packet would not be sent to the output. When I call flush I receive frames in the output perfectly.
Based on that experience, I thought I could decode GOPs, then call flush. In terms of decoding the bare minimum it's far from optimal, but at least it gives me some guarantee of when I can receive a frame. However, this is not trivial to do either since I work with libav under the hood, what I consider a keyframe might not be accepted by WebCodecs. Same issue as described here. The idea of flush without invalidating whatever inner state it has seemed like a good idea to me.
The answer to my question could be the optimizeForLatency, as in the specification it seems to do exactly what I want. However, as I read the threads here, I am now confused on what it does and what it doesn't. As @dalecurtis mentioned here, in Chromium, this flag does not affect flush directly, just omits using threading which can hold back frames. According to another thread though, I got the impression this only applies to software decoders, not hardware-accelerated ones. Does this have an effect in hw-accelerated decoding? If so, what are the performance drawbacks to consider?
Very different in nature but what I love about FFmpeg/libav is that this is very trivial to do:
intret=avcodec_receive_frame(decoder->codec_ctx, decoder->frame);
if (ret==AVERROR(EAGAIN)) {
// I know the decoder needs more frames before it can give me something
}
To summarize, my question is how can I have a guarantee that I passed enough packets (or how can I know for sure that I didn't ) to the VideoDecoder to surely have an output? Ideally, I want to decode the smallest amount possible for a guaranteed output.
Generally speaking you're meant to use the dequeue events / queue size and target the minimum number of outstanding frames you need. E.g., something like:
var active_outputs = []
function maybeScheduleDecode() {
if (active_outputs.size() >= TARGET_FRAME_COUNT) {
return;
}
decoder.decode(getNextPacket());
}
decoder.ondeque = maybeScheduleDecode;
maybeScheduleDecode();
// ...
// Later when releasing a frame:
active_outputs[0].close();
active_outputs.shift();
maybeScheduleDecode();
There's also an attribute if you don't want to use events:
Thank you @dalecurtis. That's a good point, the decodeQueueSize allows me not to decode too much ahead of time.
Still, I'm hoping to optimize more. This is an example of an h264 stream, where I want to extract a thumbnail, so in this case, getting one frame is perfectly enough for me. Here, I'm showing the presentation timestamp of what I decode, when the decoder signals dequeue and when I receive a decoded frame.
I don't understand why I receive the first frame so late and decoding so many frames has a definite impact on performance. If I call flush after the keyframe the problem is solved for this video, but that method breaks somewhere else. For interlaced videos, libav can give me the first half of the frame marked as keyframe and the second as a non-keyframe. This might be a framework issue, and I can try to peek into the stream to have a strong guess on what to expect from the VideoDecoder after calling flush. This is just one example (there might be other) why I find it hard to optimize here.
Having a way to know if the decoder would give me something in case of a flush would be a game-changer here. If not possible, understanding why I need to give the decoder so many frames would also be helpful.
At present there's not a better way. Even the user agent can't always know if the hardware framework (E.g., MediaCodec, MediaFoundation, AVFoundation, etc) will want more frames beyond what is required by the bitstream (see see #732).
Providing inputs until you get an output one per dequeue is the only surefire approach at the moment.
Activity
dalecurtis commentedon Jul 24, 2025
Generally speaking you're meant to use the
dequeueevents / queue size and target the minimum number of outstanding frames you need. E.g., something like:There's also an attribute if you don't want to use events:
webcodecs/samples/lib/video_renderer.js
Line 110 in 1e0cab7
bartadaniel commentedon Jul 25, 2025
Thank you @dalecurtis. That's a good point, the
decodeQueueSizeallows me not to decode too much ahead of time.Still, I'm hoping to optimize more. This is an example of an h264 stream, where I want to extract a thumbnail, so in this case, getting one frame is perfectly enough for me. Here, I'm showing the presentation timestamp of what I decode, when the decoder signals dequeue and when I receive a decoded frame.
I don't understand why I receive the first frame so late and decoding so many frames has a definite impact on performance. If I call
flushafter the keyframe the problem is solved for this video, but that method breaks somewhere else. For interlaced videos, libav can give me the first half of the frame marked as keyframe and the second as a non-keyframe. This might be a framework issue, and I can try to peek into the stream to have a strong guess on what to expect from theVideoDecoderafter callingflush. This is just one example (there might be other) why I find it hard to optimize here.Having a way to know if the decoder would give me something in case of a
flushwould be a game-changer here. If not possible, understanding why I need to give the decoder so many frames would also be helpful.dalecurtis commentedon Jul 28, 2025
At present there's not a better way. Even the user agent can't always know if the hardware framework (E.g., MediaCodec, MediaFoundation, AVFoundation, etc) will want more frames beyond what is required by the bitstream (see see #732).
Providing inputs until you get an output one per dequeue is the only surefire approach at the moment.