Convert H264 file to standard container

Topics: Question
Nov 23, 2014 at 5:57 AM
Hello,

first of all thanks a lot for your library.

I have been able to save RTSP stream into H264 file.
I can drag the file into the VLC player and it plays.

I am looking for a way to convert the H264 file to a standard container (mkv, mp4, or anything else).
End result should be to have a playable file that I can play with double click.

any ideas about how to do that??

Here is the code I have so far:
void Client_RtpFrameChanged(object sender, Media.Rtp.RtpFrame frame)
{
        try
        {
            var context = ((Media.Rtp.RtpClient)sender).GetContextByPayloadType(frame.PayloadTypeByte);

            if (context == null || context.MediaDescription.MediaType != Media.Sdp.MediaType.video) return;

            Media.Rtsp.Server.Media.RFC6184Media.RFC6184Frame hframe = new Media.Rtsp.Server.Media.RFC6184Media.RFC6184Frame(frame);
            if (isFirstFrame)
            {
                // first frame

                Media.Sdp.SessionDescriptionLine fmtp = context.MediaDescription.FmtpLine;

                byte[] sps = null, pps = null;

                foreach (string p in fmtp.Parts)
                {
                    string trim = p.Trim();
                    if (trim.StartsWith("sprop-parameter-sets=", StringComparison.InvariantCultureIgnoreCase))
                    {
                        string[] data = trim.Replace("sprop-parameter-sets=", string.Empty).Split(',');
                        sps = System.Convert.FromBase64String(data[0]);
                        pps = System.Convert.FromBase64String(data[1]);
                        break;
                    }
                }

                bool hasSps, hasPps, sei, slice, idr;

                hframe.Depacketize(out hasSps, out hasPps, out sei, out slice, out idr);

                using (var stream = new System.IO.MemoryStream())
                {
                    if (!hasSps && sps != null)
                    {
                        stream.Write(new byte[] { 0x00, 0x00, 0x00, 0x01 }, 0, 4);

                        stream.Write(sps, 0, sps.Length);
                    }

                    if (!hasPps && pps != null)
                    {
                        stream.Write(new byte[] { 0x00, 0x00, 0x00, 0x01 }, 0, 4);

                        stream.Write(pps, 0, pps.Length);
                    }

                    hframe.Buffer.CopyTo(stream);
                    stream.Position = 0;

                    // write to file
                    decode_stream(stream);
                    isFirstFrame = false;
                }
            }
            else
            {
                // after first packet
                hframe.Depacketize();

                // write to file
                decode_stream(hframe.Buffer);
            }


        }
        catch (Exception e)
        {

        }
    }

       private void decode_stream(Stream fin)
       {
           using (var fs = new FileStream(string.Format(C://temp/test.h264), FileMode.Append))
                fin.CopyTo(fs);
       } 
} 
Thanks for your work again!

```
Coordinator
Nov 23, 2014 at 6:56 AM
Great, what you have so far is exactly what I wrote for you :) I have updated the H264 Codec project to contains the Prefix so you can just use that instead of allocating the new array each time.

Muxing will be supported after I can get to Demuxing which will subsequently be after Container is complete.

I still have to Finish Ogg (DS), and a few other containers not to mention MPEG TS and PS and PES.

Then I also have to separate the RtpFrame classes from the RtspServer and then all the MediaTypes from that (Dll Hell)

I would love to give you something you can just use but I don't have anything right now.

The best advice I can give you until I have official support is to put it into a fragmented mp4 format ([mfra] box) with a hard coded header which indicated H.264.

Thanks and please let me know if you need anything else!
Marked as answer by juliusfriedman on 11/22/2014 at 11:56 PM
Nov 24, 2014 at 4:41 AM
okay thanks for your answer!

you actually mean writing the header of the mp4 file manually and than append the H264 file to it? just like that?
Coordinator
Nov 24, 2014 at 4:48 AM
Edited Nov 24, 2014 at 4:49 AM
Quintessentially yes.

Once you have the header in place each frame will simply be added along with another header mfra moof mdat sample moof mdat at sample etc

That should work fine.

Seeking won't work unless the demuxer is good because mp4 file usually indicates the explicit offset however because the mfra is used it will leave it up to the demuxer to decide if seeking can be performed (e.g) skipping fragments.

I will support both ways asap, if you would like to start working on the basemediawriter please by all means give it a shot.

which reminds me I still have to finish that reader to support fragmented form.

Thanks and if you needed anything else let me know!