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