文章目录
需求
实现
需求
在正式开始之前,先介绍下我的需求是怎么样的,基于此需求如何使用ffmpeg实现。仅供参考。

需求点:

将图片保存为视频
图片数量不是固定的,是由上游的webrtc传下的帧数据,转成的bitmap。所以只要webrtc开着,图片流就一直会有。
每帧图像的间隔时间依赖于不同的网络环境,所以不是固定的时间间隔。
实现
在使用原生ffmpeg之前,笔者使用了几个第三方的nuget库,如:FFmpeg.AutoGen、Xabe.FFmpeg、Accord.Video.FFMPEG。前两个库要么只支持将文件夹里现有的图片保存为mp4,要么不支持设置每帧的PTS,导致生成的mp4播放速度太快。最后选用了Accord.Video.FFMPEG,这个库能满足上述的三个需求点。无奈此库已长期不维护,当上游的FPS>15时,WriteVideoFrame方法抛出异常的频率会大大提升,导致内存泄漏,而且当前帧也会被丢掉。

然后项目使用的是.net452,一时半会版本也升级不上去,这就过滤大多数的nuget库。最后,只能使用的原生的ffmpeg了。
ffmpeg只是提供了一个exe,并没有官方的API可供我们调用,只提供了一大堆的参数说明,真是令人头大。经过不断的看文档和搜索调试之后,发现配置以下参数可以达到我们的需求。

-f image2pipe -use_wallclock_as_timestamps 1 -i - -c:v libx264 -pix_fmt yuv420p -vsync passthrough -maxrate 5000k -an -y 123.mp4
1
以下对各参数做个简单介绍:

image2pipe:使用图片管道,我们可以将图片数据一直往管道里塞,ffmpeg会不断将其添加到mp4文件中。用来满足需求1和2.
use_wallclock_as_timestamps 1:开启此选项,ffmpeg就会将接收此图片的时间作为该帧的timestamp。这样生成的MP4播放速度才正常,满足需求3.
pix_fmt yuv420p:设置像素格式,解决生成的视频无法使用windows media player播放的问题。
-vsync passthrough:可以理解为动态帧率,根据上游的帧率来决定输出mp4的帧率。默认有以下几个选项:
passthrough :使用帧原始的timestamp.
cfr (1):根据输出帧率的配置,进行自动插帧(上游帧率小于输入帧率)或者丢帧(上游帧率大于输入帧率)。
vfr (2):类似于passthrough, 不过当两帧具有timestamp时会丢弃其中一个。
drop:类似于passthrough,只不过会丢弃帧原始的timstamp,然后重新生成符合帧率要求的timestamp。
auto (-1):默认行为。在cfr和vfr之前自动选择。
maxrate:设置最大比特率
123.mp4:保存的文件名或者路径,注意里面不要有空格。
最后的C#代码如下,我们需要使用Process类来启动ffmpeg.exe。

public class FfmpegToVideoService
{
private bool _isRunning = false;
private int _fps;
private readonly Process _proc; /// <summary>
/// Bitmap保存为MP4
/// </summary>
/// <param name="filePath">mp4要保存的路径,如:D:\\a\b\123.mp4</param>
/// <param name="maxBitRate">最大比特率,单位K</param>
public FfmpegToVideoService(string filePath,int maxBitRate = 5000)
{
var formattedPath = Path.GetFullPath(filePath);
_proc = new Process();
//-pix_fmt yuv420p -movflags +faststart -r {30} -i pipe:.bmp -r {_fps} -timecode 00:00:00.000
//-vsync cfr自动差值 vfr根据timestamp,重复的丢弃 passthrough根据timestamp重复的不丢 -vsync passthrough
//-r 30 入帧出帧都是30
_proc.StartInfo.FileName = @"ffmpeg.exe";
_proc.StartInfo.Arguments = $"-f image2pipe -use_wallclock_as_timestamps 1 -i - -c:v libx264 -pix_fmt yuv420p -vsync passthrough -maxrate {maxBitRate}k -an -y {formattedPath}";
_proc.StartInfo.WorkingDirectory = CommonFunctions.BasePath;
_proc.StartInfo.UseShellExecute = false;
_proc.StartInfo.RedirectStandardInput = true;
_proc.StartInfo.RedirectStandardOutput = true;
_proc.Start();
} // 将Bitmap数据写入管道
private void SendToPipe(Bitmap bitmap)
{
if (_proc.StartInfo.RedirectStandardInput)
{
using (MemoryStream ms = new MemoryStream())
{
bitmap.Save(ms, ImageFormat.Png);
ms.WriteTo(_proc.StandardInput.BaseStream);
}
}
} /// <summary>
/// 异步线程启动服务
/// </summary>
public override void StartAsync()
{
_isRunning = true;
} /// <summary>
/// 停止服务
/// </summary>
public override void Stop()
{
_isRunning = false;
try
{
_proc.StartInfo.RedirectStandardInput = false;
_proc.StartInfo.RedirectStandardOutput = false;
_proc.StandardInput.Close();
_proc.StandardOutput.Close();
_proc.Close();
}
catch (Exception ex)
{
Log.Error(ex, "");
}
} /// <summary>
/// 添加item
/// </summary>
/// <param name="item"></param>
public override void Add(FrameInfo item)
{
if(_isRunning)
{
SendToPipe(item.Bitmap);
}
}
}

https://trac.ffmpeg.org/wiki/Slideshow
https://ffmpeg.org/ffmpeg.html#filter_005foption
https://stackoverflow.com/questions/60977555/adding-current-time-as-timestamp-in-h-264-raw-stream-with-few-frames
————————————————
版权声明:本文为CSDN博主「JimCarter」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/catshitone/article/details/126930470

