当前位置: 首页 > 知识库问答 >
问题:

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

池宸
2023-03-14

我知道使用Wireshark和VLC保存RTP h264流是可能的。但为了学习更多关于视频流,我正在尝试自己做。有几个相关的问题有助于阅读这个主题:

如何处理原始UDP数据包,以便directshow源筛选器中的解码器筛选器对其进行解码

如何将H.264 UDP数据包转换为可播放的媒体流或文件(碎片整理)

以这些为背景,我目前的工作如下:

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

我最后得到了一个文件,应该是大量的NAL帧。然后尝试在.264文件上运行ffmpeg以创建一个.mp4。这会产生几个错误:

[h264@0x15257A0]decode_slice_header错误

[h264@0x15257A0]无帧!

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

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

[buffer@0x15E16A0]无效的像素格式字符串“-1”

共有1个答案

逄边浩
2023-03-14

查看如何处理原始UDP数据包,以便可以通过directshow源筛选器中的解码器筛选器对其进行解码

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

//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;
                    }
 类似资料:
  • 我想写一个接收数字的递归方法。该方法应返回第二个数字,该数字仅由第一个参数中可被第二个参数整除的数字组成。 例如,如果使用number=5369405和digit=5调用该方法,则它应该返回505。 到目前为止,我已经编写了以下方法,但它不起作用,因为索引保持在-1,我想在每次递归期间保存它的值。我的想法是保存值以构造返回的数字。 有人能告诉我如何在每次递归期间保存索引以防止它返回-1吗? 这是我

  • 我有多个文本框,当用户在不同的文本框中键入时,我希望有一个存储所有格式化数据的数组。 格式化的数据以 m:ss 为单位(m - 分钟,s - 秒) 现在,所有不同的文本框都显示相同的值,因为只有一个this.formatTime. 我们如何改变这一点,以便v-model遍历数组,并将其添加到格式化值数组中? 文本框应显示格式化的值,并将其存储在所有格式值[]中。 我真的被困在这个,谢谢你的时间!

  • 问题内容: 假设我正在制作健身应用程序,您可以在其中进行锻炼。配置锻炼后,您需要保存它。如何添加此功能,以便当他退出应用程序并再次打开它时,他可以查看他的锻炼? 我专门在Android上工作。 这可用于保存本地游戏保存和数据。 问题答案: 我相信Kivy具有处理此问题的模块。尽管它仍(在撰写本文时)仍处于实验阶段。在这里查看:http : //kivy.org/docs/api- kivy.sto

  • 尝试将数据集吐槽到和,然后需要将其保存为格式。 这是到目前为止的代码,

  • 我需要从redis缓存中删除一个池。但是,这个池可能有数百万个密钥。我正在使用以下代码从缓存中删除键 我担心redis服务器可能会崩溃,万一有百万行。有没有办法让redis每次只选择100行并删除。类似于

  • 我正在本地机器中将spark数据集保存为拼花文件。我想知道是否有任何方法可以使用某种加密算法对数据进行加密。我用来将数据保存为拼花文件的代码如下所示。 <代码>数据集。写入()。模式(“覆盖”)。拼花地板 我看到了一个类似的问题,但我的查询不同,因为我正在写入本地磁盘。