Demux Audio and Video From MP4

This topic describes how to use the Transcoder.Run method to extract the first audio and video streams from an MP4 container and save each stream into a separate MP4 file.

The code snippets in this article are from the demux_mp4_file .NET sample.

Source File

For source we use the big_buck_bunny_trailer.mp4 file from the AVBlocks Assets repository. After downloading and unzipping you will find it in the mov subdirectory.

Code

This code extracts the first audio and video elementary streams from an MP4 container and writes them to separate MP4 files.

Initialize AVBlocks

Initialize the AVBlocks library before creating the transcoder, and shut it down after the demuxing operation is complete.

var opt = new Options();

if (!opt.Prepare(args))
    return opt.Error ? (int)ExitCodes.OptionsError : (int)ExitCodes.Success;

Library.Initialize();

// Set license information. To run AVBlocks in demo mode, comment the next line out
// Library.SetLicense("<license-string>");

bool demuxResult = DemuxMP4(opt);

Library.Shutdown();

Read the Input Container

The sample uses the MediaInfo class to inspect the MP4 input file and create the input socket from the discovered stream information.

using (var info = new MediaInfo())
{
    info.Inputs[0].File = opt.InputFile;

    if (!info.Open())
    {
        PrintError("MediaInfo open", info.Error);
        return null;
    }

    MediaSocket inSocket = MediaSocket.FromMediaInfo(info);

    info.Close();
    // ...
}

Select Audio and Video Streams

The sample keeps the first audio stream and the first video stream. Any additional pins are disabled.

Transcoder transcoder = new Transcoder();
transcoder.AllowDemoMode = true;
transcoder.Inputs.Add(inSocket);

bool audio = false;
bool video = false;

for (int i = 0; i < inSocket.Pins.Count; ++i)
{
    string fileName;
    if (inSocket.Pins[i].StreamInfo.MediaType == MediaType.Audio && !audio)
    {
        audio = true;
        fileName = opt.OutputFile + ".aud.mp4";
    }
    else if (inSocket.Pins[i].StreamInfo.MediaType == MediaType.Video && !video)
    {
        video = true;
        fileName = opt.OutputFile + ".vid.mp4";
    }
    else
    {
        inSocket.Pins[i].Connection = PinConnection.Disabled;
        continue;
    }

    MediaSocket outSocket = new MediaSocket();
    outSocket.Pins.Add(inSocket.Pins[i]);
    DeleteFile(fileName);
    outSocket.File = fileName;

    transcoder.Outputs.Add(outSocket);

    Console.WriteLine("Output file: {0}", fileName);
}

Run the Transcoder

After configuring the input and output sockets, the sample opens the transcoder, runs the demuxing operation, closes it, and returns the result.

static bool DemuxMP4(Options opt)
{
    using (var transcoder = GenerateOutputFileName(opt))
    {
        if (transcoder == null)
            return false;

        if (!transcoder.Open())
        {
            PrintError("Transcoder open", transcoder.Error);
            return false;
        }

        if (!transcoder.Run())
        {
            PrintError("Transcoder run", transcoder.Error);
            return false;
        }

        transcoder.Close();
        return true;
    }
}

Complete Code

Here’s the complete working example that demonstrates MP4 demuxing using AVBlocks for .NET.

using System;
using PrimoSoftware.AVBlocks;

namespace CliSample
{
    class Program
    {
        static int Main(string[] args)
        {
            var opt = new Options();

            if (!opt.Prepare(args))
                return opt.Error ? (int)ExitCodes.OptionsError : (int)ExitCodes.Success;

            Library.Initialize();

            // Set license information. To run AVBlocks in demo mode, comment the next line out
            // Library.SetLicense("<license-string>");

            bool demuxResult = DemuxMP4(opt);

            Library.Shutdown();

            return demuxResult ? (int)ExitCodes.Success : (int)ExitCodes.DecodingError;
        }

