RTSP_FLAG_OPTS("rtsp_flags", "set RTSP flags"),
{ "listen", "wait for incoming connections", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_LISTEN}, 0, 0, DEC, "rtsp_flags" },
{ "prefer_tcp", "try RTP via TCP first, if available", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_PREFER_TCP}, 0, 0, DEC|ENC, "rtsp_flags" },
+ { "satip_raw", "export raw MPEG-TS stream instead of demuxing", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_SATIP_RAW}, 0, 0, DEC, "rtsp_flags" },
RTSP_MEDIATYPE_OPTS("allowed_media_types", "set media types to accept from the server"),
{ "min_port", "set minimum local UDP port", OFFSET(rtp_port_min), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MIN}, 0, 65535, DEC|ENC },
{ "max_port", "set maximum local UDP port", OFFSET(rtp_port_max), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MAX}, 0, 65535, DEC|ENC },
{ "listen_timeout", "set maximum timeout (in seconds) to wait for incoming connections (-1 is infinite, imply flag listen)", OFFSET(initial_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC },
-#if FF_API_OLD_RTSP_OPTIONS
- { "timeout", "set maximum timeout (in seconds) to wait for incoming connections (-1 is infinite, imply flag listen) (deprecated, use listen_timeout)", OFFSET(initial_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC },
- { "stimeout", "set timeout (in microseconds) of socket TCP I/O operations", OFFSET(stimeout), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC },
-#else
{ "timeout", "set timeout (in microseconds) of socket TCP I/O operations", OFFSET(stimeout), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC },
-#endif
COMMON_OPTS(),
{ "user_agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = LIBAVFORMAT_IDENT}, 0, 0, DEC },
-#if FF_API_OLD_RTSP_OPTIONS
- { "user-agent", "override User-Agent header (deprecated, use user_agent)", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = LIBAVFORMAT_IDENT}, 0, 0, DEC },
-#endif
{ NULL },
};
}
}
+static int init_satip_stream(AVFormatContext *s)
+{
+ RTSPState *rt = s->priv_data;
+ RTSPStream *rtsp_st = av_mallocz(sizeof(RTSPStream));
+ if (!rtsp_st)
+ return AVERROR(ENOMEM);
+ dynarray_add(&rt->rtsp_streams,
+ &rt->nb_rtsp_streams, rtsp_st);
+
+ rtsp_st->sdp_payload_type = 33; // MP2T
+ av_strlcpy(rtsp_st->control_url,
+ rt->control_uri, sizeof(rtsp_st->control_url));
+
+ if (rt->rtsp_flags & RTSP_FLAG_SATIP_RAW) {
+ AVStream *st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+ st->id = rt->nb_rtsp_streams - 1;
+ rtsp_st->stream_index = st->index;
+ st->codecpar->codec_type = AVMEDIA_TYPE_DATA;
+ st->codecpar->codec_id = AV_CODEC_ID_MPEG2TS;
+ } else {
+ rtsp_st->stream_index = -1;
+ init_rtp_handler(&ff_mpegts_dynamic_handler, rtsp_st, NULL);
+ finalize_rtp_handler_init(s, rtsp_st, NULL);
+ }
+ return 0;
+}
+
/* parse the rtpmap description: <codec_name>/<clock_rate>[/<other params>] */
static int sdp_parse_rtpmap(AVFormatContext *s,
AVStream *st, RTSPStream *rtsp_st,
break;
case 'a':
if (av_strstart(p, "control:", &p)) {
- if (s->nb_streams == 0) {
+ if (rt->nb_rtsp_streams == 0) {
if (!strncmp(p, "rtsp://", 7))
av_strlcpy(rt->control_uri, p,
sizeof(rt->control_uri));
static void rtsp_parse_rtp_info(RTSPState *rt, const char *p)
{
int read = 0;
- char key[20], value[1024], url[1024] = "";
+ char key[20], value[MAX_URL_SIZE], url[MAX_URL_SIZE] = "";
uint32_t seq = 0, rtptime = 0;
for (;;) {
} else if (av_stristart(p, "Content-Type:", &p)) {
p += strspn(p, SPACE_CHARS);
av_strlcpy(reply->content_type, p, sizeof(reply->content_type));
+ } else if (av_stristart(p, "com.ses.streamID:", &p)) {
+ p += strspn(p, SPACE_CHARS);
+ av_strlcpy(reply->stream_id, p, sizeof(reply->stream_id));
}
}
{
RTSPState *rt = s->priv_data;
int ret, len, len1;
- uint8_t buf[1024];
+ uint8_t buf[MAX_URL_SIZE];
ret = ffurl_read_complete(rt->rtsp_hd, buf, 3);
if (ret != 3)
int return_on_interleaved_data, const char *method)
{
RTSPState *rt = s->priv_data;
- char buf[4096], buf1[1024], *q;
+ char buf[MAX_URL_SIZE], buf1[MAX_URL_SIZE], *q;
unsigned char ch;
const char *p;
int ret, content_length, line_count = 0, request = 0;
av_freep(&content);
if (request) {
- char buf[1024];
+ char buf[MAX_URL_SIZE];
char base64buf[AV_BASE64_SIZE(sizeof(buf))];
const char* ptr = buf;
int send_content_length)
{
RTSPState *rt = s->priv_data;
- char buf[4096], *out_buf;
+ char buf[MAX_URL_SIZE], *out_buf;
char base64buf[AV_BASE64_SIZE(sizeof(buf))];
if (!rt->rtsp_hd_out)
int rtx = 0, j, i, err, interleave = 0, port_off;
RTSPStream *rtsp_st;
RTSPMessageHeader reply1, *reply = &reply1;
- char cmd[2048];
+ char cmd[MAX_URL_SIZE];
const char *trans_pref;
if (rt->transport == RTSP_TRANSPORT_RDT)
port_off -= port_off & 0x01;
for (j = rt->rtp_port_min + port_off, i = 0; i < rt->nb_rtsp_streams; ++i) {
- char transport[2048];
+ char transport[MAX_URL_SIZE];
/*
* WMS serves all UDP data over a single connection, the RTX, which
rtp_opened:
port = ff_rtp_get_local_rtp_port(rtsp_st->rtp_handle);
have_port:
- snprintf(transport, sizeof(transport) - 1,
- "%s/UDP;", trans_pref);
+ av_strlcpy(transport, trans_pref, sizeof(transport));
+ av_strlcat(transport,
+ rt->server_type == RTSP_SERVER_SATIP ? ";" : "/UDP;",
+ sizeof(transport));
if (rt->server_type != RTSP_SERVER_REAL)
av_strlcat(transport, "unicast;", sizeof(transport));
av_strlcatf(transport, sizeof(transport),
goto fail;
}
+ if (rt->server_type == RTSP_SERVER_SATIP && reply->stream_id[0]) {
+ char proto[128], host[128], path[512], auth[128];
+ int port;
+ av_url_split(proto, sizeof(proto), auth, sizeof(auth), host, sizeof(host),
+ &port, path, sizeof(path), rt->control_uri);
+ ff_url_join(rt->control_uri, sizeof(rt->control_uri), proto, NULL, host,
+ port, "/stream=%s", reply->stream_id);
+ }
+
/* XXX: same protocol for all streams is required */
if (i > 0) {
if (reply->transports[0].lower_transport != rt->lower_transport ||
break;
case RTSP_LOWER_TRANSPORT_UDP: {
- char url[1024], options[30] = "";
+ char url[MAX_URL_SIZE], options[30] = "";
const char *peer = host;
if (rt->rtsp_flags & RTSP_FLAG_FILTER_SRC)
break;
}
case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: {
- char url[1024], namebuf[50], optbuf[20] = "";
+ char url[MAX_URL_SIZE], namebuf[50], optbuf[20] = "";
struct sockaddr_storage addr;
int port, ttl;
AVDictionary *opts = map_to_opts(rt);
{
RTSPState *rt = s->priv_data;
char proto[128], host[1024], path[1024];
- char tcpname[1024], cmd[2048], auth[128];
+ char tcpname[1024], cmd[MAX_URL_SIZE], auth[128];
const char *lower_rtsp_proto = "tcp";
int port, err, tcp_fd;
RTSPMessageHeader reply1, *reply = &reply1;
lower_rtsp_proto = "tls";
default_port = RTSPS_DEFAULT_PORT;
rt->lower_transport_mask = 1 << RTSP_LOWER_TRANSPORT_TCP;
+ } else if (!strcmp(proto, "satip")) {
+ av_strlcpy(proto, "rtsp", sizeof(proto));
+ rt->server_type = RTSP_SERVER_SATIP;
}
if (*auth) {
/* request options supported by the server; this also detects server
* type */
- for (rt->server_type = RTSP_SERVER_RTP;;) {
+ if (rt->server_type != RTSP_SERVER_SATIP)
+ rt->server_type = RTSP_SERVER_RTP;
+ for (;;) {
cmd[0] = 0;
if (rt->server_type == RTSP_SERVER_REAL)
av_strlcat(cmd,
break;
}
- if (CONFIG_RTSP_DEMUXER && s->iformat)
- err = ff_rtsp_setup_input_streams(s, reply);
- else if (CONFIG_RTSP_MUXER)
+#if CONFIG_RTSP_DEMUXER
+ if (s->iformat) {
+ if (rt->server_type == RTSP_SERVER_SATIP)
+ err = init_satip_stream(s);
+ else
+ err = ff_rtsp_setup_input_streams(s, reply);
+ } else
+#endif
+ if (CONFIG_RTSP_MUXER)
err = ff_rtsp_setup_output_streams(s, host);
else
av_assert0(0);
RTSPStream *rtsp_st;
int size, i, err;
char *content;
- char url[1024];
+ char url[MAX_URL_SIZE];
if (!ff_network_init())
return AVERROR(EIO);
/* read the whole sdp file */
/* XXX: better loading */
content = av_malloc(SDP_MAX_SIZE);
- if (!content)
+ if (!content) {
+ ff_network_close();
return AVERROR(ENOMEM);
+ }
size = avio_read(s->pb, content, SDP_MAX_SIZE - 1);
if (size <= 0) {
av_free(content);
+ ff_network_close();
return AVERROR_INVALIDDATA;
}
content[size] ='\0';
RTSPState *rt = s->priv_data;
const char *p;
AVBPrint sdp;
+ AVDictionary *opts = NULL;
if (!ff_network_init())
return AVERROR(EIO);
+ opts = map_to_opts(rt);
ret = ffurl_open_whitelist(&in, s->url, AVIO_FLAG_READ,
- &s->interrupt_callback, NULL, s->protocol_whitelist, s->protocol_blacklist, NULL);
+ &s->interrupt_callback, &opts, s->protocol_whitelist, s->protocol_blacklist, NULL);
+ av_dict_free(&opts);
if (ret)
goto fail;
av_log(s, AV_LOG_ERROR, "Unable to receive RTP payload type %d "
"without an SDP file describing it\n",
payload_type);
+ ret = AVERROR_INVALIDDATA;
goto fail;
}
if (par->codec_type != AVMEDIA_TYPE_DATA) {
ffio_init_context(&pb, sdp.str, sdp.len, 0, NULL, NULL, NULL, NULL);
s->pb = &pb;
- /* sdp_read_header initializes this again */
+ /* if sdp_read_header() fails then following ff_network_close() cancels out */
+ /* ff_network_init() at the start of this function. Otherwise it cancels out */
+ /* ff_network_init() inside sdp_read_header() */
ff_network_close();
rt->media_type_mask = (1 << (AVMEDIA_TYPE_SUBTITLE+1)) - 1;