diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2012-08-15 15:41:01 +0200 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2012-08-15 15:55:24 +0200 |
commit | 9e89bc37edfcd1b4b0a22c096c6546df4a9d1c0b (patch) | |
tree | de31fc8aa5b32d28a0143aff2477b4c3ada40318 /libavformat/rtmpproto.c | |
parent | aee7b88cc0675fb668e39e8f4a50f2b1bd9305d4 (diff) | |
parent | 635ac8e1be91e941908f85642e4bbb609e48193f (diff) | |
download | ffmpeg-9e89bc37edfcd1b4b0a22c096c6546df4a9d1c0b.tar.gz |
Merge remote-tracking branch 'qatar/master'
* qatar/master:
rtmp: Add support for SWFVerification
api-example: use new video encoding API.
x86: avcodec: Appropriately name files containing only init functions
mpegvideo_mmx_template: drop some commented-out cruft
libavresample: add mix level normalization option
w32pthreads: Add missing #includes to make header compile standalone
rtmp: Gracefully ignore _checkbw errors by tracking them
rtmp: Do not send _checkbw calls as notifications
prores: interlaced ProRes encoding
Conflicts:
doc/examples/decoding_encoding.c
libavcodec/proresenc_kostya.c
libavcodec/w32pthreads.h
libavcodec/x86/Makefile
libavformat/version.h
Merged-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavformat/rtmpproto.c')
-rw-r--r-- | libavformat/rtmpproto.c | 88 |
1 files changed, 83 insertions, 5 deletions
diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c index 4f57cb8a21..e3bcf3d843 100644 --- a/libavformat/rtmpproto.c +++ b/libavformat/rtmpproto.c @@ -91,7 +91,11 @@ typedef struct RTMPContext { int nb_invokes; ///< keeps track of invoke messages char* tcurl; ///< url of the target stream char* flashver; ///< version of the flash plugin + char* swfhash; ///< SHA256 hash of the decompressed SWF file (32 bytes) + int swfhash_len; ///< length of the SHA256 hash + int swfsize; ///< size of the decompressed SWF file char* swfurl; ///< url of the swf player + char swfverification[42]; ///< hash of the SWF verification char* pageurl; ///< url of the web page char* subscribe; ///< name of live stream to subscribe int server_bw; ///< server bandwidth @@ -593,6 +597,27 @@ static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt) } /** + * Generate SWF verification message and send it to the server. + */ +static int gen_swf_verification(URLContext *s, RTMPContext *rt) +{ + RTMPPacket pkt; + uint8_t *p; + int ret; + + av_log(s, AV_LOG_DEBUG, "Sending SWF verification...\n"); + if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, + 0, 44)) < 0) + return ret; + + p = pkt.data; + bytestream_put_be16(&p, 27); + memcpy(p, rt->swfverification, 42); + + return rtmp_send_packet(rt, &pkt, 0); +} + +/** * Generate server bandwidth message and send it to the server. */ static int gen_server_bw(URLContext *s, RTMPContext *rt) @@ -626,10 +651,10 @@ static int gen_check_bw(URLContext *s, RTMPContext *rt) p = pkt.data; ff_amf_write_string(&p, "_checkbw"); - ff_amf_write_number(&p, RTMP_NOTIFICATION); + ff_amf_write_number(&p, ++rt->nb_invokes); ff_amf_write_null(&p); - return rtmp_send_packet(rt, &pkt, 0); + return rtmp_send_packet(rt, &pkt, 1); } /** @@ -776,6 +801,30 @@ static int rtmp_validate_digest(uint8_t *buf, int off) return 0; } +static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt, + uint8_t *buf) +{ + uint8_t *p; + int ret; + + if (rt->swfhash_len != 32) { + av_log(s, AV_LOG_ERROR, + "Hash of the decompressed SWF file is not 32 bytes long.\n"); + return AVERROR(EINVAL); + } + + p = &rt->swfverification[0]; + bytestream_put_byte(&p, 1); + bytestream_put_byte(&p, 1); + bytestream_put_be32(&p, rt->swfsize); + bytestream_put_be32(&p, rt->swfsize); + + if ((ret = ff_rtmp_calc_digest(rt->swfhash, 32, 0, buf, 32, p)) < 0) + return ret; + + return 0; +} + /** * Perform handshake with the server by means of exchanging pseudorandom data * signed with HMAC-SHA2 digest. @@ -866,6 +915,14 @@ static int rtmp_handshake(URLContext *s, RTMPContext *rt) } } + /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF, + * key are the last 32 bytes of the server handshake. */ + if (rt->swfsize) { + if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 + + RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0) + return ret; + } + ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0, rtmp_server_key, sizeof(rtmp_server_key), digest); @@ -1001,6 +1058,13 @@ static int handle_ping(URLContext *s, RTMPPacket *pkt) if (t == 6) { if ((ret = gen_pong(s, rt, pkt)) < 0) return ret; + } else if (t == 26) { + if (rt->swfsize) { + if ((ret = gen_swf_verification(s, rt)) < 0) + return ret; + } else { + av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n"); + } } return 0; @@ -1055,15 +1119,27 @@ static int handle_server_bw(URLContext *s, RTMPPacket *pkt) static int handle_invoke_error(URLContext *s, RTMPPacket *pkt) { const uint8_t *data_end = pkt->data + pkt->data_size; + char *tracked_method = NULL; + int level = AV_LOG_ERROR; uint8_t tmpstr[256]; + int ret; + + if ((ret = find_tracked_method(s, pkt, 9, &tracked_method)) < 0) + return ret; if (!ff_amf_get_field_value(pkt->data + 9, data_end, "description", tmpstr, sizeof(tmpstr))) { - av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr); - return -1; + if (tracked_method && !strcmp(tracked_method, "_checkbw")) { + /* Ignore _checkbw errors. */ + level = AV_LOG_WARNING; + ret = 0; + } else + ret = -1; + av_log(s, level, "Server error: %s\n", tmpstr); } - return 0; + av_free(tracked_method); + return ret; } static int handle_invoke_result(URLContext *s, RTMPPacket *pkt) @@ -1705,6 +1781,8 @@ static const AVOption rtmp_options[] = { {"rtmp_pageurl", "URL of the web page in which the media was embedded. By default no value will be sent.", OFFSET(pageurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC}, {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC}, {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC}, + {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC}, + {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {0}, 0, INT_MAX, DEC}, {"rtmp_swfurl", "URL of the SWF player. By default no value will be sent", OFFSET(swfurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC}, {"rtmp_tcurl", "URL of the target stream. Defaults to proto://host[:port]/app.", OFFSET(tcurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC}, { NULL }, |