Esempio n. 1
0
/**
 * Video decoder thread
 */
static void *
vd_thread(void *aux)
{
  video_decoder_t *vd = aux;
  media_pipe_t *mp = vd->vd_mp;
  media_queue_t *mq = &mp->mp_video;
  media_buf_t *mb;
  media_codec_t *mc;
  int run = 1;
  int reqsize = -1;
  int reinit = 0;
  int size;
  vd->vd_frame = avcodec_alloc_frame();

  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_VIDEO && vd->vd_hold && 
       vd->vd_skip == 0 && mb->mb_skip == 0) {
      hts_cond_wait(&mq->mq_avail, &mp->mp_mutex);
      continue;
    }

    TAILQ_REMOVE(&mq->mq_q, mb, mb_link);
    mq->mq_freeze_tail = 1;
    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);

    mc = mb->mb_cw;

    switch(mb->mb_data_type) {
    case MB_CTRL_EXIT:
      run = 0;
      break;

    case MB_CTRL_PAUSE:
      vd->vd_hold = 1;
      break;

    case MB_CTRL_PLAY:
      vd->vd_hold = 0;
      break;

    case MB_FLUSH:
      vd_init_timings(vd);
      vd->vd_do_flush = 1;
      vd->vd_interlaced = 0;
      video_overlay_flush(vd, 1);
      break;

    case MB_VIDEO:
      if(reinit) {
	reinit = 0;
	if(mc->reinit != NULL)
	  mc->reinit(mc);
      }

      if(mb->mb_skip == 2)
	vd->vd_skip = 1;

      size = mb->mb_size;

      if(mc->decode)
	mc->decode(mc, vd, mq, mb, reqsize);
      else
	vd_decode_video(vd, mq, mb);

      update_vbitrate(mp, mq, size, vd);
      reqsize = -1;
      break;

    case MB_REQ_OUTPUT_SIZE:
      reqsize = mb->mb_data32;
      break;

    case MB_REINITIALIZE:
      reinit = 1;
      break;

#ifdef CONFIG_DVD
    case MB_DVD_HILITE:
    case MB_DVD_RESET_SPU:
    case MB_DVD_CLUT:
    case MB_DVD_PCI:
    case MB_DVD_SPU:
      dvdspu_decoder_dispatch(vd, mb, mp);
      break;
#endif

    case MB_SUBTITLE:
      if(vd->vd_ext_subtitles == NULL && mb->mb_stream == mq->mq_stream2)
	video_overlay_decode(vd, mb);
      break;

    case MB_END:
      break;

    case MB_BLACKOUT:
      if(vd->vd_accelerator_blackout)
	vd->vd_accelerator_blackout(vd->vd_accelerator_opaque);
      else
	vd->vd_frame_deliver(NULL, NULL, NULL, vd->vd_opaque);
      break;

    case MB_FLUSH_SUBTITLES:
      video_overlay_flush(vd, 1);
      break;

    case MB_EXT_SUBTITLE:
      if(vd->vd_ext_subtitles != NULL)
         subtitles_destroy(vd->vd_ext_subtitles);

      // Steal subtitle from the media_buf
      vd->vd_ext_subtitles = mb->mb_data;
      mb->mb_data = NULL; 
      video_overlay_flush(vd, 1);
      break;

    default:
      abort();
    }

    hts_mutex_lock(&mp->mp_mutex);
    mq->mq_freeze_tail = 0;
    media_buf_free_locked(mp, mb);
  }

  hts_mutex_unlock(&mp->mp_mutex);

  // Stop any video accelerator helper threads 
  video_decoder_set_accelerator(vd, NULL, NULL, NULL);

  if(vd->vd_ext_subtitles != NULL)
    subtitles_destroy(vd->vd_ext_subtitles);

  /* Free ffmpeg frame */
  av_free(vd->vd_frame);
  return NULL;
}
Esempio n. 2
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;
}
Esempio n. 3
0
static void
htsp_channelAddUpdate(htsp_connection_t *hc, htsmsg_t *m, int create)
{
  uint32_t id, next;
  int chnum;
  prop_t *p;
  char txt[200];
  const char *title, *icon;
  htsp_channel_t *ch, *n;

  if(htsmsg_get_u32(m, "channelId", &id))
    return;

  title = htsmsg_get_str(m, "channelName");
  icon  = htsmsg_get_str(m, "channelIcon");
  chnum = htsmsg_get_s32_or_default(m, "channelNumber", -1);

  if(chnum == 0)
    chnum = INT32_MAX;

  snprintf(txt, sizeof(txt), "%d", id);

  hts_mutex_lock(&hc->hc_meta_mutex);

  if(create) {

    ch = calloc(1, sizeof(htsp_channel_t));
    p = ch->ch_root = prop_create_root(txt);
    ch->ch_metadata = prop_create(p, "metadata");
    ch->ch_id = id;

    snprintf(txt, sizeof(txt), "htsp://%s:%d/channel/%d",
	     hc->hc_hostname, hc->hc_port, id);
    
    prop_set_string(prop_create(p, "url"), txt);
    prop_set_string(prop_create(p, "type"), "tvchannel");

    ch->ch_channel_num = chnum;
    mystrset(&ch->ch_title, title);

    TAILQ_INSERT_SORTED(&hc->hc_channels, ch, ch_link, channel_compar);
    n = TAILQ_NEXT(ch, ch_link);

    if(prop_set_parent_ex(p, hc->hc_channels_nodes,
			  n ? n->ch_root : NULL, NULL))
      abort();

  } else {

    int move = 0;

    ch = htsp_channel_get(hc, id);
    if(ch == NULL) {
      TRACE(TRACE_ERROR, "HTSP", "Got update for unknown channel %d", id);
      hts_mutex_unlock(&hc->hc_meta_mutex);
      return;
    }

    p = ch->ch_root;

    if(title != NULL) {
      move = 1;
      mystrset(&ch->ch_title, title);
    }

    if(chnum != -1) {
      move = 1;
      ch->ch_channel_num = chnum;
    }

    if(move) {
      TAILQ_REMOVE(&hc->hc_channels, ch, ch_link);
      TAILQ_INSERT_SORTED(&hc->hc_channels, ch, ch_link, channel_compar);
      n = TAILQ_NEXT(ch, ch_link);
      prop_move(p, n ? n->ch_root : NULL);
    }
  }

  hts_mutex_unlock(&hc->hc_meta_mutex);

  if(icon != NULL)
    prop_set_string(prop_create(ch->ch_metadata, "icon"), icon);
  if(title != NULL)
    prop_set_string(prop_create(ch->ch_metadata, "title"), title);
  if(chnum != -1)
    prop_set_int(prop_create(ch->ch_metadata, "channelNumber"), chnum);


  if(htsmsg_get_u32(m, "eventId", &id))
    id = 0;
  if(htsmsg_get_u32(m, "nextEventId", &next))
    next = 0;
  update_events(hc, ch->ch_metadata, id, next);
}
Esempio n. 4
0
media_pipe_t *
mp_create(const char *name, int flags)
{
  media_pipe_t *mp;
  prop_t *p;

  mp = calloc(1, sizeof(media_pipe_t));
  mp->mp_cancellable = cancellable_create();

  mp->mp_vol_ui = 1.0f;

  mp->mp_satisfied = -1;
  mp->mp_epoch = 1;

  mp->mp_mb_pool = pool_create("packet headers",
			       sizeof(media_buf_t),
			       POOL_ZERO_MEM);

  mp->mp_flags = flags;

  hts_mutex_lock(&media_mutex);
  LIST_INSERT_HEAD(&media_pipelines, mp, mp_global_link);
  num_media_pipelines++;
  hts_mutex_unlock(&media_mutex);


  TAILQ_INIT(&mp->mp_eq);

  atomic_set(&mp->mp_refcount, 1);

  mp->mp_buffer_limit = 1 * 1024 * 1024;

  mp->mp_name = name;

  hts_mutex_init(&mp->mp_mutex);
  hts_mutex_init(&mp->mp_clock_mutex);

  hts_mutex_init(&mp->mp_overlay_mutex);
  TAILQ_INIT(&mp->mp_overlay_queue);
  TAILQ_INIT(&mp->mp_spu_queue);

  hts_cond_init(&mp->mp_backpressure, &mp->mp_mutex);

  mp->mp_prop_root = prop_create(media_prop_sources, NULL);
  mp->mp_prop_metadata    = prop_create(mp->mp_prop_root, "metadata");

  mp->mp_prop_primary = prop_create(mp->mp_prop_root, "primary");

  mp->mp_prop_io = prop_create(mp->mp_prop_root, "io");
  mp->mp_prop_notifications = prop_create(mp->mp_prop_root, "notifications");
  mp->mp_prop_url         = prop_create(mp->mp_prop_root, "url");


  mp->mp_setting_root = prop_create(mp->mp_prop_root, "settings");

  //--------------------------------------------------
  // Video

  mp->mp_prop_video = prop_create(mp->mp_prop_root, "video");
  mp->mp_setting_video_root = prop_create(mp->mp_prop_video, "settings");
  mq_init(&mp->mp_video, mp->mp_prop_video, &mp->mp_mutex, mp);

  //--------------------------------------------------
  // Audio

  mp->mp_prop_audio = prop_create(mp->mp_prop_root, "audio");
  mp->mp_setting_audio_root = prop_create(mp->mp_prop_audio, "settings");
  mq_init(&mp->mp_audio, mp->mp_prop_audio, &mp->mp_mutex, mp);
  mp->mp_prop_audio_track_current = prop_create(mp->mp_prop_audio, "current");
  mp->mp_prop_audio_track_current_manual =
    prop_create(mp->mp_prop_audio, "manual");
  mp->mp_prop_audio_tracks = prop_create(mp->mp_prop_metadata, "audiostreams");
  prop_linkselected_create(mp->mp_prop_audio_tracks,
                           mp->mp_prop_audio, "active", NULL);

  prop_set_string(mp->mp_prop_audio_track_current, "audio:off");


  mp_track_mgr_init(mp,
                    &mp->mp_audio_track_mgr,
                    mp->mp_prop_audio_tracks,
                    MEDIA_TRACK_MANAGER_AUDIO,
                    mp->mp_prop_audio_track_current,
                    prop_create(mp->mp_prop_audio, "sorted"));

  //--------------------------------------------------
  // Subtitles

  p = prop_create(mp->mp_prop_root, "subtitle");
  mp->mp_setting_subtitle_root = prop_create(p, "settings");
  mp->mp_prop_subtitle_track_current = prop_create(p, "current");
  mp->mp_prop_subtitle_track_current_manual = prop_create(p, "manual");
  mp->mp_prop_subtitle_tracks = prop_create(mp->mp_prop_metadata,
					    "subtitlestreams");
  prop_linkselected_create(mp->mp_prop_subtitle_tracks, p, "active", NULL);


  prop_set_string(mp->mp_prop_subtitle_track_current, "sub:off");
  mp_add_track_off(mp->mp_prop_subtitle_tracks, "sub:off");

  mp_track_mgr_init(mp,
                    &mp->mp_subtitle_track_mgr,
                    mp->mp_prop_subtitle_tracks,
                    MEDIA_TRACK_MANAGER_SUBTITLES,
                    mp->mp_prop_subtitle_track_current,
                    prop_create(p, "sorted"));

  //--------------------------------------------------
  // Buffer

  p = prop_create(mp->mp_prop_root, "buffer");
  mp->mp_prop_buffer_current = prop_create(p, "current");
  prop_set_int(mp->mp_prop_buffer_current, 0);

  mp->mp_prop_buffer_limit = prop_create(p, "limit");
  prop_set_int(mp->mp_prop_buffer_limit, mp->mp_buffer_limit);

  mp->mp_prop_buffer_delay = prop_create(p, "delay");



  //

  mp->mp_prop_playstatus  = prop_create(mp->mp_prop_root, "playstatus");
  mp->mp_prop_pausereason = prop_create(mp->mp_prop_root, "pausereason");
  mp->mp_prop_currenttime = prop_create(mp->mp_prop_root, "currenttime");
  mp->mp_prop_fps = prop_create(mp->mp_prop_root, "fps");

  prop_set_float_clipping_range(mp->mp_prop_currenttime, 0, 10e6);

  mp->mp_prop_avdelta     = prop_create(mp->mp_prop_root, "avdelta");
  prop_set_float(mp->mp_prop_avdelta, 0);

  mp->mp_prop_svdelta     = prop_create(mp->mp_prop_root, "svdelta");
  prop_set_float(mp->mp_prop_svdelta, 0);

  mp->mp_prop_shuffle     = prop_create(mp->mp_prop_root, "shuffle");
  prop_set_int(mp->mp_prop_shuffle, 0);
  mp->mp_prop_repeat      = prop_create(mp->mp_prop_root, "repeat");
  prop_set_int(mp->mp_prop_repeat, 0);

  mp->mp_prop_avdiff      = prop_create(mp->mp_prop_root, "avdiff");
  mp->mp_prop_avdiff_error= prop_create(mp->mp_prop_root, "avdiffError");

  mp->mp_prop_canSkipBackward =
    prop_create(mp->mp_prop_root, "canSkipBackward");

  mp->mp_prop_canSkipForward =
    prop_create(mp->mp_prop_root, "canSkipForward");

  mp->mp_prop_canSeek =
    prop_create(mp->mp_prop_root, "canSeek");

  mp->mp_prop_canPause =
    prop_create(mp->mp_prop_root, "canPause");

  mp->mp_prop_canEject =
    prop_create(mp->mp_prop_root, "canEject");

  mp->mp_prop_canShuffle =
    prop_create(mp->mp_prop_root, "canShuffle");

  mp->mp_prop_canRepeat =
    prop_create(mp->mp_prop_root, "canRepeat");

  prop_set_int(prop_create(mp->mp_prop_root, "canStop"), 1);

  mp->mp_prop_ctrl = prop_create(mp->mp_prop_root, "ctrl");

  mp->mp_prop_model = prop_create(mp->mp_prop_root, "model");

  mp->mp_sub_currenttime =
    prop_subscribe(PROP_SUB_NO_INITIAL_UPDATE,
		   PROP_TAG_CALLBACK, mp_seek_by_propchange, mp,
                   PROP_TAG_LOCKMGR, mp_lockmgr,
                   PROP_TAG_MUTEX, mp,
		   PROP_TAG_ROOT, mp->mp_prop_currenttime,
		   NULL);

  mp->mp_sub_eventsink =
    prop_subscribe(0,
		   PROP_TAG_NAME("media", "eventSink"),
                   PROP_TAG_CALLBACK_EVENT, media_eventsink, mp,
                   PROP_TAG_LOCKMGR, mp_lockmgr,
                   PROP_TAG_MUTEX, mp,
		   PROP_TAG_NAMED_ROOT, mp->mp_prop_root, "media",
		   NULL);


  if(media_pipe_init_extra != NULL)
    media_pipe_init_extra(mp);

  return mp;
}
Esempio n. 5
0
static void
audio_process_audio(audio_decoder_t *ad, media_buf_t *mb)
{
  const audio_class_t *ac = ad->ad_ac;
  AVFrame *frame = ad->ad_frame;
  media_pipe_t *mp = ad->ad_mp;
  media_queue_t *mq = &mp->mp_audio;
  int r;
  int got_frame;

  if(mb->mb_skip || mb->mb_stream != mq->mq_stream) 
    return;

  while(mb->mb_size) {

    if(mb->mb_cw == NULL) {
      frame->sample_rate = mb->mb_rate;
      frame->format = AV_SAMPLE_FMT_S16;
      switch(mb->mb_channels) {
      case 1:
	frame->channel_layout = AV_CH_LAYOUT_MONO;
	frame->nb_samples = mb->mb_size / 2;
	break;
      case 2:
	frame->channel_layout = AV_CH_LAYOUT_STEREO;
	frame->nb_samples = mb->mb_size / 4;
	break;
      default:
	abort();
      }
      frame->data[0] = mb->mb_data;
      frame->linesize[0] = 0;
      r = mb->mb_size;
      got_frame = 1;

    } else {

      media_codec_t *mc = mb->mb_cw;

      AVCodecContext *ctx = mc->ctx;

      if(mc->codec_id != ad->ad_in_codec_id) {
	AVCodec *codec = avcodec_find_decoder(mc->codec_id);
	TRACE(TRACE_DEBUG, "audio", "Codec changed to %s (0x%x)",
	      codec ? codec->name : "???", mc->codec_id);
	ad->ad_in_codec_id = mc->codec_id;
	ad->ad_in_sample_rate = 0;

	audio_cleanup_spdif_muxer(ad);

	ad->ad_mode = ac->ac_get_mode != NULL ?
	  ac->ac_get_mode(ad, mc->codec_id,
			  ctx ? ctx->extradata : NULL,
			  ctx ? ctx->extradata_size : 0) : AUDIO_MODE_PCM;

	if(ad->ad_mode == AUDIO_MODE_SPDIF) {
	  audio_setup_spdif_muxer(ad, codec, mq);
	} else if(ad->ad_mode == AUDIO_MODE_CODED) {
	  
	  hts_mutex_lock(&mp->mp_mutex);
	  
	  ac->ac_deliver_coded_locked(ad, mb->mb_data, mb->mb_size,
				      mb->mb_pts, mb->mb_epoch);
	  hts_mutex_unlock(&mp->mp_mutex);
	  return;
	}
      }

      if(ad->ad_spdif_muxer != NULL) {
	mb->mb_pkt.stream_index = 0;
	ad->ad_pts = mb->mb_pts;
	ad->ad_epoch = mb->mb_epoch;

	mb->mb_pts = AV_NOPTS_VALUE;
	mb->mb_dts = AV_NOPTS_VALUE;
	av_write_frame(ad->ad_spdif_muxer, &mb->mb_pkt);
	avio_flush(ad->ad_spdif_muxer->pb);
	return;
      }


      if(ad->ad_mode == AUDIO_MODE_CODED) {
	ad->ad_pts = mb->mb_pts;
	ad->ad_epoch = mb->mb_epoch;
	

      }


      if(ctx == NULL) {

	AVCodec *codec = avcodec_find_decoder(mc->codec_id);
	assert(codec != NULL); // Checked in libav.c

	ctx = mc->ctx = avcodec_alloc_context3(codec);

	if(ad->ad_stereo_downmix)
          ctx->request_channel_layout = AV_CH_LAYOUT_STEREO;

	if(avcodec_open2(mc->ctx, codec, NULL) < 0) {
	  av_freep(&mc->ctx);
	  return;
	}
      }

      r = avcodec_decode_audio4(ctx, frame, &got_frame, &mb->mb_pkt);
      if(r < 0)
	return;

      if(frame->sample_rate == 0) {
	frame->sample_rate = ctx->sample_rate;

	if(frame->sample_rate == 0 && mb->mb_cw->fmt_ctx)
	  frame->sample_rate = mb->mb_cw->fmt_ctx->sample_rate;

	if(frame->sample_rate == 0) {

          if(!ad->ad_sample_rate_fail) {
            ad->ad_sample_rate_fail = 1;
            TRACE(TRACE_ERROR, "Audio",
                  "Unable to determine sample rate");
          }
	  return;
        }
      }

      if(frame->channel_layout == 0) {
        frame->channel_layout = av_get_default_channel_layout(ctx->channels);
        if(frame->channel_layout == 0) {

          if(!ad->ad_channel_layout_fail) {
            ad->ad_channel_layout_fail = 1;
              TRACE(TRACE_ERROR, "Audio",
                    "Unable to map %d channels to channel layout");
          }
	  return;
	}
      }

      if(mp->mp_stats)
	mp_set_mq_meta(mq, ctx->codec, ctx);

    }

    if(mb->mb_pts != PTS_UNSET) {

      int od = 0, id = 0;

      if(ad->ad_avr != NULL) {
	od = avresample_available(ad->ad_avr) *
	  1000000LL / ad->ad_out_sample_rate;
	id = avresample_get_delay(ad->ad_avr) *
	  1000000LL / frame->sample_rate;
      }
      ad->ad_pts = mb->mb_pts - od - id;
      ad->ad_epoch = mb->mb_epoch;

      if(mb->mb_drive_clock)
	mp_set_current_time(mp, mb->mb_pts - ad->ad_delay,
			    mb->mb_epoch, mb->mb_delta);
      mb->mb_pts = PTS_UNSET; // No longer valid
    }


    mb->mb_data += r;
    mb->mb_size -= r;

    if(got_frame) {

      if(frame->sample_rate    != ad->ad_in_sample_rate ||
	 frame->format         != ad->ad_in_sample_format ||
	 frame->channel_layout != ad->ad_in_channel_layout ||
	 ad->ad_want_reconfig) {

	ad->ad_want_reconfig = 0;
	ad->ad_in_sample_rate    = frame->sample_rate;
	ad->ad_in_sample_format  = frame->format;
	ad->ad_in_channel_layout = frame->channel_layout;

	ac->ac_reconfig(ad);

	if(ad->ad_avr == NULL)
	  ad->ad_avr = avresample_alloc_context();
	else
	  avresample_close(ad->ad_avr);

	av_opt_set_int(ad->ad_avr, "in_sample_fmt",
		       ad->ad_in_sample_format, 0);
	av_opt_set_int(ad->ad_avr, "in_sample_rate", 
		       ad->ad_in_sample_rate, 0);
	av_opt_set_int(ad->ad_avr, "in_channel_layout",
		       ad->ad_in_channel_layout, 0);

	av_opt_set_int(ad->ad_avr, "out_sample_fmt",
		       ad->ad_out_sample_format, 0);
	av_opt_set_int(ad->ad_avr, "out_sample_rate",
		       ad->ad_out_sample_rate, 0);
	av_opt_set_int(ad->ad_avr, "out_channel_layout",
		       ad->ad_out_channel_layout, 0);

	char buf1[128];
	char buf2[128];

	av_get_channel_layout_string(buf1, sizeof(buf1), 
				     -1, ad->ad_in_channel_layout);
	av_get_channel_layout_string(buf2, sizeof(buf2), 
				     -1, ad->ad_out_channel_layout);

	TRACE(TRACE_DEBUG, "Audio",
	      "Converting from [%s %dHz %s] to [%s %dHz %s]",
	      buf1, ad->ad_in_sample_rate,
	      av_get_sample_fmt_name(ad->ad_in_sample_format),
	      buf2, ad->ad_out_sample_rate,
	      av_get_sample_fmt_name(ad->ad_out_sample_format));

	if(avresample_open(ad->ad_avr)) {
	  TRACE(TRACE_ERROR, "Audio", "Unable to open resampler");
	  avresample_free(&ad->ad_avr);
	}

	if(ac->ac_set_volume != NULL) {
	  prop_set(mp->mp_prop_ctrl, "canAdjustVolume", PROP_SET_INT, 1);
	  ac->ac_set_volume(ad, ad->ad_vol_scale);
	}
      }
      if(ad->ad_avr != NULL) {
	avresample_convert(ad->ad_avr, NULL, 0, 0,
			   frame->data, frame->linesize[0],
			   frame->nb_samples);
      } else {
	int delay = 1000000LL * frame->nb_samples / frame->sample_rate;
	usleep(delay);
      }
    }
  }
}
Esempio n. 6
0
int
keyring_lookup(const char *id, char **username, char **password,
	       char **domain, int *remember_me, const char *source,
	       const char *reason, int flags)
{
  htsmsg_t *m;
  rstr_t *r;
  int remember = !!(flags & KEYRING_REMEMBER_ME_SET);

  hts_mutex_lock(&keyring_mutex);

  if(flags & KEYRING_QUERY_USER) {
    htsmsg_t *parent;
    prop_t *p = prop_create_root(NULL);

    prop_set_string(prop_create(p, "type"), "auth");
    prop_set_string(prop_create(p, "id"), id);
    prop_set_string(prop_create(p, "source"), source);
    prop_set_string(prop_create(p, "reason"), reason);
    prop_set_int(prop_create(p, "disableUsername"), username == NULL);


    prop_set_int(prop_create(p, "canRemember"),
		 !!(flags & KEYRING_SHOW_REMEMBER_ME));
    prop_t *rememberMe = prop_create(p, "rememberMe");
    prop_set_int(rememberMe, remember);

    prop_sub_t *remember_sub = 
	prop_subscribe(0,
		   PROP_TAG_CALLBACK_INT, set_remember, &remember,
		   PROP_TAG_ROOT, rememberMe,
		   NULL);

    prop_t *user = prop_create(p, "username");
    prop_t *pass = prop_create(p, "password");
 
    TRACE(TRACE_INFO, "keyring", "Requesting credentials for %s : %s : %s",
	  id, source, reason);


    event_t *e = popup_display(p);

    prop_unsubscribe(remember_sub);

    if(flags & KEYRING_ONE_SHOT)
      parent = NULL;
    else if(remember)
      parent = persistent_keyring;
    else
      parent = temporary_keyring;

    if(parent != NULL)
      htsmsg_delete_field(parent, id);

    if(event_is_action(e, ACTION_OK)) {
      /* OK */

      m = htsmsg_create_map();

      if(username != NULL) {
	r = prop_get_string(user);
	htsmsg_add_str(m, "username", r ? rstr_get(r) : "");
	*username = strdup(r ? rstr_get(r) : "");
	rstr_release(r);
      }

      r = prop_get_string(pass);
      htsmsg_add_str(m, "password", r ? rstr_get(r) : "");
      *password = strdup(r ? rstr_get(r) : "");
      rstr_release(r);

      if(parent != NULL) {
	htsmsg_add_msg(parent, id, m);

	if(parent == persistent_keyring)
	  keyring_store();
      }

    } else {
      /* CANCEL */
      if(parent == persistent_keyring)
	keyring_store();
    }

    if(remember_me != NULL)
      *remember_me = remember;

    prop_destroy(p);

    if(event_is_action(e, ACTION_CANCEL)) {
      /* return CANCEL to caller */
      hts_mutex_unlock(&keyring_mutex);
      event_release(e);
      return -1;
    }
    event_release(e);

  } else {

    if((m = htsmsg_get_map(temporary_keyring, id)) == NULL &&
       (m = htsmsg_get_map(persistent_keyring, id)) == NULL) {
      hts_mutex_unlock(&keyring_mutex);
      return 1;
    }
    
    setstr(username, m, "username");
    setstr(password, m, "password");
    setstr(domain, m, "domain");
  }

  hts_mutex_unlock(&keyring_mutex);
  return 0;
}
Esempio n. 7
0
void
load_site_news(void)
{
#if ENABLE_WEBPOPUP
  struct http_header_list response_headers;
  buf_t *b;
  char errbuf[512];
  b = fa_load("https://movian.tv/projects/movian/news.json",
              FA_LOAD_FLAGS(FA_DISABLE_AUTH | FA_COMPRESSION),
              FA_LOAD_RESPONSE_HEADERS(&response_headers),
              FA_LOAD_ERRBUF(errbuf, sizeof(errbuf)),
              NULL);
  if(b == NULL) {
    TRACE(TRACE_DEBUG, "News", "Unable to load news -- %s", errbuf);
    return;
  }

  const char *dateheader = http_header_get(&response_headers, "date");
  if(dateheader == NULL) {
    buf_release(b);
    http_headers_free(&response_headers);
    return;
  }
  dateheader = mystrdupa(dateheader);
  http_headers_free(&response_headers);


  htsmsg_t *newsinfo = htsmsg_store_load("sitenews");
  time_t no_news_before;

  if(newsinfo == NULL)
    newsinfo = htsmsg_create_map();

  no_news_before = htsmsg_get_u32_or_default(newsinfo, "nothingbefore", 0);

  if(no_news_before == 0) {
    if(http_ctime(&no_news_before, dateheader)) {
      buf_release(b);
      htsmsg_release(newsinfo);
      return;
    }

    htsmsg_add_u32(newsinfo, "nothingbefore", no_news_before);
    htsmsg_store_save(newsinfo, "sitenews");
    htsmsg_release(newsinfo);
  }

  htsmsg_t *doc = htsmsg_json_deserialize(buf_cstr(b));
  buf_release(b);
  if(doc == NULL) {
    return;
  }

  hts_mutex_lock(&news_mutex);

  htsmsg_t *news = htsmsg_get_list(doc, "news");
  if(news != NULL) {
    htsmsg_field_t *f;
    HTSMSG_FOREACH(f, news) {
      htsmsg_t *entry;
      if((entry = htsmsg_get_map_by_field(f)) == NULL)
        continue;

      const char *title = htsmsg_get_str(entry, "title");
      const char *created_on = htsmsg_get_str(entry, "created_on");
      int id = htsmsg_get_u32_or_default(entry, "id", 0);
      if(created_on == NULL || title == NULL || id == 0)
        continue;

      time_t t;

      if(parse_created_on_time(&t, created_on))
        continue;

      if(t < no_news_before)
        continue;

      char idstr[64];
      snprintf(idstr, sizeof(idstr), "sitenews:%d", id);
      prop_t *p = add_news_locked(idstr, title, NULL, "Read more", idstr);
      if(p != NULL) {
        prop_subscribe(PROP_SUB_TRACK_DESTROY,
                       PROP_TAG_CALLBACK, open_news, p,
                       PROP_TAG_ROOT, prop_create(p, "eventSink"),
                       PROP_TAG_MUTEX, &news_mutex,
                       NULL);
      }
    }
Esempio n. 8
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);

  }
