[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