Vorbis Decoder (Run)

This article explains how to use Transcoder::run to decode a Vorbis OGG file to a WAV file.

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

Linux and Windows samples are also available:

Source Audio

For source we use the Hydrate-Kenny_Beltrey.ogg file from the AVBlocks Assets repository. After downloading and unzipping you will find Hydrate-Kenny_Beltrey.ogg in the aud subdirectory.

Code

This code takes a Vorbis OGG file and decodes it to uncompressed WAV output.

Initialize AVBlocks

The first step in any AVBlocks application is to initialize the library. This must be done before using any other AVBlocks functionality. Always call Library::shutdown() at the end of the program to clean up resources.

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();

    bool result = decode(opt);

    Library::shutdown();

    return result ? 0 : 1;
}

Configure Input Socket

The input socket points directly to the Vorbis OGG input file.

bool decode(Options& opt)
{
    primo::ref<MediaSocket> inSocket(Library::createMediaSocket());
    inSocket->setFile(primo::ustring(opt.inputFile));

    // ...existing code...
}

Configure Output Socket

The output socket writes a WAV file. The sample configures the output socket as StreamType::WAVE and uses an LPCM audio stream pin.

primo::ref<MediaSocket> createOutputSocket(Options& opt)
{
    auto socket = primo::make_ref(Library::createMediaSocket());
    socket->setFile(primo::ustring(opt.outputFile));
    socket->setStreamType(StreamType::WAVE);

    auto pin = primo::make_ref(Library::createMediaPin());
    socket->pins()->add(pin.get());

    auto asi = primo::make_ref(Library::createAudioStreamInfo());
    pin->setStreamInfo(asi.get());

    asi->setStreamType(StreamType::LPCM);

    // You can change the number of the channels
    //asi->setChannels(1);

    // or the sampling rate and
    //asi->setSampleRate(44100);

    return socket;
}

Configure Transcoder and Decode

After creating the input and output sockets, the sample creates a transcoder, enables demo mode, adds the sockets, removes any existing output file, opens the transcoder, runs the decode, and closes it.

bool decode(Options& opt)
{
    primo::ref<MediaSocket> inSocket(Library::createMediaSocket());
    inSocket->setFile(primo::ustring(opt.inputFile));

    // create output socket
    auto outSocket = createOutputSocket(opt);

    // create transcoder
    auto transcoder = primo::make_ref(Library::createTranscoder());

    // Continue to work even when license is invalid
    // This is not recommended in production
    transcoder->setAllowDemoMode(true);

    transcoder->inputs()->add(inSocket.get());
    transcoder->outputs()->add(outSocket.get());

    // transcoder will fail if output exists (by design)
    deleteFile(opt.outputFile.c_str());

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

    if (!transcoder->run())
    {
        printError("Transcoder run", transcoder->error());

        transcoder->close();
        return false;
    }

    transcoder->close();
    return true;
}

Complete C++ Code

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

#include <primo/avblocks/avb.h>

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

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

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

#include <memory.h>

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

primo::ref<MediaSocket> createOutputSocket(Options& opt)
{
    auto socket = primo::make_ref(Library::createMediaSocket());
    socket->setFile(primo::ustring(opt.outputFile));
    socket->setStreamType(StreamType::WAVE);

    auto pin = primo::make_ref(Library::createMediaPin());
    socket->pins()->add(pin.get());

    auto asi = primo::make_ref(Library::createAudioStreamInfo());
    pin->setStreamInfo(asi.get());

    asi->setStreamType(StreamType::LPCM);

    // You can change the number of the channels
    //asi->setChannels(1);

    // or the sampling rate and
    //asi->setSampleRate(44100);

    return socket;
}

bool decode(Options& opt)
{
    primo::ref<MediaSocket> inSocket(Library::createMediaSocket());
    inSocket->setFile(primo::ustring(opt.inputFile));

    // create output socket
    auto outSocket = createOutputSocket(opt);

    // create transcoder
    auto transcoder = primo::make_ref(Library::createTranscoder());

    // Continue to work even when license is invalid
    // This is not recommended in production
    transcoder->setAllowDemoMode(true);

    transcoder->inputs()->add(inSocket.get());
    transcoder->outputs()->add(outSocket.get());

    // transcoder will fail if output exists (by design)
    deleteFile(opt.outputFile.c_str());

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

    if (!transcoder->run())
    {
        printError("Transcoder run", transcoder->error());

        transcoder->close();
        return false;
    }

    transcoder->close();
    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();

    bool result = decode(opt);

    Library::shutdown();

    return result ? 0 : 1;
}

How to Run

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

Command Line

./dec_vorbis_file --input <ogg file> --output <wav file>

Examples

List options:

./bin/x64/dec_vorbis_file --help

dec_vorbis_file --input <ogg file> --output <wav file>
  -h,    --help
  -i,    --input    input OGG file
  -o,    --output   output WAV file

The following example decodes input file ./assets/aud/Hydrate-Kenny_Beltrey.ogg into output file Hydrate-Kenny_Beltrey.wav:

mkdir -p ./output/dec_vorbis_file

./bin/x64/dec_vorbis_file \
  --input ./assets/aud/Hydrate-Kenny_Beltrey.ogg \
  --output ./output/dec_vorbis_file/Hydrate-Kenny_Beltrey.wav