gpt4 book ai didi

c# - C#中的实时视频流

转载 作者:太空狗 更新时间:2023-10-29 19:46:59 26 4
gpt4 key购买 nike

我正在开发一个用于实时流式传输的应用程序。流媒体包括两个部分。我使用采集卡采集一些直播源,需要实时流式传输。并且还需要流式传输本地视频文件。

为了实时流式传输本地视频文件,我使用 emgu cv 将视频帧捕获为位图。为此,我创建了位图列表,并使用一个线程将捕获的位图保存到该列表中。我还在图片框中显示这些帧。位图列表可以存储 1 秒的视频。如果帧速率是30 它将存储 30 个视频帧。填充此列表后,我启动另一个线程来编码该 1 秒 block 视频。

出于编码目的,我使用名为 nreco 的 ffmpeg 包装器。我把那个视频帧写到 ffmpeg并启动 ffmpeg 进行编码。停止该任务后,我可以获得字节数组形式的编码数据。

然后我使用 UDP 协议(protocol)通过 LAN 发送该数据。

这很好用。但是我无法实现流畅的流式传输。当我通过 VLC 播放器接收流时,数据包之间有几毫秒的延迟,而且我还注意到有一个帧丢失了。

private Capture _capture = null;
Image<Bgr, Byte> frame;

// Here I capture the frames and store them in a list
private void ProcessFrame(object sender, EventArgs arg)
{
frame = _capture.QueryFrame();
frameBmp = new Bitmap((int)frameWidth, (int)frameHeight, PixelFormat.Format24bppRgb);
frameBmp = frame.ToBitmap();


twoSecondVideoBitmapFramesForEncode.Add(frameBmp);
////}
if (twoSecondVideoBitmapFramesForEncode.Count == (int)FrameRate)
{
isInitiate = false;
thread = new Thread(new ThreadStart(encodeTwoSecondVideo));
thread.IsBackground = true;
thread.Start();
}
}

public void encodeTwoSecondVideo()
{
List<Bitmap> copyOfTwoSecondVideo = new List<Bitmap>();
copyOfTwoSecondVideo = twoSecondVideoBitmapFramesForEncode.ToList();
twoSecondVideoBitmapFramesForEncode.Clear();

int g = (int)FrameRate * 2;

// create the ffmpeg task. these are the parameters i use for h264 encoding

string outPutFrameSize = frameWidth.ToString() + "x" + frameHeight.ToString();
//frame.ToBitmap().Save(msBit, frame.ToBitmap().RawFormat);
ms = new MemoryStream();
//Create video encoding task and set main parameters for the video encode

ffMpegTask = ffmpegConverter.ConvertLiveMedia(
Format.raw_video,
ms,
Format.h264,
new ConvertSettings()
{

CustomInputArgs = " -pix_fmt bgr24 -video_size " + frameWidth + "x" + frameHeight + " -framerate " + FrameRate + " ", // windows bitmap pixel format
CustomOutputArgs = " -threads 7 -preset ultrafast -profile:v baseline -level 3.0 -tune zerolatency -qp 0 -pix_fmt yuv420p -g " + g + " -keyint_min " + g + " -flags -global_header -sc_threshold 40 -qscale:v 1 -crf 25 -b:v 10000k -bufsize 20000k -s " + outPutFrameSize + " -r " + FrameRate + " -pass 1 -coder 1 -movflags frag_keyframe -movflags +faststart -c:a libfdk_aac -b:a 128k "
//VideoFrameSize = FrameSize.hd1080,
//VideoFrameRate = 30

});

////////ffMpegTask.Start();
ffMpegTask.Start();


// I get the 2 second chunk video bitmap from the list and write to the ffmpeg
foreach (var item in copyOfTwoSecondVideo)
{
id++;
byte[] buf = null;
BitmapData bd = null;
Bitmap frameBmp = null;

Thread.Sleep((int)(1000.5 / FrameRate));

bd = item.LockBits(new Rectangle(0, 0, item.Width, item.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
buf = new byte[bd.Stride * item.Height];
Marshal.Copy(bd.Scan0, buf, 0, buf.Length);
ffMpegTask.Write(buf, 0, buf.Length);
item.UnlockBits(bd);
}
}

这是我实现直播的过程。但流水并不顺畅。我尝试改用队列列表以减少填充列表的延迟。因为我认为延迟发生编码线程编码并非常快速地发送 2 秒视频。但是当它完成这个位图列表的编码过程时不全满。因此编码线程将停止,直到下一个 2 秒视频准备就绪。

如果哪位大侠能帮我解决一下,感激不尽。如果我这样做的方式是错误的,请纠正我。谢谢你!

最佳答案

很难对代码说些什么,因为您的片段没有提供整个过程的详细信息。

首先,您可以完全消除帧缓冲区(位图列表)。只需创建 1 个实时流编码进程(每 2 秒 block 创建一个新进程是非常糟糕的主意)并在位图出现时使用 Write 方法将其推送到 VideoConverter。由于您实时从捕获设备获取帧,因此您也不需要进行任何手动延迟( Thread.Sleep((int)(1000.5/FrameRate)) )。因此,您应该在 VLC 端获得流畅的视频(由于编码和网络传输,一些延迟 - 通常大约 200-500ms - 是不可避免的)。

如果您时不时地从捕获设备获取帧,您可以尝试“-re”FFMpeg 选项。

关于c# - C#中的实时视频流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24839558/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com