HEVC / H.265 Annex B Decoder (Run)¶
This article explains how you can use {transcoder-run-net} to decode a HEVC / H.265 Annex B elementary stream to a raw YUV video file.
The code snippets in this article are from the dec_hevc_file .NET sample.
Source Video¶
For source we use a HEVC-encoded video file. After downloading and unzipping the AVBlocks Assets archive, you can find HEVC test files in the vid subdirectory.
Code¶
This code takes a compressed HEVC elementary stream file and decodes it to raw YUV 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. The Library.Initialize() method sets up the internal state and loads necessary codecs. Always remember to call Library.Shutdown() at the end of your program to properly clean up resources and release any allocated memory.
static int Main(string[] args)
{
var opt = new Options();
if (!opt.Prepare(args))
return opt.Error ? (int)ExitCodes.OptionsError : (int)ExitCodes.Success;
Library.Initialize();
bool decodeResult = Decode(opt);
Library.Shutdown();
return decodeResult ? (int)ExitCodes.Success : (int)ExitCodes.DecodingError;
}
Configure Input Socket¶
The input socket defines the source HEVC elementary stream. We use MediaInfo to automatically detect the video parameters from the input file. This is more convenient than manually specifying parameters, as MediaInfo reads the stream headers and extracts all necessary information about the encoded video, including resolution, frame rate, and codec settings.
static bool Decode(Options opt)
{
// transcoder will fail if output exists (by design)
DeleteFile(opt.OutputFile);
var mediaInfo = new PrimoSoftware.AVBlocks.MediaInfo();
mediaInfo.Inputs[0].File = opt.InputFile;
if (!mediaInfo.Open())
{
PrintError("MediaInfo.Open()", mediaInfo.Error);
return false;
}
MediaSocket inSocket = MediaSocket.FromMediaInfo(mediaInfo);
MediaSocket outSocket = CreateOutputSocket(opt);
// create Transcoder
using (Transcoder transcoder = new Transcoder())
{
transcoder.AllowDemoMode = true;
transcoder.Inputs.Add(inSocket);
transcoder.Outputs.Add(outSocket);
bool res = transcoder.Open();
PrintError("Transcoder open", transcoder.Error);
if (!res)
return false;
res = transcoder.Run();
PrintError("Transcoder run", transcoder.Error);
if (!res)
return false;
transcoder.Close();
PrintError("Transcoder close", transcoder.Error);
if (!res)
return false;
}
return true;
}
Configure Output Socket¶
The output socket defines the raw YUV video format for the decoded output. We specify the output file path, set the stream type to UncompressedVideo, and configure the video pin with ColorFormat.YUV420 for standard 4:2:0 YUV planar format.
static MediaSocket CreateOutputSocket(Options opt)
{
MediaSocket socket = new MediaSocket();
socket.File = opt.OutputFile;
socket.StreamType = StreamType.UncompressedVideo;
MediaPin pin = new MediaPin();
socket.Pins.Add(pin);
VideoStreamInfo vsi = new VideoStreamInfo();
pin.StreamInfo = vsi;
vsi.StreamType = StreamType.UncompressedVideo;
vsi.ColorFormat = ColorFormat.YUV420;
return socket;
}
Configure and Run Transcoder¶
This section shows how to set up the transcoder with the input and output sockets, then run the decoding operation. The AllowDemoMode = true property allows the transcoder to work even without a valid license (useful for testing, but not recommended for production). We add our input and output sockets to the transcoder, open it to prepare for processing, run the actual transcoding operation, and finally close it to clean up.
// create output socket
MediaSocket outSocket = CreateOutputSocket(opt);
// create Transcoder
using (Transcoder transcoder = new Transcoder())
{
transcoder.AllowDemoMode = true;
transcoder.Inputs.Add(inSocket);
transcoder.Outputs.Add(outSocket);
bool res = transcoder.Open();
PrintError("Transcoder open", transcoder.Error);
if (!res)
return false;
res = transcoder.Run();
PrintError("Transcoder run", transcoder.Error);
if (!res)
return false;
transcoder.Close();
PrintError("Transcoder close", transcoder.Error);
if (!res)
return false;
}
return true;
Complete Code¶
Here’s the complete working example that demonstrates HEVC/H.265 decoding using AVBlocks for .NET. This code combines all the previous snippets into a functional program that can be compiled and run.
using System;
using PrimoSoftware.AVBlocks;
namespace CliSample
{
class Program
{
static int Main(string[] args)
{
var opt = new Options();
if (!opt.Prepare(args))
return opt.Error ? (int)ExitCodes.OptionsError : (int)ExitCodes.Success;
Library.Initialize();
bool decodeResult = Decode(opt);
Library.Shutdown();
return decodeResult ? (int)ExitCodes.Success : (int)ExitCodes.DecodingError;
}
static bool Decode(Options opt)
{
// transcoder will fail if output exists (by design)
DeleteFile(opt.OutputFile);
var mediaInfo = new PrimoSoftware.AVBlocks.MediaInfo();
mediaInfo.Inputs[0].File = opt.InputFile;
if (!mediaInfo.Open())
{
PrintError("MediaInfo.Open()", mediaInfo.Error);
return false;
}
MediaSocket inSocket = MediaSocket.FromMediaInfo(mediaInfo);
MediaSocket outSocket = CreateOutputSocket(opt);
// create Transcoder
using (Transcoder transcoder = new Transcoder())
{
transcoder.AllowDemoMode = true;
transcoder.Inputs.Add(inSocket);
transcoder.Outputs.Add(outSocket);
bool res = transcoder.Open();
PrintError("Transcoder open", transcoder.Error);
if (!res)
return false;
res = transcoder.Run();
PrintError("Transcoder run", transcoder.Error);
if (!res)
return false;
transcoder.Close();
PrintError("Transcoder close", transcoder.Error);
if (!res)
return false;
}
return true;
}
static void DeleteFile(string filename)
{
try
{
if (System.IO.File.Exists(filename))
System.IO.File.Delete(filename);
}
catch { }
}
static MediaSocket CreateOutputSocket(Options opt)
{
MediaSocket socket = new MediaSocket();
socket.File = opt.OutputFile;
socket.StreamType = StreamType.UncompressedVideo;
MediaPin pin = new MediaPin();
socket.Pins.Add(pin);
VideoStreamInfo vsi = new VideoStreamInfo();
pin.StreamInfo = vsi;
vsi.StreamType = StreamType.UncompressedVideo;
vsi.ColorFormat = ColorFormat.YUV420;
return socket;
}
static void PrintError(string action, ErrorInfo e)
{
if (action != null)
{
Console.Write("{0}: ", action);
}
if (ErrorFacility.Success == e.Facility)
{
Console.WriteLine("Success");
return;
}
else
{
Console.WriteLine("{0}, facility:{1} code:{2} hint:{3}", e.Message ?? "", e.Facility, e.Code, e.Hint ?? "");
}
}
enum ExitCodes : int
{
Success = 0,
OptionsError = 1,
DecodingError = 2,
}
}
}
How to Run¶
See the dec_hevc_file .NET sample for details.
Command Line¶
dec_hevc_file --input <file.h265> --output <file.yuv>
Examples¶
List options:
./bin/net10.0/dec_hevc_file --help
Decode the H.265 file ./assets/vid/foreman_qcif.h265 to YUV output:
# Linux and macOS
mkdir -p ./output/dec_hevc_file
./bin/net10.0/dec_hevc_file \
--input ./assets/vid/foreman_qcif.h265 \
--output ./output/dec_hevc_file/foreman_qcif.yuv
# Windows
mkdir -Force -Path ./output/dec_hevc_file
./bin/net10.0/dec_hevc_file `
--input ./assets/vid/foreman_qcif.h265 `
--output ./output/dec_hevc_file/foreman_qcif.yuv