gpt4 book ai didi

python-3.x - 从 h264 帧解析数据包时 PyAV 不一致

转载 作者:行者123 更新时间:2023-12-04 22:46:48 46 4
gpt4 key购买 nike

当生成 H.264 帧并使用 pyAV 解码它们时,只有在调用 parse 时才会从帧中解析数据包。方法两次。
考虑以下测试 H.264 输入,使用以下命令创建:ffmpeg -f lavfi -i testsrc=duration=10:size=1280x720:rate=30 -f image2 -vcodec libx264 -bsf h264_mp4toannexb -force_key_frames source -x264-params keyint=1:scenecut=0 "frame-%4d.h264"现在,使用 pyAV 解析第一帧:

import av
codec = av.CodecContext.create('h264', 'r')
with open('/path/to/frame-0001.h264', 'rb') as file_handler:
chunk = file_handler.read()
packets = codec.parse(chunk) # This line needs to be invoked twice to parse packets
除非再次调用最后一行( packets = codec.parse(chunk)),否则数据包保持为空
此外,对于我无法描述的不同现实生活示例,似乎从数据包中解码帧也需要多次解码调用:
packet = packets[0]
frames = codec.decode(packet) # This line needs to be invoked 2-3 times to actually receive frames.
有谁知道 pyAV 这种不一致的行为?
(在 macOS Monterey 12.3.1、ffmpeg 4.4.1、pyAV 9.0.2 上使用 Python 3.8.12)

最佳答案

这是预期的 PyAV 行为。不仅,这是底层 libav 的预期行为。 .一个数据包不能保证一个帧,在产生一个帧之前可能需要多个数据包。这在 FFmpeg's video decoder example 中很明显。 :

    while (ret >= 0) {
ret = avcodec_receive_frame(dec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
如果它需要更多的数据包来形成一个帧,它会抛出 EAGAIN错误。
[编辑]
实际上,上面的例子并不是一个很好的例子,因为它只是在 EAGAIN 上退出。 .要检索帧,它应该是 continueEAGAIN :
    while (ret >= 0) {
ret = avcodec_receive_frame(dec_ctx, frame);
if (AVERROR(EAGAIN))
continue;
if (ret == AVERROR_EOF)
return;
[编辑]
pyav的codec.parse()
有时需要额外调用的解码是一个众所周知的事实,但需要刷新的解析器不太常见。以下是 PyAV 和 FFmpeg 的区别:
PyAV 使用 av_parser_parse2() 解析输入数据像这样 [ref] :

while True:

with nogil:
consumed = lib.av_parser_parse2(
self.parser,
self.ptr,
&out_data, &out_size,
in_data, in_size,
lib.AV_NOPTS_VALUE, lib.AV_NOPTS_VALUE,
0
)
err_check(consumed)

# ...snip...

if not in_size:
# This was a flush. Only one packet should ever be returned.
break

in_data += consumed
in_size -= consumed

if not in_size:
# Aaaand now we're done.
break

所以它会一直读取,直到输入数据被 100% 消耗,并注意它不会调用 av_parser_parse2在缓冲区的末尾(这是有道理的,因为输入数据可能只是流数据的一部分。
相比之下,FFmpeg 不调用 av_parser_parse2直接使用 parse_packet 你可以看到它是如何处理类似情况的:
while (size > 0 || (flush && got_output)) {
int64_t next_pts = pkt->pts;
int64_t next_dts = pkt->dts;
int len;

len = av_parser_parse2(sti->parser, sti->avctx,
&out_pkt->data, &out_pkt->size, data, size,
pkt->pts, pkt->dts, pkt->pos);
它调用 av_parser_parse2还可以在输入数据流用完后刷新流。因此,您需要在 PyAV 中执行相同的操作:读取所有帧后,调用 codec.parse()最后一次刷新最后一个数据包。

关于python-3.x - 从 h264 帧解析数据包时 PyAV 不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71724612/

46 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com