【问题标题】:Non monotonically increasing dts to muxer in stream非单调增加 dts 到流中的复用器
【发布时间】:2018-08-14 16:00:55
【问题描述】:

我只是想从缓冲区中保存相同的视频帧,在那里我正确保存了帧的位图帧和时间戳。

writer1 = new VideoFileWriter();
this.writer1.Width = this.videoSourceEndo.VideoResolution.FrameSize.Width;
this.writer1.Height = this.videoSourceEndo.VideoResolution.FrameSize.Height;
this.writer1.VideoCodec = VideoCodec.H264;
this.writer1.BitRate = (this.videoSourceEndo.VideoResolution.FrameSize.Height * this.videoSourceEndo.VideoResolution.FrameSize.Width * 30);

this.writer1.VideoOptions["preset"] = "superfast";
this.writer1.VideoOptions["tune"] = "zerolatency";

writer1.Open("test_HDMI.mp4");

(...)

writer1.WriteVideoFrame(endoFrameBuffer[endoFrameBuffer.Tail],endoFrameBuffer.getframetime(endoFrameBuffer.Tail));

但在视觉工作室(不是第一帧)我得到这个错误: Accord.Video.VideoException: '写入视频帧时出错。错误 -22:参数无效。有关详细信息,请参阅控制台输出。'

在控制台上: 应用程序在流 0 中向复用器提供了无效的、非单调递增的 dts:512 >= 512

我不知道这是什么原因,因为在调试时所有值似乎都是正确的。 (如果您需要更多代码,请告诉我)

【问题讨论】:

  • 我假设您正确设置了编解码器/流time_base(我在这里看不到)。所以你的问题就在这里endoFrameBuffer.getframetime(endoFrameBuffer.Tail)让我们看看代码
  • endoFrameBuffer 只是一个带有位图图像和正确时间跨度的 RingBuffer :public TimeSpan getframetime(int index) { return _timeBuffer[index]; }
  • 设置值我只是添加一个新元素,如下所示:endoFrameBuffer.Enqueue(eventArgs.Frame,DateTime.Now - _firstFrameTime.Value); 当 newframe 事件被触发时。然后在另一个线程上,我只是从 RingBuffer 记录每一帧。
  • 我直接问你,fps那个视频流是什么(因为pts=512对我来说很不寻常)。 getFrameTime 方法是否返回 pts 值?。
  • 视频流大约是 aprox。 30 帧/秒。 getFrameTime 返回 TimeSpan(帧与接收到的第一帧之间的时间差)

标签: c# ffmpeg accord.net


【解决方案1】:

好的,我会放在这里。 第一件事 VideoStream->time_base: 1/15360 来自哪里,这应该是 30fps 的 1000/30000 或 29.97 fps 的 1001/30000。

第二个问题是您的 pts/dts 和帧持续时间计算。如您所见,最后两个 pts/dts 值相同。

对于数据包持续时间(我假设 fps 通常应该是恒定的),请使用这些预先计算的值(或作为参考检查您的值):

fps     duration (same unit as AVPacket::duration)
23.98   2086
24.00   2000
25.00   2000
29.97   2068
30.00   2000
50.00   1000
59.94   1016
60.00   1000

至于手动计算pts/dts: 这是我使用的 C++ 函数:

static void write_video_pts(EncoderContext *ectx, AVPacket *pkt)
{
    pkt->pts          = ectx->video_pts; /* this is to keep next pts value, same unit as AVPacket::pts */
    ectx->video_pts  += ectx->frame_duration; /* check above table for ectx->frame_duration value */
    pkt->dts          = pkt->pts;
    pkt->duration     = ectx->frame_duration; /* check above table for ectx->frame_duration value */
    pkt->stream_index = ectx->VideoStream->index; /* AVStream */
}

当从 RAW 源手动编码时,这些绝对有效,比如你的。当然不是为了转码。

希望对您有所帮助。

【讨论】:

  • 我不明白为什么会这样。使用 Accord 框架,link 我只需要传递这些值,它们看起来是正确的......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-09-18
  • 1970-01-01
  • 2018-07-19
  • 1970-01-01
  • 1970-01-01
  • 2011-07-11
  • 1970-01-01
相关资源
最近更新 更多