[FFmpeg-cvslog] rtmp: Automatically compute the hash for SWFVerification

Samuel Pitoiset git at videolan.org
Thu Aug 16 16:24:42 CEST 2012


ffmpeg | branch: master | Samuel Pitoiset <samuel.pitoiset at gmail.com> | Wed Aug 15 16:11:50 2012 +0200| [93f257db6b818896e58c708d3c2ec4b8cb0c7b00] | committer: Martin Storsjö

rtmp: Automatically compute the hash for SWFVerification

Signed-off-by: Martin Storsjö <martin at martin.st>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=93f257db6b818896e58c708d3c2ec4b8cb0c7b00
---

 doc/protocols.texi      |    3 ++
 libavformat/rtmpproto.c |  134 +++++++++++++++++++++++++++++++++++++++++++++++
 libavformat/version.h   |    2 +-
 3 files changed, 138 insertions(+), 1 deletion(-)

diff --git a/doc/protocols.texi b/doc/protocols.texi
index bdb3e8c..ea5706f 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -251,6 +251,9 @@ Size of the decompressed SWF file, required for SWFVerification.
 @item rtmp_swfurl
 URL of the SWF player for the media. By default no value will be sent.
 
+ at item rtmp_swfverify
+URL to player swf file, compute hash/size automatically.
+
 @item rtmp_tcurl
 URL of the target stream. Defaults to proto://host[:port]/app.
 
diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c
index 9b85e52..db11501 100644
--- a/libavformat/rtmpproto.c
+++ b/libavformat/rtmpproto.c
@@ -41,6 +41,10 @@
 #include "rtmppkt.h"
 #include "url.h"
 
+#if CONFIG_ZLIB
+#include <zlib.h>
+#endif
+
 //#define DEBUG
 
 #define APP_MAX_LENGTH 128
@@ -95,6 +99,7 @@ typedef struct RTMPContext {
     int           swfhash_len;                ///< length of the SHA256 hash
     int           swfsize;                    ///< size of the decompressed SWF file
     char*         swfurl;                     ///< url of the swf player
+    char*         swfverify;                  ///< URL to player swf file, compute hash/size automatically
     char          swfverification[42];        ///< hash of the SWF verification
     char*         pageurl;                    ///< url of the web page
     char*         subscribe;                  ///< name of live stream to subscribe
@@ -825,6 +830,129 @@ static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt,
     return 0;
 }
 
+#if CONFIG_ZLIB
+static int rtmp_uncompress_swfplayer(uint8_t *in_data, int64_t in_size,
+                                     uint8_t **out_data, int64_t *out_size)
+{
+    z_stream zs = { 0 };
+    void *ptr;
+    int size;
+    int ret = 0;
+
+    zs.avail_in = in_size;
+    zs.next_in  = in_data;
+    ret = inflateInit(&zs);
+    if (ret != Z_OK)
+        return AVERROR_UNKNOWN;
+
+    do {
+        uint8_t tmp_buf[16384];
+
+        zs.avail_out = sizeof(tmp_buf);
+        zs.next_out  = tmp_buf;
+
+        ret = inflate(&zs, Z_NO_FLUSH);
+        if (ret != Z_OK && ret != Z_STREAM_END) {
+            ret = AVERROR_UNKNOWN;
+            goto fail;
+        }
+
+        size = sizeof(tmp_buf) - zs.avail_out;
+        if (!(ptr = av_realloc(*out_data, *out_size + size))) {
+            ret = AVERROR(ENOMEM);
+            goto fail;
+        }
+        *out_data = ptr;
+
+        memcpy(*out_data + *out_size, tmp_buf, size);
+        *out_size += size;
+    } while (zs.avail_out == 0);
+
+fail:
+    inflateEnd(&zs);
+    return ret;
+}
+#endif
+
+static int rtmp_calc_swfhash(URLContext *s)
+{
+    RTMPContext *rt = s->priv_data;
+    uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
+    int64_t in_size, out_size;
+    URLContext *stream;
+    char swfhash[32];
+    int swfsize;
+    int ret = 0;
+
+    /* Get the SWF player file. */
+    if ((ret = ffurl_open(&stream, rt->swfverify, AVIO_FLAG_READ,
+                          &s->interrupt_callback, NULL)) < 0) {
+        av_log(s, AV_LOG_ERROR, "Cannot open connection %s.\n", rt->swfverify);
+        goto fail;
+    }
+
+    if ((in_size = ffurl_seek(stream, 0, AVSEEK_SIZE)) < 0) {
+        ret = AVERROR(EIO);
+        goto fail;
+    }
+
+    if (!(in_data = av_malloc(in_size))) {
+        ret = AVERROR(ENOMEM);
+        goto fail;
+    }
+
+    if ((ret = ffurl_read_complete(stream, in_data, in_size)) < 0)
+        goto fail;
+
+    if (in_size < 3) {
+        ret = AVERROR_INVALIDDATA;
+        goto fail;
+    }
+
+    if (!memcmp(in_data, "CWS", 3)) {
+        /* Decompress the SWF player file using Zlib. */
+        if (!(out_data = av_malloc(8))) {
+            ret = AVERROR(ENOMEM);
+            goto fail;
+        }
+        *in_data = 'F'; // magic stuff
+        memcpy(out_data, in_data, 8);
+        out_size = 8;
+
+#if CONFIG_ZLIB
+        if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
+                                             &out_data, &out_size)) < 0)
+            goto fail;
+#else
+        av_log(s, AV_LOG_ERROR,
+               "Zlib is required for decompressing the SWF player file.\n");
+        ret = AVERROR(EINVAL);
+        goto fail;
+#endif
+        swfsize = out_size;
+        swfdata = out_data;
+    } else {
+        swfsize = in_size;
+        swfdata = in_data;
+    }
+
+    /* Compute the SHA256 hash of the SWF player file. */
+    if ((ret = ff_rtmp_calc_digest(swfdata, swfsize, 0,
+                                   "Genuine Adobe Flash Player 001", 30,
+                                   swfhash)) < 0)
+        goto fail;
+
+    /* Set SWFVerification parameters. */
+    av_opt_set_bin(rt, "rtmp_swfhash", swfhash, 32, 0);
+    rt->swfsize = swfsize;
+
+fail:
+    av_freep(&in_data);
+    av_freep(&out_data);
+    ffurl_close(stream);
+    return ret;
+}
+
 /**
  * Perform handshake with the server by means of exchanging pseudorandom data
  * signed with HMAC-SHA2 digest.
@@ -1492,6 +1620,11 @@ static int rtmp_open(URLContext *s, const char *uri, int flags)
         goto fail;
     }
 
+    if (rt->swfverify) {
+        if ((ret = rtmp_calc_swfhash(s)) < 0)
+            goto fail;
+    }
+
     rt->state = STATE_START;
     if ((ret = rtmp_handshake(s, rt)) < 0)
         goto fail;
@@ -1784,6 +1917,7 @@ static const AVOption rtmp_options[] = {
     {"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_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
     {"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 },
 };
diff --git a/libavformat/version.h b/libavformat/version.h
index 54185fa..e54f22e 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -31,7 +31,7 @@
 
 #define LIBAVFORMAT_VERSION_MAJOR 54
 #define LIBAVFORMAT_VERSION_MINOR 13
-#define LIBAVFORMAT_VERSION_MICRO  3
+#define LIBAVFORMAT_VERSION_MICRO  4
 
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
                                                LIBAVFORMAT_VERSION_MINOR, \



More information about the ffmpeg-cvslog mailing list