rtmp: Make the input FLV parser handle data cut at any point

Message ID 1316638832-13508-1-git-send-email-martin@martin.st
State Committed
Commit b14629e5eafb34dd71702aa42863388438060cd1
Headers show

Commit Message

Martin Storsjö Sept. 21, 2011, 9 p.m.
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.
---
 libavformat/rtmpproto.c |   61 ++++++++++++++++++++--------------------------
 1 files changed, 27 insertions(+), 34 deletions(-)

Comments

Kostya Shishkov Sept. 22, 2011, 5:22 a.m. | #1
On Thu, Sep 22, 2011 at 12:00:32AM +0300, Martin Storsjö wrote:
> 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.
> ---
>  libavformat/rtmpproto.c |   61 ++++++++++++++++++++--------------------------
>  1 files changed, 27 insertions(+), 34 deletions(-)

LGTM
Martin Storsjö Sept. 22, 2011, 8:01 a.m. | #2
On Thu, 22 Sep 2011, Kostya Shishkov wrote:

> On Thu, Sep 22, 2011 at 12:00:32AM +0300, Martin Storsjö wrote:
>> 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.
>> ---
>>  libavformat/rtmpproto.c |   61 ++++++++++++++++++++--------------------------
>>  1 files changed, 27 insertions(+), 34 deletions(-)
>
> LGTM

Applied

// Martin
Luca Barbato Sept. 22, 2011, 11:21 a.m. | #3
+1

Patch

diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c
index a8be052..093d21a 100644
--- a/libavformat/rtmpproto.c
+++ b/libavformat/rtmpproto.c
@@ -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;