rtmp: Make the input FLV parser handle data cut at any point
authorMartin Storsjö <martin@martin.st>
Wed, 21 Sep 2011 20:21:30 +0000 (23:21 +0300)
committerMartin Storsjö <martin@martin.st>
Thu, 22 Sep 2011 07:36:16 +0000 (10:36 +0300)
This makes the RTMP writing code able to handle FLV data
fed in arbitrarily small or large chunks, with multiple
consecutive packets in one write call, or having the FLV
packet header split over numerous write calls.

When used in conjunction with the flv muxer, the AVIO buffer
size still needs to be large enough to fit the initial metadata
packet though, since the size of that packet is written with a
seekback.

Signed-off-by: Martin Storsjö <martin@martin.st>
libavformat/rtmpproto.c

index a8be052..093d21a 100644 (file)
@@ -72,6 +72,8 @@ typedef struct RTMPContext {
     uint32_t      bytes_read;                 ///< number of bytes read from server
     uint32_t      last_bytes_read;            ///< number of bytes read last reported to server
     int           skip_bytes;                 ///< number of bytes to skip from the input FLV stream in the next write call
     uint32_t      bytes_read;                 ///< number of bytes read from server
     uint32_t      last_bytes_read;            ///< number of bytes read last reported to server
     int           skip_bytes;                 ///< number of bytes to skip from the input FLV stream in the next write call
+    uint8_t       flv_header[11];             ///< partial incoming flv packet header
+    int           flv_header_bytes;           ///< number of initialized bytes in flv_header
 } RTMPContext;
 
 #define PLAYER_KEY_OPEN_PART_LEN 30   ///< length of partial key used for first client digest signing
 } RTMPContext;
 
 #define PLAYER_KEY_OPEN_PART_LEN 30   ///< length of partial key used for first client digest signing
@@ -880,6 +882,7 @@ static int rtmp_open(URLContext *s, const char *uri, int flags)
         rt->flv_size = 0;
         rt->flv_data = NULL;
         rt->flv_off  = 0;
         rt->flv_size = 0;
         rt->flv_data = NULL;
         rt->flv_off  = 0;
+        rt->skip_bytes = 13;
     }
 
     s->max_packet_size = rt->stream->max_packet_size;
     }
 
     s->max_packet_size = rt->stream->max_packet_size;
@@ -926,34 +929,29 @@ static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
     uint32_t ts;
     const uint8_t *buf_temp = buf;
 
     uint32_t ts;
     const uint8_t *buf_temp = buf;
 
-    if (rt->skip_bytes) {
-        int skip = FFMIN(rt->skip_bytes, size);
-        buf_temp       += skip;
-        size_temp      -= skip;
-        rt->skip_bytes -= skip;
-        if (size_temp <= 0)
-            return size;
-    }
-
-    if (!rt->flv_off && size_temp < 11) {
-        av_log(s, AV_LOG_DEBUG, "FLV packet too small %d\n", size);
-        return 0;
-    }
-
     do {
     do {
-        if (!rt->flv_off) {
-            //skip flv header
-            if (buf_temp[0] == 'F' && buf_temp[1] == 'L' && buf_temp[2] == 'V') {
-                buf_temp += 9 + 4;
-                size_temp -= 9 + 4;
-            }
+        if (rt->skip_bytes) {
+            int skip = FFMIN(rt->skip_bytes, size_temp);
+            buf_temp       += skip;
+            size_temp      -= skip;
+            rt->skip_bytes -= skip;
+            continue;
+        }
+
+        if (rt->flv_header_bytes < 11) {
+            const uint8_t *header = rt->flv_header;
+            int copy = FFMIN(11 - rt->flv_header_bytes, size_temp);
+            bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
+            rt->flv_header_bytes += copy;
+            size_temp            -= copy;
+            if (rt->flv_header_bytes < 11)
+                break;
 
 
-            pkttype = bytestream_get_byte(&buf_temp);
-            pktsize = bytestream_get_be24(&buf_temp);
-            ts = bytestream_get_be24(&buf_temp);
-            ts |= bytestream_get_byte(&buf_temp) << 24;
-            bytestream_get_be24(&buf_temp);
-            size_temp -= 11;
+            pkttype = bytestream_get_byte(&header);
+            pktsize = bytestream_get_be24(&header);
+            ts = bytestream_get_be24(&header);
+            ts |= bytestream_get_byte(&header) << 24;
+            bytestream_get_be24(&header);
             rt->flv_size = pktsize;
 
             //force 12bytes header
             rt->flv_size = pktsize;
 
             //force 12bytes header
@@ -984,18 +982,13 @@ static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
         }
 
         if (rt->flv_off == rt->flv_size) {
         }
 
         if (rt->flv_off == rt->flv_size) {
-            if (size_temp < 4) {
-                rt->skip_bytes = 4 - size_temp;
-                buf_temp += size_temp;
-                size_temp = 0;
-            } else {
-                bytestream_get_be32(&buf_temp);
-                size_temp -= 4;
-            }
+            rt->skip_bytes = 4;
+
             ff_rtmp_packet_write(rt->stream, &rt->out_pkt, rt->chunk_size, rt->prev_pkt[1]);
             ff_rtmp_packet_destroy(&rt->out_pkt);
             rt->flv_size = 0;
             rt->flv_off = 0;
             ff_rtmp_packet_write(rt->stream, &rt->out_pkt, rt->chunk_size, rt->prev_pkt[1]);
             ff_rtmp_packet_destroy(&rt->out_pkt);
             rt->flv_size = 0;
             rt->flv_off = 0;
+            rt->flv_header_bytes = 0;
         }
     } while (buf_temp - buf < size);
     return size;
         }
     } while (buf_temp - buf < size);
     return size;