[FFmpeg-devel] [PATCH] RTMPE support
Kostya
kostya.shishkov
Fri Mar 26 06:40:55 CET 2010
On Thu, Mar 25, 2010 at 09:06:51PM -0700, Howard Chu wrote:
> M?ns Rullg?rd wrote:
>> Right, that changes things a bit. What you have there still isn't
>> quite what you want. Try this instead:
>>
>> RTMP-OBJS-$(CONFIG_LIBRTMP) = librtmp.o
>> RTMP-OBJS-$(!CONFIG_LIBRTMP) = rtmpproto.o rtmppkt.o
>> OBJS-$(CONFIG_RTMP_PROTOCOL) += $(RTMP-OBJS-yes)
>
> That works fine, thanks. Tested with both ffplay and mplayer (using
> mplayer ffmpeg://rtmpe://foobar/ etc...)
>
> --
> -- Howard Chu
[...]
> Index: libavformat/librtmp.c
> ===================================================================
> --- libavformat/librtmp.c (revision 0)
> +++ libavformat/librtmp.c (revision 0)
[...]
> +
> +static int rtmp_close(URLContext * h)
> +{
> + struct rtmp_state *rs = h->priv_data;
> +
> + RTMP_Close(&rs->r);
> + av_free((void *)rs->r.Link.hostname);
Looks like you have some tabs to replace with spaces.
> + av_free(rs);
> + return 0;
> +}
> +
> +#define BUFFERTIME 30000 /* msecs */
> +#define RTMP_TIMEOUT 30 /* secs */
> +#define SWF_AGE 30 /* days */
> +
> +/**
> + * 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)
> +{
> + struct rtmp_state *rs;
> + int proto, rc;
> + unsigned int port = 0, swfSize;
> + AVal playpath = { NULL, 0 }, app, tcUrl, swfHash;
> + char *host = NULL;
> + unsigned char hash[HASHLEN];
> + char *ptr, *p1, *p2;
> +
> + rs = av_mallocz(sizeof(struct rtmp_state));
> + if (!rs)
> + return AVERROR(ENOMEM);
> +
> + switch(av_log_get_level()) {
> + default:
> + case AV_LOG_FATAL:
> + rc = RTMP_LOGCRIT; break;
> + case AV_LOG_ERROR:
> + rc = RTMP_LOGERROR; break;
> + case AV_LOG_WARNING:
> + rc = RTMP_LOGWARNING; break;
> + case AV_LOG_INFO:
> + rc = RTMP_LOGINFO; break;
> + case AV_LOG_VERBOSE:
> + rc = RTMP_LOGDEBUG; break;
> + case AV_LOG_DEBUG:
> + rc = RTMP_LOGDEBUG2; break;
> + }
> + RTMP_LogSetLevel(rc);
> +
> + rs->av_class = &rtmp_class;
> + ptr = strchr(s->filename, ' ');
> + while (ptr) {
> + int ret;
> + const AVOption *o = NULL;
> + *ptr++ = '\0';
> + p1 = ptr;
> + p2 = strchr(p1, '=');
> + if (!p2)
> + break;
> + *p2++ = '\0';
> + ptr = strchr(p2, ' ');
> + if (ptr)
> + *ptr = '\0';
> + ret = av_set_string3(rs, p1, p2, 1, &o);
> + if (o && ret < 0) {
> + /* invalid value */
> + rc = AVERROR(EINVAL);
> + goto fail;
> + }
> + if (!o) {
> + rc = AVERROR(ENOTSUP);
> + goto fail;
> + }
> + }
> + if (!RTMP_ParseURL(s->filename, &proto, &host, &port, &playpath, &app)) {
> + rc = -1;
> + goto fail;
> + }
> +
> + if (rs->swfUrl.av_val)
> + rs->swfUrl.av_len = strlen(rs->swfUrl.av_val);
> + if (rs->pageUrl.av_val)
> + rs->pageUrl.av_len = strlen(rs->pageUrl.av_val);
> + if (rs->tcUrl.av_val)
> + rs->tcUrl.av_len = strlen(rs->tcUrl.av_val);
> + if (rs->app.av_val)
> + rs->app.av_len = strlen(rs->app.av_val);
> + if (rs->playpath.av_val)
> + rs->playpath.av_len = strlen(rs->playpath.av_val);
> + if (rs->token.av_val)
> + rs->token.av_len = strlen(rs->token.av_val);
> +
> + if (playpath.av_len) {
> + if (rs->playpath.av_len) {
> + av_free(playpath.av_val);
> + } else {
> + rs->playpath = playpath;
> + }
> + playpath.av_val = NULL;
> + playpath.av_len = 0;
> + }
> +
> + if (rs->tcUrl.av_len) {
> + tcUrl = rs->tcUrl;
> + } else {
> + tcUrl.av_val = s->filename;
> + tcUrl.av_len = app.av_len + (app.av_val - s->filename);
> + }
> +
> + if (rs->swfUrl.av_len && rs->swfVerify &&
> + !RTMP_HashSWF(rs->swfUrl.av_val, &swfSize, hash, SWF_AGE)) {
> + swfHash.av_val = (char *)hash;
> + swfHash.av_len = HASHLEN;
> + } else {
> + swfHash.av_val = NULL;
> + swfHash.av_len = 0;
> + swfSize = 0;
> + }
> +
> + if (flags & URL_WRONLY)
> + proto |= RTMP_FEATURE_WRITE;
> +
> + RTMP_Init(&rs->r);
> + RTMP_SetBufferMS(&rs->r, BUFFERTIME);
> + RTMP_SetupStream(&rs->r, proto, host, port, NULL, &rs->playpath, &tcUrl,
> + &rs->swfUrl, &rs->pageUrl, &app, NULL, &swfHash,
> + swfSize, NULL, NULL, 0, 0, rs->isLive, RTMP_TIMEOUT);
> + rs->r.Link.token = rs->token;
> +
> + if (!RTMP_Connect(&rs->r, NULL) || !RTMP_ConnectStream(&rs->r, 0, 0)) {
> + rc = -1;
> + goto fail;
> + }
> +
> + s->priv_data = rs;
> + s->is_streamed = 1;
> + return 0;
> +fail:
> + av_free(host);
> + av_free(playpath.av_val);
Where are those allocated? And have you tested this path?
> + av_free(rs);
> + return rc;
> +}
> +
> +static int rtmp_write(URLContext *s, uint8_t *buf, int size)
> +{
> + struct rtmp_state *rs = s->priv_data;
> +
> + return RTMP_Write(&rs->r, buf, size);
> +}
> +
> +static int rtmp_read(URLContext * s, uint8_t * buf, int size)
> +{
> + struct rtmp_state *rs = s->priv_data;
> +
> + return RTMP_Read(&rs->r, buf, size);
> +}
> +
> +static int rtmp_pause(URLContext * s, int pause)
> +{
> + struct rtmp_state *rs = s->priv_data;
> +
> + if (pause)
> + rs->r.m_pauseStamp =
> + rs->r.m_channelTimestamp[rs->r.m_mediaChannel];
> + if (!RTMP_SendPause(&rs->r, pause, rs->r.m_pauseStamp))
> + return -1;
> + return 0;
> +}
> +
> +static int64_t rtmp_seek(URLContext * s, int stream_index,
> + int64_t timestamp, int flags)
> +{
> + struct rtmp_state *rs = s->priv_data;
> +
> + if (flags & AVSEEK_FLAG_BYTE)
> + return AVERROR(ENOTSUP);
> +
> + /* seeks are in milliseconds */
> + timestamp = av_rescale(timestamp, AV_TIME_BASE, 1000);
> + if (!RTMP_SendSeek(&rs->r, timestamp))
> + return -1;
> + return timestamp;
> +}
[...]
More information about the ffmpeg-devel
mailing list