Statistics
| Branch: | Revision:

ffmpeg / libavformat / rtmpproto.c @ f68c8a50

History | View | Annotate | Download (23.5 KB)

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
};