diff options
author | Uwe L. Korn <uwelk@xhochy.com> | 2014-05-31 20:37:26 +0100 |
---|---|---|
committer | Martin Storsjö <martin@martin.st> | 2014-06-01 23:30:48 +0300 |
commit | 59cb5747ec3c5cd842b94e574c37889521c97cc4 (patch) | |
tree | a439cc21684d9a25a0f08810de0a5f497690ec64 | |
parent | 3b18857ab301d2a0b3e86e9d85eed76f0798a29c (diff) | |
download | ffmpeg-59cb5747ec3c5cd842b94e574c37889521c97cc4.tar.gz |
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ö <martin@martin.st>
-rw-r--r-- | libavformat/rtmpproto.c | 66 |
1 files changed, 65 insertions, 1 deletions
diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c index 0cc702ad62..de09486dd7 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; |