From: Michael Niedermayer Date: Sun, 1 Jun 2014 22:32:06 +0000 (+0200) Subject: Merge commit '59cb5747ec3c5cd842b94e574c37889521c97cc4' X-Git-Tag: n2.3~791 X-Git-Url: http://git.videolan.org/?p=ffmpeg.git;a=commitdiff_plain;h=e91f27cbbb276bbdc9f7bc18e69e9b5fe6d16387;hp=-c Merge commit '59cb5747ec3c5cd842b94e574c37889521c97cc4' * commit '59cb5747ec3c5cd842b94e574c37889521c97cc4': rtmpproto: read metadata to set correct FLV header Merged-by: Michael Niedermayer --- e91f27cbbb276bbdc9f7bc18e69e9b5fe6d16387 diff --combined libavformat/rtmpproto.c index 7aa8b51593,de09486dd7..3814da8c54 --- a/libavformat/rtmpproto.c +++ b/libavformat/rtmpproto.c @@@ -2,20 -2,20 +2,20 @@@ * RTMP network protocol * Copyright (c) 2009 Konstantin Shishkov * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@@ -48,7 -48,7 +48,7 @@@ #include #endif -#define APP_MAX_LENGTH 128 +#define APP_MAX_LENGTH 1024 #define PLAYPATH_MAX_LENGTH 256 #define TCURL_MAX_LENGTH 512 #define FLASHVER_MAX_LENGTH 64 @@@ -97,6 -97,9 +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 @@@ -271,6 -274,9 +274,6 @@@ static int rtmp_write_amf_data(URLConte *value = '\0'; value++; - if (!field || !value) - goto fail; - ff_amf_write_field_name(p, field); } else { goto fail; @@@ -317,7 -323,7 +320,7 @@@ static int gen_connect(URLContext *s, R int ret; if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, - 0, 4096)) < 0) + 0, 4096 + APP_MAX_LENGTH)) < 0) return ret; p = pkt.data; @@@ -414,7 -420,6 +417,7 @@@ static int read_connect(URLContext *s, if (pkt.type == RTMP_PT_CHUNK_SIZE) { if ((ret = handle_chunk_size(s, &pkt)) < 0) return ret; + ff_rtmp_packet_destroy(&pkt); if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size, &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0) @@@ -1712,23 -1717,18 +1715,23 @@@ static int handle_connect_error(URLCont char *value = strchr(ptr, '='); if (next) *next++ = '\0'; - if (value) + if (value) { *value++ = '\0'; - if (!strcmp(ptr, "user")) { - user = value; - } else if (!strcmp(ptr, "salt")) { - salt = value; - } else if (!strcmp(ptr, "opaque")) { - opaque = value; - } else if (!strcmp(ptr, "challenge")) { - challenge = value; - } else if (!strcmp(ptr, "nonce")) { - nonce = value; + if (!strcmp(ptr, "user")) { + user = value; + } else if (!strcmp(ptr, "salt")) { + salt = value; + } else if (!strcmp(ptr, "opaque")) { + opaque = value; + } else if (!strcmp(ptr, "challenge")) { + challenge = value; + } else if (!strcmp(ptr, "nonce")) { + nonce = value; + } else { + av_log(s, AV_LOG_INFO, "Ignoring unsupported var %s\n", ptr); + } + } else { + av_log(s, AV_LOG_WARNING, "Variable %s has NULL value\n", ptr); } ptr = next; } @@@ -2112,6 -2112,12 +2115,12 @@@ static int append_flv_data(RTMPContext 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) { @@@ -2144,6 -2150,38 +2153,38 @@@ static int handle_notify(URLContext *s &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; @@@ -2287,7 -2325,7 +2328,7 @@@ static int get_packet(URLContext *s, in } } rt->bytes_read += ret; - if (rt->bytes_read > rt->last_bytes_read + rt->client_report_size) { + if (rt->bytes_read - rt->last_bytes_read > rt->client_report_size) { av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n"); if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0) return ret; @@@ -2521,10 -2559,6 +2562,10 @@@ reconnect if (old_app) { // The name of application has been defined by the user, override it. + if (strlen(old_app) >= APP_MAX_LENGTH) { + ret = AVERROR(EINVAL); + goto fail; + } av_free(rt->app); rt->app = old_app; } @@@ -2578,6 -2612,9 +2619,9 @@@ 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; @@@ -2617,7 -2654,27 +2661,27 @@@ 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;