diff options
Diffstat (limited to 'src/rmd_timer.c')
-rw-r--r-- | src/rmd_timer.c | 65 |
1 files changed, 59 insertions, 6 deletions
diff --git a/src/rmd_timer.c b/src/rmd_timer.c index ff9d068..be757a6 100644 --- a/src/rmd_timer.c +++ b/src/rmd_timer.c @@ -39,15 +39,65 @@ #include <unistd.h> -void *rmdTimer(ProgData *pdata){ - struct timespec delay; +static struct timespec us_to_timespec(unsigned int us) +{ + return (struct timespec){ + .tv_sec = us / 1000000, + .tv_nsec = (us % 1000000) * 1000, + }; +} - rmdThreadsSetName("rmdTimer"); +static void sync_streams(ProgData *pdata, unsigned int *frame_step, struct timespec *delay) { + int avd; + + pthread_mutex_lock(&pdata->avd_mutex); + avd = pdata->avd; + pthread_mutex_unlock(&pdata->avd_mutex); + + /* There are two knobs available for keeping the video synchronized with the audio: + * 1. frame_step; how many frames to encode from this frame (aka dropping frames if > 1) + * 2. delay; how long to delay the next get_frame + * + * When avd is negative, we need more video relative to audio. That can be achieved + * by either sleeping less between frames, or dropping them by having the encoder + * encode a given frame multiple times. + * + * When avd is positive, we need more audio relative to video, so less video. This + * can be achieved by sleeping more between frames. + */ + + if (avd < 0) { + int frames_behind = -avd / pdata->frametime; + + if (frames_behind > 0) { + /* more than a whole frame behind, drop frames to catch up */ + *frame_step += frames_behind; + } else { + /* less than a whole frame behind, just sleep less */ + *delay = us_to_timespec(pdata->frametime + avd); + } - delay.tv_sec = 1.f / pdata->args.fps; - delay.tv_nsec = 1000000000.f / pdata->args.fps - delay.tv_sec * 1000000000.f; + } else if (avd > 0) { + /* sleep longer */ + *delay = us_to_timespec(pdata->frametime + avd); + } + +#if 0 + printf("avd: %i frame_step: %u delay: %lu,%lu\n", + avd, *frame_step, (*delay).tv_sec, (*delay).tv_nsec); +#endif +} + +void *rmdTimer(ProgData *pdata) { + + rmdThreadsSetName("rmdTimer"); while (pdata->timer_alive) { + struct timespec delay; + unsigned int frame_step = 1; + + delay.tv_sec = 1.f / pdata->args.fps; + delay.tv_nsec = 1000000000.f / pdata->args.fps - delay.tv_sec * 1000000000.f; pthread_mutex_lock(&pdata->pause_mutex); if (pdata->pause_state_changed) { @@ -71,8 +121,11 @@ void *rmdTimer(ProgData *pdata){ } else pthread_mutex_unlock(&pdata->pause_mutex); + if (!pdata->args.nosound) + sync_streams(pdata, &frame_step, &delay); + pthread_mutex_lock(&pdata->time_mutex); - pdata->time_frameno++; + pdata->time_frameno += frame_step; pthread_mutex_unlock(&pdata->time_mutex); pthread_cond_signal(&pdata->time_cond); |