Git Product home page Git Product logo

sharpmp4parser's Introduction

SharpMp4Parser

A C# API to read, write and create MP4 container. It is a C# netstandard2.0 port of the Java mp4parser from https://github.com/sannies/mp4parser with some additional fixes and improvements. The API was kept mostly the same as the Java implementation so many examples from the original repo should work. Because it has no native dependencies (this is NOT another FFMPEG/Media Foundation wrapper), it is portable and can be used on Windows as well as Linux and MacOS.

What can you do?

  • Muxing audio/video into an MP4 file (supports AAC for audio and H264/H265 for video)
  • Append recordings that use the same encode settings
  • Modify MP4 metadata
  • Shorten recordings by omitting frames
  • Move the MOOV box from the end of the file to the beginning to make the video streamable from the web
  • Parse the VPS/SPS/PPS to get video information such as the FPS or the size

For the API you can refer to the tests as there are many examples for various use cases.

Differences from the Java version

Added features

  • H265 Streaming
  • H265 Muxing
  • API to directly pass H264/H265 NALs to the MP4 writer

Missing features

  • TTML support (TBD)

Known issues

  • FragmentedMp4Writer can only encode video without audio, video + audio is not supported and produces an invalid file (the same limitation exists in the Java version). Use StandardMp4Writer which supports both.

Extensibility

Logging

By default all warnings and errors get written to the System.Diagnostics.Debug output, which is stripped out in Release. I did not want to add any heavy dependencies so the SharpMp4Parser.Java.LOG static class exposes multiple actions that can be assigned by the user:

SharpMp4Parser.Java.LOG.SinkError = (message, exception) => { Debug.WriteLine(message); };
SharpMp4Parser.Java.LOG.SinkWarning = (message, exception) => { Debug.WriteLine(message); };

Temporary files

The parser is using temporary files to offload as much as possible from RAM onto the disk. This could be an issue on mobile platforms where file access is restricted. While there is a default implementation in place that is using the System.IO.FileStream APIs, it is also possible to provide your own implementation based upon the ITemporaryFile interface:

public class MyTemporaryFile : ITemporaryFile
{
    private FileStream _stream;

    public MyTemporaryFile(long contentSize)
    {
        _stream = System.IO.File.Create(System.IO.Path.GetRandomFileName(), (int)contentSize, FileOptions.DeleteOnClose);
    }

    public void Write(byte[] bytes, int offset, int count)
    {
        _stream.Write(bytes, offset, count);
        _stream.Flush();
    }

    public void Read(Stream buffer)
    {
        _stream.Seek(0, SeekOrigin.Begin);
        _stream.CopyTo(buffer);
    }

    public void Close()
    {
        _stream.Close();
    }
}

Then create a factory by implementing the ITemporaryFileFactory interface:

public class MyTemporaryFileFactory : ITemporaryFileFactory
{
    public ITemporaryFile Create(long contentSize)
    {
        return new MyTemporaryFile(contentSize);
    }
}

And finally replace the default factory implementation:

SharpMp4Parser.Java.TemporaryFileAccess.Factory = new MyTemporaryFileFactory();

Examples

Record H264 video with AAC audio

Create the video track:

var h264Track = new H264StreamingTrack();

Create the audio track:

var aacTrack = new AacStreamingTrack(192, 192, 2, 44100, 0x4); // correct AAC parameters should be retrieved from the source, e.g. from the SDP or ADTS header

Create the output file where you want to store the MP4 and wrap it with a ByteStream object:

var outputFile = new ByteStream(File.Create("output.mp4"));

Create the MP4 writer with all the tracks that should be in the output:

var writer = new StandardMp4Writer(new List<StreamingTrack>() { h264Track, aacTrack }, output);

Pass the NALs from another source (e.g. RTP, raw *.h264 file, etc.):

List<byte[]> nals = ...; // retrieve the NALs from your source

foreach(byte[] nalBytes in nals)
{
   h264Track.ProcessNal(nalBytes);
}

Pass the AAC frames - the frames should not include ADTS header:

List<byte[]> frames = ...; // retrieve the AAC frames from your source

foreach(byte[] frameBytes in frames)
{
   aacTrack.ProcessFrame(frameBytes);
}

To stop recording and save the file, call:

h264Track.ProcessNalFinalize();
writer.close();
outputFile.close();

Record H265 video

Create the video track:

var h265Track = new H265StreamingTrack();

Create the output file where you want to store the MP4 and wrap it with a ByteStream object:

var outputFile = new ByteStream(File.Create("output.mp4"));

Create the MP4 writer with all the tracks that should be in the output:

var writer = new StandardMp4Writer(new List<StreamingTrack>() { h265Track }, output);

Pass the NALs from another source (e.g. RTP, raw *.h265 file, etc.):

List<byte[]> nals = ...; // retrieve the NALs from your source

foreach(byte[] nalBytes in nals)
{
   h265Track.ProcessNal(nalBytes);
}

To stop recording and save the file, call:

h265Track.ProcessNalFinalize();
writer.close();
outputFile.close();

Move the MOOV box to the beginning of the MP4 file

When recording the MP4 files as described in the previous examples, the MOOV box will be created at the end of the file when the stream is stopped. This makes it harder for such files to be streamed to the web as the web browser will have to download the entire file before it can play it. Fortunatelly, it is easy to re-encode the existing file and move the MOOV box to the beginning.

// open the file from the previous recording
var inputFile = new ByteStream(File.Open("output.mp4"));
var inputMovie = MovieCreator.build(inputFile, "inmem");

// create a new Movie where we will transfer all the tracks from the original Movie
var outputMovie = new Movie();

// move all tracks from the input to the new Movie
var tracks = inputMovie.getTracks();
foreach (var track in tracks)
{
   outputMovie.addTrack(track);
}

Container outputContainer = new DefaultMp4Builder().build(outputMovie);
var outputFile = new ByteStream(File.Create("output_muxed.mp4"));
outputContainer.writeContainer(outputFile);
outputFile.close();

inputFile.close();

Thread safety

The parser is NOT thread safe so thread synchronization is the responsibility of the caller. Multiple instances can be used simultaneously from multiple threads provided each instance is being accessed by the same thread that created it.

Contribute

Pull requests with fixes are welcome!

Credits

sharpmp4parser's People

Contributors

jimm98y avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

ghd258 5653325

sharpmp4parser's Issues

.NET reference assemblies error

When cloning this repo and attempting to build in the latest version of VS 2019 I get the following error:

The reference assemblies for ".NETFramework,Version=v6.0" were not found. You might be using an older .NET SDK to target .NET 5.0 or higher. Update Visual Studio and/or your .NET SDK
SharpMp4Parser.Tests
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets	

I'm confused by this error requiring .Net Framework 6.0 when according to the README this library should be compatible with .Net 2.0
Is perhaps the source code .Net 2.0 compatible while the tests require a .Net 6.0 SDK, or is it something else?

Thanks for having a look.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.