画中画(Picture in Picture,简称PIP)是视频处理中常见的一种技术,允许在主视频上叠加另一个视频。本文将详细介绍如何使用 Xabe.FFmpeg 库在 C# 中实现画中画效果。
首先,需要安装以下 NuGet 包:
C#Install-Package Xabe.FFmpeg Install-Package Xabe.FFmpeg.Downloader
C#public static async Task CreatePictureInPicture(
string mainVideoPath, // 主视频路径
string overlayVideoPath, // 叠加视频路径
string outputPath, // 输出视频路径
int x = 50, // 叠加视频的 X 坐标
int y = 50, // 叠加视频的 Y 坐标
int width = 320, // 叠加视频的宽度
int height = 240) // 叠加视频的高度
{
try
{
// 获取主视频信息
IMediaInfo mainVideoInfo = await FFmpeg.GetMediaInfo(mainVideoPath);
IMediaInfo overlayVideoInfo = await FFmpeg.GetMediaInfo(overlayVideoPath);
// 获取视频流
IVideoStream mainVideoStream = mainVideoInfo.VideoStreams.First();
IVideoStream overlayVideoStream = overlayVideoInfo.VideoStreams.First();
// 获取视频持续时间的更可靠方法
double mainVideoDuration = mainVideoInfo.Duration.TotalSeconds;
// 设置画中画过滤器,包括缩放
string filter =
$"[1:v]scale={width}:{height}[pip];" + // 缩放叠加视频
$"[0:v][pip]overlay=x={x}:y={y}:enable='between(t,0,{mainVideoDuration})'[outv]";
// 执行 FFmpeg 转换
await FFmpeg.Conversions.New()
.AddParameter($"-i {mainVideoPath}")
.AddParameter($"-i {overlayVideoPath}")
.AddParameter($"-filter_complex {filter}")
.AddParameter("-map [outv]")
.SetOutput(outputPath)
.Start();
}
catch (Exception ex)
{
Console.WriteLine($"画中画处理错误: {ex.Message}");
}
}
C#static async Task Main(string[] args)
{
// 设置FFmpeg的二进制文件路径(如果是非标准安装)
FFmpeg.SetExecutablesPath("D:\\Software\\ffmpeg-master-latest-win64-gpl-shared\\bin");
await CreatePictureInPicture(
mainVideoPath: @"D:\Video\1.mp4",
overlayVideoPath: @"D:\Video\2.mp4",
outputPath: @"d:\output_pip.mp4",
x: 50, // 距离左边 50 像素
y: 50, // 距离顶部 50 像素
width: 320,
height: 240
);
}
C#using Xabe.FFmpeg;
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace App16
{
internal class Program
{
public static async Task CreatePictureInPicture(
string mainVideoPath, // 主视频路径
string overlayVideoPath, // 叠加视频路径
string outputPath, // 输出视频路径
int x = 50, // 叠加视频的 X 坐标
int y = 50, // 叠加视频的 Y 坐标
int width = 320, // 叠加视频的宽度
int height = 240) // 叠加视频的高度
{
try
{
// 获取主视频信息
IMediaInfo mainVideoInfo = await FFmpeg.GetMediaInfo(mainVideoPath);
IMediaInfo overlayVideoInfo = await FFmpeg.GetMediaInfo(overlayVideoPath);
// 获取视频流
IVideoStream mainVideoStream = mainVideoInfo.VideoStreams.First();
IVideoStream overlayVideoStream = overlayVideoInfo.VideoStreams.First();
// 获取视频持续时间的更可靠方法
double mainVideoDuration = mainVideoInfo.Duration.TotalSeconds;
// 设置画中画和音频混合的复杂滤镜
string filter =
$"[1:v]scale={width}:{height}[pip];" + // 缩放叠加视频
$"[0:v][pip]overlay=x={x}:y={y}:enable='between(t,0,{mainVideoDuration})'[outv];" +
$"[0:a][1:a]amix=inputs=2:duration=first[outa]"; // 混合音频
// 执行 FFmpeg 转换
await FFmpeg.Conversions.New()
.AddParameter($"-i {mainVideoPath}")
.AddParameter($"-i {overlayVideoPath}")
.AddParameter($"-filter_complex {filter}")
.AddParameter("-map [outv]") // 视频映射
.AddParameter("-map [outa]") // 音频映射
.SetOutput(outputPath)
.Start();
}
catch (Exception ex)
{
Console.WriteLine($"画中画处理错误: {ex.Message}");
}
}
static async Task Main(string[] args)
{
// 设置FFmpeg的二进制文件路径(如果是非标准安装)
FFmpeg.SetExecutablesPath("D:\\Software\\ffmpeg-master-latest-win64-gpl-shared\\bin");
await CreatePictureInPicture(
mainVideoPath: @"D:\Video\1.mp4",
overlayVideoPath: @"D:\Video\2.mp4",
outputPath: @"d:\output_pip.mp4",
x: 50, // 距离左边 50 像素
y: 50, // 距离顶部 50 像素
width: 320,
height: 240
);
}
}
}
C#using Xabe.FFmpeg;
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace App16
{
internal class Program
{
public static async Task CreatePictureInPicture(
string mainVideoPath, // 主视频路径
string overlayVideoPath, // 叠加视频路径
string outputPath, // 输出视频路径
IProgress<double> progress = null, // 进度回调
CancellationToken cancellationToken = default, // 取消令牌
int x = 50, // 叠加视频的 X 坐标
int y = 50, // 叠加视频的 Y 坐标
int width = 320, // 叠加视频的宽度
int height = 240) // 叠加视频的高度
{
try
{
// 获取主视频信息
IMediaInfo mainVideoInfo = await FFmpeg.GetMediaInfo(mainVideoPath);
IMediaInfo overlayVideoInfo = await FFmpeg.GetMediaInfo(overlayVideoPath);
// 获取视频流
IVideoStream mainVideoStream = mainVideoInfo.VideoStreams.First();
IVideoStream overlayVideoStream = overlayVideoInfo.VideoStreams.First();
// 获取视频持续时间的更可靠方法
double mainVideoDuration = mainVideoInfo.Duration.TotalSeconds;
// 设置画中画和音频混合的复杂滤镜
string filter =
$"[1:v]scale={width}:{height}[pip];" + // 缩放叠加视频
$"[0:v][pip]overlay=x={x}:y={y}:enable='between(t,0,{mainVideoDuration})'[outv];" +
$"[0:a][1:a]amix=inputs=2:duration=first[outa]"; // 混合音频
// 执行 FFmpeg 转换
var conversion = FFmpeg.Conversions.New()
.AddParameter($"-i {mainVideoPath}")
.AddParameter($"-i {overlayVideoPath}")
.AddParameter($"-filter_complex {filter}")
.AddParameter("-map [outv]") // 视频映射
.AddParameter("-map [outa]") // 音频映射
.SetOutput(outputPath);
// 如果提供了进度回调,添加进度事件
if (progress != null)
{
conversion.OnProgress += (sender, e) =>
{
// 计算百分比进度
double progressPercentage = e.Percent;
progress.Report(progressPercentage);
};
}
// 添加取消令牌支持
await conversion.Start(cancellationToken);
}
catch (OperationCanceledException)
{
Console.WriteLine("操作已取消");
}
catch (Exception ex)
{
Console.WriteLine($"画中画处理错误: {ex.Message}");
}
}
static async Task Main(string[] args)
{
// 设置FFmpeg的二进制文件路径(如果是非标准安装)
FFmpeg.SetExecutablesPath("D:\\Software\\ffmpeg-master-latest-win64-gpl-shared\\bin");
// 创建进度回调
var progress = new Progress<double>(percent =>
{
// 控制台进度条
Console.Write($"\r进度: {percent:F2}% [");
int progressBarWidth = 50;
int filledWidth = (int)(percent / 100 * progressBarWidth);
Console.Write(new string('=', filledWidth));
Console.Write(new string(' ', progressBarWidth - filledWidth));
Console.Write("]");
});
// 创建取消令牌源
var cts = new CancellationTokenSource();
// 可选:添加取消操作的监听(例如按 Ctrl+C)
Console.CancelKeyPress += (sender, e) =>
{
e.Cancel = true; // 阻止默认的程序终止
cts.Cancel(); // 触发取消
};
try
{
await CreatePictureInPicture(
mainVideoPath: @"D:\Video\1.mp4",
overlayVideoPath: @"D:\Video\2.mp4",
outputPath: @"d:\output_pip.mp4",
progress: progress, // 传入进度回调
cancellationToken: cts.Token, // 传入取消令牌
x: 50, // 距离左边 50 像素
y: 50, // 距离顶部 50 像素
width: 320,
height: 240
);
Console.WriteLine("\n转换完成!");
}
catch (Exception ex)
{
Console.WriteLine($"\n发生错误: {ex.Message}");
}
}
}
}

可以根据视频长度和需求动态调整叠加视频的位置和大小。
通过调整 FFmpeg 过滤器,可以实现多个视频的叠加。
Xabe.FFmpeg 提供了强大且灵活的视频处理能力,通过合理使用,可以轻松实现画中画等高级视频特效。
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!