Ejemplo n.º 1
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;
}
Ejemplo n.º 2
0
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);
}
Ejemplo n.º 3
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;
}
Ejemplo n.º 4
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;
}
Ejemplo n.º 5
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;
}
Ejemplo n.º 6
0
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");
}
Ejemplo n.º 7
0
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);
}
Ejemplo n.º 8
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;
}
Ejemplo n.º 9
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;
}
Ejemplo n.º 10
0
void*
rtspserver(void *arg) {
#ifdef WIN32
	SOCKET s = *((SOCKET*) arg);
	int sinlen = sizeof(struct sockaddr_in);
#else
	int s = *((int*) arg);
	socklen_t sinlen = sizeof(struct sockaddr_in);
#endif
	const char *p;
	char buf[8192];
	char cmd[32], url[1024], protocol[32];
	int rlen;
	struct sockaddr_in sin;
	RTSPContext ctx;
	RTSPMessageHeader header1, *header = &header1;
	//int thread_ret;
	// image info
	//int iwidth = video_source_maxwidth(0);
	//int iheight = video_source_maxheight(0);
	//
	rtspconf = rtspconf_global();
	sinlen = sizeof(sin);
	getpeername(s, (struct sockaddr*) &sin, &sinlen);
	//
	bzero(&ctx, sizeof(ctx));
	if(per_client_init(&ctx) < 0) {
		ga_error("server initialization failed.\n");
		return NULL;
	}
	bcopy(&sin, &ctx.client, sizeof(ctx.client));
	ctx.state = SERVER_STATE_IDLE;
	// XXX: hasVideo is used to sync audio/video
	// This value is increased by 1 for each captured frame until it is gerater than zero
	// when this value is greater than zero, audio encoding then starts ...
	//ctx.hasVideo = -(rtspconf->video_fps>>1);	// for slow encoders?
	ctx.hasVideo = 0;	// with 'zerolatency'
	pthread_mutex_init(&ctx.rtsp_writer_mutex, NULL);
	//
	ga_error("[tid %ld] client connected from %s:%d\n",
		ga_gettid(),
		inet_ntoa(sin.sin_addr), htons(sin.sin_port));
	//
	ctx.fd = s;
	//
	do {
		int i, fdmax, active;
		fd_set rfds;
		struct timeval to;
		FD_ZERO(&rfds);
		FD_SET(ctx.fd, &rfds);
		fdmax = ctx.fd;
#ifdef HOLE_PUNCHING
		for(i = 0; i < 2*ctx.streamCount; i++) {
			FD_SET(ctx.rtpSocket[i], &rfds);
			if(ctx.rtpSocket[i] > fdmax)
				fdmax = ctx.rtpSocket[i];
		}
#endif
		to.tv_sec = 0;
		to.tv_usec = 500000;
		if((active = select(fdmax+1, &rfds, NULL, NULL, &to)) < 0) {
			ga_error("select() failed: %s\n", strerror(errno));
			goto quit;
		}
		if(active == 0) {
			// try again!
			continue;
		}
#ifdef HOLE_PUNCHING
		for(i = 0; i < 2*ctx.streamCount; i++) {
			struct sockaddr_in xsin;
#ifdef WIN32
			int xsinlen = sizeof(xsin);
#else
			socklen_t xsinlen = sizeof(xsin);
#endif
			if(FD_ISSET(ctx.rtpSocket[i], &rfds) == 0)
				continue;
			recvfrom(ctx.rtpSocket[i], buf, sizeof(buf), 0,
				(struct sockaddr*) &xsin, &xsinlen);
			if(ctx.rtpPortChecked[i] != 0)
				continue;
			// XXX: port should not flip-flop, so check only once
			if(xsin.sin_addr.s_addr != ctx.client.sin_addr.s_addr) {
				ga_error("RTP: client address mismatched? %u.%u.%u.%u != %u.%u.%u.%u\n",
					NIPQUAD(ctx.client.sin_addr.s_addr),
					NIPQUAD(xsin.sin_addr.s_addr));
				continue;
			}
			if(xsin.sin_port != ctx.rtpPeerPort[i]) {
				ga_error("RTP: client port reconfigured: %u -> %u\n",
					(unsigned int) ntohs(ctx.rtpPeerPort[i]),
					(unsigned int) ntohs(xsin.sin_port));
				ctx.rtpPeerPort[i] = xsin.sin_port;
			} else {
				ga_error("RTP: client is not under an NAT, port %d confirmed\n",
					(int) ntohs(ctx.rtpPeerPort[i]));
			}
			ctx.rtpPortChecked[i] = 1;
		}
		// is RTSP connection?
		if(FD_ISSET(ctx.fd, &rfds) == 0)
			continue;
#endif
		// read commands
		if((rlen = rtsp_getnext(&ctx, buf, sizeof(buf))) < 0) {
			goto quit;
		}
		// Interleaved binary data?
		if(buf[0] == '$') {
			handle_rtcp(&ctx, buf, rlen);
			continue;
		}
		// REQUEST line
		ga_error("%s", buf);
		p = buf;
		get_word(cmd, sizeof(cmd), &p);
		get_word(url, sizeof(url), &p);
		get_word(protocol, sizeof(protocol), &p);
		// check protocol
		if(strcmp(protocol, "RTSP/1.0") != 0) {
			rtsp_reply_error(&ctx, RTSP_STATUS_VERSION);
			goto quit;
		}
		// read headers
		bzero(header, sizeof(*header));
		do {
			int myseq = -1;
			char mysession[sizeof(header->session_id)] = "";
			if((rlen = rtsp_getnext(&ctx, buf, sizeof(buf))) < 0)
				goto quit;
			if(buf[0]=='\n' || (buf[0]=='\r' && buf[1]=='\n'))
				break;
#if 0
			ga_error("HEADER: %s", buf);
#endif
			// Special handling to CSeq & Session header
			// ff_rtsp_parse_line cannot handle CSeq & Session properly on Windows
			// any more?
			if(strncasecmp("CSeq: ", buf, 6) == 0) {
				myseq = strtol(buf+6, NULL, 10);
			}
			if(strncasecmp("Session: ", buf, 9) == 0) {
				strcpy(mysession, buf+9);
			}
			//
			ff_rtsp_parse_line(header, buf, NULL, NULL);
			//
			if(myseq > 0 && header->seq <= 0) {
				ga_error("WARNING: CSeq fixes applied (%d->%d).\n",
					header->seq, myseq);
				header->seq = myseq;
			}
			if(mysession[0] != '\0' && header->session_id[0]=='\0') {
				unsigned i;
				for(i = 0; i < sizeof(header->session_id)-1; i++) {
					if(mysession[i] == '\0'
					|| isspace(mysession[i])
					|| mysession[i] == ';')
						break;
					header->session_id[i] = mysession[i];
				}
				header->session_id[i+1] = '\0';
				ga_error("WARNING: Session fixes applied (%s)\n",
					header->session_id);
			}
		} while(1);
		// special handle to session_id
		if(header->session_id != NULL) {
			char *p = header->session_id;
			while(*p != '\0') {
				if(*p == '\r' || *p == '\n') {
					*p = '\0';
					break;
				}
				p++;
			}
		}
		// handle commands
		ctx.seq = header->seq;
		if (!strcmp(cmd, "DESCRIBE"))
			rtsp_cmd_describe(&ctx, url);
		else if (!strcmp(cmd, "OPTIONS"))
			rtsp_cmd_options(&ctx, url);
		else if (!strcmp(cmd, "SETUP"))
			rtsp_cmd_setup(&ctx, url, header);
		else if (!strcmp(cmd, "PLAY"))
			rtsp_cmd_play(&ctx, url, header);
		else if (!strcmp(cmd, "PAUSE"))
			rtsp_cmd_pause(&ctx, url, header);
		else if (!strcmp(cmd, "TEARDOWN"))
			rtsp_cmd_teardown(&ctx, url, header, 1);
		else
			rtsp_reply_error(&ctx, RTSP_STATUS_METHOD);
		if(ctx.state == SERVER_STATE_TEARDOWN) {
			break;
		}
	} while(1);
quit:
	ctx.state = SERVER_STATE_TEARDOWN;
	//
	close(ctx.fd);
	// 2014-05-20: support only share-encoder model
	ff_server_unregister_client(&ctx);
	//
	per_client_deinit(&ctx);
	//ga_error("RTSP client thread terminated (%d/%d clients left).\n",
	//	video_source_client_count(), audio_source_client_count());
	ga_error("RTSP client thread terminated.\n");
	//
	return NULL;
}
Ejemplo n.º 11
0
void*
rtspserver(void *arg) {
#ifdef WIN32
	SOCKET s = *((SOCKET*) arg);
	int sinlen = sizeof(struct sockaddr_in);
#else
	int s = *((int*) arg);
	socklen_t sinlen = sizeof(struct sockaddr_in);
#endif
	const char *p;
	char buf[8192];
	char cmd[32], url[1024], protocol[32];
	int rlen;
	struct sockaddr_in sin;
	RTSPContext ctx;
	RTSPMessageHeader header1, *header = &header1;
	int thread_ret;
	// image info
	int iwidth = video_source_width(0);
	int iheight = video_source_height(0);
	//
	rtspconf = rtspconf_global();
	sinlen = sizeof(sin);
	getpeername(s, (struct sockaddr*) &sin, &sinlen);
	//
	bzero(&ctx, sizeof(ctx));
	if(per_client_init(&ctx) < 0) {
		ga_error("server initialization failed.\n");
		return NULL;
	}
	ctx.state = SERVER_STATE_IDLE;
	// XXX: hasVideo is used to sync audio/video
	// This value is increased by 1 for each captured frame until it is gerater than zero
	// when this value is greater than zero, audio encoding then starts ...
	//ctx.hasVideo = -(rtspconf->video_fps>>1);	// for slow encoders?
	ctx.hasVideo = 0;	// with 'zerolatency'
	pthread_mutex_init(&ctx.rtsp_writer_mutex, NULL);
#if 0
	ctx.audioparam.channels = rtspconf->audio_channels;
	ctx.audioparam.samplerate = rtspconf->audio_samplerate;
	if(rtspconf->audio_device_format == AV_SAMPLE_FMT_S16) {
#ifdef WIN32
#else
		ctx.audioparam.format = SND_PCM_FORMAT_S16_LE;
#endif
		ctx.audioparam.bits_per_sample = 16;
	}
	//
	ga_error("INFO: image: %dx%d; audio: %d ch 16-bit pcm @ %dHz\n",
			iwidth, iheight,
			ctx.audioparam.channels,
			ctx.audioparam.samplerate);
#endif
	//
#if 0
#ifdef WIN32
	if(ga_wasapi_init(&ctx.audioparam) < 0) {
		ga_error("cannot init wasapi.\n");
		return NULL;
	}
#else
	if((ctx.audioparam.handle = ga_alsa_init(&ctx.audioparam.sndlog)) == NULL) {
		ga_error("cannot init alsa.\n");
		return NULL;
	}
	if(ga_alsa_set_param(&ctx.audioparam) < 0) {
		ga_error("cannot set alsa parameter\n");
		return NULL;
	}
#endif
#endif
	//
	ga_error("[tid %ld] client connected from %s:%d\n",
		ga_gettid(),
		inet_ntoa(sin.sin_addr), htons(sin.sin_port));
	//
	ctx.fd = s;
	//
	do {
		fd_set rfds;
		FD_ZERO(&rfds);
		FD_SET(ctx.fd, &rfds);
		if(select(ctx.fd+1, &rfds, NULL, NULL, NULL) <=0) {
			ga_error("select() failed: %s\n", strerror(errno));
			goto quit;
		}
		// read commands
		if((rlen = rtsp_getnext(&ctx, buf, sizeof(buf))) < 0) {
			goto quit;
		}
		// Interleaved binary data?
		if(buf[0] == '$') {
			handle_rtcp(&ctx, buf, rlen);
			continue;
		}
		// REQUEST line
		ga_error("%s", buf);
		p = buf;
		get_word(cmd, sizeof(cmd), &p);
		get_word(url, sizeof(url), &p);
		get_word(protocol, sizeof(protocol), &p);
		// check protocol
		if(strcmp(protocol, "RTSP/1.0") != 0) {
			rtsp_reply_error(&ctx, RTSP_STATUS_VERSION);
			goto quit;
		}
		// read headers
		bzero(header, sizeof(*header));
		do {
			int myseq = -1;
			char mysession[sizeof(header->session_id)] = "";
			if((rlen = rtsp_getnext(&ctx, buf, sizeof(buf))) < 0)
				goto quit;
			if(buf[0]=='\n' || (buf[0]=='\r' && buf[1]=='\n'))
				break;
#if 0
			ga_error("HEADER: %s", buf);
#endif
			// Special handling to CSeq & Session header
			// ff_rtsp_parse_line cannot handle CSeq & Session properly on Windows
			// any more?
			if(strncasecmp("CSeq: ", buf, 6) == 0) {
				myseq = strtol(buf+6, NULL, 10);
			}
			if(strncasecmp("Session: ", buf, 9) == 0) {
				strcpy(mysession, buf+9);
			}
			//
			ff_rtsp_parse_line(header, buf, NULL, NULL);
			//
			if(myseq > 0 && header->seq <= 0) {
				ga_error("WARNING: CSeq fixes applied (%d->%d).\n",
					header->seq, myseq);
				header->seq = myseq;
			}
			if(mysession[0] != '\0' && header->session_id[0]=='\0') {
				unsigned i;
				for(i = 0; i < sizeof(header->session_id)-1; i++) {
					if(mysession[i] == '\0'
					|| isspace(mysession[i])
					|| mysession[i] == ';')
						break;
					header->session_id[i] = mysession[i];
				}
				header->session_id[i+1] = '\0';
				ga_error("WARNING: Session fixes applied (%s)\n",
					header->session_id);
			}
		} while(1);
		// special handle to session_id
		if(header->session_id != NULL) {
			char *p = header->session_id;
			while(*p != '\0') {
				if(*p == '\r' || *p == '\n') {
					*p = '\0';
					break;
				}
				p++;
			}
		}
		// handle commands
		ctx.seq = header->seq;
		if (!strcmp(cmd, "DESCRIBE"))
			rtsp_cmd_describe(&ctx, url);
		else if (!strcmp(cmd, "OPTIONS"))
			rtsp_cmd_options(&ctx, url);
		else if (!strcmp(cmd, "SETUP"))
			rtsp_cmd_setup(&ctx, url, header);
		else if (!strcmp(cmd, "PLAY"))
			rtsp_cmd_play(&ctx, url, header);
		else if (!strcmp(cmd, "PAUSE"))
			rtsp_cmd_pause(&ctx, url, header);
		else if (!strcmp(cmd, "TEARDOWN"))
			rtsp_cmd_teardown(&ctx, url, header);
		else
			rtsp_reply_error(&ctx, RTSP_STATUS_METHOD);
		if(ctx.state == SERVER_STATE_TEARDOWN) {
			break;
		}
	} while(1);
quit:
	ctx.state = SERVER_STATE_TEARDOWN;
	//
	close(ctx.fd);
#ifdef	SHARE_ENCODER
	encoder_unregister_client(&ctx);
#else
	ga_error("connection closed, checking for worker threads...\n");
#if 0
	//
	if(ctx.vthreadId != 0) {
		video_source_notify_one(ctx.vthreadId);
	}
#endif
	pthread_join(ctx.vthread, (void**) &thread_ret);
#ifdef	ENABLE_AUDIO
	pthread_join(ctx.athread, (void**) &thread_ret);
#endif	/* ENABLE_AUDIO */
#endif	/* SHARE_ENCODER */
	//
	per_client_deinit(&ctx);
	//ga_error("RTSP client thread terminated (%d/%d clients left).\n",
	//	video_source_client_count(), audio_source_client_count());
	ga_error("RTSP client thread terminated.\n");
	//
	return NULL;
}
Ejemplo n.º 12
0
static int rtsp_parse_request(RTSPContext *c)
{
    const char *p, *p1, *p2;
    char cmd[32];
    char url[1024];
    char protocol[32];
    char line[1024];
    int len;
    RTSPMessageHeader header1 = { 0 }, *header = &header1;

    c->buffer_ptr[0] = '\0';
    p = c->buffer;

    get_word(cmd, sizeof(cmd), &p);
    get_word(url, sizeof(url), &p);
    get_word(protocol, sizeof(protocol), &p);

    av_strlcpy(c->method, cmd, sizeof(c->method));
    av_strlcpy(c->url, url, sizeof(c->url));
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));

    if (avio_open_dyn_buf(&c->pb) < 0) {
       //  XXX: cannot do more 
        c->pb = NULL;//  safety 
        return -1;
    }

    printf("cmd = %s \n", cmd);
    /* check version name */
    if (strcmp(protocol, "RTSP/1.0") != 0) {
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
        goto the_end;
    }
    /* parse each header line */
    /* skip to next line */
    while (*p != '\n' && *p != '\0')
        p++;
    if (*p == '\n')
        p++;
    while (*p != '\0') {
      p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
      if (!p1)
          break;
      p2 = p1;
      if (p2 > p && p2[-1] == '\r')
          p2--;
      /* skip empty line */
      if (p2 == p)
          break;
      len = p2 - p;
      if (len > sizeof(line) - 1)
          len = sizeof(line) - 1;
      memcpy(line, p, len);
      line[len] = '\0';
      //printf("rstp_parse_line = %s\n", line);
      // range parsing! 
      if (!strncmp(line, "Range: npt=", strlen("Range: npt="))) {
        printf("range info contained! line = %s \n", line);
        char *end_pos = strrchr(line, '-');
        char *start_pos = strrchr(line, '=');
        char *start_npt = malloc(end_pos - start_pos - 1);
        strncpy(start_npt, start_pos+1, end_pos - start_pos - 1);
        //printf("range start npt = %s\n", start_npt);
        double start_time = 0.0;
        sscanf(start_npt, "%lf", &start_time);
        //printf("range start time = %lfs\n", start_time);
        c->ntp_start_time = start_time;
      }

      // for trick
      if (!strncmp(line, "Scale:", strlen("Scale:"))) {
        printf("scale info contained! line = %s \n", line);
        char *end_pos = strrchr(line, '\n');
        char *start_pos = strrchr(line, ' ');
        char *scale = malloc(end_pos - start_pos - 1);
        strncpy(scale, start_pos+1, end_pos - start_pos - 1);
        printf("scale = %s\n", scale);
        double speed = 0.0;
        sscanf(scale, "%lf", &speed);
      }
      ff_rtsp_parse_line(header, line, NULL, NULL);
      p = p1 + 1;
    }
    /* handle sequence number */
    c->seq = header->seq;
    if (!strcmp(cmd, "DESCRIBE")) {
        printf("DESCRIBE!!!\n");
        rtsp_cmd_describe(c, url);
    }
    else if (!strcmp(cmd, "OPTIONS")) {
        printf("Options! \n");
        rtsp_cmd_options(c, url);
    }
    else if (!strcmp(cmd, "SETUP")) {
        printf("Setup!!!\n");
        rtsp_cmd_setup(c, url, header);
    }
    else if (!strcmp(cmd, "PLAY")) {
        printf("Play!!! \n");
        rtsp_cmd_play(c, url, header);
    }
    else if (!strcmp(cmd, "PAUSE")) {
        printf("PAUSE!!!\n");
        rtsp_cmd_interrupt(c, url, header, 1);
    }
    else if (!strcmp(cmd, "TEARDOWN")) {
        rtsp_cmd_interrupt(c, url, header, 0);
        printf("TEARDOWN!!!\n");
    }
    else {
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
        printf("Error!!");
    }

 the_end:
    // write rstp reply packet! text 
    len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
    c->pb = NULL; /* safety */
    if (len < 0) {
      /* XXX: cannot do more */
      printf("error! len < 0 when avio close dyn buf");
        return -1;
    }
    c->buffer_ptr = c->pb_buffer;
    c->buffer_end = c->pb_buffer + len;
    c->state = RTSPSTATE_SEND_REPLY;
    return 0;
}
Ejemplo n.º 13
0
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");
}