]> git.sesse.net Git - ffmpeg/blob - libavformat/rtmpproto.c
Release frame after decoding is done
[ffmpeg] / 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                           29 + 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     ff_amf_write_number(&p, 0.0);
177
178     ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
179     ff_rtmp_packet_destroy(&pkt);
180
181     // set client buffer time disguised in ping packet
182     ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, 1, 10);
183
184     p = pkt.data;
185     bytestream_put_be16(&p, 3);
186     bytestream_put_be32(&p, 1);
187     bytestream_put_be32(&p, 256); //TODO: what is a good value here?
188
189     ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
190     ff_rtmp_packet_destroy(&pkt);
191 }
192
193 /**
194  * Generates ping reply and sends it to the server.
195  */
196 static void gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
197 {
198     RTMPPacket pkt;
199     uint8_t *p;
200
201     ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, ppkt->timestamp + 1, 6);
202     p = pkt.data;
203     bytestream_put_be16(&p, 7);
204     bytestream_put_be32(&p, AV_RB32(ppkt->data+2) + 1);
205     ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
206     ff_rtmp_packet_destroy(&pkt);
207 }
208
209 //TODO: Move HMAC code somewhere. Eventually.
210 #define HMAC_IPAD_VAL 0x36
211 #define HMAC_OPAD_VAL 0x5C
212
213 /**
214  * Calculates HMAC-SHA2 digest for RTMP handshake packets.
215  *
216  * @param src    input buffer
217  * @param len    input buffer length (should be 1536)
218  * @param gap    offset in buffer where 32 bytes should not be taken into account
219  *               when calculating digest (since it will be used to store that digest)
220  * @param key    digest key
221  * @param keylen digest key length
222  * @param dst    buffer where calculated digest will be stored (32 bytes)
223  */
224 static void rtmp_calc_digest(const uint8_t *src, int len, int gap,
225                              const uint8_t *key, int keylen, uint8_t *dst)
226 {
227     struct AVSHA *sha;
228     uint8_t hmac_buf[64+32] = {0};
229     int i;
230
231     sha = av_mallocz(av_sha_size);
232
233     if (keylen < 64) {
234         memcpy(hmac_buf, key, keylen);
235     } else {
236         av_sha_init(sha, 256);
237         av_sha_update(sha,key, keylen);
238         av_sha_final(sha, hmac_buf);
239     }
240     for (i = 0; i < 64; i++)
241         hmac_buf[i] ^= HMAC_IPAD_VAL;
242
243     av_sha_init(sha, 256);
244     av_sha_update(sha, hmac_buf, 64);
245     if (gap <= 0) {
246         av_sha_update(sha, src, len);
247     } else { //skip 32 bytes used for storing digest
248         av_sha_update(sha, src, gap);
249         av_sha_update(sha, src + gap + 32, len - gap - 32);
250     }
251     av_sha_final(sha, hmac_buf + 64);
252
253     for (i = 0; i < 64; i++)
254         hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
255     av_sha_init(sha, 256);
256     av_sha_update(sha, hmac_buf, 64+32);
257     av_sha_final(sha, dst);
258
259     av_free(sha);
260 }
261
262 /**
263  * Puts HMAC-SHA2 digest of packet data (except for the bytes where this digest
264  * will be stored) into that packet.
265  *
266  * @param buf handshake data (1536 bytes)
267  * @return offset to the digest inside input data
268  */
269 static int rtmp_handshake_imprint_with_digest(uint8_t *buf)
270 {
271     int i, digest_pos = 0;
272
273     for (i = 8; i < 12; i++)
274         digest_pos += buf[i];
275     digest_pos = (digest_pos % 728) + 12;
276
277     rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
278                      rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
279                      buf + digest_pos);
280     return digest_pos;
281 }
282
283 /**
284  * Verifies that the received server response has the expected digest value.
285  *
286  * @param buf handshake data received from the server (1536 bytes)
287  * @param off position to search digest offset from
288  * @return 0 if digest is valid, digest position otherwise
289  */
290 static int rtmp_validate_digest(uint8_t *buf, int off)
291 {
292     int i, digest_pos = 0;
293     uint8_t digest[32];
294
295     for (i = 0; i < 4; i++)
296         digest_pos += buf[i + off];
297     digest_pos = (digest_pos % 728) + off + 4;
298
299     rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
300                      rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
301                      digest);
302     if (!memcmp(digest, buf + digest_pos, 32))
303         return digest_pos;
304     return 0;
305 }
306
307 /**
308  * Performs handshake with the server by means of exchanging pseudorandom data
309  * signed with HMAC-SHA2 digest.
310  *
311  * @return 0 if handshake succeeds, negative value otherwise
312  */
313 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
314 {
315     AVLFG rnd;
316     uint8_t tosend    [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
317         3,                // unencrypted data
318         0, 0, 0, 0,       // client uptime
319         RTMP_CLIENT_VER1,
320         RTMP_CLIENT_VER2,
321         RTMP_CLIENT_VER3,
322         RTMP_CLIENT_VER4,
323     };
324     uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
325     uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
326     int i;
327     int server_pos, client_pos;
328     uint8_t digest[32];
329
330     av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Handshaking...\n");
331
332     av_lfg_init(&rnd, 0xDEADC0DE);
333     // generate handshake packet - 1536 bytes of pseudorandom data
334     for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
335         tosend[i] = av_lfg_get(&rnd) >> 24;
336     client_pos = rtmp_handshake_imprint_with_digest(tosend + 1);
337
338     url_write(rt->stream, tosend, RTMP_HANDSHAKE_PACKET_SIZE + 1);
339     i = url_read_complete(rt->stream, serverdata, RTMP_HANDSHAKE_PACKET_SIZE + 1);
340     if (i != RTMP_HANDSHAKE_PACKET_SIZE + 1) {
341         av_log(LOG_CONTEXT, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
342         return -1;
343     }
344     i = url_read_complete(rt->stream, clientdata, RTMP_HANDSHAKE_PACKET_SIZE);
345     if (i != RTMP_HANDSHAKE_PACKET_SIZE) {
346         av_log(LOG_CONTEXT, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
347         return -1;
348     }
349
350     av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
351            serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
352
353     server_pos = rtmp_validate_digest(serverdata + 1, 772);
354     if (!server_pos) {
355         server_pos = rtmp_validate_digest(serverdata + 1, 8);
356         if (!server_pos) {
357             av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server response validating failed\n");
358             return -1;
359         }
360     }
361
362     rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
363                      rtmp_server_key, sizeof(rtmp_server_key),
364                      digest);
365     rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE-32, 0,
366                      digest, 32,
367                      digest);
368     if (memcmp(digest, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
369         av_log(LOG_CONTEXT, AV_LOG_ERROR, "Signature mismatch\n");
370         return -1;
371     }
372
373     for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
374         tosend[i] = av_lfg_get(&rnd) >> 24;
375     rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
376                      rtmp_player_key, sizeof(rtmp_player_key),
377                      digest);
378     rtmp_calc_digest(tosend,  RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
379                      digest, 32,
380                      tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
381
382     // write reply back to the server
383     url_write(rt->stream, tosend, RTMP_HANDSHAKE_PACKET_SIZE);
384     return 0;
385 }
386
387 /**
388  * Parses received packet and may perform some action depending on
389  * the packet contents.
390  * @return 0 for no errors, negative values for serious errors which prevent
391  *         further communications, positive values for uncritical errors
392  */
393 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
394 {
395     int i, t;
396     const uint8_t *data_end = pkt->data + pkt->data_size;
397
398     switch (pkt->type) {
399     case RTMP_PT_CHUNK_SIZE:
400         if (pkt->data_size != 4) {
401             av_log(LOG_CONTEXT, AV_LOG_ERROR,
402                    "Chunk size change packet is not 4 bytes long (%d)\n", pkt->data_size);
403             return -1;
404         }
405         rt->chunk_size = AV_RB32(pkt->data);
406         if (rt->chunk_size <= 0) {
407             av_log(LOG_CONTEXT, AV_LOG_ERROR, "Incorrect chunk size %d\n", rt->chunk_size);
408             return -1;
409         }
410         av_log(LOG_CONTEXT, AV_LOG_DEBUG, "New chunk size = %d\n", rt->chunk_size);
411         break;
412     case RTMP_PT_PING:
413         t = AV_RB16(pkt->data);
414         if (t == 6)
415             gen_pong(s, rt, pkt);
416         break;
417     case RTMP_PT_INVOKE:
418         //TODO: check for the messages sent for wrong state?
419         if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
420             uint8_t tmpstr[256];
421
422             if (!ff_amf_get_field_value(pkt->data + 9, data_end,
423                                         "description", tmpstr, sizeof(tmpstr)))
424                 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
425             return -1;
426         } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
427             switch (rt->state) {
428             case STATE_HANDSHAKED:
429                 gen_create_stream(s, rt);
430                 rt->state = STATE_CONNECTING;
431                 break;
432             case STATE_CONNECTING:
433                 //extract a number from the result
434                 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
435                     av_log(LOG_CONTEXT, AV_LOG_WARNING, "Unexpected reply on connect()\n");
436                 } else {
437                     rt->main_channel_id = (int) av_int2dbl(AV_RB64(pkt->data + 21));
438                 }
439                 gen_play(s, rt);
440                 rt->state = STATE_READY;
441                 break;
442             }
443         } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
444             const uint8_t* ptr = pkt->data + 11;
445             uint8_t tmpstr[256];
446             int t;
447
448             for (i = 0; i < 2; i++) {
449                 t = ff_amf_tag_size(ptr, data_end);
450                 if (t < 0)
451                     return 1;
452                 ptr += t;
453             }
454             t = ff_amf_get_field_value(ptr, data_end,
455                                        "level", tmpstr, sizeof(tmpstr));
456             if (!t && !strcmp(tmpstr, "error")) {
457                 if (!ff_amf_get_field_value(ptr, data_end,
458                                             "description", tmpstr, sizeof(tmpstr)))
459                     av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
460                 return -1;
461             }
462             t = ff_amf_get_field_value(ptr, data_end,
463                                        "code", tmpstr, sizeof(tmpstr));
464             if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) {
465                 rt->state = STATE_PLAYING;
466                 return 0;
467             }
468         }
469         break;
470     }
471     return 0;
472 }
473
474 /**
475  * Interacts with the server by receiving and sending RTMP packets until
476  * there is some significant data (media data or expected status notification).
477  *
478  * @param s          reading context
479  * @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)
480  * @return 0 for successful operation, negative value in case of error
481  */
482 static int get_packet(URLContext *s, int for_header)
483 {
484     RTMPContext *rt = s->priv_data;
485     int ret;
486
487     for(;;) {
488         RTMPPacket rpkt;
489         if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
490                                        rt->chunk_size, rt->prev_pkt[0])) != 0) {
491             if (ret > 0) {
492                 return AVERROR(EAGAIN);
493             } else {
494                 return AVERROR(EIO);
495             }
496         }
497
498         ret = rtmp_parse_result(s, rt, &rpkt);
499         if (ret < 0) {//serious error in current packet
500             ff_rtmp_packet_destroy(&rpkt);
501             return -1;
502         }
503         if (for_header && rt->state == STATE_PLAYING) {
504             ff_rtmp_packet_destroy(&rpkt);
505             return 0;
506         }
507         if (!rpkt.data_size) {
508             ff_rtmp_packet_destroy(&rpkt);
509             continue;
510         }
511         if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO ||
512             rpkt.type == RTMP_PT_NOTIFY) {
513             uint8_t *p;
514             uint32_t ts = rpkt.timestamp;
515
516             if (rpkt.type == RTMP_PT_VIDEO) {
517                 rt->video_ts += rpkt.timestamp;
518                 ts = rt->video_ts;
519             } else if (rpkt.type == RTMP_PT_AUDIO) {
520                 rt->audio_ts += rpkt.timestamp;
521                 ts = rt->audio_ts;
522             }
523             // generate packet header and put data into buffer for FLV demuxer
524             rt->flv_off  = 0;
525             rt->flv_size = rpkt.data_size + 15;
526             rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size);
527             bytestream_put_byte(&p, rpkt.type);
528             bytestream_put_be24(&p, rpkt.data_size);
529             bytestream_put_be24(&p, ts);
530             bytestream_put_byte(&p, ts >> 24);
531             bytestream_put_be24(&p, 0);
532             bytestream_put_buffer(&p, rpkt.data, rpkt.data_size);
533             bytestream_put_be32(&p, 0);
534             ff_rtmp_packet_destroy(&rpkt);
535             return 0;
536         } else if (rpkt.type == RTMP_PT_METADATA) {
537             // we got raw FLV data, make it available for FLV demuxer
538             rt->flv_off  = 0;
539             rt->flv_size = rpkt.data_size;
540             rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
541             memcpy(rt->flv_data, rpkt.data, rpkt.data_size);
542             ff_rtmp_packet_destroy(&rpkt);
543             return 0;
544         }
545         ff_rtmp_packet_destroy(&rpkt);
546     }
547     return 0;
548 }
549
550 static int rtmp_close(URLContext *h)
551 {
552     RTMPContext *rt = h->priv_data;
553
554     av_freep(&rt->flv_data);
555     url_close(rt->stream);
556     av_free(rt);
557     return 0;
558 }
559
560 /**
561  * Opens RTMP connection and verifies that the stream can be played.
562  *
563  * URL syntax: rtmp://server[:port][/app][/playpath]
564  *             where 'app' is first one or two directories in the path
565  *             (e.g. /ondemand/, /flash/live/, etc.)
566  *             and 'playpath' is a file name (the rest of the path,
567  *             may be prefixed with "mp4:")
568  */
569 static int rtmp_open(URLContext *s, const char *uri, int flags)
570 {
571     RTMPContext *rt;
572     char proto[8], hostname[256], path[1024], app[128], *fname;
573     uint8_t buf[2048];
574     int port, is_input;
575     int ret;
576
577     is_input = !(flags & URL_WRONLY);
578
579     rt = av_mallocz(sizeof(RTMPContext));
580     if (!rt)
581         return AVERROR(ENOMEM);
582     s->priv_data = rt;
583
584     url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
585               path, sizeof(path), s->filename);
586
587     if (port < 0)
588         port = RTMP_DEFAULT_PORT;
589     snprintf(buf, sizeof(buf), "tcp://%s:%d", hostname, port);
590
591     if (url_open(&rt->stream, buf, URL_RDWR) < 0)
592         goto fail;
593
594     if (!is_input) {
595         av_log(LOG_CONTEXT, AV_LOG_ERROR, "RTMP output is not supported yet.\n");
596         goto fail;
597     } else {
598         rt->state = STATE_START;
599         if (rtmp_handshake(s, rt))
600             return -1;
601
602         rt->chunk_size = 128;
603         rt->state = STATE_HANDSHAKED;
604         //extract "app" part from path
605         if (!strncmp(path, "/ondemand/", 10)) {
606             fname = path + 10;
607             memcpy(app, "ondemand", 9);
608         } else {
609             char *p = strchr(path + 1, '/');
610             if (!p) {
611                 fname = path + 1;
612                 app[0] = '\0';
613             } else {
614                 char *c = strchr(p + 1, ':');
615                 fname = strchr(p + 1, '/');
616                 if (!fname || c < fname) {
617                     fname = p + 1;
618                     av_strlcpy(app, path + 1, p - path);
619                 } else {
620                     fname++;
621                     av_strlcpy(app, path + 1, fname - path - 1);
622                 }
623             }
624         }
625         if (!strchr(fname, ':') &&
626             (!strcmp(fname + strlen(fname) - 4, ".f4v") ||
627              !strcmp(fname + strlen(fname) - 4, ".mp4"))) {
628             memcpy(rt->playpath, "mp4:", 5);
629         } else {
630             rt->playpath[0] = 0;
631         }
632         strncat(rt->playpath, fname, sizeof(rt->playpath) - 5);
633
634         av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
635                proto, path, app, rt->playpath);
636         gen_connect(s, rt, proto, hostname, port, app);
637
638         do {
639             ret = get_packet(s, 1);
640         } while (ret == EAGAIN);
641         if (ret < 0)
642             goto fail;
643         // generate FLV header for demuxer
644         rt->flv_size = 13;
645         rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
646         rt->flv_off  = 0;
647         memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size);
648     }
649
650     s->max_packet_size = url_get_max_packet_size(rt->stream);
651     s->is_streamed     = 1;
652     return 0;
653
654 fail:
655     rtmp_close(s);
656     return AVERROR(EIO);
657 }
658
659 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
660 {
661     RTMPContext *rt = s->priv_data;
662     int orig_size = size;
663     int ret;
664
665     while (size > 0) {
666         int data_left = rt->flv_size - rt->flv_off;
667
668         if (data_left >= size) {
669             memcpy(buf, rt->flv_data + rt->flv_off, size);
670             rt->flv_off += size;
671             return orig_size;
672         }
673         if (data_left > 0) {
674             memcpy(buf, rt->flv_data + rt->flv_off, data_left);
675             buf  += data_left;
676             size -= data_left;
677             rt->flv_off = rt->flv_size;
678         }
679         if ((ret = get_packet(s, 0)) < 0)
680            return ret;
681     }
682     return orig_size;
683 }
684
685 static int rtmp_write(URLContext *h, uint8_t *buf, int size)
686 {
687     return 0;
688 }
689
690 URLProtocol rtmp_protocol = {
691     "rtmp",
692     rtmp_open,
693     rtmp_read,
694     rtmp_write,
695     NULL, /* seek */
696     rtmp_close,
697 };