Esempio n. 9
0
int
keyring_lookup(const char *id, char **username, char **password,
	       char **domain, int query, const char *source,
	       const char *reason, int force_temporary)
{
  htsmsg_t *m;
  rstr_t *r;


  hts_mutex_lock(&keyring_mutex);

  if(query) {
    htsmsg_t *parent;
    prop_t *p = prop_create_root(NULL);

    prop_set_string(prop_create(p, "type"), "auth");
    prop_set_string(prop_create(p, "id"), id);
    prop_set_string(prop_create(p, "source"), source);
    prop_set_string(prop_create(p, "reason"), reason);

    int remember = !force_temporary;
    prop_set_int(prop_create(p, "canRemember"), remember);
    prop_t *rememberMe = prop_create(p, "rememberMe");
    prop_set_int(rememberMe, remember);

    prop_sub_t *remember_sub = 
	prop_subscribe(0,
		   PROP_TAG_CALLBACK_INT, set_remember, &remember,
		   PROP_TAG_ROOT, rememberMe,
		   NULL);

    prop_t *user = prop_create(p, "username");
    prop_t *pass = prop_create(p, "password");
 
    TRACE(TRACE_INFO, "keyring", "Requesting credentials for %s : %s : %s",
	  id, source, reason);


    event_t *e = popup_display(p);

    prop_unsubscribe(remember_sub);

    if(remember)
      parent = persistent_keyring;
    else
      parent = temporary_keyring;

    htsmsg_delete_field(parent, id);

    if(event_is_action(e, ACTION_OK)) {
      /* OK */

      m = htsmsg_create_map();

      r = prop_get_string(user);
      htsmsg_add_str(m, "username", r ? rstr_get(r) : "");
      rstr_release(r);

      r = prop_get_string(pass);
      htsmsg_add_str(m, "password", r ? rstr_get(r) : "");
      rstr_release(r);

      htsmsg_add_msg(parent, id, m);

      if(parent == persistent_keyring)
	keyring_store();

    } else {
      /* CANCEL, store without adding anything */
      keyring_store();
    }

    prop_destroy(p);

    if(event_is_action(e, ACTION_CANCEL)) {
      /* return CANCEL to caller */
      hts_mutex_unlock(&keyring_mutex);
      event_release(e);
      return -1;
    }
    event_release(e);
  }

  if((m = htsmsg_get_map(temporary_keyring, id)) == NULL &&
     (m = htsmsg_get_map(persistent_keyring, id)) == NULL) {
    hts_mutex_unlock(&keyring_mutex);
    return 1;
  }

  setstr(username, m, "username");
  setstr(password, m, "password");
  setstr(domain, m, "domain");

  hts_mutex_unlock(&keyring_mutex);
  return 0;
}
Esempio n. 10
0
static void
gdk_obtain(void)
{
    hts_mutex_lock(&gdk_mutex);
}
Esempio n. 11
0
int
ecmascript_openuri(prop_t *page, const char *url, int sync)
{
  hts_regmatch_t matches[8];

  hts_mutex_lock(&route_mutex);

  es_route_t *er;

  LIST_FOREACH(er, &routes, er_link)
    if(!hts_regexec(&er->er_regex, url, 8, matches, 0))
      break;

  if(er == NULL) {
    hts_mutex_unlock(&route_mutex);
    return 1;
  }

  es_resource_retain(&er->super);

  es_context_t *ec = er->super.er_ctx;

  hts_mutex_unlock(&route_mutex);

  es_context_begin(ec);


  duk_context *ctx = ec->ec_duk;


  es_push_root(ctx, er);

  es_stprop_push(ctx, page);

  duk_push_boolean(ctx, sync);

  int array_idx = duk_push_array(ctx);

  for(int i = 1; i < 8; i++) {
    if(matches[i].rm_so == -1)
      break;

    duk_push_lstring(ctx,
                     url + matches[i].rm_so,
                     matches[i].rm_eo - matches[i].rm_so);
    duk_put_prop_index(ctx, array_idx, i-1);
  }

  int rc = duk_pcall(ctx, 3);
  if(rc) {
    if(duk_is_string(ctx, -1)) {
      nav_open_error(page, duk_to_string(ctx, -1));
    } else {
      duk_get_prop_string(ctx, -1, "message");
      nav_open_error(page, duk_to_string(ctx, -1));
      duk_pop(ctx);
    }
    es_dump_err(ctx);
  }
  duk_pop(ctx);

  es_context_end(ec);
  es_resource_release(&er->super);

  return 0;
}
Esempio n. 12
0
static int
rpi_codec_create(media_codec_t *mc, const media_codec_params_t *mcp,
		 media_pipe_t *mp)
{
  int fmt;

  switch(mc->codec_id) {

  case CODEC_ID_H264:
    fmt = OMX_VIDEO_CodingAVC;
    break;

  case CODEC_ID_MPEG2VIDEO:
    if(!omx_enable_mpg2)
      return 1;
    fmt = OMX_VIDEO_CodingMPEG2;
    break;

#if 0
  case CODEC_ID_VC1:
  case CODEC_ID_WMV3:
    if(mcp->extradata_size == 0)
      return 1;

    mc->decode = vc1_pt_decode;
    return 0;
#endif

  default:
    return 1;
  }

  rpi_video_codec_t *rvc = calloc(1, sizeof(rpi_video_codec_t));

  hts_cond_init(&rvc->rvc_avail_cond, &mp->mp_mutex);

  omx_component_t *d = omx_component_create("OMX.broadcom.video_decode",
					    &mp->mp_mutex,
					    &rvc->rvc_avail_cond);

  if(d == NULL) {
    hts_cond_destroy(&rvc->rvc_avail_cond);
    free(rvc);
    return 1;
  }

  rvc->rvc_decoder = d;

  omx_set_state(d, OMX_StateIdle);

  OMX_VIDEO_PARAM_PORTFORMATTYPE format;
  OMX_INIT_STRUCTURE(format);
  format.nPortIndex = 130; 
  format.eCompressionFormat = fmt;
  omxchk(OMX_SetParameter(d->oc_handle,
			  OMX_IndexParamVideoPortFormat, &format));

  OMX_PARAM_BRCMVIDEODECODEERRORCONCEALMENTTYPE ec;
  OMX_INIT_STRUCTURE(ec);
  ec.bStartWithValidFrame = OMX_FALSE;
  omxchk(OMX_SetParameter(d->oc_handle,
			  OMX_IndexParamBrcmVideoDecodeErrorConcealment, &ec));

  
  OMX_CONFIG_BOOLEANTYPE bt;
  OMX_INIT_STRUCTURE(bt);
  bt.bEnabled = 1;
  omxchk(OMX_SetConfig(d->oc_handle,
		       OMX_IndexParamBrcmInterpolateMissingTimestamps, &bt));
  
  omx_alloc_buffers(d, 130);
  omx_set_state(d, OMX_StateExecuting);

  if(mcp->extradata_size) {

    hts_mutex_lock(&mp->mp_mutex);
    OMX_BUFFERHEADERTYPE *buf = omx_get_buffer_locked(rvc->rvc_decoder);
    hts_mutex_unlock(&mp->mp_mutex);
    buf->nOffset = 0;
    buf->nFilledLen = mcp->extradata_size;
    memcpy(buf->pBuffer, mcp->extradata, buf->nFilledLen);
    buf->nFlags = OMX_BUFFERFLAG_CODECCONFIG;
    omxchk(OMX_EmptyThisBuffer(rvc->rvc_decoder->oc_handle, buf));
  }

  mc->opaque = rvc;
  mc->close  = rpi_codec_close;
  mc->decode = rpi_codec_decode;
  mc->flush  = rpi_codec_flush;
  return 0;
}
Esempio n. 13
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)
      hts_cond_wait(&rpd->rpd_cond, &rpd->rpd_mtx);

    hts_mutex_unlock(&rpd->rpd_mtx);
    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;
}
Esempio n. 14
0
/**
 * Video decoder thread
 */
