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