1

I'm just trying to save same frames on video from a buffer, where I properly saved the Bitmap Frame, and the Time Stamp, of the frame.

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));

But on visual studio (not on the first frame) I'm getting this error: Accord.Video.VideoException: 'Error while writing video frame. Error -22: Invalid argument. See console output for more details.'

And on console: Application provided invalid, non monotonically increasing dts to muxer in stream 0: 512 >= 512

I don't know the reason for that because on debug all values seems right. (Please let me know if you need more code)

Eduardo Preto
  • 21
  • 1
  • 1
  • 8
  • I'm assuming you set codec/stream `time_base`'s correctly (which I don't see here). So your problem lies here `endoFrameBuffer.getframetime(endoFrameBuffer.Tail)` let's see the code – the kamilz Mar 08 '18 at 07:46
  • endoFrameBuffer is just a RingBuffer with Bitmap Images and the proper timespan : `public TimeSpan getframetime(int index) { return _timeBuffer[index]; }` – Eduardo Preto Mar 08 '18 at 10:44
  • to set the values I just add a new element, like this: `endoFrameBuffer.Enqueue(eventArgs.Frame,DateTime.Now - _firstFrameTime.Value);` when the newframe event is fired. Then On the other thread I'm just recording each frame from the RingBuffer. – Eduardo Preto Mar 08 '18 at 10:51
  • Let me ask you directly, what `fps` is that video stream (because pts=512 is unusual to me). Is `getFrameTime` method returns `pts` value ?. – the kamilz Mar 08 '18 at 11:50
  • the video stream is about aprox. 30fps. getFrameTime return the TimeSpan (diference of time between the frame and the first frame received) – Eduardo Preto Mar 08 '18 at 12:06
  • Here it is the cmd print: https://imgur.com/IcuSJX4 – Eduardo Preto Mar 08 '18 at 12:13

1 Answers1

2

Ok, I'll put here. 1st thing where does VideoStream->time_base: 1/15360 comes from, this should be 1000/30000 for 30fps or 1001/30000 for 29.97 fps.

2nd something wrong with your pts/dts and frame duration calculation. As you see last two pts/dts values are same.

For packet duration (I'm assuming fps is constant as normally should) use these pre-calculated values (or check with yours as reference):

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

As for manually calculating pts/dts: this is my C++ function that I use:

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 */
}

These definitely works when manually encode from RAW source, like yours. Not for transcoding of course.

Hope that helps.

the kamilz
  • 1,860
  • 1
  • 15
  • 19
  • I can't understand why this is happening. Using Accord framework, [link](http://accord-framework.net/docs/html/M_Accord_Video_FFMPEG_VideoFileWriter_WriteVideoFrame_2.htm) I simply need to pass this values, and they seem right... – Eduardo Preto Mar 08 '18 at 17:27
  • If I wrote this code today, it would have been much different. For example, at a first glance, a better name for the function should be `set_video_pts` but this function does more than that. So I think I'd eventually be settled on `update_videopkt_props`. – the kamilz Dec 29 '22 at 07:25