When a client close a rtsp connexion, it is supposed to send the TEARDOWN
packet according to
​https://en.wikipedia.org/wiki/Real_Time_Streaming_Protocol to tell to the
server to stop the streaming.
ffmpeg doesn't (controlled by wireshark, works with some other soft), while
i guess it worked at a given time while the code to do it is inside ffmpeg.

In short, because my tv provider allows only 1 channel at a time, i've to
wait 30 seconds between each channel change. However, even with 2 channels
at a time, the traffic is higer for 30 secondes and there are troubles
until the end of the server streaming of the 1st channel.

Below, you'll find more detail, and a not perfect at all but working in my
case patch to show the problem more in detail.

How to reproduce:

% ffplay 
'rtsp://mafreebox.freebox.fr/fbxtv_pub/stream?namespace=1&service=201&flavour=ld'

The attached file is not really a patch while it's not the good way to fix.
However, it works in my case.

I found that ff_rtsp_send_cmd_async(s, "TEARDOWN", rt->control_uri, NULL);
doesn't send the teardown packet, but the same command for DESCRIBE works,
so i tried to call this function before (i supposed that something is
closed too soon, or not flushed) :

The thing is that

rtsp::read_close function
containing ff_rtsp_send_cmd_async(s, "TEARDOWN", rt->control_uri, NULL);

is called after

is->abort_request = 1;
SDL_WaitThread(is->read_tid, NULL);

and at the end, the packet is never sent.
To quickly and badly fix, i've added a preclose function called before the
sdl_waitthread.

I'have troubleshooted this bug for 1 week, and only yesterday i finally
found it was related to ffmpeg, so i'm new to the ffmpeg code, so for the
moment, i don't the architecture and the best place to put the TEARDOWN
packet. (at the end of the thread ? or at the same place but fixing
something else). You guess i didn't found immediatly it was a missing
teardown packet in the rtsp protocol (i'm new to that protocol too...).
diff --git a/ffplay.c b/ffplay.c
index 4a084b4..c47cc95 100644
--- a/ffplay.c
+++ b/ffplay.c
@@ -1192,6 +1192,8 @@ static void stream_component_close(VideoState *is, int stream_index)
 
 static void stream_close(VideoState *is)
 {
+    avformat_preclose_input(&is->ic);
+  
     /* XXX: use a special url_shutdown call to abort parse cleanly */
     is->abort_request = 1;
     SDL_WaitThread(is->read_tid, NULL);
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index f3ffcfb..76d9402 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -693,6 +693,12 @@ typedef struct AVInputFormat {
     int (*read_packet)(struct AVFormatContext *, AVPacket *pkt);
 
     /**
+     * The stream is going to be closed. The AVFormatContext and AVStreams are not
+     * freed by this function
+     */
+    int (*read_preclose)(struct AVFormatContext *);
+  
+    /**
      * Close the stream. The AVFormatContext and AVStreams are not
      * freed by this function
      */
@@ -2231,6 +2237,14 @@ int av_read_play(AVFormatContext *s);
 int av_read_pause(AVFormatContext *s);
 
 /**
+ * Call before closing input AVFormatContext.
+ */
+void avformat_preclose_input(AVFormatContext **s);
+/**
+ * @}
+ */
+
+/**
  * Close an opened input AVFormatContext. Free it and all its contents
  * and set *s to NULL.
  */
diff --git a/libavformat/rtspdec.c b/libavformat/rtspdec.c
index 3c0010e..17afd47 100644
--- a/libavformat/rtspdec.c
+++ b/libavformat/rtspdec.c
@@ -53,13 +53,20 @@ static const struct RTSPStatusMessage {
     { 0,                          "NULL"                             }
 };
 
-static int rtsp_read_close(AVFormatContext *s)
+static int rtsp_read_preclose(AVFormatContext *s)
 {
     RTSPState *rt = s->priv_data;
 
-    if (!(rt->rtsp_flags & RTSP_FLAG_LISTEN))
-        ff_rtsp_send_cmd_async(s, "TEARDOWN", rt->control_uri, NULL);
+    if (!(rt->rtsp_flags & RTSP_FLAG_LISTEN)) {
+      ff_rtsp_send_cmd_async(s, "TEARDOWN", rt->control_uri, NULL);
+    }
+    return 0;
+}
 
+static int rtsp_read_close(AVFormatContext *s)
+{
+    RTSPState *rt = s->priv_data;
+	
     ff_rtsp_close_streams(s);
     ff_rtsp_close_connections(s);
     ff_network_close();
@@ -551,7 +558,7 @@ static int rtsp_read_play(AVFormatContext *s)
         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++) {
@@ -616,7 +623,7 @@ int ff_rtsp_setup_input_streams(AVFormatContext *s, RTSPMessageHeader *reply)
     }
     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);
@@ -966,6 +973,7 @@ AVInputFormat ff_rtsp_demuxer = {
     .read_probe     = rtsp_probe,
     .read_header    = rtsp_read_header,
     .read_packet    = rtsp_read_packet,
+    .read_preclose  = rtsp_read_preclose,
     .read_close     = rtsp_read_close,
     .read_seek      = rtsp_read_seek,
     .flags          = AVFMT_NOFILE,
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 689473e..853fb59 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -3707,6 +3707,20 @@ void avformat_free_context(AVFormatContext *s)
     av_free(s);
 }
 
+void avformat_preclose_input(AVFormatContext **ps)
+{
+    AVFormatContext *s;
+
+    if (!ps || !*ps)
+        return;
+
+    s  = *ps;
+    
+    if (s->iformat)
+        if (s->iformat->read_preclose)
+            s->iformat->read_preclose(s);
+}
+
 void avformat_close_input(AVFormatContext **ps)
 {
     AVFormatContext *s;
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to