Beispiel #1
0
static void
rtsp_cmd_play(RTSPContext *ctx, const char *url, RTSPMessageHeader *h) {
	char path[4096];
	//
	av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path, sizeof(path), url);
	if(strncmp(path, rtspconf->object, strlen(rtspconf->object)) != 0) {
		rtsp_reply_error(ctx, RTSP_STATUS_SESSION);
		return;
	}
	if(strcmp(ctx->session_id, h->session_id) != 0) {
		rtsp_reply_error(ctx, RTSP_STATUS_SESSION);
		return;
	}
	//
	if(ctx->state != SERVER_STATE_READY
	&& ctx->state != SERVER_STATE_PAUSE) {
		rtsp_reply_error(ctx, RTSP_STATUS_STATE);
		return;
	}
	// 2014-05-20: support only shared-encoder model
	if(ff_server_register_client(ctx) < 0) {
		ga_error("cannot register encoder client.\n");
		rtsp_reply_error(ctx, RTSP_STATUS_INTERNAL);
		return;
	}
	//
	ctx->state = SERVER_STATE_PLAYING;
	rtsp_reply_header(ctx, RTSP_STATUS_OK);
	rtsp_printf(ctx, "Session: %s\r\n", ctx->session_id);
	rtsp_printf(ctx, "\r\n");
	return;
}
Beispiel #2
0
static void
rtsp_cmd_pause(RTSPContext *ctx, const char *url, RTSPMessageHeader *h) {
	char path[4096];
	//
	av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path, sizeof(path), url);
	if(strncmp(path, rtspconf->object, strlen(rtspconf->object)) != 0) {
		rtsp_reply_error(ctx, RTSP_STATUS_SESSION);
		return;
	}
	if(strcmp(ctx->session_id, h->session_id) != 0) {
		rtsp_reply_error(ctx, RTSP_STATUS_SESSION);
		return;
	}
	//
	if(ctx->state != SERVER_STATE_PLAYING) {
		rtsp_reply_error(ctx, RTSP_STATUS_STATE);
		return;
	}
	//
	ctx->state = SERVER_STATE_PAUSE;
	rtsp_reply_header(ctx, RTSP_STATUS_OK);
	rtsp_printf(ctx, "Session: %s\r\n", ctx->session_id);
	rtsp_printf(ctx, "\r\n");
	return;
}
Beispiel #3
0
static void
rtsp_cmd_describe(RTSPContext *ctx, const char *url) {
	struct sockaddr_in myaddr;
#ifdef WIN32
	int addrlen;
#else
	socklen_t addrlen;
#endif
	char path[4096];
	char content[4096];
	int content_length;
	//
	av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path, sizeof(path), url);
	if(strcmp(path, rtspconf->object) != 0) {
		rtsp_reply_error(ctx, RTSP_STATUS_SERVICE);
		return;
	}
	//
	addrlen = sizeof(myaddr);
	getsockname(ctx->fd, (struct sockaddr*) &myaddr, &addrlen);
	content_length = prepare_sdp_description(ctx, content, sizeof(content));
	if(content_length < 0) {
		rtsp_reply_error(ctx, RTSP_STATUS_INTERNAL);
		return;
	}
	// state does not change
	rtsp_reply_header(ctx, RTSP_STATUS_OK);
	rtsp_printf(ctx, "Content-Base: %s/\r\n", url);
	rtsp_printf(ctx, "Content-Type: application/sdp\r\n");
	rtsp_printf(ctx, "Content-Length: %d\r\n", content_length);
	rtsp_printf(ctx, "\r\n");
	rtsp_write(ctx, content, content_length);
	return;
}
static void rtsp_cmd_interrupt(RTSPContext *c, const char *url, RTSPMessageHeader *h, int pause_only)
{
  RTSPContext *rtp_c;

  rtp_c = find_rtp_session_with_url(url, h->session_id);
  if (!rtp_c) {
    rtsp_reply_error(c, RTSP_STATUS_SESSION);
    return;
  }

  if (pause_only) {
    if (rtp_c->state != RTPSTATE_SEND_DATA) {
      rtsp_reply_error(c, RTSP_STATUS_STATE);
      return;
    }
    rtp_c->state = HTTPSTATE_READY;
    c->ntp_start_time = 0.0;
  }

  rtsp_reply_header(c, RTSP_STATUS_OK);
  /* session ID */
  avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
  avio_printf(c->pb, "\r\n");

  if (!pause_only)
    close_connection(rtp_c);
}
/* RTSP Handle Function */
static void rtsp_cmd_options(RTSPContext *c, const char *url)
{
  rtsp_reply_header(c, RTSP_STATUS_OK);
  avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
  avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
  avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
  avio_printf(c->pb, "\r\n");
}
static void rtsp_cmd_play(RTSPContext *c, const char *url, RTSPMessageHeader *h)
{
    RTSPContext *rtp_c;

    rtp_c = find_rtp_session_with_url(url, h->session_id);
    if (!rtp_c) {
      printf("can't find rtp session %s with url %s \n", h->session_id, url);
      rtsp_reply_error(c, RTSP_STATUS_SESSION);
      return;
    }

    rtp_c->start_time = cur_time; // set start time
    // pos * 188이 offset!
    int64_t last_offset = rtp_c->cur_offset;
    printf("cmd play! cur_offset = %lld\n", rtp_c->cur_offset);
    if (c->ntp_start_time != 0.0) {
      // set start time for seek! 
      printf("find start time by ntp time!!! seek request! seek time = %lfs \n", c->ntp_start_time);
      rtp_c->ntp_start_time = c->ntp_start_time;
      rtp_c->cur_idx = get_closest_iframe_by_time(rtp_c->stream->first_idx, rtp_c->ntp_start_time);
      if (rtp_c->cur_idx != NULL)
        rtp_c->cur_offset = rtp_c->cur_idx->pos * 188;
      // play time이 바뀐 경우, buffer도 비워줘야 함.
      if (rtp_c->buffer_ptr >= rtp_c->buffer_end) {
        printf("no need to reset rtp_c->buffer ptr \n");
      } else {
        printf("need to reset rtp_c->buffer ptr \n");
        rtp_c->buffer_ptr = rtp_c->buffer_end;
        av_free(c->pb_buffer);
      }
    } else {
      rtp_c->cur_idx = NULL;
    }
    printf("cmd play! after find iframe cur_offset = %lld\n", rtp_c->cur_offset);
    // reset served bytes for restart from pause state
    rtp_c->served_bytes = 0;
    rtp_c->state = RTPSTATE_SEND_DATA;
    /* now everything is OK, so we can send the connection parameters */
    rtsp_reply_header(c, RTSP_STATUS_OK);
    /* session ID */
    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
    if (rtp_c->cur_idx != NULL) {
      avio_printf(c->pb, "Range: npt=%.3lf-\r\n", get_iIndex_PCR(rtp_c->cur_idx));
      printf("range response! Range: npt=%.3lf-\n", get_iIndex_PCR(rtp_c->cur_idx));
      avio_printf(c->pb, "RTP-Info: seq=%d\r\n", rtp_c->cur_seq);
      printf("RTP info: seq=%d\n", rtp_c->cur_seq);
    }
    avio_printf(c->pb, "\r\n");
}
Beispiel #7
0
static void
rtsp_cmd_play(RTSPContext *ctx, const char *url, RTSPMessageHeader *h) {
	char path[4096];
	//
	av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path, sizeof(path), url);
	if(strncmp(path, rtspconf->object, strlen(rtspconf->object)) != 0) {
		rtsp_reply_error(ctx, RTSP_STATUS_SESSION);
		return;
	}
	if(strcmp(ctx->session_id, h->session_id) != 0) {
		rtsp_reply_error(ctx, RTSP_STATUS_SESSION);
		return;
	}
	//
	if(ctx->state != SERVER_STATE_READY
	&& ctx->state != SERVER_STATE_PAUSE) {
		rtsp_reply_error(ctx, RTSP_STATUS_STATE);
		return;
	}
	// create threads
