1
votes

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)

1
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 codethe kamilz
endoFrameBuffer is just a RingBuffer with Bitmap Images and the proper timespan : public TimeSpan getframetime(int index) { return _timeBuffer[index]; }Eduardo Preto
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
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
the video stream is about aprox. 30fps. getFrameTime return the TimeSpan (diference of time between the frame and the first frame received)Eduardo Preto

1 Answers

1
votes

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.