Esempio n. 1
0
static void
video_seek(rtmp_t *r, media_pipe_t *mp, media_buf_t **mbp,
	   int64_t pos, const char *txt)
{
  if(pos < 0)
    pos = 0;

  TRACE(TRACE_DEBUG, "Video", "seek %s to %.2f", txt, pos / 1000000.0);
 
  RTMP_SendSeek(r->r, pos / 1000);

  r->seekpos_video = pos;
  r->seekpos_audio = pos;

  mp->mp_video.mq_seektarget = pos;
  mp->mp_audio.mq_seektarget = pos;

  mp_flush(mp);

  if(mbp != NULL && *mbp != NULL) {
    media_buf_free_unlocked(mp, *mbp);
    *mbp = NULL;
  }

  prop_set_float(prop_create(mp->mp_prop_root, "seektime"), pos / 1000000.0);
}
Esempio n. 2
0
static int64_t
video_seek(rtmp_t *r, media_pipe_t *mp, media_buf_t **mbp,
	   int64_t pos, int backward, const char *txt)
{
  if(pos < 0)
    pos = 0;

  TRACE(TRACE_DEBUG, "Video", "seek %s to %.2f", txt, pos / 1000000.0);
 
  RTMP_SendSeek(r->r, pos / 1000);

  r->seekpos = pos;

  mp->mp_video.mq_seektarget = pos;
  mp->mp_audio.mq_seektarget = pos;

  mp_flush(mp, 0);
  
  if(mbp != NULL && *mbp != NULL) {
    media_buf_free(*mbp);
    *mbp = NULL;
  }

  prop_set_float(prop_create(mp->mp_prop_root, "seektime"), pos / 1000000.0);
  r->lastsubpts = AV_NOPTS_VALUE;

  return pos;
}
Esempio n. 3
0
int64_t rtmp_read_seek(LibRTMPContext *ctx, int64_t timestamp)
{
    RTMP *r = &ctx->rtmp;

    if (!RTMP_SendSeek(r, timestamp))
        return ERROR_UNKNOWN;
    return timestamp;
}
Esempio n. 4
0
static int64_t rtmp_read_seek(URLContext *s, int stream_index,
                              int64_t timestamp, int flags)
{
    RTMP *r = s->priv_data;

    if (flags & AVSEEK_FLAG_BYTE)
        return AVERROR(ENOSYS);

    /* seeks are in milliseconds */
    if (stream_index < 0)
        timestamp = av_rescale_rnd(timestamp, 1000, AV_TIME_BASE,
            flags & AVSEEK_FLAG_BACKWARD ? AV_ROUND_DOWN : AV_ROUND_UP);

    if (!RTMP_SendSeek(r, timestamp))
        return -1;
    return timestamp;
}
static gboolean
gst_rtmp_src_do_seek (GstBaseSrc * basesrc, GstSegment * segment)
{
  GstRTMPSrc *src;

  src = GST_RTMP_SRC (basesrc);

  if (segment->format != GST_FORMAT_TIME) {
    GST_LOG_OBJECT (src, "Only time based seeks are supported");
    return FALSE;
  }

  if (!src->rtmp) {
    GST_LOG_OBJECT (src, "Not connected yet");
    return FALSE;
  }

  src->discont = TRUE;

  /* Initial seek */
  if (src->cur_offset == 0 && segment->start == 0)
    return TRUE;

  if (!src->seekable) {
    GST_LOG_OBJECT (src, "Not a seekable stream");
    return FALSE;
  }

  src->last_timestamp = GST_CLOCK_TIME_NONE;
  if (!RTMP_SendSeek (src->rtmp, segment->start / GST_MSECOND)) {
    GST_ERROR_OBJECT (src, "Seeking failed");
    src->seekable = FALSE;
    return FALSE;
  }

  GST_DEBUG_OBJECT (src, "Seek to %" GST_TIME_FORMAT " successfull",
      GST_TIME_ARGS (segment->start));

  return TRUE;
}
Esempio n. 6
0
static event_t *
rtmp_playvideo(const char *url0, media_pipe_t *mp,
	       char *errbuf, size_t errlen,
	       video_queue_t *vq, struct vsource_list *vsl,
	       const video_args_t *va0)
{
  video_args_t va = *va0;
  rtmp_t r = {0};
  event_t *e;
  char *url = mystrdupa(url0);

  mp_set_url(mp, va0->canonical_url, va0->parent_url, va0->parent_title);

  usage_event("Play video", 1, USAGE_SEG("format", "RTMP"));

  prop_set(mp->mp_prop_metadata, "format", PROP_SET_STRING, "RTMP");
  prop_set(mp->mp_prop_root, "loading", PROP_SET_INT, 1);

  va.flags |= BACKEND_VIDEO_NO_FS_SCAN;

  rtmp_log_level = RTMP_LOGINFO;
  RTMP_LogSetLevel(rtmp_log_level);

  r.r = RTMP_Alloc();
  RTMP_Init(r.r, mp->mp_cancellable);

  int64_t start = playinfo_get_restartpos(va.canonical_url, va.title, va.resume_mode);

  if(!RTMP_SetupURL(r.r, url)) {
    snprintf(errbuf, errlen, "Unable to setup RTMP-session");
    rtmp_free(&r);
    return NULL;
  }

  r.r->Link.lFlags |= RTMP_LF_SWFV;

  if(!RTMP_Connect(r.r, NULL, errbuf, errlen, 5000)) {
    rtmp_free(&r);
    return NULL;
  }

  if(!RTMP_ConnectStream(r.r, 0)) {
    snprintf(errbuf, errlen, "Unable to connect RTMP-stream");
    rtmp_free(&r);
    return NULL;
  }

  if(start)
    RTMP_SendSeek(r.r, start);
    
  r.mp = mp;
  
  mp->mp_audio.mq_stream = 0;
  mp->mp_video.mq_stream = 0;

  if(start > 0) {
    r.seekpos_video = start * 1000;
    r.seekpos_audio = start * 1000;
    mp->mp_seek_base = r.seekpos_video;
    mp->mp_video.mq_seektarget = r.seekpos_video;
    mp->mp_audio.mq_seektarget = r.seekpos_video;
  } else {
    mp->mp_video.mq_seektarget = AV_NOPTS_VALUE;
    mp->mp_audio.mq_seektarget = AV_NOPTS_VALUE;
    mp->mp_seek_base = 0;
    r.seekpos_audio = AV_NOPTS_VALUE;
    r.seekpos_video = AV_NOPTS_VALUE;
  }

  mp_configure(mp, MP_CAN_PAUSE, MP_BUFFER_DEEP, 0, "video");
  mp->mp_max_realtime_delay = (r.r->Link.timeout - 1) * 1000000;

  mp_become_primary(mp);

  playinfo_register_play(va.canonical_url, 0);

  r.canonical_url = va.canonical_url;
  r.restartpos_last = -1;

  r.url = url;
  r.va = &va;
  r.is_loading = 1;
  e = rtmp_loop(&r, mp, url, errbuf, errlen);

  if(r.ss)
    sub_scanner_destroy(r.ss);

  if(r.total_duration) {
    int p = mp->mp_seek_base / (r.total_duration * 10);
    if(p >= video_settings.played_threshold) {
      TRACE(TRACE_DEBUG, "RTMP", "Playback reached %d%%, counting as played",
	    p);
      playinfo_register_play(va.canonical_url, 1);
      playinfo_set_restartpos(va.canonical_url, -1, 0);
    } else {
      playinfo_set_restartpos(va.canonical_url, mp->mp_seek_base / 1000, 0);
    }
  }

  mp_shutdown(mp);

  TRACE(TRACE_DEBUG, "RTMP", "End of playback");

  rtmp_free(&r);
  return e;
}
Esempio n. 7
0
static event_t *
rtmp_loop(rtmp_t *r, media_pipe_t *mp, char *url, char *errbuf, size_t errlen)
{
  RTMPPacket p = {0};
  int pos = -1, ret;
  uint32_t dts;
  event_t *e = NULL;

  while(1) {


    if(pos == -1) {

      mp->mp_eof = 0;
      ret = RTMP_GetNextMediaPacket(r->r, &p);

      if(ret == 2) {
	/* Wait for queues to drain */
	mp->mp_eof = 1;
      again:
	e = mp_wait_for_empty_queues(mp);

	if(e != NULL) {
	  e = rtmp_process_event(r, e, NULL);
	  if(e == NULL)
	    goto again;
	}

	if(e == NULL)
	  e = event_create_type(EVENT_EOF);
	break;
      }

      if(ret == 0) {
	int64_t restartpos = r->seekpos_video;

        if(cancellable_is_cancelled(mp->mp_cancellable)) {
          snprintf(errbuf, errlen, "Cancelled");
          return NULL;
        }

	TRACE(TRACE_ERROR, "RTMP", "Disconnected");
	sleep(1);

	if(restartpos == AV_NOPTS_VALUE) {
	  snprintf(errbuf, errlen,
		   "Giving up restart since nothing was decoded");
	  return NULL;
	}


	RTMP_Close(r->r);

	RTMP_Init(r->r, mp->mp_cancellable);

	memset(&p, 0, sizeof(p));

	TRACE(TRACE_DEBUG, "RTMP", "Reconnecting stream at pos %ld", 
	      restartpos);

	if(!RTMP_SetupURL(r->r, url)) {
	  snprintf(errbuf, errlen, "Unable to setup RTMP session");
	  return NULL;
	}

	if(!RTMP_Connect(r->r, NULL, errbuf, errlen, 5000)) {
	  return NULL;
	}

	if(!RTMP_ConnectStream(r->r, 0)) {
	  snprintf(errbuf, errlen, "Unable to stream RTMP session");
	  return NULL;
	}

	if(mp->mp_flags & MP_CAN_SEEK)
	  RTMP_SendSeek(r->r, restartpos / 1000);
	continue;
      }

      dts = p.m_nTimeStamp;

      switch(p.m_packetType) {
      case RTMP_PACKET_TYPE_INFO:
	if(handle_metadata(r, p.m_body, p.m_nBodySize, mp, errbuf, errlen)) {
	  RTMPPacket_Free(&p);
	  return NULL;
	}
	break;

      case RTMP_PACKET_TYPE_VIDEO:
	e = get_packet_v(r, (void *)p.m_body, p.m_nBodySize, dts, mp);
	break;

      case RTMP_PACKET_TYPE_AUDIO:
	e = get_packet_a(r, (void *)p.m_body, p.m_nBodySize, dts, mp);
	break;
	
      case 0x16:
	pos = 0;
	break;
      default:
	TRACE(TRACE_DEBUG, "RTMP", 
	      "Got unknown packet type %d\n", p.m_packetType);
	break;
      }
      if(pos == -1)
	RTMPPacket_Free(&p);
    }

    if(pos != -1) {
      if(pos + 11 < p.m_nBodySize) {
	uint32_t ds = AMF_DecodeInt24(p.m_body + pos + 1);
	  
	if(pos + 11 + ds + 4 > p.m_nBodySize) {
	  snprintf(errbuf, errlen, "Corrupt stream");
	  RTMPPacket_Free(&p);
	  return NULL;
	}

	dts = AMF_DecodeInt24(p.m_body + pos + 4);
	dts |= (p.m_body[pos + 7] << 24);

	if(p.m_body[pos] == RTMP_PACKET_TYPE_INFO) {
	  if(handle_metadata(r, p.m_body, p.m_nBodySize, mp, errbuf, errlen)) {
	    RTMPPacket_Free(&p);
	    return NULL;
	  }
	} else if(p.m_body[pos] == RTMP_PACKET_TYPE_VIDEO) {
	  e = get_packet_v(r, (void *)p.m_body + pos + 11, ds, dts, mp);
	} else if(p.m_body[pos] == RTMP_PACKET_TYPE_AUDIO) {
	  e = get_packet_a(r, (void *)p.m_body + pos + 11, ds, dts, mp);
	} else {
	  TRACE(TRACE_DEBUG, "RTMP", 
		"Got unknown packet type %d\n", p.m_body[pos]);
	}
	pos += 11 + ds + 4;
      } else {
	pos = -1;
	RTMPPacket_Free(&p);
      }
    }
    if(e != NULL)
      break;
  }
  return e;
}
Esempio n. 8
0
static event_t *
rtmp_playvideo(const char *url0, media_pipe_t *mp,
	       char *errbuf, size_t errlen,
	       video_queue_t *vq, struct vsource_list *vsl,
	       const video_args_t *va0)
{
  video_args_t va = *va0;
  rtmp_t r = {0};
  event_t *e;
  char *url = mystrdupa(url0);

  va.flags |= BACKEND_VIDEO_NO_FS_SCAN;

  prop_set_string(mp->mp_prop_type, "video");

  rtmp_log_level = RTMP_LOGINFO;
  RTMP_LogSetLevel(rtmp_log_level);

  r.r = RTMP_Alloc();
  RTMP_Init(r.r);

  int64_t start = 0;

  if(va.flags & BACKEND_VIDEO_RESUME ||
     (video_settings.resume_mode == VIDEO_RESUME_YES &&
      !(va.flags & BACKEND_VIDEO_START_FROM_BEGINNING)))
    start = video_get_restartpos(va.canonical_url);

  if(!RTMP_SetupURL(r.r, url)) {
    snprintf(errbuf, errlen, "Unable to setup RTMP-session");
    rtmp_free(&r);
    return NULL;
  }

  r.r->Link.lFlags |= RTMP_LF_SWFV;

  if(!RTMP_Connect(r.r, NULL)) {
    snprintf(errbuf, errlen, "Unable to connect RTMP-session");
    rtmp_free(&r);
    return NULL;
  }

  if(!RTMP_ConnectStream(r.r, 0)) {
    snprintf(errbuf, errlen, "Unable to connect RTMP-stream");
    rtmp_free(&r);
    return NULL;
  }

  if(start)
    RTMP_SendSeek(r.r, start);
    
  r.mp = mp;
  
  mp->mp_audio.mq_stream = 0;
  mp->mp_video.mq_stream = 0;

  if(start > 0) {
    r.seekpos_video = start * 1000;
    r.seekpos_audio = start * 1000;
    mp->mp_seek_base = r.seekpos_video;
    mp->mp_video.mq_seektarget = r.seekpos_video;
    mp->mp_audio.mq_seektarget = r.seekpos_video;
  } else {
    mp->mp_video.mq_seektarget = AV_NOPTS_VALUE;
    mp->mp_audio.mq_seektarget = AV_NOPTS_VALUE;
    mp->mp_seek_base = 0;
    r.seekpos_audio = AV_NOPTS_VALUE;
    r.seekpos_video = AV_NOPTS_VALUE;
  }

  mp_configure(mp, MP_PLAY_CAPS_PAUSE, MP_BUFFER_DEEP, 0);
  mp->mp_max_realtime_delay = (r.r->Link.timeout - 1) * 1000000;

  mp_become_primary(mp);

  metadb_register_play(va.canonical_url, 0, CONTENT_VIDEO);

  r.canonical_url = va.canonical_url;
  r.restartpos_last = -1;

  sub_scanner_t *ss =
    sub_scanner_create(url, mp->mp_prop_subtitle_tracks, &va, 0);

  e = rtmp_loop(&r, mp, url, errbuf, errlen);

  sub_scanner_destroy(ss);

  if(r.total_duration) {
    int p = mp->mp_seek_base / (r.total_duration * 10);
    if(p >= video_settings.played_threshold) {
      TRACE(TRACE_DEBUG, "RTMP", "Playback reached %d%%, counting as played",
	    p);
      metadb_register_play(va.canonical_url, 1, CONTENT_VIDEO);
      metadb_set_video_restartpos(va.canonical_url, -1);
    }
  }

  mp_flush(mp, 0);
  mp_shutdown(mp);

  TRACE(TRACE_DEBUG, "RTMP", "End of stream");

  rtmp_free(&r);
  return e;
}