VP8 Decoder (Run)¶
This article explains how to use Transcoder::run to decode VP8 video in an IVF container to a raw YUV video file.
The code snippets in this article are from the dec_vp8_file macOS sample.
Linux and Windows samples are also available:
Source Video¶
For source we use the foreman_qcif_vp8.ivf file from the AVBlocks Assets repository. After downloading and unzipping you will find foreman_qcif_vp8.ivf in the vid subdirectory.
Code¶
This code takes a compressed VP8 video file in an IVF container and decodes it to raw YUV 4:2:0 video format.
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 decodeResult = decodeVp8File(opt);
Library::shutdown();
return decodeResult ? 0 : 1;
}
Configure Input Socket¶
The input socket is created from MediaInfo, which reads the VP8/IVF input file and detects the encoded video stream parameters.
bool decodeVp8File(Options& opt)
{
// transcoder will fail if output exists (by design)
deleteFile(primo::ustring(opt.outputFile));
auto mediaInfo = primo::make_ref(Library::createMediaInfo());
mediaInfo->inputs()->at(0)->setFile(primo::ustring(opt.inputFile));
if(!mediaInfo->open())
{
printError("MediaInfo open:", mediaInfo->error());
return false;
}
// create input socket
auto inputSocket = primo::make_ref(Library::createMediaSocket(mediaInfo.get()));
// ...existing code...
}
Configure Output Socket¶
The output socket writes uncompressed video to the requested YUV file. The sample configures the output video stream as StreamType::UncompressedVideo with ColorFormat::YUV420.
primo::ref<MediaSocket> createOutputSocket(Options& opt)
{
auto vsi = primo::make_ref(Library::createVideoStreamInfo());
vsi->setStreamType(StreamType::UncompressedVideo);
vsi->setColorFormat(ColorFormat::YUV420);
auto pin = primo::make_ref(Library::createMediaPin());
pin->setStreamInfo(vsi.get());
auto socket = primo::make_ref(Library::createMediaSocket());
socket->setFile(primo::ustring(opt.outputFile));
socket->setStreamType(StreamType::UncompressedVideo);
socket->pins()->add(pin.get());
return socket;
}
Configure Transcoder and Decode¶
After creating the input socket from MediaInfo and the YUV output socket, the sample creates a transcoder, enables demo mode, adds the sockets, opens the transcoder, runs the decode, and closes it.
bool decodeVp8File(Options& opt)
{
// transcoder will fail if output exists (by design)
deleteFile(primo::ustring(opt.outputFile));
auto mediaInfo = primo::make_ref(Library::createMediaInfo());
mediaInfo->inputs()->at(0)->setFile(primo::ustring(opt.inputFile));
if(!mediaInfo->open())
{
printError("MediaInfo open:", mediaInfo->error());
return false;
}
// create input socket
auto inputSocket = primo::make_ref(Library::createMediaSocket(mediaInfo.get()));
// create output socket
auto outputSocket = createOutputSocket(opt);
// create transcoder
auto transcoder = primo::make_ref(Library::createTranscoder());
transcoder->setAllowDemoMode(true);
transcoder->inputs()->add(inputSocket.get());
transcoder->outputs()->add(outputSocket.get());
if(!transcoder->open())
{
printError("Transcoder open", transcoder->error());
return false;
}
if(!transcoder->run())
{
printError("Transcoder run", transcoder->error());
return false;
}
transcoder->close();
cout << "Output: " << opt.outputFile << endl;
return true;
}
Complete C++ Code¶
Here’s the complete working example from dec_vp8_file.cpp:
#include <cstdio>
#include <memory.h>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#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"
using namespace primo::codecs;
using namespace primo::avblocks;
using namespace std;
primo::ref<MediaSocket> createOutputSocket(Options& opt)
{
auto vsi = primo::make_ref(Library::createVideoStreamInfo());
vsi->setStreamType(StreamType::UncompressedVideo);
vsi->setColorFormat(ColorFormat::YUV420);
auto pin = primo::make_ref(Library::createMediaPin());
pin->setStreamInfo(vsi.get());
auto socket = primo::make_ref(Library::createMediaSocket());
socket->setFile(primo::ustring(opt.outputFile));
socket->setStreamType(StreamType::UncompressedVideo);
socket->pins()->add(pin.get());
return socket;
}
bool decodeVp8File(Options& opt)
{
// transcoder will fail if output exists (by design)
deleteFile(primo::ustring(opt.outputFile));
auto mediaInfo = primo::make_ref(Library::createMediaInfo());
mediaInfo->inputs()->at(0)->setFile(primo::ustring(opt.inputFile));
if(!mediaInfo->open())
{
printError("MediaInfo open:", mediaInfo->error());
return false;
}
// create input socket
auto inputSocket = primo::make_ref(Library::createMediaSocket(mediaInfo.get()));
// create output socket
auto outputSocket = createOutputSocket(opt);
// create transcoder
auto transcoder = primo::make_ref(Library::createTranscoder());
transcoder->setAllowDemoMode(true);
transcoder->inputs()->add(inputSocket.get());
transcoder->outputs()->add(outputSocket.get());
if(!transcoder->open())
{
printError("Transcoder open", transcoder->error());
return false;
}
if(!transcoder->run())
{
printError("Transcoder run", transcoder->error());
return false;
}
transcoder->close();
cout << "Output: " << opt.outputFile << 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();
bool decodeResult = decodeVp8File(opt);
Library::shutdown();
return decodeResult ? 0 : 1;
}
How to Run¶
See the build instructions for macOS and the dec_vp8_file example for details.
Command Line¶
./dec_vp8_file --input <file> --output <yuv_file>
Examples¶
List options:
./bin/x64/dec_vp8_file --help
Usage: dec_vp8_file -i <ivf file> -o <yuv file>
-h, --help
--input VP8/IVF input file.
--output YUV output file.
The following command decodes a VP8 video from assets/vid/foreman_qcif_vp8.ivf to output/dec_vp8_file/foreman_qcif.yuv:
mkdir -p ./output/dec_vp8_file
./bin/x64/dec_vp8_file \
--input ./assets/vid/foreman_qcif_vp8.ivf \
--output ./output/dec_vp8_file/foreman_qcif.yuv