Libav 0.7.1
libavformat/rtmpproto.c
Go to the documentation of this file.
00001 /*
00002  * RTMP network protocol
00003  * Copyright (c) 2009 Kostya Shishkov
00004  *
00005  * This file is part of Libav.
00006  *
00007  * Libav 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  * Libav 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 Libav; 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 #include "url.h"
00040 
00041 //#define DEBUG
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   ///< length of partial key used for first client digest signing
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   ///< length of partial key used for first server digest signing
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     // set client buffer time disguised in ping packet
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); //TODO: what is a good value here?
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 //TODO: Move HMAC code somewhere. Eventually.
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 { //skip 32 bytes used for storing digest
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; //reuse XORed key for opad
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,                // unencrypted data
00462         0, 0, 0, 0,       // client uptime
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     // generate handshake packet - 1536 bytes of pseudorandom data
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         // write reply back to the server
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         //TODO: check for the messages sent for wrong state?
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                 /* hack for Wowza Media Server, it does not send result for
00609                  * releaseStream and FCPublish calls */
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                 //extract a number from the result
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) {//serious error in current packet
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             // generate packet header and put data into buffer for FLV demuxer
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             // we got raw FLV data, make it available for FLV demuxer
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             /* rewrite timestamps */
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     //extract "app" part from path
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         // generate FLV header for demuxer
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             //skip flv header
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             //force 12bytes header
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             //this can be a big packet, it's better to send it right here
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 };