]> rtime.felk.cvut.cz Git - frescor/ffmpeg.git/blob - libavformat/rtmpproto.c
change \0xa9enc tag metadata name to encoder to match id3v2
[frescor/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 libavformat/rtmpproto.c
24  * RTMP protocol
25  */
26
27 #include "libavcodec/bytestream.h"
28 #include "libavutil/avstring.h"
29 #include "libavutil/lfg.h"
30 #include "libavutil/sha.h"
31 #include "avformat.h"
32
33 #include "network.h"
34
35 #include "flv.h"
36 #include "rtmp.h"
37 #include "rtmppkt.h"
38
39 /* we can't use av_log() with URLContext yet... */
40 #if LIBAVFORMAT_VERSION_MAJOR < 53
41 #define LOG_CONTEXT NULL
42 #else
43 #define LOG_CONTEXT s
44 #endif
45
46 /** RTMP protocol handler state */
47 typedef enum {
48     STATE_START,      ///< client has not done anything yet
49     STATE_HANDSHAKED, ///< client has performed handshake
50     STATE_CONNECTING, ///< client connected to server successfully
51     STATE_READY,      ///< client has sent all needed commands and waits for server reply
52     STATE_PLAYING,    ///< client has started receiving multimedia data from server
53 } ClientState;
54
55 /** protocol handler context */
56 typedef struct RTMPContext {
57     URLContext*   stream;                     ///< TCP stream used in interactions with RTMP server
58     RTMPPacket    prev_pkt[2][RTMP_CHANNELS]; ///< packet history used when reading and sending packets
59     int           chunk_size;                 ///< size of the chunks RTMP packets are divided into
60     char          playpath[256];              ///< path to filename to play (with possible "mp4:" prefix)
61     ClientState   state;                      ///< current state
62     int           main_channel_id;            ///< an additional channel ID which is used for some invocations
63     uint8_t*      flv_data;                   ///< buffer with data for demuxer
64     int           flv_size;                   ///< current buffer size
65     int           flv_off;                    ///< number of bytes read from current buffer
66     uint32_t      video_ts;                   ///< current video timestamp in milliseconds
67     uint32_t      audio_ts;                   ///< current audio timestamp in milliseconds
68 } RTMPContext;
69
70 #define PLAYER_KEY_OPEN_PART_LEN 30   ///< length of partial key used for first client digest signing
71 /** Client key used for digest signing */
72 static const uint8_t rtmp_player_key[] = {
73     'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
74     'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
75
76     0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
77     0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
78     0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
79 };
80
81 #define SERVER_KEY_OPEN_PART_LEN 36   ///< length of partial key used for first server digest signing
82 /** Key used for RTMP server digest signing */
83 static const uint8_t rtmp_server_key[] = {
84     'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
85     'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
86     'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
87
88     0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
89     0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
90     0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
91 };
92
93 /**
94  * Generates 'connect' call and sends it to the server.
95  */
96 static void gen_connect(URLContext *s, RTMPContext *rt, const char *proto,
97                         const char *host, int port, const char *app)
98 {
99     RTMPPacket pkt;
100     uint8_t ver[32], *p;
101     char tcurl[512];
102
103     ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE, 0, 4096);
104     p = pkt.data;
105
106     snprintf(tcurl, sizeof(tcurl), "%s://%s:%d/%s", proto, host, port, app);
107     ff_amf_write_string(&p, "connect");
108     ff_amf_write_number(&p, 1.0);
109     ff_amf_write_object_start(&p);
110     ff_amf_write_field_name(&p, "app");
111     ff_amf_write_string(&p, app);
112
113     snprintf(ver, sizeof(ver), "%s %d,%d,%d,%d", RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1,
114              RTMP_CLIENT_VER2, RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
115     ff_amf_write_field_name(&p, "flashVer");
116     ff_amf_write_string(&p, ver);
117     ff_amf_write_field_name(&p, "tcUrl");
118     ff_amf_write_string(&p, tcurl);
119     ff_amf_write_field_name(&p, "fpad");
120     ff_amf_write_bool(&p, 0);
121     ff_amf_write_field_name(&p, "capabilities");
122     ff_amf_write_number(&p, 15.0);
123     ff_amf_write_field_name(&p, "audioCodecs");
124     ff_amf_write_number(&p, 1639.0);
125     ff_amf_write_field_name(&p, "videoCodecs");
126     ff_amf_write_number(&p, 252.0);
127     ff_amf_write_field_name(&p, "videoFunction");
128     ff_amf_write_number(&p, 1.0);
129     ff_amf_write_object_end(&p);
130
131     pkt.data_size = p - pkt.data;
132
133     ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
134 }
135
136 /**
137  * Generates 'createStream' call and sends it to the server. It should make
138  * the server allocate some channel for media streams.
139  */
140 static void gen_create_stream(URLContext *s, RTMPContext *rt)
141 {
142     RTMPPacket pkt;
143     uint8_t *p;
144
145     av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Creating stream...\n");
146     ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE, 0, 25);
147
148     p = pkt.data;
149     ff_amf_write_string(&p, "createStream");
150     ff_amf_write_number(&p, 3.0);
151     ff_amf_write_null(&p);
152
153     ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
154     ff_rtmp_packet_destroy(&pkt);
155 }
156
157 /**
158  * Generates 'play' call and sends it to the server, then pings the server
159  * to start actual playing.
160  */
161 static void gen_play(URLContext *s, RTMPContext *rt)
162 {
163     RTMPPacket pkt;
164     uint8_t *p;
165
166     av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
167     ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE, 0,
168                           20 + strlen(rt->playpath));
169     pkt.extra = rt->main_channel_id;
170
171     p = pkt.data;
172     ff_amf_write_string(&p, "play");
173     ff_amf_write_number(&p, 0.0);
174     ff_amf_write_null(&p);
175     ff_amf_write_string(&p, rt->playpath);
176
177     ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
178     ff_rtmp_packet_destroy(&pkt);
179
180     // set client buffer time disguised in ping packet
181     ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, 1, 10);
182
183     p = pkt.data;
184     bytestream_put_be16(&p, 3);
185     bytestream_put_be32(&p, 1);
186     bytestream_put_be32(&p, 256); //TODO: what is a good value here?
187
188     ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
189     ff_rtmp_packet_destroy(&pkt);
190 }
191
192 /**
193  * Generates ping reply and sends it to the server.
194  */
195 static void gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
196 {
197     RTMPPacket pkt;
198     uint8_t *p;
199
200     ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, ppkt->timestamp + 1, 6);
201     p = pkt.data;
202     bytestream_put_be16(&p, 7);
203     bytestream_put_be32(&p, AV_RB32(ppkt->data+2) + 1);
204     ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
205     ff_rtmp_packet_destroy(&pkt);
206 }
207
208 //TODO: Move HMAC code somewhere. Eventually.
209 #define HMAC_IPAD_VAL 0x36
210 #define HMAC_OPAD_VAL 0x5C
211
212 /**
213  * Calculates HMAC-SHA2 digest for RTMP handshake packets.
214  *
215  * @param src    input buffer
216  * @param len    input buffer length (should be 1536)
217  * @param gap    offset in buffer where 32 bytes should not be taken into account
218  *               when calculating digest (since it will be used to store that digest)
219  * @param key    digest key
220  * @param keylen digest key length
221  * @param dst    buffer where calculated digest will be stored (32 bytes)
222  */
223 static void rtmp_calc_digest(const uint8_t *src, int len, int gap,
224                              const uint8_t *key, int keylen, uint8_t *dst)
225 {
226     struct AVSHA *sha;
227     uint8_t hmac_buf[64+32] = {0};
228     int i;
229
230     sha = av_mallocz(av_sha_size);
231
232     if (keylen < 64) {
233         memcpy(hmac_buf, key, keylen);
234     } else {
235         av_sha_init(sha, 256);
236         av_sha_update(sha,key, keylen);
237         av_sha_final(sha, hmac_buf);
238     }
239     for (i = 0; i < 64; i++)
240         hmac_buf[i] ^= HMAC_IPAD_VAL;
241
242     av_sha_init(sha, 256);
243     av_sha_update(sha, hmac_buf, 64);
244     if (gap <= 0) {
245         av_sha_update(sha, src, len);
246     } else { //skip 32 bytes used for storing digest
247         av_sha_update(sha, src, gap);
248         av_sha_update(sha, src + gap + 32, len - gap - 32);
249     }
250     av_sha_final(sha, hmac_buf + 64);
251
252     for (i = 0; i < 64; i++)
253         hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
254     av_sha_init(sha, 256);
255     av_sha_update(sha, hmac_buf, 64+32);
256     av_sha_final(sha, dst);
257
258     av_free(sha);
259 }
260
261 /**
262  * Puts HMAC-SHA2 digest of packet data (except for the bytes where this digest
263  * will be stored) into that packet.
264  *
265  * @param buf handshake data (1536 bytes)
266  * @return offset to the digest inside input data
267  */
268 static int rtmp_handshake_imprint_with_digest(uint8_t *buf)
269 {
270     int i, digest_pos = 0;
271
272     for (i = 8; i < 12; i++)
273         digest_pos += buf[i];
274     digest_pos = (digest_pos % 728) + 12;
275
276     rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
277                      rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
278                      buf + digest_pos);
279     return digest_pos;
280 }
281
282 /**
283  * Verifies that the received server response has the expected digest value.
284  *
285  * @param buf handshake data received from the server (1536 bytes)
286  * @param off position to search digest offset from
287  * @return 0 if digest is valid, digest position otherwise
288  */
289 static int rtmp_validate_digest(uint8_t *buf, int off)
290 {
291     int i, digest_pos = 0;
292     uint8_t digest[32];
293
294     for (i = 0; i < 4; i++)
295         digest_pos += buf[i + off];
296     digest_pos = (digest_pos % 728) + off + 4;
297
298     rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
299                      rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
300                      digest);
301     if (!memcmp(digest, buf + digest_pos, 32))
302         return digest_pos;
303     return 0;
304 }
305
306 /**
307  * Performs handshake with the server by means of exchanging pseudorandom data
308  * signed with HMAC-SHA2 digest.
309  *
310  * @return 0 if handshake succeeds, negative value otherwise
311  */
312 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
313 {
314     AVLFG rnd;
315     uint8_t tosend    [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
316         3,                // unencrypted data
317         0, 0, 0, 0,       // client uptime
318         RTMP_CLIENT_VER1,
319         RTMP_CLIENT_VER2,
320         RTMP_CLIENT_VER3,
321         RTMP_CLIENT_VER4,
322     };
323     uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
324     uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
325     int i;
326     int server_pos, client_pos;
327     uint8_t digest[32];
328
329     av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Handshaking...\n");
330
331     av_lfg_init(&rnd, 0xDEADC0DE);
332     // generate handshake packet - 1536 bytes of pseudorandom data
333     for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
334         tosend[i] = av_lfg_get(&rnd) >> 24;
335     client_pos = rtmp_handshake_imprint_with_digest(tosend + 1);
336
337     url_write(rt->stream, tosend, RTMP_HANDSHAKE_PACKET_SIZE + 1);
338     i = url_read_complete(rt->stream, serverdata, RTMP_HANDSHAKE_PACKET_SIZE + 1);
339     if (i != RTMP_HANDSHAKE_PACKET_SIZE + 1) {
340         av_log(LOG_CONTEXT, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
341         return -1;
342     }
343     i = url_read_complete(rt->stream, clientdata, RTMP_HANDSHAKE_PACKET_SIZE);
344     if (i != RTMP_HANDSHAKE_PACKET_SIZE) {
345         av_log(LOG_CONTEXT, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
346         return -1;
347     }
348
349     av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
350            serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
351
352     server_pos = rtmp_validate_digest(serverdata + 1, 772);
353     if (!server_pos) {
354         server_pos = rtmp_validate_digest(serverdata + 1, 8);
355         if (!server_pos) {
356             av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server response validating failed\n");
357             return -1;
358         }
359     }
360
361     rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
362                      rtmp_server_key, sizeof(rtmp_server_key),
363                      digest);
364     rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE-32, 0,
365                      digest, 32,
366                      digest);
367     if (memcmp(digest, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
368         av_log(LOG_CONTEXT, AV_LOG_ERROR, "Signature mismatch\n");
369         return -1;
370     }
371
372     for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
373         tosend[i] = av_lfg_get(&rnd) >> 24;
374     rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
375                      rtmp_player_key, sizeof(rtmp_player_key),
376                      digest);
377     rtmp_calc_digest(tosend,  RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
378                      digest, 32,
379                      tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
380
381     // write reply back to the server
382     url_write(rt->stream, tosend, RTMP_HANDSHAKE_PACKET_SIZE);
383     return 0;
384 }
385
386 /**
387  * Parses received packet and may perform some action depending on
388  * the packet contents.
389  * @return 0 for no errors, negative values for serious errors which prevent
390  *         further communications, positive values for uncritical errors
391  */
392 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
393 {
394     int i, t;
395     const uint8_t *data_end = pkt->data + pkt->data_size;
396
397     switch (pkt->type) {
398     case RTMP_PT_CHUNK_SIZE:
399         if (pkt->data_size != 4) {
400             av_log(LOG_CONTEXT, AV_LOG_ERROR,
401                    "Chunk size change packet is not 4 bytes long (%d)\n", pkt->data_size);
402             return -1;
403         }
404         rt->chunk_size = AV_RB32(pkt->data);
405         if (rt->chunk_size <= 0) {
406             av_log(LOG_CONTEXT, AV_LOG_ERROR, "Incorrect chunk size %d\n", rt->chunk_size);
407             return -1;
408         }
409         av_log(LOG_CONTEXT, AV_LOG_DEBUG, "New chunk size = %d\n", rt->chunk_size);
410         break;
411     case RTMP_PT_PING:
412         t = AV_RB16(pkt->data);
413         if (t == 6)
414             gen_pong(s, rt, pkt);
415         break;
416     case RTMP_PT_INVOKE:
417         //TODO: check for the messages sent for wrong state?
418         if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
419             uint8_t tmpstr[256];
420
421             if (!ff_amf_get_field_value(pkt->data + 9, data_end,
422                                         "description", tmpstr, sizeof(tmpstr)))
423                 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
424             return -1;
425         } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
426             switch (rt->state) {
427             case STATE_HANDSHAKED:
428                 gen_create_stream(s, rt);
429                 rt->state = STATE_CONNECTING;
430                 break;
431             case STATE_CONNECTING:
432                 //extract a number from the result
433                 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
434                     av_log(LOG_CONTEXT, AV_LOG_WARNING, "Unexpected reply on connect()\n");
435                 } else {
436                     rt->main_channel_id = (int) av_int2dbl(AV_RB64(pkt->data + 21));
437                 }
438                 gen_play(s, rt);
439                 rt->state = STATE_READY;
440                 break;
441             }
442         } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
443             const uint8_t* ptr = pkt->data + 11;
444             uint8_t tmpstr[256];
445             int t;
446
447             for (i = 0; i < 2; i++) {
448                 t = ff_amf_tag_size(ptr, data_end);
449                 if (t < 0)
450                     return 1;
451                 ptr += t;
452             }
453             t = ff_amf_get_field_value(ptr, data_end,
454                                        "level", tmpstr, sizeof(tmpstr));
455             if (!t && !strcmp(tmpstr, "error")) {
456                 if (!ff_amf_get_field_value(ptr, data_end,
457                                             "description", tmpstr, sizeof(tmpstr)))
458                     av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
459                 return -1;
460             }
461             t = ff_amf_get_field_value(ptr, data_end,
462                                        "code", tmpstr, sizeof(tmpstr));
463             if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) {
464                 rt->state = STATE_PLAYING;
465                 return 0;
466             }
467         }
468         break;
469     }
470     return 0;
471 }
472
473 /**
474  * Interacts with the server by receiving and sending RTMP packets until
475  * there is some significant data (media data or expected status notification).
476  *
477  * @param s          reading context
478  * @param for_header non-zero value tells function to work until it gets notification from the server that playing has been started, otherwise function will work until some media data is received (or an error happens)
479  * @return 0 for successful operation, negative value in case of error
480  */
481 static int get_packet(URLContext *s, int for_header)
482 {
483     RTMPContext *rt = s->priv_data;
484     int ret;
485
486     for(;;) {
487         RTMPPacket rpkt;
488         if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
489                                        rt->chunk_size, rt->prev_pkt[0])) != 0) {
490             if (ret > 0) {
491                 return AVERROR(EAGAIN);
492             } else {
493                 return AVERROR(EIO);
494             }
495         }
496
497         ret = rtmp_parse_result(s, rt, &rpkt);
498         if (ret < 0) {//serious error in current packet
499             ff_rtmp_packet_destroy(&rpkt);
500             return -1;
501         }
502         if (for_header && rt->state == STATE_PLAYING) {
503             ff_rtmp_packet_destroy(&rpkt);
504             return 0;
505         }
506         if (!rpkt.data_size) {
507             ff_rtmp_packet_destroy(&rpkt);
508             continue;
509         }
510         if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO ||
511             rpkt.type == RTMP_PT_NOTIFY) {
512             uint8_t *p;
513             uint32_t ts = rpkt.timestamp;
514
515             if (rpkt.type == RTMP_PT_VIDEO) {
516                 rt->video_ts += rpkt.timestamp;
517                 ts = rt->video_ts;
518             } else if (rpkt.type == RTMP_PT_AUDIO) {
519                 rt->audio_ts += rpkt.timestamp;
520                 ts = rt->audio_ts;
521             }
522             // generate packet header and put data into buffer for FLV demuxer
523             rt->flv_off  = 0;
524             rt->flv_size = rpkt.data_size + 15;
525             rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size);
526             bytestream_put_byte(&p, rpkt.type);
527             bytestream_put_be24(&p, rpkt.data_size);
528             bytestream_put_be24(&p, ts);
529             bytestream_put_byte(&p, ts >> 24);
530             bytestream_put_be24(&p, 0);
531             bytestream_put_buffer(&p, rpkt.data, rpkt.data_size);
532             bytestream_put_be32(&p, 0);
533             ff_rtmp_packet_destroy(&rpkt);
534             return 0;
535         } else if (rpkt.type == RTMP_PT_METADATA) {
536             // we got raw FLV data, make it available for FLV demuxer
537             rt->flv_off  = 0;
538             rt->flv_size = rpkt.data_size;
539             rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
540             memcpy(rt->flv_data, rpkt.data, rpkt.data_size);
541             ff_rtmp_packet_destroy(&rpkt);
542             return 0;
543         }
544         ff_rtmp_packet_destroy(&rpkt);
545     }
546     return 0;
547 }
548
549 static int rtmp_close(URLContext *h)
550 {
551     RTMPContext *rt = h->priv_data;
552
553     av_freep(&rt->flv_data);
554     url_close(rt->stream);
555     av_free(rt);
556     return 0;
557 }
558
559 /**
560  * Opens RTMP connection and verifies that the stream can be played.
561  *
562  * URL syntax: rtmp://server[:port][/app][/playpath]
563  *             where 'app' is first one or two directories in the path
564  *             (e.g. /ondemand/, /flash/live/, etc.)
565  *             and 'playpath' is a file name (the rest of the path,
566  *             may be prefixed with "mp4:")
567  */
568 static int rtmp_open(URLContext *s, const char *uri, int flags)
569 {
570     RTMPContext *rt;
571     char proto[8], hostname[256], path[1024], app[128], *fname;
572     uint8_t buf[2048];
573     int port, is_input;
574     int ret;
575
576     is_input = !(flags & URL_WRONLY);
577
578     rt = av_mallocz(sizeof(RTMPContext));
579     if (!rt)
580         return AVERROR(ENOMEM);
581     s->priv_data = rt;
582
583     url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
584               path, sizeof(path), s->filename);
585
586     if (port < 0)
587         port = RTMP_DEFAULT_PORT;
588     snprintf(buf, sizeof(buf), "tcp://%s:%d", hostname, port);
589
590     if (url_open(&rt->stream, buf, URL_RDWR) < 0)
591         goto fail;
592
593     if (!is_input) {
594         av_log(LOG_CONTEXT, AV_LOG_ERROR, "RTMP output is not supported yet.\n");
595         goto fail;
596     } else {
597         rt->state = STATE_START;
598         if (rtmp_handshake(s, rt))
599             return -1;
600
601         rt->chunk_size = 128;
602         rt->state = STATE_HANDSHAKED;
603         //extract "app" part from path
604         if (!strncmp(path, "/ondemand/", 10)) {
605             fname = path + 10;
606             memcpy(app, "ondemand", 9);
607         } else {
608             char *p = strchr(path + 1, '/');
609             if (!p) {
610                 fname = path + 1;
611                 app[0] = '\0';
612             } else {
613                 char *c = strchr(p + 1, ':');
614                 fname = strchr(p + 1, '/');
615                 if (!fname || c < fname) {
616                     fname = p + 1;
617                     av_strlcpy(app, path + 1, p - path);
618                 } else {
619                     fname++;
620                     av_strlcpy(app, path + 1, fname - path - 1);
621                 }
622             }
623         }
624         if (!strchr(fname, ':') &&
625             (!strcmp(fname + strlen(fname) - 4, ".f4v") ||
626              !strcmp(fname + strlen(fname) - 4, ".mp4"))) {
627             memcpy(rt->playpath, "mp4:", 5);
628         } else {
629             rt->playpath[0] = 0;
630         }
631         strncat(rt->playpath, fname, sizeof(rt->playpath) - 5);
632
633         av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
634                proto, path, app, rt->playpath);
635         gen_connect(s, rt, proto, hostname, port, app);
636
637         do {
638             ret = get_packet(s, 1);
639         } while (ret == EAGAIN);
640         if (ret < 0)
641             goto fail;
642         // generate FLV header for demuxer
643         rt->flv_size = 13;
644         rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
645         rt->flv_off  = 0;
646         memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size);
647     }
648
649     s->max_packet_size = url_get_max_packet_size(rt->stream);
650     s->is_streamed     = 1;
651     return 0;
652
653 fail:
654     rtmp_close(s);
655     return AVERROR(EIO);
656 }
657
658 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
659 {
660     RTMPContext *rt = s->priv_data;
661     int orig_size = size;
662     int ret;
663
664     while (size > 0) {
665         int data_left = rt->flv_size - rt->flv_off;
666
667         if (data_left >= size) {
668             memcpy(buf, rt->flv_data + rt->flv_off, size);
669             rt->flv_off += size;
670             return orig_size;
671         }
672         if (data_left > 0) {
673             memcpy(buf, rt->flv_data + rt->flv_off, data_left);
674             buf  += data_left;
675             size -= data_left;
676             rt->flv_off = rt->flv_size;
677         }
678         if ((ret = get_packet(s, 0)) < 0)
679            return ret;
680     }
681     return orig_size;
682 }
683
684 static int rtmp_write(URLContext *h, uint8_t *buf, int size)
685 {
686     return 0;
687 }
688
689 URLProtocol rtmp_protocol = {
690     "rtmp",
691     rtmp_open,
692     rtmp_read,
693     rtmp_write,
694     NULL, /* seek */
695     rtmp_close,
696 };