static void *
vd_thread(void *aux)
{
  video_decoder_t *vd = aux;
  media_pipe_t *mp = vd->vd_mp;
  media_queue_t *mq = &mp->mp_video;
  media_buf_t *mb;
  media_buf_t *cur = NULL;
  media_codec_t *mc, *mc_current = NULL;
  int run = 1;
  int reqsize = -1;
  int size;
  int reinit = 0;

  const media_buf_meta_t *mbm = NULL;

  vd->vd_frame = av_frame_alloc();

  hts_mutex_lock(&mp->mp_mutex);

  while(run) {

    if(mbm != vd->vd_reorder_current) {
      mbm = vd->vd_reorder_current;
      hts_mutex_unlock(&mp->mp_mutex);

      vd->vd_estimated_duration = mbm->mbm_duration;

      video_decoder_set_current_time(vd, mbm->mbm_pts, mbm->mbm_epoch,
				     mbm->mbm_delta);
      hts_mutex_lock(&mp->mp_mutex);
      continue;
    }

    media_buf_t *ctrl = TAILQ_FIRST(&mq->mq_q_ctrl);
    media_buf_t *data = TAILQ_FIRST(&mq->mq_q_data);
    media_buf_t *aux  = TAILQ_FIRST(&mq->mq_q_aux);

    if(ctrl != NULL) {
      TAILQ_REMOVE(&mq->mq_q_ctrl, ctrl, mb_link);
      mb = ctrl;

    } else if(aux != NULL && aux->mb_pts < vd->vd_subpts + 1000000LL) {

      if(vd->vd_hold) {
	hts_cond_wait(&mq->mq_avail, &mp->mp_mutex);
	continue;
      }

      TAILQ_REMOVE(&mq->mq_q_aux, aux, mb_link);
      mb = aux;

    } else if(cur != NULL) {

      if(vd->vd_hold) {
	hts_cond_wait(&mq->mq_avail, &mp->mp_mutex);
	continue;
      }

      mb = cur;
      goto retry_current;
    } else if(data != NULL) {

      if(vd->vd_hold) {
	hts_cond_wait(&mq->mq_avail, &mp->mp_mutex);
	continue;
      }

      TAILQ_REMOVE(&mq->mq_q_data, data, mb_link);
      mp_check_underrun(mp);
      mb = data;

    } else {
      hts_cond_wait(&mq->mq_avail, &mp->mp_mutex);
      continue;
    }


    mq->mq_packets_current--;
    mp->mp_buffer_current -= mb->mb_size;
    mq_update_stats(mp, mq);

    hts_cond_signal(&mp->mp_backpressure);

  retry_current:
    mc = mb->mb_cw;

    if(mb->mb_data_type == MB_VIDEO && mc->decode_locked != NULL) {

      if(mc != mc_current) {
	if(mc_current != NULL)
	  media_codec_deref(mc_current);

	mc_current = media_codec_ref(mc);
	prop_set_int(mq->mq_prop_too_slow, 0);
      }

      size = mb->mb_size;

      mq->mq_no_data_interest = 1;
      if(mc->decode_locked(mc, vd, mq, mb)) {
        cur = mb;
 	hts_cond_wait(&mq->mq_avail, &mp->mp_mutex);
        continue;
      }
      mq->mq_no_data_interest = 0;
      cur = NULL;

      update_vbitrate(mp, mq, size, vd);
      media_buf_free_locked(mp, mb);
      continue;
    }

    hts_mutex_unlock(&mp->mp_mutex);


    switch(mb->mb_data_type) {
    case MB_CTRL_EXIT:
      run = 0;
      break;

    case MB_CTRL_PAUSE:
      vd->vd_hold = 1;
      break;

    case MB_CTRL_PLAY:
      vd->vd_hold = 0;
      break;

    case MB_CTRL_FLUSH:
      if(cur != NULL) {
        media_buf_free_unlocked(mp, cur);
        mq->mq_no_data_interest = 0;
        cur = NULL;
      }
      vd_init_timings(vd);
      vd->vd_interlaced = 0;

      hts_mutex_lock(&mp->mp_overlay_mutex);
      video_overlay_flush_locked(mp, 1);
      dvdspu_flush_locked(mp);
      hts_mutex_unlock(&mp->mp_overlay_mutex);

      mp->mp_video_frame_deliver(NULL, mp->mp_video_frame_opaque);

      if(mc_current != NULL) {
        mc_current->flush(mc_current, vd);
	media_codec_deref(mc_current);
	mc_current = NULL;
      }

      mp->mp_video_frame_deliver(NULL, mp->mp_video_frame_opaque);
      if(mp->mp_seek_video_done != NULL)
	mp->mp_seek_video_done(mp);
      break;

    case MB_VIDEO:
      if(mc != mc_current) {
	if(mc_current != NULL)
	  media_codec_deref(mc_current);

	mc_current = media_codec_ref(mc);
	prop_set_int(mq->mq_prop_too_slow, 0);
      }

      if(reinit) {
	if(mc->reinit != NULL)
	  mc->reinit(mc);
	reinit = 0;
      }

      size = mb->mb_size;

      mc->decode(mc, vd, mq, mb, reqsize);
      update_vbitrate(mp, mq, size, vd);
      reqsize = -1;
      break;

    case MB_CTRL_REQ_OUTPUT_SIZE:
      reqsize = mb->mb_data32;
      break;

    case MB_CTRL_REINITIALIZE:
      reinit = 1;
      break;

    case MB_CTRL_RECONFIGURE:
      mb->mb_cw->reconfigure(mc, mb->mb_frame_info);
      break;

#if ENABLE_DVD
    case MB_DVD_RESET_SPU:
      hts_mutex_lock(&mp->mp_overlay_mutex);
      vd->vd_spu_curbut = 1;
      dvdspu_flush_locked(mp);
      hts_mutex_unlock(&mp->mp_overlay_mutex);
      break;

    case MB_CTRL_DVD_HILITE:
      vd->vd_spu_curbut = mb->mb_data32;
      vd->vd_spu_repaint = 1;
      break;

    case MB_DVD_PCI:
      memcpy(&vd->vd_pci, mb->mb_data, sizeof(pci_t));
      vd->vd_spu_repaint = 1;
      event_payload_t *ep =
        event_create(EVENT_DVD_PCI, sizeof(event_t) + sizeof(pci_t));
      memcpy(ep->payload, mb->mb_data, sizeof(pci_t));
      mp_enqueue_event(mp, &ep->h);
      event_release(&ep->h);
      break;

    case MB_DVD_CLUT:
      dvdspu_decode_clut(vd->vd_dvd_clut, (void *)mb->mb_data);
      break;

    case MB_DVD_SPU:
      dvdspu_enqueue(mp, mb->mb_data, mb->mb_size, 
		     vd->vd_dvd_clut, 0, 0, mb->mb_pts);
      break;
#endif

    case MB_CTRL_DVD_SPU2:
      dvdspu_enqueue(mp, mb->mb_data+72, mb->mb_size-72,
		     (void *)mb->mb_data,
		     ((const uint32_t *)mb->mb_data)[16],
		     ((const uint32_t *)mb->mb_data)[17],
		     mb->mb_pts);
      break;
      


    case MB_SUBTITLE:
      if(vd->vd_ext_subtitles == NULL && mb->mb_stream == mq->mq_stream2)
	video_overlay_decode(mp, mb);
      break;

    case MB_CTRL_FLUSH_SUBTITLES:
      hts_mutex_lock(&mp->mp_overlay_mutex);
      video_overlay_flush_locked(mp, 1);
      hts_mutex_unlock(&mp->mp_overlay_mutex);
      break;

    case MB_CTRL_EXT_SUBTITLE:
      if(vd->vd_ext_subtitles != NULL)
         subtitles_destroy(vd->vd_ext_subtitles);

      // Steal subtitle from the media_buf
      vd->vd_ext_subtitles = (void *)mb->mb_data;
      mb->mb_data = NULL;
      hts_mutex_lock(&mp->mp_overlay_mutex);
      video_overlay_flush_locked(mp, 1);
      hts_mutex_unlock(&mp->mp_overlay_mutex);
      break;

    default:
      abort();
    }

    hts_mutex_lock(&mp->mp_mutex);
    media_buf_free_locked(mp, mb);
  }

  if(cur != NULL)
    media_buf_free_locked(mp, cur);

  mq->mq_no_data_interest = 0;

  hts_mutex_unlock(&mp->mp_mutex);

  if(mc_current != NULL)
    media_codec_deref(mc_current);

  if(vd->vd_ext_subtitles != NULL)
    subtitles_destroy(vd->vd_ext_subtitles);

  av_frame_free(&vd->vd_frame);
  return NULL;
}
Esempio n. 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;
}
Esempio n. 16
0
/**
 * Decode subtitles from LAVC
 */
