[mythtv] Re: [mythtv-commits] mythtv commits

Bruce Markey bjm at lvcm.com
Tue Aug 24 22:32:05 EDT 2004


Doug, I hope I didn't sound like I was arguing for argument's
sake. If so, I apologize. I want the code to work correctly
and honestly believe that the cause of the problem you see
can not be as you've describe. I'll explain below. I'll keep
an open mind about what you have to say and I hope you can
do the same so we can figure out what really needs to happen
and do the right thing.

Doug Larrick wrote:
> Bruce Markey wrote:
> 
>> Nexttrigger should normally be incremented by exactly one frame
>> interval and mark out the cadence of the frames. However, as
>> you know, audio and video can drift so it is adjusted plus or
>> minus one refreshrate which you pass as avsync_adjustment when
>> necessary. Nothing else should really be fudging that cadence
>> so that nexttrigger reflects the steady pace within a frame or
>> so of matching the video exactly with the audio.
> 
> 
> What you're ignoring in the above description is that the refresh rate 
> of the display is often not exactly equal to the frame rate of the 
> video, due to inaccuracy in modeline, driver or hardware limitations, or 
> (mis)configuration (such as running a 29.97 Hz video on a 60 or (worse) 
> 75 Hz desktop system).

Here's something we can agree on: I am ignoring the refresh rate 
of the display. That's the point of the description. I am aware
that the refresh rate of the display can be different and I know
that each of the timing methods need to do the right things for the
right reasons when the refresh rate of the monitor is different
than the NTSC 29.97fps of the recording.

Something needs to keep track of when the frames of the recorded
file ought to be played to honor the timing of the frames at the
time they were recorded. If frame 100 should have been played at
this time, frame 101 should be played one frame interval later.
Frame 102 another frame interval after that. This is what the
nexttrigger is for. It keeps track of the manufacturer's suggested
retail time for the next frame to be played. This is a suggested
marker for the timing method to use as guidance and should keep
track of when the next recorded frame should be due regardless
of the timing method that ends up using this information. For
no refresh info methods, ASAP after nexttrigger. With refresh
info, on the next refresh after nexttrigger.

> When this happens, the delay as measured by KeepPhase will creep in one 
> direction or the other.  If it happens to creep upwards (toward 0), the 
> errors will accumulate and the calculated delay will drift until it hits 
> the limit you left in.  If it happens to creep downwards, it will 
> eventually overflow one video refresh interval and we'll have a 
> one-refresh hiccup that looks like an a/v sync correction (i.e. all but 
> invisible).  Well, almost.  With HDTV-sized frames, the display starts 
> to look crappy as this value approaches an entire refresh interval in 
> magnitude.  My theory is that we're not giving the card enough time to 
> process the frame in between sending it the data and telling it to show.

I see. I'd be interested to know a little more about what this
crappy display looks like. Do you mean multiple stutters clumped
together or frames tearing or something else?

I certainly believe that you see a problem and I do want that
problem to be fixed (actually, I want MythTV to be the best
possible DVR in every way =). I understand your theory that
the card may not be given enough time to process the frame before
Show is called. However, I don't believe the time distance from
nexttrigger to the next (or previous) refresh can cause this to
happen. Here's why.

Stating near the end of the loop, WaitForFrame has returned
indicating that it's found a refresh after delay is less than
zero.

(A) Show is called to display the prepared frame.

(B) The video timecode is checked against lastaudiotime ASAP to
see if they are out of sync and determine if an adjustment needs
to be made.

(C) Back to the OutputVideoLoop to go the next time around. It
may do some housekeeping then calls AVSync which prepares the next
frame to be displayed. As soon as the frame is ready, it drops
into WaitForFrame.

(D) Assuming a refresh based method, if delay isn't less than
zero already, it start a loop waiting for a refresh that returns
after m_delay is no longer greater than zero.

(E) Returned from waiting for refresh. Is delay greater than zero?
Yes, keep waiting. [This step may happen 0, 1, 2 or more times
before the next step. Normally once for TV-out. Normally once or
twice for a higher refresh rate monitor]

(F) Returned from waiting for refresh. Is delay greater than zero?
No, update nexttrigger and fall through so that Show will be
called as in (A).


Steps (A) thru (D) happen as soon as possible after the previous
frame was shown. This happens in a fraction of a frame interval.
It must because 'bob' wouldn't work unless these steps always
finish in less than half of a frame interval. During playback,
this is all the work that mythfrontend is doing. It normally takes
up, say, 10% of the CPU time. So for example, these steps are all
normally done within the first 20% of the frame interval. The
other 80% is waiting until nexttrigger and calling Show soon
thereafter.

Nothing in steps (A) up until (D) know anything about nexttrigger.
They are unaffected. Where the nexttrigger suggested time is
located doesn't come into play until (E) and (F).

