Example #1
0
/**
 * Must be called with mp locked
 */
void
mq_flush(media_pipe_t *mp, media_queue_t *mq, int full)
{
  hts_mutex_lock(&mp->mp_mutex);
  mq_flush_locked(mp, mq, full);
  mp_check_underrun(mp);
  hts_mutex_unlock(&mp->mp_mutex);
}
Example #2
0
void
mp_configure(media_pipe_t *mp, int flags, int buffer_size, int64_t duration,
             const char *type)
{
  hts_mutex_lock(&mp->mp_mutex);

  prop_set_string(mp->mp_prop_playstatus, "play");

  mp->mp_framerate.num = 0;
  mp->mp_framerate.den = 1;

  mp->mp_max_realtime_delay = INT32_MAX;

  mp_set_clr_flags_locked(mp, flags,
                          MP_PRE_BUFFERING |
                          MP_FLUSH_ON_HOLD |
                          MP_ALWAYS_SATISFIED |
                          MP_CAN_SEEK |
                          MP_CAN_PAUSE |
                          MP_CAN_EJECT);

  prop_set(mp->mp_prop_root, "type", PROP_SET_STRING, type);

  switch(buffer_size) {
  case MP_BUFFER_NONE:
    mp->mp_buffer_limit = 0;
    break;

  case MP_BUFFER_SHALLOW:
    mp->mp_buffer_limit = 1 * 1024 * 1024;
    break;

  case MP_BUFFER_DEEP:
    mp->mp_buffer_limit = video_settings.video_buffer_size * 1024 * 1024;
    break;
  }

  prop_set_int(mp->mp_prop_buffer_limit, mp->mp_buffer_limit);
  mp_set_duration(mp, duration);

  if(mp->mp_clock_setup != NULL)
    mp->mp_clock_setup(mp, mp->mp_audio.mq_stream != -1);

  if(mp->mp_flags & MP_PRE_BUFFERING)
    mp_check_underrun(mp);

  hts_mutex_unlock(&mp->mp_mutex);
}
Example #3
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);
      mp_check_underrun(mp);
      mb = data;
      if(mb->mb_dts != PTS_UNSET)
        mq->mq_last_deq_dts = mb->mb_dts;
    } else {
      hts_cond_wait(&mq->mq_avail, &mp->mp_mutex);
      continue;
    }

    mq->mq_packets_current--;
    mp->mp_buffer_current -= mb->mb_size;

    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) {

      if(!mb->mb_skip && mb->mb_stream == mq->mq_stream) {

        int r = ac->ac_deliver_coded_locked(ad, mb->mb_data, mb->mb_size,
                                          mb->mb_pts, mb->mb_epoch);
        if(r) {
          TAILQ_INSERT_HEAD(&mq->mq_q_data, mb, mb_link);
          mq->mq_packets_current++;
          mp->mp_buffer_current += mb->mb_size;

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

        update_abitrate(mp, mq, mb->mb_size, ad);
      }

    } else {

      hts_mutex_unlock(&mp->mp_mutex);

      switch(mb->mb_data_type) {
      case MB_AUDIO:
	if(audio_process_audio(ad, mb)) {
          hts_mutex_lock(&mp->mp_mutex);
          mq->mq_packets_current++;
          mp->mp_buffer_current += mb->mb_size;
          TAILQ_INSERT_HEAD(&mq->mq_q_data, mb, mb_link);
          continue;
        }
	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);
    }
    mq_update_stats(mp, mq, 1);
    hts_cond_signal(&mp->mp_backpressure);
    media_buf_free_locked(mp, mb);
  }

  hts_mutex_unlock(&mp->mp_mutex);

  if(ac->ac_fini != NULL)
    ac->ac_fini(ad);
  return NULL;
}
Example #4
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;
}