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

Michael Niedermayer michaelni
Tue Jul 28 15:33:36 CEST 2009


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:
> [...]
> > > +        if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
> > > +            uint8_t tmpstr[256];
> > > +
> > > +            if (!ff_amf_find_field(pkt->data + 9, pkt->data + pkt->data_size,
> > > +                                   "description", tmpstr, sizeof(tmpstr)))
> > > +                av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
> > > +            return -1;
> > > +        }
> > > +        if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
> > > +            switch (rt->state) {
> > > +            case STATE_HANDSHAKED:
> > > +                gen_create_stream(s, rt);
> > > +                rt->state = STATE_CONNECTING;
> > > +                break;
> > > +            case STATE_CONNECTING:
> > > +                //extract a number from result
> > > +                if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
> > > +                    av_log(LOG_CONTEXT, AV_LOG_WARNING, "Unexpected reply on connect()\n");
> > > +                } else {
> > > +                    rt->main_channel_id = (int) av_int2dbl(AV_RB64(pkt->data + 21));
> > > +                }
> > > +                gen_play(s, rt);
> > > +                rt->state = STATE_READY;
> > > +                break;
> > > +            }
> > > +        }
> > > +        if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
> > 
> > else if
> 
> elsif'ed
> 

> > 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?


[...]
> +
> +#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?


[...]
> +/**
> + * 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

[...]
> +/**
> + * 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?


> +
> +    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?


> +        }
> +        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


> +        // 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)


> +        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


[...]
> +URLProtocol rtmp_protocol = {
> +    "rtmp",
> +    rtmp_open,
> +    rtmp_read,
> +    rtmp_write,
> +    NULL, /* seek */
> +    rtmp_close,
> +};

seeking is still not implemeneted?


[...]
> +/**
> + * 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

[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

I am the wisest man alive, for I know one thing, and that is that I know
nothing. -- Socrates
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20090728/f90dcc28/attachment.pgp>



More information about the ffmpeg-devel mailing list