Demux Audio and Video From WebM¶
This topic describes how to use the TTranscoder::run method to extract the first audio and video streams from a WebM container and save each stream into a separate WebM file.
The code snippets in this article are from the demux_webm_file macOS sample.
Linux and Windows samples are also available:
Source File¶
For source we use the big-buck-bunny_trailer_vp8_vorbis.webm 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 a WebM container and writes them to separate WebM files.
Initialize AVBlocks¶
Initialize the AVBlocks library before creating the transcoder, and shut it down after the demuxing 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;
}
TLibrary library;
return demux(opt) ? 0 : 1;
}
Read the Input Container¶
The sample uses TMediaInfo to inspect the WebM input file and create the input socket from the discovered stream information.
TMediaInfo mediaInfo;
mediaInfo.inputs(0).file(opt.inputFile);
mediaInfo.open();
TMediaSocket inSocket(mediaInfo);
TTranscoder transcoder;
transcoder.allowDemoMode(true);
transcoder.addInput(inSocket);
Select Audio and Video Streams¶
The sample keeps the first audio stream and the first video stream. Any additional pins are disabled.
bool audio = false;
bool video = false;
for (int i = 0; i < inSocket.pins().count(); ++i)
{
auto pin = inSocket.pins(i);
auto mediaType = pin.streamInfo().mediaType();
std::string fileName;
if (mediaType == MediaType::Audio && !audio)
{
audio = true;
fileName = opt.outputFile + ".aud.webm";
}
else if (mediaType == MediaType::Video && !video)
{
video = true;
fileName = opt.outputFile + ".vid.webm";
}
else
{
pin.connection(PinConnection::Disabled);
continue;
}
Create Output Sockets¶
For each selected stream, the sample creates an output socket, attaches the corresponding input pin, sets the output file, and adds the socket to the transcoder outputs.
std::println("Output file: {}", fileName);
deleteFile(fileName.c_str());
TMediaSocket outSocket;
outSocket.addPin(TMediaPin(pin.get()));
outSocket.file(fileName);
transcoder.addOutput(outSocket);
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.
bool demux(const Options& opt)
{
try {
TMediaInfo mediaInfo;
mediaInfo.inputs(0).file(opt.inputFile);
mediaInfo.open();
TMediaSocket inSocket(mediaInfo);
TTranscoder transcoder;
transcoder.allowDemoMode(true);
transcoder.addInput(inSocket);
bool audio = false;
bool video = false;
for (int i = 0; i < inSocket.pins().count(); ++i)
{
auto pin = inSocket.pins(i);
auto mediaType = pin.streamInfo().mediaType();
std::string fileName;
if (mediaType == MediaType::Audio && !audio)
{
audio = true;
fileName = opt.outputFile + ".aud.webm";
}
else if (mediaType == MediaType::Video && !video)
{
video = true;
fileName = opt.outputFile + ".vid.webm";
}
else
{
pin.connection(PinConnection::Disabled);
continue;
}
std::println("Output file: {}", fileName);
deleteFile(fileName.c_str());
TMediaSocket outSocket;
outSocket.addPin(TMediaPin(pin.get()));
outSocket.file(fileName);
transcoder.addOutput(outSocket);
}
transcoder.open().run().close();
return true;
} catch (const TAVBlocksException& ex) {
std::println(stderr, "AVBlocks error: {}", ex.what());
return false;
} catch (const std::exception& ex) {
std::println(stderr, "Error: {}", ex.what());
return false;
}
}
Complete C++ Code¶
Here’s the complete working example from demux_webm_file.cpp:
#include <primo/avblocks/avb++.h>
#include <print>
#include <string>
#include "options.h"
#include "util.h"
using namespace primo::codecs;
using namespace primo::avblocks;
using namespace primo::avblocks::modern;
bool demux(const Options& opt)
{
try {
TMediaInfo mediaInfo;
mediaInfo.inputs(0).file(opt.inputFile);
mediaInfo.open();
TMediaSocket inSocket(mediaInfo);
TTranscoder transcoder;
transcoder.allowDemoMode(true);
transcoder.addInput(inSocket);
bool audio = false;
bool video = false;
for (int i = 0; i < inSocket.pins().count(); ++i)
{
auto pin = inSocket.pins(i);
auto mediaType = pin.streamInfo().mediaType();
std::string fileName;
if (mediaType == MediaType::Audio && !audio)
{
audio = true;
fileName = opt.outputFile + ".aud.webm";
}
else if (mediaType == MediaType::Video && !video)
{
video = true;
fileName = opt.outputFile + ".vid.webm";
}
else
{
pin.connection(PinConnection::Disabled);
continue;
}
std::println("Output file: {}", fileName);
deleteFile(fileName.c_str());
TMediaSocket outSocket;
outSocket.addPin(TMediaPin(pin.get()));
outSocket.file(fileName);
transcoder.addOutput(outSocket);
}
transcoder.open().run().close();
return true;
} catch (const TAVBlocksException& ex) {
std::println(stderr, "AVBlocks error: {}", ex.what());
return false;
} catch (const std::exception& ex) {
std::println(stderr, "Error: {}", ex.what());
return false;
}
}
int main(int argc, char* argv[])
{
Options opt;
switch(prepareOptions(opt, argc, argv))
{
case Command: return 0;
case Error: return 1;
case Parsed: break;
}
TLibrary library;
return demux(opt) ? 0 : 1;
}
How to Run¶
See the build instructions for macOS and the demux_webm_file example for details.
Command Line¶
demux_webm_file --input <input_webm_file> --output <output_webm_file_name_without_extension>
Examples¶
List options:
./bin/x64/demux_webm_file --help
Usage: demux_webm_file -i <input_webm_file> -o <output_webm_file_name_without_extension>
-h, --help
-i, --input Input webm file.
-o, --output Output webm filename (without extension).
Extract the audio and video elementary streams from the input file ./assets/mov/big-buck-bunny_trailer_vp8_vorbis.webm into output files named big-buck-bunny_trailer_vp8_vorbis.vid.webm and big-buck-bunny_trailer_vp8_vorbis.aud.webm:
mkdir -p ./output/demux_webm_file
./bin/x64/demux_webm_file \
--input ./assets/mov/big-buck-bunny_trailer_vp8_vorbis.webm \
--output ./output/demux_webm_file/big-buck-bunny_trailer_vp8_vorbis