Search code examples
c#ffmpegvlclibvlcsharpffmpeg

I have a log file with RTP packets: now what?


I have a log file with RTP packets coming off of a black box device. I also have a corresponding SDP file (RTSP DESCRIBE) for that. I need to convert this file into some kind of playable video file. Can I pass these two files to FFMpeg or VLC or something else and have it mux that data into something playable?

As an alternate plan, I can loop through the individual packets in code and do something with each packet. However, it seems that there are existing libraries for parsing this data. And it seems to do it by hand would be asking for a large project. Is there some kind of video file format that is a pretty raw mix of SDP and RTP? Thanks for your time.

Is there a way for FFmpeg or VLC to open an SDP file and then get their input packets through STDIN?

I generally use C#, but I could use C if necessary.

Update 1: Here is my unworking code. I'm trying to get some kind of output to play with ffplay, but I haven't had any luck yet. It gives me invalid data errors. It does go over all the data correctly as far as I can tell. My output is nearly as big as my input (at about 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;
            }
        }
    }

Solution

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

    Stay away from doing anything at the packet level because you may get bogged down in the details of how encoded streams are packetized.

    look thru the above link. SDP / RTP / RTSP streaming are pretty involved protocols that usually do not work when you try to hook them up directly to players expecting to just open a local media file.

    If you are handling streams and you want to save a file from the stream , you might want to google 'filesinks' with any of the big media projects ( ffmpeg, vlc, live555, openrtsp ) because those projects already have opensource fileSink implementations (C, C++).

    For example, in live555, all of the codecs have fileSink implementations in ./live/liveMedia directory.

    If you have a stream from an SDP source, you can handle each of the tracks (audio, video) with a fileSink for the codec used by that track. Then you can mux those tracks to a player or play the tracks independently.