static void
video_subtitles_decode_lavc(video_decoder_t *vd, media_buf_t *mb,
			    AVCodecContext *ctx)
{
  AVSubtitle sub;
  int size = 0, i, x, y;
  subtitle_t *s;

  AVPacket avpkt;
  av_init_packet(&avpkt);
  avpkt.data = mb->mb_data;
  avpkt.size = mb->mb_size;

  if(avcodec_decode_subtitle2(ctx, &sub, &size, &avpkt) < 1 || size < 1) 
    return;

  s = malloc(sizeof(subtitle_t) + sizeof(subtitle_rect_t) * sub.num_rects);

  s->s_active = 0;
  s->s_text = NULL;
  s->s_start = mb->mb_pts + sub.start_display_time * 1000;
  s->s_stop  = mb->mb_pts + sub.end_display_time * 1000;
  s->s_num_rects = sub.num_rects;

  for(i = 0; i < sub.num_rects; i++) {
    AVSubtitleRect *r = sub.rects[i];
    subtitle_rect_t *sr = &s->s_rects[i];

    switch(r->type) {

    case SUBTITLE_BITMAP:
      sr->x = r->x;
      sr->y = r->y;
      sr->w = r->w;
      sr->h = r->h;

      const uint8_t *src = r->pict.data[0];
      const uint32_t *clut = (uint32_t *)r->pict.data[1];

      sr->bitmap = malloc(4 * r->w * r->h);
      uint32_t *dst = (uint32_t *)sr->bitmap;
      
      for(y = 0; y < r->h; y++) {
	for(x = 0; x < r->w; x++) {
	  *dst++ = clut[src[x]];
	}
	src += r->pict.linesize[0];
      }
      break;

    default:
      sr->x = 0;
      sr->y = 0;
      sr->w = 0;
      sr->h = 0;
      sr->bitmap = NULL;
      break;
    }
  }

  hts_mutex_lock(&vd->vd_sub_mutex);
  TAILQ_INSERT_TAIL(&vd->vd_sub_queue, s, s_link);
  hts_mutex_unlock(&vd->vd_sub_mutex);
}
Esempio n. 17
0
static void
gu_enter(void)
{
    hts_mutex_lock(&gu_mutex);
}
Esempio n. 18
0
static int
pulseaudio_audio_deliver(audio_decoder_t *ad, int samples,
			 int64_t pts, int epoch)
{
  decoder_t *d = (decoder_t *)ad;
  size_t bytes;

  if(ad->ad_spdif_muxer != NULL) {
    bytes = ad->ad_spdif_frame_size;
  } else {
    bytes = samples * d->framesize;
  }

  void *buf;
  assert(d->s != NULL);

  pa_threaded_mainloop_lock(mainloop);

  int writable = pa_stream_writable_size(d->s);
  if(writable == 0) {
    d->blocked = 1;
    pa_threaded_mainloop_unlock(mainloop);
    return 1; 
  }

  pa_stream_begin_write(d->s, &buf, &bytes);
  assert(bytes > 0);

  if(ad->ad_spdif_muxer != NULL) {
    memcpy(buf, ad->ad_spdif_frame, ad->ad_spdif_frame_size);
  } else {
    int rsamples = bytes / d->framesize;
    uint8_t *data[8] = {0};
    data[0] = (uint8_t *)buf;
    assert(rsamples <= samples);
    avresample_read(ad->ad_avr, data, rsamples);
  }

  if(pts != AV_NOPTS_VALUE) {

    media_pipe_t *mp = ad->ad_mp;
    hts_mutex_lock(&mp->mp_clock_mutex);

    const pa_timing_info *ti = pa_stream_get_timing_info(d->s);
    if(ti != NULL) {
      mp->mp_audio_clock_avtime = 
	ti->timestamp.tv_sec * 1000000LL + ti->timestamp.tv_usec;

      int64_t busec = pa_bytes_to_usec(ti->write_index - ti->read_index,
				       &d->ss);

      int64_t delay = ti->sink_usec + busec + ti->transport_usec;
      mp->mp_audio_clock = pts - delay;
      mp->mp_audio_clock_epoch = epoch;
    }
    hts_mutex_unlock(&mp->mp_clock_mutex);
  }

  pa_stream_write(d->s, buf, bytes, NULL, 0LL, PA_SEEK_RELATIVE);
  ad->ad_spdif_frame_size = 0;

  pa_threaded_mainloop_unlock(mainloop);
  return 0;
}
Esempio n. 19
0
static void
picture_out(vdec_decoder_t *vdd)
{
  int r;
  uint32_t addr;
  vdec_picture_format picfmt;
  vdec_pic_t *vp;
  char metainfo[64];
  pktmeta_t *pm;

  picfmt.alpha = 0;
  picfmt.format_type = VDEC_PICFMT_YUV420P;
  picfmt.color_matrix = VDEC_COLOR_MATRIX_BT709;

  r = vdec_get_pic_item(vdd->handle, &addr);
  if(r != 0)
    return;


  vdec_picture *pi = (void *)(intptr_t)addr;

  pm = &vdd->pktmeta[pi->userdata[0]];

  vdd->pending_flush |= pm->flush;

  if(/* pi->status != 0 ||*/ pi->attr != 0 || pm->skip) {
    vdec_get_picture(vdd->handle, &picfmt, NULL);
    reset_active_pictures(vdd, pm->skip ? "Skip" : "Error", 0);
    return;
  }

  if(vdd->pending_flush) {
    reset_active_pictures(vdd, "stream flush", 0);
    vdd->pending_flush = 0;
    vdd->max_order = -1;
  }

  int64_t pts = pm->nopts ? AV_NOPTS_VALUE : 
    pi->pts[0].low + ((uint64_t)pi->pts[0].hi << 32);

  int64_t dts = pm->nodts ? AV_NOPTS_VALUE : 
    pi->dts[0].low + ((uint64_t)pi->dts[0].hi << 32);
  int64_t order;

  if(pi->codec_type == VDEC_CODEC_TYPE_MPEG2) {
    vdec_mpeg2_info *mpeg2 = (void *)(intptr_t)pi->codec_specific_addr;

    vp = alloc_picture(vdd, mpeg2->width, mpeg2->height);

    vp->fi.fi_width = mpeg2->width;
    vp->fi.fi_height = mpeg2->height;
    vp->fi.fi_duration = mpeg2->frame_rate <= 8 ? 
      mpeg_durations[mpeg2->frame_rate] : 40000;

    if(pm->disable_deinterlacer) {
      vp->fi.fi_interlaced = 0;
    } else {
      vp->fi.fi_interlaced = !mpeg2->progressive_frame;
      vp->fi.fi_tff = mpeg2->top_field_first;
    }

    if(mpeg2->color_description)
      vp->fi.fi_color_space = mpeg2->matrix_coefficients;

    switch(pm->aspect_override) {

    default:
      switch(mpeg2->aspect_ratio) {
      case VDEC_MPEG2_ARI_SAR_1_1:
	vp->fi.fi_dar_num = mpeg2->width;
	vp->fi.fi_dar_den = mpeg2->height;
	break;
      case VDEC_MPEG2_ARI_DAR_4_3:
	vp->fi.fi_dar_num = 4;
	vp->fi.fi_dar_den = 3;
	break;
      case VDEC_MPEG2_ARI_DAR_16_9:
	vp->fi.fi_dar_num = 16;
	vp->fi.fi_dar_den = 9;
	break;
      case VDEC_MPEG2_ARI_DAR_2P21_1:
	vp->fi.fi_dar_num = 221;
	vp->fi.fi_dar_den = 100;
	break;
      }
      break;
    case 1:
      vp->fi.fi_dar_num = 4;
      vp->fi.fi_dar_den = 3;
      break;
    case 2:
      vp->fi.fi_dar_num = 16;
      vp->fi.fi_dar_den = 9;
      break;
    }

    snprintf(metainfo, sizeof(metainfo),
	     "MPEG2 %dx%d%c (Cell)",
	     mpeg2->width, mpeg2->height, vp->fi.fi_interlaced ? 'i' : 'p');

    if(pts == AV_NOPTS_VALUE && dts != AV_NOPTS_VALUE &&
       mpeg2->picture_coding_type[0] == 3)
      pts = dts;

#if VDEC_DETAILED_DEBUG
    TRACE(TRACE_DEBUG, "VDEC DEC", "%ld %d",
	  pts,
	  mpeg2->picture_coding_type[0]);
#endif

    order = vdd->order_base;
    vdd->order_base++;

  } else {
    vdec_h264_info *h264 = (void *)(intptr_t)pi->codec_specific_addr;

    vp = alloc_picture(vdd, h264->width, h264->height);

    vp->fi.fi_width = h264->width - vdd->crop_right;
    vp->fi.fi_height = h264->height - vdd->crop_bottom;

    vp->fi.fi_duration = h264->frame_rate <= 7 ? 
      mpeg_durations[h264->frame_rate + 1] : 40000;


    switch(h264->pic_struct) {
    default:
    case 0:
      vp->fi.fi_interlaced = 0;
      vp->fi.fi_tff = 0;
      break;
    case 3: // top field + bottom field
      vp->fi.fi_interlaced = 1;
      vp->fi.fi_tff = 1;
      break;
    case 4: // bottom field + top field
      vp->fi.fi_interlaced = 1;
      vp->fi.fi_tff = 0;
      break;
    }

    if(h264->color_description_present_flag)
      vp->fi.fi_color_space = h264->matrix_coefficients;

    vp->fi.fi_dar_num = h264->width;
    vp->fi.fi_dar_den = h264->height;

    if(h264->aspect_ratio_idc == 0xff) {
      vp->fi.fi_dar_num *= h264->sar_width;
      vp->fi.fi_dar_den *= h264->sar_height;
    } else {
      const uint8_t *p;
      p = h264_sar[h264->aspect_ratio_idc <= 16 ? h264->aspect_ratio_idc : 0];
      vp->fi.fi_dar_num *= p[0];
      vp->fi.fi_dar_den *= p[1];
    }

    if(h264->idr_picture_flag) {
      vdd->order_base += 0x100000000LL;
      vdd->poc_ext = 0;
    }

    uint32_t om = h264->pic_order_count[0] & 0x7fff;

    int p = om >> 13;
    if(p == ((vdd->poc_ext + 1) & 3)) {
      vdd->poc_ext = p;
      if(p == 0)
	vdd->order_base += 0x100000000LL;
    }

    if(p == 3 && vdd->poc_ext == 0) {
      order = vdd->order_base + om - 0x100000000LL;
    } else {
      order = vdd->order_base + om;
    }

    if(pts == AV_NOPTS_VALUE && dts != AV_NOPTS_VALUE) {
      if(h264->picture_type[0] == 2) {
	vdd->seen_b_frames = 100;
	pts = dts;
      }

      if(vdd->seen_b_frames)
	vdd->seen_b_frames--;

      if(!vdd->seen_b_frames)
	pts = dts;
    }

#if VDEC_DETAILED_DEBUG
    TRACE(TRACE_DEBUG, "VDEC DEC", "POC=%3d:%-3d IDR=%d PS=%d LD=%d %x 0x%llx %ld %d %d",
	  (uint16_t)h264->pic_order_count[0],
	  (uint16_t)h264->pic_order_count[1],
	  h264->idr_picture_flag,
	  h264->pic_struct,
	  h264->low_delay_hrd_flag,
	  h264->nalUnitPresentFlags,
	  order,
	  pts,
	  h264->picture_type[0],
          h264->frame_mbs_only_flag);
#endif

    if(vdd->level_major)
      snprintf(metainfo, sizeof(metainfo),
	       "h264 (Level %d.%d) %dx%d%c (Cell)",
	       vdd->level_major, vdd->level_minor,
	       h264->width, h264->height, vp->fi.fi_interlaced ? 'i' : 'p');
    else
      snprintf(metainfo, sizeof(metainfo),
	       "h264 %dx%d%c (Cell)",
	       h264->width, h264->height, vp->fi.fi_interlaced ? 'i' : 'p');

  }

  prop_set_string(vdd->metainfo, metainfo);

  vp->fi.fi_pix_fmt = AV_PIX_FMT_YUV420P;
  vp->fi.fi_pts = pts;
  
  vp->fi.fi_epoch = pm->epoch;
  vp->fi.fi_prescaled = 0;
  vp->fi.fi_color_space = COLOR_SPACE_UNSET;
  vp->fi.fi_user_time = pm->user_time;
  vp->fi.fi_drive_clock = pm->drive_clock;

  vdec_get_picture(vdd->handle, &picfmt, rsx_to_ppu(vp->vp_offset[0]));

  vp->order = order;

  hts_mutex_lock(&vdd->mtx);

  LIST_INSERT_SORTED(&vdd->pictures, vp, link, vp_cmp, vdec_pic_t);
  vdd->num_pictures++;
  if(vdd->max_order != -1) {
    if(vp->order > vdd->max_order) {
      vdd->flush_to = vdd->max_order;
      vdd->max_order = vp->order;
    }
  } else {
    vdd->max_order = vp->order;
  }
  hts_mutex_unlock(&vdd->mtx);

}
Esempio n. 20
0
static image_t *
fa_image_from_video(const char *url0, const image_meta_t *im,
		    char *errbuf, size_t errlen, int *cache_control,
		    cancellable_t *c)
{
  static char *stated_url;
  static fa_stat_t fs;
  time_t stattime = 0;
  time_t mtime = 0;
  image_t *img = NULL;
  char cacheid[512];
  char *url = mystrdupa(url0);
  char *tim = strchr(url, '#');
  const char *siz;
  *tim++ = 0;
  int secs;

  if(!strcmp(tim, "cover"))
    secs = -1;
  else
    secs = atoi(tim);

  hts_mutex_lock(&image_from_video_mutex[0]);

  if(strcmp(url, stated_url ?: "")) {
    free(stated_url);
    stated_url = NULL;
    if(fa_stat(url, &fs, errbuf, errlen)) {
      hts_mutex_unlock(&image_from_video_mutex[0]);
      return NULL;
    }
    stated_url = strdup(url);
  }
  stattime = fs.fs_mtime;
  hts_mutex_unlock(&image_from_video_mutex[0]);

  if(im->im_req_width < 100 && im->im_req_height < 100) {
    siz = "min";
  } else if(im->im_req_width < 200 && im->im_req_height < 200) {
    siz = "mid";
  } else {
    siz = "max";
  }

  snprintf(cacheid, sizeof(cacheid), "%s-%s", url0, siz);
  buf_t *b = blobcache_get(cacheid, "videothumb", 0, 0, NULL, &mtime);
  if(b != NULL && mtime == stattime) {
    img = image_coded_create_from_buf(b, IMAGE_JPEG);
    buf_release(b);
    return img;
  }
  buf_release(b);

  if(ONLY_CACHED(cache_control)) {
    snprintf(errbuf, errlen, "Not cached");
    return NULL;
  }

  hts_mutex_lock(&image_from_video_mutex[1]);
  img = fa_image_from_video2(url, im, cacheid, errbuf, errlen,
                             secs, stattime, c);
  hts_mutex_unlock(&image_from_video_mutex[1]);
  if(img != NULL)
    img->im_flags |= IMAGE_ADAPTED;
  return img;
}
Esempio n. 21
0
static void
blobcache_prune(void)
{
  DIR *d1, *d2;
  struct dirent *de1, *de2;
  char path[PATH_MAX];
  char path2[PATH_MAX];
  char path3[PATH_MAX];
  struct stat st;
  
  uint64_t tsize = 0, msize;
  int files = 0;
  struct cachfile_list list;

  snprintf(path, sizeof(path), "%s/blobcache", showtime_cache_path);

  if((d1 = opendir(path)) == NULL)
    return;

  LIST_INIT(&list);

  while((de1 = readdir(d1)) != NULL) {
    if(de1->d_name[0] != '.') {
      snprintf(path2, sizeof(path2), "%s/blobcache/%s",
	       showtime_cache_path, de1->d_name);

      if((d2 = opendir(path2)) != NULL) {
	while((de2 = readdir(d2)) != NULL) {
          if(de2->d_name[0] != '.') {

	    snprintf(path3, sizeof(path3), "%s/blobcache/%s/%s",
		     showtime_cache_path, de1->d_name,
		     de2->d_name);
	    
	    if(!stat(path3, &st)) {
	      addfile(&list, de1->d_name, de2->d_name, &st);
	      files++;
	      tsize += st.st_size;
	    }
	  }
	}
	closedir(d2);
      }
    }
  }
  closedir(d1);
  
  msize = blobcache_compute_size(tsize);
  
  if(files > 0) {
    struct cachefile **v, *c, *next;
    int i;

    time_t now;
    time(&now);

    for(c = LIST_FIRST(&list); c != NULL; c = next) {
      next = LIST_NEXT(c, link);

      digest_to_path(c->d, path, sizeof(path));
      int fd = open(path, O_RDONLY, 0);
      if(fd != -1) {
	uint8_t buf[4];
	
	if(read(fd, buf, 4) == 4) {
	  time_t exp = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];

	  if(exp < now) {
	    tsize -= c->size;
	    files--;
	    unlink(path);
	    LIST_REMOVE(c, link);
	    free(c);
	  }
	}
	close(fd);
      }
    }

    v = malloc(sizeof(struct cachfile_list *) * files);
    i = 0;
    LIST_FOREACH(c, &list, link)
      v[i++] = c;

    assert(i == files);

    qsort(v, files, sizeof(struct cachfile_list *), cfcmp);

    for(i = 0; i < files; i++) {
      c = v[i];
    
      if(tsize > msize) {
	digest_to_path(c->d, path, sizeof(path));
	if(!unlink(path))
	  tsize -= c->size;
      }
      free(c);
    }
    free(v);
  }


  hts_mutex_lock(&blobcache_mutex);

  blobcache_size_max = msize;
  blobcache_size_current = tsize;

  TRACE(TRACE_DEBUG, "blobcache", "Using %lld MB out of %lld MB",
	blobcache_size_current / 1000000LL, 
	blobcache_size_max     / 1000000LL);

  hts_mutex_unlock(&blobcache_mutex);
}
Esempio n. 22
0
/**
 * Video decoder thread
 */
