summaryrefslogtreecommitdiff
path: root/src/rmd_timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rmd_timer.c')
-rw-r--r--src/rmd_timer.c65
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);
© All Rights Reserved