In (E) we haven't reached the target time yet. In (F) the target
time has past. Say the refresh interval is 16666usec (and assume
for the example that we hit it exactly each time =). The exact
same events happen the same way if delay is 1001 at (E) and
-15665 at (F) or if they are 15665 at (E) and -1001 at (F).
It doesn't matter where nexttrigger is between two refreshes.
It only affects the bool for "while (m_delay > 0)".

Nexttrigger does not affect when PrepareFrame is run or how
much time it is alloted to run nor does it cause Show to be
called immediately after PrepareFrame nor does it constrain
how much time Show has to complete. Therefore, I don't think
your theory adds up as stated but there are a couple other
possibilities.

If the problem is that the frame is torn or has garbage or
is damaged in some way, it may be that PrepareFrame is returning
before it is actually ready for Show to be called. This might
come into play if delay is already negative when WaitForFrame
is called. This might happen if the previous frame was 'late'
because the CPU was busy with other processes. In that case
Show would be called right after PrepareFrame. The fix would
be to add something to make sure some minimum time had passed
between PrepareFrame and Show. However, this could happen at
any time and wouldn't necessarily be related to nexttrigger.

Or is the problem a cluster of stutters? You said it happens
when this value approaches an entire refresh interval. Far away
one refresh is the same as close to another. If the value is
-16650 when the loop falls through, on the previous refresh it
was 16 (plus or minus inaccuracies). If so, this may be a
form of the straddle problem that is not being handled correctly.

If the delay values after it fell through were: -16644, -16661,
-16638, -16647, ... no problem so far ... -16658, -1, ...opps...
-16649, -11, -23, -16644, -16644. This would be the straddle
problem. It's so close to zero on the previous refresh that it
sometimes goes over the edge and some frames are drawn one
refresh earlier than the others around them. However, this
shouldn't happen because of KeepPhase. It doesn't matter which
side it is drifting from, nexttrigger is moved the first time
something falls between 0 and -1000. In this case, -1.

> I have instrumented the code in the past to demonstrate this effect to 
> my satisfaction; unfortunately I have not kept this instrumentation code 
> up to date with the current reimplementation.  I have a feeling I will 
> need to redo this work in order to convince you, but my notes and 
> conclusions from before were quite clear.  The effect was also worse on 
> an nVidia MX440 (slower) than on an FX5200.

Ya, I would be interested in what you found and how it relates to
the steps (A)-(F) from above. I just can't see how the position
of nexttrigger would affect the data that is being move around
on the card so I would like to know what this is about.

> Actually, for the reason I gave above, it *does* matter.  At least for 
> HDTV-sized frames, if m_delay is too small (nearer to the -15500 end),

So I think this is the misunderstanding. This says that it is
refresh time right now. Myth's internal variable's time came
and went 15500usec ago. I assume that this statement assumes
that something on the card needs to be completed by -16666 which
is 1166usec later and that 1166 isn't enough time to do something?
If so, not to worry, that isn't true. Show gets called and the
card does it's thing and knows nothing about, or is in any way
constrained by myth's internal variable to track the frame intervals.

BTW, if m_delay were to be calculated at this point in time (which
it won't be) it would be 33366 - 15500 = 17866. Steps (A)-(D) will
happen ASAP. Delay will again be ~1166 at (E) and ~-15500 at (F).
There will be two full refresh cycles between frames to show the
last frame and to prepare the next.

> the card doesn't output video properly as I described above.  The code 
> you removed was simply keeping this value between -1000 and (roughly) 
> -8000 rather than -15500.

Right, I knew that and that's why I took it out. It doesn't
need to be penned into a range. This was forcing it to be
tugged along with the refresh timing. However, nexttrigger
should solely reflect the frame intervals and avsync and the
frame timing should adjust to it and not the other way around.
It's my bad that the straddle fix gave the impression that it
should be otherwise.

With a display that has a different refresh rate, the delay
values are different for each frame. There is a ~1/33 chance
that it could fall into the straddle fix DMZ and be shifted
by about 1/16th of a frame. The other adjustment would apply
to about half the frames. Nexttrigger would be batted around
constantly for no good reason.

The other thing is that it was checking for anything beyond
(roughly) -8000. Frames often are late primarily becase the
CPU may be busy servicing other processes. Most glitches are
a result of kernel scheduler events rather than adjustment
or errors in the calculating the target time. This other
check would shift nexttrigger every time there was a frame
late by more than 8000 even though most late frames are not
related to a sync timing issue.

>   The same amount of a/v divergence occurs 
> either way, it's just a matter of when it gets corrected, and by what 
> code.  Either the vsync code skips a tooth and inserts a hiccup, or the 
> A/V sync code notices the out-of-sync condition and takes its own 
> corrective action.

Right. I couldn't agree with you more.

With that I'll stop at a point where we agree in the beginning
and at the end =).

--  bjm



More information about the mythtv-dev mailing list