[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