rtmp: Make the input FLV parser handle data cut at any point
[ffmpeg.git] / 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
+    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
@@ -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->skip_bytes = 13;
     }
 
     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;
 
-    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 {
-        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
@@ -984,18 +982,13 @@ static int rtmp_write(URLContext *s, const uint8_t *buf, int 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;
+            rt->flv_header_bytes = 0;
         }
     } while (buf_temp - buf < size);
     return size;