Giter VIP home page Giter VIP logo

crymedia's Introduction

CryMedia

A cross-platform .NET library that offers a simple interface for reading, writing and playing video and audio files using FFmpeg.

Focuses on the ability to edit raw video/audio data directly using C#.

Requirements

  • FFmpeg executable for reading and writing video/audio data
  • FFprobe executable for reading video/audio metadata
  • FFplay executable for playing video/audio data

These executables should either be available in the PATH env. variable or should be specified manually.

Install

dotnet add package CryMediaAPI

(Requires .NET Core 3.1) For older versions I recommend downloading the code from here and using it directly. For even older versions, you might have to replace the JSON serializer and adjust the syntax.

Video Usage

Reading video metadata

// reading video file
var video = new VideoReader("test.mp4");

// load metadata
await video.LoadMetadataAsync();

// example metadata that you can get
var width = video.Metadata.Width;
var height = video.Metadata.Height;
var fps = video.Metadata.AvgFramerate;
var duration = video.Metadata.Duration;

Reading and modifying video frames

// open video for reading frames
video.Load();

// read next frame (in RGB24 format)
var frame = video.NextFrame();

// get pixel at (1, 1)
var px = frame.GetPixels(1, 1).Span;

// set pixel to RGB (255, 0, 0)
px[0] = 255;
px[1] = 0;
px[2] = 0;

Writing video frames