#ifndef SHARE_ENCODER
	if(pthread_create(&ctx->vthread, NULL, vencoder_thread, ctx) != 0) {
		ga_error("cannot create video thread\n");
		rtsp_reply_error(ctx, RTSP_STATUS_INTERNAL);
		return;
	}
#ifdef ENABLE_AUDIO
	if(pthread_create(&ctx->athread, NULL, aencoder_thread, ctx) != 0) {
		ga_error("cannot create audio thread\n");
		rtsp_reply_error(ctx, RTSP_STATUS_INTERNAL);
		return;
	}
#endif	/* ENABLE_AUDIO */
#else
	if(encoder_register_client(ctx) < 0) {
		ga_error("cannot register encoder client.\n");
		rtsp_reply_error(ctx, RTSP_STATUS_INTERNAL);
		return;
	}
#endif	/* SHARE_ENCODER */
	//
	ctx->state = SERVER_STATE_PLAYING;
	rtsp_reply_header(ctx, RTSP_STATUS_OK);
	rtsp_printf(ctx, "Session: %s\r\n", ctx->session_id);
	rtsp_printf(ctx, "\r\n");
	return;
}
static void rtsp_cmd_describe(RTSPContext *c, const char *url)
{
  iStream *stream;
  char path1[1024];
  const char *path;
  uint8_t *content;
  int content_length = 0;
  socklen_t len;
  struct sockaddr_in my_addr;

  /* find which URL is asked */
  av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
  int l = strlen(path1);
  if (path1[l-1] == '/') {
    path1[l-1] = '\0';
  }
  path = path1;
  if (*path == '/')
      path++;

  for(stream = first_stream; stream != NULL; stream = stream->next) {
      if (!strcmp(path, stream->name)) {
          goto found;
      }
  }
  /* no stream found */
  rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
  return;

found:
  /* prepare the media description in SDP format */
  content = av_mallocz(1024);
  /* get the host IP */
  len = sizeof(my_addr);
  getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
  rtsp_reply_header(c, RTSP_STATUS_OK);
  avio_printf(c->pb, "Content-Base: %s/\r\n", url);
  avio_printf(c->pb, "Content-Type: application/sdp\r\n");
  int added_length = 0;
  // 여기에 sdp정보 추가 해야 함. 
  content_length = generate_sdp_context(stream, &content);
  avio_printf(c->pb, "Content-Length: %d\r\n", content_length + added_length);
  avio_printf(c->pb, "\r\n");
  // content added
  avio_write(c->pb, content, content_length + added_length);
  av_free(content);
}
Beispiel #9
0
static void
rtsp_cmd_teardown(RTSPContext *ctx, const char *url, RTSPMessageHeader *h, int bruteforce) {
	char path[4096];
	//
	av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path, sizeof(path), url);
	if(strncmp(path, rtspconf->object, strlen(rtspconf->object)) != 0) {
		rtsp_reply_error(ctx, RTSP_STATUS_SESSION);
		return;
	}
	if(strcmp(ctx->session_id, h->session_id) != 0) {
		rtsp_reply_error(ctx, RTSP_STATUS_SESSION);
		return;
	}
	//
	ctx->state = SERVER_STATE_TEARDOWN;
	if(bruteforce != 0)
		return;
	// XXX: well, gently response
	rtsp_reply_header(ctx, RTSP_STATUS_OK);
	rtsp_printf(ctx, "Session: %s\r\n", ctx->session_id);
	rtsp_printf(ctx, "\r\n");
	return;
}
Beispiel #10
0
static void
rtsp_cmd_setup(RTSPContext *ctx, const char *url, RTSPMessageHeader *h) {
	int i;
	RTSPTransportField *th;
	struct sockaddr_in destaddr, myaddr;
#ifdef WIN32
	int destaddrlen, myaddrlen;
#else
	socklen_t destaddrlen, myaddrlen;
#endif
	char path[4096];
	char channelname[VIDEO_SOURCE_CHANNEL_MAX+1][RTSP_STREAM_FORMAT_MAXLEN];
	int baselen = strlen(rtspconf->object);
	int streamid;
	int rtp_port, rtcp_port;
	enum RTSPStatusCode errcode;
	//
	av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path, sizeof(path), url);
	for(i = 0; i < VIDEO_SOURCE_CHANNEL_MAX+1; i++) {
		snprintf(channelname[i], RTSP_STREAM_FORMAT_MAXLEN, RTSP_STREAM_FORMAT, i);
	}
	//
	if(strncmp(path, rtspconf->object, baselen) != 0) {
		ga_error("invalid object (path=%s)\n", path);
		rtsp_reply_error(ctx, RTSP_STATUS_AGGREGATE);
		return;
	}
	for(i = 0; i < VIDEO_SOURCE_CHANNEL_MAX+1; i++) {
		if(strcmp(path+baselen+1, channelname[i]) == 0) {
			streamid = i;
			break;
		}
	}
	if(i == VIDEO_SOURCE_CHANNEL_MAX+1) {
		// not found
		ga_error("invalid service (path=%s)\n", path);
		rtsp_reply_error(ctx, RTSP_STATUS_SERVICE);
		return;
	}
	//
	if(ctx->state != SERVER_STATE_IDLE
	&& ctx->state != SERVER_STATE_READY) {
		rtsp_reply_error(ctx, RTSP_STATUS_STATE);
		return;
	}
	// create session id?
	if(ctx->session_id == NULL) {
		if(h->session_id[0] == '\0') {
			snprintf(h->session_id, sizeof(h->session_id), "%04x%04x",
				rand()%0x0ffff, rand()%0x0ffff);
			ctx->session_id = strdup(h->session_id);
			ga_error("New session created (id = %s)\n", ctx->session_id);
		}
	}
	// session id must match -- we have only one session
	if(ctx->session_id == NULL
	|| strcmp(ctx->session_id, h->session_id) != 0) {
		ga_error("Bad session id %s != %s\n", h->session_id, ctx->session_id);
		errcode = RTSP_STATUS_SESSION;
		goto error_setup;
	}
	// find supported transport
	if((th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP)) == NULL) {
		th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
	}
	if(th == NULL) {
		ga_error("Cannot find transport\n");
		errcode = RTSP_STATUS_TRANSPORT;
		goto error_setup;
	}
	//
	destaddrlen = sizeof(destaddr);
	bzero(&destaddr, destaddrlen);
	if(getpeername(ctx->fd, (struct sockaddr*) &destaddr, &destaddrlen) < 0) {
		ga_error("Cannot get peername\n");
		errcode = RTSP_STATUS_INTERNAL;
		goto error_setup;
	}
	destaddr.sin_port = htons(th->client_port_min);
	//
	myaddrlen = sizeof(myaddr);
	bzero(&myaddr, myaddrlen);
	if(getsockname(ctx->fd, (struct sockaddr*) &myaddr, &myaddrlen) < 0) {
		ga_error("Cannot get sockname\n");
		errcode = RTSP_STATUS_INTERNAL;
		goto error_setup;
	}
	//
	ctx->lower_transport[streamid] = th->lower_transport;
	if(rtp_new_av_stream(ctx, &destaddr, streamid,
			streamid == video_source_channels()/*rtspconf->audio_id*/ ?
				rtspconf->audio_encoder_codec->id : rtspconf->video_encoder_codec->id) < 0) {
		ga_error("Create AV stream %d failed.\n", streamid);
		errcode = RTSP_STATUS_TRANSPORT;
		goto error_setup;
	}
	//
	ctx->state = SERVER_STATE_READY;
	rtsp_reply_header(ctx, RTSP_STATUS_OK);
	rtsp_printf(ctx, "Session: %s\r\n", ctx->session_id);
	switch(th->lower_transport) {
	case RTSP_LOWER_TRANSPORT_UDP:
#ifdef HOLE_PUNCHING
		rtp_port = ctx->rtpLocalPort[streamid*2];
		rtcp_port = ctx->rtpLocalPort[streamid*2+1];
		ctx->rtpPeerPort[streamid*2] = htons(th->client_port_min);
		ctx->rtpPeerPort[streamid*2+1] = htons(th->client_port_max);
#else
		rtp_port = ff_rtp_get_local_rtp_port((URLContext*) ctx->fmtctx[streamid]->pb->opaque);
		rtcp_port = ff_rtp_get_local_rtcp_port((URLContext*) ctx->fmtctx[streamid]->pb->opaque);
#endif
		ga_error("RTP/UDP: streamid=%d; client=%d-%d; server=%d-%d\n",
			streamid,
			th->client_port_min, th->client_port_max,
			rtp_port, rtcp_port);
		rtsp_printf(ctx, "Transport: RTP/AVP/UDP;unicast;client_port=%d-%d;server_port=%d-%d\r\n",
		       th->client_port_min, th->client_port_max,
		       rtp_port, rtcp_port);
		break;
	case RTSP_LOWER_TRANSPORT_TCP:
		ga_error("RTP/TCP: interleaved=%d-%d\n",
			streamid*2, streamid*2+1);
		rtsp_printf(ctx, "Transport: RTP/AVP/TCP;unicast;interleaved=%d-%d\r\n",
			streamid*2, streamid*2+1, streamid*2);
		break;
	default:
		// should not happen
		break;
	}
	rtsp_printf(ctx, "\r\n");
	return;
