Mux Audio and Video Into WebM

This topic describes how to use the Transcoder::run method to mux Vorbis audio and VP8 video into a WebM file.

The code snippets in this article are from the mux_webm_file macOS sample.

Linux and Windows samples are also available:

Source Files

For source we use the big-buck-bunny_trailer_vp8_vorbis.aud.webm and big-buck-bunny_trailer_vp8_vorbis.vid.webm files from the AVBlocks Assets repository. After downloading and unzipping you will find them in the aud and vid subdirectories.

Code

This code multiplexes two single-stream WebM files, one containing Vorbis audio and one containing VP8 video, into a WebM container file.

Initialize AVBlocks

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

int main(int argc, char* argv[])
{
    Options opt;

    switch(prepareOptions( opt, argc, argv))
    {
        case Command: return 0;
        case Error: return 1;
        case Parsed: break;
    }

    Library::initialize();

    // set your license string
    // Library::setLicense("PRIMO-LICENSE");

    bool webmMuxResult = WebMMux(opt);

    Library::shutdown();

    return webmMuxResult ? 0 : 1;
}

Create the WebM Output Socket

The output socket is configured as StreamType::WebM. The sample adds one output pin for each input audio or video stream.

bool WebMMux(const Options& opt)
{
    deleteFile(primo::ustring(opt.output_file));

    primo::ref<Transcoder> transcoder (Library::createTranscoder());

    // Transcoder demo mode must be enabled,
    // in order to use the production release for testing (without a valid license)
    transcoder->setAllowDemoMode(true);

    primo::ref<MediaSocket> outputSocket(Library::createMediaSocket());
    outputSocket->setFile(primo::ustring(opt.output_file));
    outputSocket->setStreamType(StreamType::WebM);

    // ...existing code...
}

Add Vorbis Audio Inputs

For each audio input, the sample creates a Vorbis output pin, adds it to the WebM output socket, creates an input socket for the source WebM file, and adds that input socket to the transcoder.

    // audio
    for(int i = 0; i < (int)opt.input_audio.size(); i++)
    {
        primo::ref<MediaPin> outputPin(Library::createMediaPin());
        primo::ref<AudioStreamInfo> asi(Library::createAudioStreamInfo());
        asi->setStreamType(StreamType::Vorbis);
        outputPin->setStreamInfo(asi.get());

        outputSocket->pins()->add(outputPin.get());

        primo::ref<MediaSocket> inputSocket(Library::createMediaSocket());
        inputSocket->setFile(primo::ustring(opt.input_audio[i]));
        inputSocket->setStreamType(StreamType::WebM);
        transcoder->inputs()->add(inputSocket.get());

        cout << "Muxing audio input: " << opt.input_audio[i] << endl;
    }

Add VP8 Video Inputs

For each video input, the sample creates a VP8 output pin, adds it to the WebM output socket, creates an input socket for the source WebM file, and adds that input socket to the transcoder.

    // video
    for (int i = 0; i < (int)opt.input_video.size(); i++)
    {
        primo::ref<MediaPin> outputPin(Library::createMediaPin());
        primo::ref<VideoStreamInfo> vsi(Library::createVideoStreamInfo());
        vsi->setStreamType(StreamType::VP8);
        outputPin->setStreamInfo(vsi.get());

        outputSocket->pins()->add(outputPin.get());

        primo::ref<MediaSocket> inputSocket(Library::createMediaSocket());
        inputSocket->setFile(primo::ustring(opt.input_video[i]));
        inputSocket->setStreamType(StreamType::WebM);
        transcoder->inputs()->add(inputSocket.get());

        cout << "Muxing video input: " << opt.input_video[i] << endl;
    }

Run the Transcoder

After all input sockets and output pins are configured, the sample adds the output socket to the transcoder, opens it, runs the muxing operation, closes it, and prints the output file path.

    transcoder->outputs()->add(outputSocket.get());

    if (!transcoder->open())
    {
        printError("Open Transcoder", transcoder->error());
        return false;
    }

    if (!transcoder->run())
    {
        printError("Run Transcoder", transcoder->error());
        return false;
    }

    transcoder->close();

    cout << "Output file: " << opt.output_file << endl;

    return true;
}

Complete C++ Code

Here’s the complete working example from mux_webm_file.cpp:

