Module: libav
Branch: master
Commit: 59cb5747ec3c5cd842b94e574c37889521c97cc4

Author:    Uwe L. Korn <[email protected]>
Committer: Martin Storsjö <[email protected]>
Date:      Sat May 31 20:37:26 2014 +0100

rtmpproto: read metadata to set correct FLV header

In the presence of no metadata, do not set any stream flag in the FLV
header but let the demuxer handle the detection and creation of streams
as data arrives.

Signed-off-by: Martin Storsjö <[email protected]>

---

 libavformat/rtmpproto.c |   66 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 65 insertions(+), 1 deletion(-)

diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c
index 0cc702a..de09486 100644
--- a/libavformat/rtmpproto.c
+++ b/libavformat/rtmpproto.c
@@ -97,6 +97,9 @@ 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
+    int           has_audio;                  ///< presence of audio data
+    int           has_video;                  ///< presence of video data
+    int           received_metadata;          ///< Indicates if we have 
received metadata about the streams
     uint8_t       flv_header[RTMP_HEADER];    ///< partial incoming flv packet 
header
     int           flv_header_bytes;           ///< number of initialized bytes 
in flv_header
     int           nb_invokes;                 ///< keeps track of invoke 
messages
@@ -2109,6 +2112,12 @@ static int append_flv_data(RTMPContext *rt, RTMPPacket 
*pkt, int skip)
     const int size      = pkt->size - skip;
     uint32_t ts         = pkt->timestamp;
 
+    if (pkt->type == RTMP_PT_AUDIO) {
+        rt->has_audio = 1;
+    } else if (pkt->type == RTMP_PT_VIDEO) {
+        rt->has_video = 1;
+    }
+
     old_flv_size = update_offset(rt, size + 15);
 
     if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
@@ -2141,6 +2150,38 @@ static int handle_notify(URLContext *s, RTMPPacket *pkt)
                            &stringlen))
         return AVERROR_INVALIDDATA;
 
+    if (!strcmp(commandbuffer, "onMetaData")) {
+        // metadata properties should be stored in a mixed array
+        if (bytestream2_get_byte(&gbc) == AMF_DATA_TYPE_MIXEDARRAY) {
+            // We have found a metaData Array so flv can determine the streams
+            // from this.
+            rt->received_metadata = 1;
+            // skip 32-bit max array index
+            bytestream2_skip(&gbc, 4);
+            while (bytestream2_get_bytes_left(&gbc) > 3) {
+                if (ff_amf_get_string(&gbc, statusmsg, sizeof(statusmsg),
+                                      &stringlen))
+                    return AVERROR_INVALIDDATA;
+                // We do not care about the content of the property (yet).
+                stringlen = ff_amf_tag_size(gbc.buffer, gbc.buffer_end);
+                if (stringlen < 0)
+                    return AVERROR_INVALIDDATA;
+                bytestream2_skip(&gbc, stringlen);
+
+                // The presence of the following properties indicates that the
+                // respective streams are present.
+                if (!strcmp(statusmsg, "videocodecid")) {
+                    rt->has_video = 1;
+                }
+                if (!strcmp(statusmsg, "audiocodecid")) {
+                    rt->has_audio = 1;
+                }
+            }
+            if (bytestream2_get_be24(&gbc) != AMF_END_OF_OBJECT)
+                return AVERROR_INVALIDDATA;
+        }
+    }
+
     // Skip the @setDataFrame string and validate it is a notification
     if (!strcmp(commandbuffer, "@setDataFrame")) {
         skip = gbc.buffer - pkt->data;
@@ -2571,6 +2612,9 @@ reconnect:
 
     rt->client_report_size = 1048576;
     rt->bytes_read = 0;
+    rt->has_audio = 0;
+    rt->has_video = 0;
+    rt->received_metadata = 0;
     rt->last_bytes_read = 0;
     rt->server_bw = 2500000;
 
@@ -2610,7 +2654,27 @@ reconnect:
         if ((err = av_reallocp(&rt->flv_data, rt->flv_size)) < 0)
             return err;
         rt->flv_off  = 0;
-        memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size);
+        memcpy(rt->flv_data, "FLV\1\0\0\0\0\011\0\0\0\0", rt->flv_size);
+
+        // Read packets until we reach the first A/V packet or read metadata.
+        // If there was a metadata package in front of the A/V packets, we can
+        // build the FLV header from this. If we do not receive any metadata,
+        // the FLV decoder will allocate the needed streams when their first
+        // audio or video packet arrives.
+        while (!rt->has_audio && !rt->has_video && !rt->received_metadata) {
+            if ((ret = get_packet(s, 0)) < 0)
+               return ret;
+        }
+
+        // Either after we have read the metadata or (if there is none) the
+        // first packet of an A/V stream, we have a better knowledge about the
+        // streams, so set the FLV header accordingly.
+        if (rt->has_audio) {
+            rt->flv_data[4] |= FLV_HEADER_FLAG_HASAUDIO;
+        }
+        if (rt->has_video) {
+            rt->flv_data[4] |= FLV_HEADER_FLAG_HASVIDEO;
+        }
     } else {
         rt->flv_size = 0;
         rt->flv_data = NULL;

_______________________________________________
libav-commits mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-commits

Reply via email to