Index: patched-ffmpeg-mt/libavformat/rtmpproto.c |
=================================================================== |
--- patched-ffmpeg-mt/libavformat/rtmpproto.c (revision 41250) |
+++ patched-ffmpeg-mt/libavformat/rtmpproto.c (working copy) |
@@ -72,6 +72,9 @@ |
int flv_size; ///< current buffer size |
int flv_off; ///< number of bytes read from current buffer |
RTMPPacket out_pkt; ///< rtmp packet, created from flv a/v or metadata (for output) |
+ uint32_t client_report_size; ///< number of bytes after which client should report to server |
+ uint32_t bytes_read; ///< number of bytes read from server |
+ uint32_t last_bytes_read; ///< number of bytes read last reported to server |
} RTMPContext; |
#define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing |
@@ -110,7 +113,7 @@ |
ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, 4096); |
p = pkt.data; |
- snprintf(tcurl, sizeof(tcurl), "%s://%s:%d/%s", proto, host, port, rt->app); |
+ ff_url_join(tcurl, sizeof(tcurl), proto, NULL, host, port, "/%s", rt->app); |
ff_amf_write_string(&p, "connect"); |
ff_amf_write_number(&p, 1.0); |
ff_amf_write_object_start(&p); |
@@ -337,6 +340,21 @@ |
ff_rtmp_packet_destroy(&pkt); |
} |
+/** |
+ * Generates report on bytes read so far and sends it to the server. |
+ */ |
+static void gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts) |
+{ |
+ RTMPPacket pkt; |
+ uint8_t *p; |
+ |
+ ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ, ts, 4); |
+ p = pkt.data; |
+ bytestream_put_be32(&p, rt->bytes_read); |
+ ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]); |
+ ff_rtmp_packet_destroy(&pkt); |
+} |
+ |
//TODO: Move HMAC code somewhere. Eventually. |
#define HMAC_IPAD_VAL 0x36 |
#define HMAC_OPAD_VAL 0x5C |
@@ -556,6 +574,16 @@ |
if (t == 6) |
gen_pong(s, rt, pkt); |
break; |
+ case RTMP_PT_CLIENT_BW: |
+ if (pkt->data_size < 4) { |
+ av_log(LOG_CONTEXT, AV_LOG_ERROR, |
+ "Client bandwidth report packet is less than 4 bytes long (%d)\n", |
+ pkt->data_size); |
+ return -1; |
+ } |
+ av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Client bandwidth = %d\n", AV_RB32(pkt->data)); |
+ rt->client_report_size = AV_RB32(pkt->data) >> 1; |
+ break; |
case RTMP_PT_INVOKE: |
//TODO: check for the messages sent for wrong state? |
if (!memcmp(pkt->data, "\002\000\006_error", 9)) { |
@@ -669,6 +697,12 @@ |
return AVERROR(EIO); |
} |
} |
+ rt->bytes_read += ret; |
+ if (rt->bytes_read > rt->last_bytes_read + rt->client_report_size) { |
+ av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Sending bytes read report\n"); |
+ gen_bytes_read(s, rt, rpkt.timestamp + 1); |
+ rt->last_bytes_read = rt->bytes_read; |
+ } |
ret = rtmp_parse_result(s, rt, &rpkt); |
if (ret < 0) {//serious error in current packet |
@@ -778,12 +812,12 @@ |
s->priv_data = rt; |
rt->is_input = !(flags & URL_WRONLY); |
- url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, |
- path, sizeof(path), s->filename); |
+ ff_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, |
+ path, sizeof(path), s->filename); |
if (port < 0) |
port = RTMP_DEFAULT_PORT; |
- snprintf(buf, sizeof(buf), "tcp://%s:%d", hostname, port); |
+ ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL); |
if (url_open(&rt->stream, buf, URL_RDWR) < 0) { |
av_log(LOG_CONTEXT, AV_LOG_ERROR, "Cannot open connection %s\n", buf); |
@@ -826,6 +860,10 @@ |
} |
strncat(rt->playpath, fname, sizeof(rt->playpath) - 5); |
+ rt->client_report_size = 1048576; |
+ rt->bytes_read = 0; |
+ rt->last_bytes_read = 0; |
+ |
av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n", |
proto, path, rt->app, rt->playpath); |
gen_connect(s, rt, proto, hostname, port); |