error_setup:
	if(ctx->session_id != NULL) {
		free(ctx->session_id);
		ctx->session_id = NULL;
	}
	if(ctx->encoder[streamid] != NULL) {
		ctx->encoder[streamid] = NULL;
	}
	if(ctx->stream[streamid] != NULL) {
		ctx->stream[streamid] = NULL;
	}
	if(ctx->fmtctx[streamid] != NULL) {
		avformat_free_context(ctx->fmtctx[streamid]);
		ctx->fmtctx[streamid] = NULL;
	}
	rtsp_reply_error(ctx, errcode);
	return;
}
Beispiel #11
0
static void
rtsp_reply_error(RTSPContext *c, enum RTSPStatusCode error_number) {
	rtsp_reply_header(c, error_number);
	rtsp_printf(c, "\r\n");
}
static void rtsp_cmd_setup(RTSPContext *c, const char *url, RTSPMessageHeader *h)
{
    iStream *stream;
    int stream_index, rtp_port, rtcp_port;
    char buf[1024];
    char path1[1024];
    char *path;
    RTSPContext *rtp_c;
    RTSPTransportField *th;
    struct sockaddr_in dest_addr;
    RTSPActionServerSetup setup;

    /* find which URL is asked */
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
    int len = strlen(path1);
    if (path1[len-1] == '/') {
      path1[len-1] = '\0';
    }
    // / 뒤에꺼 없애자! 
    char *removed_path = strrchr(path1, '/');
    if (removed_path != NULL && removed_path != path1)
    {
      path = path1;
      path[removed_path-path1] = '\0'; 
    } else {
      path = path1;
    }
    if (*path == '/')
        path++;
    printf("rtsp setup! find stream name = %s\n", path);
    /* now check each stream */
    for(stream = first_stream; stream != NULL; stream = stream->next) {
        /* accept aggregate filenames only if single stream */
        if (!strcmp(path, stream->name)) {
          goto found;
        }
    }
    /* no stream found */
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
    return;
 found:

    /* generate session id if needed */
    if (h->session_id[0] == '\0') {
      unsigned random0 = av_lfg_get(&random_state);
      unsigned random1 = av_lfg_get(&random_state);
      snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
               random0, random1);
    }

    /* find RTP session, and create it if none found */
    rtp_c = find_rtp_session(h->session_id);
    if (!rtp_c) {
      rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id);
      if (!rtp_c) {
          rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
          return;
      }
    }

    /* test if stream is OK (test needed because several SETUP needs
       to be done for a given file) */
    if (rtp_c->stream != stream) {
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
        return;
    }

    // udp 로 전송 가능한지 체크. 
    th = find_transport(h);
    if (!th) {
      printf("can't do udp transport \n");
      rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
      return;
    }

    /* setup default options */
    setup.transport_option[0] = '\0';
    dest_addr = rtp_c->from_addr;
    dest_addr.sin_port = htons(th->client_port_min);
    // setup stream 
    // open new rtp/udp socket!
    if (rtp_new_stream(rtp_c, &dest_addr) < 0) {
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
        return;
    }
    rtp_c->to_addr = dest_addr;
    /* now everything is OK, so we can send the connection parameters */
    rtsp_reply_header(c, RTSP_STATUS_OK);
    /* session ID */
    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);

    // rtcp 도 열어야되나? -_-;
    rtp_port = rtp_c->udp_port;
    rtcp_port = rtp_port+1; //  실제로 만들지는 않음..
    avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
                "client_port=%d-%d;server_port=%d-%d",
                th->client_port_min, th->client_port_max,
                rtp_port, rtcp_port);
    if (setup.transport_option[0] != '\0')
        avio_printf(c->pb, ";%s", setup.transport_option);
        
    avio_printf(c->pb, "\r\n");
    avio_printf(c->pb, "\r\n");
}