从rtp数据包中解析MPEG4帧

Alt*_*f M 3 ffmpeg rtp mpeg-4

我试图从来自轴摄像机的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.

需要注意的是:当我传递iframes和p帧时,这些帧全神贯注于其他制造商的propreitary协议中,ffmpeg能够解析并提供非常好的pcitures.

任何帮助表示赞赏

Cip*_*ipi 9

尝试在AXIS IP摄像机上摆弄您的MPEG4流设置.注意视频和图像/高级部分,你应该设置它:

  1. 视频对象类型:SIMPLE
  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帧(I-VOP)和9个P-VOP-s,但所有都将具有000001B6起始码.区分它们的技巧是检查第五个字节中的下两个BITS.检查表格以确定您获得的VOP类型:

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

现在,要解码视频,您必须将VOS发送到解码器,然后立即进行I-VOP.但是,你从RTP流中提取这些帧的方式很难......如果I-VOP的大小是10000B,而你的网络MTU是1400B,你就不能按原样发送它而没有网络拥塞.因此,AXIS摄像机将I-VOP和所有其他BIG帧分成FRAGMENTS,它通过RTP发送为RTP数据包,其大小不超过MTU.主要思想是这个(例子):

  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. 您的缓冲区现在包含一个可以发送到解码器的整个帧!

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