Libav
|
00001 /* 00002 * RTMP network protocol 00003 * Copyright (c) 2009 Kostya Shishkov 00004 * 00005 * This file is part of FFmpeg. 00006 * 00007 * FFmpeg is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * FFmpeg is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with FFmpeg; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 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 /* we can't use av_log() with URLContext yet... */ 00041 #if LIBAVFORMAT_VERSION_MAJOR < 53 00042 #define LOG_CONTEXT NULL 00043 #else 00044 #define LOG_CONTEXT s 00045 #endif 00046 00047 //#define DEBUG 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 ///< length of partial key used for first client digest signing 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 ///< length of partial key used for first server digest signing 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 // set client buffer time disguised in ping packet 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); //TODO: what is a good value here? 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 //TODO: Move HMAC code somewhere. Eventually. 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 { //skip 32 bytes used for storing digest 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; //reuse XORed key for opad 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, // unencrypted data 00468 0, 0, 0, 0, // client uptime 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 // generate handshake packet - 1536 bytes of pseudorandom data 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 // write reply back to the server 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 //TODO: check for the messages sent for wrong state? 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 /* hack for Wowza Media Server, it does not send result for 00615 * releaseStream and FCPublish calls */ 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 //extract a number from the result 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) {//serious error in current packet 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 // generate packet header and put data into buffer for FLV demuxer 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 // we got raw FLV data, make it available for FLV demuxer 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 /* rewrite timestamps */ 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 //extract "app" part from path 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 // generate FLV header for demuxer 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 //skip flv header 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 //force 12bytes header 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 //this can be a big packet, it's better to send it right here 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, /* seek */ 00997 rtmp_close, 00998 };