annotate ffmpeg/libavformat/librtmp.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents f445c3017523
children
rev   line source
yading@11 1 /*
yading@11 2 * RTMP network protocol
yading@11 3 * Copyright (c) 2010 Howard Chu
yading@11 4 *
yading@11 5 * This file is part of FFmpeg.
yading@11 6 *
yading@11 7 * FFmpeg is free software; you can redistribute it and/or
yading@11 8 * modify it under the terms of the GNU Lesser General Public
yading@11 9 * License as published by the Free Software Foundation; either
yading@11 10 * version 2.1 of the License, or (at your option) any later version.
yading@11 11 *
yading@11 12 * FFmpeg is distributed in the hope that it will be useful,
yading@11 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@11 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@11 15 * Lesser General Public License for more details.
yading@11 16 *
yading@11 17 * You should have received a copy of the GNU Lesser General Public
yading@11 18 * License along with FFmpeg; if not, write to the Free Software
yading@11 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@11 20 */
yading@11 21
yading@11 22 /**
yading@11 23 * @file
yading@11 24 * RTMP protocol based on http://rtmpdump.mplayerhq.hu/ librtmp
yading@11 25 */
yading@11 26
yading@11 27 #include "libavutil/avstring.h"
yading@11 28 #include "libavutil/mathematics.h"
yading@11 29 #include "libavutil/opt.h"
yading@11 30 #include "avformat.h"
yading@11 31 #include "url.h"
yading@11 32
yading@11 33 #include <librtmp/rtmp.h>
yading@11 34 #include <librtmp/log.h>
yading@11 35
yading@11 36 typedef struct LibRTMPContext {
yading@11 37 const AVClass *class;
yading@11 38 RTMP rtmp;
yading@11 39 char *app;
yading@11 40 char *playpath;
yading@11 41 } LibRTMPContext;
yading@11 42
yading@11 43 static void rtmp_log(int level, const char *fmt, va_list args)
yading@11 44 {
yading@11 45 switch (level) {
yading@11 46 default:
yading@11 47 case RTMP_LOGCRIT: level = AV_LOG_FATAL; break;
yading@11 48 case RTMP_LOGERROR: level = AV_LOG_ERROR; break;
yading@11 49 case RTMP_LOGWARNING: level = AV_LOG_WARNING; break;
yading@11 50 case RTMP_LOGINFO: level = AV_LOG_INFO; break;
yading@11 51 case RTMP_LOGDEBUG: level = AV_LOG_VERBOSE; break;
yading@11 52 case RTMP_LOGDEBUG2: level = AV_LOG_DEBUG; break;
yading@11 53 }
yading@11 54
yading@11 55 av_vlog(NULL, level, fmt, args);
yading@11 56 av_log(NULL, level, "\n");
yading@11 57 }
yading@11 58
yading@11 59 static int rtmp_close(URLContext *s)
yading@11 60 {
yading@11 61 LibRTMPContext *ctx = s->priv_data;
yading@11 62 RTMP *r = &ctx->rtmp;
yading@11 63
yading@11 64 RTMP_Close(r);
yading@11 65 return 0;
yading@11 66 }
yading@11 67
yading@11 68 /**
yading@11 69 * Open RTMP connection and verify that the stream can be played.
yading@11 70 *
yading@11 71 * URL syntax: rtmp://server[:port][/app][/playpath][ keyword=value]...
yading@11 72 * where 'app' is first one or two directories in the path
yading@11 73 * (e.g. /ondemand/, /flash/live/, etc.)
yading@11 74 * and 'playpath' is a file name (the rest of the path,
yading@11 75 * may be prefixed with "mp4:")
yading@11 76 *
yading@11 77 * Additional RTMP library options may be appended as
yading@11 78 * space-separated key-value pairs.
yading@11 79 */
yading@11 80 static int rtmp_open(URLContext *s, const char *uri, int flags)
yading@11 81 {
yading@11 82 LibRTMPContext *ctx = s->priv_data;
yading@11 83 RTMP *r = &ctx->rtmp;
yading@11 84 int rc = 0, level;
yading@11 85 char *filename = s->filename;
yading@11 86
yading@11 87 switch (av_log_get_level()) {
yading@11 88 default:
yading@11 89 case AV_LOG_FATAL: level = RTMP_LOGCRIT; break;
yading@11 90 case AV_LOG_ERROR: level = RTMP_LOGERROR; break;
yading@11 91 case AV_LOG_WARNING: level = RTMP_LOGWARNING; break;
yading@11 92 case AV_LOG_INFO: level = RTMP_LOGINFO; break;
yading@11 93 case AV_LOG_VERBOSE: level = RTMP_LOGDEBUG; break;
yading@11 94 case AV_LOG_DEBUG: level = RTMP_LOGDEBUG2; break;
yading@11 95 }
yading@11 96 RTMP_LogSetLevel(level);
yading@11 97 RTMP_LogSetCallback(rtmp_log);
yading@11 98
yading@11 99 if (ctx->app || ctx->playpath) {
yading@11 100 int len = strlen(s->filename) + 1;
yading@11 101 if (ctx->app) len += strlen(ctx->app) + sizeof(" app=");
yading@11 102 if (ctx->playpath) len += strlen(ctx->playpath) + sizeof(" playpath=");
yading@11 103
yading@11 104 if (!(filename = av_malloc(len)))
yading@11 105 return AVERROR(ENOMEM);
yading@11 106
yading@11 107 av_strlcpy(filename, s->filename, len);
yading@11 108 if (ctx->app) {
yading@11 109 av_strlcat(filename, " app=", len);
yading@11 110 av_strlcat(filename, ctx->app, len);
yading@11 111 }
yading@11 112 if (ctx->playpath) {
yading@11 113 av_strlcat(filename, " playpath=", len);
yading@11 114 av_strlcat(filename, ctx->playpath, len);
yading@11 115 }
yading@11 116 }
yading@11 117
yading@11 118 RTMP_Init(r);
yading@11 119 if (!RTMP_SetupURL(r, filename)) {
yading@11 120 rc = AVERROR_UNKNOWN;
yading@11 121 goto fail;
yading@11 122 }
yading@11 123
yading@11 124 if (flags & AVIO_FLAG_WRITE)
yading@11 125 RTMP_EnableWrite(r);
yading@11 126
yading@11 127 if (!RTMP_Connect(r, NULL) || !RTMP_ConnectStream(r, 0)) {
yading@11 128 rc = AVERROR_UNKNOWN;
yading@11 129 goto fail;
yading@11 130 }
yading@11 131
yading@11 132 s->is_streamed = 1;
yading@11 133 rc = 0;
yading@11 134 fail:
yading@11 135 if (filename != s->filename)
yading@11 136 av_freep(&filename);
yading@11 137 return rc;
yading@11 138 }
yading@11 139
yading@11 140 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
yading@11 141 {
yading@11 142 LibRTMPContext *ctx = s->priv_data;
yading@11 143 RTMP *r = &ctx->rtmp;
yading@11 144
yading@11 145 return RTMP_Write(r, buf, size);
yading@11 146 }
yading@11 147
yading@11 148 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
yading@11 149 {
yading@11 150 LibRTMPContext *ctx = s->priv_data;
yading@11 151 RTMP *r = &ctx->rtmp;
yading@11 152
yading@11 153 return RTMP_Read(r, buf, size);
yading@11 154 }
yading@11 155
yading@11 156 static int rtmp_read_pause(URLContext *s, int pause)
yading@11 157 {
yading@11 158 LibRTMPContext *ctx = s->priv_data;
yading@11 159 RTMP *r = &ctx->rtmp;
yading@11 160
yading@11 161 if (!RTMP_Pause(r, pause))
yading@11 162 return AVERROR_UNKNOWN;
yading@11 163 return 0;
yading@11 164 }
yading@11 165
yading@11 166 static int64_t rtmp_read_seek(URLContext *s, int stream_index,
yading@11 167 int64_t timestamp, int flags)
yading@11 168 {
yading@11 169 LibRTMPContext *ctx = s->priv_data;
yading@11 170 RTMP *r = &ctx->rtmp;
yading@11 171
yading@11 172 if (flags & AVSEEK_FLAG_BYTE)
yading@11 173 return AVERROR(ENOSYS);
yading@11 174
yading@11 175 /* seeks are in milliseconds */
yading@11 176 if (stream_index < 0)
yading@11 177 timestamp = av_rescale_rnd(timestamp, 1000, AV_TIME_BASE,
yading@11 178 flags & AVSEEK_FLAG_BACKWARD ? AV_ROUND_DOWN : AV_ROUND_UP);
yading@11 179
yading@11 180 if (!RTMP_SendSeek(r, timestamp))
yading@11 181 return AVERROR_UNKNOWN;
yading@11 182 return timestamp;
yading@11 183 }
yading@11 184
yading@11 185 static int rtmp_get_file_handle(URLContext *s)
yading@11 186 {
yading@11 187 LibRTMPContext *ctx = s->priv_data;
yading@11 188 RTMP *r = &ctx->rtmp;
yading@11 189
yading@11 190 return RTMP_Socket(r);
yading@11 191 }
yading@11 192
yading@11 193 #define OFFSET(x) offsetof(LibRTMPContext, x)
yading@11 194 #define DEC AV_OPT_FLAG_DECODING_PARAM
yading@11 195 #define ENC AV_OPT_FLAG_ENCODING_PARAM
yading@11 196 static const AVOption options[] = {
yading@11 197 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
yading@11 198 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
yading@11 199 { NULL },
yading@11 200 };
yading@11 201
yading@11 202 #define RTMP_CLASS(flavor)\
yading@11 203 static const AVClass lib ## flavor ## _class = {\
yading@11 204 .class_name = "lib" #flavor " protocol",\
yading@11 205 .item_name = av_default_item_name,\
yading@11 206 .option = options,\
yading@11 207 .version = LIBAVUTIL_VERSION_INT,\
yading@11 208 };
yading@11 209
yading@11 210 RTMP_CLASS(rtmp)
yading@11 211 URLProtocol ff_librtmp_protocol = {
yading@11 212 .name = "rtmp",
yading@11 213 .url_open = rtmp_open,
yading@11 214 .url_read = rtmp_read,
yading@11 215 .url_write = rtmp_write,
yading@11 216 .url_close = rtmp_close,
yading@11 217 .url_read_pause = rtmp_read_pause,
yading@11 218 .url_read_seek = rtmp_read_seek,
yading@11 219 .url_get_file_handle = rtmp_get_file_handle,
yading@11 220 .priv_data_size = sizeof(LibRTMPContext),
yading@11 221 .priv_data_class = &librtmp_class,
yading@11 222 .flags = URL_PROTOCOL_FLAG_NETWORK,
yading@11 223 };
yading@11 224
yading@11 225 RTMP_CLASS(rtmpt)
yading@11 226 URLProtocol ff_librtmpt_protocol = {
yading@11 227 .name = "rtmpt",
yading@11 228 .url_open = rtmp_open,
yading@11 229 .url_read = rtmp_read,
yading@11 230 .url_write = rtmp_write,
yading@11 231 .url_close = rtmp_close,
yading@11 232 .url_read_pause = rtmp_read_pause,
yading@11 233 .url_read_seek = rtmp_read_seek,
yading@11 234 .url_get_file_handle = rtmp_get_file_handle,
yading@11 235 .priv_data_size = sizeof(LibRTMPContext),
yading@11 236 .priv_data_class = &librtmpt_class,
yading@11 237 .flags = URL_PROTOCOL_FLAG_NETWORK,
yading@11 238 };
yading@11 239
yading@11 240 RTMP_CLASS(rtmpe)
yading@11 241 URLProtocol ff_librtmpe_protocol = {
yading@11 242 .name = "rtmpe",
yading@11 243 .url_open = rtmp_open,
yading@11 244 .url_read = rtmp_read,
yading@11 245 .url_write = rtmp_write,
yading@11 246 .url_close = rtmp_close,
yading@11 247 .url_read_pause = rtmp_read_pause,
yading@11 248 .url_read_seek = rtmp_read_seek,
yading@11 249 .url_get_file_handle = rtmp_get_file_handle,
yading@11 250 .priv_data_size = sizeof(LibRTMPContext),
yading@11 251 .priv_data_class = &librtmpe_class,
yading@11 252 .flags = URL_PROTOCOL_FLAG_NETWORK,
yading@11 253 };
yading@11 254
yading@11 255 RTMP_CLASS(rtmpte)
yading@11 256 URLProtocol ff_librtmpte_protocol = {
yading@11 257 .name = "rtmpte",
yading@11 258 .url_open = rtmp_open,
yading@11 259 .url_read = rtmp_read,
yading@11 260 .url_write = rtmp_write,
yading@11 261 .url_close = rtmp_close,
yading@11 262 .url_read_pause = rtmp_read_pause,
yading@11 263 .url_read_seek = rtmp_read_seek,
yading@11 264 .url_get_file_handle = rtmp_get_file_handle,
yading@11 265 .priv_data_size = sizeof(LibRTMPContext),
yading@11 266 .priv_data_class = &librtmpte_class,
yading@11 267 .flags = URL_PROTOCOL_FLAG_NETWORK,
yading@11 268 };
yading@11 269
yading@11 270 RTMP_CLASS(rtmps)
yading@11 271 URLProtocol ff_librtmps_protocol = {
yading@11 272 .name = "rtmps",
yading@11 273 .url_open = rtmp_open,
yading@11 274 .url_read = rtmp_read,
yading@11 275 .url_write = rtmp_write,
yading@11 276 .url_close = rtmp_close,
yading@11 277 .url_read_pause = rtmp_read_pause,
yading@11 278 .url_read_seek = rtmp_read_seek,
yading@11 279 .url_get_file_handle = rtmp_get_file_handle,
yading@11 280 .priv_data_size = sizeof(LibRTMPContext),
yading@11 281 .priv_data_class = &librtmps_class,
yading@11 282 .flags = URL_PROTOCOL_FLAG_NETWORK,
yading@11 283 };