How can I deal with C # .NET TimeSpan Progressive rounding error when recording video frame by frame?

This is a neat problem, not "tell me which code works", but rather the question "how do I logically handle this situation."

In short, I have video + audio coming from an IP camera via RTSP.

Video and audio are decoded and recorded frame by frame in a single mp4 container in separate streams (shown below).

The problem is that video and audio are becoming more and more synchronized with time due to a lack of accuracy with the finite TimeSpan time and start time for each video frame.

There should be 1 / framerate = 0.0333667000333667 for each video frame, but it uses (even with the FromTicks () method), start time = 0.0 and end time 0.0333667 for the first frame.

I can adjust the frame rate of the video decoder from 29.97 (it pulls this from the camera settings declared as the frame rate), as a result of which either the video that precedes the sound or lags behind the sound is simply creating each video medium. StartTime and mediaBuffer.EndTime are too soon or too late compared to audio.

Over time, the miniature decimal truncation results in the video and audio not being synchronized - the longer the recording, the more synchronization of the two tracks fails.

I really don't understand why this is happening because the rounding error should not logically matter.

1 , , , + - 1 , + - 1 , , . , :

[< -------- -1 -------- > < -------- + 1s -------- > ] -------------------------------------------------- - --------

- ?

" = , = + 1/ " - " = - 1/ , = / ".

, ( = / ).

, :

---------- ----------

, , ​​ , .

-, " -, " (1/framerate) + ", , , , ?

    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 == Codec.G711A || sub.ti.MediaCapability.Codec == Codec.G711U)
                {
                    MediaBuffer<byte> mediaBuffer = new MediaBuffer<byte>(p.DataPointer, 0, (int)p.DataSize);
                    mediaBuffer.StartTime = current;
                    mediaBuffer.EndTime = current.Add(TimeSpan.FromSeconds((p.DataSize) / (double)audioDecoder.SampleRate));

                    current = mediaBuffer.EndTime;

                    if (SaveToFile == true)
                    {
                        WriteMp4Data(mediaBuffer);
                    }
                }
            }
        }
    }

    public void VideoDecoderThreadProc()
    {
        byte[] totalFrame = null;

        TimeSpan current = TimeSpan.FromSeconds(0.0);
        TimeSpan videoFrame = TimeSpan.FromTicks(3336670);
        long frameIndex = 1;

        while (IsRunning)
        {
            if (completedFrames.Count > 50)
            {
                System.Threading.Thread.Sleep(20);
                continue;
            }

            RTPFrame nextFrame = jitter.FindCompleteFrame();

            if (nextFrame == null)
            {
                System.Threading.Thread.Sleep(20);
                continue;
            }

            if (nextFrame.HasSequenceGaps == true)
            {
                continue;
            }

            totalFrame = new byte[nextFrame.TotalPayloadSize * 2];
            int offset = 0;

            while (nextFrame.PacketCount > 0)
            {
                byte[] fragFrame = nextFrame.GetAssembledFrame();

                if (fragFrame != null)
                {
                    fragFrame.CopyTo(totalFrame, offset);
                    offset += fragFrame.Length;
                }
            }

            MediaBuffer<byte> mediaBuffer = new MediaBuffer<byte>(
                totalFrame,
                0,
                offset,
                TimeSpan.FromTicks(Convert.ToInt64((frameIndex - 1) / mp4TrackInfo.Video.Framerate * 10000000)),
                TimeSpan.FromTicks(Convert.ToInt64(frameIndex / mp4TrackInfo.Video.Framerate * 10000000)));

            if (SaveToFile == true)
            {
                WriteMp4Data(mediaBuffer);
            }

            lock (completedFrames)
            {
                completedFrames.Add(mediaBuffer);
            }

            frameIndex++;
        }
    }
+5
2

, :

  • . , , //, . - , ..

  • .. , , . .

    , - directshow, , . , ns ms. . , .

    , , "timingFraction". , , ( Frame Time/NS_PS_MS). , ( ++ modf). ( , ) , . , , . , .

  • . , , 1 , . , . , , , . - , . , . , , , .

, , 100 , , , , 1. , , , .

, , . , . 1 33 , 2 - 34 , 67 . 70 , - . / .

, , . 10 , , . , 10 , . http://helpx.adobe.com/audition/kb/troubleshoot-recording-playback-monitoring-audition.html

,

10 - , .

10 - , .

11-20 - , , > .

20-30 - , > .

, .

+1

, , , .

1/ = 0,0333667000333667

, 29.97 . 29.97 - . 30 / 1.001 = 29.97002997002997 FPS. 1 / (30 / 1.001) = 0.0333666666666667 . , . "60i".

+1

All Articles