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

Kostya kostya.shishkov
Tue Jul 28 08:27:11 CEST 2009


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).
 
> [...]
> > +int ff_rtmp_packet_read(URLContext *h, RTMPPacket *p,
> > +                        int chunk_size, RTMPPacket *prev_pkt)
> > +{
> > +    uint8_t hdr, t, buf[16];
> > +    int channel_id, timestamp, data_size, offset = 0;
> > +    uint32_t extra = 0;
> > +    uint8_t type;
> > +
> > +    if (url_read(h, &hdr, 1) != 1) {
> > +        return AVERROR(EIO);
> > +    }
> > +    channel_id = hdr & 0x3F;
> > +
> > +    hdr >>= 6;
> > +    if (hdr == RTMP_PS_ONEBYTE) {
> > +        //todo
> > +        return -1;
> > +    } else {
> > +        if (url_read_complete(h, buf, 3) != 3)
> > +            return AVERROR(EIO);
> > +        timestamp = AV_RB24(buf);
> > +        if (hdr != RTMP_PS_FOURBYTES) {
> > +            if (url_read_complete(h, buf, 3) != 3)
> > +                return AVERROR(EIO);
> > +            data_size = AV_RB24(buf);
> > +            if (url_read_complete(h, &type, 1) != 1)
> > +                return AVERROR(EIO);
> > +            if (hdr == RTMP_PS_TWELVEBYTES) {
> > +                if (url_read_complete(h, buf, 4) != 4)
> > +                    return AVERROR(EIO);
> > +                extra = AV_RL32(buf);
> > +            } else {
> > +                extra = prev_pkt[channel_id].extra;
> > +            }
> > +        } else {
> > +            data_size = prev_pkt[channel_id].data_size;
> > +            type      = prev_pkt[channel_id].type;
> > +            extra     = prev_pkt[channel_id].extra;
> > +        }
> > +    }
> > +    if (ff_rtmp_packet_create(p, channel_id, type, timestamp, data_size))
> > +        return -1;
> > +    p->extra = extra;
> > +    // save history
> > +    prev_pkt[channel_id].channel_id = channel_id;
> > +    prev_pkt[channel_id].type       = type;
> > +    prev_pkt[channel_id].data_size  = data_size;
> > +    prev_pkt[channel_id].timestamp  = timestamp;
> > +    prev_pkt[channel_id].extra      = extra;
> > +    while (data_size > 0) {
> > +        int toread = FFMIN(data_size, chunk_size);
> > +        int r;
> > +        if ((r = url_read_complete(h, p->data + offset, toread)) != toread) {
> 
> r seems unused

dropped 
 
> [...]
> > +/**
> > + * Creates new RTMP packet with given attributes.
> > + *
> > + * @param pkt        packet
> > + * @param channel_id packet channel ID
> > + * @param type       packet type
> > + * @param timestamp  packet timestamp
> > + * @param size       packet size
> > + * @return zero on success, negative value otherwise
> > + */
> > +int ff_rtmp_packet_create(RTMPPacket *pkt, int channel_id, RTMPPacketType type,
> > +                          int timestamp, int size);
> > +
> > +/**
> > + * Frees RTMP packet.
> > + *
> > + * @param pkt packet
> > + */
> > +void ff_rtmp_packet_destroy(RTMPPacket *pkt);
> > +
> 
> > +/**
> > + * Reads RTMP packet.
> 
> reads from where?

explained 
 
> > + *
> > + * @param h          reader context
> > + * @param p          packet
> > + * @param chunk_size current chunk size
> > + * @param prev_pkt   previously read packet headers for all channels
> > + *                   (may be needed for restoring incomplete packet header)
> > + * @return zero on success, negative value otherwise
> > + */
> > +int ff_rtmp_packet_read(URLContext *h, RTMPPacket *p,
> > +                        int chunk_size, RTMPPacket *prev_pkt);
> > +
> > +/**
> > + * Sends RTMP packet.
> 
> sends to where?
> i think you could be a little bit more verbose ...

I seem to lack -v option. 
 
> > + *
> > + * @param h          reader context
> > + * @param p          packet to send
> > + * @param chunk_size current chunk size
> > + * @param prev_pkt   previously sent packet headers for all channels
> > + *                   (may be used for packet header compressing)
> > + * @return zero on success, negative value otherwise
> > + */
> > +int ff_rtmp_packet_write(URLContext *h, RTMPPacket *p,
> > +                         int chunk_size, RTMPPacket *prev_pkt);
> > +
> > +/**
> > + * @defgroup amffuncs functions used to work with AMF format (which is also used in .flv)
> > + * @see amf_* funcs in libavformat/flvdec.c
> > + * @{
> > + */
> > +
> 
> > +/**
> > + * Calculates number of bytes needed to skip first AMF entry in data.
> > + *
> > + * @param data input data
> > + * @param data_end input buffer end
> > + * @return number of bytes used by first AMF entry
> > + */
> > +int ff_amf_skip_data(const uint8_t *data, const uint8_t *data_end);
> > +
> 
> the function name is misleading becauase it does not "skip data"
> rather it finds the size of the next element

renamed 
 
> > +/**
> > + * Retrieves value of given AMF object field in string form.
> > + *
> > + * @param data     AMF object data
> > + * @param data_end input buffer end
> > + * @param name     name of field to retrieve
> > + * @param dst      buffer for storing result
> > + * @param dst_size output buffer size
> > + * @return 0 if search and retrieval succeeded, negative value otherwise
> > + */
> > +int ff_amf_find_field(const uint8_t *data, const uint8_t *data_end,
> > +                      const uint8_t *name, uint8_t *dst, int dst_size);
> 
> if i interpret the doxy correctly 
> read_field_as_string seems a better name
 
renamed to ff_amf_get_field_value(). _as_string suffix is rather useless
since string is universal format.
 
> [...]
> -- 
> Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
-------------- next part --------------
A non-text attachment was scrubbed...
Name: rtmp.patch
Type: text/x-diff
Size: 42900 bytes
Desc: not available
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20090728/bfe356c5/attachment.patch>



More information about the ffmpeg-devel mailing list