Pad Video¶
How to fit a 16:9 video into a 4:3 frame by sizing and padding the original picture.
The code snippets in this article are from the simple_video_pad .NET sample.
Source Video¶
For a source video we use the MP4 file from the TED talk video What’s the next window into our universe? by Andrew Connolly. The original video format is Wide 480p or 16:9, 854 x 480.
Code¶
This code takes a 16:9 480p (854x480) video, and squeezes it into a 4:3 640x480 frame, while maintaining the original 16:9 picture aspect ratio. The audio stream is copied from the source as is.
Initialize AVBlocks and Configure Transcoder¶
The sample uses hardcoded input and output file paths. It creates a MediaInfo object to probe the input file, then creates input and output sockets. The output socket is cloned from the input socket, then the frame size is set to 640x480, the display ratio to 4:3, pad parameters are set (105 pixels top and bottom), and the interpolation method is set to Super for best downscaling quality.
static int Main(string[] args)
{
string inputPath = "AndrewConnolly_2014.mp4";
string outputPath = "AndrewConnolly_2014_640x480_Padded.mp4";
Library.Initialize();
bool result = PadVideo(inputPath, outputPath);
Library.Shutdown();
return result ? (int)ExitCodes.Success : (int)ExitCodes.EncodeError;
}
static bool PadVideo(string inputPath, string outputPath)
{
string outputDir = Path.GetDirectoryName(outputPath);
if (!string.IsNullOrEmpty(outputDir) && !Directory.Exists(outputDir))
{
Directory.CreateDirectory(outputDir);
}
if (File.Exists(outputPath))
{
File.Delete(outputPath);
}
using (var mediaInfo = new MediaInfo())
{
mediaInfo.Inputs[0].File = inputPath;
if (!mediaInfo.Open())
{
PrintError("Open MediaInfo", mediaInfo.Error);
return false;
}
var inputSocket = MediaSocket.FromMediaInfo(mediaInfo);
var outputSocket = (MediaSocket)inputSocket.Clone();
outputSocket.File = outputPath;
var outVideoPin = outputSocket.Pins[0];
var outVideoStream = outVideoPin.StreamInfo as VideoStreamInfo;
outVideoStream.FrameWidth = 640;
outVideoStream.FrameHeight = 480;
outVideoStream.DisplayRatioWidth = 4;
outVideoStream.DisplayRatioHeight = 3;
int padAmount = (480 - 640 * 9 / 16) / 2;
outVideoPin.Params.Add(Param.Video.Pad.Top, padAmount);
outVideoPin.Params.Add(Param.Video.Pad.Bottom, padAmount);
outVideoPin.Params.Add(Param.Video.Resize.InterpolationMethod, (int)InterpolationMethod.Super);
using (var transcoder = new Transcoder())
{
transcoder.AllowDemoMode = true;
transcoder.Inputs.Add(inputSocket);
transcoder.Outputs.Add(outputSocket);
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;
}
PrintError Helper¶
static void PrintError(string action, ErrorInfo error)
{
if (action != null)
{
Console.Write("{0}: ", action);
}
if (ErrorFacility.Success == error.Facility)
{
Console.WriteLine("Success");
return;
}
else
{
Console.WriteLine("{0}, facility:{1} code:{2} hint:{3}", error.Message ?? "", error.Facility, error.Code, error.Hint ?? "");
}
}
Complete Code¶
Here’s the complete working example that demonstrates video padding using AVBlocks for .NET.
using System;
using System.IO;
using PrimoSoftware.AVBlocks;
namespace SimpleVideoPad
{
class Program
{
static int Main(string[] args)
{
string inputPath = "AndrewConnolly_2014.mp4";
string outputPath = "AndrewConnolly_2014_640x480_Padded.mp4";
Library.Initialize();
bool result = PadVideo(inputPath, outputPath);
Library.Shutdown();
return result ? (int)ExitCodes.Success : (int)ExitCodes.EncodeError;
}
static bool PadVideo(string inputPath, string outputPath)
{
string outputDir = Path.GetDirectoryName(outputPath);
if (!string.IsNullOrEmpty(outputDir) && !Directory.Exists(outputDir))
{
Directory.CreateDirectory(outputDir);
}
if (File.Exists(outputPath))
{
File.Delete(outputPath);
}
using (var mediaInfo = new MediaInfo())
{
mediaInfo.Inputs[0].File = inputPath;
if (!mediaInfo.Open())
{
PrintError("Open MediaInfo", mediaInfo.Error);
return false;
}
var inputSocket = MediaSocket.FromMediaInfo(mediaInfo);
var outputSocket = (MediaSocket)inputSocket.Clone();
outputSocket.File = outputPath;
var outVideoPin = outputSocket.Pins[0];
var outVideoStream = outVideoPin.StreamInfo as VideoStreamInfo;
outVideoStream.FrameWidth = 640;
outVideoStream.FrameHeight = 480;
outVideoStream.DisplayRatioWidth = 4;
outVideoStream.DisplayRatioHeight = 3;
int padAmount = (480 - 640 * 9 / 16) / 2;
outVideoPin.Params.Add(Param.Video.Pad.Top, padAmount);
outVideoPin.Params.Add(Param.Video.Pad.Bottom, padAmount);
outVideoPin.Params.Add(Param.Video.Resize.InterpolationMethod, (int)InterpolationMethod.Super);
using (var transcoder = new Transcoder())
{
transcoder.AllowDemoMode = true;
transcoder.Inputs.Add(inputSocket);
transcoder.Outputs.Add(outputSocket);
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;
}
static void PrintError(string action, ErrorInfo error)
{
if (action != null)
{
Console.Write("{0}: ", action);
}
if (ErrorFacility.Success == error.Facility)
{
Console.WriteLine("Success");
return;
}
else
{
Console.WriteLine("{0}, facility:{1} code:{2} hint:{3}", error.Message ?? "", error.Facility, error.Code, error.Hint ?? "");
}
}
enum ExitCodes : int
{
Success = 0,
EncodeError = 2,
}
}
}
How to Run¶
See the simple_video_pad .NET sample for details.
Command Line¶
This sample uses hardcoded input and output file paths — no command line parsing.
bin/net10.0/simple_video_pad
Examples¶
Build the sample from the repository root:
dotnet build samples.sln
Download the sample video:
cd samples/simple_video_pad
curl -L -o AndrewConnolly_2014.mp4 \
https://archive.org/download/AndrewConnolly_2014/AndrewConnolly_2014.mp4
Run the sample (the input/output file paths are relative to the working directory):
# Linux and macOS
../../bin/net10.0/simple_video_pad
# Windows
..\..\bin\net10.0\simple_video_pad.exe
The padded output file AndrewConnolly_2014_640x480_Padded.mp4 will be created in the samples/simple_video_pad directory.