Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/262.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/video/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将视频渲染到可能具有不一致帧速率的文件_C#_Video_Aforge - Fatal编程技术网

C# 将视频渲染到可能具有不一致帧速率的文件

C# 将视频渲染到可能具有不一致帧速率的文件,c#,video,aforge,C#,Video,Aforge,我从一个源(可以被认为是一个黑匣子)获取原始视频帧的速率可能不一致。我正在试着把视频输入到磁盘上。我正在用一台福格的录像机这样做,并且正在向MP4文件写入数据 但是,我接收帧的速率不一致导致视频速度加快。似乎我只能创建具有固定帧速率的视频文件,即使源没有固定帧速率 这在渲染到屏幕时不是问题,因为我们可以尽可能快地渲染。写入文件时我不能这样做,因为回放文件将以固定的帧速率播放 有什么解决办法?输出不必是相同的视频格式,只要以后有合理的转换方法(不必是实时的)。视频提要可能很长,所以我不能将所有内容

我从一个源(可以被认为是一个黑匣子)获取原始视频帧的速率可能不一致。我正在试着把视频输入到磁盘上。我正在用一台福格的
录像机
这样做,并且正在向MP4文件写入数据

但是,我接收帧的速率不一致导致视频速度加快。似乎我只能创建具有固定帧速率的视频文件,即使源没有固定帧速率

这在渲染到屏幕时不是问题,因为我们可以尽可能快地渲染。写入文件时我不能这样做,因为回放文件将以固定的帧速率播放

有什么解决办法?输出不必是相同的视频格式,只要以后有合理的转换方法(不必是实时的)。视频提要可能很长,所以我不能将所有内容都存储在内存中,以后再进行编码

我的代码目前大致如下:

VideoFileWriter writer = new VideoFileWriter();
Stopwatch stopwatch = new Stopwatch();

public override void Start() {
    writer.Open("output.mp4", videoWidth, videoHeight, frameRate, AForge.Video.FFMPEG.VideoCodec.MPEG4);
    stopwatch.Start();
}

public override void End() {
    writer.Close();
}

public override void Draw(Frame frame) {
    double elapsedTimeInSeconds = stopwatch.ElapsedTicks / (double) Stopwatch.Frequency;
    double timeBetweenFramesInSeconds = 1.0 / FrameRate;
    if (elapsedTimeInSeconds >= timeBetweenFramesInSeconds) {
        stopwatch.Restart();
        writer.WriteVideoFrame(frame.ToBitmap());
    }
}

其中,我们的黑框调用
开始
结束
、和
绘制
方法。我在
Draw
中的当前检查可以防止我们绘制得太快,但无法处理绘制得太慢的情况。

结果是
WriteVideoFrame
过载,函数的一个变体是。正如您所猜测的,时间戳用于使帧在视频中的特定时间出现

因此,通过跟踪实时,我们可以将每一帧设置为使用它应该在视频中的时间。当然,如果渲染速度不够快,视频质量会更差,但这解决了当前的问题

以下是我用于
Draw
函数的代码:

// We can provide a frame offset so that each frame has a time that it's supposed to be
// seen at. This ensures that the video looks correct if the render rate is lower than
// the frame rate, since these times will be used (it'll be choppy, but at least it'll
// be paced correctly -- necessary so that sound won't go out of sync).
long currentTick = DateTime.Now.Ticks;
StartTick = StartTick ?? currentTick;
var frameOffset = new TimeSpan(currentTick - StartTick.Value);

// Figure out if we need to render this frame to the file (ie, has enough time passed
// that this frame will be in the file?). This prevents us from going over the
// desired frame rate and improves performance (assuming that we can go over the frame
// rate).
double elapsedTimeInSeconds = stopwatch.ElapsedTicks / (double) Stopwatch.Frequency;
double timeBetweenFramesInSeconds = 1.0 / FrameRate;
if (elapsedTimeInSeconds >= timeBetweenFramesInSeconds)
{
    stopwatch.Restart();

    Writer.WriteVideoFrame(frame.ToBitmap(), frameOffset);
}

其中
StartTick
是对象的
long?
成员。

我也遇到了这个问题。在我的例子中,我正在用一个RGE模拟闭路电视系统。中央电视台在录制的时间上应该是准确的,所以我在这方面面临着一个很大的困境。这是我在这本书中使用的作品

首先,声明一个Timespan,它将作为录制的基础。您需要在开始录制时设置此选项。该值是您开始录制的时间。为了得到这个答案,我们将其称为
tmspartrecording

然后在捕获设备的新帧事件中:

var currentTime = DateTime.Now.TimeOfDay;
// this will get the elapse time between
// the current time from the time you start your recording
TimeSpan elapse = currentTime - tmspStartRecording;
writer.WriteVideoFrame((Bitmap)image.Clone(),elapse);

别忘了设置开始时间跨度的值,好吗?

如果您使用的是高帧率-
秒表-
它可能值得使用,而不是
DateTime
减法。除了我(当时出于任何原因)之外,这与我使用的几乎相同通过从
DateTime中减去刻度来获得时间跨度。现在
而不是直接减去刻度(这会导致
时间跨度
。虽然我很确定您不能使用
时间跨度
。如果您的录制时间超过午夜,则会失败。应该只使用
日期时间。现在
。我只使用25 fps,即使我的网络摄像头可以处理。应用程序无法足够快地处理该帧。在我的情况下,我会强制使用在午夜时重置保存,然后初始化一个新的。增加一个RGE的帧进程的一个好方法是为编写器创建一个新的单独线程。