[FFmpeg-devel] [PATCH] RTMP client support for lavf

Kostya kostya.shishkov
Wed Jul 29 08:26:05 CEST 2009


On Tue, Jul 28, 2009 at 03:33:36PM +0200, Michael Niedermayer wrote:
> On Tue, Jul 28, 2009 at 09:27:11AM +0300, Kostya wrote:
> > On Fri, Jul 24, 2009 at 03:08:32AM +0200, Michael Niedermayer wrote:
> > > On Thu, Jul 23, 2009 at 06:34:13AM +0300, Kostya wrote:
> > > > On Wed, Jul 22, 2009 at 12:01:46PM +0200, Michael Niedermayer wrote:
> > > > > On Wed, Jul 22, 2009 at 07:58:05AM +0300, Kostya wrote:
> > > > > > On Tue, Jul 21, 2009 at 11:30:26PM +0200, Michael Niedermayer wrote:
> > > > > > > On Tue, Jul 21, 2009 at 11:04:09AM +0300, Kostya wrote:
> > > > > > > > On Mon, Jul 20, 2009 at 05:05:41PM +0200, Michael Niedermayer wrote:
> > > > > > > > > On Sat, Jul 18, 2009 at 08:01:17PM +0300, Kostya wrote:
> > > > > > > > > > On Sat, Jul 18, 2009 at 11:29:34AM +0200, Michael Niedermayer wrote:
> > > > > > > > > > > On Fri, Jul 17, 2009 at 06:38:46PM +0300, Kostya wrote:
[...]
> > > also shouldnt there be checks against receiving the wrong thing in the wrong
> > > state?
> > 
> > well, because I can't be sure about what is wrong and I'm as willing to
> > read Adobe spec as you're willing sign some agreement (for the same
> > reason too).
> 
> so you think it might be ok for the playing state to return to prior
> not yet initialized states?
 
Yes, I'm pretty sure of that - especially when server streams the same
data on connect.
 
