编辑
2025-11-22
C#
00

目录

准备工作
安装 NuGet 包
画中画实现详细代码
基本画中画方法
使用示例
混合音频
增加进度条
高级特性
动态调整画中画位置
多视频叠加
注意事项
性能优化建议
结语

画中画(Picture in Picture,简称PIP)是视频处理中常见的一种技术,允许在主视频上叠加另一个视频。本文将详细介绍如何使用 Xabe.FFmpeg 库在 C# 中实现画中画效果。

准备工作

安装 NuGet 包

首先,需要安装以下 NuGet 包:

  • Xabe.FFmpeg
  • Xabe.FFmpeg.Downloader
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}"); } } } }

image.png

高级特性

动态调整画中画位置

可以根据视频长度和需求动态调整叠加视频的位置和大小。

多视频叠加

通过调整 FFmpeg 过滤器,可以实现多个视频的叠加。

注意事项

  • 确保输入视频编码兼容
  • 处理大文件时注意内存占用
  • 根据实际需求调整视频参数

性能优化建议

  • 使用硬件加速编码
  • 选择合适的视频编码器
  • 预先检查视频兼容性

结语

Xabe.FFmpeg 提供了强大且灵活的视频处理能力,通过合理使用,可以轻松实现画中画等高级视频特效。

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!