2

我有一个日志文件,其中包含来自黑盒设备的 RTP 数据包。我也有一个相应的 SDP 文件(RTSP DESCRIBE)。我需要将此文件转换为某种可播放的视频文件。我可以将这两个文件传递给 FFMpeg 或 VLC 或其他东西,然后让它将这些数据混合成可播放的东西吗?

作为替代计划,我可以循环遍历代码中的各个数据包并对每个数据包执行某些操作。但是,似乎有用于解析这些数据的现有库。它似乎手工完成将要求一个大型项目。是否有某种视频文件格式是 SDP 和 RTP 的原始混合?谢谢你的时间。

FFmpeg 或 VLC 有没有办法打开 SDP 文件,然后通过 STDIN 获取它们的输入数据包?

我通常使用 C#,但如有必要,我可以使用 C。

更新 1:这是我无法正常工作的代码。我正在尝试获得某种输出来与 ffplay 一起玩,但我还没有运气。它给了我无效的数据错误。据我所知,它确实正确地检查了所有数据。我的输出几乎和我的输入一样大(大约 4MB)。

    public class RtpPacket2
    {
        public byte VersionPXCC;
        public byte MPT;
        public ushort Sequence; // length?
        public uint Timestamp;
        public uint Ssrc;
        public int Version { get { return VersionPXCC >> 6; } }
        public bool Padding { get { return (VersionPXCC & 32) > 0; } }
        public bool Extension { get { return (VersionPXCC & 16) > 0; } }
        public int CsrcCount { get { return VersionPXCC & 0xf; } } // ItemCount
        public bool Marker { get { return (MPT & 0x80) > 0; } }
        public int PayloadType { get { return MPT & 0x7f; } } // PacketType
    }


    static void Main(string[] args)
    {
        if (args.Length != 2)
        {
            Console.WriteLine("Usage: <input RTP file> <output 3GP file>");
            return;
        }
        var inputFile = args[0];
        var outputFile = args[1];
        if(File.Exists(outputFile)) File.Delete(outputFile);

        // FROM the SDP : fmtp 96 profile-level-id=4D0014;packetization-mode=0
        var sps = Convert.FromBase64String("Z0LAHoiLUFge0IAAA4QAAK/IAQ=="); //      BitConverter.ToString(sps)  "67-42-C0-1E-88-8B-50-58-1E-D0-80-00-03-84-00-00-AF-C8-01"  string
        var pps = Convert.FromBase64String("aM44gA=="); //      BitConverter.ToString(pps)  "68-CE-38-80"   string
        var sep = new byte[] { 00, 00, 01 };

        var packet = new RtpPacket2();
        bool firstFrame = true;
        using (var input = File.OpenRead(inputFile))
        using (var reader = new BinaryReader(input))
        using (var output = File.OpenWrite(outputFile))
        {
            //output.Write(header, 0, header.Length);
            output.Write(sep, 0, sep.Length);
            output.Write(sps, 0, sps.Length);
            output.Write(sep, 0, sep.Length);
            output.Write(pps, 0, pps.Length);
            output.Write(sep, 0, sep.Length);
            while (input.Position < input.Length)
            {
                var size = reader.ReadInt16();
                packet.VersionPXCC = reader.ReadByte();
                packet.MPT = reader.ReadByte();
                packet.Sequence = reader.ReadUInt16();
                packet.Timestamp = reader.ReadUInt32();
                packet.Ssrc = reader.ReadUInt32();
                if (packet.PayloadType == 96)
                {
                    if (packet.CsrcCount > 0 || packet.Extension) throw new NotImplementedException();

                    var header0 = reader.ReadByte();
                    var header1 = reader.ReadByte();

                    var fragmentType = header0 & 0x1F; // should be 28 for video
                    if(fragmentType != 28) // 28 for video?
                    {
                        input.Position += size - 14;
                        continue;
                    }
                    var nalUnit = header0 & ~0x1F;
                    var nalType = header1 & 0x1F;
                    var start = (header1 & 0x80) > 0;
                    var end = (header1 & 0x40) > 0;

                    if(firstFrame)
                    {
                        output.Write(sep, 0, sep.Length);
                        output.WriteByte((byte)(nalUnit | fragmentType));
                        firstFrame = false;
                    }

                    for (int i = 0; i < size - 14; i++)
                        output.WriteByte(reader.ReadByte());
                    if (packet.Marker)
                        firstFrame = true;
                }
                else input.Position += size - 12;
            }
        }
    }
4

2 回答 2

0

http://www.bogotobogo.com/VideoStreaming/videostreaming_etc.php

远离在数据包级别做任何事情,因为您可能会陷入编码流如何打包的细节中。

看看上面的链接。SDP / RTP / RTSP 流是相当复杂的协议,当您尝试将它们直接连接到期望只打开本地媒体文件的播放器时,它们通常不起作用。

如果您正在处理流并且想要从流中保存文件,您可能希望使用任何大型媒体项目(ffmpeg、vlc、live555、openrtsp)搜索“filesink”,因为这些项目已经具有开源 fileSink 实现(C , C++)。

例如,在 live555 中,所有编解码器在 ./live/liveMedia 目录中都有 fileSink 实现。

如果您有来自 SDP 源的流,则可以使用该轨道使用的编解码器的 fileSink 处理每个轨道(音频、视频)。然后,您可以将这些曲目混合到播放器或独立播放曲目。

于 2012-04-12T02:54:27.560 回答
0

在 vlc 中打开 SDP 文件,然后编写一个小应用程序将您的 RTP 数据包重新播放到网络,以便 VLC 可以接收它们。确保将它们播放到 127.0.0.1 和与 SDP 文件匹配的端口号。

VLC 将等到它收到一些数据包,然后使用 VLC 保存媒体而不转码为 MP4 或类似文件格式。

于 2012-05-09T04:44:40.813 回答