> [...]
> > +
> > +#define PLAYER_KEY_OPEN_PART_LEN 30   ///< length of partial key used for first client digest signing
> > +/** Client key used for digest signing */
> > +static const uint8_t rtmp_player_key[] = {
> > +    'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
> > +    'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
> > +
> > +    0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
> > +    0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
> > +    0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
> > +};
> > +
> > +#define SERVER_KEY_OPEN_PART_LEN 36   ///< length of partial key used for first server digest signing
> > +/** Key used for RTMP server digest signing */
> > +static const uint8_t rtmp_server_key[] = {
> > +    'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
> > +    'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
> > +    'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
> 
> Is it needed to lie here ? or does it also work with correct info?

Huh? That's the key used by server to sign handshake data. If server
uses different key then we can't deal with it. 
 
> [...]
> > +/**
> > + * Parses received packet and may perform some action depending on packet contents.
> > + * @return 0 for no errors, -1 for serious errors which prevent further
> > + *         communications, positive values for uncritical errors
> 
> please use <0 for errors like everything else in ffmpeg

ok

> [...]
> > +/**
> > + * Opens RTMP connection and verifies that the stream can be played.
> > + *
> > + * URL syntax: rtmp://server[:port][/app][/playpath]
> > + *             where 'app' is first one or two directories in the path
> > + *             (e.g. /ondemand/, /flash/live/, etc.)
> > + *             and 'playpath' is a file name (the rest of the path,
> > + *             may be prefixed with "mp4:")
> > + */
> > +static int rtmp_open(URLContext *s, const char *uri, int flags)
> > +{
> > +    RTMPContext *rt;
> > +    char proto[8], hostname[256], path[1024], app[128], *fname;
> > +    uint8_t buf[2048];
> > +    int port, is_input;
> > +
> > +    is_input = !(flags & URL_WRONLY);
> > +
> > +    rt = av_mallocz(sizeof(RTMPContext));
> > +    if (!rt)
> > +        return AVERROR(ENOMEM);
> > +    s->priv_data = rt;
> > +
> > +    url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
> > +              path, sizeof(path), s->filename);
> > +
> 
> > +    if (port == -1)
> > +        port = RTMP_DEFAULT_PORT;
> > +    snprintf(buf, sizeof(buf), "tcp://%s:%d", hostname, port);
> 
> so port==-2 is ok?

now it's ok
 
> > +
> > +    if (url_open(&rt->stream, buf, URL_RDWR) < 0)
> > +        goto fail;
> > +
> > +    if (!is_input) {
> > +        av_log(LOG_CONTEXT, AV_LOG_ERROR, "RTMP output is not supported yet.\n");
> > +        goto fail;
> > +    } else {
> > +        rt->state = STATE_START;
> > +        if (rtmp_handshake(s, rt))
> > +            return -1;
> > +
> > +        rt->chunk_size = 128;
> > +        rt->state = STATE_HANDSHAKED;
> > +        //extract "app" part from path
> > +        if (!strncmp(path, "/ondemand/", 10)) {
> > +            fname = path + 10;
> > +            memcpy(app, "ondemand", 9);
> > +        } else {
> > +            char *p = strchr(path + 1, '/');
> > +            if (!p) {
> > +                fname = path + 1;
> > +                app[0] = '\0';
> > +            } else {
> > +                fname = strchr(p + 1, '/');
> > +                if (!fname) {
> > +                    fname = p + 1;
> > +                    av_strlcpy(app, path + 1, p - path);
> > +                } else {
> > +                    fname++;
> > +                    av_strlcpy(app, path + 1, fname - path - 1);
> > +                }
> > +            }
> > +        }
> > +        if (!strcmp(fname + strlen(fname) - 4, ".f4v") ||
> > +            !strcmp(fname + strlen(fname) - 4, ".mp4")) {
> > +            memcpy(rt->playpath, "mp4:", 5);
> > +        } else {
> 
> > +            rt->playpath[0] = ':';
> > +            rt->playpath[0] = 0;
> 
> have you considered testing your code?

yes, and code seems to work. Maybe not always in optimal way :( 
 
> > +        }
> > +        strncat(rt->playpath, fname, sizeof(rt->playpath) - 5);
> > +
> > +        av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
> > +               proto, path, app, rt->playpath);
> > +        gen_connect(s, rt, proto, hostname, port, app);
> > +
> > +        if (get_packet(s, 1) < 0)
> > +            goto fail;
> 
> i doubt that will work with EAGAIN

now it works 

> > +        // generate FLV header for demuxer
> 
> > +        rt->flv_data = av_realloc(rt->flv_data, 13);
> > +        rt->flv_size = 13;
> 
> thats better the other way arround (without 2 litteral 13)

done 
 
> > +        rt->flv_off  = 0;
> > +        memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", 13);
> > +    }
> > +
> > +    s->max_packet_size = url_get_max_packet_size(rt->stream);
> > +    s->is_streamed = 1;
> > +    return 0;
> > +
> > +fail:
> > +    if (rt->stream)
> > +        url_close(rt->stream);
> > +    av_free(rt);
> 
> that looks almost like a duplicate of rtmp_close

now it's called 

> [...]
> > +URLProtocol rtmp_protocol = {
> > +    "rtmp",
> > +    rtmp_open,
> > +    rtmp_read,
> > +    rtmp_write,
> > +    NULL, /* seek */
> > +    rtmp_close,
> > +};
> 
> seeking is still not implemeneted?

not until API change, still thinking on it
 
> [...]
> > +/**
> > + * structure for holding RTMP packets
> > + */
> > +typedef struct RTMPPacket {
> > +    uint8_t        channel_id; ///< RTMP channel ID
> > +    RTMPPacketType type;       ///< packet type
> > +    uint32_t       timestamp;  ///< packet timestamp
> 
> > +    uint32_t       extra;      ///< additional data
> 
> thats very clear

for me too

> [...]
> -- 
> Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
-------------- next part --------------
A non-text attachment was scrubbed...
Name: rtmp.patch
Type: text/x-diff
Size: 43080 bytes
Desc: not available
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20090729/96ce7687/attachment.patch>



More information about the ffmpeg-devel mailing list