static void *
vd_thread(void *aux)
{
  video_decoder_t *vd = aux;
  media_pipe_t *mp = vd->vd_mp;
  media_queue_t *mq = &mp->mp_video;
  media_buf_t *mb;
  media_codec_t *mc;
  int run = 1;
  int reqsize = -1;
  int reinit = 0;
  int size;
  vd->vd_frame = avcodec_alloc_frame();

  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_VIDEO && vd->vd_hold && 
       vd->vd_skip == 0 && 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);

    mc = mb->mb_cw;

    switch(mb->mb_data_type) {
    case MB_CTRL_EXIT:
      run = 0;
      break;

    case MB_CTRL_PAUSE:
      vd->vd_hold = 1;
      break;

    case MB_CTRL_PLAY:
      vd->vd_hold = 0;
      break;

    case MB_FLUSH:
      vd_init_timings(vd);
      vd->vd_do_flush = 1;
      vd->vd_interlaced = 0;
      video_overlay_flush(vd, 1);
      dvdspu_flush(vd);
      break;

    case MB_VIDEO:
      if(reinit) {
	reinit = 0;
	if(mc->reinit != NULL)
	  mc->reinit(mc);
      }

      if(mb->mb_skip == 2)
	vd->vd_skip = 1;

      size = mb->mb_size;

      if(mc->decode)
	mc->decode(mc, vd, mq, mb, reqsize);
      else
	vd_decode_video(vd, mq, mb);

      update_vbitrate(mp, mq, size, vd);
      reqsize = -1;
      break;

    case MB_REQ_OUTPUT_SIZE:
      reqsize = mb->mb_data32;
      break;

    case MB_REINITIALIZE:
      reinit = 1;
      break;

#if ENABLE_DVD
    case MB_DVD_RESET_SPU:
      vd->vd_spu_curbut = 1;
      dvdspu_flush(vd);
      break;

    case MB_DVD_HILITE:
      vd->vd_spu_curbut = mb->mb_data32;
      vd->vd_spu_repaint = 1;
      break;

    case MB_DVD_PCI:
      memcpy(&vd->vd_pci, mb->mb_data, sizeof(pci_t));
      vd->vd_spu_repaint = 1;
      event_t *e = event_create(EVENT_DVD_PCI, sizeof(event_t) + sizeof(pci_t));
      memcpy(e->e_payload, mb->mb_data, sizeof(pci_t));
      mp_enqueue_event(mp, e);
      event_release(e);
      break;

    case MB_DVD_CLUT:
      dvdspu_decode_clut(vd->vd_dvd_clut, mb->mb_data);
      break;

    case MB_DVD_SPU:
      dvdspu_enqueue(vd, mb->mb_data, mb->mb_size, 
		     vd->vd_dvd_clut, 0, 0, mb->mb_pts);
      break;
#endif

    case MB_DVD_SPU2:
      dvdspu_enqueue(vd, mb->mb_data+72, mb->mb_size-72,
		     mb->mb_data,
		     ((const uint32_t *)mb->mb_data)[16],
		     ((const uint32_t *)mb->mb_data)[17],
		     mb->mb_pts);
      break;
      


    case MB_SUBTITLE:
      if(vd->vd_ext_subtitles == NULL && mb->mb_stream == mq->mq_stream2)
	video_overlay_decode(vd, mb);
      break;

    case MB_END:
      break;

    case MB_BLACKOUT:
      vd->vd_frame_deliver(FRAME_BUFFER_TYPE_BLACKOUT, NULL, NULL,
			   vd->vd_opaque);
      break;

    case MB_FLUSH_SUBTITLES:
      video_overlay_flush(vd, 1);
      break;

    case MB_EXT_SUBTITLE:
      if(vd->vd_ext_subtitles != NULL)
         subtitles_destroy(vd->vd_ext_subtitles);

      // Steal subtitle from the media_buf
      vd->vd_ext_subtitles = mb->mb_data;
      mb->mb_data = NULL; 
      video_overlay_flush(vd, 1);
      break;

    default:
      abort();
    }

    hts_mutex_lock(&mp->mp_mutex);
    media_buf_free_locked(mp, mb);
  }

  hts_mutex_unlock(&mp->mp_mutex);

  if(vd->vd_ext_subtitles != NULL)
    subtitles_destroy(vd->vd_ext_subtitles);

  /* Free ffmpeg frame */
  av_free(vd->vd_frame);
  return NULL;
}
Esempio n. 23
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;

  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_freeze_tail = 1;
    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(mb->mb_stream != mq->mq_stream)
	break;

      ad_decode_buf(ad, mp, mq, mb);
      break;

    case MB_END:
      mp_set_current_time(mp, AV_NOPTS_VALUE);
      break;

    default:
      abort();
    }
    hts_mutex_lock(&mp->mp_mutex);
    mq->mq_freeze_tail = 0;
    media_buf_free_locked(mp, mb);
  }
  hts_mutex_unlock(&mp->mp_mutex);
  audio_fifo_purge(thefifo, ad, NULL);
  return NULL;
}
Esempio n. 24
0
static void
sunxi_set_bg(const char *path)
{
  char errbuf[128];
  image_meta_t im = {0};
  unsigned long args[4] = {0};
  pixmap_t *pm;
  int width = 1280, height = 720;
  int r;

  return;

  // hum
  im.im_req_width  = width;
  im.im_req_height = height;

  rstr_t *rpath = rstr_alloc(path);

  pm = backend_imageloader(rpath, &im, NULL, errbuf, sizeof(errbuf),
			   NULL, NULL, NULL);
  rstr_release(rpath);

  if(pm == NULL) {
    TRACE(TRACE_ERROR, "BG", "Unable to load %s -- %s", path, errbuf);
    return;
  }

  int bpp;

  switch(pm->pm_type) {
  case PIXMAP_RGB24:
    bpp = 3;
    break;
  case PIXMAP_BGR32:
    bpp = 4;
    break;
  default:
    abort();
  }


  size_t tsize = pm->pm_height * pm->pm_linesize;

  hts_mutex_lock(&sunxi.gfxmem_mutex);
  uint8_t *dst = tlsf_memalign(sunxi.gfxmem, 1024, tsize);
  hts_mutex_unlock(&sunxi.gfxmem_mutex);
  memcpy(dst, pm->pm_pixels, tsize);

  pixmap_release(pm);

  __disp_video_fb_t   frmbuf;
  memset(&frmbuf, 0, sizeof(__disp_video_fb_t));
  frmbuf.addr[0] = va_to_pa(dst);
  frmbuf.addr[1] = va_to_pa(dst);
  frmbuf.addr[2] = va_to_pa(dst);

  args[1] = DISP_LAYER_WORK_MODE_NORMAL;
  int hlay = ioctl(sunxi.dispfd, DISP_CMD_LAYER_REQUEST, args);
  if(hlay == -1)
    exit(3);

  __disp_layer_info_t l;
  memset(&l, 0, sizeof(l));
    
  l.mode = DISP_LAYER_WORK_MODE_NORMAL;
  l.pipe = 1;

  l.fb.size.width  = pm->pm_linesize / bpp;
  l.fb.size.height = pm->pm_height;
  l.fb.addr[0] = frmbuf.addr[0];
  l.fb.addr[1] = frmbuf.addr[1];
  l.fb.addr[2] = frmbuf.addr[2];

  switch(pm->pm_type) {
  case PIXMAP_RGB24:
    l.fb.format = DISP_FORMAT_RGB888;
    l.fb.br_swap       = 1;
    l.fb.mode  = DISP_MOD_INTERLEAVED;
    break;
  case PIXMAP_BGR32:
    l.fb.format = DISP_FORMAT_ARGB8888;
    l.fb.br_swap       = 1;
    l.fb.mode  = DISP_MOD_INTERLEAVED;
    break;
  default:
    abort();
  }

  ///  l.fb.seq   = 0;
  //  l.fb.mode   = DISP_MOD_NON_MB_PLANAR;
  //  l.fb.format = DISP_FORMAT_YUV420;

  l.ck_enable        = 0;
  l.alpha_en         = 1;
  l.alpha_val        = 0;
  l.src_win.x        = 0;
  l.src_win.y        = 0;
  l.src_win.width    = width;
  l.src_win.height   = height;
  l.scn_win.x        = 0;
  l.scn_win.y        = 0;
  l.scn_win.width    = width;
  l.scn_win.height   = height;
    
  args[1] = hlay;
  args[2] = (__u32)&l;
  args[3] = 0;
  r = ioctl(sunxi.dispfd,DISP_CMD_LAYER_SET_PARA,(void*)args);
  if(r)
    perror("ioctl(disphd,DISP_CMD_LAYER_SET_PARA)");
 
  args[1] = hlay;
  args[2] = 0;
  r = ioctl(sunxi.dispfd,DISP_CMD_LAYER_OPEN,(void*)args);
  if(r)
    perror("ioctl(disphd,DISP_CMD_LAYER_OPEN)");

  bg_open = 1;

  args[1] = hlay;
  if(ioctl(sunxi.dispfd, DISP_CMD_LAYER_BOTTOM, args))
    perror("ioctl(disphd,DISP_CMD_LAYER_BOTTOM)");

  bg_layer = hlay;
}
Esempio n. 25
0
void *
audio_decode_thread(void *aux)
{
  audio_decoder_t *ad = aux;
  const audio_class_t *ac = ad->ad_ac;
  int run = 1;
  media_pipe_t *mp = ad->ad_mp;
  media_queue_t *mq = &mp->mp_audio;
  media_buf_t *mb;
  int blocked = 0;

  if(ac->ac_init != NULL)
    ac->ac_init(ad);

  ad->ad_discontinuity = 1;

  hts_mutex_lock(&mp->mp_mutex);

  while(run) {

    int avail;
    
    if(ad->ad_spdif_muxer != NULL) {
      avail = ad->ad_spdif_frame_size;
    } else {
      avail = ad->ad_avr != NULL ? avresample_available(ad->ad_avr) : 0;
    }
    media_buf_t *data = TAILQ_FIRST(&mq->mq_q_data);
    media_buf_t *ctrl = TAILQ_FIRST(&mq->mq_q_ctrl);

    if(avail >= ad->ad_tile_size && blocked == 0 && !ad->ad_paused && !ctrl) {
      assert(avail != 0);

      int samples = MIN(ad->ad_tile_size, avail);
      int r;

      if(ac->ac_deliver_locked != NULL) {
        r = ac->ac_deliver_locked(ad, samples, ad->ad_pts, ad->ad_epoch);
        if(r) {
          hts_cond_wait(&mq->mq_avail, &mp->mp_mutex);
          continue;
        }
      } else {
        hts_mutex_unlock(&mp->mp_mutex);
        r = ac->ac_deliver_unlocked(ad, samples, ad->ad_pts, ad->ad_epoch);
        hts_mutex_lock(&mp->mp_mutex);
      }

      if(r) {
	blocked = 1;
      } else {
	ad->ad_pts = AV_NOPTS_VALUE;
      }
      continue;
    }

    if(ctrl != NULL) {
      TAILQ_REMOVE(&mq->mq_q_ctrl, ctrl, mb_link);
      mb = ctrl;
    } else if(data != NULL && avail < ad->ad_tile_size) {
      TAILQ_REMOVE(&mq->mq_q_data, data, mb_link);
      mb = data;
    } else {
      hts_cond_wait(&mq->mq_avail, &mp->mp_mutex);
      continue;
    }

    mq->mq_packets_current--;
    mp->mp_buffer_current -= mb->mb_size;
    mq_update_stats(mp, mq);
    hts_cond_signal(&mp->mp_backpressure);

    if(mb->mb_data_type == MB_CTRL_UNBLOCK) {
      assert(blocked);
      blocked = 0;
    } else if(ad->ad_mode == AUDIO_MODE_CODED && 
	      ac->ac_deliver_coded_locked != NULL &&
	      mb->mb_data_type == MB_AUDIO) {

      ac->ac_deliver_coded_locked(ad, mb->mb_data, mb->mb_size,
				  mb->mb_pts, mb->mb_epoch);

    } else {

      hts_mutex_unlock(&mp->mp_mutex);

      switch(mb->mb_data_type) {
      case MB_AUDIO:
	audio_process_audio(ad, mb);
	break;

      case MB_SET_PROP_STRING:
        prop_set_string(mb->mb_prop, (void *)mb->mb_data);
	break;

      case MB_CTRL_SET_VOLUME_MULTIPLIER:
        ad->ad_vol_scale = mb->mb_float;
	if(ac->ac_set_volume != NULL)
	  ac->ac_set_volume(ad, ad->ad_vol_scale);
        break;

      case MB_CTRL_PAUSE:
	ad->ad_paused = 1;
	if(ac->ac_pause)
	  ac->ac_pause(ad);
	break;

      case MB_CTRL_PLAY:
	ad->ad_paused = 0;
	if(ac->ac_play)
	  ac->ac_play(ad);
	break;

      case MB_CTRL_FLUSH:
        // Reset some error reporting filters
        ad->ad_channel_layout_fail = 0;
        ad->ad_sample_rate_fail = 0;

	if(ac->ac_flush)
	  ac->ac_flush(ad);
	ad->ad_pts = AV_NOPTS_VALUE;

	if(mp->mp_seek_audio_done != NULL)
	  mp->mp_seek_audio_done(mp);
	ad->ad_discontinuity = 1;

	if(ad->ad_avr != NULL) {
	  avresample_read(ad->ad_avr, NULL, avresample_available(ad->ad_avr));
	  assert(avresample_available(ad->ad_avr) == 0);
	}
	break;

      case MB_CTRL_EXIT:
	run = 0;
	break;

      default:
	abort();
      }

      hts_mutex_lock(&mp->mp_mutex);
    }
    media_buf_free_locked(mp, mb);
  }

  hts_mutex_unlock(&mp->mp_mutex);

  if(ac->ac_fini != NULL)
    ac->ac_fini(ad);
  return NULL;
}
Esempio n. 26
0
void
glw_lock(glw_root_t *gr)
{
  hts_mutex_lock(&gr->gr_mutex);
}
Esempio n. 27
0
static void
vda_decode(struct media_codec *mc, struct video_decoder *vd,
	   struct media_queue *mq, struct media_buf *mb, int reqsize)
{
  vda_decoder_t *vdad = mc->opaque;
  CFDictionaryRef user_info;
  CFDataRef coded_frame;
  const int num_kvs = 6;
  CFStringRef keys[num_kvs];
  CFNumberRef values[num_kvs];
  const int keyframe = mb->mb_keyframe;
  const int drive_clock = mb->mb_drive_clock;
  vda_frame_t *vf;
  int i;
  uint8_t skip = mb->mb_skip;

