On Sat, 31 May 2014, Uwe L. Korn wrote:

In the presence of no metadata, do not set any stream flag in the FLV
header but let the decoder handle the detection and creation of streams
as data arrives.
---
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;
--
2.0.0

This looks quite ok to me. I'll test it a little and push in a while unless there's something else I've missed.

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

Reply via email to