using (var writer = new VideoWriter("out.mp4", width, height, fps)
{
    // open video for writing
    writer.OpenWrite();

    while (true)
    {
        // read next frame (using VideoReader)
        var f = video.NextFrame(frame);
        if (f == null) break;
       
        // draw a red square (100x100 pixels)
        for (int i = 0; i < 100; i++)
            for (int j = 0; j < 100; j++)
            {
                var px = frame.GetPixels(i, j).Span;
                px[0] = 255;
                px[1] = 0;
                px[2] = 0;
            }

        // write the modified frame
        writer.WriteFrame(frame);
    }
}

Custom Encoding Options

You can customize the encoding options that will be passed to FFmpeg.

// EncoderOptions class
var options = new EncoderOptions()
{
    Format = "mp4",
    EncoderName = "libx264",
    EncoderArguments = "-preset veryfast -crf 23"
};

// pass options to VideoWriter
var writer = new VideoWriter("out.mp4", w, h, fps, options);

Or use the existing EncoderOptions builders! Or implement your own!

var encoder = new H264Encoder();
encoder.EncoderPreset = H264Encoder.Preset.Medium;
encoder.EncoderTune = H264Encoder.Tune.Film;
encoder.EncoderProfile = H264Encoder.Profile.High;
encoder.SetCQP(22);

var options = encoder.Create();
var writer = new VideoWriter("out.mp4", w, h, fps, options);

Playing video files

var player = new VideoPlayer("video.mp4");
player.Play();

Playing video frames directly

var player = new VideoPlayer();
player.OpenWrite(video.Metadata.Width, video.Metadata.Height, video.Metadata.AvgFramerateText);

// play frame... (usually you would have this in a loop)
player.WriteFrame(frame);

// dispose manually or use 'using' statement
player.Dispose();

Seeking & saving frame as image

// seek to 60 seconds and 500ms (60.5sec)
videoReader.Load(60.5);   

var fr = videoReader.NextFrame();

// save frame as PNG
fr.Save("frame.png");

// save frame as WEBP
fr.Save("frame.webp", "libwebp");

Audio Usage

Reading audio metadata

// reading audio file
var audio = new AudioReader("test.mp3");

// load metadata
await audio.LoadMetadataAsync();

// example metadata that you can get
var channels = audio.Metadata.Channels;
var samplerate = audio.Metadata.SampleRate;
var codec = audio.Metadata.Codec;
var duration = audio.Metadata.Duration;

Reading and modifying audio samples (frames)

// open audio for reading samples (frames)
audio.Load();
// audio.Load(24); // <-- you can specify bit-depth (16, 24, 32)

// read next number of samples (frame) (in S16LE format - depends on used bit-depth)
var frame = audio.NextFrame();

// get first sample from first channel
var val = frame.GetSample(0, 0).Span;

// set values (default bit-depth is 16 = 2 bytes)
val[0] = 124;
val[1] = 23;

Writing audio samples (frames)

using (var writer = new AudioWriter("out.mp3", channels, sample_rate, 16)
{
    // open audio for writing
    writer.OpenWrite();

    while (true)
    {
        // read next number of samples (frame)
        var f = audio.NextFrame(frame);
        if (f == null) break;

        // get and modify first sample in first channel
        var val = frame.GetSample(0, 0).Span;
        val[0] = 122;
        val[1] = 23;

        // write the modified frame
        writer.WriteFrame(frame);
    }
}

Custom encoding options

// this is the default encoder
var options = new EncoderOptions()
{
    Format = "mp3",
    EncoderName = "libmp3lame",
    EncoderArguments = "-ar 44100 -ac 2 -b:a 192k"
};

// pass options to AudioWriter
var writer = new AudioWriter("out.mp3", channels, sample_rate, 16, options);

Or use the existing EncoderOptions builders! Or implement your own!

var encoder = new OpusEncoder();
encoder.CodecApplication = OpusEncoder.Application.Audio;
encoder.CompressionLevel = 10;
encoder.SetVBR("128k");

var options = encoder.Create();
var writer = new AudioWriter("out.ogg", channels, sample_rate, 16, options);

Playing audio files

var player = new AudioPlayer("audio.mp3");
player.Play();

Playing audio samples directly

var player = new AudioPlayer();
player.OpenWrite(audio.Metadata.SampleRate, audio.Metadata.Channels);

// play frame... (usually you would have this in a loop)
player.WriteFrame(sample);

// dispose manually or use 'using' statement
player.Dispose();

Conversions

You can manually set the EncoderOptions object and use the VideoWriter static methods for conversions:

// This will convert the "from.mp4" video to "to.flv" video
VideoWriter.FileToFile("from.mp4", "to.flv", new EncoderOptions
{
    Format = "flv",
    EncoderName = "h264_nvenc",
    EncoderArguments = "-preset slow"
}, out _);

// This will convert the "from.mp4" directly into a stream (example: for streaming video)
var stream = VideoWriter.FileToStream("from.mp4", new EncoderOptions
{
    Format = "flv",
    EncoderName = "h264_nvenc",
    EncoderArguments = "-preset slow"
}, out _);

// You can convert from one stream to another stream
var (input, output) = VideoWriter.StreamToStream(new EncoderOptions
{
    Format = "flv",
    EncoderName = "h264_nvenc",
    EncoderArguments = "-preset slow"
}, out _, "-f mp4");  // <-- you can further describe the input stream if required

Or you can use EncoderOption builders. For example VP9:

// Converting video to VP9 manually (using constant quality mode and row multithreading)
var encoder = new VP9Encoder();
encoder.RowBasedMultithreading = true;
encoder.SetCQP(31);

// get EncoderOptions from builder
var options = encoder.Create();

// EXAMPLE: using VideoReader + VideoWriter for conversion 
using (var reader = new VideoReader(input))
{
    reader.LoadMetadata();
    reader.Load();

    using (var writer = new VideoWriter(output,
        reader.Metadata.Width,
        reader.Metadata.Height,
        reader.Metadata.AvgFramerate,
        options))
    {
        writer.OpenWrite();
        
        // instead of "CopyTo" can read and write frames separately
        reader.CopyTo(writer);
    }
}

AudioVideoWriter

Made to handle both video and audio readers and writing to a single file or stream.

If you only want to convert files, use the static methods on VideoWriter (FileToFile, FileToStream, ...). Use this if you have a Video and Audio reader and want to join them together.

// Load video
var vreader = new VideoReader(input);
vreader.LoadMetadata();
vreader.Load();

// Load audio
var areader = new AudioReader(input);
areader.LoadMetadata();
areader.Load();

// Get video and audio stream metadata (or just access metadata properties directly instead)
var vstream = vreader.Metadata.GetFirstVideoStream();
var astream = areader.Metadata.GetFirstAudioStream();

// Prepare writer (Converting to H.264 + AAC video)
var writer = new AudioVideoWriter(output,
    vstream.Width.Value,
    vstream.Height.Value,
    vstream.AvgFrameRateNumber,
    astream.Channels.Value,
    astream.SampleRateNumber, 16,
    new H264Encoder().Create(),
    new AACEncoder().Create());

// Open for writing (this starts the FFmpeg process)
writer.OpenWrite();

// Attach a progress tracker to the FFmpeg process
var progress = FFmpegWrapper.RegisterProgressTracker(writer.CurrentFFmpegProcess, vreader.Metadata.Duration);
progress.ProgressChanged += (s, p) => Console.WriteLine($"{p:0.00}%");

// Copy raw data directly from stream to stream
// Or you can read/write frames manually here
var t1 = vreader.DataStream.CopyToAsync(writer.InputDataStreamVideo);
var t2 = areader.DataStream.CopyToAsync(writer.InputDataStreamAudio);

Task.WaitAll(t1, t2);

FFmpeg Wrapper

For specialized needs, you can use the FFmpeg wrapper functions directly using the FFmpegWrapper static class.

Development

This is a personal project. I might add more features in the future.

You are free to request any wanted features and I will consider adding them.

crymedia's People

Contributors

cryshana avatar

Stargazers

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

Watchers

 avatar  avatar  avatar  avatar

crymedia's Issues

subscribing to event ErrorDataReceived does not allow to update UI, kindly suggest

p.ErrorDataReceived += (sender, d) =>
{
if (!string.IsNullOrEmpty(d.Data))
{
Match match = Regex.Match(d.Data, pattern);
if (match.Success)
{
string number = match.Groups[1].Value;
int progress = Convert.ToInt32(number);
FileDto.EncryptionPercentage = progress * 100 / totalChunks;
Dispatcher.InvokeAsync((Action)delegate
{
TranscodeProgressBar.Value = FileDto.EncryptionPercentage.Value;
//if (OnFileEncryptProgressChanged != null)
// OnFileEncryptProgressChanged?.Invoke(new EncryptEventArgs(fileDto));
});
//TranscodeProgressBar.Value = FileDto.EncryptionPercentage.Value;
//if (OnFileEncryptProgressChanged != null)
// OnFileEncryptProgressChanged?.Invoke(new EncryptEventArgs(fileDto));
}
}

Invalid duration specification for ss:30 (ffmpeg)

Hi

I got this error when using Load(30):
Invalid duration specification for ss: 30,00

Resolved by adding CultureInfo:

public void Load(double offsetSeconds)
{
CultureInfo enUS = new CultureInfo("en-US");
// we will be reading video in RGB24 format
DataStream = FFmpegWrapper.OpenOutput(ffmpeg, $"{(offsetSeconds &lt;= 0 ? "" : $"-ss {offsetSeconds.ToString(enUS):0.00}")} -i "{Filename}"" +
$" -pix_fmt rgb24 -f rawvideo -");
OpenedForReading = true;
}

Can I use this redo to download m3u8 live stream URL and save to local hard drive.

Hello:
I happen to find your repo, and it seems to be interesting. However, as it is rather complicated,
I can’t figure out yet how to download multiple M3U8 videos and save to local hard drive.
For example, I have the following 2 M3U8 videos in the URL:
http://demo.unified-streaming.com/video/tears-of-steel/tears-of-steel.ism/.m3u8
http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8
I want to launch 2 clients to download them at the same time, when finished, I want to save the files as local files: C:\1.mp4 and C:\2.mp4 and stop or dispose the client.
Please show me how I can do this with C#.
By the way, I am using Windows 10 Version 21H1, and Visual Studio 2019 Version 16.10.4.
Thanks,

I would like to play mp4 video using memory stream

I have encrypted video which I would like to play chunk by chunk using memory stream

can this be possible with VideoPlayer component?

request if you can make that way, at least play from memory stream

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.