2009-02-15, 23:30
As a personal experiment, I've tried to solve this and I've come a long way, but because I'm not an expert on the xbmc code I can't implement it properly (yet).
The problem:
Videocards and soundcards have their own clock, which is always slightly different from the system clock, so if the display's refreshrate is set at 60 hertz, compared to the system clock it might be 60.01 hertz or 59.99 hertz.
Video output in xbmc is synchronized to the system clock (which is periodically synced by the audio clock as far as I can tell) and it tries to reproduce the source framerate as good as it can.
This means that, if you have a 60 hertz display and play a 29.97 fps movie, some frames will be shown longer or shorter than needed, to keep the video in sync with the audio, this is what causes the jerky playback.
The solution:
Xbmc should determine how many times a frame should be shown, and show it exactly that many times. If the display is 60 hertz and a 29.97 fps movie is being played, the optimal situation is that every frame is showed exactly twice, causing the movie to be played at 30 fps.
If a 23.976 fps movie is played, every first frame should be shown two times and every second frame should be shown three times, causing the movie to be played at 24 fps.
The audio thread should check how far off sync it is, and resample the audio so it will play faster/slower to keep the audio in sync with the video.
What I have done:
The video thread determines how many times a frame should be shown, it then does the required number of calls to g_renderManager.FlipPage (thanks to elupus for the tip).
After that, the clock is updated to the pts of the frame.
The audio thread doesn't sync the clock anymore, instead it resamples the audio (using libsamplerate) to stay in sync, using a simple proportional algorithm with an offset correction (measure the average error for one second, if it's more than 10 ms out of sync, correct it and let it stabilize for three seconds).
There are some problems with it, fast-forwarding doesn't really work and on some xvid movies the clock seems to stop when black frames are showed.
Also, if decoding a frame takes longer than the time between two vsync interrupts, the movie slows down and things start to sound like a broken record player.
Overall I'm quite happy with it, and I'm sure these issues can be solved.
The problem:
Videocards and soundcards have their own clock, which is always slightly different from the system clock, so if the display's refreshrate is set at 60 hertz, compared to the system clock it might be 60.01 hertz or 59.99 hertz.
Video output in xbmc is synchronized to the system clock (which is periodically synced by the audio clock as far as I can tell) and it tries to reproduce the source framerate as good as it can.
This means that, if you have a 60 hertz display and play a 29.97 fps movie, some frames will be shown longer or shorter than needed, to keep the video in sync with the audio, this is what causes the jerky playback.
The solution:
Xbmc should determine how many times a frame should be shown, and show it exactly that many times. If the display is 60 hertz and a 29.97 fps movie is being played, the optimal situation is that every frame is showed exactly twice, causing the movie to be played at 30 fps.
If a 23.976 fps movie is played, every first frame should be shown two times and every second frame should be shown three times, causing the movie to be played at 24 fps.
The audio thread should check how far off sync it is, and resample the audio so it will play faster/slower to keep the audio in sync with the video.
What I have done:
The video thread determines how many times a frame should be shown, it then does the required number of calls to g_renderManager.FlipPage (thanks to elupus for the tip).
After that, the clock is updated to the pts of the frame.
The audio thread doesn't sync the clock anymore, instead it resamples the audio (using libsamplerate) to stay in sync, using a simple proportional algorithm with an offset correction (measure the average error for one second, if it's more than 10 ms out of sync, correct it and let it stabilize for three seconds).
There are some problems with it, fast-forwarding doesn't really work and on some xvid movies the clock seems to stop when black frames are showed.
Also, if decoding a frame takes longer than the time between two vsync interrupts, the movie slows down and things start to sound like a broken record player.
Overall I'm quite happy with it, and I'm sure these issues can be solved.