static int rtsp_read_play(AVFormatContext *s) { RTSPState *rt = s->priv_data; RTSPMessageHeader reply1, *reply = &reply1; int i; char cmd[1024]; av_log(s, AV_LOG_DEBUG, "hello state=%d\n", rt->state); rt->nb_byes = 0; if (!(rt->server_type == RTSP_SERVER_REAL && rt->need_subscription)) { if (rt->transport == RTSP_TRANSPORT_RTP) { for (i = 0; i < rt->nb_rtsp_streams; i++) { RTSPStream *rtsp_st = rt->rtsp_streams[i]; RTPDemuxContext *rtpctx = rtsp_st->transport_priv; if (!rtpctx) continue; ff_rtp_reset_packet_queue(rtpctx); rtpctx->last_rtcp_ntp_time = AV_NOPTS_VALUE; rtpctx->first_rtcp_ntp_time = AV_NOPTS_VALUE; rtpctx->base_timestamp = 0; rtpctx->timestamp = 0; rtpctx->unwrapped_timestamp = 0; rtpctx->rtcp_ts_offset = 0; } } if (rt->state == RTSP_STATE_PAUSED) { cmd[0] = 0; } else { snprintf(cmd, sizeof(cmd), "Range: npt=%"PRId64".%03"PRId64"-\r\n", rt->seek_timestamp / AV_TIME_BASE, rt->seek_timestamp / (AV_TIME_BASE / 1000) % 1000); } ff_rtsp_send_cmd(s, "PLAY", rt->control_uri, cmd, reply, NULL); if (reply->status_code != RTSP_STATUS_OK) { return ff_rtsp_averror(reply->status_code, -1); } if (rt->transport == RTSP_TRANSPORT_RTP && reply->range_start != AV_NOPTS_VALUE) { for (i = 0; i < rt->nb_rtsp_streams; i++) { RTSPStream *rtsp_st = rt->rtsp_streams[i]; RTPDemuxContext *rtpctx = rtsp_st->transport_priv; AVStream *st = NULL; if (!rtpctx || rtsp_st->stream_index < 0) continue; st = s->streams[rtsp_st->stream_index]; rtpctx->range_start_offset = av_rescale_q(reply->range_start, AV_TIME_BASE_Q, st->time_base); } } } rt->state = RTSP_STATE_STREAMING; return 0; }
/* pause the stream */ static int rtsp_read_pause(AVFormatContext *s) { RTSPState *rt = s->priv_data; RTSPMessageHeader reply1, *reply = &reply1; if (rt->state != RTSP_STATE_STREAMING) return 0; else if (!(rt->server_type == RTSP_SERVER_REAL && rt->need_subscription)) { ff_rtsp_send_cmd(s, "PAUSE", rt->control_uri, NULL, reply, NULL); if (reply->status_code != RTSP_STATUS_OK) { return ff_rtsp_averror(reply->status_code, -1); } } rt->state = RTSP_STATE_PAUSED; return 0; }
int ff_rtsp_setup_input_streams(AVFormatContext *s, RTSPMessageHeader *reply) { RTSPState *rt = s->priv_data; char cmd[1024]; unsigned char *content = NULL; int ret; /* describe the stream */ snprintf(cmd, sizeof(cmd), "Accept: application/sdp\r\n"); if (rt->server_type == RTSP_SERVER_REAL) { /** * The Require: attribute is needed for proper streaming from * Realmedia servers. */ av_strlcat(cmd, "Require: com.real.retain-entity-for-setup\r\n", sizeof(cmd)); } ff_rtsp_send_cmd(s, "DESCRIBE", rt->control_uri, cmd, reply, &content); if (reply->status_code != RTSP_STATUS_OK) { av_freep(&content); return ff_rtsp_averror(reply->status_code, AVERROR_INVALIDDATA); } if (!content) return AVERROR_INVALIDDATA; av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", content); /* now we got the SDP description, we parse it */ ret = ff_sdp_parse(s, (const char *)content); av_freep(&content); if (ret < 0) return ret; return 0; }
static int rtsp_read_packet(AVFormatContext *s, AVPacket *pkt) { RTSPState *rt = s->priv_data; int ret; RTSPMessageHeader reply1, *reply = &reply1; char cmd[1024]; retry: if (rt->server_type == RTSP_SERVER_REAL) { int i; for (i = 0; i < s->nb_streams; i++) rt->real_setup[i] = s->streams[i]->discard; if (!rt->need_subscription) { if (memcmp (rt->real_setup, rt->real_setup_cache, sizeof(enum AVDiscard) * s->nb_streams)) { snprintf(cmd, sizeof(cmd), "Unsubscribe: %s\r\n", rt->last_subscription); ff_rtsp_send_cmd(s, "SET_PARAMETER", rt->control_uri, cmd, reply, NULL); if (reply->status_code != RTSP_STATUS_OK) return ff_rtsp_averror(reply->status_code, AVERROR_INVALIDDATA); rt->need_subscription = 1; } } if (rt->need_subscription) { int r, rule_nr, first = 1; memcpy(rt->real_setup_cache, rt->real_setup, sizeof(enum AVDiscard) * s->nb_streams); rt->last_subscription[0] = 0; snprintf(cmd, sizeof(cmd), "Subscribe: "); for (i = 0; i < rt->nb_rtsp_streams; i++) { rule_nr = 0; for (r = 0; r < s->nb_streams; r++) { if (s->streams[r]->id == i) { if (s->streams[r]->discard != AVDISCARD_ALL) { if (!first) av_strlcat(rt->last_subscription, ",", sizeof(rt->last_subscription)); ff_rdt_subscribe_rule( rt->last_subscription, sizeof(rt->last_subscription), i, rule_nr); first = 0; } rule_nr++; } } } av_strlcatf(cmd, sizeof(cmd), "%s\r\n", rt->last_subscription); ff_rtsp_send_cmd(s, "SET_PARAMETER", rt->control_uri, cmd, reply, NULL); if (reply->status_code != RTSP_STATUS_OK) return ff_rtsp_averror(reply->status_code, AVERROR_INVALIDDATA); rt->need_subscription = 0; if (rt->state == RTSP_STATE_STREAMING) rtsp_read_play (s); } } ret = ff_rtsp_fetch_packet(s, pkt); if (ret < 0) { if (ret == AVERROR(ETIMEDOUT) && !rt->packets) { if (rt->lower_transport == RTSP_LOWER_TRANSPORT_UDP && rt->lower_transport_mask & (1 << RTSP_LOWER_TRANSPORT_TCP)) { RTSPMessageHeader reply1, *reply = &reply1; av_log(s, AV_LOG_WARNING, "UDP timeout, retrying with TCP\n"); if (rtsp_read_pause(s) != 0) return -1; // TEARDOWN is required on Real-RTSP, but might make // other servers close the connection. if (rt->server_type == RTSP_SERVER_REAL) ff_rtsp_send_cmd(s, "TEARDOWN", rt->control_uri, NULL, reply, NULL); rt->session_id[0] = '\0'; if (resetup_tcp(s) == 0) { rt->state = RTSP_STATE_IDLE; rt->need_subscription = 1; if (rtsp_read_play(s) != 0) return -1; goto retry; } } } return ret; } rt->packets++; if (!(rt->rtsp_flags & RTSP_FLAG_LISTEN)) { /* send dummy request to keep TCP connection alive */ if ((av_gettime_relative() - rt->last_cmd_time) / 1000000 >= rt->timeout / 2 || rt->auth_state.stale) { if (rt->server_type == RTSP_SERVER_WMS || (rt->server_type != RTSP_SERVER_REAL && rt->get_parameter_supported)) { ff_rtsp_send_cmd_async(s, "GET_PARAMETER", rt->control_uri, NULL); } else { ff_rtsp_send_cmd_async(s, "OPTIONS", rt->control_uri, NULL); } /* The stale flag should be reset when creating the auth response in * ff_rtsp_send_cmd_async, but reset it here just in case we never * called the auth code (if we didn't have any credentials set). */ rt->auth_state.stale = 0; } } return 0; }