static void *cache_thread(void *arg) { struct priv *s = arg; mpthread_set_name("cache"); pthread_mutex_lock(&s->mutex); update_cached_controls(s); double last = mp_time_sec(); while (s->control != CACHE_CTRL_QUIT) { if (mp_time_sec() - last > CACHE_UPDATE_CONTROLS_TIME) { update_cached_controls(s); last = mp_time_sec(); } if (s->control > 0) { cache_execute_control(s); } else { cache_fill(s); } if (s->control == CACHE_CTRL_PING) { pthread_cond_signal(&s->wakeup); s->control = CACHE_CTRL_NONE; } if (s->idle && s->control == CACHE_CTRL_NONE) { struct timespec ts = mp_rel_time_to_timespec(CACHE_IDLE_SLEEP_TIME); pthread_cond_timedwait(&s->wakeup, &s->mutex, &ts); } } pthread_cond_signal(&s->wakeup); pthread_mutex_unlock(&s->mutex); MP_VERBOSE(s, "Cache exiting...\n"); return NULL; }
static void flip_page(struct vo *vo) { struct vo_priv *p = vo->priv; pthread_mutex_lock(&p->ctx->lock); while (p->ctx->queued_frames >= p->frame_queue_size) { switch (p->frame_drop_mode) { case FRAME_DROP_CLEAR: frame_queue_drop_all(p->ctx); break; case FRAME_DROP_POP: frame_queue_shrink(p->ctx, p->frame_queue_size - 1); break; case FRAME_DROP_BLOCK: ; struct timespec ts = mp_rel_time_to_timespec(0.2); if (p->ctx->frozen || pthread_cond_timedwait(&p->ctx->wakeup, &p->ctx->lock, &ts)) { frame_queue_drop_all(p->ctx); p->ctx->frozen = true; } break; } } frame_queue_push(p->ctx, p->ctx->waiting_frame); p->ctx->waiting_frame = NULL; update(p); pthread_mutex_unlock(&p->ctx->lock); }
// Used by the main thread to wakeup the cache thread, and to wait for the // cache thread. The cache mutex has to be locked when calling this function. // *retry_time should be set to 0 on the first call. static void cache_wakeup_and_wait(struct priv *s, double *retry_time) { double start = mp_time_sec(); if (*retry_time >= CACHE_WAIT_TIME) { MP_WARN(s, "Cache is not responding - slow/stuck network connection?\n"); *retry_time = -1; // do not warn again for this call } pthread_cond_signal(&s->wakeup); struct timespec ts = mp_rel_time_to_timespec(CACHE_WAIT_TIME); pthread_cond_timedwait(&s->wakeup, &s->mutex, &ts); if (*retry_time >= 0) *retry_time += mp_time_sec() - start; }
static void flip_page(struct vo *vo) { struct vo_priv *p = vo->priv; struct timespec ts = mp_rel_time_to_timespec(0.2); pthread_mutex_lock(&p->ctx->lock); // Wait until frame was rendered while (p->ctx->next_frame) { if (pthread_cond_timedwait(&p->ctx->wakeup, &p->ctx->lock, &ts)) { MP_VERBOSE(vo, "mpv_opengl_cb_draw() not being called or stuck.\n"); goto done; } } // Unblock mpv_opengl_cb_draw(). p->ctx->present_count += 1; pthread_cond_signal(&p->ctx->wakeup); if (p->ctx->redrawing) goto done; // do not block for redrawing // Wait until frame was presented while (p->ctx->expected_flip_count > p->ctx->flip_count) { // mpv_opengl_cb_report_flip() is declared as optional API. // Assume the user calls it consistently _if_ it's called at all. if (!p->ctx->flip_count) break; if (pthread_cond_timedwait(&p->ctx->wakeup, &p->ctx->lock, &ts)) { MP_VERBOSE(vo, "mpv_opengl_cb_report_flip() not being called.\n"); goto done; } } done: // Cleanup after the API user is not reacting, or is being unusually slow. if (p->ctx->next_frame) { talloc_free(p->ctx->next_frame); p->ctx->next_frame = NULL; p->ctx->present_count += 2; pthread_cond_signal(&p->ctx->wakeup); vo_increment_drop_count(vo, 1); } pthread_mutex_unlock(&p->ctx->lock); }