|
|
@@ -28,6 +28,7 @@ |
|
|
|
#include "libavutil/avstring.h" |
|
|
|
#include "libavutil/intfloat.h" |
|
|
|
#include "libavutil/lfg.h" |
|
|
|
#include "libavutil/opt.h" |
|
|
|
#include "libavutil/sha.h" |
|
|
|
#include "avformat.h" |
|
|
|
#include "internal.h" |
|
|
@@ -41,6 +42,8 @@ |
|
|
|
|
|
|
|
//#define DEBUG |
|
|
|
|
|
|
|
#define APP_MAX_LENGTH 128 |
|
|
|
|
|
|
|
/** RTMP protocol handler state */ |
|
|
|
typedef enum { |
|
|
|
STATE_START, ///< client has not done anything yet |
|
|
@@ -56,12 +59,13 @@ typedef enum { |
|
|
|
|
|
|
|
/** protocol handler context */ |
|
|
|
typedef struct RTMPContext { |
|
|
|
const AVClass *class; |
|
|
|
URLContext* stream; ///< TCP stream used in interactions with RTMP server |
|
|
|
RTMPPacket prev_pkt[2][RTMP_CHANNELS]; ///< packet history used when reading and sending packets |
|
|
|
int chunk_size; ///< size of the chunks RTMP packets are divided into |
|
|
|
int is_input; ///< input/output flag |
|
|
|
char playpath[256]; ///< path to filename to play (with possible "mp4:" prefix) |
|
|
|
char app[128]; ///< application |
|
|
|
char *app; ///< name of application |
|
|
|
ClientState state; ///< current state |
|
|
|
int main_channel_id; ///< an additional channel ID which is used for some invocations |
|
|
|
uint8_t* flv_data; ///< buffer with data for demuxer |
|
|
@@ -822,6 +826,7 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) |
|
|
|
{ |
|
|
|
RTMPContext *rt = s->priv_data; |
|
|
|
char proto[8], hostname[256], path[1024], *fname; |
|
|
|
char *old_app; |
|
|
|
uint8_t buf[2048]; |
|
|
|
int port; |
|
|
|
int ret; |
|
|
@@ -847,6 +852,16 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) |
|
|
|
|
|
|
|
rt->chunk_size = 128; |
|
|
|
rt->state = STATE_HANDSHAKED; |
|
|
|
|
|
|
|
// Keep the application name when it has been defined by the user. |
|
|
|
old_app = rt->app; |
|
|
|
|
|
|
|
rt->app = av_malloc(APP_MAX_LENGTH); |
|
|
|
if (!rt->app) { |
|
|
|
rtmp_close(s); |
|
|
|
return AVERROR(ENOMEM); |
|
|
|
} |
|
|
|
|
|
|
|
//extract "app" part from path |
|
|
|
if (!strncmp(path, "/ondemand/", 10)) { |
|
|
|
fname = path + 10; |
|
|
@@ -868,6 +883,13 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (old_app) { |
|
|
|
// The name of application has been defined by the user, override it. |
|
|
|
av_free(rt->app); |
|
|
|
rt->app = old_app; |
|
|
|
} |
|
|
|
|
|
|
|
if (!strchr(fname, ':') && |
|
|
|
(!strcmp(fname + strlen(fname) - 4, ".f4v") || |
|
|
|
!strcmp(fname + strlen(fname) - 4, ".mp4"))) { |
|
|
@@ -1013,6 +1035,22 @@ static int rtmp_write(URLContext *s, const uint8_t *buf, int size) |
|
|
|
return size; |
|
|
|
} |
|
|
|
|
|
|
|
#define OFFSET(x) offsetof(RTMPContext, x) |
|
|
|
#define DEC AV_OPT_FLAG_DECODING_PARAM |
|
|
|
#define ENC AV_OPT_FLAG_ENCODING_PARAM |
|
|
|
|
|
|
|
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}, |
|
|
|
{ NULL }, |
|
|
|
}; |
|
|
|
|
|
|
|
static const AVClass rtmp_class = { |
|
|
|
.class_name = "rtmp", |
|
|
|
.item_name = av_default_item_name, |
|
|
|
.option = rtmp_options, |
|
|
|
.version = LIBAVUTIL_VERSION_INT, |
|
|
|
}; |
|
|
|
|
|
|
|
URLProtocol ff_rtmp_protocol = { |
|
|
|
.name = "rtmp", |
|
|
|
.url_open = rtmp_open, |
|
|
@@ -1021,4 +1059,5 @@ URLProtocol ff_rtmp_protocol = { |
|
|
|
.url_close = rtmp_close, |
|
|
|
.priv_data_size = sizeof(RTMPContext), |
|
|
|
.flags = URL_PROTOCOL_FLAG_NETWORK, |
|
|
|
.priv_data_class= &rtmp_class, |
|
|
|
}; |