rtmp: fix url parsing
[ffmpeg.git] / libavformat / rtmpproto.c
1 /*
2  * RTMP network protocol
3  * Copyright (c) 2009 Kostya Shishkov
4  *
5  * This file is part of Libav.
6  *
7  * Libav is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * Libav is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with Libav; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 /**
23  * @file
24  * RTMP protocol
25  */
26
27 #include "libavcodec/bytestream.h"
28 #include "libavutil/avstring.h"
29 #include "libavutil/intfloat.h"
30 #include "libavutil/lfg.h"
31 #include "libavutil/opt.h"
32 #include "libavutil/sha.h"
33 #include "avformat.h"
34 #include "internal.h"
35
36 #include "network.h"
37
38 #include "flv.h"
39 #include "rtmp.h"
40 #include "rtmppkt.h"
41 #include "url.h"
42
43 //#define DEBUG
44
45 #define APP_MAX_LENGTH 128
46 #define PLAYPATH_MAX_LENGTH 256
47 #define TCURL_MAX_LENGTH 512
48 #define FLASHVER_MAX_LENGTH 64
49
50 /** RTMP protocol handler state */
51 typedef enum {
52     STATE_START,      ///< client has not done anything yet
53     STATE_HANDSHAKED, ///< client has performed handshake
54     STATE_RELEASING,  ///< client releasing stream before publish it (for output)
55     STATE_FCPUBLISH,  ///< client FCPublishing stream (for output)
56     STATE_CONNECTING, ///< client connected to server successfully
57     STATE_READY,      ///< client has sent all needed commands and waits for server reply
58     STATE_PLAYING,    ///< client has started receiving multimedia data from server
59     STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output)
60     STATE_STOPPED,    ///< the broadcast has been stopped
61 } ClientState;
62
63 /** protocol handler context */
64 typedef struct RTMPContext {
65     const AVClass *class;
66     URLContext*   stream;                     ///< TCP stream used in interactions with RTMP server
67     RTMPPacket    prev_pkt[2][RTMP_CHANNELS]; ///< packet history used when reading and sending packets
68     int           chunk_size;                 ///< size of the chunks RTMP packets are divided into
69     int           is_input;                   ///< input/output flag
70     char          *playpath;                  ///< stream identifier to play (with possible "mp4:" prefix)
71     int           live;                       ///< 0: recorded, -1: live, -2: both
72     char          *app;                       ///< name of application
73     ClientState   state;                      ///< current state
74     int           main_channel_id;            ///< an additional channel ID which is used for some invocations
75     uint8_t*      flv_data;                   ///< buffer with data for demuxer
76     int           flv_size;                   ///< current buffer size
77     int           flv_off;                    ///< number of bytes read from current buffer
78     RTMPPacket    out_pkt;                    ///< rtmp packet, created from flv a/v or metadata (for output)
79     uint32_t      client_report_size;         ///< number of bytes after which client should report to server
80     uint32_t      bytes_read;                 ///< number of bytes read from server
81     uint32_t      last_bytes_read;            ///< number of bytes read last reported to server
82     int           skip_bytes;                 ///< number of bytes to skip from the input FLV stream in the next write call
83     uint8_t       flv_header[11];             ///< partial incoming flv packet header
84     int           flv_header_bytes;           ///< number of initialized bytes in flv_header
85     int           nb_invokes;                 ///< keeps track of invoke messages
86     int           create_stream_invoke;       ///< invoke id for the create stream command
87     char*         tcurl;                      ///< url of the target stream
88     char*         flashver;                   ///< version of the flash plugin
89     char*         swfurl;                     ///< url of the swf player
90 } RTMPContext;
91
92 #define PLAYER_KEY_OPEN_PART_LEN 30   ///< length of partial key used for first client digest signing
93 /** Client key used for digest signing */
94 static const uint8_t rtmp_player_key[] = {
95     'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
96     'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
97
98     0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
99     0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
100     0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
101 };
102
103 #define SERVER_KEY_OPEN_PART_LEN 36   ///< length of partial key used for first server digest signing
104 /** Key used for RTMP server digest signing */
105 static const uint8_t rtmp_server_key[] = {
106     'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
107     'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
108     'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
109
110     0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
111     0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
112     0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
113 };
114
115 /**
116  * Generate 'connect' call and send it to the server.
117  */
118 static int gen_connect(URLContext *s, RTMPContext *rt)
119 {
120     RTMPPacket pkt;
121     uint8_t *p;
122     int ret;
123
124     if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
125                                      0, 4096)) < 0)
126         return ret;
127
128     p = pkt.data;
129
130     ff_amf_write_string(&p, "connect");
131     ff_amf_write_number(&p, ++rt->nb_invokes);
132     ff_amf_write_object_start(&p);
133     ff_amf_write_field_name(&p, "app");
134     ff_amf_write_string(&p, rt->app);
135
136     if (!rt->is_input) {
137         ff_amf_write_field_name(&p, "type");
138         ff_amf_write_string(&p, "nonprivate");
139     }
140     ff_amf_write_field_name(&p, "flashVer");
141     ff_amf_write_string(&p, rt->flashver);
142
143     if (rt->swfurl) {
144         ff_amf_write_field_name(&p, "swfUrl");
145         ff_amf_write_string(&p, rt->swfurl);
146     }
147
148     ff_amf_write_field_name(&p, "tcUrl");
149     ff_amf_write_string(&p, rt->tcurl);
150     if (rt->is_input) {
151         ff_amf_write_field_name(&p, "fpad");
152         ff_amf_write_bool(&p, 0);
153         ff_amf_write_field_name(&p, "capabilities");
154         ff_amf_write_number(&p, 15.0);
155
156         /* Tell the server we support all the audio codecs except
157          * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
158          * which are unused in the RTMP protocol implementation. */
159         ff_amf_write_field_name(&p, "audioCodecs");
160         ff_amf_write_number(&p, 4071.0);
161         ff_amf_write_field_name(&p, "videoCodecs");
162         ff_amf_write_number(&p, 252.0);
163         ff_amf_write_field_name(&p, "videoFunction");
164         ff_amf_write_number(&p, 1.0);
165     }
166     ff_amf_write_object_end(&p);
167
168     pkt.data_size = p - pkt.data;
169
170     ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
171                                rt->prev_pkt[1]);
172     ff_rtmp_packet_destroy(&pkt);
173
174     return ret;
175 }
176
177 /**
178  * Generate 'releaseStream' call and send it to the server. It should make
179  * the server release some channel for media streams.
180  */
181 static int gen_release_stream(URLContext *s, RTMPContext *rt)
182 {
183     RTMPPacket pkt;
184     uint8_t *p;
185     int ret;
186
187     if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
188                                      0, 29 + strlen(rt->playpath))) < 0)
189         return ret;
190
191     av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
192     p = pkt.data;
193     ff_amf_write_string(&p, "releaseStream");
194     ff_amf_write_number(&p, ++rt->nb_invokes);
195     ff_amf_write_null(&p);
196     ff_amf_write_string(&p, rt->playpath);
197
198     ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
199                                rt->prev_pkt[1]);
200     ff_rtmp_packet_destroy(&pkt);
201
202     return ret;
203 }
204
205 /**
206  * Generate 'FCPublish' call and send it to the server. It should make
207  * the server preapare for receiving media streams.
208  */
209 static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
210 {
211     RTMPPacket pkt;
212     uint8_t *p;
213     int ret;
214
215     if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
216                                      0, 25 + strlen(rt->playpath))) < 0)
217         return ret;
218
219     av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
220     p = pkt.data;
221     ff_amf_write_string(&p, "FCPublish");
222     ff_amf_write_number(&p, ++rt->nb_invokes);
223     ff_amf_write_null(&p);
224     ff_amf_write_string(&p, rt->playpath);
225
226     ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
227                                rt->prev_pkt[1]);
228     ff_rtmp_packet_destroy(&pkt);
229
230     return ret;
231 }
232
233 /**
234  * Generate 'FCUnpublish' call and send it to the server. It should make
235  * the server destroy stream.
236  */
237 static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
238 {
239     RTMPPacket pkt;
240     uint8_t *p;
241     int ret;
242
243     if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
244                                      0, 27 + strlen(rt->playpath))) < 0)
245         return ret;
246
247     av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
248     p = pkt.data;
249     ff_amf_write_string(&p, "FCUnpublish");
250     ff_amf_write_number(&p, ++rt->nb_invokes);
251     ff_amf_write_null(&p);
252     ff_amf_write_string(&p, rt->playpath);
253
254     ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
255                                rt->prev_pkt[1]);
256     ff_rtmp_packet_destroy(&pkt);
257
258     return ret;
259 }
260
261 /**
262  * Generate 'createStream' call and send it to the server. It should make
263  * the server allocate some channel for media streams.
264  */
265 static int gen_create_stream(URLContext *s, RTMPContext *rt)
266 {
267     RTMPPacket pkt;
268     uint8_t *p;
269     int ret;
270
271     av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
272
273     if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
274                                      0, 25)) < 0)
275         return ret;
276
277     p = pkt.data;
278     ff_amf_write_string(&p, "createStream");
279     ff_amf_write_number(&p, ++rt->nb_invokes);
280     ff_amf_write_null(&p);
281     rt->create_stream_invoke = rt->nb_invokes;
282
283     ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
284                                rt->prev_pkt[1]);
285     ff_rtmp_packet_destroy(&pkt);
286
287     return ret;
288 }
289
290
291 /**
292  * Generate 'deleteStream' call and send it to the server. It should make
293  * the server remove some channel for media streams.
294  */
295 static int gen_delete_stream(URLContext *s, RTMPContext *rt)
296 {
297     RTMPPacket pkt;
298     uint8_t *p;
299     int ret;
300
301     av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
302
303     if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
304                                      0, 34)) < 0)
305         return ret;
306
307     p = pkt.data;
308     ff_amf_write_string(&p, "deleteStream");
309     ff_amf_write_number(&p, ++rt->nb_invokes);
310     ff_amf_write_null(&p);
311     ff_amf_write_number(&p, rt->main_channel_id);
312
313     ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
314                                rt->prev_pkt[1]);
315     ff_rtmp_packet_destroy(&pkt);
316
317     return ret;
318 }
319
320 /**
321  * Generate 'play' call and send it to the server, then ping the server
322  * to start actual playing.
323  */
324 static int gen_play(URLContext *s, RTMPContext *rt)
325 {
326     RTMPPacket pkt;
327     uint8_t *p;
328     int ret;
329
330     av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
331
332     if ((ret = ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE,
333                                      0, 29 + strlen(rt->playpath))) < 0)
334         return ret;
335
336     pkt.extra = rt->main_channel_id;
337
338     p = pkt.data;
339     ff_amf_write_string(&p, "play");
340     ff_amf_write_number(&p, ++rt->nb_invokes);
341     ff_amf_write_null(&p);
342     ff_amf_write_string(&p, rt->playpath);
343     ff_amf_write_number(&p, rt->live);
344
345     ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
346                                rt->prev_pkt[1]);
347     ff_rtmp_packet_destroy(&pkt);
348
349     if (ret < 0)
350         return ret;
351
352     // set client buffer time disguised in ping packet
353     if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
354                                      1, 10)) < 0)
355         return ret;
356
357     p = pkt.data;
358     bytestream_put_be16(&p, 3);
359     bytestream_put_be32(&p, 1);
360     bytestream_put_be32(&p, 256); //TODO: what is a good value here?
361
362     ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
363                                rt->prev_pkt[1]);
364     ff_rtmp_packet_destroy(&pkt);
365
366     return ret;
367 }
368
369 /**
370  * Generate 'publish' call and send it to the server.
371  */
372 static int gen_publish(URLContext *s, RTMPContext *rt)
373 {
374     RTMPPacket pkt;
375     uint8_t *p;
376     int ret;
377
378     av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
379
380     if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
381                                      0, 30 + strlen(rt->playpath))) < 0)
382         return ret;
383
384     pkt.extra = rt->main_channel_id;
385
386     p = pkt.data;
387     ff_amf_write_string(&p, "publish");
388     ff_amf_write_number(&p, ++rt->nb_invokes);
389     ff_amf_write_null(&p);
390     ff_amf_write_string(&p, rt->playpath);
391     ff_amf_write_string(&p, "live");
392
393     ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
394                                rt->prev_pkt[1]);
395     ff_rtmp_packet_destroy(&pkt);
396
397     return ret;
398 }
399
400 /**
401  * Generate ping reply and send it to the server.
402  */
403 static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
404 {
405     RTMPPacket pkt;
406     uint8_t *p;
407     int ret;
408
409     if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
410                                      ppkt->timestamp + 1, 6)) < 0)
411         return ret;
412
413     p = pkt.data;
414     bytestream_put_be16(&p, 7);
415     bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
416     ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
417                                rt->prev_pkt[1]);
418     ff_rtmp_packet_destroy(&pkt);
419
420     return ret;
421 }
422
423 /**
424  * Generate server bandwidth message and send it to the server.
425  */
426 static int gen_server_bw(URLContext *s, RTMPContext *rt)
427 {
428     RTMPPacket pkt;
429     uint8_t *p;
430     int ret;
431
432     if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_SERVER_BW,
433                                      0, 4)) < 0)
434         return ret;
435
436     p = pkt.data;
437     bytestream_put_be32(&p, 2500000);
438     ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
439                                rt->prev_pkt[1]);
440     ff_rtmp_packet_destroy(&pkt);
441
442     return ret;
443 }
444
445 /**
446  * Generate check bandwidth message and send it to the server.
447  */
448 static int gen_check_bw(URLContext *s, RTMPContext *rt)
449 {
450     RTMPPacket pkt;
451     uint8_t *p;
452     int ret;
453
454     if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
455                                      0, 21)) < 0)
456         return ret;
457
458     p = pkt.data;
459     ff_amf_write_string(&p, "_checkbw");
460     ff_amf_write_number(&p, ++rt->nb_invokes);
461     ff_amf_write_null(&p);
462
463     ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
464                                rt->prev_pkt[1]);
465     ff_rtmp_packet_destroy(&pkt);
466
467     return ret;
468 }
469
470 /**
471  * Generate report on bytes read so far and send it to the server.
472  */
473 static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
474 {
475     RTMPPacket pkt;
476     uint8_t *p;
477     int ret;
478
479     if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
480                                      ts, 4)) < 0)
481         return ret;
482
483     p = pkt.data;
484     bytestream_put_be32(&p, rt->bytes_read);
485     ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
486                                rt->prev_pkt[1]);
487     ff_rtmp_packet_destroy(&pkt);
488
489     return ret;
490 }
491
492 //TODO: Move HMAC code somewhere. Eventually.
493 #define HMAC_IPAD_VAL 0x36
494 #define HMAC_OPAD_VAL 0x5C
495
496 /**
497  * Calculate HMAC-SHA2 digest for RTMP handshake packets.
498  *
499  * @param src    input buffer
500  * @param len    input buffer length (should be 1536)
501  * @param gap    offset in buffer where 32 bytes should not be taken into account
502  *               when calculating digest (since it will be used to store that digest)
503  * @param key    digest key
504  * @param keylen digest key length
505  * @param dst    buffer where calculated digest will be stored (32 bytes)
506  */
507 static int rtmp_calc_digest(const uint8_t *src, int len, int gap,
508                             const uint8_t *key, int keylen, uint8_t *dst)
509 {
510     struct AVSHA *sha;
511     uint8_t hmac_buf[64+32] = {0};
512     int i;
513
514     sha = av_mallocz(av_sha_size);
515     if (!sha)
516         return AVERROR(ENOMEM);
517
518     if (keylen < 64) {
519         memcpy(hmac_buf, key, keylen);
520     } else {
521         av_sha_init(sha, 256);
522         av_sha_update(sha,key, keylen);
523         av_sha_final(sha, hmac_buf);
524     }
525     for (i = 0; i < 64; i++)
526         hmac_buf[i] ^= HMAC_IPAD_VAL;
527
528     av_sha_init(sha, 256);
529     av_sha_update(sha, hmac_buf, 64);
530     if (gap <= 0) {
531         av_sha_update(sha, src, len);
532     } else { //skip 32 bytes used for storing digest
533         av_sha_update(sha, src, gap);
534         av_sha_update(sha, src + gap + 32, len - gap - 32);
535     }
536     av_sha_final(sha, hmac_buf + 64);
537
538     for (i = 0; i < 64; i++)
539         hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
540     av_sha_init(sha, 256);
541     av_sha_update(sha, hmac_buf, 64+32);
542     av_sha_final(sha, dst);
543
544     av_free(sha);
545
546     return 0;
547 }
548
549 /**
550  * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
551  * will be stored) into that packet.
552  *
553  * @param buf handshake data (1536 bytes)
554  * @return offset to the digest inside input data
555  */
556 static int rtmp_handshake_imprint_with_digest(uint8_t *buf)
557 {
558     int i, digest_pos = 0;
559     int ret;
560
561     for (i = 8; i < 12; i++)
562         digest_pos += buf[i];
563     digest_pos = (digest_pos % 728) + 12;
564
565     ret = rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
566                            rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
567                            buf + digest_pos);
568     if (ret < 0)
569         return ret;
570
571     return digest_pos;
572 }
573
574 /**
575  * Verify that the received server response has the expected digest value.
576  *
577  * @param buf handshake data received from the server (1536 bytes)
578  * @param off position to search digest offset from
579  * @return 0 if digest is valid, digest position otherwise
580  */
581 static int rtmp_validate_digest(uint8_t *buf, int off)
582 {
583     int i, digest_pos = 0;
584     uint8_t digest[32];
585     int ret;
586
587     for (i = 0; i < 4; i++)
588         digest_pos += buf[i + off];
589     digest_pos = (digest_pos % 728) + off + 4;
590
591     ret = rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
592                            rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
593                            digest);
594     if (ret < 0)
595         return ret;
596
597     if (!memcmp(digest, buf + digest_pos, 32))
598         return digest_pos;
599     return 0;
600 }
601
602 /**
603  * Perform handshake with the server by means of exchanging pseudorandom data
604  * signed with HMAC-SHA2 digest.
605  *
606  * @return 0 if handshake succeeds, negative value otherwise
607  */
608 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
609 {
610     AVLFG rnd;
611     uint8_t tosend    [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
612         3,                // unencrypted data
613         0, 0, 0, 0,       // client uptime
614         RTMP_CLIENT_VER1,
615         RTMP_CLIENT_VER2,
616         RTMP_CLIENT_VER3,
617         RTMP_CLIENT_VER4,
618     };
619     uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
620     uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
621     int i;
622     int server_pos, client_pos;
623     uint8_t digest[32];
624     int ret;
625
626     av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
627
628     av_lfg_init(&rnd, 0xDEADC0DE);
629     // generate handshake packet - 1536 bytes of pseudorandom data
630     for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
631         tosend[i] = av_lfg_get(&rnd) >> 24;
632     client_pos = rtmp_handshake_imprint_with_digest(tosend + 1);
633     if (client_pos < 0)
634         return client_pos;
635
636     if ((ret = ffurl_write(rt->stream, tosend,
637                            RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
638         av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
639         return ret;
640     }
641
642     if ((ret = ffurl_read_complete(rt->stream, serverdata,
643                                    RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
644         av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
645         return ret;
646     }
647
648     if ((ret = ffurl_read_complete(rt->stream, clientdata,
649                                    RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
650         av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
651         return ret;
652     }
653
654     av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
655            serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
656
657     if (rt->is_input && serverdata[5] >= 3) {
658         server_pos = rtmp_validate_digest(serverdata + 1, 772);
659         if (server_pos < 0)
660             return server_pos;
661
662         if (!server_pos) {
663             server_pos = rtmp_validate_digest(serverdata + 1, 8);
664             if (server_pos < 0)
665                 return server_pos;
666
667             if (!server_pos) {
668                 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
669                 return AVERROR(EIO);
670             }
671         }
672
673         ret = rtmp_calc_digest(tosend + 1 + client_pos, 32, 0, rtmp_server_key,
674                                sizeof(rtmp_server_key), digest);
675         if (ret < 0)
676             return ret;
677
678         ret = rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
679                                digest, 32, digest);
680         if (ret < 0)
681             return ret;
682
683         if (memcmp(digest, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
684             av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
685             return AVERROR(EIO);
686         }
687
688         for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
689             tosend[i] = av_lfg_get(&rnd) >> 24;
690         ret = rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
691                                rtmp_player_key, sizeof(rtmp_player_key),
692                                digest);
693         if (ret < 0)
694             return ret;
695
696         ret = rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
697                                digest, 32,
698                                tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
699         if (ret < 0)
700             return ret;
701
702         // write reply back to the server
703         if ((ret = ffurl_write(rt->stream, tosend,
704                                RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
705             return ret;
706     } else {
707         if ((ret = ffurl_write(rt->stream, serverdata + 1,
708                                RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
709             return ret;
710     }
711
712     return 0;
713 }
714
715 /**
716  * Parse received packet and possibly perform some action depending on
717  * the packet contents.
718  * @return 0 for no errors, negative values for serious errors which prevent
719  *         further communications, positive values for uncritical errors
720  */
721 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
722 {
723     int i, t;
724     const uint8_t *data_end = pkt->data + pkt->data_size;
725     int ret;
726
727 #ifdef DEBUG
728     ff_rtmp_packet_dump(s, pkt);
729 #endif
730
731     switch (pkt->type) {
732     case RTMP_PT_CHUNK_SIZE:
733         if (pkt->data_size != 4) {
734             av_log(s, AV_LOG_ERROR,
735                    "Chunk size change packet is not 4 bytes long (%d)\n", pkt->data_size);
736             return -1;
737         }
738         if (!rt->is_input)
739             if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->chunk_size,
740                                             rt->prev_pkt[1])) < 0)
741                 return ret;
742         rt->chunk_size = AV_RB32(pkt->data);
743         if (rt->chunk_size <= 0) {
744             av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n", rt->chunk_size);
745             return -1;
746         }
747         av_log(s, AV_LOG_DEBUG, "New chunk size = %d\n", rt->chunk_size);
748         break;
749     case RTMP_PT_PING:
750         t = AV_RB16(pkt->data);
751         if (t == 6)
752             if ((ret = gen_pong(s, rt, pkt)) < 0)
753                 return ret;
754         break;
755     case RTMP_PT_CLIENT_BW:
756         if (pkt->data_size < 4) {
757             av_log(s, AV_LOG_ERROR,
758                    "Client bandwidth report packet is less than 4 bytes long (%d)\n",
759                    pkt->data_size);
760             return -1;
761         }
762         av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", AV_RB32(pkt->data));
763         rt->client_report_size = AV_RB32(pkt->data) >> 1;
764         break;
765     case RTMP_PT_INVOKE:
766         //TODO: check for the messages sent for wrong state?
767         if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
768             uint8_t tmpstr[256];
769
770             if (!ff_amf_get_field_value(pkt->data + 9, data_end,
771                                         "description", tmpstr, sizeof(tmpstr)))
772                 av_log(s, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
773             return -1;
774         } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
775             switch (rt->state) {
776             case STATE_HANDSHAKED:
777                 if (!rt->is_input) {
778                     if ((ret = gen_release_stream(s, rt)) < 0)
779                         return ret;
780                     if ((ret = gen_fcpublish_stream(s, rt)) < 0)
781                         return ret;
782                     rt->state = STATE_RELEASING;
783                 } else {
784                     if ((ret = gen_server_bw(s, rt)) < 0)
785                         return ret;
786                     rt->state = STATE_CONNECTING;
787                 }
788                 if ((ret = gen_create_stream(s, rt)) < 0)
789                     return ret;
790                 break;
791             case STATE_FCPUBLISH:
792                 rt->state = STATE_CONNECTING;
793                 break;
794             case STATE_RELEASING:
795                 rt->state = STATE_FCPUBLISH;
796                 /* hack for Wowza Media Server, it does not send result for
797                  * releaseStream and FCPublish calls */
798                 if (!pkt->data[10]) {
799                     int pkt_id = av_int2double(AV_RB64(pkt->data + 11));
800                     if (pkt_id == rt->create_stream_invoke)
801                         rt->state = STATE_CONNECTING;
802                 }
803                 if (rt->state != STATE_CONNECTING)
804                     break;
805             case STATE_CONNECTING:
806                 //extract a number from the result
807                 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
808                     av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
809                 } else {
810                     rt->main_channel_id = av_int2double(AV_RB64(pkt->data + 21));
811                 }
812                 if (rt->is_input) {
813                     if ((ret = gen_play(s, rt)) < 0)
814                         return ret;
815                 } else {
816                     if ((ret = gen_publish(s, rt)) < 0)
817                         return ret;
818                 }
819                 rt->state = STATE_READY;
820                 break;
821             }
822         } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
823             const uint8_t* ptr = pkt->data + 11;
824             uint8_t tmpstr[256];
825
826             for (i = 0; i < 2; i++) {
827                 t = ff_amf_tag_size(ptr, data_end);
828                 if (t < 0)
829                     return 1;
830                 ptr += t;
831             }
832             t = ff_amf_get_field_value(ptr, data_end,
833                                        "level", tmpstr, sizeof(tmpstr));
834             if (!t && !strcmp(tmpstr, "error")) {
835                 if (!ff_amf_get_field_value(ptr, data_end,
836                                             "description", tmpstr, sizeof(tmpstr)))
837                     av_log(s, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
838                 return -1;
839             }
840             t = ff_amf_get_field_value(ptr, data_end,
841                                        "code", tmpstr, sizeof(tmpstr));
842             if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
843             if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
844             if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
845             if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
846         } else if (!memcmp(pkt->data, "\002\000\010onBWDone", 11)) {
847             if ((ret = gen_check_bw(s, rt)) < 0)
848                 return ret;
849         }
850         break;
851     }
852     return 0;
853 }
854
855 /**
856  * Interact with the server by receiving and sending RTMP packets until
857  * there is some significant data (media data or expected status notification).
858  *
859  * @param s          reading context
860  * @param for_header non-zero value tells function to work until it
861  * gets notification from the server that playing has been started,
862  * otherwise function will work until some media data is received (or
863  * an error happens)
864  * @return 0 for successful operation, negative value in case of error
865  */
866 static int get_packet(URLContext *s, int for_header)
867 {
868     RTMPContext *rt = s->priv_data;
869     int ret;
870     uint8_t *p;
871     const uint8_t *next;
872     uint32_t data_size;
873     uint32_t ts, cts, pts=0;
874
875     if (rt->state == STATE_STOPPED)
876         return AVERROR_EOF;
877
878     for (;;) {
879         RTMPPacket rpkt = { 0 };
880         if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
881                                        rt->chunk_size, rt->prev_pkt[0])) <= 0) {
882             if (ret == 0) {
883                 return AVERROR(EAGAIN);
884             } else {
885                 return AVERROR(EIO);
886             }
887         }
888         rt->bytes_read += ret;
889         if (rt->bytes_read > rt->last_bytes_read + rt->client_report_size) {
890             av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
891             if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
892                 return ret;
893             rt->last_bytes_read = rt->bytes_read;
894         }
895
896         ret = rtmp_parse_result(s, rt, &rpkt);
897         if (ret < 0) {//serious error in current packet
898             ff_rtmp_packet_destroy(&rpkt);
899             return ret;
900         }
901         if (rt->state == STATE_STOPPED) {
902             ff_rtmp_packet_destroy(&rpkt);
903             return AVERROR_EOF;
904         }
905         if (for_header && (rt->state == STATE_PLAYING || rt->state == STATE_PUBLISHING)) {
906             ff_rtmp_packet_destroy(&rpkt);
907             return 0;
908         }
909         if (!rpkt.data_size || !rt->is_input) {
910             ff_rtmp_packet_destroy(&rpkt);
911             continue;
912         }
913         if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO ||
914            (rpkt.type == RTMP_PT_NOTIFY && !memcmp("\002\000\012onMetaData", rpkt.data, 13))) {
915             ts = rpkt.timestamp;
916
917             // generate packet header and put data into buffer for FLV demuxer
918             rt->flv_off  = 0;
919             rt->flv_size = rpkt.data_size + 15;
920             rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size);
921             bytestream_put_byte(&p, rpkt.type);
922             bytestream_put_be24(&p, rpkt.data_size);
923             bytestream_put_be24(&p, ts);
924             bytestream_put_byte(&p, ts >> 24);
925             bytestream_put_be24(&p, 0);
926             bytestream_put_buffer(&p, rpkt.data, rpkt.data_size);
927             bytestream_put_be32(&p, 0);
928             ff_rtmp_packet_destroy(&rpkt);
929             return 0;
930         } else if (rpkt.type == RTMP_PT_METADATA) {
931             // we got raw FLV data, make it available for FLV demuxer
932             rt->flv_off  = 0;
933             rt->flv_size = rpkt.data_size;
934             rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
935             /* rewrite timestamps */
936             next = rpkt.data;
937             ts = rpkt.timestamp;
938             while (next - rpkt.data < rpkt.data_size - 11) {
939                 next++;
940                 data_size = bytestream_get_be24(&next);
941                 p=next;
942                 cts = bytestream_get_be24(&next);
943                 cts |= bytestream_get_byte(&next) << 24;
944                 if (pts==0)
945                     pts=cts;
946                 ts += cts - pts;
947                 pts = cts;
948                 bytestream_put_be24(&p, ts);
949                 bytestream_put_byte(&p, ts >> 24);
950                 next += data_size + 3 + 4;
951             }
952             memcpy(rt->flv_data, rpkt.data, rpkt.data_size);
953             ff_rtmp_packet_destroy(&rpkt);
954             return 0;
955         }
956         ff_rtmp_packet_destroy(&rpkt);
957     }
958 }
959
960 static int rtmp_close(URLContext *h)
961 {
962     RTMPContext *rt = h->priv_data;
963     int ret = 0;
964
965     if (!rt->is_input) {
966         rt->flv_data = NULL;
967         if (rt->out_pkt.data_size)
968             ff_rtmp_packet_destroy(&rt->out_pkt);
969         if (rt->state > STATE_FCPUBLISH)
970             ret = gen_fcunpublish_stream(h, rt);
971     }
972     if (rt->state > STATE_HANDSHAKED)
973         ret = gen_delete_stream(h, rt);
974
975     av_freep(&rt->flv_data);
976     ffurl_close(rt->stream);
977     return ret;
978 }
979
980 /**
981  * Open RTMP connection and verify that the stream can be played.
982  *
983  * URL syntax: rtmp://server[:port][/app][/playpath]
984  *             where 'app' is first one or two directories in the path
985  *             (e.g. /ondemand/, /flash/live/, etc.)
986  *             and 'playpath' is a file name (the rest of the path,
987  *             may be prefixed with "mp4:")
988  */
989 static int rtmp_open(URLContext *s, const char *uri, int flags)
990 {
991     RTMPContext *rt = s->priv_data;
992     char proto[8], hostname[256], path[1024], *fname;
993     char *old_app;
994     uint8_t buf[2048];
995     int port;
996     int ret;
997
998     rt->is_input = !(flags & AVIO_FLAG_WRITE);
999
1000     av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
1001                  path, sizeof(path), s->filename);
1002
1003     if (port < 0)
1004         port = RTMP_DEFAULT_PORT;
1005     ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
1006
1007     if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
1008                           &s->interrupt_callback, NULL)) < 0) {
1009         av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
1010         goto fail;
1011     }
1012
1013     rt->state = STATE_START;
1014     if ((ret = rtmp_handshake(s, rt)) < 0)
1015         goto fail;
1016
1017     rt->chunk_size = 128;
1018     rt->state = STATE_HANDSHAKED;
1019
1020     // Keep the application name when it has been defined by the user.
1021     old_app = rt->app;
1022
1023     rt->app = av_malloc(APP_MAX_LENGTH);
1024     if (!rt->app) {
1025         ret = AVERROR(ENOMEM);
1026         goto fail;
1027     }
1028
1029     //extract "app" part from path
1030     if (!strncmp(path, "/ondemand/", 10)) {
1031         fname = path + 10;
1032         memcpy(rt->app, "ondemand", 9);
1033     } else {
1034         char *next = *path ? path + 1 : path;
1035         char *p = strchr(next, '/');
1036         if (!p) {
1037             fname = next;
1038             rt->app[0] = '\0';
1039         } else {
1040             // make sure we do not mismatch a playpath for an application instance
1041             char *c = strchr(p + 1, ':');
1042             fname = strchr(p + 1, '/');
1043             if (!fname || (c && c < fname)) {
1044                 fname = p + 1;
1045                 av_strlcpy(rt->app, path + 1, p - path);
1046             } else {
1047                 fname++;
1048                 av_strlcpy(rt->app, path + 1, fname - path - 1);
1049             }
1050         }
1051     }
1052
1053     if (old_app) {
1054         // The name of application has been defined by the user, override it.
1055         av_free(rt->app);
1056         rt->app = old_app;
1057     }
1058
1059     if (!rt->playpath) {
1060         rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
1061         if (!rt->playpath) {
1062             ret = AVERROR(ENOMEM);
1063             goto fail;
1064         }
1065
1066         if (!strchr(fname, ':') &&
1067             (!strcmp(fname + strlen(fname) - 4, ".f4v") ||
1068              !strcmp(fname + strlen(fname) - 4, ".mp4"))) {
1069             memcpy(rt->playpath, "mp4:", 5);
1070         } else {
1071             rt->playpath[0] = 0;
1072         }
1073         strncat(rt->playpath, fname, PLAYPATH_MAX_LENGTH - 5);
1074     }
1075
1076     if (!rt->tcurl) {
1077         rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
1078         if (!rt->tcurl) {
1079             ret = AVERROR(ENOMEM);
1080             goto fail;
1081         }
1082         ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
1083                     port, "/%s", rt->app);
1084     }
1085
1086     if (!rt->flashver) {
1087         rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
1088         if (!rt->flashver) {
1089             ret = AVERROR(ENOMEM);
1090             goto fail;
1091         }
1092         if (rt->is_input) {
1093             snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
1094                     RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
1095                     RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
1096         } else {
1097             snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
1098                     "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
1099         }
1100     }
1101
1102     rt->client_report_size = 1048576;
1103     rt->bytes_read = 0;
1104     rt->last_bytes_read = 0;
1105
1106     av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
1107            proto, path, rt->app, rt->playpath);
1108     if ((ret = gen_connect(s, rt)) < 0)
1109         goto fail;
1110
1111     do {
1112         ret = get_packet(s, 1);
1113     } while (ret == EAGAIN);
1114     if (ret < 0)
1115         goto fail;
1116
1117     if (rt->is_input) {
1118         // generate FLV header for demuxer
1119         rt->flv_size = 13;
1120         rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
1121         rt->flv_off  = 0;
1122         memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size);
1123     } else {
1124         rt->flv_size = 0;
1125         rt->flv_data = NULL;
1126         rt->flv_off  = 0;
1127         rt->skip_bytes = 13;
1128     }
1129
1130     s->max_packet_size = rt->stream->max_packet_size;
1131     s->is_streamed     = 1;
1132     return 0;
1133
1134 fail:
1135     rtmp_close(s);
1136     return ret;
1137 }
1138
1139 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
1140 {
1141     RTMPContext *rt = s->priv_data;
1142     int orig_size = size;
1143     int ret;
1144
1145     while (size > 0) {
1146         int data_left = rt->flv_size - rt->flv_off;
1147
1148         if (data_left >= size) {
1149             memcpy(buf, rt->flv_data + rt->flv_off, size);
1150             rt->flv_off += size;
1151             return orig_size;
1152         }
1153         if (data_left > 0) {
1154             memcpy(buf, rt->flv_data + rt->flv_off, data_left);
1155             buf  += data_left;
1156             size -= data_left;
1157             rt->flv_off = rt->flv_size;
1158             return data_left;
1159         }
1160         if ((ret = get_packet(s, 0)) < 0)
1161            return ret;
1162     }
1163     return orig_size;
1164 }
1165
1166 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
1167 {
1168     RTMPContext *rt = s->priv_data;
1169     int size_temp = size;
1170     int pktsize, pkttype;
1171     uint32_t ts;
1172     const uint8_t *buf_temp = buf;
1173     int ret;
1174
1175     do {
1176         if (rt->skip_bytes) {
1177             int skip = FFMIN(rt->skip_bytes, size_temp);
1178             buf_temp       += skip;
1179             size_temp      -= skip;
1180             rt->skip_bytes -= skip;
1181             continue;
1182         }
1183
1184         if (rt->flv_header_bytes < 11) {
1185             const uint8_t *header = rt->flv_header;
1186             int copy = FFMIN(11 - rt->flv_header_bytes, size_temp);
1187             bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
1188             rt->flv_header_bytes += copy;
1189             size_temp            -= copy;
1190             if (rt->flv_header_bytes < 11)
1191                 break;
1192
1193             pkttype = bytestream_get_byte(&header);
1194             pktsize = bytestream_get_be24(&header);
1195             ts = bytestream_get_be24(&header);
1196             ts |= bytestream_get_byte(&header) << 24;
1197             bytestream_get_be24(&header);
1198             rt->flv_size = pktsize;
1199
1200             //force 12bytes header
1201             if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
1202                 pkttype == RTMP_PT_NOTIFY) {
1203                 if (pkttype == RTMP_PT_NOTIFY)
1204                     pktsize += 16;
1205                 rt->prev_pkt[1][RTMP_SOURCE_CHANNEL].channel_id = 0;
1206             }
1207
1208             //this can be a big packet, it's better to send it right here
1209             if ((ret = ff_rtmp_packet_create(&rt->out_pkt, RTMP_SOURCE_CHANNEL,
1210                                              pkttype, ts, pktsize)) < 0)
1211                 return ret;
1212
1213             rt->out_pkt.extra = rt->main_channel_id;
1214             rt->flv_data = rt->out_pkt.data;
1215
1216             if (pkttype == RTMP_PT_NOTIFY)
1217                 ff_amf_write_string(&rt->flv_data, "@setDataFrame");
1218         }
1219
1220         if (rt->flv_size - rt->flv_off > size_temp) {
1221             bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, size_temp);
1222             rt->flv_off += size_temp;
1223             size_temp = 0;
1224         } else {
1225             bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, rt->flv_size - rt->flv_off);
1226             size_temp   -= rt->flv_size - rt->flv_off;
1227             rt->flv_off += rt->flv_size - rt->flv_off;
1228         }
1229
1230         if (rt->flv_off == rt->flv_size) {
1231             rt->skip_bytes = 4;
1232
1233             if ((ret = ff_rtmp_packet_write(rt->stream, &rt->out_pkt,
1234                                             rt->chunk_size, rt->prev_pkt[1])) < 0)
1235                 return ret;
1236             ff_rtmp_packet_destroy(&rt->out_pkt);
1237             rt->flv_size = 0;
1238             rt->flv_off = 0;
1239             rt->flv_header_bytes = 0;
1240         }
1241     } while (buf_temp - buf < size);
1242     return size;
1243 }
1244
1245 #define OFFSET(x) offsetof(RTMPContext, x)
1246 #define DEC AV_OPT_FLAG_DECODING_PARAM
1247 #define ENC AV_OPT_FLAG_ENCODING_PARAM
1248
1249 static const AVOption rtmp_options[] = {
1250     {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1251     {"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},
1252     {"rtmp_live", "Specify that the media is a live stream.", OFFSET(live), AV_OPT_TYPE_INT, {-2}, INT_MIN, INT_MAX, DEC, "rtmp_live"},
1253     {"any", "both", 0, AV_OPT_TYPE_CONST, {-2}, 0, 0, DEC, "rtmp_live"},
1254     {"live", "live stream", 0, AV_OPT_TYPE_CONST, {-1}, 0, 0, DEC, "rtmp_live"},
1255     {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {0}, 0, 0, DEC, "rtmp_live"},
1256     {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1257     {"rtmp_swfurl", "URL of the SWF player. By default no value will be sent", OFFSET(swfurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1258     {"rtmp_tcurl", "URL of the target stream. Defaults to rtmp://host[:port]/app.", OFFSET(tcurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1259     { NULL },
1260 };
1261
1262 static const AVClass rtmp_class = {
1263     .class_name = "rtmp",
1264     .item_name  = av_default_item_name,
1265     .option     = rtmp_options,
1266     .version    = LIBAVUTIL_VERSION_INT,
1267 };
1268
1269 URLProtocol ff_rtmp_protocol = {
1270     .name           = "rtmp",
1271     .url_open       = rtmp_open,
1272     .url_read       = rtmp_read,
1273     .url_write      = rtmp_write,
1274     .url_close      = rtmp_close,
1275     .priv_data_size = sizeof(RTMPContext),
1276     .flags          = URL_PROTOCOL_FLAG_NETWORK,
1277     .priv_data_class= &rtmp_class,
1278 };