3

我正在尝试从来自轴摄像头的 rtp 流中解析不同的 mpeg4 帧,并使用 avcodec_decode_video 函数将数据包提供给 ffmpeg 库。这是我正在执行的步骤 1. rtsp 流已初始化 2. rtp 流开始流入 3. 我收到的第一个数据包以 000001b0... 开头,随后是配置数据,之后该帧以 000001b6.. 第二个 rtp 有效负载开始会有所不同,直到我得到一个设置了标记位的 rtp 数据包。之后我再次收到以 000001b6 开头的数据包,然后继续大约 5-10 个 rtp 数据包.. 这种模式重复

我正在做的是如果我检测到 000001b0/b6 - 在正确初始化解码器上下文之后,我将累积所有之后的数据包并将更大的缓冲区提供给 libavcodec 的 avcodec_decode_video 函数。

但是我在这里得到了一张糟糕的图片,最上面的部分是一个单杠 - 清晰的图片,其余的都很糟糕。我不确定它为什么会这样。请帮我

我在 rtp 数据包中获得的数据是动态 96。

需要注意的一点:当我传递专注于其他制造商专有协议的 iframe 和 p 帧时,ffmpeg 能够解析并提供非常好的图片。

任何帮助表示赞赏

4

1 回答 1

9

尝试在 AXIS IP 摄像机上调整 MPEG4 流设置。注意您应该设置的视频和图像/高级部分:

  1. 视频对象类型:简单
  2. [x] 符合 ISMA
  3. GOV 结构:IP

此外,尝试更改“优先级”或“优化视频流”设置(您应该有帧速率、图像质量、带宽,无)。

如果这些都不起作用,请阅读更多...

我希望您了解 MPEG4 流是如何通过 RTP 传输的。简而言之(如果您不确定如何):

  1. “配置框架”(Visual Object Sequence Start)以整数000001B0(十六进制)开头。它包含要解码的视频所需的数据。您只需在第一次尝试解码流时将其发送到解码器,它用于解码其后出现的所有 VOP。请注意,AXIS 在 SDP 中发送此数据包(在 RTSP 中响应 DESCRIBE),例如: a=fmtp:96 profile-level-id=245; config=000001B0F5000001B5891300000100000001200086C40FA28A021E0A21. 因此,如果流永远不会改变,并且您在 SDP 中得到了这个,那么您不需要将 VOS 传递给解码器......但如果这样做,就没有害处。

  2. 视频对象平面(I-VOP、P-VOP、B-VOP)以整数开头000001B6。如果您将 GOV 长度设置为 10,并且将流的结构设置为“IP”,您将获得 1 个 I-Frame (I-VOP) 和 9 个 P-VOP-s,但都将具有000001B6起始代码。区分它们的技巧是检查第 5 个字节中的下两个 BITS。检查表格以确定您获得的 VOP 类型:

    VOP_CODING_TYPE (binary)  Coding method
                          00  intra-coded (I)
                          01  predictive-coded (P)
                          10  bidirectionally-predictive-coded (B)
                          11  sprite (S)
    

现在,要解码视频,您必须将 VOS 发送到解码器,然后立即发送 I-VOP。但是首先,您从 RTP 流中提取这些帧的方式很尴尬……如果 I-VOP 的大小为 10000B,而您的网络 MTU 为 1400B,则您无法按原样发送它并且不会出现网络拥塞。因此,AXIS 摄像机将 I-VOP 和所有其他 BIG 帧拆分为片段,通过 RTP 作为大小不超过 MTU 的 RTP 数据包发送。主要思想是这个(例子):

  1. 将 10000B 拆分为 MTU 大小的片段(对于 1400B MTU,您会得到大约 8x[1400B] 和 1x[200B] 片段)
  2. 发送 RTP MARKER BIT 设置为 0 的每一个
  3. 发送 RTP MARKER BIT 设置为 1 的最后一个片段以标记最后一个片段

现在,当你收到这个时,你有点明白了,但你需要恢复原始的 10KB FRAME 以便解码器对其进行解码。你正在做的事情,你只是解码大得多的帧的第一个 MTU 字节,你发送到解码器的所有其他片段都被丢弃。这就是为什么你可以得到糟糕的照片......

要恢复原始帧:

  1. 接收起始码000001B6000001B0RTP MARKER位为0的包。如果MARKER设置为1,就是整帧,可以直接解码!如果为 0,则后面有更多部分...
  2. 将第一个片段所有随后的片段放入缓冲区,直到获得一个 MARKER BIT 设置为 1 的片段。当您获得最后一个片段时,将其放入缓冲区。
  3. 您的缓冲区现在包含一整帧,您可以将其发送到解码器!

在那里,希望我能帮助... :)

于 2011-01-26T09:29:03.310 回答