#include <primo/avblocks/avb.h>

#include <primo/platform/reference++.h>
#include <primo/platform/error_facility.h>
#include <primo/platform/ustring.h>

#include <cstdio>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>

#include "util.h"
#include "options.h"

using namespace primo::codecs;
using namespace primo::avblocks;
using namespace std;

bool WebMMux(const Options& opt)
{
    deleteFile(primo::ustring(opt.output_file));

    primo::ref<Transcoder> transcoder (Library::createTranscoder());

    // Transcoder demo mode must be enabled,
    // in order to use the production release for testing (without a valid license)
    transcoder->setAllowDemoMode(true);

    primo::ref<MediaSocket> outputSocket(Library::createMediaSocket());
    outputSocket->setFile(primo::ustring(opt.output_file));
    outputSocket->setStreamType(StreamType::WebM);

    // audio
    for(int i = 0; i < (int)opt.input_audio.size(); i++)
    {
        primo::ref<MediaPin> outputPin(Library::createMediaPin());
        primo::ref<AudioStreamInfo> asi(Library::createAudioStreamInfo());
        asi->setStreamType(StreamType::Vorbis);
        outputPin->setStreamInfo(asi.get());

        outputSocket->pins()->add(outputPin.get());

        primo::ref<MediaSocket> inputSocket(Library::createMediaSocket());
        inputSocket->setFile(primo::ustring(opt.input_audio[i]));
        inputSocket->setStreamType(StreamType::WebM);
        transcoder->inputs()->add(inputSocket.get());

        cout << "Muxing audio input: " << opt.input_audio[i] << endl;
    }

    // video
    for (int i = 0; i < (int)opt.input_video.size(); i++)
    {
        primo::ref<MediaPin> outputPin(Library::createMediaPin());
        primo::ref<VideoStreamInfo> vsi(Library::createVideoStreamInfo());
        vsi->setStreamType(StreamType::VP8);
        outputPin->setStreamInfo(vsi.get());

        outputSocket->pins()->add(outputPin.get());

        primo::ref<MediaSocket> inputSocket(Library::createMediaSocket());
        inputSocket->setFile(primo::ustring(opt.input_video[i]));
        inputSocket->setStreamType(StreamType::WebM);
        transcoder->inputs()->add(inputSocket.get());

        cout << "Muxing video input: " << opt.input_video[i] << endl;
    }

    transcoder->outputs()->add(outputSocket.get());

    if (!transcoder->open())
    {
        printError("Open Transcoder", transcoder->error());
        return false;
    }

    if (!transcoder->run())
    {
        printError("Run Transcoder", transcoder->error());
        return false;
    }

    transcoder->close();

    cout << "Output file: " << opt.output_file << endl;

    return true;
}

int main(int argc, char* argv[])
{
    Options opt;

    switch(prepareOptions( opt, argc, argv))
    {
        case Command: return 0;
        case Error: return 1;
        case Parsed: break;
    }

    Library::initialize();

    // set your license string
    // Library::setLicense("PRIMO-LICENSE");

    bool webmMuxResult = WebMMux(opt);

    Library::shutdown();

    return webmMuxResult ? 0 : 1;
}

How to Run

See the build instructions for macOS and the mux_webm_file example for details.

Command Line

mux_webm_file --audio <Vorbis_file>.webm --video <VP8_file>.webm --output <output>.webm

Examples

List options:

./bin/x64/mux_webm_file --help

Usage: mux_webm_file --audio <input_Vorbis> --video <input_VP8> --output <output.webm>
  -?,    --help
  -a,    --audio    input Vorbis files. Can be used multiple times
  -v,    --video    input VP8 files. Can be used multiple times
  -o,    --output   output file

Mux the WebM files big-buck-bunny_trailer_vp8_vorbis.aud.webm and big-buck-bunny_trailer_vp8_vorbis.vid.webm into the WebM file big-buck-bunny_trailer.webm:

mkdir -p ./output/mux_webm_file

./bin/x64/mux_webm_file \
    --audio ./assets/aud/big-buck-bunny_trailer_vp8_vorbis.aud.webm \
    --video ./assets/vid/big-buck-bunny_trailer_vp8_vorbis.vid.webm \
    --output ./output/mux_webm_file/big-buck-bunny_trailer.webm