  vdad->vdad_vd = vd;

  coded_frame = CFDataCreate(kCFAllocatorDefault, mb->mb_data, mb->mb_size);


  keys[0] = CFSTR("pts");
  keys[1] = CFSTR("duration");
  keys[2] = CFSTR("keyframe");
  keys[3] = CFSTR("epoch");
  keys[4] = CFSTR("drive_clock");
  keys[5] = CFSTR("skip");

  values[0] = CFNumberCreate(NULL, kCFNumberSInt64Type, &mb->mb_pts);
  values[1] = CFNumberCreate(NULL, kCFNumberSInt32Type, &mb->mb_duration);
  values[2] = CFNumberCreate(NULL, kCFNumberSInt32Type, &keyframe);
  values[3] = CFNumberCreate(NULL, kCFNumberSInt8Type, &mb->mb_epoch);
  values[4] = CFNumberCreate(NULL, kCFNumberSInt8Type, &drive_clock);
  values[5] = CFNumberCreate(NULL, kCFNumberSInt8Type, &skip);

  user_info = CFDictionaryCreate(kCFAllocatorDefault,
				 (const void **)keys,
				 (const void **)values,
				 num_kvs,
				 &kCFTypeDictionaryKeyCallBacks,
				 &kCFTypeDictionaryValueCallBacks);
  for(i = 0; i < num_kvs; i++)
    CFRelease(values[i]);
  uint32_t flags = 0;

