C#队列怎么保存图片
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#队列怎么保存图片相关的知识,希望对你有一定的参考价值。
参考技术A /// <summary>/// 图片转二进制 /// </summary>
/// <param name="imgPhoto">图片对象</param>
/// <returns>二进制</returns>
public static byte[] PhotoImageInsert(System.Drawing.Image imgPhoto)
//将Image转换成流数据,并保存为byte[]
MemoryStream mstream = new MemoryStream();
imgPhoto.Save(mstream, System.Drawing.Imaging.ImageFormat.Jpeg); byte[] byData = new Byte[mstream.Length];
mstream.Position = 0;
mstream.Read(byData, 0, byData.Length);
mstream.Close(); return byData;
调用这个方法把普通转为2进制,并把它转成 Base64 形式的 System.String
string s = Convert.ToBase64String(PhotoImageInsert(PictureBox.Image))
转完之后,剩下的就是保存到数据库了,这个就是普通的Insert了,倒是要注意字段的长度
读取图片并显示出来:
如何读取的代码我就不写了,相信大家肯定是没问题的。
//字符串转二进制
byte[] imageBytes = Convert.FromBase64String(dt.Rows[0]["img_pic"].ToString());
MemoryStream ms = new MemoryStream(imageBytes);
Bitmap bmpt = new Bitmap(ms);
PictureBox.Image = bmpt; 参考技术B 内存队列,特点是快。但是我们不光是需要快,还要能支持并发的入队和出对。那么看起来ConcurrentQueue<T>似乎能满足我们的要求了,一方面性能还可以,另一方面内置支持了并发操作。但是有一点没满足,那就是我们希望当队列里没有消息的时候,队列的消费者不能让CPU空转,CPU空转会直接导致CPU占用100%,导致机器无法工作。幸运的是,.net中也有一个支持这种功能的集合,那就是:BlockingCollection<T>,这种集合能提供在队列内无元素的时候block当前线程的功能。我们可以用以下的方式来实例化一个队列:
private BlockingCollection<T> _queue = new BlockingCollection<T>(new ConcurrentQueue<T>());
并发入队的时候,我们只要写下面的代码即可:
_queue.Add(message);
并发出队的时候,只要:
_queue.Take();
我们不难看出,ConcurrentQueue<T>是提供了队列加并发访问的支持,而BlockingCollection<T>是在此基础上再增加blocking线程的功能。
是不是非常简单,经过测试,BlockingCollection<T>的性能已经非常好,每秒10万次入队出对肯定没问题,所以不必担心成为瓶颈。 参考技术C 用文件流把图片化为2进制保存到数据库
C#使用ffmpeg image2pipe将图片保存为mp4视频
文章目录
需求
在正式开始之前,先介绍下我的需求是怎么样的,基于此需求如何使用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
以下对各参数做个简单介绍:
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 maxBitRatek -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
以上是关于C#队列怎么保存图片的主要内容,如果未能解决你的问题,请参考以下文章