Commit 94d56502 authored by Michael Niedermayer's avatar Michael Niedermayer

Merge remote-tracking branch 'qatar/master'

* qatar/master:
  rtmp: Do not send extension for flv files
  rtmp: support connection parameters
  doc: Add documentation for the newly added rtmp_* options
Merged-by: 's avatarMichael Niedermayer <michaelni@gmx.at>
parents 65efc66d f862537d
...@@ -209,11 +209,58 @@ The number of the TCP port to use (by default is 1935). ...@@ -209,11 +209,58 @@ The number of the TCP port to use (by default is 1935).
@item app @item app
It is the name of the application to access. It usually corresponds to It is the name of the application to access. It usually corresponds to
the path where the application is installed on the RTMP server the path where the application is installed on the RTMP server
(e.g. @file{/ondemand/}, @file{/flash/live/}, etc.). (e.g. @file{/ondemand/}, @file{/flash/live/}, etc.). You can override
the value parsed from the URI through the @code{rtmp_app} option, too.
@item playpath @item playpath
It is the path or name of the resource to play with reference to the It is the path or name of the resource to play with reference to the
application specified in @var{app}, may be prefixed by "mp4:". application specified in @var{app}, may be prefixed by "mp4:". You
can override the value parsed from the URI through the @code{rtmp_playpath}
option, too.
@end table
Additionally, the following parameters can be set via command line options
(or in code via @code{AVOption}s):
@table @option
@item rtmp_app
Name of application to connect on the RTMP server. This option
overrides the parameter specified in the URI.
@item rtmp_conn
Extra arbitrary AMF connection parameters, parsed from a string,
e.g. like @code{B:1 S:authMe O:1 NN:code:1.23 NS:flag:ok O:0}.
Each value is prefixed by a single character denoting the type,
B for Boolean, N for number, S for string, O for object, or Z for null,
followed by a colon. For Booleans the data must be either 0 or 1 for
FALSE or TRUE, respectively. Likewise for Objects the data must be 0 or
1 to end or begin an object, respectively. Data items in subobjects may
be named, by prefixing the type with 'N' and specifying the name before
the value (i.e. @code{NB:myFlag:1}). This option may be used multiple
times to construct arbitrary AMF sequences.
@item rtmp_flashver
Version of the Flash plugin used to run the SWF player. The default
is LNX 9,0,124,2.
@item rtmp_live
Specify that the media is a live stream. No resuming or seeking in
live streams is possible. The default value is @code{any}, which means the
subscriber first tries to play the live stream specified in the
playpath. If a live stream of that name is not found, it plays the
recorded stream. The other possible values are @code{live} and
@code{recorded}.
@item rtmp_playpath
Stream identifier to play or to publish. This option overrides the
parameter specified in the URI.
@item rtmp_swfurl
URL of the SWF player for the media. By default no value will be sent.
@item rtmp_tcurl
URL of the target stream.
@end table @end table
......
...@@ -70,6 +70,7 @@ typedef struct RTMPContext { ...@@ -70,6 +70,7 @@ typedef struct RTMPContext {
char *playpath; ///< stream identifier to play (with possible "mp4:" prefix) char *playpath; ///< stream identifier to play (with possible "mp4:" prefix)
int live; ///< 0: recorded, -1: live, -2: both int live; ///< 0: recorded, -1: live, -2: both
char *app; ///< name of application char *app; ///< name of application
char *conn; ///< append arbitrary AMF data to the Connect message
ClientState state; ///< current state ClientState state; ///< current state
int main_channel_id; ///< an additional channel ID which is used for some invocations int main_channel_id; ///< an additional channel ID which is used for some invocations
uint8_t* flv_data; ///< buffer with data for demuxer uint8_t* flv_data; ///< buffer with data for demuxer
...@@ -112,6 +113,65 @@ static const uint8_t rtmp_server_key[] = { ...@@ -112,6 +113,65 @@ static const uint8_t rtmp_server_key[] = {
0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
}; };
static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
{
char *field, *value, *saveptr;
char type;
/* The type must be B for Boolean, N for number, S for string, O for
* object, or Z for null. For Booleans the data must be either 0 or 1 for
* FALSE or TRUE, respectively. Likewise for Objects the data must be
* 0 or 1 to end or begin an object, respectively. Data items in subobjects
* may be named, by prefixing the type with 'N' and specifying the name
* before the value (ie. NB:myFlag:1). This option may be used multiple times
* to construct arbitrary AMF sequences. */
if (param[0] && param[1] == ':') {
type = param[0];
value = param + 2;
} else if (param[0] == 'N' && param[1] && param[2] == ':') {
type = param[1];
field = strtok_r(param + 3, ":", &saveptr);
value = strtok_r(NULL, ":", &saveptr);
if (!field || !value)
goto fail;
ff_amf_write_field_name(p, field);
} else {
goto fail;
}
switch (type) {
case 'B':
ff_amf_write_bool(p, value[0] != '0');
break;
case 'S':
ff_amf_write_string(p, value);
break;
case 'N':
ff_amf_write_number(p, strtod(value, NULL));
break;
case 'Z':
ff_amf_write_null(p);
break;
case 'O':
if (value[0] != '0')
ff_amf_write_object_start(p);
else
ff_amf_write_object_end(p);
break;
default:
goto fail;
break;
}
return 0;
fail:
av_log(s, AV_LOG_ERROR, "Invalid AMF parameter: %s\n", param);
return AVERROR(EINVAL);
}
/** /**
* Generate 'connect' call and send it to the server. * Generate 'connect' call and send it to the server.
*/ */
...@@ -165,6 +225,22 @@ static int gen_connect(URLContext *s, RTMPContext *rt) ...@@ -165,6 +225,22 @@ static int gen_connect(URLContext *s, RTMPContext *rt)
} }
ff_amf_write_object_end(&p); ff_amf_write_object_end(&p);
if (rt->conn) {
char *param, *saveptr;
// Write arbitrary AMF data to the Connect message.
param = strtok_r(rt->conn, " ", &saveptr);
while (param != NULL) {
if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
// Invalid AMF parameter.
ff_rtmp_packet_destroy(&pkt);
return ret;
}
param = strtok_r(NULL, " ", &saveptr);
}
}
pkt.data_size = p - pkt.data; pkt.data_size = p - pkt.data;
ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
...@@ -1057,6 +1133,8 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) ...@@ -1057,6 +1133,8 @@ static int rtmp_open(URLContext *s, const char *uri, int flags)
} }
if (!rt->playpath) { if (!rt->playpath) {
int len = strlen(fname);
rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH); rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
if (!rt->playpath) { if (!rt->playpath) {
ret = AVERROR(ENOMEM); ret = AVERROR(ENOMEM);
...@@ -1064,9 +1142,11 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) ...@@ -1064,9 +1142,11 @@ static int rtmp_open(URLContext *s, const char *uri, int flags)
} }
if (!strchr(fname, ':') && if (!strchr(fname, ':') &&
(!strcmp(fname + strlen(fname) - 4, ".f4v") || (!strcmp(fname + len - 4, ".f4v") ||
!strcmp(fname + strlen(fname) - 4, ".mp4"))) { !strcmp(fname + len - 4, ".mp4"))) {
memcpy(rt->playpath, "mp4:", 5); memcpy(rt->playpath, "mp4:", 5);
} else if (!strcmp(fname + len - 4, ".flv")) {
fname[len - 4] = '\0';
} else { } else {
rt->playpath[0] = 0; rt->playpath[0] = 0;
} }
...@@ -1248,6 +1328,7 @@ static int rtmp_write(URLContext *s, const uint8_t *buf, int size) ...@@ -1248,6 +1328,7 @@ static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
static const AVOption rtmp_options[] = { static const AVOption rtmp_options[] = {
{"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC}, {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
{"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
{"rtmp_flashver", "Version of the Flash plugin used to run the SWF player.", OFFSET(flashver), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC}, {"rtmp_flashver", "Version of the Flash plugin used to run the SWF player.", OFFSET(flashver), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
{"rtmp_live", "Specify that the media is a live stream.", OFFSET(live), AV_OPT_TYPE_INT, {-2}, INT_MIN, INT_MAX, DEC, "rtmp_live"}, {"rtmp_live", "Specify that the media is a live stream.", OFFSET(live), AV_OPT_TYPE_INT, {-2}, INT_MIN, INT_MAX, DEC, "rtmp_live"},
{"any", "both", 0, AV_OPT_TYPE_CONST, {-2}, 0, 0, DEC, "rtmp_live"}, {"any", "both", 0, AV_OPT_TYPE_CONST, {-2}, 0, 0, DEC, "rtmp_live"},
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment