+/* close and free RTSP streams */
+void ff_rtsp_close_streams(AVFormatContext *s)
+{
+ RTSPState *rt = s->priv_data;
+ int i;
+ RTSPStream *rtsp_st;
+
+ for (i = 0; i < rt->nb_rtsp_streams; i++) {
+ rtsp_st = rt->rtsp_streams[i];
+ if (rtsp_st) {
+ if (rtsp_st->transport_priv) {
+ if (s->oformat) {
+ AVFormatContext *rtpctx = rtsp_st->transport_priv;
+ av_write_trailer(rtpctx);
+ url_fclose(rtpctx->pb);
+ av_metadata_free(&rtpctx->streams[0]->metadata);
+ av_metadata_free(&rtpctx->metadata);
+ av_free(rtpctx->streams[0]);
+ av_free(rtpctx);
+ } else if (rt->transport == RTSP_TRANSPORT_RDT)
+ ff_rdt_parse_close(rtsp_st->transport_priv);
+ else
+ rtp_parse_close(rtsp_st->transport_priv);
+ }
+ if (rtsp_st->rtp_handle)
+ url_close(rtsp_st->rtp_handle);
+ if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context)
+ rtsp_st->dynamic_handler->close(
+ rtsp_st->dynamic_protocol_context);
+ }
+ }
+ av_free(rt->rtsp_streams);
+ if (rt->asf_ctx) {
+ av_close_input_stream (rt->asf_ctx);
+ rt->asf_ctx = NULL;
+ }
+ av_freep(&rt->auth_b64);
+}
+
+static void *rtsp_rtp_mux_open(AVFormatContext *s, AVStream *st, URLContext *handle) {
+ AVFormatContext *rtpctx;
+ int ret;
+ AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
+
+ if (!rtp_format)
+ return NULL;
+
+ /* Allocate an AVFormatContext for each output stream */
+ rtpctx = avformat_alloc_context();
+ if (!rtpctx)
+ return NULL;
+
+ rtpctx->oformat = rtp_format;
+ if (!av_new_stream(rtpctx, 0)) {
+ av_free(rtpctx);
+ return NULL;
+ }
+ /* Copy the max delay setting; the rtp muxer reads this. */
+ rtpctx->max_delay = s->max_delay;
+ /* Copy other stream parameters. */
+ rtpctx->streams[0]->sample_aspect_ratio = st->sample_aspect_ratio;
+
+ /* Remove the local codec, link to the original codec
+ * context instead, to give the rtp muxer access to
+ * codec parameters. */
+ av_free(rtpctx->streams[0]->codec);
+ rtpctx->streams[0]->codec = st->codec;
+
+ url_fdopen(&rtpctx->pb, handle);
+ ret = av_write_header(rtpctx);
+
+ if (ret) {
+ url_fclose(rtpctx->pb);
+ av_free(rtpctx->streams[0]);
+ av_free(rtpctx);
+ return NULL;
+ }
+
+ /* Copy the RTP AVStream timebase back to the original AVStream */
+ st->time_base = rtpctx->streams[0]->time_base;
+ return rtpctx;
+}
+
+static int rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st)
+{
+ RTSPState *rt = s->priv_data;
+ AVStream *st = NULL;
+
+ /* open the RTP context */
+ if (rtsp_st->stream_index >= 0)
+ st = s->streams[rtsp_st->stream_index];
+ if (!st)
+ s->ctx_flags |= AVFMTCTX_NOHEADER;
+
+ if (s->oformat) {
+ rtsp_st->transport_priv = rtsp_rtp_mux_open(s, st, rtsp_st->rtp_handle);
+ /* Ownage of rtp_handle is passed to the rtp mux context */
+ rtsp_st->rtp_handle = NULL;
+ } else if (rt->transport == RTSP_TRANSPORT_RDT)
+ rtsp_st->transport_priv = ff_rdt_parse_open(s, st->index,
+ rtsp_st->dynamic_protocol_context,
+ rtsp_st->dynamic_handler);
+ else
+ rtsp_st->transport_priv = rtp_parse_open(s, st, rtsp_st->rtp_handle,
+ rtsp_st->sdp_payload_type,
+ &rtsp_st->rtp_payload_data);
+
+ if (!rtsp_st->transport_priv) {
+ return AVERROR(ENOMEM);
+ } else if (rt->transport != RTSP_TRANSPORT_RDT) {
+ if (rtsp_st->dynamic_handler) {
+ rtp_parse_set_dynamic_protocol(rtsp_st->transport_priv,
+ rtsp_st->dynamic_protocol_context,
+ rtsp_st->dynamic_handler);
+ }
+ }
+
+ return 0;
+}
+
+#if CONFIG_RTSP_DEMUXER || CONFIG_RTSP_MUXER
+static int rtsp_probe(AVProbeData *p)
+{
+ if (av_strstart(p->filename, "rtsp:", NULL))
+ return AVPROBE_SCORE_MAX;
+ return 0;
+}
+