        static bool DemuxMP4(Options opt)
        {
            using (var transcoder = GenerateOutputFileName(opt))
            {
                if (transcoder == null)
                    return false;

                if (!transcoder.Open())
                {
                    PrintError("Transcoder open", transcoder.Error);
                    return false;
                }

                if (!transcoder.Run())
                {
                    PrintError("Transcoder run", transcoder.Error);
                    return false;
                }

                transcoder.Close();
                return true;
            }
        }

        static Transcoder GenerateOutputFileName(Options opt)
        {
            using (var info = new MediaInfo())
            {
                info.Inputs[0].File = opt.InputFile;

                if (!info.Open())
                {
                    PrintError("MediaInfo open", info.Error);
                    return null;
                }

                MediaSocket inSocket = MediaSocket.FromMediaInfo(info);

                info.Close();

                Transcoder transcoder = new Transcoder();
                transcoder.AllowDemoMode = true;
                transcoder.Inputs.Add(inSocket);

                bool audio = false;
                bool video = false;

                for (int i = 0; i < inSocket.Pins.Count; ++i)
                {
                    string fileName;
                    if (inSocket.Pins[i].StreamInfo.MediaType == MediaType.Audio && !audio)
                    {
                        audio = true;
                        fileName = opt.OutputFile + ".aud.mp4";
                    }
                    else if (inSocket.Pins[i].StreamInfo.MediaType == MediaType.Video && !video)
                    {
                        video = true;
                        fileName = opt.OutputFile + ".vid.mp4";
                    }
                    else
                    {
                        inSocket.Pins[i].Connection = PinConnection.Disabled;
                        continue;
                    }

                    Console.WriteLine("Output file: {0}", fileName);
                    DeleteFile(fileName);

                    MediaSocket outSocket = new MediaSocket();
                    outSocket.Pins.Add(inSocket.Pins[i]);
                    outSocket.File = fileName;

                    transcoder.Outputs.Add(outSocket);
                }

                return transcoder;
            }
        }

        static void DeleteFile(string filename)
        {
            try
            {
                if (System.IO.File.Exists(filename))
                    System.IO.File.Delete(filename);
            }
            catch { }
        }

        static void PrintError(string action, ErrorInfo e)
        {
            if (action != null)
            {
                Console.Write("{0}: ", action);
            }

            if (ErrorFacility.Success == e.Facility)
            {
                Console.WriteLine("Success");
                return;
            }
            else
            {
                Console.WriteLine("{0}, facility:{1} code:{2} hint:{3}", e.Message ?? "", e.Facility, e.Code, e.Hint ?? "");
            }
        }

        enum ExitCodes : int
        {
            Success = 0,
            OptionsError = 1,
            DecodingError = 2,
        }
    }
}

How to Run

See the build instructions for macOS and the demux_mp4_file .NET sample for details.

Command Line

demux_mp4_file --input <input_mp4_file> --output <output_mp4_filename_without_extension>

Examples

List options:

./bin/net10.0/demux_mp4_file --help
Usage: demux_mp4_file --input <input_mp4_file> --output <output_mp4_filename_without_extension>
  -?,    --help
  -i,    --input    Input mp4 file
  -o,    --output   Output mp4 filename (without extension)

Extract the audio and video streams from ./assets/mov/big_buck_bunny_trailer.mp4 and save to ./output/demux_mp4_file/big_buck_bunny_trailer.aud.mp4 and ./output/demux_mp4_file/big_buck_bunny_trailer.vid.mp4:

# Linux and macOS
mkdir -p ./output/demux_mp4_file

./bin/net10.0/demux_mp4_file \
    --input ./assets/mov/big_buck_bunny_trailer.mp4 \
    --output ./output/demux_mp4_file/big_buck_bunny_trailer
# Windows
mkdir -Force -Path ./output/demux_mp4_file

./bin/net10.0/demux_mp4_file `
    --input ./assets/mov/big_buck_bunny_trailer.mp4 `
    --output ./output/demux_mp4_file/big_buck_bunny_trailer