gpt4 book ai didi

networking - 以有用的形式保存 H264 RTP 数据包

转载 作者:行者123 更新时间:2023-12-04 23:29:24 25 4
gpt4 key购买 nike

我知道可以使用 Wireshark 和 VLC 保存 RTP h264 流。但为了更多地了解视频流,我正在尝试自己做。有几个相关的问题可以很好地阅读这个主题:

How to process raw UDP packets so that they can be decoded by a decoder filter in a directshow source filter

Problem to Decode H264 video over RTP with ffmpeg (libavcodec)

How to convert H.264 UDP packets to playable media stream or file (defragmentation)

以这些为背景,这就是我目前所处的位置:

  • 我可以通过 UTP 接收 RTP 数据包。
  • 我按照上述问题中的讨论解析数据包。
  • 我将数据包写入文件,以\x000001 分隔,并根据上述指南再次添加 NAL 字节。
  • 在文件的开头,我放置了从我的代码与服务器的 RTSP 对话中获得的 SPS 和 PPS(再次由正确的字节分隔)。

  • 我最终得到了一个据说有很多 NAL 帧的文件。然后我尝试在 .264 文件上运行 ffmpeg 以创建 .mp4。这带来了几个错误:

    [h264 @ 0x15257a0] decode_slice_header 错误

    [h264@0x15257a0] 没有框架!

    [h264 @ 0x15257a0] 引用了不存在的 PPS

    [h264 @ 0x15257a0] 引用了不存在的 PPS 0

    [buffer @ 0x15e16a0] 无效的像素格式字符串'-1'

    在我弄清楚这个问题之前,我基本上处于停滞状态。我已经彻底阅读了上面链接到的问题,并且该流绝对是可见的,因为我可以通过 VLC 连接和观看它,并且根据wireshark,传入的数据包肯定是 H264 RTP 数据包。如果 VLC 可以做到,为什么我不能!我将不胜感激对我的错误的任何洞察以及可能解决它们之间分歧的三个相关问题的总结。

    最佳答案

    How to process raw UDP packets so that they can be decoded by a decoder filter in a directshow source filter

    它有你需要的答案,但过程是这样的:

    //Determine if the forbidden bit is set and the type of nal from the first byte
    byte firstByte = packetData[offset];

    //bool forbiddenZeroBit = ((firstByte & 0x80) >> 7) != 0;

    byte nalUnitType = (byte)(firstByte & Common.Binary.FiveBitMaxValue);

    //o The F bit MUST be cleared if all F bits of the aggregated NAL units are zero; otherwise, it MUST be set.
    //if (forbiddenZeroBit && nalUnitType <= 23 && nalUnitType > 29) throw new InvalidOperationException("Forbidden Zero Bit is Set.");

    //Determine what to do
    switch (nalUnitType)
    {
    //Reserved - Ignore
    case 0:
    case 30:
    case 31:
    {
    return;
    }
    case 24: //STAP - A
    case 25: //STAP - B
    case 26: //MTAP - 16
    case 27: //MTAP - 24
    {
    //Move to Nal Data
    ++offset;

    //Todo Determine if need to Order by DON first.
    //EAT DON for ALL BUT STAP - A
    if (nalUnitType != 24) offset += 2;

    //Consume the rest of the data from the packet
    while (offset < count)
    {
    //Determine the nal unit size which does not include the nal header
    int tmp_nal_size = Common.Binary.Read16(packetData, offset, BitConverter.IsLittleEndian);
    offset += 2;

    //If the nal had data then write it
    if (tmp_nal_size > 0)
    {
    //For DOND and TSOFFSET
    switch (nalUnitType)
    {
    case 25:// MTAP - 16
    {
    //SKIP DOND and TSOFFSET
    offset += 3;
    goto default;
    }
    case 26:// MTAP - 24
    {
    //SKIP DOND and TSOFFSET
    offset += 4;
    goto default;
    }
    default:
    {
    //Read the nal header but don't move the offset
    byte nalHeader = (byte)(packetData[offset] & Common.Binary.FiveBitMaxValue);

    if (nalHeader > 5)
    {
    if (nalHeader == 6)
    {
    Buffer.WriteByte(0);
    containsSei = true;
    }
    else if (nalHeader == 7)
    {
    Buffer.WriteByte(0);
    containsPps = true;
    }
    else if (nalHeader == 8)
    {
    Buffer.WriteByte(0);
    containsSps = true;
    }
    }

    if (nalHeader == 1) containsSlice = true;

    if (nalHeader == 5) isIdr = true;

    //Done reading
    break;
    }
    }

    //Write the start code
    Buffer.Write(NalStart, 0, 3);

    //Write the nal header and data
    Buffer.Write(packetData, offset, tmp_nal_size);

    //Move the offset past the nal
    offset += tmp_nal_size;
    }
    }

    return;
    }
    case 28: //FU - A
    case 29: //FU - B
    {
    /*
    Informative note: When an FU-A occurs in interleaved mode, it
    always follows an FU-B, which sets its DON.
    * Informative note: If a transmitter wants to encapsulate a single
    NAL unit per packet and transmit packets out of their decoding
    order, STAP-B packet type can be used.
    */
    //Need 2 bytes
    if (count > 2)
    {
    //Read the Header
    byte FUHeader = packetData[++offset];

    bool Start = ((FUHeader & 0x80) >> 7) > 0;

    //bool End = ((FUHeader & 0x40) >> 6) > 0;

    //bool Receiver = (FUHeader & 0x20) != 0;

    //if (Receiver) throw new InvalidOperationException("Receiver Bit Set");

    //Move to data
    ++offset;

    //Todo Determine if need to Order by DON first.
    //DON Present in FU - B
    if (nalUnitType == 29) offset += 2;

    //Determine the fragment size
    int fragment_size = count - offset;

    //If the size was valid
    if (fragment_size > 0)
    {
    //If the start bit was set
    if (Start)
    {
    //Reconstruct the nal header
    //Use the first 3 bits of the first byte and last 5 bites of the FU Header
    byte nalHeader = (byte)((firstByte & 0xE0) | (FUHeader & Common.Binary.FiveBitMaxValue));

    //Could have been SPS / PPS / SEI
    if (nalHeader > 5)
    {
    if (nalHeader == 6)
    {
    Buffer.WriteByte(0);
    containsSei = true;
    }
    else if (nalHeader == 7)
    {
    Buffer.WriteByte(0);
    containsPps = true;
    }
    else if (nalHeader == 8)
    {
    Buffer.WriteByte(0);
    containsSps = true;
    }
    }

    if (nalHeader == 1) containsSlice = true;

    if (nalHeader == 5) isIdr = true;

    //Write the start code
    Buffer.Write(NalStart, 0, 3);

    //Write the re-construced header
    Buffer.WriteByte(nalHeader);
    }

    //Write the data of the fragment.
    Buffer.Write(packetData, offset, fragment_size);
    }
    }
    return;
    }
    default:
    {
    // 6 SEI, 7 and 8 are SPS and PPS
    if (nalUnitType > 5)
    {
    if (nalUnitType == 6)
    {
    Buffer.WriteByte(0);
    containsSei = true;
    }
    else if (nalUnitType == 7)
    {
    Buffer.WriteByte(0);
    containsPps = true;
    }
    else if (nalUnitType == 8)
    {
    Buffer.WriteByte(0);
    containsSps = true;
    }
    }

    if (nalUnitType == 1) containsSlice = true;

    if (nalUnitType == 5) isIdr = true;

    //Write the start code
    Buffer.Write(NalStart, 0, 3);

    //Write the nal heaer and data data
    Buffer.Write(packetData, offset, count - offset);

    return;
    }

    关于networking - 以有用的形式保存 H264 RTP 数据包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24670366/

    25 4 0