Simple Video Converter

Building a video converter using C++ and the AVBlocks Transcoder.

Source Video

For a video source we use the Wildlife.mp4 movie from the Internet Archive. The original format is an MP4 container with H.264/AVC video and AAC audio. On Windows we use the Wildlife.wmv version of the same movie.

Overview

These snippets are fully functional video converters. They take Wildlife.mp4 (Wildlife.wmv on Windows) as input and convert it to H.265/HEVC video and AAC audio in an MP4 container, saved as Wildlife_h265_aac.mp4.

macOS

Code

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

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

int main(int argc, const char *argv[]) {
    Library::initialize();

    auto inputFile = primo::ustring(L"Wildlife.mp4");
    auto outputFile = primo::ustring(L"Wildlife_h265_aac.mp4");

    auto inputInfo = primo::make_ref(Library::createMediaInfo());
    inputInfo->inputs()->at(0)->setFile(inputFile);

    if (inputInfo->open()) {
        auto inputSocket = primo::make_ref(
            Library::createMediaSocket(inputInfo.get())
        );
        
        // Start with same output as the input, which is MP4 / H.264 + AAC
        auto outputSocket = primo::make_ref(inputSocket->clone());

        // Change the video stream type to H.265 (HEVC) 
        // and the stream subtype to HEVC Annex B
        auto outVideoStream = (VideoStreamInfo*)outputSocket
                                                ->pins()->at(0)
                                                ->streamInfo();
        outVideoStream->setStreamType(StreamType::H265);
        outVideoStream->setStreamSubType(StreamSubType::HEVC_Annex_B);
        
        // Input is H.264/AVC at 700 kbps
        // With H.265/HEVC we can use lower bitrate, e.g. 500 kbps
        outVideoStream->setBitrate(500'000);

        // Change the output file name to Wildlife_h265_aac.mp4
        outputSocket->setFile(outputFile);
        
        // Create Transcoder and configure it with 
        // the input and output sockets
        auto transcoder = primo::make_ref(Library::createTranscoder());
        transcoder->inputs()->add(inputSocket.get());
        transcoder->outputs()->add(outputSocket.get());

        // Allow demo mode for the transcoder when 
        // using the demo version of the library
        transcoder->setAllowDemoMode(true);

        // Run the transcoder
        if (transcoder->open()) {
            transcoder->run();
            transcoder->close();
        } else {
            std::cerr << "transcoder->open() failed: " 
                      << primo::ustring(transcoder->error()->message()) 
                      << std::endl;
        }
    }

    Library::shutdown();
    return 0;
}

How to run

Follow the steps in Create a Command Line Tool using CMake on macOS, but use the code from this article.

Download the Wildlife.mp4 sample file and save it in the project directory:

curl \
  -L -o Wildlife.mp4 \
  https://archive.org/download/WildlifeSampleVideo/Wildlife.mp4

Run the application. Wait for the Transcoder to finish - it will take a few minutes. The converted file Wildlife_h265_aac.mp4 will be in the project directory.

Linux

Code

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

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

int main(int argc, const char *argv[]) {
    Library::initialize();

    auto inputFile = primo::ustring(L"Wildlife.mp4");
    auto outputFile = primo::ustring(L"Wildlife_h265_aac.mp4");

    auto inputInfo = primo::make_ref(Library::createMediaInfo());
    inputInfo->inputs()->at(0)->setFile(inputFile);

    if (inputInfo->open()) {
        auto inputSocket = primo::make_ref(
            Library::createMediaSocket(inputInfo.get())
        );
        
        // Start with same output as the input, which is MP4 / H.264 + AAC
        auto outputSocket = primo::make_ref(inputSocket->clone());

        // Change the video stream type to H.265 (HEVC) 
        // and the stream subtype to HEVC Annex B
        auto outVideoStream = (VideoStreamInfo*)outputSocket
                                                ->pins()->at(0)
                                                ->streamInfo();
        outVideoStream->setStreamType(StreamType::H265);
        outVideoStream->setStreamSubType(StreamSubType::HEVC_Annex_B);
        
        // Input is H.264/AVC at 700 kbps
        // With H.265/HEVC we can use lower bitrate, e.g. 500 kbps
        outVideoStream->setBitrate(500'000);

        // Change the output file name to Wildlife_h265_aac.mp4
        outputSocket->setFile(outputFile);
        
        // Create Transcoder and configure it with 
        // the input and output sockets
        auto transcoder = primo::make_ref(Library::createTranscoder());
        transcoder->inputs()->add(inputSocket.get());
        transcoder->outputs()->add(outputSocket.get());

        // Allow demo mode for the transcoder when 
        // using the demo version of the library
        transcoder->setAllowDemoMode(true);

        // Run the transcoder
        if (transcoder->open()) {
            transcoder->run();
            transcoder->close();
        } else {
            std::cerr << "transcoder->open() failed: " 
                      << primo::ustring(transcoder->error()->message()) 
                      << std::endl;
        }
    }

    Library::shutdown();
    return 0;
}

How to run

Follow the steps in Create a Command Line Tool using CMake on Ubuntu, but use the code from this article.

Download the Wildlife.mp4 sample file and save it in the project directory:

curl \
  -L -o Wildlife.mp4 \
  https://archive.org/download/WildlifeSampleVideo/Wildlife.mp4

Run the application. Wait for the Transcoder to finish - it will take a few minutes. The converted file Wildlife_h265_aac.mp4 will be in the project directory.

Windows

Code

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

#include <windows.h>

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

int wmain(int argc, wchar_t* argv[])
{
    // needed for WMV
    CoInitializeEx(nullptr, COINITBASE_MULTITHREADED);

    Library::initialize();

    auto inputFile = primo::ustring(L"Wildlife.wmv");
    auto outputFile = primo::ustring(L"Wildlife_h265_aac.mp4");

    auto inputInfo = primo::make_ref(Library::createMediaInfo());
    inputInfo->inputs()->at(0)->setFile(inputFile);

    if (inputInfo->open()) {
        auto inputSocket = primo::make_ref(
            Library::createMediaSocket(inputInfo.get())
        );
        
        // Start with MP4 / H.264 + AAC preset, then change video to H.265
        auto outputSocket = primo::make_ref(
            Library::createMediaSocket(Preset::Video::Generic::MP4::Base_H264_AAC)
        );

        // Get the output video stream info and modify it for H.265/HEVC
        auto outVideoStream = (VideoStreamInfo*)outputSocket->pins()->at(0)->streamInfo();
        outVideoStream->setStreamType(StreamType::H265);
        outVideoStream->setStreamSubType(StreamSubType::HEVC_Annex_B);
        
        // With H.265/HEVC we can use lower bitrate, e.g. 500 kbps
        outVideoStream->setBitrate(500'000);

        // Change the output file name to Wildlife_h265_aac.mp4
        outputSocket->setFile(outputFile);
        
        // Create Transcoder and configure it with 
        // the input and output sockets
        auto transcoder = primo::make_ref(Library::createTranscoder());
        transcoder->inputs()->add(inputSocket.get());
        transcoder->outputs()->add(outputSocket.get());

        // Allow demo mode for the transcoder when 
        // using the demo version of the library
        transcoder->setAllowDemoMode(true);

        // Run the transcoder
        if (transcoder->open()) {
            transcoder->run();
            transcoder->close();
        } else {
            std::wcerr << L"transcoder->open() failed: " 
                       << primo::ustring(transcoder->error()->message()) 
                       << std::endl;
        }
    }

    Library::shutdown();

    CoUninitialize();

    return 0;
}

How to run

Follow the steps in Create a Command Line Tool using CMake on Windows, but use the code from this article.

Download the Wildlife.wmv sample file and save it in the project directory:

Invoke-WebRequest `
  -Uri https://archive.org/download/WildlifeSampleVideo/Wildlife.wmv `
  -OutFile Wildlife.wmv

Run the application. Wait for the Transcoder to finish - it will take a few seconds. The converted file Wildlife_h265_aac.mp4 will be in the project directory.