00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00027 #include "libavcodec/bytestream.h"
00028 #include "libavutil/avstring.h"
00029 #include "libavutil/lfg.h"
00030 #include "libavutil/sha.h"
00031 #include "avformat.h"
00032 #include "internal.h"
00033
00034 #include "network.h"
00035
00036 #include "flv.h"
00037 #include "rtmp.h"
00038 #include "rtmppkt.h"
00039 #include "url.h"
00040
00041
00042
00044 typedef enum {
00045 STATE_START,
00046 STATE_HANDSHAKED,
00047 STATE_RELEASING,
00048 STATE_FCPUBLISH,
00049 STATE_CONNECTING,
00050 STATE_READY,
00051 STATE_PLAYING,
00052 STATE_PUBLISHING,
00053 STATE_STOPPED,
00054 } ClientState;
00055
00057 typedef struct RTMPContext {
00058 URLContext* stream;
00059 RTMPPacket prev_pkt[2][RTMP_CHANNELS];
00060 int chunk_size;
00061 int is_input;
00062 char playpath[256];
00063 char app[128];
00064 ClientState state;
00065 int main_channel_id;
00066 uint8_t* flv_data;
00067 int flv_size;
00068 int flv_off;
00069 RTMPPacket out_pkt;
00070 uint32_t client_report_size;
00071 uint32_t bytes_read;
00072 uint32_t last_bytes_read;
00073 } RTMPContext;
00074
00075 #define PLAYER_KEY_OPEN_PART_LEN 30
00076
00077 static const uint8_t rtmp_player_key[] = {
00078 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
00079 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
00080
00081 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
00082 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
00083 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
00084 };
00085
00086 #define SERVER_KEY_OPEN_PART_LEN 36
00087
00088 static const uint8_t rtmp_server_key[] = {
00089 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
00090 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
00091 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
00092
00093 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
00094 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
00095 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
00096 };
00097
00101 static void gen_connect(URLContext *s, RTMPContext *rt, const char *proto,
00102 const char *host, int port)
00103 {
00104 RTMPPacket pkt;
00105 uint8_t ver[64], *p;
00106 char tcurl[512];
00107
00108 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, 4096);
00109 p = pkt.data;
00110
00111 ff_url_join(tcurl, sizeof(tcurl), proto, NULL, host, port, "/%s", rt->app);
00112 ff_amf_write_string(&p, "connect");
00113 ff_amf_write_number(&p, 1.0);
00114 ff_amf_write_object_start(&p);
00115 ff_amf_write_field_name(&p, "app");
00116 ff_amf_write_string(&p, rt->app);
00117
00118 if (rt->is_input) {
00119 snprintf(ver, sizeof(ver), "%s %d,%d,%d,%d", RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1,
00120 RTMP_CLIENT_VER2, RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
00121 } else {
00122 snprintf(ver, sizeof(ver), "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
00123 ff_amf_write_field_name(&p, "type");
00124 ff_amf_write_string(&p, "nonprivate");
00125 }
00126 ff_amf_write_field_name(&p, "flashVer");
00127 ff_amf_write_string(&p, ver);
00128 ff_amf_write_field_name(&p, "tcUrl");
00129 ff_amf_write_string(&p, tcurl);
00130 if (rt->is_input) {
00131 ff_amf_write_field_name(&p, "fpad");
00132 ff_amf_write_bool(&p, 0);
00133 ff_amf_write_field_name(&p, "capabilities");
00134 ff_amf_write_number(&p, 15.0);
00135 ff_amf_write_field_name(&p, "audioCodecs");
00136 ff_amf_write_number(&p, 1639.0);
00137 ff_amf_write_field_name(&p, "videoCodecs");
00138 ff_amf_write_number(&p, 252.0);
00139 ff_amf_write_field_name(&p, "videoFunction");
00140 ff_amf_write_number(&p, 1.0);
00141 }
00142 ff_amf_write_object_end(&p);
00143
00144 pkt.data_size = p - pkt.data;
00145
00146 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
00147 ff_rtmp_packet_destroy(&pkt);
00148 }
00149
00154 static void gen_release_stream(URLContext *s, RTMPContext *rt)
00155 {
00156 RTMPPacket pkt;
00157 uint8_t *p;
00158
00159 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0,
00160 29 + strlen(rt->playpath));
00161
00162 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
00163 p = pkt.data;
00164 ff_amf_write_string(&p, "releaseStream");
00165 ff_amf_write_number(&p, 2.0);
00166 ff_amf_write_null(&p);
00167 ff_amf_write_string(&p, rt->playpath);
00168
00169 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
00170 ff_rtmp_packet_destroy(&pkt);
00171 }
00172
00177 static void gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
00178 {
00179 RTMPPacket pkt;
00180 uint8_t *p;
00181
00182 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0,
00183 25 + strlen(rt->playpath));
00184
00185 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
00186 p = pkt.data;
00187 ff_amf_write_string(&p, "FCPublish");
00188 ff_amf_write_number(&p, 3.0);
00189 ff_amf_write_null(&p);
00190 ff_amf_write_string(&p, rt->playpath);
00191
00192 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
00193 ff_rtmp_packet_destroy(&pkt);
00194 }
00195
00200 static void gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
00201 {
00202 RTMPPacket pkt;
00203 uint8_t *p;
00204
00205 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0,
00206 27 + strlen(rt->playpath));
00207
00208 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
00209 p = pkt.data;
00210 ff_amf_write_string(&p, "FCUnpublish");
00211 ff_amf_write_number(&p, 5.0);
00212 ff_amf_write_null(&p);
00213 ff_amf_write_string(&p, rt->playpath);
00214
00215 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
00216 ff_rtmp_packet_destroy(&pkt);
00217 }
00218
00223 static void gen_create_stream(URLContext *s, RTMPContext *rt)
00224 {
00225 RTMPPacket pkt;
00226 uint8_t *p;
00227
00228 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
00229 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, 25);
00230
00231 p = pkt.data;
00232 ff_amf_write_string(&p, "createStream");
00233 ff_amf_write_number(&p, rt->is_input ? 3.0 : 4.0);
00234 ff_amf_write_null(&p);
00235
00236 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
00237 ff_rtmp_packet_destroy(&pkt);
00238 }
00239
00240
00245 static void gen_delete_stream(URLContext *s, RTMPContext *rt)
00246 {
00247 RTMPPacket pkt;
00248 uint8_t *p;
00249
00250 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
00251 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, 34);
00252
00253 p = pkt.data;
00254 ff_amf_write_string(&p, "deleteStream");
00255 ff_amf_write_number(&p, 0.0);
00256 ff_amf_write_null(&p);
00257 ff_amf_write_number(&p, rt->main_channel_id);
00258
00259 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
00260 ff_rtmp_packet_destroy(&pkt);
00261 }
00262
00267 static void gen_play(URLContext *s, RTMPContext *rt)
00268 {
00269 RTMPPacket pkt;
00270 uint8_t *p;
00271
00272 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
00273 ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE, 0,
00274 20 + strlen(rt->playpath));
00275 pkt.extra = rt->main_channel_id;
00276
00277 p = pkt.data;
00278 ff_amf_write_string(&p, "play");
00279 ff_amf_write_number(&p, 0.0);
00280 ff_amf_write_null(&p);
00281 ff_amf_write_string(&p, rt->playpath);
00282
00283 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
00284 ff_rtmp_packet_destroy(&pkt);
00285
00286
00287 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, 1, 10);
00288
00289 p = pkt.data;
00290 bytestream_put_be16(&p, 3);
00291 bytestream_put_be32(&p, 1);
00292 bytestream_put_be32(&p, 256);
00293
00294 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
00295 ff_rtmp_packet_destroy(&pkt);
00296 }
00297
00301 static void gen_publish(URLContext *s, RTMPContext *rt)
00302 {
00303 RTMPPacket pkt;
00304 uint8_t *p;
00305
00306 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
00307 ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE, 0,
00308 30 + strlen(rt->playpath));
00309 pkt.extra = rt->main_channel_id;
00310
00311 p = pkt.data;
00312 ff_amf_write_string(&p, "publish");
00313 ff_amf_write_number(&p, 0.0);
00314 ff_amf_write_null(&p);
00315 ff_amf_write_string(&p, rt->playpath);
00316 ff_amf_write_string(&p, "live");
00317
00318 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
00319 ff_rtmp_packet_destroy(&pkt);
00320 }
00321
00325 static void gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
00326 {
00327 RTMPPacket pkt;
00328 uint8_t *p;
00329
00330 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, ppkt->timestamp + 1, 6);
00331 p = pkt.data;
00332 bytestream_put_be16(&p, 7);
00333 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
00334 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
00335 ff_rtmp_packet_destroy(&pkt);
00336 }
00337
00341 static void gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
00342 {
00343 RTMPPacket pkt;
00344 uint8_t *p;
00345
00346 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ, ts, 4);
00347 p = pkt.data;
00348 bytestream_put_be32(&p, rt->bytes_read);
00349 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
00350 ff_rtmp_packet_destroy(&pkt);
00351 }
00352
00353
00354 #define HMAC_IPAD_VAL 0x36
00355 #define HMAC_OPAD_VAL 0x5C
00356
00368 static void rtmp_calc_digest(const uint8_t *src, int len, int gap,
00369 const uint8_t *key, int keylen, uint8_t *dst)
00370 {
00371 struct AVSHA *sha;
00372 uint8_t hmac_buf[64+32] = {0};
00373 int i;
00374
00375 sha = av_mallocz(av_sha_size);
00376
00377 if (keylen < 64) {
00378 memcpy(hmac_buf, key, keylen);
00379 } else {
00380 av_sha_init(sha, 256);
00381 av_sha_update(sha,key, keylen);
00382 av_sha_final(sha, hmac_buf);
00383 }
00384 for (i = 0; i < 64; i++)
00385 hmac_buf[i] ^= HMAC_IPAD_VAL;
00386
00387 av_sha_init(sha, 256);
00388 av_sha_update(sha, hmac_buf, 64);
00389 if (gap <= 0) {
00390 av_sha_update(sha, src, len);
00391 } else {
00392 av_sha_update(sha, src, gap);
00393 av_sha_update(sha, src + gap + 32, len - gap - 32);
00394 }
00395 av_sha_final(sha, hmac_buf + 64);
00396
00397 for (i = 0; i < 64; i++)
00398 hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL;
00399 av_sha_init(sha, 256);
00400 av_sha_update(sha, hmac_buf, 64+32);
00401 av_sha_final(sha, dst);
00402
00403 av_free(sha);
00404 }
00405
00413 static int rtmp_handshake_imprint_with_digest(uint8_t *buf)
00414 {
00415 int i, digest_pos = 0;
00416
00417 for (i = 8; i < 12; i++)
00418 digest_pos += buf[i];
00419 digest_pos = (digest_pos % 728) + 12;
00420
00421 rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
00422 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
00423 buf + digest_pos);
00424 return digest_pos;
00425 }
00426
00434 static int rtmp_validate_digest(uint8_t *buf, int off)
00435 {
00436 int i, digest_pos = 0;
00437 uint8_t digest[32];
00438
00439 for (i = 0; i < 4; i++)
00440 digest_pos += buf[i + off];
00441 digest_pos = (digest_pos % 728) + off + 4;
00442
00443 rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
00444 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
00445 digest);
00446 if (!memcmp(digest, buf + digest_pos, 32))
00447 return digest_pos;
00448 return 0;
00449 }
00450
00457 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
00458 {
00459 AVLFG rnd;
00460 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
00461 3,
00462 0, 0, 0, 0,
00463 RTMP_CLIENT_VER1,
00464 RTMP_CLIENT_VER2,
00465 RTMP_CLIENT_VER3,
00466 RTMP_CLIENT_VER4,
00467 };
00468 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
00469 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
00470 int i;
00471 int server_pos, client_pos;
00472 uint8_t digest[32];
00473
00474 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
00475
00476 av_lfg_init(&rnd, 0xDEADC0DE);
00477
00478 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
00479 tosend[i] = av_lfg_get(&rnd) >> 24;
00480 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1);
00481
00482 ffurl_write(rt->stream, tosend, RTMP_HANDSHAKE_PACKET_SIZE + 1);
00483 i = ffurl_read_complete(rt->stream, serverdata, RTMP_HANDSHAKE_PACKET_SIZE + 1);
00484 if (i != RTMP_HANDSHAKE_PACKET_SIZE + 1) {
00485 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
00486 return -1;
00487 }
00488 i = ffurl_read_complete(rt->stream, clientdata, RTMP_HANDSHAKE_PACKET_SIZE);
00489 if (i != RTMP_HANDSHAKE_PACKET_SIZE) {
00490 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
00491 return -1;
00492 }
00493
00494 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
00495 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
00496
00497 if (rt->is_input && serverdata[5] >= 3) {
00498 server_pos = rtmp_validate_digest(serverdata + 1, 772);
00499 if (!server_pos) {
00500 server_pos = rtmp_validate_digest(serverdata + 1, 8);
00501 if (!server_pos) {
00502 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
00503 return -1;
00504 }
00505 }
00506
00507 rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
00508 rtmp_server_key, sizeof(rtmp_server_key),
00509 digest);
00510 rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE-32, 0,
00511 digest, 32,
00512 digest);
00513 if (memcmp(digest, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
00514 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
00515 return -1;
00516 }
00517
00518 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
00519 tosend[i] = av_lfg_get(&rnd) >> 24;
00520 rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
00521 rtmp_player_key, sizeof(rtmp_player_key),
00522 digest);
00523 rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
00524 digest, 32,
00525 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
00526
00527
00528 ffurl_write(rt->stream, tosend, RTMP_HANDSHAKE_PACKET_SIZE);
00529 } else {
00530 ffurl_write(rt->stream, serverdata+1, RTMP_HANDSHAKE_PACKET_SIZE);
00531 }
00532
00533 return 0;
00534 }
00535
00542 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
00543 {
00544 int i, t;
00545 const uint8_t *data_end = pkt->data + pkt->data_size;
00546
00547 #ifdef DEBUG
00548 ff_rtmp_packet_dump(s, pkt);
00549 #endif
00550
00551 switch (pkt->type) {
00552 case RTMP_PT_CHUNK_SIZE:
00553 if (pkt->data_size != 4) {
00554 av_log(s, AV_LOG_ERROR,
00555 "Chunk size change packet is not 4 bytes long (%d)\n", pkt->data_size);
00556 return -1;
00557 }
00558 if (!rt->is_input)
00559 ff_rtmp_packet_write(rt->stream, pkt, rt->chunk_size, rt->prev_pkt[1]);
00560 rt->chunk_size = AV_RB32(pkt->data);
00561 if (rt->chunk_size <= 0) {
00562 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n", rt->chunk_size);
00563 return -1;
00564 }
00565 av_log(s, AV_LOG_DEBUG, "New chunk size = %d\n", rt->chunk_size);
00566 break;
00567 case RTMP_PT_PING:
00568 t = AV_RB16(pkt->data);
00569 if (t == 6)
00570 gen_pong(s, rt, pkt);
00571 break;
00572 case RTMP_PT_CLIENT_BW:
00573 if (pkt->data_size < 4) {
00574 av_log(s, AV_LOG_ERROR,
00575 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
00576 pkt->data_size);
00577 return -1;
00578 }
00579 av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", AV_RB32(pkt->data));
00580 rt->client_report_size = AV_RB32(pkt->data) >> 1;
00581 break;
00582 case RTMP_PT_INVOKE:
00583
00584 if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
00585 uint8_t tmpstr[256];
00586
00587 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
00588 "description", tmpstr, sizeof(tmpstr)))
00589 av_log(s, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
00590 return -1;
00591 } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
00592 switch (rt->state) {
00593 case STATE_HANDSHAKED:
00594 if (!rt->is_input) {
00595 gen_release_stream(s, rt);
00596 gen_fcpublish_stream(s, rt);
00597 rt->state = STATE_RELEASING;
00598 } else {
00599 rt->state = STATE_CONNECTING;
00600 }
00601 gen_create_stream(s, rt);
00602 break;
00603 case STATE_FCPUBLISH:
00604 rt->state = STATE_CONNECTING;
00605 break;
00606 case STATE_RELEASING:
00607 rt->state = STATE_FCPUBLISH;
00608
00609
00610 if (!pkt->data[10]) {
00611 int pkt_id = (int) av_int2dbl(AV_RB64(pkt->data + 11));
00612 if (pkt_id == 4)
00613 rt->state = STATE_CONNECTING;
00614 }
00615 if (rt->state != STATE_CONNECTING)
00616 break;
00617 case STATE_CONNECTING:
00618
00619 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
00620 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
00621 } else {
00622 rt->main_channel_id = (int) av_int2dbl(AV_RB64(pkt->data + 21));
00623 }
00624 if (rt->is_input) {
00625 gen_play(s, rt);
00626 } else {
00627 gen_publish(s, rt);
00628 }
00629 rt->state = STATE_READY;
00630 break;
00631 }
00632 } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
00633 const uint8_t* ptr = pkt->data + 11;
00634 uint8_t tmpstr[256];
00635
00636 for (i = 0; i < 2; i++) {
00637 t = ff_amf_tag_size(ptr, data_end);
00638 if (t < 0)
00639 return 1;
00640 ptr += t;
00641 }
00642 t = ff_amf_get_field_value(ptr, data_end,
00643 "level", tmpstr, sizeof(tmpstr));
00644 if (!t && !strcmp(tmpstr, "error")) {
00645 if (!ff_amf_get_field_value(ptr, data_end,
00646 "description", tmpstr, sizeof(tmpstr)))
00647 av_log(s, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
00648 return -1;
00649 }
00650 t = ff_amf_get_field_value(ptr, data_end,
00651 "code", tmpstr, sizeof(tmpstr));
00652 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
00653 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
00654 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
00655 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
00656 }
00657 break;
00658 }
00659 return 0;
00660 }
00661
00673 static int get_packet(URLContext *s, int for_header)
00674 {
00675 RTMPContext *rt = s->priv_data;
00676 int ret;
00677 uint8_t *p;
00678 const uint8_t *next;
00679 uint32_t data_size;
00680 uint32_t ts, cts, pts=0;
00681
00682 if (rt->state == STATE_STOPPED)
00683 return AVERROR_EOF;
00684
00685 for (;;) {
00686 RTMPPacket rpkt = { 0 };
00687 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
00688 rt->chunk_size, rt->prev_pkt[0])) <= 0) {
00689 if (ret == 0) {
00690 return AVERROR(EAGAIN);
00691 } else {
00692 return AVERROR(EIO);
00693 }
00694 }
00695 rt->bytes_read += ret;
00696 if (rt->bytes_read > rt->last_bytes_read + rt->client_report_size) {
00697 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
00698 gen_bytes_read(s, rt, rpkt.timestamp + 1);
00699 rt->last_bytes_read = rt->bytes_read;
00700 }
00701
00702 ret = rtmp_parse_result(s, rt, &rpkt);
00703 if (ret < 0) {
00704 ff_rtmp_packet_destroy(&rpkt);
00705 return -1;
00706 }
00707 if (rt->state == STATE_STOPPED) {
00708 ff_rtmp_packet_destroy(&rpkt);
00709 return AVERROR_EOF;
00710 }
00711 if (for_header && (rt->state == STATE_PLAYING || rt->state == STATE_PUBLISHING)) {
00712 ff_rtmp_packet_destroy(&rpkt);
00713 return 0;
00714 }
00715 if (!rpkt.data_size || !rt->is_input) {
00716 ff_rtmp_packet_destroy(&rpkt);
00717 continue;
00718 }
00719 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO ||
00720 (rpkt.type == RTMP_PT_NOTIFY && !memcmp("\002\000\012onMetaData", rpkt.data, 13))) {
00721 ts = rpkt.timestamp;
00722
00723
00724 rt->flv_off = 0;
00725 rt->flv_size = rpkt.data_size + 15;
00726 rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size);
00727 bytestream_put_byte(&p, rpkt.type);
00728 bytestream_put_be24(&p, rpkt.data_size);
00729 bytestream_put_be24(&p, ts);
00730 bytestream_put_byte(&p, ts >> 24);
00731 bytestream_put_be24(&p, 0);
00732 bytestream_put_buffer(&p, rpkt.data, rpkt.data_size);
00733 bytestream_put_be32(&p, 0);
00734 ff_rtmp_packet_destroy(&rpkt);
00735 return 0;
00736 } else if (rpkt.type == RTMP_PT_METADATA) {
00737
00738 rt->flv_off = 0;
00739 rt->flv_size = rpkt.data_size;
00740 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
00741
00742 next = rpkt.data;
00743 ts = rpkt.timestamp;
00744 while (next - rpkt.data < rpkt.data_size - 11) {
00745 next++;
00746 data_size = bytestream_get_be24(&next);
00747 p=next;
00748 cts = bytestream_get_be24(&next);
00749 cts |= bytestream_get_byte(&next) << 24;
00750 if (pts==0)
00751 pts=cts;
00752 ts += cts - pts;
00753 pts = cts;
00754 bytestream_put_be24(&p, ts);
00755 bytestream_put_byte(&p, ts >> 24);
00756 next += data_size + 3 + 4;
00757 }
00758 memcpy(rt->flv_data, rpkt.data, rpkt.data_size);
00759 ff_rtmp_packet_destroy(&rpkt);
00760 return 0;
00761 }
00762 ff_rtmp_packet_destroy(&rpkt);
00763 }
00764 return 0;
00765 }
00766
00767 static int rtmp_close(URLContext *h)
00768 {
00769 RTMPContext *rt = h->priv_data;
00770
00771 if (!rt->is_input) {
00772 rt->flv_data = NULL;
00773 if (rt->out_pkt.data_size)
00774 ff_rtmp_packet_destroy(&rt->out_pkt);
00775 if (rt->state > STATE_FCPUBLISH)
00776 gen_fcunpublish_stream(h, rt);
00777 }
00778 if (rt->state > STATE_HANDSHAKED)
00779 gen_delete_stream(h, rt);
00780
00781 av_freep(&rt->flv_data);
00782 ffurl_close(rt->stream);
00783 av_free(rt);
00784 return 0;
00785 }
00786
00796 static int rtmp_open(URLContext *s, const char *uri, int flags)
00797 {
00798 RTMPContext *rt;
00799 char proto[8], hostname[256], path[1024], *fname;
00800 uint8_t buf[2048];
00801 int port;
00802 int ret;
00803
00804 rt = av_mallocz(sizeof(RTMPContext));
00805 if (!rt)
00806 return AVERROR(ENOMEM);
00807 s->priv_data = rt;
00808 rt->is_input = !(flags & AVIO_FLAG_WRITE);
00809
00810 av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
00811 path, sizeof(path), s->filename);
00812
00813 if (port < 0)
00814 port = RTMP_DEFAULT_PORT;
00815 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
00816
00817 if (ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE) < 0) {
00818 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
00819 goto fail;
00820 }
00821
00822 rt->state = STATE_START;
00823 if (rtmp_handshake(s, rt))
00824 return -1;
00825
00826 rt->chunk_size = 128;
00827 rt->state = STATE_HANDSHAKED;
00828
00829 if (!strncmp(path, "/ondemand/", 10)) {
00830 fname = path + 10;
00831 memcpy(rt->app, "ondemand", 9);
00832 } else {
00833 char *p = strchr(path + 1, '/');
00834 if (!p) {
00835 fname = path + 1;
00836 rt->app[0] = '\0';
00837 } else {
00838 char *c = strchr(p + 1, ':');
00839 fname = strchr(p + 1, '/');
00840 if (!fname || c < fname) {
00841 fname = p + 1;
00842 av_strlcpy(rt->app, path + 1, p - path);
00843 } else {
00844 fname++;
00845 av_strlcpy(rt->app, path + 1, fname - path - 1);
00846 }
00847 }
00848 }
00849 if (!strchr(fname, ':') &&
00850 (!strcmp(fname + strlen(fname) - 4, ".f4v") ||
00851 !strcmp(fname + strlen(fname) - 4, ".mp4"))) {
00852 memcpy(rt->playpath, "mp4:", 5);
00853 } else {
00854 rt->playpath[0] = 0;
00855 }
00856 strncat(rt->playpath, fname, sizeof(rt->playpath) - 5);
00857
00858 rt->client_report_size = 1048576;
00859 rt->bytes_read = 0;
00860 rt->last_bytes_read = 0;
00861
00862 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
00863 proto, path, rt->app, rt->playpath);
00864 gen_connect(s, rt, proto, hostname, port);
00865
00866 do {
00867 ret = get_packet(s, 1);
00868 } while (ret == EAGAIN);
00869 if (ret < 0)
00870 goto fail;
00871
00872 if (rt->is_input) {
00873
00874 rt->flv_size = 13;
00875 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
00876 rt->flv_off = 0;
00877 memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size);
00878 } else {
00879 rt->flv_size = 0;
00880 rt->flv_data = NULL;
00881 rt->flv_off = 0;
00882 }
00883
00884 s->max_packet_size = rt->stream->max_packet_size;
00885 s->is_streamed = 1;
00886 return 0;
00887
00888 fail:
00889 rtmp_close(s);
00890 return AVERROR(EIO);
00891 }
00892
00893 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
00894 {
00895 RTMPContext *rt = s->priv_data;
00896 int orig_size = size;
00897 int ret;
00898
00899 while (size > 0) {
00900 int data_left = rt->flv_size - rt->flv_off;
00901
00902 if (data_left >= size) {
00903 memcpy(buf, rt->flv_data + rt->flv_off, size);
00904 rt->flv_off += size;
00905 return orig_size;
00906 }
00907 if (data_left > 0) {
00908 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
00909 buf += data_left;
00910 size -= data_left;
00911 rt->flv_off = rt->flv_size;
00912 return data_left;
00913 }
00914 if ((ret = get_packet(s, 0)) < 0)
00915 return ret;
00916 }
00917 return orig_size;
00918 }
00919
00920 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
00921 {
00922 RTMPContext *rt = s->priv_data;
00923 int size_temp = size;
00924 int pktsize, pkttype;
00925 uint32_t ts;
00926 const uint8_t *buf_temp = buf;
00927
00928 if (size < 11) {
00929 av_log(s, AV_LOG_DEBUG, "FLV packet too small %d\n", size);
00930 return 0;
00931 }
00932
00933 do {
00934 if (!rt->flv_off) {
00935
00936 if (buf_temp[0] == 'F' && buf_temp[1] == 'L' && buf_temp[2] == 'V') {
00937 buf_temp += 9 + 4;
00938 size_temp -= 9 + 4;
00939 }
00940
00941 pkttype = bytestream_get_byte(&buf_temp);
00942 pktsize = bytestream_get_be24(&buf_temp);
00943 ts = bytestream_get_be24(&buf_temp);
00944 ts |= bytestream_get_byte(&buf_temp) << 24;
00945 bytestream_get_be24(&buf_temp);
00946 size_temp -= 11;
00947 rt->flv_size = pktsize;
00948
00949
00950 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
00951 pkttype == RTMP_PT_NOTIFY) {
00952 if (pkttype == RTMP_PT_NOTIFY)
00953 pktsize += 16;
00954 rt->prev_pkt[1][RTMP_SOURCE_CHANNEL].channel_id = 0;
00955 }
00956
00957
00958 ff_rtmp_packet_create(&rt->out_pkt, RTMP_SOURCE_CHANNEL, pkttype, ts, pktsize);
00959 rt->out_pkt.extra = rt->main_channel_id;
00960 rt->flv_data = rt->out_pkt.data;
00961
00962 if (pkttype == RTMP_PT_NOTIFY)
00963 ff_amf_write_string(&rt->flv_data, "@setDataFrame");
00964 }
00965
00966 if (rt->flv_size - rt->flv_off > size_temp) {
00967 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, size_temp);
00968 rt->flv_off += size_temp;
00969 } else {
00970 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, rt->flv_size - rt->flv_off);
00971 rt->flv_off += rt->flv_size - rt->flv_off;
00972 }
00973
00974 if (rt->flv_off == rt->flv_size) {
00975 bytestream_get_be32(&buf_temp);
00976
00977 ff_rtmp_packet_write(rt->stream, &rt->out_pkt, rt->chunk_size, rt->prev_pkt[1]);
00978 ff_rtmp_packet_destroy(&rt->out_pkt);
00979 rt->flv_size = 0;
00980 rt->flv_off = 0;
00981 }
00982 } while (buf_temp - buf < size_temp);
00983 return size;
00984 }
00985
00986 URLProtocol ff_rtmp_protocol = {
00987 .name = "rtmp",
00988 .url_open = rtmp_open,
00989 .url_read = rtmp_read,
00990 .url_write = rtmp_write,
00991 .url_close = rtmp_close,
00992 };