Browse code

Merge commit '0d6fa3977b016f1b72b0b24b8834ff9222498548'

* commit '0d6fa3977b016f1b72b0b24b8834ff9222498548':
rtmp: Add seek support

Conflicts:
Changelog
libavformat/version.h

Merged-by: Michael Niedermayer <michaelni@gmx.at>

Michael Niedermayer authored on 2013/08/03 16:01:48
Showing 3 changed files
... ...
@@ -7,6 +7,7 @@ version <next>
7 7
 - perspective filter ported from libmpcodecs
8 8
 - ffprobe -show_programs option
9 9
 - compand filter
10
+- RTMP seek support
10 11
 
11 12
 
12 13
 version 2.0:
... ...
@@ -60,6 +60,7 @@ typedef enum {
60 60
     STATE_HANDSHAKED, ///< client has performed handshake
61 61
     STATE_FCPUBLISH,  ///< client FCPublishing stream (for output)
62 62
     STATE_PLAYING,    ///< client has started receiving multimedia data from server
63
+    STATE_SEEKING,    ///< client has started the seek operation. Back on STATE_PLAYING when the time comes
63 64
     STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output)
64 65
     STATE_RECEIVING,  ///< received a publish command (for input)
65 66
     STATE_STOPPED,    ///< the broadcast has been stopped
... ...
@@ -704,6 +705,28 @@ static int gen_play(URLContext *s, RTMPContext *rt)
704 704
     return rtmp_send_packet(rt, &pkt, 1);
705 705
 }
706 706
 
707
+static int gen_seek(URLContext *s, RTMPContext *rt, int64_t timestamp)
708
+{
709
+    RTMPPacket pkt;
710
+    uint8_t *p;
711
+    int ret;
712
+
713
+    av_log(s, AV_LOG_DEBUG, "Sending seek command for timestamp %lld\n", timestamp);
714
+
715
+    if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 26)) < 0)
716
+        return ret;
717
+
718
+    pkt.extra = rt->main_channel_id;
719
+
720
+    p = pkt.data;
721
+    ff_amf_write_string(&p, "seek");
722
+    ff_amf_write_number(&p, 0); //no tracking back responses
723
+    ff_amf_write_null(&p); //as usual, the first null param
724
+    ff_amf_write_number(&p, timestamp); //where we want to jump
725
+
726
+    return rtmp_send_packet(rt, &pkt, 1);
727
+}
728
+
707 729
 /**
708 730
  * Generate 'publish' call and send it to the server.
709 731
  */
... ...
@@ -1960,6 +1983,7 @@ static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
1960 1960
     if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
1961 1961
     if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
1962 1962
     if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
1963
+    if (!t && !strcmp(tmpstr, "NetStream.Seek.Notify")) rt->state = STATE_PLAYING;
1963 1964
 
1964 1965
     return 0;
1965 1966
 }
... ...
@@ -2148,6 +2172,17 @@ static int get_packet(URLContext *s, int for_header)
2148 2148
         }
2149 2149
 
2150 2150
         ret = rtmp_parse_result(s, rt, &rpkt);
2151
+
2152
+        // At this point we must check if we are in the seek state and continue
2153
+        // with the next packet. handle_invoke will get us out of this state
2154
+        // when the right message is encountered
2155
+        if (rt->state == STATE_SEEKING) {
2156
+            ff_rtmp_packet_destroy(&rpkt);
2157
+            // We continue, let the natural flow of things happen:
2158
+            // AVERROR(EAGAIN) or handle_invoke gets us out of here
2159
+            continue;
2160
+        }
2161
+
2151 2162
         if (ret < 0) {//serious error in current packet
2152 2163
             ff_rtmp_packet_destroy(&rpkt);
2153 2164
             return ret;
... ...
@@ -2512,6 +2547,25 @@ static int rtmp_read(URLContext *s, uint8_t *buf, int size)
2512 2512
     return orig_size;
2513 2513
 }
2514 2514
 
2515
+static int64_t rtmp_seek(URLContext *s, int stream_index, int64_t timestamp,
2516
+                         int flags)
2517
+{
2518
+    RTMPContext *rt = s->priv_data;
2519
+    int ret;
2520
+    av_log(s, AV_LOG_DEBUG,
2521
+           "Seek on stream index %d at timestamp %lld with flags %08x\n",
2522
+           stream_index, timestamp, flags);
2523
+    if ((ret = gen_seek(s, rt, timestamp)) < 0) {
2524
+        av_log(s, AV_LOG_ERROR,
2525
+               "Unable to send seek command on stream index %d at timestamp %lld with flags %08x\n",
2526
+               stream_index, timestamp, flags);
2527
+        return ret;
2528
+    }
2529
+    rt->flv_off = rt->flv_size;
2530
+    rt->state = STATE_SEEKING;
2531
+    return timestamp;
2532
+}
2533
+
2515 2534
 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
2516 2535
 {
2517 2536
     RTMPContext *rt = s->priv_data;
... ...
@@ -2663,6 +2717,7 @@ URLProtocol ff_##flavor##_protocol = {           \
2663 2663
     .name           = #flavor,                   \
2664 2664
     .url_open       = rtmp_open,                 \
2665 2665
     .url_read       = rtmp_read,                 \
2666
+    .url_read_seek  = rtmp_seek,                 \
2666 2667
     .url_write      = rtmp_write,                \
2667 2668
     .url_close      = rtmp_close,                \
2668 2669
     .priv_data_size = sizeof(RTMPContext),       \
... ...
@@ -30,8 +30,8 @@
30 30
 #include "libavutil/avutil.h"
31 31
 
32 32
 #define LIBAVFORMAT_VERSION_MAJOR 55
33
-#define LIBAVFORMAT_VERSION_MINOR 12
34
-#define LIBAVFORMAT_VERSION_MICRO 102
33
+#define LIBAVFORMAT_VERSION_MINOR 13
34
+#define LIBAVFORMAT_VERSION_MICRO 100
35 35
 
36 36
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
37 37
                                                LIBAVFORMAT_VERSION_MINOR, \