Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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
}
Beispiel #4
0
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
}
Beispiel #5
0
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;
}
Beispiel #6
0
/**
 * 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);
}
Beispiel #7
0
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;
}
Beispiel #8
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;
}
Beispiel #9
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);
}
Beispiel #10
0
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;
}
Beispiel #11
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;
}
Beispiel #12
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;
}
Beispiel #13
0
int64_t
showtime_get_avtime(void)
{
  return showtime_get_ts();
}
Beispiel #14
0
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;
}
Beispiel #15
0
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;
}
Beispiel #16
0
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);

  }
Beispiel #17
0
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;
}
Beispiel #18
0
/**
 * 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();
}
Beispiel #19
0
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;
}
Beispiel #20
0
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);
}