这是一个很好的问题,而不是"告诉我代码是什么工作",而是"如何在逻辑上处理这种情况"问题.
简而言之,我通过RTSP从IP摄像机进入视频+音频.
视频和音频通过单独的线程(如下所示)逐帧解码并记录到单个mp4容器中.
问题是由于TimeSpan结束时间和每个视频帧的开始时间不精确,视频和音频会逐渐变得越来越不同步.
对于每个视频帧,它应该是1 /帧速率= 0.0333667000333667的持续时间,但它正在使用(即使使用FromTicks()方法),第一帧的开始时间= 0.0和结束时间0.0333667.
我可以调整29.97的视频解码器帧速率值(它从摄像机的设置声明的帧速率中拉出),导致视频在音频之前,或滞后于音频 - 这只是制作每个视频mediaBuffer.StartTime和mediaBuffer .EndTime要么太早,要么太晚,与音频相比.
随着时间的推移,微小的十进制截断最终导致视频和音频不同步 - 录制时间越长,两个轨道获得的同步越多.
我真的不明白为什么会这样,因为舍入误差在逻辑上不重要.
即使我只有1秒的精度,我每秒只会写一个视频帧,它在时间线上的位置大致应该是+ - 1秒,这应该使每个渐进帧相同+ - 1秒到达应有的位置,不会逐渐增加错位.我想象每个框架看起来都像这样:
[<-------- -1第二个-------->预期的确切帧时间<-------- + 1s -------->] --- -------------------------------------------------记录帧时间--------
我在这里错过了什么吗?
我没做"新帧开始时间=最后帧结束时间,新帧结束时间=新帧开始时间+ 1 /帧速率" - 我实际上在做"新帧开始时间=帧索引 - 1 /帧速率,新帧结束时间=帧索引/帧速率".
也就是说,我正在根据它们应该具有的预期时间来计算帧开始和结束时间(帧时间=帧位置/帧速率).
我的代码正在做的是:
预计时间----------预计时间----------预计时间帧时间帧时间
我在数学上理解这个问题,我只是不明白为什么十进制截断证明了这个问题,或者逻辑上知道解决它的最佳解决方案是什么.
如果我实现的内容是"每x帧,使用"(1 /帧速率)+一些"以弥补所有丢失的时间,那么可以将帧匹配到应该的位置,或者只是导致视频混乱?
public void AudioDecoderThreadProc()
{
TimeSpan current = TimeSpan.FromSeconds(0.0);
while (IsRunning)
{
RTPFrame nextFrame = jitter.FindCompleteFrame();
if (nextFrame == null)
{
System.Threading.Thread.Sleep(20);
continue;
}
while (nextFrame.PacketCount > 0 && IsRunning)
{
RTPPacket p = nextFrame.GetNextPacket();
if (sub.ti.MediaCapability.Codec == …Run Code Online (Sandbox Code Playgroud) 比较2个BitmapImage对象的最快方法是什么.一个是在Image Source属性中,另一个是我在代码中创建的.
我可以使用新的位图图像设置图像源,但它会导致闪烁,因为它会一遍又一遍地设置相同的图像.
我想只设置图像,如果它的像素与Image.Source中的像素不同.
编辑:
AlbumArt是视图中的图像(跟随MVVM).
一些代码(在视图代码后面运行):
Task.Factory.StartNew(() =>
{
while (((App)Application.Current).Running)
{
Thread.Sleep(1000);
Application.Current.Dispatcher.Invoke(new Action(() =>
{
if ((this.DataContext as AudioViewModel).CurrentDevice != null)
{
if ((((this.DataContext as AudioViewModel).CurrentDevice) as AUDIO).SupportsAlbumArt)
{
BitmapImage image = new BitmapImage();
image.BeginInit();
image.UriSource = new Uri((((this.DataContext as AudioViewModel).CurrentDevice) as AUDIO).AlbumArt);
image.CacheOption = BitmapCacheOption.None;
image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
image.EndInit();
AlbumArt.Source = image;
...
Run Code Online (Sandbox Code Playgroud) 我遇到一个InvalidOperationException,消息"调用线程必须是STA,因为许多UI组件都需要这个." 在WPF应用程序中,严重依赖于引用的库.
我试图确定错误的来源,使用各种线程和对象的调度程序,确保main()具有STAthread属性,尝试在看似相关的方法上设置"[STAThread]".
在MyParticipant构造函数中,正在构建MyVideoRenderer pic,它继承了VideoRenderer,VideoRenderer构造函数本身就抛出了这个异常,而没有进入构造函数.
码:
public class MyParticipant : Participant //inside MainWindow.xaml.cs
{
public enum PictureMode
{
Avatar,
Video
}
public PictureMode pictureMode = PictureMode.Avatar;
public ProgressBar voiceVolume;
public Label nameLabel;
public MyVideoRenderer pic;
public MyVideo video;
public bool isCachedInClient = false;
public string displayName = null;
public Image avatarImage = null;
public static int picHeight = 480;
public static int piclWidth = 640;
public static int panelHeight = 155;
public static int panelWidth = 174;
public static Color …Run Code Online (Sandbox Code Playgroud)