  VDADecoderDecode(vdad->vdad_decoder, flags, coded_frame, user_info);
  CFRelease(user_info);
  CFRelease(coded_frame);


  hts_mutex_lock(&vdad->vdad_mutex);

  if(vdad->vdad_flush_to != PTS_UNSET) {
    while((vf = LIST_FIRST(&vdad->vdad_frames)) != NULL) {
      if(vdad->vdad_flush_to < vf->vf_pts)
	break;
      LIST_REMOVE(vf, vf_link);
      hts_mutex_unlock(&vdad->vdad_mutex);
      emit_frame(vdad, vf, mq);
      hts_mutex_lock(&vdad->vdad_mutex);
      CFRelease(vf->vf_buf);
      free(vf);
    }
  }
  hts_mutex_unlock(&vdad->vdad_mutex);
}
Esempio n. 28
0
static htsmsg_t *
htsp_reqreply(htsp_connection_t *hc, htsmsg_t *m)
{
  void *buf;
  size_t len;
  uint32_t seq;
  int r;
  tcpcon_t *tc = hc->hc_tc;
  uint32_t noaccess;
  htsmsg_t *reply;
  htsp_msg_t *hm = NULL;
  int retry = 0;
  char id[100];
  char *username;
  char *password;
  struct AVSHA1 *shactx = alloca(av_sha1_size);
  uint8_t d[20];

  if(tc == NULL)
    return NULL;

  /* Generate a sequence number for our message */
  seq = atomic_add(&hc->hc_seq_generator, 1);
  htsmsg_add_u32(m, "seq", seq);

 again:

  snprintf(id, sizeof(id), "htsp://%s:%d", hc->hc_hostname, hc->hc_port);

  r = keyring_lookup(id, &username, &password, NULL, !!retry,
		     "TV client", "Access denied");

  if(r == -1) {
    /* User rejected */
    return NULL;
  }

  if(r == 0) {
    /* Got auth credentials */
    htsmsg_delete_field(m, "username");
    htsmsg_delete_field(m, "digest");

    if(username != NULL) 
      htsmsg_add_str(m, "username", username);

    if(password != NULL) {
      av_sha1_init(shactx);
      av_sha1_update(shactx, (const uint8_t *)password, strlen(password));
      av_sha1_update(shactx, hc->hc_challenge, 32);
      av_sha1_final(shactx, d);
      htsmsg_add_bin(m, "digest", d, 20);
    }

    free(username);
    free(password);
  }

  
  


  if(htsmsg_binary_serialize(m, &buf, &len, -1) < 0) {
    htsmsg_destroy(m);
    return NULL;
  }

  if(hc->hc_is_async) {
    /* Async, set up a struct that will be signalled when we get a reply */

    hm = malloc(sizeof(htsp_msg_t));
    hm->hm_msg = NULL;
    hm->hm_seq = seq;
    hm->hm_error = 0;
    hts_mutex_lock(&hc->hc_rpc_mutex);
    TAILQ_INSERT_TAIL(&hc->hc_rpc_queue, hm, hm_link);
    hts_mutex_unlock(&hc->hc_rpc_mutex);
  }

  if(tc->write(tc, buf, len)) {
    free(buf);
    htsmsg_destroy(m);
    
    if(hm != NULL) {
      hts_mutex_lock(&hc->hc_rpc_mutex);
      TAILQ_REMOVE(&hc->hc_rpc_queue, hm, hm_link);
      hts_mutex_unlock(&hc->hc_rpc_mutex);
      free(hm);
    }
    return NULL;
  }
  free(buf);


  if(hm != NULL) {
    hts_mutex_lock(&hc->hc_rpc_mutex);
    while(1) {
      if(hm->hm_error != 0) {
	r = hm->hm_error;
	TAILQ_REMOVE(&hc->hc_rpc_queue, hm, hm_link);
	hts_mutex_unlock(&hc->hc_rpc_mutex);
	free(hm);

	htsmsg_destroy(m);
	return NULL;
      }

      if(hm->hm_msg != NULL)
	break;

      hts_cond_wait(&hc->hc_rpc_cond, &hc->hc_rpc_mutex);
    }
      
    TAILQ_REMOVE(&hc->hc_rpc_queue, hm, hm_link);
    hts_mutex_unlock(&hc->hc_rpc_mutex);
    reply = hm->hm_msg;
    free(hm);

  } else {

    if((reply = htsp_recv(hc)) == NULL) {
      htsmsg_destroy(m);
      return NULL;
    }
  }

  
  if(!htsmsg_get_u32(reply, "noaccess", &noaccess) && noaccess) {
    retry++;
    goto again;
  }

  htsmsg_destroy(m); /* Destroy original message */
  return reply;
}