static int repaint(glw_gradient_t *gg, glw_root_t *gr, int tile, int w, int h, int tiles) { int x, y, n = showtime_get_ts(), m = 0; uint8_t *p, *pixmap; size_t s = h * w * GRAD_BPP; if(w < 1 || h < 1) return 0; p = pixmap = malloc(s); for(y = 0; y < h; y++) { float a = (float)y / (float)h; int r = 65280 * GLW_LERP(a, gg->gg_col1[0], gg->gg_col2[0]); int g = 65280 * GLW_LERP(a, gg->gg_col1[1], gg->gg_col2[1]); int b = 65280 * GLW_LERP(a, gg->gg_col1[2], gg->gg_col2[2]); for(x = 0; x < w; x++) { n = n * 1664525 + 1013904223; *p++ = (b + (n & 0xff)) >> 8; n = n * 1664525 + 1013904223; *p++ = (g + (n & 0xff)) >> 8; n = n * 1664525 + 1013904223; *p++ = (r + (n & 0xff)) >> 8; } n = n ^ m; m = m * 1664525 + 1013904223; } if(gg->gg_image_flags & GLW_IMAGE_BEVEL_TOP) bevel_top(pixmap, w, h); if(gg->gg_image_flags & GLW_IMAGE_BEVEL_BOTTOM) bevel_bottom(pixmap, w, h); glw_tex_upload(gr, &gg->gg_tex[0], pixmap, GLW_TEXTURE_FORMAT_RGB, w, h, GLW_TEX_REPEAT); if(tiles == 3) { p = malloc(s); memcpy(p, pixmap, s); if(gg->gg_image_flags & GLW_IMAGE_BEVEL_LEFT) bevel_left(p, w, h); glw_tex_upload(gr, &gg->gg_tex[1], p, GLW_TEXTURE_FORMAT_RGB, w, h, GLW_TEX_REPEAT); memcpy(p, pixmap, s); if(gg->gg_image_flags & GLW_IMAGE_BEVEL_RIGHT) bevel_right(p, w, h); glw_tex_upload(gr, &gg->gg_tex[2], p, GLW_TEXTURE_FORMAT_RGB, w, h, GLW_TEX_REPEAT); free(p); } free(pixmap); return 1; }
static void glw_freefloat_ctor(glw_t *w) { glw_freefloat_t *ff = (glw_freefloat_t *)w; ff->rand = showtime_get_ts(); ff->num_visible = GLW_FREEFLOAT_MAX_VISIBLE; }
static void current_media_playstatus(void *opaque, const char *str) { // Reset time to avoid risk of turning off as soon as track playback // has ended if UI has been idle last_activity = showtime_get_ts(); active_media = !!str; // If str is something then we're playing, paused, etc }
static int check_vsync(glw_x11_t *gx11) { int i; int64_t c; glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glXSwapBuffers(gx11->display, gx11->win); c = showtime_get_ts(); for(i = 0; i < 5; i++) { glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glXSwapBuffers(gx11->display, gx11->win); } c = showtime_get_ts() - c; return c > 25000; // Probably working }
static int bwlimit_read(fa_handle_t *handle, void *buf, size_t size) { bwlimit_t *s = (bwlimit_t *)handle; int64_t ts = showtime_get_ts(); int r = fa_read(s->s_src, buf, size); ts = showtime_get_ts() - ts; int64_t delay = s->s_spill + r * 1000000LL / s->s_bps - ts; if(delay > 0) { usleep(delay); s->s_spill = 0; } else { s->s_spill = ts; } return r; }
/** * Periodically check if we should auto standby */ static void check_autostandby(callout_t *c, void *aux) { int64_t idle = showtime_get_ts() - last_activity; idle /= (1000000 * 60); // Convert to minutes if(standby_delay && idle >= standby_delay && !active_media) { TRACE(TRACE_INFO, "runcontrol", "Automatic standby after %d minutes idle", standby_delay); showtime_shutdown(SHOWTIME_EXIT_STANDBY); return; } callout_arm(&autostandby_timer, check_autostandby, NULL, 1); }
static void setup_floater(glw_freefloat_t *ff, glw_t *c) { ff->xpos++; c->glw_parent_v = 0; c->glw_parent_s = 0.001; c->glw_parent_s2 = 0; c->glw_parent_a = showtime_get_ts(); c->glw_parent_x = -1.0 + (ff->xpos % ff->num_visible) * 2 / ((float)ff->num_visible - 1); ff->rand = ff->rand * 1664525 + 1013904223; c->glw_parent_y = (ff->rand & 0xffff) / 32768.0 - 1.0; }
static u32 playOneBlock(u64 *readIndex, float *dst, const audio_mode_t *am, const audio_buf_t *ab, sys_event_queue_t snd_queue, int channels) { u32 ret = 0; u64 current_block = *readIndex; int64_t pts; u32 audio_block_index = (current_block + 1) % AUDIO_BLOCK_8; sys_event_t event; ret = sys_event_queue_receive(snd_queue, &event, 20 * 1000); float *buf = dst + channels * AUDIO_BLOCK_SAMPLES * audio_block_index; if(ab == NULL) { fillBuffersilence(buf, channels); } else { if(ab->ab_isfloat) copy_buf_float(buf, ab, channels); else copy_buf_int16(buf, ab, channels); if((pts = ab->ab_pts) != AV_NOPTS_VALUE && ab->ab_mp != NULL) { pts += am->am_audio_delay * 1000; pts -= 1000000LL * (AUDIO_BLOCK_SAMPLES * AUDIO_BLOCK_8) / 48000; media_pipe_t *mp = ab->ab_mp; hts_mutex_lock(&mp->mp_clock_mutex); mp->mp_audio_clock = pts; mp->mp_audio_clock_realtime = showtime_get_ts(); mp->mp_audio_clock_epoch = ab->ab_epoch; hts_mutex_unlock(&mp->mp_clock_mutex); } } return 0; }
static void init_autostandby(void) { htsmsg_t *store = htsmsg_store_load("runcontrol"); if(store == NULL) store = htsmsg_create_map(); settings_create_int(settings_general, "autostandby", _p("Automatic standby"), 0, store, 0, 60, 5, set_autostandby, NULL, SETTINGS_INITIAL_UPDATE, " min", NULL, runcontrol_save_settings, NULL); last_activity = showtime_get_ts(); prop_subscribe(0, PROP_TAG_NAME("global", "media", "current", "playstatus"), PROP_TAG_CALLBACK_STRING, current_media_playstatus, NULL, NULL); callout_arm(&autostandby_timer, check_autostandby, NULL, 1); }
int glw_init(glw_root_t *gr, const char *instance) { char skinbuf[PATH_MAX]; const char *skin = gconf.skin; if(skin == NULL) { snprintf(skinbuf, sizeof(skinbuf), "%s/glwskins/"SHOWTIME_GLW_DEFAULT_SKIN, showtime_dataroot()); skin = skinbuf; } hts_mutex_init(&gr->gr_mutex); gr->gr_courier = prop_courier_create_passive(); gr->gr_token_pool = pool_create("glwtokens", sizeof(token_t), POOL_ZERO_MEM); gr->gr_clone_pool = pool_create("glwclone", sizeof(glw_clone_t), POOL_ZERO_MEM); gr->gr_skin = strdup(skin); gr->gr_vpaths[0] = "skin"; gr->gr_vpaths[1] = gr->gr_skin; gr->gr_vpaths[2] = NULL; gr->gr_font_domain = freetype_get_context(); glw_text_bitmap_init(gr); glw_init_settings(gr, instance); TAILQ_INIT(&gr->gr_destroyer_queue); glw_tex_init(gr); gr->gr_framerate = 60; gr->gr_frameduration = 1000000 / gr->gr_framerate; gr->gr_ui_start = showtime_get_ts(); return 0; }
int glw_init(glw_root_t *gr) { char skinbuf[PATH_MAX]; const char *skin = gconf.skin; if(gr->gr_prop_dispatcher == NULL) gr->gr_prop_dispatcher = &prop_courier_poll_timed; gr->gr_prop_maxtime = -1; assert(glw_settings.gs_settings != NULL); if(prop_set_parent(gr->gr_prop_ui, prop_get_global())) abort(); if(prop_set_parent(gr->gr_prop_nav, prop_get_global())) abort(); if(skin == NULL) { snprintf(skinbuf, sizeof(skinbuf), "%s/glwskins/"SHOWTIME_GLW_DEFAULT_SKIN, showtime_dataroot()); skin = skinbuf; } hts_mutex_init(&gr->gr_mutex); gr->gr_courier = prop_courier_create_passive(); gr->gr_token_pool = pool_create("glwtokens", sizeof(token_t), POOL_ZERO_MEM); gr->gr_clone_pool = pool_create("glwclone", sizeof(glw_clone_t), POOL_ZERO_MEM); gr->gr_skin = strdup(skin); gr->gr_vpaths[0] = "skin"; gr->gr_vpaths[1] = gr->gr_skin; gr->gr_vpaths[2] = NULL; gr->gr_font_domain = freetype_get_context(); glw_text_bitmap_init(gr); prop_setv(gr->gr_prop_ui, "skin", "path", NULL, PROP_SET_STRING, gr->gr_skin); gr->gr_pointer_visible = prop_create(gr->gr_prop_ui, "pointerVisible"); gr->gr_is_fullscreen = prop_create(gr->gr_prop_ui, "fullscreen"); gr->gr_screensaver_active = prop_create(gr->gr_prop_ui, "screensaverActive"); gr->gr_prop_width = prop_create(gr->gr_prop_ui, "width"); gr->gr_prop_height = prop_create(gr->gr_prop_ui, "height"); prop_set_int(gr->gr_screensaver_active, 0); gr->gr_evsub = prop_subscribe(0, PROP_TAG_CALLBACK, glw_eventsink, gr, PROP_TAG_NAME("ui", "eventSink"), PROP_TAG_ROOT, gr->gr_prop_ui, PROP_TAG_COURIER, gr->gr_courier, NULL); TAILQ_INIT(&gr->gr_destroyer_queue); glw_tex_init(gr); gr->gr_framerate = 60; gr->gr_frameduration = 1000000 / gr->gr_framerate; gr->gr_ui_start = showtime_get_ts(); gr->gr_open_osk = glw_osk_open; return 0; }
static void * ad_thread(void *aux) { audio_decoder_t *ad = aux; media_pipe_t *mp = ad->ad_mp; media_queue_t *mq = &mp->mp_audio; media_buf_t *mb; int hold = 0; int run = 1; int64_t silence_start_pts = AV_NOPTS_VALUE; uint64_t silence_start_realtime = 0; hts_mutex_lock(&mp->mp_mutex); while(run) { if((mb = TAILQ_FIRST(&mq->mq_q)) == NULL) { hts_cond_wait(&mq->mq_avail, &mp->mp_mutex); continue; } if(mb->mb_data_type == MB_AUDIO && hold && mb->mb_skip == 0) { hts_cond_wait(&mq->mq_avail, &mp->mp_mutex); continue; } TAILQ_REMOVE(&mq->mq_q, mb, mb_link); mq->mq_packets_current--; mp->mp_buffer_current -= mb->mb_size; mq_update_stats(mp, mq); hts_cond_signal(&mp->mp_backpressure); hts_mutex_unlock(&mp->mp_mutex); switch(mb->mb_data_type) { case MB_CTRL_EXIT: run = 0; break; case MB_CTRL_PAUSE: /* Copy back any pending audio in the output fifo */ audio_fifo_purge(thefifo, ad, &ad->ad_hold_queue); hold = 1; break; case MB_CTRL_PLAY: hold = 0; break; case MB_FLUSH: ad->ad_do_flush = 1; /* Flush any pending audio in the output fifo */ audio_fifo_purge(thefifo, ad, NULL); audio_decoder_flush(ad); break; case MB_AUDIO: if(mb->mb_skip != 0) break; if(mq->mq_stream == -1) { if(mb->mb_pts == AV_NOPTS_VALUE) break; if(silence_start_pts == AV_NOPTS_VALUE) { silence_start_pts = mb->mb_pts; silence_start_realtime = showtime_get_ts(); } else { int64_t d = mb->mb_pts - silence_start_pts; if(d > 0) { int64_t sleeptime = silence_start_realtime + d - showtime_get_ts(); if(sleeptime > 0) usleep(sleeptime); } } break; } if(mb->mb_stream != mq->mq_stream) break; ad_decode_buf(ad, mp, mq, mb); silence_start_pts = AV_NOPTS_VALUE; break; case MB_END: mp_set_current_time(mp, AV_NOPTS_VALUE); break; default: abort(); } hts_mutex_lock(&mp->mp_mutex); media_buf_free_locked(mp, mb); } hts_mutex_unlock(&mp->mp_mutex); audio_fifo_purge(thefifo, ad, NULL); return NULL; }
int64_t showtime_get_avtime(void) { return showtime_get_ts(); }
static void * ssdp_thread(void *aux) { struct sockaddr_in si = {0}; int fdm, fdu; int one = 1, r; int64_t next_send = 0; struct pollfd fds[2]; socklen_t sl = sizeof(struct sockaddr_in); struct ip_mreq imr; fdm = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); setsockopt(fdm, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int)); #if defined(SO_REUSEPORT) setsockopt(fdm, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(int)); #endif #if defined(IP_RECVDSTADDR) setsockopt(fdm, IPPROTO_IP, IP_RECVDSTADDR, &one, sizeof(int)); #endif si.sin_family = AF_INET; si.sin_port = htons(1900); if(bind(fdm, (struct sockaddr *)&si, sizeof(struct sockaddr_in)) == -1) { TRACE(TRACE_ERROR, "SSDP", "Unable to bind -- %s", strerror(errno)); return NULL; } memset(&imr, 0, sizeof(imr)); imr.imr_multiaddr.s_addr = htonl(0xeffffffa); // 239.255.255.250 if(setsockopt(fdm, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(struct ip_mreq)) == -1) { TRACE(TRACE_ERROR, "SSDP", "Unable to join 239.255.255.250: %s", strerror(errno)); return NULL; } fdu = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); #if defined(IP_RECVDSTADDR) setsockopt(fdu, IPPROTO_IP, IP_RECVDSTADDR, &one, sizeof(int)); #endif si.sin_family = AF_INET; si.sin_port = 0; if(bind(fdu, (struct sockaddr *)&si, sizeof(struct sockaddr_in)) == -1) { TRACE(TRACE_ERROR, "SSDP", "Unable to bind"); return NULL; } if(getsockname(fdu, (struct sockaddr *)&ssdp_selfaddr, &sl) == -1) { TRACE(TRACE_ERROR, "SSDP", "Unable to figure local port"); return NULL; } ssdp_fdm = fdm; ssdp_fdu = fdu; ssdp_send_static(fdu, SEARCHREQ); fds[0].fd = fdm; fds[0].events = POLLIN; fds[1].fd = fdu; fds[1].events = POLLIN; while(ssdp_run) { int64_t delta = next_send - showtime_get_ts(); if(delta <= 0) { delta = 15000000LL; next_send = showtime_get_ts() + delta; ssdp_send_notify("ssdp:alive"); } r = poll(fds, 2, (delta / 1000) + 1); if(r > 0 && fds[0].revents & POLLIN) ssdp_input(fdm, 1); if(r > 0 && fds[1].revents & POLLIN) ssdp_input(fdu, 0); } return NULL; }
static int pa_audio_start(audio_mode_t *am, audio_fifo_t *af) { pa_audio_mode_t *pam = (pa_audio_mode_t *)am; audio_buf_t *ab = NULL; size_t l, length; int64_t pts; media_pipe_t *mp; int r = 0; pa_threaded_mainloop_lock(mainloop); #if PA_API_VERSION >= 12 pa_proplist *pl = pa_proplist_new(); pa_proplist_sets(pl, PA_PROP_APPLICATION_ID, "com.lonelycoder.hts.showtime"); pa_proplist_sets(pl, PA_PROP_APPLICATION_NAME, "Showtime"); /* Create a new connection context */ pam->context = pa_context_new_with_proplist(api, "Showtime", pl); pa_proplist_free(pl); #else pam->context = pa_context_new(api, "Showtime"); #endif if(pam->context == NULL) { pa_threaded_mainloop_unlock(mainloop); return -1; } pa_context_set_state_callback(pam->context, context_state_callback, pam); /* Connect the context */ if(pa_context_connect(pam->context, NULL, 0, NULL) < 0) { TRACE(TRACE_ERROR, "PA", "pa_context_connect() failed: %s", pa_strerror(pa_context_errno(pam->context))); pa_threaded_mainloop_unlock(mainloop); return -1; } /* Need at least one packet of audio */ /* Subscribe to updates of master volume */ pam->sub_mvol = prop_subscribe(PROP_SUB_DIRECT_UPDATE, PROP_TAG_CALLBACK_FLOAT, set_mastervol, pam, PROP_TAG_ROOT, prop_mastervol, PROP_TAG_EXTERNAL_LOCK, mainloop, prop_pa_lockmgr, NULL); /* Subscribe to updates of master volume mute */ pam->sub_mute = prop_subscribe(PROP_SUB_DIRECT_UPDATE, PROP_TAG_CALLBACK_INT, set_mastermute, pam, PROP_TAG_ROOT, prop_mastermute, PROP_TAG_EXTERNAL_LOCK, mainloop, prop_pa_lockmgr, NULL); while(1) { if(ab == NULL) { pa_threaded_mainloop_unlock(mainloop); ab = af_deq2(af, 1, am); pa_threaded_mainloop_lock(mainloop); if(ab == AF_EXIT) { ab = NULL; break; } } if(pa_context_get_state(pam->context) == PA_CONTEXT_TERMINATED || pa_context_get_state(pam->context) == PA_CONTEXT_FAILED) { r = -1; break; } if(pam->stream != NULL && (pam->cur_format != ab->ab_format || pam->cur_rate != ab->ab_samplerate || pam->cur_isfloat != ab->ab_isfloat)) { stream_destroy(pam); } if(pam->stream == NULL && pa_context_get_state(pam->context) == PA_CONTEXT_READY) { /* Context is ready, but we don't have a stream yet, set it up */ stream_setup(pam, ab); } if(pam->stream == NULL) { pa_threaded_mainloop_wait(mainloop); continue; } switch(pa_stream_get_state(pam->stream)) { case PA_STREAM_UNCONNECTED: case PA_STREAM_CREATING: pa_threaded_mainloop_wait(mainloop); continue; case PA_STREAM_READY: break; case PA_STREAM_TERMINATED: case PA_STREAM_FAILED: pa_stream_unref(pam->stream); pam->stream = NULL; char msg[100]; snprintf(msg, sizeof(msg), "Audio stream disconnected from " "PulseAudio server -- %s.", pa_strerror(pam->stream_error)); mp_flush(ab->ab_mp, 0); mp_enqueue_event(ab->ab_mp, event_create_str(EVENT_INTERNAL_PAUSE, msg)); audio_fifo_purge(af, NULL, NULL); if(ab != NULL) { ab_free(ab); ab = NULL; } continue; } if(ab->ab_flush) { pa_operation *o; o = pa_stream_flush(pam->stream, NULL, NULL); if(o != NULL) pa_operation_unref(o); ab->ab_flush = 0; } l = pa_stream_writable_size(pam->stream); if(l == 0) { pa_threaded_mainloop_wait(mainloop); continue; } length = ab->ab_frames * pa_frame_size(&pam->ss) - ab->ab_tmp; if(l > length) l = length; if((pts = ab->ab_pts) != AV_NOPTS_VALUE && ab->ab_mp != NULL) { int64_t pts; pa_usec_t delay; pts = ab->ab_pts; ab->ab_pts = AV_NOPTS_VALUE; if(!pa_stream_get_latency(pam->stream, &delay, NULL)) { mp = ab->ab_mp; hts_mutex_lock(&mp->mp_clock_mutex); mp->mp_audio_clock = pts - delay; mp->mp_audio_clock_realtime = showtime_get_ts(); mp->mp_audio_clock_epoch = ab->ab_epoch; hts_mutex_unlock(&mp->mp_clock_mutex); } } pa_stream_write(pam->stream, ab->ab_data + ab->ab_tmp, l, NULL, 0LL, PA_SEEK_RELATIVE); ab->ab_tmp += l; assert(ab->ab_tmp <= ab->ab_frames * pa_frame_size(&pam->ss)); if(ab->ab_frames * pa_frame_size(&pam->ss) == ab->ab_tmp) { ab_free(ab); ab = NULL; } } prop_unsubscribe(pam->sub_mvol); prop_unsubscribe(pam->sub_mute); if(pam->stream != NULL) stream_destroy(pam); pa_threaded_mainloop_unlock(mainloop); pa_context_unref(pam->context); if(ab != NULL) { ab_free(ab); ab = NULL; } return r; }
static int wii_audio_start(audio_mode_t *am, audio_fifo_t *af) { audio_buf_t *ab; int tbuf = 0, i; uint32_t level; int64_t pts; media_pipe_t *mp; prop_sub_t *s_vol; s_vol = prop_subscribe(PROP_SUB_DIRECT_UPDATE, PROP_TAG_CALLBACK_FLOAT, set_mastervol, NULL, PROP_TAG_ROOT, prop_mastervol, NULL); LWP_InitQueue(&audio_queue); AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ); AUDIO_RegisterDMACallback(switch_buffers); AUDIO_StartDMA(); while(1) { level = IRQ_Disable(); while(tbuf == cur_buffer) LWP_ThreadSleep(audio_queue); tbuf = cur_buffer; IRQ_Restore(level); ab = af_deq(af, 0); if(am != audio_mode_current) { /* We're not the selected audio output anymore, return. */ if(ab != NULL) ab_free(ab); break; } if(ab != NULL) { const int16_t *src = (const int16_t *)ab->ab_data; int16_t *dst = (int16_t *)buffer[!tbuf]; for(i = 0; i < ADMA_BUFFER_SIZE / 2; i++) *dst++ = (*src++ * audio_vol) >> 16; /* PTS is the time of the first frame of this audio packet */ if((pts = ab->ab_pts) != AV_NOPTS_VALUE && ab->ab_mp != NULL) { #if 0 /* Convert the frame delay into micro seconds */ d = (fr * 1000 / aam->aam_sample_rate) * 1000; /* Subtract it from our timestamp, this will yield the PTS for the sample currently played */ pts -= d; /* Offset with user configure delay */ #endif pts += am->am_audio_delay * 1000; mp = ab->ab_mp; hts_mutex_lock(&mp->mp_clock_mutex); mp->mp_audio_clock = pts; mp->mp_audio_clock_realtime = showtime_get_ts(); mp->mp_audio_clock_epoch = ab->ab_epoch; hts_mutex_unlock(&mp->mp_clock_mutex); } ab_free(ab); } else { memset(buffer[!tbuf], 0, ADMA_BUFFER_SIZE); } DCFlushRange(buffer[!tbuf], ADMA_BUFFER_SIZE); }
static void * dummy_audio_thread(void *aux) { audio_decoder_t *ad = aux; media_pipe_t *mp = ad->ad_mp; media_queue_t *mq = &mp->mp_audio; media_buf_t *mb; int hold = 0; int run = 1; int64_t rt = 0; int64_t base = AV_NOPTS_VALUE; hts_mutex_lock(&mp->mp_mutex); while(run) { if((mb = TAILQ_FIRST(&mq->mq_q)) == NULL) { hts_cond_wait(&mq->mq_avail, &mp->mp_mutex); continue; } if(mb->mb_data_type == MB_AUDIO && hold && mb->mb_skip == 0) { hts_cond_wait(&mq->mq_avail, &mp->mp_mutex); continue; } TAILQ_REMOVE(&mq->mq_q, mb, mb_link); mq->mq_packets_current--; mp->mp_buffer_current -= mb->mb_size; mq_update_stats(mp, mq); hts_cond_signal(&mp->mp_backpressure); hts_mutex_unlock(&mp->mp_mutex); switch(mb->mb_data_type) { case MB_CTRL_EXIT: run = 0; break; case MB_CTRL_PAUSE: hold = 1; break; case MB_CTRL_PLAY: hold = 0; base = AV_NOPTS_VALUE; break; case MB_FLUSH: base = AV_NOPTS_VALUE; break; case MB_AUDIO: if(mb->mb_skip || mb->mb_stream != mq->mq_stream) break; if(mb->mb_pts != AV_NOPTS_VALUE) { audio_set_clock(mp, mb->mb_pts, 0, mb->mb_epoch); if(base == AV_NOPTS_VALUE) { base = mb->mb_pts; rt = showtime_get_ts(); } else { int64_t d = mb->mb_pts - base; if(d > 0) { int sleeptime = rt + d - showtime_get_ts(); if(sleeptime > 0) usleep(sleeptime); } } } break; default: abort(); } hts_mutex_lock(&mp->mp_mutex); media_buf_free_locked(mp, mb); } hts_mutex_unlock(&mp->mp_mutex); return NULL; }
/** * Called from various places to indicate that user is active * * Defined in showtime.h */ void runcontrol_activity(void) { if(standby_delay) last_activity = showtime_get_ts(); }
static pixmap_t * rpi_pixmap_decode(pixmap_t *pm, const image_meta_t *im, char *errbuf, size_t errlen) { if(pm->pm_type != PIXMAP_JPEG) return NULL; #ifdef TIMING int64_t ts = showtime_get_ts(), ts2; #endif rpi_pixmap_decoder_t *rpd = pixmap_decoder_create(OMX_IMAGE_CodingJPEG); if(rpd == NULL) return NULL; rpd->rpd_im = im; #ifdef NOCOPY #error check rpd->rpd_decoder->oc_stream_corrupt OMX_PARAM_PORTDEFINITIONTYPE portdef; memset(&portdef, 0, sizeof(portdef)); portdef.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE); portdef.nVersion.nVersion = OMX_VERSION; portdef.nPortIndex = rpd->rpd_decoder->oc_inport; omxchk(OMX_GetParameter(rpd->rpd_decoder->oc_handle, OMX_IndexParamPortDefinition, &portdef)); omx_send_command(rpd->rpd_decoder, OMX_CommandPortEnable, rpd->rpd_decoder->oc_inport, NULL, 0); OMX_BUFFERHEADERTYPE *buf; for(int i = 0; i < portdef.nBufferCountActual; i++) { omxchk(OMX_UseBuffer(rpd->rpd_decoder->oc_handle, &buf, rpd->rpd_decoder->oc_inport, NULL, pm->pm_size, pm->pm_data)); } // Waits for the OMX_CommandPortEnable command omx_wait_command(rpd->rpd_decoder); omx_set_state(rpd->rpd_decoder, OMX_StateExecuting); CHECKPOINT("Initialized"); buf->nOffset = 0; buf->nFilledLen = pm->pm_size; buf->nFlags |= OMX_BUFFERFLAG_EOS; rpd->rpd_decoder->oc_inflight_buffers++; omxchk(OMX_EmptyThisBuffer(rpd->rpd_decoder->oc_handle, buf)); hts_mutex_lock(&rpd->rpd_mtx); while(rpd->rpd_change == 0) hts_cond_wait(&rpd->rpd_cond, &rpd->rpd_mtx); hts_mutex_unlock(&rpd->rpd_mtx); CHECKPOINT("Setup tunnel"); setup_tunnel(rpd); #else const void *data = pm->pm_data; size_t len = pm->pm_size; hts_mutex_lock(&rpd->rpd_mtx); while(len > 0) { OMX_BUFFERHEADERTYPE *buf; if(rpd->rpd_decoder->oc_stream_corrupt) break; if(rpd->rpd_change == 1) { rpd->rpd_change = 2; hts_mutex_unlock(&rpd->rpd_mtx); setup_tunnel(rpd); hts_mutex_lock(&rpd->rpd_mtx); continue; } if(rpd->rpd_decoder->oc_avail == NULL) { hts_cond_wait(&rpd->rpd_cond, &rpd->rpd_mtx); continue; } buf = rpd->rpd_decoder->oc_avail; rpd->rpd_decoder->oc_avail = buf->pAppPrivate; rpd->rpd_decoder->oc_inflight_buffers++; hts_mutex_unlock(&rpd->rpd_mtx); buf->nOffset = 0; buf->nFilledLen = MIN(len, buf->nAllocLen); memcpy(buf->pBuffer, data, buf->nFilledLen); buf->nFlags = 0; if(len <= buf->nAllocLen) buf->nFlags |= OMX_BUFFERFLAG_EOS; data += buf->nFilledLen; len -= buf->nFilledLen; omxchk(OMX_EmptyThisBuffer(rpd->rpd_decoder->oc_handle, buf)); hts_mutex_lock(&rpd->rpd_mtx); } if(rpd->rpd_decoder->oc_stream_corrupt) { hts_mutex_unlock(&rpd->rpd_mtx); goto err; } if(rpd->rpd_change != 2) { while(rpd->rpd_change == 0 && !rpd->rpd_decoder->oc_stream_corrupt) hts_cond_wait(&rpd->rpd_cond, &rpd->rpd_mtx); hts_mutex_unlock(&rpd->rpd_mtx); if(rpd->rpd_decoder->oc_stream_corrupt) goto err; setup_tunnel(rpd); } else { hts_mutex_unlock(&rpd->rpd_mtx); } #endif omx_wait_fill_buffer(rpd->rpd_resizer, rpd->rpd_buf); CHECKPOINT("Got buffer"); err: omx_flush_port(rpd->rpd_decoder, rpd->rpd_decoder->oc_inport); omx_flush_port(rpd->rpd_decoder, rpd->rpd_decoder->oc_outport); omx_flush_port(rpd->rpd_resizer, rpd->rpd_resizer->oc_inport); omx_flush_port(rpd->rpd_resizer, rpd->rpd_resizer->oc_outport); if(rpd->rpd_tunnel != NULL) { omx_tunnel_destroy(rpd->rpd_tunnel); rpd->rpd_tunnel = NULL; } omx_set_state(rpd->rpd_decoder, OMX_StateIdle); omx_set_state(rpd->rpd_resizer, OMX_StateIdle); if(rpd->rpd_buf != NULL) { omxchk(OMX_FreeBuffer(rpd->rpd_resizer->oc_handle, rpd->rpd_resizer->oc_outport, rpd->rpd_buf)); } omx_release_buffers(rpd->rpd_decoder, rpd->rpd_decoder->oc_inport); omx_set_state(rpd->rpd_resizer, OMX_StateLoaded); omx_set_state(rpd->rpd_decoder, OMX_StateLoaded); omx_component_destroy(rpd->rpd_resizer); omx_component_destroy(rpd->rpd_decoder); hts_cond_destroy(&rpd->rpd_cond); hts_mutex_destroy(&rpd->rpd_mtx); pixmap_t *out = rpd->rpd_pm; if(out) { pixmap_release(pm); } else { snprintf(errbuf, errlen, "Load error"); } free(rpd); CHECKPOINT("All done"); return out; }
static void render_unlocked(glw_root_t *gr) { glw_backend_root_t *gbr = &gr->gr_be; int i; struct render_job *rj = gbr->gbr_render_jobs; int64_t ts = showtime_get_ts(); int current_blendmode = GLW_BLEND_NORMAL; glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); int program_switches = 0; const float *vertices = gbr->gbr_vertex_buffer; glBindBuffer(GL_ARRAY_BUFFER, gbr->gbr_vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * VERTEX_SIZE * gbr->gbr_vertex_offset, vertices, GL_STATIC_DRAW); vertices = NULL; glVertexAttribPointer(0, 4, GL_FLOAT, 0, sizeof(float) * VERTEX_SIZE, vertices); glVertexAttribPointer(1, 4, GL_FLOAT, 0, sizeof(float) * VERTEX_SIZE, vertices + 4); glVertexAttribPointer(2, 4, GL_FLOAT, 0, sizeof(float) * VERTEX_SIZE, vertices + 8); for(i = 0; i < gbr->gbr_num_render_jobs; i++, rj++) { const struct glw_backend_texture *t0 = rj->t0; glw_program_t *gp = get_program(gbr, t0, rj->t1, rj->blur, rj->flags, rj->up); if(gp == NULL) continue; if(glw_load_program(gbr, gp)) { program_switches++; } glUniform4f(gp->gp_uniform_color_offset, rj->rgb_off.r, rj->rgb_off.g, rj->rgb_off.b, 0); glw_program_set_uniform_color(gbr, rj->rgb_mul.r, rj->rgb_mul.g, rj->rgb_mul.b, rj->alpha); if(gp->gp_uniform_time != -1) glUniform1f(gp->gp_uniform_time, gr->gr_time_sec); if(gp->gp_uniform_resolution != -1) glUniform2f(gp->gp_uniform_resolution, rj->width, rj->height); if(gp->gp_uniform_blur != -1 && t0 != NULL) glUniform3f(gp->gp_uniform_blur, rj->blur, 1.5 / t0->width, 1.5 / t0->height); if(rj->eyespace) { glUniformMatrix4fv(gp->gp_uniform_modelview, 1, 0, glw_identitymtx); } else { glUniformMatrix4fv(gp->gp_uniform_modelview, 1, 0, glw_mtx_get(rj->m)); } if(current_blendmode != rj->blendmode) { current_blendmode = rj->blendmode; switch(current_blendmode) { case GLW_BLEND_NORMAL: glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); break; case GLW_BLEND_ADDITIVE: glBlendFuncSeparate(GL_SRC_COLOR, GL_ONE, GL_ONE, GL_ONE); break; } } glDrawArrays(GL_TRIANGLES, rj->vertex_offset, rj->num_vertices); } if(current_blendmode != GLW_BLEND_NORMAL) { glBlendFuncSeparate(GL_SRC_COLOR, GL_ONE, GL_ONE, GL_ONE); } ts = showtime_get_ts() - ts; static int hold; hold++; if(hold < 20) return; static int cnt; static int64_t tssum; tssum += ts; cnt++; // printf("%16d (%d) %d switches\n", (int)ts, (int)(tssum/cnt), program_switches); }