【C#】使用ffmpeg image2pipe将图片保存为mp4视频的更多相关文章

  1. 使用ffmpeg将BMP图片编码为x264视频文件,将H264视频保存为BMP图片,yuv视频文件保存为图片的代码

    ffmpeg开源库,实现将bmp格式的图片编码成x264文件,并将编码好的H264文件解码保存为BMP文件. 实现将视频文件yuv格式保存的图片格式的測试,图像格式png,jpg, gif等等測试均O ...

  2. FFMPEG,将字幕“烧进”MP4视频中

    原文地址:http://blog.csdn.net/ufocode/article/details/75475539 由于mp4容器,不像MKV等容器有自己的字幕流. MKV这种容器的视频格式中,会带 ...

  3. FFmpeg解码视频帧为jpg图片保存到本地

    FFmpeg解码视频帧为jpg图片保存到本地 - CSDN博客 https://blog.csdn.net/qq_28284547/article/details/78151635

  4. ffmpeg 推送、保存rtmp 流命令

    1.将文件当做直播送至live ffmpeg -re -i localFile.mp4 -c copy -f flv rtmp://server/live/streamName 2.将直播媒体保存至本 ...

  5. php 获取远程图片保存到本地

    php 获取远程图片保存到本地 使用两个函数 1.获取远程文件 2.把图片保存到本地 /** * 获取远程图片并把它保存到本地 * $url 是远程图片的完整URL地址,不能为空. */ functi ...

  6. 用qt代码怎样编写图片保存格式[qt4.6]

    用qt代码怎样编写图片保存格式 qt提供了多个保存图片的接口,比较常用的接口如下 bool QPixmap::save ( const QString & fileName, const ch ...

  7. iOS 将图片保存到本地

    //将图片保存到本地 + (void)SaveImageToLocal:(UIImage*)image Keys:(NSString*)key {     NSUserDefaults* prefer ...

  8. C# 图片保存到数据库和从数据库读取图片并显示

    图片保存到数据库的方法: public void imgToDB(string sql)        {   //参数sql中要求保存的imge变量名称为@images            //调 ...

  9. file_put_contents() 图片保存 函数成功之后返回值

    今天弄图片保存时,用到file_put_contents()来保存图片,运行了几次,发下一直没有数据出来,以为是这个函数没操作成功 于是查看了下这个函数的用法和返回值,发现我输出的返回都正确,后来才发 ...

  10. iOS9中将图片保存到照片中的某个相册的方法说明

    iOS9中将图片保存到照片中的某个相册的方法说明 在App中很经常遇到的就是用户点击某张图片后将图片保存到本地,下面介绍下iOS中保存图片的一些东西 1.首先,在iOS中把图片保存到系统照片是比较简单 ...

随机推荐

  1. 视频播放测试地址(MP4、M3U8 格式)

    最近在开发视频播放相关的业务功能,开发测试时,需要涉及到 MP4.M3U8 等视频格式. 我每次找测试视频地址时,都要找很久,现在把我在网上收集到的 MP4.M3U8 格式视频地址放在这里,希望帮助到 ...

  2. 国内十大活跃报表 BI 产品深度点评

    目前国内市场上的报表 BI 工具琳琅满目,看起来也各有特点,这给选型工作带来了一些困扰,本文就一些较活跃的报表 BI 产品进行点评,对于不太熟悉这些产品和技术的同学,可作为参考资料. 这里选了十个产品 ...

  3. 力扣1662(java&python)-检查两个字符串数组是否相等(简单)

    题目: 给你两个字符串数组 word1 和 word2 .如果两个数组表示的字符串相同,返回 true :否则,返回 false . 数组表示的字符串 是由数组中的所有元素 按顺序 连接形成的字符串. ...

  4. EasyNLP中文文图生成模型带你秒变艺术家

    简介: 我们在EasyNLP框架中集成了中文文图生成功能,同时开放了模型的Checkpoint. 导读 宣物莫大于言,存形莫善于画. --[晋]陆机 多模态数据(文本.图像.声音)是人类认识.理解和表 ...

  5. 阿里巴巴 DevOps 工具体系

    ​简介: 随着阿里巴巴多元化业务 20 多年的高速发展,技术体系经历了 web 时代.移动化时代.数据智能时代.云计算时代等多个重大变革.在这些变革中,开发者面对的技术体系.工具体系.知识体系也在不断 ...

  6. [GPT] php查询mongo,触发了 operation exceeded time limit

      "operation exceeded time limit"错误通常意味着查询所需的时间超过了MongoDB实例配置的操作超时限制. 这可以是由于查询需要处理大量数据或没有正 ...

  7. [FE] Js DOM 操作的几个常见错误

    1.setTimeout 匿名函数传参问题,匿名函数形参是不能直接在内部使用的,匿名函数传参需要按顺序从 setTimeout 的第三个参数开始依次传递. 2. Js clone出来的 dom 节点, ...

  8. [TP5] 动态绑定指定默认模块, 解决: 控制器不存在:app\index\controller\Api

    当在 TP5 入口中简单使用 define('BIND_MODULE','index') 绑定默认模块后,访问 api 模块会提示: 控制器不存在:app\index\controller\Api 这 ...

  9. IIncrementalGenerator 判断程序集的引用关系

    本文将告诉大家如何在 IIncrementalGenerator 增量 Source Generator 生成代码里面,在 Roslyn 分析器里面判断两个程序集是否存在引用关系 先上核心代码实现,核 ...

  10. JS代码优化小技巧

    下面介绍一种JS代码优化的一个小技巧,通过动态加载引入js外部文件来提高网页加载速度 [基本优化] 将所有需要的<script>标签都放在</body>之前,确保脚本执行之前完 ...