[rtmpdump] r64 - hand2.c rtmp2.c rtmp2.h rtmpd2.c
hyc
subversion at mplayerhq.hu
Wed Dec 16 07:26:45 CET 2009
Author: hyc
Date: Wed Dec 16 07:26:45 2009
New Revision: 64
Log:
Re-indented, fixed up
Modified:
hand2.c
rtmp2.c
rtmp2.h
rtmpd2.c
Modified: hand2.c
==============================================================================
--- hand2.c Wed Dec 16 07:26:23 2009 (r63)
+++ hand2.c Wed Dec 16 07:26:45 2009 (r64)
@@ -27,182 +27,219 @@
#include "dh.h"
-static const char GenuineFMSKey[] =
-{
- 0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c,
- 0x61, 0x73, 0x68, 0x20, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
- 0x20, 0x30, 0x30, 0x31, // Genuine Adobe Flash Media Server 001
+static const char GenuineFMSKey[] = {
+ 0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62,
+ 0x65, 0x20, 0x46, 0x6c,
+ 0x61, 0x73, 0x68, 0x20, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x20, 0x53, 0x65,
+ 0x72, 0x76, 0x65, 0x72,
+ 0x20, 0x30, 0x30, 0x31, // Genuine Adobe Flash Media Server 001
- 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1,
- 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36,
- 0xcf, 0xeb, 0x31, 0xae
-}; // 68
+ 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1,
+ 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab,
+ 0x93, 0xb8, 0xe6, 0x36,
+ 0xcf, 0xeb, 0x31, 0xae
+}; // 68
-static const char GenuineFPKey[] =
-{
- 0x47,0x65,0x6E,0x75,0x69,0x6E,0x65,0x20,0x41,0x64,0x6F,0x62,0x65,0x20,0x46,0x6C,
- 0x61,0x73,0x68,0x20,0x50,0x6C,0x61,0x79,0x65,0x72,0x20,0x30,0x30,0x31,0xF0,0xEE,
- 0xC2,0x4A,0x80,0x68,0xBE,0xE8,0x2E,0x00,0xD0,0xD1,0x02,0x9E,0x7E,0x57,0x6E,0xEC,
- 0x5D,0x2D,0x29,0x80,0x6F,0xAB,0x93,0xB8,0xE6,0x36,0xCF,0xEB,0x31,0xAE
-}; // 62
+static const char GenuineFPKey[] = {
+ 0x47, 0x65, 0x6E, 0x75, 0x69, 0x6E, 0x65, 0x20, 0x41, 0x64, 0x6F, 0x62,
+ 0x65, 0x20, 0x46, 0x6C,
+ 0x61, 0x73, 0x68, 0x20, 0x50, 0x6C, 0x61, 0x79, 0x65, 0x72, 0x20, 0x30,
+ 0x30, 0x31, 0xF0, 0xEE,
+ 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02, 0x9E,
+ 0x7E, 0x57, 0x6E, 0xEC,
+ 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8, 0xE6, 0x36, 0xCF, 0xEB,
+ 0x31, 0xAE
+}; // 62
static void InitRC4Encryption
-(
- uint8_t *secretKey,
- uint8_t *pubKeyIn,
- uint8_t *pubKeyOut,
- RC4_KEY **rc4keyIn,
- RC4_KEY **rc4keyOut
-)
+ (uint8_t * secretKey,
+ uint8_t * pubKeyIn,
+ uint8_t * pubKeyOut, RC4_KEY ** rc4keyIn, RC4_KEY ** rc4keyOut)
{
- uint8_t digest[SHA256_DIGEST_LENGTH];
- unsigned int digestLen = 0;
+ uint8_t digest[SHA256_DIGEST_LENGTH];
+ unsigned int digestLen = 0;
- *rc4keyIn = malloc(sizeof(RC4_KEY));
- *rc4keyOut = malloc(sizeof(RC4_KEY));
+ *rc4keyIn = malloc(sizeof(RC4_KEY));
+ *rc4keyOut = malloc(sizeof(RC4_KEY));
- HMAC_CTX ctx;
- HMAC_CTX_init(&ctx);
- HMAC_Init_ex(&ctx, secretKey, 128, EVP_sha256(), 0);
- HMAC_Update(&ctx, pubKeyIn, 128);
- HMAC_Final(&ctx, digest, &digestLen);
- HMAC_CTX_cleanup(&ctx);
+ HMAC_CTX ctx;
+ HMAC_CTX_init(&ctx);
+ HMAC_Init_ex(&ctx, secretKey, 128, EVP_sha256(), 0);
+ HMAC_Update(&ctx, pubKeyIn, 128);
+ HMAC_Final(&ctx, digest, &digestLen);
+ HMAC_CTX_cleanup(&ctx);
- Log(LOGDEBUG, "RC4 Out Key: ");
- LogHex(LOGDEBUG, (char*)digest, 16);
+ Log(LOGDEBUG, "RC4 Out Key: ");
+ LogHex(LOGDEBUG, (char *) digest, 16);
- RC4_set_key(*rc4keyOut, 16, digest);
+ RC4_set_key(*rc4keyOut, 16, digest);
- HMAC_CTX_init(&ctx);
- HMAC_Init_ex(&ctx, secretKey, 128, EVP_sha256(), 0);
- HMAC_Update(&ctx, pubKeyOut, 128);
- HMAC_Final(&ctx, digest, &digestLen);
- HMAC_CTX_cleanup(&ctx);
+ HMAC_CTX_init(&ctx);
+ HMAC_Init_ex(&ctx, secretKey, 128, EVP_sha256(), 0);
+ HMAC_Update(&ctx, pubKeyOut, 128);
+ HMAC_Final(&ctx, digest, &digestLen);
+ HMAC_CTX_cleanup(&ctx);
- Log(LOGDEBUG, "RC4 In Key: ");
- LogHex(LOGDEBUG, (char*)digest, 16);
-
- RC4_set_key(*rc4keyIn, 16, digest);
+ Log(LOGDEBUG, "RC4 In Key: ");
+ LogHex(LOGDEBUG, (char *) digest, 16);
+
+ RC4_set_key(*rc4keyIn, 16, digest);
}
-static unsigned int GetDHOffset2(char *handshake, unsigned int len)
+static unsigned int
+GetDHOffset2(char *handshake, unsigned int len)
{
- unsigned int offset = 0;
- unsigned char *ptr = (unsigned char *)handshake + 768;
+ unsigned int offset = 0;
+ unsigned char *ptr = (unsigned char *) handshake + 768;
- assert(RTMP_SIG_SIZE <= len);
+ assert(RTMP_SIG_SIZE <= len);
- offset += (*ptr); ptr++;
- offset += (*ptr); ptr++;
- offset += (*ptr); ptr++;
- offset += (*ptr);
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
- unsigned int res = (offset % 632) + 8;
+ unsigned int res = (offset % 632) + 8;
- if(res + 128 > 767) {
- Log(LOGERROR, "%s: Couldn't calculate correct DH offset (got %d), exiting!\n", __FUNCTION__, res);
- exit(1);
- }
- return res;
+ if (res + 128 > 767)
+ {
+ Log(LOGERROR,
+ "%s: Couldn't calculate correct DH offset (got %d), exiting!\n",
+ __FUNCTION__, res);
+ exit(1);
+ }
+ return res;
}
-static unsigned int GetDigestOffset2(char *handshake, unsigned int len)
+static unsigned int
+GetDigestOffset2(char *handshake, unsigned int len)
{
- unsigned int offset = 0;
- unsigned char *ptr = (unsigned char *)handshake + 772;
+ unsigned int offset = 0;
+ unsigned char *ptr = (unsigned char *) handshake + 772;
- //assert(12 <= len);
+ //assert(12 <= len);
- offset += (*ptr); ptr++;
- offset += (*ptr); ptr++;
- offset += (*ptr); ptr++;
- offset += (*ptr);
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
- unsigned int res = (offset % 728) + 776;
+ unsigned int res = (offset % 728) + 776;
- if(res+32 > 1535) {
- Log(LOGERROR, "%s: Couldn't calculate correct digest offset (got %d), exiting\n", __FUNCTION__, res);
- exit(1);
- }
- return res;
+ if (res + 32 > 1535)
+ {
+ Log(LOGERROR,
+ "%s: Couldn't calculate correct digest offset (got %d), exiting\n",
+ __FUNCTION__, res);
+ exit(1);
+ }
+ return res;
}
-static unsigned int GetDHOffset1(char *handshake, unsigned int len)
+static unsigned int
+GetDHOffset1(char *handshake, unsigned int len)
{
- unsigned int offset = 0;
- unsigned char *ptr = (unsigned char *)handshake + 1532;
+ unsigned int offset = 0;
+ unsigned char *ptr = (unsigned char *) handshake + 1532;
- assert(RTMP_SIG_SIZE <= len);
+ assert(RTMP_SIG_SIZE <= len);
- offset += (*ptr); ptr++;
- offset += (*ptr); ptr++;
- offset += (*ptr); ptr++;
- offset += (*ptr);
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
- unsigned int res = (offset % 632) + 772;
+ unsigned int res = (offset % 632) + 772;
- if(res+128 > 1531) {
- Log(LOGERROR, "%s: Couldn't calculate DH offset (got %d), exiting!\n", __FUNCTION__, res);
- exit(1);
- }
+ if (res + 128 > 1531)
+ {
+ Log(LOGERROR, "%s: Couldn't calculate DH offset (got %d), exiting!\n",
+ __FUNCTION__, res);
+ exit(1);
+ }
- return res;
+ return res;
}
-static unsigned int GetDigestOffset1(char *handshake, unsigned int len)
+static unsigned int
+GetDigestOffset1(char *handshake, unsigned int len)
{
- unsigned int offset = 0;
- unsigned char *ptr = (unsigned char *)handshake + 8;
+ unsigned int offset = 0;
+ unsigned char *ptr = (unsigned char *) handshake + 8;
- assert(12 <= len);
+ assert(12 <= len);
- offset += (*ptr); ptr++;
- offset += (*ptr); ptr++;
- offset += (*ptr); ptr++;
- offset += (*ptr);
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
+ ptr++;
+ offset += (*ptr);
- unsigned int res = (offset % 728) + 12;
+ unsigned int res = (offset % 728) + 12;
- if(res+32 > 771) {
- Log(LOGDEBUG, "%s: Couldn't calculate digest offset (got %d), exiting!\n", __FUNCTION__, res);
- exit(1);
- }
+ if (res + 32 > 771)
+ {
+ Log(LOGDEBUG,
+ "%s: Couldn't calculate digest offset (got %d), exiting!\n",
+ __FUNCTION__, res);
+ exit(1);
+ }
- return res;
+ return res;
}
-static void HMACsha256(const char *message, size_t messageLen, const char *key, size_t keylen, char *digest)
+static void
+HMACsha256(const char *message, size_t messageLen, const char *key,
+ size_t keylen, char *digest)
{
- unsigned int digestLen;
+ unsigned int digestLen;
- HMAC_CTX ctx;
- HMAC_CTX_init(&ctx);
- HMAC_Init_ex(&ctx, (unsigned char*)key, keylen, EVP_sha256(), NULL);
- HMAC_Update(&ctx, (unsigned char *)message, messageLen);
- HMAC_Final(&ctx, (unsigned char *)digest, &digestLen);
- HMAC_CTX_cleanup(&ctx);
+ HMAC_CTX ctx;
+ HMAC_CTX_init(&ctx);
+ HMAC_Init_ex(&ctx, (unsigned char *) key, keylen, EVP_sha256(), NULL);
+ HMAC_Update(&ctx, (unsigned char *) message, messageLen);
+ HMAC_Final(&ctx, (unsigned char *) digest, &digestLen);
+ HMAC_CTX_cleanup(&ctx);
- assert(digestLen == 32);
+ assert(digestLen == 32);
}
-static void CalculateDigest(unsigned int digestPos, char *handshakeMessage, const char *key, size_t keyLen, char *digest)
+static void
+CalculateDigest(unsigned int digestPos, char *handshakeMessage,
+ const char *key, size_t keyLen, char *digest)
{
- const int messageLen = RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH;
- char message[messageLen];
+ const int messageLen = RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH;
+ char message[messageLen];
- memcpy(message, handshakeMessage, digestPos);
- memcpy(message+digestPos, &handshakeMessage[digestPos+SHA256_DIGEST_LENGTH], messageLen-digestPos);
+ memcpy(message, handshakeMessage, digestPos);
+ memcpy(message + digestPos,
+ &handshakeMessage[digestPos + SHA256_DIGEST_LENGTH],
+ messageLen - digestPos);
- HMACsha256(message, messageLen, key, keyLen, digest);
+ HMACsha256(message, messageLen, key, keyLen, digest);
}
-static bool VerifyDigest(unsigned int digestPos, char *handshakeMessage, const char *key, size_t keyLen)
+static bool
+VerifyDigest(unsigned int digestPos, char *handshakeMessage, const char *key,
+ size_t keyLen)
{
- char calcDigest[SHA256_DIGEST_LENGTH];
+ char calcDigest[SHA256_DIGEST_LENGTH];
- CalculateDigest(digestPos, handshakeMessage, key, keyLen, calcDigest);
+ CalculateDigest(digestPos, handshakeMessage, key, keyLen, calcDigest);
- return memcmp(&handshakeMessage[digestPos], calcDigest, SHA256_DIGEST_LENGTH)==0;
+ return memcmp(&handshakeMessage[digestPos], calcDigest,
+ SHA256_DIGEST_LENGTH) == 0;
}
/* handshake
@@ -215,326 +252,386 @@ static bool VerifyDigest(unsigned int di
*
*/
-static bool HandShake(RTMP *r, bool FP9HandShake)
+static bool
+HandShake(RTMP * r, bool FP9HandShake)
{
- int i;
- bool encrypted = r->Link.protocol == RTMP_PROTOCOL_RTMPE || r->Link.protocol == RTMP_PROTOCOL_RTMPTE;
+ int i;
+ bool encrypted = r->Link.protocol == RTMP_PROTOCOL_RTMPE
+ || r->Link.protocol == RTMP_PROTOCOL_RTMPTE;
- char clientsig[RTMP_SIG_SIZE+1];
- char serversig[RTMP_SIG_SIZE];
+ char clientsig[RTMP_SIG_SIZE + 1];
+ char serversig[RTMP_SIG_SIZE];
- if (encrypted || r->Link.SWFHash.av_len)
- FP9HandShake = true;
- else
- FP9HandShake = false;
+ if (encrypted || r->Link.SWFHash.av_len)
+ FP9HandShake = true;
+ else
+ FP9HandShake = false;
- memset(clientsig, 0, RTMP_SIG_SIZE+1);
+ memset(clientsig, 0, RTMP_SIG_SIZE + 1);
- r->Link.rc4keyIn = r->Link.rc4keyOut = 0;
+ r->Link.rc4keyIn = r->Link.rc4keyOut = 0;
- if(encrypted)
- clientsig[0] = 0x06; // 0x08 is RTMPE as well
- else
- clientsig[0] = 0x03;
+ if (encrypted)
+ clientsig[0] = 0x06; // 0x08 is RTMPE as well
+ else
+ clientsig[0] = 0x03;
#if 0
- uint32_t uptime = htonl(GetTime());
- memcpy(clientsig + 1, &uptime, 4);
+ uint32_t uptime = htonl(GetTime());
+ memcpy(clientsig + 1, &uptime, 4);
#else
- clientsig[1] = 0;
- clientsig[2] = 0;
- clientsig[3] = 0;
- clientsig[4] = 0;
+ clientsig[1] = 0;
+ clientsig[2] = 0;
+ clientsig[3] = 0;
+ clientsig[4] = 0;
#endif
- if(FP9HandShake) {
- // set version to at least 9.0.115.0
- clientsig[5] = 9;
- clientsig[6] = 0;
- clientsig[7] = 124;
- clientsig[8] = 2;
+ if (FP9HandShake)
+ {
+ // set version to at least 9.0.115.0
+ clientsig[5] = 9;
+ clientsig[6] = 0;
+ clientsig[7] = 124;
+ clientsig[8] = 2;
- Log(LOGDEBUG, "%s: Client type: %02X\n", __FUNCTION__, clientsig[0]);
+ Log(LOGDEBUG, "%s: Client type: %02X\n", __FUNCTION__, clientsig[0]);
- //clientsig[0] = 0x08;
+ //clientsig[0] = 0x08;
- /*clientsig[1] = 0x00;
- clientsig[2] = 0x00;
- clientsig[3] = 0x04;
- clientsig[4] = 0x60;
-
- clientsig[5] = 128;
- clientsig[6] = 0;
- clientsig[7] = 1;
- clientsig[8] = 2;
- clientsig[9] = 0xBE;
- clientsig[10] = 0xF6;
+ /*clientsig[1] = 0x00;
+ clientsig[2] = 0x00;
+ clientsig[3] = 0x04;
+ clientsig[4] = 0x60;
- //*/
- } else {
- memset(&clientsig[5], 0, 4);
- }
+ clientsig[5] = 128;
+ clientsig[6] = 0;
+ clientsig[7] = 1;
+ clientsig[8] = 2;
+ clientsig[9] = 0xBE;
+ clientsig[10] = 0xF6;
- // generate random data
+ // */
+ }
+ else
+ {
+ memset(&clientsig[5], 0, 4);
+ }
+
+ // generate random data
#ifdef _DEBUG
- for(i=9; i<=RTMP_SIG_SIZE; i++)
- clientsig[i] = 0;//(char)(rand() % 256);//0xff;
+ for (i = 9; i <= RTMP_SIG_SIZE; i++)
+ clientsig[i] = 0; //(char)(rand() % 256);//0xff;
#else
- for(i=9; i<=RTMP_SIG_SIZE; i++)
- clientsig[i] = (char)(rand() % 256);
+ for (i = 9; i <= RTMP_SIG_SIZE; i++)
+ clientsig[i] = (char) (rand() % 256);
#endif
- int dhposClient = 0;
- RC4_KEY *keyIn = 0;
- RC4_KEY *keyOut = 0;
-
- if(encrypted) {
- // generate Diffie-Hellmann parameters
- r->Link.dh = DHInit(1024);
- if(!r->Link.dh) {
- Log(LOGERROR, "%s: Couldn't initialize Diffie-Hellmann!", __FUNCTION__);
- return false;
- }
+ int dhposClient = 0;
+ RC4_KEY *keyIn = 0;
+ RC4_KEY *keyOut = 0;
- dhposClient = GetDHOffset1(&clientsig[1], RTMP_SIG_SIZE);
- Log(LOGDEBUG, "%s: DH pubkey position: %d", __FUNCTION__, dhposClient);
+ if (encrypted)
+ {
+ // generate Diffie-Hellmann parameters
+ r->Link.dh = DHInit(1024);
+ if (!r->Link.dh)
+ {
+ Log(LOGERROR, "%s: Couldn't initialize Diffie-Hellmann!",
+ __FUNCTION__);
+ return false;
+ }
- if(!DHGenerateKey(r->Link.dh)) {
- Log(LOGERROR, "%s: Couldn't generate Diffie-Hellmann public key!", __FUNCTION__);
- return false;
- }
+ dhposClient = GetDHOffset1(&clientsig[1], RTMP_SIG_SIZE);
+ Log(LOGDEBUG, "%s: DH pubkey position: %d", __FUNCTION__, dhposClient);
- if(!DHGetPublicKey(r->Link.dh, (uint8_t*)&clientsig[1+dhposClient], 128)) {
- Log(LOGERROR, "%s: Couldn't write public key!", __FUNCTION__);
- return false;
- }
+ if (!DHGenerateKey(r->Link.dh))
+ {
+ Log(LOGERROR, "%s: Couldn't generate Diffie-Hellmann public key!",
+ __FUNCTION__);
+ return false;
}
- // set handshake digest
- if(FP9HandShake)
+ if (!DHGetPublicKey
+ (r->Link.dh, (uint8_t *) & clientsig[1 + dhposClient], 128))
{
- int digestPosClient = GetDigestOffset1(clientsig+1, RTMP_SIG_SIZE); // maybe reuse this value in verification
- Log(LOGDEBUG, "%s: Client digest offset: %d", __FUNCTION__, digestPosClient);
-
- CalculateDigest(digestPosClient, clientsig+1, GenuineFPKey, 30, &clientsig[1+digestPosClient]);
-
- Log(LOGDEBUG, "%s: Initial client digest: ", __FUNCTION__);
- LogHex(LOGDEBUG, (char *)clientsig+1+digestPosClient, SHA256_DIGEST_LENGTH);
+ Log(LOGERROR, "%s: Couldn't write public key!", __FUNCTION__);
+ return false;
}
+ }
+
+ // set handshake digest
+ if (FP9HandShake)
+ {
+ int digestPosClient = GetDigestOffset1(clientsig + 1, RTMP_SIG_SIZE); // maybe reuse this value in verification
+ Log(LOGDEBUG, "%s: Client digest offset: %d", __FUNCTION__,
+ digestPosClient);
+
+ CalculateDigest(digestPosClient, clientsig + 1, GenuineFPKey, 30,
+ &clientsig[1 + digestPosClient]);
+
+ Log(LOGDEBUG, "%s: Initial client digest: ", __FUNCTION__);
+ LogHex(LOGDEBUG, (char *) clientsig + 1 + digestPosClient,
+ SHA256_DIGEST_LENGTH);
+ }
#ifdef _DEBUG
- Log(LOGDEBUG, "Clientsig: ");
- LogHex(LOGDEBUG, &clientsig[1], RTMP_SIG_SIZE);
+ Log(LOGDEBUG, "Clientsig: ");
+ LogHex(LOGDEBUG, &clientsig[1], RTMP_SIG_SIZE);
#endif
- if(!WriteN(r, clientsig, RTMP_SIG_SIZE + 1))
- return false;
+ if (!WriteN(r, clientsig, RTMP_SIG_SIZE + 1))
+ return false;
- char type;
- if(ReadN(r, &type, 1) != 1) // 0x03 or 0x06
- return false;
+ char type;
+ if (ReadN(r, &type, 1) != 1) // 0x03 or 0x06
+ return false;
- Log(LOGDEBUG, "%s: Type Answer : %02X", __FUNCTION__, type);
+ Log(LOGDEBUG, "%s: Type Answer : %02X", __FUNCTION__, type);
- if(type != clientsig[0])
- Log(LOGWARNING, "%s: Type mismatch: client sent %d, server answered %d", __FUNCTION__, clientsig[0], type);
+ if (type != clientsig[0])
+ Log(LOGWARNING, "%s: Type mismatch: client sent %d, server answered %d",
+ __FUNCTION__, clientsig[0], type);
- if(ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
- return false;
+ if (ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
+ return false;
- // decode server response
- uint32_t suptime;
+ // decode server response
+ uint32_t suptime;
- memcpy(&suptime, serversig, 4);
- suptime = ntohl(suptime);
+ memcpy(&suptime, serversig, 4);
+ suptime = ntohl(suptime);
- Log(LOGDEBUG, "%s: Server Uptime : %d", __FUNCTION__, suptime);
- Log(LOGDEBUG, "%s: FMS Version : %d.%d.%d.%d", __FUNCTION__, serversig[4], serversig[5], serversig[6], serversig[7]);
+ Log(LOGDEBUG, "%s: Server Uptime : %d", __FUNCTION__, suptime);
+ Log(LOGDEBUG, "%s: FMS Version : %d.%d.%d.%d", __FUNCTION__, serversig[4],
+ serversig[5], serversig[6], serversig[7]);
#ifdef _DEBUG
- Log(LOGDEBUG,"Server signature:");
- LogHex(LOGDEBUG, serversig, RTMP_SIG_SIZE);
+ Log(LOGDEBUG, "Server signature:");
+ LogHex(LOGDEBUG, serversig, RTMP_SIG_SIZE);
#endif
- if(!FP9HandShake) {
- if(!WriteN(r, serversig, RTMP_SIG_SIZE))
- return false;
+ if (!FP9HandShake)
+ {
+ if (!WriteN(r, serversig, RTMP_SIG_SIZE))
+ return false;
+ }
+ // we have to use this signature now to find the correct algorithms for getting the digest and DH positions
+ int digestPosServer = GetDigestOffset2(serversig, RTMP_SIG_SIZE);
+ int dhposServer = GetDHOffset2(serversig, RTMP_SIG_SIZE);
+
+ if (FP9HandShake
+ && !VerifyDigest(digestPosServer, serversig, GenuineFMSKey, 36))
+ {
+ Log(LOGWARNING, "Trying different position for server digest!\n");
+ digestPosServer = GetDigestOffset1(serversig, RTMP_SIG_SIZE);
+ dhposServer = GetDHOffset1(serversig, RTMP_SIG_SIZE);
+
+ if (!VerifyDigest(digestPosServer, serversig, GenuineFMSKey, 36))
+ {
+ Log(LOGERROR, "Couldn't verify the server digest\n"); //, continuing anyway, will probably fail!\n");
+ return false;
}
- // we have to use this signature now to find the correct algorithms for getting the digest and DH positions
- int digestPosServer = GetDigestOffset2(serversig, RTMP_SIG_SIZE);
- int dhposServer = GetDHOffset2(serversig, RTMP_SIG_SIZE);
+ }
- if(FP9HandShake && !VerifyDigest(digestPosServer, serversig, GenuineFMSKey, 36)) {
- Log(LOGWARNING, "Trying different position for server digest!\n");
- digestPosServer = GetDigestOffset1(serversig, RTMP_SIG_SIZE);
- dhposServer = GetDHOffset1(serversig, RTMP_SIG_SIZE);
+ Log(LOGDEBUG, "%s: Server DH public key offset: %d", __FUNCTION__,
+ dhposServer);
- if(!VerifyDigest(digestPosServer, serversig, GenuineFMSKey, 36)) {
- Log(LOGERROR, "Couldn't verify the server digest\n");//, continuing anyway, will probably fail!\n");
- return false;
- }
- }
+ // generate SWFVerification token (SHA256 HMAC hash of decompressed SWF, key are the last 32 bytes of the server handshake)
+ if (r->Link.SWFHash.av_len)
+ {
+ const char swfVerify[] = { 0x01, 0x01 };
- Log(LOGDEBUG, "%s: Server DH public key offset: %d", __FUNCTION__, dhposServer);
+ memcpy(r->Link.SWFVerificationResponse, swfVerify, 2);
+ AMF_EncodeInt32(&r->Link.SWFVerificationResponse[2], r->Link.SWFSize);
+ AMF_EncodeInt32(&r->Link.SWFVerificationResponse[6], r->Link.SWFSize);
+ HMACsha256(r->Link.SWFHash.av_val, SHA256_DIGEST_LENGTH,
+ &serversig[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH],
+ SHA256_DIGEST_LENGTH, &r->Link.SWFVerificationResponse[10]);
+ }
- // generate SWFVerification token (SHA256 HMAC hash of decompressed SWF, key are the last 32 bytes of the server handshake)
- if(r->Link.SWFHash.av_len) {
- const char swfVerify[] = {0x01,0x01};
+ // do Diffie-Hellmann Key exchange for encrypted RTMP
+ if (encrypted)
+ {
+ // compute secret key
+ uint8_t secretKey[128] = { 0 };
- memcpy(r->Link.SWFVerificationResponse, swfVerify, 2);
- AMF_EncodeInt32(&r->Link.SWFVerificationResponse[2], r->Link.SWFSize);
- AMF_EncodeInt32(&r->Link.SWFVerificationResponse[6], r->Link.SWFSize);
- HMACsha256(r->Link.SWFHash.av_val, SHA256_DIGEST_LENGTH, &serversig[RTMP_SIG_SIZE-SHA256_DIGEST_LENGTH], SHA256_DIGEST_LENGTH, &r->Link.SWFVerificationResponse[10]);
+ //Log(LOGDEBUG, "Expecting secure key at %d\nKeys at ", dhposServer);
+ //int i;
+ //int len=0;
+ int len =
+ DHComputeSharedSecretKey(r->Link.dh,
+ (uint8_t *) & serversig[dhposServer], 128,
+ secretKey);
+ if (len < 0)
+ {
+ Log(LOGDEBUG, "%s: Wrong secret key position!", __FUNCTION__);
+ return false;
}
- // do Diffie-Hellmann Key exchange for encrypted RTMP
- if(encrypted) {
- // compute secret key
- uint8_t secretKey[128] = {0};
-
- //Log(LOGDEBUG, "Expecting secure key at %d\nKeys at ", dhposServer);
- //int i;
- //int len=0;
- int len = DHComputeSharedSecretKey(r->Link.dh, (uint8_t *)&serversig[dhposServer], 128, secretKey);
- if(len < 0) {
- Log(LOGDEBUG, "%s: Wrong secret key position!", __FUNCTION__);
- return false;
- }
+ /*
+ printf("sigpos: %d\n", sigpos);
+ for(i=8; i<1535-128; i++) {
+ if(i+128 < sigpos || i > sigpos+SHA256_DIGEST_LENGTH) {
+ int len1 = DHComputeSharedSecretKey(Link.dh, (uint8_t *)&serversig[i], 128, secretKey);
+ if(len1 > 0) {
+ LogPrintf("%d,", i);
+ //LogHex((char *)&serversig[i], 128);
+ }
+ }
+ }
+ LogPrintf("\n");// */
- /*
- printf("sigpos: %d\n", sigpos);
- for(i=8; i<1535-128; i++) {
- if(i+128 < sigpos || i > sigpos+SHA256_DIGEST_LENGTH) {
- int len1 = DHComputeSharedSecretKey(Link.dh, (uint8_t *)&serversig[i], 128, secretKey);
- if(len1 > 0) {
- LogPrintf("%d,", i);
- //LogHex((char *)&serversig[i], 128);
- }
- }
- }
- LogPrintf("\n");//*/
+ if (len < 0)
+ {
+ Log(LOGERROR,
+ "%s: Couldn't compute secret key, the public key is probably insecure (FMS change?)\n",
+ __FUNCTION__);
+ exit(1);
+ return false;
+ }
- if(len < 0) {
- Log(LOGERROR, "%s: Couldn't compute secret key, the public key is probably insecure (FMS change?)\n", __FUNCTION__);
- exit(1);
- return false;
- }
+ Log(LOGDEBUG, "%s: Secret key: ", __FUNCTION__);
+ LogHex(LOGDEBUG, (char *) secretKey, 128);
- Log(LOGDEBUG, "%s: Secret key: ", __FUNCTION__);
- LogHex(LOGDEBUG, (char *)secretKey, 128);
-
- InitRC4Encryption(
- secretKey,
- (uint8_t*)&serversig[dhposServer],
- (uint8_t*)&clientsig[1+dhposClient],
- &keyIn,
- &keyOut);
+ InitRC4Encryption(secretKey,
+ (uint8_t *) & serversig[dhposServer],
+ (uint8_t *) & clientsig[1 + dhposClient],
+ &keyIn, &keyOut);
- // well here is another interesting key, lets see what it is for!
- //HMACsha256(serversig, RTMP_SIG_SIZE, (char *)secretKey, 128, initialKey);
- //Log(LOGDEBUG, "%s: Calculated initial key:", __FUNCTION__);
- //LogHex(initialKey, SHA256_DIGEST_LENGTH);
- }
+ // well here is another interesting key, lets see what it is for!
+ //HMACsha256(serversig, RTMP_SIG_SIZE, (char *)secretKey, 128, initialKey);
+ //Log(LOGDEBUG, "%s: Calculated initial key:", __FUNCTION__);
+ //LogHex(initialKey, SHA256_DIGEST_LENGTH);
+ }
- // 2nd part of handshake
- char resp[RTMP_SIG_SIZE];
- if(ReadN(r, resp, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
- return false;
+ // 2nd part of handshake
+ char resp[RTMP_SIG_SIZE];
+ if (ReadN(r, resp, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
+ return false;
- #ifdef _DEBUG
- Log(LOGDEBUG, "%s: 2nd handshake: ", __FUNCTION__);
- LogHex(LOGDEBUG, resp, RTMP_SIG_SIZE);
- #endif
+#ifdef _DEBUG
+ Log(LOGDEBUG, "%s: 2nd handshake: ", __FUNCTION__);
+ LogHex(LOGDEBUG, resp, RTMP_SIG_SIZE);
+#endif
- if(FP9HandShake && resp[4] == 0 && resp[5] == 0 && resp[6] == 0 && resp[7] == 0) {
- Log(LOGDEBUG, "%s: Wait, did the server just refuse signed authetication?", __FUNCTION__);
+ if (FP9HandShake && resp[4] == 0 && resp[5] == 0 && resp[6] == 0
+ && resp[7] == 0)
+ {
+ Log(LOGDEBUG,
+ "%s: Wait, did the server just refuse signed authetication?",
+ __FUNCTION__);
+ }
+
+ if (!FP9HandShake)
+ {
+ if (memcmp(resp, clientsig + 1, RTMP_SIG_SIZE) != 0)
+ {
+ Log(LOGWARNING, "%s: client signature does not match!",
+ __FUNCTION__);
}
+ }
+ else
+ {
+ // verify server response
+ int digestPosClient = GetDigestOffset1(clientsig + 1, RTMP_SIG_SIZE);
- if(!FP9HandShake) {
- if(memcmp(resp, clientsig + 1, RTMP_SIG_SIZE) != 0) {
- Log(LOGWARNING, "%s: client signature does not match!", __FUNCTION__);
- }
- } else {
- // verify server response
- int digestPosClient = GetDigestOffset1(clientsig+1, RTMP_SIG_SIZE);
-
- char signature[SHA256_DIGEST_LENGTH];
- char digest[SHA256_DIGEST_LENGTH];
+ char signature[SHA256_DIGEST_LENGTH];
+ char digest[SHA256_DIGEST_LENGTH];
- Log(LOGDEBUG, "%s: Client signature digest position: %d", __FUNCTION__, digestPosClient);
+ Log(LOGDEBUG, "%s: Client signature digest position: %d", __FUNCTION__,
+ digestPosClient);
- HMACsha256(&clientsig[1+digestPosClient], SHA256_DIGEST_LENGTH, GenuineFMSKey, sizeof(GenuineFMSKey), digest);
- HMACsha256(resp, RTMP_SIG_SIZE-SHA256_DIGEST_LENGTH, digest, SHA256_DIGEST_LENGTH, signature);
+ HMACsha256(&clientsig[1 + digestPosClient], SHA256_DIGEST_LENGTH,
+ GenuineFMSKey, sizeof(GenuineFMSKey), digest);
+ HMACsha256(resp, RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH, digest,
+ SHA256_DIGEST_LENGTH, signature);
- // show some information
- Log(LOGDEBUG, "%s: Digest key: ", __FUNCTION__);
- LogHex(LOGDEBUG, digest, SHA256_DIGEST_LENGTH);
+ // show some information
+ Log(LOGDEBUG, "%s: Digest key: ", __FUNCTION__);
+ LogHex(LOGDEBUG, digest, SHA256_DIGEST_LENGTH);
- Log(LOGDEBUG, "%s: Signature calculated:", __FUNCTION__);
- LogHex(LOGDEBUG, signature, SHA256_DIGEST_LENGTH);
+ Log(LOGDEBUG, "%s: Signature calculated:", __FUNCTION__);
+ LogHex(LOGDEBUG, signature, SHA256_DIGEST_LENGTH);
- Log(LOGDEBUG, "%s: Server sent signature:", __FUNCTION__);
- LogHex(LOGDEBUG, &resp[RTMP_SIG_SIZE-SHA256_DIGEST_LENGTH], SHA256_DIGEST_LENGTH);
+ Log(LOGDEBUG, "%s: Server sent signature:", __FUNCTION__);
+ LogHex(LOGDEBUG, &resp[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH],
+ SHA256_DIGEST_LENGTH);
- if(memcmp(signature, &resp[RTMP_SIG_SIZE-SHA256_DIGEST_LENGTH], SHA256_DIGEST_LENGTH) != 0) {
- Log(LOGWARNING, "%s: Server not genuine Adobe!", __FUNCTION__);
- return false;
- } else {
- Log(LOGDEBUG, "%s: Genuine Adobe Flash Media Server", __FUNCTION__);
- }
-
- // generate signed answer
- char clientResp[RTMP_SIG_SIZE];
+ if (memcmp
+ (signature, &resp[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH],
+ SHA256_DIGEST_LENGTH) != 0)
+ {
+ Log(LOGWARNING, "%s: Server not genuine Adobe!", __FUNCTION__);
+ return false;
+ }
+ else
+ {
+ Log(LOGDEBUG, "%s: Genuine Adobe Flash Media Server", __FUNCTION__);
+ }
+
+ // generate signed answer
+ char clientResp[RTMP_SIG_SIZE];
#ifdef _DEBUG
- for(i=0; i<RTMP_SIG_SIZE; i++)
- clientResp[i] = 0;//(char)(rand() % 256);//0xff;
+ for (i = 0; i < RTMP_SIG_SIZE; i++)
+ clientResp[i] = 0; //(char)(rand() % 256);//0xff;
#else
- for(i=0; i<RTMP_SIG_SIZE; i++)
- clientResp[i] = (char)(rand() % 256);
+ for (i = 0; i < RTMP_SIG_SIZE; i++)
+ clientResp[i] = (char) (rand() % 256);
#endif
- // calculate response now
- char signatureResp[SHA256_DIGEST_LENGTH];
- char digestResp[SHA256_DIGEST_LENGTH];
+ // calculate response now
+ char signatureResp[SHA256_DIGEST_LENGTH];
+ char digestResp[SHA256_DIGEST_LENGTH];
- HMACsha256(&serversig[digestPosServer], SHA256_DIGEST_LENGTH, GenuineFPKey, sizeof(GenuineFPKey), digestResp);
- HMACsha256(clientResp, RTMP_SIG_SIZE-SHA256_DIGEST_LENGTH, digestResp, SHA256_DIGEST_LENGTH, signatureResp);
+ HMACsha256(&serversig[digestPosServer], SHA256_DIGEST_LENGTH,
+ GenuineFPKey, sizeof(GenuineFPKey), digestResp);
+ HMACsha256(clientResp, RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH, digestResp,
+ SHA256_DIGEST_LENGTH, signatureResp);
- // some info output
- Log(LOGDEBUG, "%s: Calculated digest key from secure key and server digest: ", __FUNCTION__);
- LogHex(LOGDEBUG, digestResp, SHA256_DIGEST_LENGTH);
+ // some info output
+ Log(LOGDEBUG,
+ "%s: Calculated digest key from secure key and server digest: ",
+ __FUNCTION__);
+ LogHex(LOGDEBUG, digestResp, SHA256_DIGEST_LENGTH);
- Log(LOGDEBUG, "%s: Client signature calculated:", __FUNCTION__);
- LogHex(LOGDEBUG, signatureResp, SHA256_DIGEST_LENGTH);
+ Log(LOGDEBUG, "%s: Client signature calculated:", __FUNCTION__);
+ LogHex(LOGDEBUG, signatureResp, SHA256_DIGEST_LENGTH);
- memcpy(&clientResp[RTMP_SIG_SIZE-SHA256_DIGEST_LENGTH], signatureResp, SHA256_DIGEST_LENGTH);
+ memcpy(&clientResp[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH], signatureResp,
+ SHA256_DIGEST_LENGTH);
#ifdef _DEBUG
- Log(LOGDEBUG, "%s: Sending final signed handshake response: ", __FUNCTION__);
- LogHex(LOGDEBUG, clientResp, RTMP_SIG_SIZE);
+ Log(LOGDEBUG, "%s: Sending final signed handshake response: ",
+ __FUNCTION__);
+ LogHex(LOGDEBUG, clientResp, RTMP_SIG_SIZE);
#endif
- if(!WriteN(r, clientResp, RTMP_SIG_SIZE))
- return false;
- }
-
- if(encrypted) {
- // set keys for encryption from now on
- r->Link.rc4keyIn = keyIn;
- r->Link.rc4keyOut = keyOut;
+ if (!WriteN(r, clientResp, RTMP_SIG_SIZE))
+ return false;
+ }
- char buff[RTMP_SIG_SIZE];
+ if (encrypted)
+ {
+ // set keys for encryption from now on
+ r->Link.rc4keyIn = keyIn;
+ r->Link.rc4keyOut = keyOut;
- // update the keystreams
- if(r->Link.rc4keyIn) {
- RC4(r->Link.rc4keyIn, RTMP_SIG_SIZE, (uint8_t*)buff, (uint8_t*)buff);
- }
+ char buff[RTMP_SIG_SIZE];
- if(r->Link.rc4keyOut) {
- RC4(r->Link.rc4keyOut, RTMP_SIG_SIZE, (uint8_t*)buff, (uint8_t*)buff);
- }
+ // update the keystreams
+ if (r->Link.rc4keyIn)
+ {
+ RC4(r->Link.rc4keyIn, RTMP_SIG_SIZE, (uint8_t *) buff,
+ (uint8_t *) buff);
}
-
- Log(LOGDEBUG, "%s: Handshaking finished....", __FUNCTION__);
- return true;
+
+ if (r->Link.rc4keyOut)
+ {
+ RC4(r->Link.rc4keyOut, RTMP_SIG_SIZE, (uint8_t *) buff,
+ (uint8_t *) buff);
+ }
+ }
+
+ Log(LOGDEBUG, "%s: Handshaking finished....", __FUNCTION__);
+ return true;
}
Modified: rtmp2.c
==============================================================================
--- rtmp2.c Wed Dec 16 07:26:23 2009 (r63)
+++ rtmp2.c Wed Dec 16 07:26:45 2009 (r64)
@@ -47,6 +47,7 @@
#define RTMP_LARGE_HEADER_SIZE 12
static const int packetSize[] = { 12, 8, 4, 1 };
+
#define RTMP_PACKET_SIZE_LARGE 0
#define RTMP_PACKET_SIZE_MEDIUM 1
#define RTMP_PACKET_SIZE_SMALL 2
@@ -54,104 +55,108 @@ static const int packetSize[] = { 12, 8,
extern bool bCtrlC;
-char RTMPProtocolStrings[][7] =
-{
- "RTMP",
- "RTMPT",
- "RTMPS",
- "RTMPE",
- "RTMPTE",
- "RTMFP"
+char RTMPProtocolStrings[][7] = {
+ "RTMP",
+ "RTMPT",
+ "RTMPS",
+ "RTMPE",
+ "RTMPTE",
+ "RTMFP"
};
-char RTMPProtocolStringsLower[][7] =
-{
- "rtmp",
- "rtmpt",
- "rtmps",
- "rtmpe",
- "rtmpte",
- "rtmpfp"
+char RTMPProtocolStringsLower[][7] = {
+ "rtmp",
+ "rtmpt",
+ "rtmps",
+ "rtmpe",
+ "rtmpte",
+ "rtmpfp"
};
-static bool DumpMetaData(AMFObject *obj);
-static bool HandShake(RTMP *r, bool FP9HandShake);
-static bool SocksNegotiate(RTMP *r);
+static bool DumpMetaData(AMFObject * obj);
+static bool HandShake(RTMP * r, bool FP9HandShake);
+static bool SocksNegotiate(RTMP * r);
-static bool SendConnectPacket(RTMP *r);
-static bool SendServerBW(RTMP *r);
-static bool SendCheckBW(RTMP *r);
-static bool SendCheckBWResult(RTMP *r, double txn);
-static bool SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime);
-static bool SendBGHasStream(RTMP *r, double dId, AVal *playpath);
-static bool SendCreateStream(RTMP *r, double dStreamId);
-static bool SendDeleteStream(RTMP *r, double dStreamId);
-static bool SendFCSubscribe(RTMP *r, AVal *subscribepath);
-static bool SendPlay(RTMP *r);
-static bool SendSeek(RTMP *r, double dTime);
-static bool SendBytesReceived(RTMP *r);
+static bool SendConnectPacket(RTMP * r);
+static bool SendServerBW(RTMP * r);
+static bool SendCheckBW(RTMP * r);
+static bool SendCheckBWResult(RTMP * r, double txn);
+static bool SendCtrl(RTMP * r, short nType, unsigned int nObject,
+ unsigned int nTime);
+static bool SendBGHasStream(RTMP * r, double dId, AVal * playpath);
+static bool SendCreateStream(RTMP * r, double dStreamId);
+static bool SendDeleteStream(RTMP * r, double dStreamId);
+static bool SendFCSubscribe(RTMP * r, AVal * subscribepath);
+static bool SendPlay(RTMP * r);
+static bool SendSeek(RTMP * r, double dTime);
+static bool SendBytesReceived(RTMP * r);
-static int HandlePacket(RTMP *r, RTMPPacket *packet);
-static int HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize);
-static bool HandleMetadata(RTMP *r, char *body, unsigned int len);
-static void HandleChangeChunkSize(RTMP *r, const RTMPPacket *packet);
-static void HandleAudio(RTMP *r, const RTMPPacket *packet);
-static void HandleVideo(RTMP *r, const RTMPPacket *packet);
-static void HandleCtrl(RTMP *r, const RTMPPacket *packet);
-static void HandleServerBW(RTMP *r, const RTMPPacket *packet);
-static void HandleClientBW(RTMP *r, const RTMPPacket *packet);
+static int HandlePacket(RTMP * r, RTMPPacket * packet);
+static int HandleInvoke(RTMP * r, const char *body, unsigned int nBodySize);
+static bool HandleMetadata(RTMP * r, char *body, unsigned int len);
+static void HandleChangeChunkSize(RTMP * r, const RTMPPacket * packet);
+static void HandleAudio(RTMP * r, const RTMPPacket * packet);
+static void HandleVideo(RTMP * r, const RTMPPacket * packet);
+static void HandleCtrl(RTMP * r, const RTMPPacket * packet);
+static void HandleServerBW(RTMP * r, const RTMPPacket * packet);
+static void HandleClientBW(RTMP * r, const RTMPPacket * packet);
-static int EncodeString(char *output, const AVal *name, const AVal *value);
-static int EncodeNumber(char *output, const AVal *name, double dVal);
-static int EncodeBoolean(char *output, const AVal *name, bool bVal);
+static int EncodeString(char *output, const AVal * name, const AVal * value);
+static int EncodeNumber(char *output, const AVal * name, double dVal);
+static int EncodeBoolean(char *output, const AVal * name, bool bVal);
-static bool SendRTMP(RTMP *r, RTMPPacket *packet, bool queue);
+static bool SendRTMP(RTMP * r, RTMPPacket * packet, bool queue);
-static bool ReadPacket(RTMP *r, RTMPPacket *packet);
-static int ReadN(RTMP *r, char *buffer, int n);
-static bool WriteN(RTMP *r, const char *buffer, int n);
+static bool ReadPacket(RTMP * r, RTMPPacket * packet);
+static int ReadN(RTMP * r, char *buffer, int n);
+static bool WriteN(RTMP * r, const char *buffer, int n);
-static bool FillBuffer(RTMP *r);
+static bool FillBuffer(RTMP * r);
-int32_t RTMP_GetTime()
+int32_t
+RTMP_GetTime()
{
#ifdef _DEBUG
- return 0;
+ return 0;
#elif defined(WIN32)
- return timeGetTime();
+ return timeGetTime();
#else
- struct tms t;
- return times(&t)*1000/sysconf(_SC_CLK_TCK);
+ struct tms t;
+ return times(&t) * 1000 / sysconf(_SC_CLK_TCK);
#endif
}
-void RTMPPacket_Reset(RTMPPacket *p)
+void
+RTMPPacket_Reset(RTMPPacket * p)
{
p->m_headerType = 0;
p->m_packetType = 0;
p->m_nChannel = 0;
- p->m_nInfoField1 = 0;
- p->m_nInfoField2 = 0;
+ p->m_nInfoField1 = 0;
+ p->m_nInfoField2 = 0;
p->m_hasAbsTimestamp = false;
p->m_nBodySize = 0;
p->m_nBytesRead = 0;
}
-void RTMPPacket_Dump(RTMPPacket *p)
+void
+RTMPPacket_Dump(RTMPPacket * p)
{
- Log(LOGDEBUG,"RTMP PACKET: packet type: 0x%02x. channel: 0x%02x. info 1: %d info 2: %d. Body size: %lu. body: 0x%02x",
- p->m_packetType, p->m_nChannel,
- p->m_nInfoField1, p->m_nInfoField2, p->m_nBodySize, p->m_body?(unsigned char)p->m_body[0]:0);
+ Log(LOGDEBUG,
+ "RTMP PACKET: packet type: 0x%02x. channel: 0x%02x. info 1: %d info 2: %d. Body size: %lu. body: 0x%02x",
+ p->m_packetType, p->m_nChannel, p->m_nInfoField1, p->m_nInfoField2,
+ p->m_nBodySize, p->m_body ? (unsigned char) p->m_body[0] : 0);
}
-void RTMP_Init(RTMP *r)
+void
+RTMP_Init(RTMP * r)
{
int i;
- for (i=0; i<RTMP_CHANNELS; i++)
- {
- r->m_vecChannelsIn[i] = NULL;
- r->m_vecChannelsOut[i] = NULL;
- }
+ for (i = 0; i < RTMP_CHANNELS; i++)
+ {
+ r->m_vecChannelsIn[i] = NULL;
+ r->m_vecChannelsOut[i] = NULL;
+ }
RTMP_Close(r);
r->m_nBufferMS = 300;
r->m_fDuration = 0;
@@ -164,41 +169,54 @@ void RTMP_Init(RTMP *r)
r->m_mediaChannel = 0;
}
-double RTMP_GetDuration(RTMP *r) { return r->m_fDuration; }
-bool RTMP_IsConnected(RTMP *r) { return r->m_socket != 0; }
-bool RTMP_IsTimedout(RTMP *r) { return r->m_bTimedout; }
+double
+RTMP_GetDuration(RTMP * r)
+{
+ return r->m_fDuration;
+}
-void RTMP_SetBufferMS(RTMP *r, int size)
+bool
+RTMP_IsConnected(RTMP * r)
+{
+ return r->m_socket != 0;
+}
+
+bool
+RTMP_IsTimedout(RTMP * r)
+{
+ return r->m_bTimedout;
+}
+
+void
+RTMP_SetBufferMS(RTMP * r, int size)
{
r->m_nBufferMS = size;
}
-void RTMP_UpdateBufferMS(RTMP *r)
+void
+RTMP_UpdateBufferMS(RTMP * r)
{
SendCtrl(r, 3, r->m_stream_id, r->m_nBufferMS);
}
-void RTMP_SetupStream(
- RTMP *r,
- int protocol,
- const char *hostname,
- unsigned int port,
- const char *sockshost,
- AVal *playpath,
- AVal *tcUrl,
- AVal *swfUrl,
- AVal *pageUrl,
- AVal *app,
- AVal *auth,
- AVal *swfSHA256Hash,
- uint32_t swfSize,
- AVal *flashVer,
- AVal *subscribepath,
- double dTime,
- uint32_t dLength,
- bool bLiveStream,
- long int timeout
-)
+void
+RTMP_SetupStream(RTMP * r,
+ int protocol,
+ const char *hostname,
+ unsigned int port,
+ const char *sockshost,
+ AVal * playpath,
+ AVal * tcUrl,
+ AVal * swfUrl,
+ AVal * pageUrl,
+ AVal * app,
+ AVal * auth,
+ AVal * swfSHA256Hash,
+ uint32_t swfSize,
+ AVal * flashVer,
+ AVal * subscribepath,
+ double dTime,
+ uint32_t dLength, bool bLiveStream, long int timeout)
{
assert(protocol < 6);
@@ -207,55 +225,61 @@ void RTMP_SetupStream(
Log(LOGDEBUG, "Port : %d", port);
Log(LOGDEBUG, "Playpath : %s", playpath->av_val);
- if(tcUrl)
- Log(LOGDEBUG, "tcUrl : %s", tcUrl->av_val);
- if(swfUrl)
- Log(LOGDEBUG, "swfUrl : %s", swfUrl->av_val);
- if(pageUrl)
- Log(LOGDEBUG, "pageUrl : %s", pageUrl->av_val);
- if(app)
- Log(LOGDEBUG, "app : %s", app->av_val);
- if(auth)
- Log(LOGDEBUG, "auth : %s", auth->av_val);
- if(subscribepath)
- Log(LOGDEBUG, "subscribepath : %s", subscribepath->av_val);
- if(flashVer)
- Log(LOGDEBUG, "flashVer : %s", flashVer->av_val);
- if(dTime > 0)
- Log(LOGDEBUG, "SeekTime : %.3f sec", (double)dTime/1000.0);
- if(dLength > 0)
- Log(LOGDEBUG, "playLength : %.3f sec", (double)dLength/1000.0);
+ if (tcUrl)
+ Log(LOGDEBUG, "tcUrl : %s", tcUrl->av_val);
+ if (swfUrl)
+ Log(LOGDEBUG, "swfUrl : %s", swfUrl->av_val);
+ if (pageUrl)
+ Log(LOGDEBUG, "pageUrl : %s", pageUrl->av_val);
+ if (app)
+ Log(LOGDEBUG, "app : %s", app->av_val);
+ if (auth)
+ Log(LOGDEBUG, "auth : %s", auth->av_val);
+ if (subscribepath)
+ Log(LOGDEBUG, "subscribepath : %s", subscribepath->av_val);
+ if (flashVer)
+ Log(LOGDEBUG, "flashVer : %s", flashVer->av_val);
+ if (dTime > 0)
+ Log(LOGDEBUG, "SeekTime : %.3f sec", (double) dTime / 1000.0);
+ if (dLength > 0)
+ Log(LOGDEBUG, "playLength : %.3f sec", (double) dLength / 1000.0);
- Log(LOGDEBUG, "live : %s", bLiveStream ? "yes":"no");
- Log(LOGDEBUG, "timeout : %d sec", timeout);
+ Log(LOGDEBUG, "live : %s", bLiveStream ? "yes" : "no");
+ Log(LOGDEBUG, "timeout : %d sec", timeout);
- if(swfSHA256Hash != NULL && swfSize > 0) {
- r->Link.SWFHash = *swfSHA256Hash;
- r->Link.SWFSize = swfSize;
- Log(LOGDEBUG, "SWFSHA256:");
- LogHex(LOGDEBUG, r->Link.SWFHash.av_val, 32);
- Log(LOGDEBUG, "SWFSize : %lu", r->Link.SWFSize);
- } else {
- r->Link.SWFHash.av_len = 0;
- r->Link.SWFHash.av_val = NULL;
- r->Link.SWFSize = 0;
- }
+ if (swfSHA256Hash != NULL && swfSize > 0)
+ {
+ r->Link.SWFHash = *swfSHA256Hash;
+ r->Link.SWFSize = swfSize;
+ Log(LOGDEBUG, "SWFSHA256:");
+ LogHex(LOGDEBUG, r->Link.SWFHash.av_val, 32);
+ Log(LOGDEBUG, "SWFSize : %lu", r->Link.SWFSize);
+ }
+ else
+ {
+ r->Link.SWFHash.av_len = 0;
+ r->Link.SWFHash.av_val = NULL;
+ r->Link.SWFSize = 0;
+ }
- if(sockshost)
- {
- const char *socksport = strchr(sockshost, ':');
- char *hostname = strdup(sockshost);
+ if (sockshost)
+ {
+ const char *socksport = strchr(sockshost, ':');
+ char *hostname = strdup(sockshost);
- if(socksport)
- hostname[socksport - sockshost] = '\0';
- r->Link.sockshost = hostname;
+ if (socksport)
+ hostname[socksport - sockshost] = '\0';
+ r->Link.sockshost = hostname;
- r->Link.socksport = socksport ? atoi(socksport + 1) : 1080;
- Log(LOGDEBUG, "Connecting via SOCKS proxy: %s:%d", r->Link.sockshost, r->Link.socksport);
- } else {
- r->Link.sockshost = NULL;
- r->Link.socksport = 0;
- }
+ r->Link.socksport = socksport ? atoi(socksport + 1) : 1080;
+ Log(LOGDEBUG, "Connecting via SOCKS proxy: %s:%d", r->Link.sockshost,
+ r->Link.socksport);
+ }
+ else
+ {
+ r->Link.sockshost = NULL;
+ r->Link.socksport = 0;
+ }
r->Link.tcUrl = *tcUrl;
@@ -279,28 +303,31 @@ void RTMP_SetupStream(
r->Link.port = 1935;
}
-static bool add_addr_info(struct sockaddr_in* service, const char *hostname, int port)
+static bool
+add_addr_info(struct sockaddr_in *service, const char *hostname, int port)
{
service->sin_addr.s_addr = inet_addr(hostname);
if (service->sin_addr.s_addr == INADDR_NONE)
- {
- struct hostent *host = gethostbyname(hostname);
- if (host == NULL || host->h_addr == NULL)
{
- Log(LOGERROR, "Problem accessing the DNS. (addr: %s)", hostname);
- return false;
+ struct hostent *host = gethostbyname(hostname);
+ if (host == NULL || host->h_addr == NULL)
+ {
+ Log(LOGERROR, "Problem accessing the DNS. (addr: %s)", hostname);
+ return false;
+ }
+ service->sin_addr = *(struct in_addr *) host->h_addr;
}
- service->sin_addr = *(struct in_addr*)host->h_addr;
- }
service->sin_port = htons(port);
return true;
}
-bool RTMP_Connect(RTMP *r) {
+bool
+RTMP_Connect(RTMP * r)
+{
struct sockaddr_in service;
if (!r->Link.hostname)
- return false;
+ return false;
// close any previous connection
RTMP_Close(r);
@@ -313,71 +340,84 @@ bool RTMP_Connect(RTMP *r) {
service.sin_family = AF_INET;
if (r->Link.socksport)
- {
- // Connect via SOCKS
- if(!add_addr_info(&service, r->Link.sockshost, r->Link.socksport)) return false;
- } else {
- // Connect directly
- if(!add_addr_info(&service, r->Link.hostname, r->Link.port)) return false;
- }
+ {
+ // Connect via SOCKS
+ if (!add_addr_info(&service, r->Link.sockshost, r->Link.socksport))
+ return false;
+ }
+ else
+ {
+ // Connect directly
+ if (!add_addr_info(&service, r->Link.hostname, r->Link.port))
+ return false;
+ }
r->m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (r->m_socket != -1)
- {
- if (connect(r->m_socket, (struct sockaddr*) &service, sizeof(struct sockaddr)) < 0)
{
- int err = GetSockError();
- Log(LOGERROR, "%s, failed to connect socket. %d (%s)", __FUNCTION__,
- err, strerror(err));
- RTMP_Close(r);
- return false;
- }
+ if (connect
+ (r->m_socket, (struct sockaddr *) &service,
+ sizeof(struct sockaddr)) < 0)
+ {
+ int err = GetSockError();
+ Log(LOGERROR, "%s, failed to connect socket. %d (%s)", __FUNCTION__,
+ err, strerror(err));
+ RTMP_Close(r);
+ return false;
+ }
- if(r->Link.socksport) {
- Log(LOGDEBUG, "%s ... SOCKS negotiation", __FUNCTION__);
- if (!SocksNegotiate(r))
- {
- Log(LOGERROR, "%s, SOCKS negotiation failed.", __FUNCTION__);
- RTMP_Close(r);
- return false;
- }
- }
+ if (r->Link.socksport)
+ {
+ Log(LOGDEBUG, "%s ... SOCKS negotiation", __FUNCTION__);
+ if (!SocksNegotiate(r))
+ {
+ Log(LOGERROR, "%s, SOCKS negotiation failed.", __FUNCTION__);
+ RTMP_Close(r);
+ return false;
+ }
+ }
- Log(LOGDEBUG, "%s, ... connected, handshaking", __FUNCTION__);
- if (!HandShake(r, true))
- {
- Log(LOGERROR, "%s, handshake failed.", __FUNCTION__);
- RTMP_Close(r);
- return false;
- }
+ Log(LOGDEBUG, "%s, ... connected, handshaking", __FUNCTION__);
+ if (!HandShake(r, true))
+ {
+ Log(LOGERROR, "%s, handshake failed.", __FUNCTION__);
+ RTMP_Close(r);
+ return false;
+ }
- Log(LOGDEBUG, "%s, handshaked", __FUNCTION__);
- if (!SendConnectPacket(r))
+ Log(LOGDEBUG, "%s, handshaked", __FUNCTION__);
+ if (!SendConnectPacket(r))
+ {
+ Log(LOGERROR, "%s, RTMP connect failed.", __FUNCTION__);
+ RTMP_Close(r);
+ return false;
+ }
+ // set timeout
+ struct timeval tv;
+ memset(&tv, 0, sizeof(tv));
+ tv.tv_sec = r->Link.timeout;
+ if (setsockopt
+ (r->m_socket, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, sizeof(tv)))
+ {
+ Log(LOGERROR, "%s, Setting socket timeout to %ds failed!",
+ __FUNCTION__, tv.tv_sec);
+ }
+ }
+ else
{
- Log(LOGERROR, "%s, RTMP connect failed.", __FUNCTION__);
- RTMP_Close(r);
+ Log(LOGERROR, "%s, failed to create socket. Error: %d", __FUNCTION__,
+ GetSockError());
return false;
}
- // set timeout
- struct timeval tv;
- memset(&tv, 0, sizeof(tv));
- tv.tv_sec = r->Link.timeout;
- if (setsockopt(r->m_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv))) {
- Log(LOGERROR,"%s, Setting socket timeout to %ds failed!", __FUNCTION__, tv.tv_sec);
- }
- }
- else
- {
- Log(LOGERROR, "%s, failed to create socket. Error: %d", __FUNCTION__, GetSockError());
- return false;
- }
int on = 1;
setsockopt(r->m_socket, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
return true;
}
-static bool SocksNegotiate(RTMP *r) {
+static bool
+SocksNegotiate(RTMP * r)
+{
struct sockaddr_in service;
memset(&service, 0, sizeof(struct sockaddr_in));
@@ -385,27 +425,33 @@ static bool SocksNegotiate(RTMP *r) {
unsigned long addr = htonl(service.sin_addr.s_addr);
char packet[] = {
- 4, 1, // SOCKS 4, connect
- (r->Link.port >> 8) & 0xFF,
- (r->Link.port) & 0xFF,
- (char) (addr >> 24) & 0xFF, (char) (addr >> 16) & 0xFF,
- (char) (addr >> 8) & 0xFF, (char) addr & 0xFF,
- 0}; // NULL terminate
+ 4, 1, // SOCKS 4, connect
+ (r->Link.port >> 8) & 0xFF,
+ (r->Link.port) & 0xFF,
+ (char) (addr >> 24) & 0xFF, (char) (addr >> 16) & 0xFF,
+ (char) (addr >> 8) & 0xFF, (char) addr & 0xFF,
+ 0
+ }; // NULL terminate
WriteN(r, packet, sizeof packet);
- if(ReadN(r, packet, 8) != 8)
+ if (ReadN(r, packet, 8) != 8)
return false;
- if(packet[0] == 0 && packet[1] == 90) {
- return true;
- } else {
- Log(LOGERROR, "%s, SOCKS returned error code %d", packet[1]);
- return false;
- }
+ if (packet[0] == 0 && packet[1] == 90)
+ {
+ return true;
+ }
+ else
+ {
+ Log(LOGERROR, "%s, SOCKS returned error code %d", packet[1]);
+ return false;
+ }
}
-bool RTMP_ConnectStream(RTMP *r, double seekTime, uint32_t dLength) {
+bool
+RTMP_ConnectStream(RTMP * r, double seekTime, uint32_t dLength)
+{
RTMPPacket packet;
if (seekTime >= -2.0)
r->Link.seekTime = seekTime;
@@ -416,28 +462,32 @@ bool RTMP_ConnectStream(RTMP *r, double
r->m_mediaChannel = 0;
RTMPPacket_Reset(&packet);
- while (!r->m_bPlaying && RTMP_IsConnected(r) && ReadPacket(r, &packet)) {
- if (!RTMPPacket_IsReady(&packet))
- {
- continue;
- }
-
- if ((packet.m_packetType == RTMP_PACKET_TYPE_AUDIO) || \
- (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO) || \
- (packet.m_packetType == RTMP_PACKET_TYPE_INFO))
+ while (!r->m_bPlaying && RTMP_IsConnected(r) && ReadPacket(r, &packet))
{
- Log(LOGDEBUG, "%s, received FLV packet before play()!", __FUNCTION__);
- break;
- }
+ if (!RTMPPacket_IsReady(&packet))
+ {
+ continue;
+ }
- HandlePacket(r, &packet);
- RTMPPacket_Reset(&packet);
- }
+ if ((packet.m_packetType == RTMP_PACKET_TYPE_AUDIO) ||
+ (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO) ||
+ (packet.m_packetType == RTMP_PACKET_TYPE_INFO))
+ {
+ Log(LOGDEBUG, "%s, received FLV packet before play()!",
+ __FUNCTION__);
+ break;
+ }
+
+ HandlePacket(r, &packet);
+ }
return r->m_bPlaying;
}
-bool RTMP_ReconnectStream(RTMP *r, int bufferTime, double seekTime, uint32_t dLength) {
+bool
+RTMP_ReconnectStream(RTMP * r, int bufferTime, double seekTime,
+ uint32_t dLength)
+{
RTMP_DeleteStream(r);
SendCreateStream(r, 2.0);
@@ -447,12 +497,14 @@ bool RTMP_ReconnectStream(RTMP *r, int b
return RTMP_ConnectStream(r, seekTime, dLength);
}
-bool RTMP_ToggleStream(RTMP *r)
+bool
+RTMP_ToggleStream(RTMP * r)
{
bool res;
res = RTMP_SendPause(r, true, r->m_pauseStamp);
- if (!res) return res;
+ if (!res)
+ return res;
r->m_pausing = 1;
sleep(1);
@@ -461,7 +513,9 @@ bool RTMP_ToggleStream(RTMP *r)
return res;
}
-void RTMP_DeleteStream(RTMP *r) {
+void
+RTMP_DeleteStream(RTMP * r)
+{
if (r->m_stream_id < 0)
return;
@@ -470,35 +524,42 @@ void RTMP_DeleteStream(RTMP *r) {
SendDeleteStream(r, r->m_stream_id);
}
-int RTMP_GetNextMediaPacket(RTMP *r, RTMPPacket *packet)
+int
+RTMP_GetNextMediaPacket(RTMP * r, RTMPPacket * packet)
{
int bHasMediaPacket = 0;
RTMPPacket_Reset(packet);
while (!bHasMediaPacket && RTMP_IsConnected(r) && ReadPacket(r, packet))
- {
- if (!RTMPPacket_IsReady(packet))
{
- continue;
- }
+ if (!RTMPPacket_IsReady(packet))
+ {
+ continue;
+ }
- bHasMediaPacket = HandlePacket(r, packet);
+ bHasMediaPacket = HandlePacket(r, packet);
- if (!bHasMediaPacket) {
- RTMPPacket_Reset(packet);
- } else if (r->m_pausing == 3) {
- if (packet->m_nTimeStamp <= r->m_mediaStamp) {
- bHasMediaPacket = 0;
+ if (!bHasMediaPacket)
+ {
+ }
+ else if (r->m_pausing == 3)
+ {
+ if (packet->m_nTimeStamp <= r->m_mediaStamp)
+ {
+ bHasMediaPacket = 0;
#ifdef _DEBUG
- Log(LOGDEBUG, "Skipped type: %02X, size: %d, TS: %d ms, abs TS: %d, pause: %d ms",
- packet->m_packetType, packet->m_nBodySize, packet->m_nTimeStamp, packet->m_hasAbsTimestamp, r->m_mediaStamp);
+ Log(LOGDEBUG,
+ "Skipped type: %02X, size: %d, TS: %d ms, abs TS: %d, pause: %d ms",
+ packet->m_packetType, packet->m_nBodySize,
+ packet->m_nTimeStamp, packet->m_hasAbsTimestamp,
+ r->m_mediaStamp);
#endif
- continue;
- }
- r->m_pausing = 0;
+ continue;
+ }
+ r->m_pausing = 0;
+ }
}
- }
-
+
if (bHasMediaPacket)
r->m_bPlaying = true;
else if (r->m_bTimedout)
@@ -507,143 +568,158 @@ int RTMP_GetNextMediaPacket(RTMP *r, RTM
return bHasMediaPacket;
}
-static int HandlePacket(RTMP *r, RTMPPacket *packet) {
+static int
+HandlePacket(RTMP * r, RTMPPacket * packet)
+{
int bHasMediaPacket = 0;
- switch (packet->m_packetType)
+ switch (packet->m_packetType)
{
- case 0x01:
- // chunk size
- HandleChangeChunkSize(r, packet);
- break;
+ case 0x01:
+ // chunk size
+ HandleChangeChunkSize(r, packet);
+ break;
- case 0x03:
- // bytes read report
- Log(LOGDEBUG, "%s, received: bytes read report", __FUNCTION__);
- break;
+ case 0x03:
+ // bytes read report
+ Log(LOGDEBUG, "%s, received: bytes read report", __FUNCTION__);
+ break;
- case 0x04:
- // ctrl
- HandleCtrl(r, packet);
- break;
+ case 0x04:
+ // ctrl
+ HandleCtrl(r, packet);
+ break;
- case 0x05:
- // server bw
- HandleServerBW(r, packet);
- break;
+ case 0x05:
+ // server bw
+ HandleServerBW(r, packet);
+ break;
- case 0x06:
- // client bw
- HandleClientBW(r, packet);
- break;
+ case 0x06:
+ // client bw
+ HandleClientBW(r, packet);
+ break;
- case 0x08:
- // audio data
- //Log(LOGDEBUG, "%s, received: audio %lu bytes", __FUNCTION__, packet.m_nBodySize);
- HandleAudio(r, packet);
- bHasMediaPacket = 1;
- if (!r->m_mediaChannel)
- r->m_mediaChannel = packet->m_nChannel;
- if (!r->m_pausing)
- r->m_mediaStamp = packet->m_nTimeStamp;
- break;
+ case 0x08:
+ // audio data
+ //Log(LOGDEBUG, "%s, received: audio %lu bytes", __FUNCTION__, packet.m_nBodySize);
+ HandleAudio(r, packet);
+ bHasMediaPacket = 1;
+ if (!r->m_mediaChannel)
+ r->m_mediaChannel = packet->m_nChannel;
+ if (!r->m_pausing)
+ r->m_mediaStamp = packet->m_nTimeStamp;
+ break;
- case 0x09:
- // video data
- //Log(LOGDEBUG, "%s, received: video %lu bytes", __FUNCTION__, packet.m_nBodySize);
- HandleVideo(r, packet);
- bHasMediaPacket = 1;
- if (!r->m_mediaChannel)
- r->m_mediaChannel = packet->m_nChannel;
- if (!r->m_pausing)
- r->m_mediaStamp = packet->m_nTimeStamp;
- break;
+ case 0x09:
+ // video data
+ //Log(LOGDEBUG, "%s, received: video %lu bytes", __FUNCTION__, packet.m_nBodySize);
+ HandleVideo(r, packet);
+ bHasMediaPacket = 1;
+ if (!r->m_mediaChannel)
+ r->m_mediaChannel = packet->m_nChannel;
+ if (!r->m_pausing)
+ r->m_mediaStamp = packet->m_nTimeStamp;
+ break;
- case 0x0F: // flex stream send
- Log(LOGDEBUG, "%s, flex stream send, size %lu bytes, not supported, ignoring", __FUNCTION__, packet->m_nBodySize);
- break;
+ case 0x0F: // flex stream send
+ Log(LOGDEBUG,
+ "%s, flex stream send, size %lu bytes, not supported, ignoring",
+ __FUNCTION__, packet->m_nBodySize);
+ break;
- case 0x10: // flex shared object
- Log(LOGDEBUG, "%s, flex shared object, size %lu bytes, not supported, ignoring", __FUNCTION__, packet->m_nBodySize);
- break;
+ case 0x10: // flex shared object
+ Log(LOGDEBUG,
+ "%s, flex shared object, size %lu bytes, not supported, ignoring",
+ __FUNCTION__, packet->m_nBodySize);
+ break;
- case 0x11: // flex message
+ case 0x11: // flex message
{
- Log(LOGDEBUG, "%s, flex message, size %lu bytes, not fully supported", __FUNCTION__, packet->m_nBodySize);
+ Log(LOGDEBUG, "%s, flex message, size %lu bytes, not fully supported",
+ __FUNCTION__, packet->m_nBodySize);
//LogHex(packet.m_body, packet.m_nBodySize);
// some DEBUG code
/*RTMP_LIB_AMFObject obj;
- int nRes = obj.Decode(packet.m_body+1, packet.m_nBodySize-1);
- if(nRes < 0) {
- Log(LOGERROR, "%s, error decoding AMF3 packet", __FUNCTION__);
- //return;
- }
+ int nRes = obj.Decode(packet.m_body+1, packet.m_nBodySize-1);
+ if(nRes < 0) {
+ Log(LOGERROR, "%s, error decoding AMF3 packet", __FUNCTION__);
+ //return;
+ }
- obj.Dump();*/
+ obj.Dump(); */
- if ( HandleInvoke(r, packet->m_body+1, packet->m_nBodySize-1) == 1 )
+ if (HandleInvoke(r, packet->m_body + 1, packet->m_nBodySize - 1) == 1)
bHasMediaPacket = 2;
+ RTMPPacket_Reset(packet);
break;
}
- case 0x12:
- // metadata (notify)
- Log(LOGDEBUG, "%s, received: notify %lu bytes", __FUNCTION__, packet->m_nBodySize);
- if ( HandleMetadata(r, packet->m_body, packet->m_nBodySize) )
- bHasMediaPacket = 1;
- break;
+ case 0x12:
+ // metadata (notify)
+ Log(LOGDEBUG, "%s, received: notify %lu bytes", __FUNCTION__,
+ packet->m_nBodySize);
+ if (HandleMetadata(r, packet->m_body, packet->m_nBodySize))
+ bHasMediaPacket = 1;
+ break;
- case 0x13:
- Log(LOGDEBUG, "%s, shared object, not supported, ignoring", __FUNCTION__);
- break;
+ case 0x13:
+ Log(LOGDEBUG, "%s, shared object, not supported, ignoring",
+ __FUNCTION__);
+ break;
- case 0x14:
- // invoke
- Log(LOGDEBUG, "%s, received: invoke %lu bytes", __FUNCTION__, packet->m_nBodySize);
- //LogHex(packet.m_body, packet.m_nBodySize);
+ case 0x14:
+ // invoke
+ Log(LOGDEBUG, "%s, received: invoke %lu bytes", __FUNCTION__,
+ packet->m_nBodySize);
+ //LogHex(packet.m_body, packet.m_nBodySize);
- if ( HandleInvoke(r, packet->m_body, packet->m_nBodySize) == 1 )
- bHasMediaPacket = 2;
- break;
+ if (HandleInvoke(r, packet->m_body, packet->m_nBodySize) == 1)
+ bHasMediaPacket = 2;
+ RTMPPacket_Reset(packet);
+ break;
- case 0x16:
+ case 0x16:
{
// go through FLV packets and handle metadata packets
- unsigned int pos=0;
+ unsigned int pos = 0;
uint32_t nTimeStamp = packet->m_nTimeStamp;
- Log(LOGDEBUG, "%s, received: FLV %lu bytes", __FUNCTION__, packet->m_nBodySize);
-
- while(pos+11 < packet->m_nBodySize) {
- uint32_t dataSize = AMF_DecodeInt24(packet->m_body+pos+1); // size without header (11) and prevTagSize (4)
+ while (pos + 11 < packet->m_nBodySize)
+ {
+ uint32_t dataSize = AMF_DecodeInt24(packet->m_body + pos + 1); // size without header (11) and prevTagSize (4)
- if(pos+11+dataSize+4 > packet->m_nBodySize) {
- Log(LOGWARNING, "Stream corrupt?!");
- break;
- }
- if(packet->m_body[pos] == 0x12) {
- HandleMetadata(r, packet->m_body+pos+11, dataSize);
- } else if (packet->m_body[pos] == 8 || packet->m_body[pos] == 9) {
- nTimeStamp = AMF_DecodeInt24(packet->m_body+pos+4);
- nTimeStamp |= (packet->m_body[pos+7]<<24);
- }
- pos += (11+dataSize+4);
- }
+ if (pos + 11 + dataSize + 4 > packet->m_nBodySize)
+ {
+ Log(LOGWARNING, "Stream corrupt?!");
+ break;
+ }
+ if (packet->m_body[pos] == 0x12)
+ {
+ HandleMetadata(r, packet->m_body + pos + 11, dataSize);
+ }
+ else if (packet->m_body[pos] == 8 || packet->m_body[pos] == 9)
+ {
+ nTimeStamp = AMF_DecodeInt24(packet->m_body + pos + 4);
+ nTimeStamp |= (packet->m_body[pos + 7] << 24);
+ }
+ pos += (11 + dataSize + 4);
+ }
if (!r->m_pausing)
r->m_mediaStamp = nTimeStamp;
- // FLV tag(s)
- //Log(LOGDEBUG, "%s, received: FLV tag(s) %lu bytes", __FUNCTION__, packet.m_nBodySize);
- bHasMediaPacket = 1;
- break;
+ // FLV tag(s)
+ //Log(LOGDEBUG, "%s, received: FLV tag(s) %lu bytes", __FUNCTION__, packet.m_nBodySize);
+ bHasMediaPacket = 1;
+ break;
}
- default:
- Log(LOGDEBUG, "%s, unknown packet type received: 0x%02x", __FUNCTION__, packet->m_packetType);
- #ifdef _DEBUG
- LogHex(LOGDEBUG, packet->m_body, packet->m_nBodySize);
- #endif
+ default:
+ Log(LOGDEBUG, "%s, unknown packet type received: 0x%02x", __FUNCTION__,
+ packet->m_packetType);
+#ifdef _DEBUG
+ LogHex(LOGDEBUG, packet->m_body, packet->m_nBodySize);
+#endif
}
- Log(LOGDEBUG, "%s, done %lu bytes", __FUNCTION__, packet->m_nBodySize);
return bHasMediaPacket;
}
@@ -652,11 +728,12 @@ extern FILE *netstackdump;
extern FILE *netstackdump_read;
#endif
-static int ReadN(RTMP *r, char *buffer, int n)
+static int
+ReadN(RTMP * r, char *buffer, int n)
{
int nOriginalSize = n;
char *ptr;
-
+
r->m_bTimedout = false;
#ifdef _DEBUG
@@ -665,99 +742,105 @@ static int ReadN(RTMP *r, char *buffer,
ptr = buffer;
while (n > 0)
- {
- int nBytes = 0, nRead;
- if(r->m_nBufferSize == 0)
- if (!FillBuffer(r)) {
- if (!r->m_bTimedout)
- RTMP_Close(r);
- return 0;
+ {
+ int nBytes = 0, nRead;
+ if (r->m_nBufferSize == 0)
+ if (!FillBuffer(r))
+ {
+ if (!r->m_bTimedout)
+ RTMP_Close(r);
+ return 0;
+ }
+ nRead = ((n < r->m_nBufferSize) ? n : r->m_nBufferSize);
+ if (nRead > 0)
+ {
+ memcpy(ptr, r->m_pBufferStart, nRead);
+ r->m_pBufferStart += nRead;
+ r->m_nBufferSize -= nRead;
+ nBytes = nRead;
+ r->m_nBytesIn += nRead;
+ if (r->m_nBytesIn > r->m_nBytesInSent + r->m_nClientBW / 2)
+ SendBytesReceived(r);
}
- nRead = ((n<r->m_nBufferSize)?n:r->m_nBufferSize);
- if(nRead > 0) {
- memcpy(ptr, r->m_pBufferStart, nRead);
- r->m_pBufferStart += nRead;
- r->m_nBufferSize -= nRead;
- nBytes = nRead;
- r->m_nBytesIn += nRead;
- if(r->m_nBytesIn > r->m_nBytesInSent + r->m_nClientBW/2 )
- SendBytesReceived(r);
- }
- //Log(LOGDEBUG, "%s: %d bytes\n", __FUNCTION__, nBytes);
+ //Log(LOGDEBUG, "%s: %d bytes\n", __FUNCTION__, nBytes);
#ifdef _DEBUG
- fwrite(ptr, 1, nBytes, netstackdump_read);
+ fwrite(ptr, 1, nBytes, netstackdump_read);
#endif
- if (nBytes == 0)
- {
- Log(LOGDEBUG, "%s, RTMP socket closed by server", __FUNCTION__);
- //goto again;
- RTMP_Close(r);
- break;
- }
-
+ if (nBytes == 0)
+ {
+ Log(LOGDEBUG, "%s, RTMP socket closed by server", __FUNCTION__);
+ //goto again;
+ RTMP_Close(r);
+ break;
+ }
+
#ifdef CRYPTO
- if(r->Link.rc4keyIn) {
- RC4(r->Link.rc4keyIn, nBytes, (uint8_t*)ptr, (uint8_t*)ptr);
- }
+ if (r->Link.rc4keyIn)
+ {
+ RC4(r->Link.rc4keyIn, nBytes, (uint8_t *) ptr, (uint8_t *) ptr);
+ }
#endif
- n -= nBytes;
- ptr += nBytes;
- }
+ n -= nBytes;
+ ptr += nBytes;
+ }
return nOriginalSize - n;
}
-static bool WriteN(RTMP *r, const char *buffer, int n)
+static bool
+WriteN(RTMP * r, const char *buffer, int n)
{
const char *ptr = buffer;
#ifdef CRYPTO
char *encrypted = 0;
char buf[RTMP_BUFFER_CACHE_SIZE];
-
- if(r->Link.rc4keyOut) {
- if (n > sizeof(buf))
- encrypted = (char *)malloc(n);
- else
- encrypted = (char *)buf;
- ptr = encrypted;
- RC4(r->Link.rc4keyOut, n, (uint8_t*)buffer, (uint8_t*)ptr);
- }
+
+ if (r->Link.rc4keyOut)
+ {
+ if (n > sizeof(buf))
+ encrypted = (char *) malloc(n);
+ else
+ encrypted = (char *) buf;
+ ptr = encrypted;
+ RC4(r->Link.rc4keyOut, n, (uint8_t *) buffer, (uint8_t *) ptr);
+ }
#endif
-
+
while (n > 0)
- {
+ {
#ifdef _DEBUG
- fwrite(ptr, 1, n, netstackdump);
+ fwrite(ptr, 1, n, netstackdump);
#endif
- int nBytes = send(r->m_socket, ptr, n, 0);
- //Log(LOGDEBUG, "%s: %d\n", __FUNCTION__, nBytes);
-
- if (nBytes < 0)
- {
- int sockerr = GetSockError();
- Log(LOGERROR, "%s, RTMP send error %d (%d bytes)", __FUNCTION__, sockerr, n);
+ int nBytes = send(r->m_socket, ptr, n, 0);
+ //Log(LOGDEBUG, "%s: %d\n", __FUNCTION__, nBytes);
- if (sockerr == EINTR && !bCtrlC)
- continue;
-
- RTMP_Close(r);
- n = 1;
- break;
+ if (nBytes < 0)
+ {
+ int sockerr = GetSockError();
+ Log(LOGERROR, "%s, RTMP send error %d (%d bytes)", __FUNCTION__,
+ sockerr, n);
+
+ if (sockerr == EINTR && !bCtrlC)
+ continue;
+
+ RTMP_Close(r);
+ n = 1;
+ break;
+ }
+
+ if (nBytes == 0)
+ break;
+
+ n -= nBytes;
+ ptr += nBytes;
}
-
- if (nBytes == 0)
- break;
-
- n -= nBytes;
- ptr += nBytes;
- }
#ifdef CRYPTO
- if(encrypted && encrypted != buf)
+ if (encrypted && encrypted != buf)
free(encrypted);
#endif
@@ -779,13 +862,14 @@ SAVC(videoCodecs);
SAVC(videoFunction);
SAVC(objectEncoding);
-static bool SendConnectPacket(RTMP *r)
+static bool
+SendConnectPacket(RTMP * r)
{
RTMPPacket packet;
- packet.m_nChannel = 0x03; // control channel (invoke)
+ packet.m_nChannel = 0x03; // control channel (invoke)
packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
- packet.m_packetType = 0x14; // INVOKE
+ packet.m_packetType = 0x14; // INVOKE
packet.m_nInfoField1 = 0;
packet.m_nInfoField2 = 0;
packet.m_hasAbsTimestamp = 0;
@@ -794,49 +878,51 @@ static bool SendConnectPacket(RTMP *r)
enc += AMF_EncodeString(enc, &av_connect);
enc += AMF_EncodeNumber(enc, 1.0);
*enc++ = AMF_OBJECT;
-
- if(r->Link.app.av_len)
- enc += EncodeString(enc, &av_app, &r->Link.app);
- if(r->Link.flashVer.av_len)
- enc += EncodeString(enc, &av_flashVer, &r->Link.flashVer);
- if(r->Link.swfUrl.av_len)
- enc += EncodeString(enc, &av_swfUrl, &r->Link.swfUrl);
- if(r->Link.tcUrl.av_len)
- enc += EncodeString(enc, &av_tcUrl, &r->Link.tcUrl);
-
+
+ if (r->Link.app.av_len)
+ enc += EncodeString(enc, &av_app, &r->Link.app);
+ if (r->Link.flashVer.av_len)
+ enc += EncodeString(enc, &av_flashVer, &r->Link.flashVer);
+ if (r->Link.swfUrl.av_len)
+ enc += EncodeString(enc, &av_swfUrl, &r->Link.swfUrl);
+ if (r->Link.tcUrl.av_len)
+ enc += EncodeString(enc, &av_tcUrl, &r->Link.tcUrl);
+
enc += EncodeBoolean(enc, &av_fpad, false);
enc += EncodeNumber(enc, &av_capabilities, 15.0);
enc += EncodeNumber(enc, &av_audioCodecs, r->m_fAudioCodecs);
enc += EncodeNumber(enc, &av_videoCodecs, r->m_fVideoCodecs);
enc += EncodeNumber(enc, &av_videoFunction, 1.0);
- if(r->Link.pageUrl.av_len)
- enc += EncodeString(enc, &av_pageUrl, &r->Link.pageUrl);
+ if (r->Link.pageUrl.av_len)
+ enc += EncodeString(enc, &av_pageUrl, &r->Link.pageUrl);
- enc += EncodeNumber(enc, &av_objectEncoding, 0.0); // AMF0, AMF3 not supported yet
- *enc++ = 0; *enc++ = 0; // end of object - 0x00 0x00 0x09
+ enc += EncodeNumber(enc, &av_objectEncoding, 0.0); // AMF0, AMF3 not supported yet
+ *enc++ = 0;
+ *enc++ = 0; // end of object - 0x00 0x00 0x09
*enc++ = AMF_OBJECT_END;
-
+
// add auth string
- if(r->Link.auth.av_len)
- {
- *enc++ = 0x01;
- *enc++ = 0x01;
+ if (r->Link.auth.av_len)
+ {
+ *enc++ = 0x01;
+ *enc++ = 0x01;
- enc += AMF_EncodeString(enc, &r->Link.auth);
- }
- packet.m_nBodySize = enc-packet.m_body;
+ enc += AMF_EncodeString(enc, &r->Link.auth);
+ }
+ packet.m_nBodySize = enc - packet.m_body;
return SendRTMP(r, &packet, true);
}
SAVC(bgHasStream);
-static bool SendBGHasStream(RTMP *r, double dId, AVal *playpath)
+static bool
+SendBGHasStream(RTMP * r, double dId, AVal * playpath)
{
RTMPPacket packet;
- packet.m_nChannel = 0x03; // control channel (invoke)
+ packet.m_nChannel = 0x03; // control channel (invoke)
packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
- packet.m_packetType = 0x14; // INVOKE
+ packet.m_packetType = 0x14; // INVOKE
packet.m_nInfoField1 = 0;
packet.m_nInfoField2 = 0;
packet.m_hasAbsTimestamp = 0;
@@ -848,19 +934,20 @@ static bool SendBGHasStream(RTMP *r, dou
enc += AMF_EncodeString(enc, playpath);
- packet.m_nBodySize = enc-packet.m_body;
+ packet.m_nBodySize = enc - packet.m_body;
return SendRTMP(r, &packet, true);
}
SAVC(createStream);
-static bool SendCreateStream(RTMP *r, double dStreamId)
+static bool
+SendCreateStream(RTMP * r, double dStreamId)
{
RTMPPacket packet;
- packet.m_nChannel = 0x03; // control channel (invoke)
+ packet.m_nChannel = 0x03; // control channel (invoke)
packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
- packet.m_packetType = 0x14; // INVOKE
+ packet.m_packetType = 0x14; // INVOKE
packet.m_nInfoField1 = 0;
packet.m_nInfoField2 = 0;
packet.m_hasAbsTimestamp = 0;
@@ -868,7 +955,7 @@ static bool SendCreateStream(RTMP *r, do
char *enc = packet.m_body;
enc += AMF_EncodeString(enc, &av_createStream);
enc += AMF_EncodeNumber(enc, dStreamId);
- *enc++ = AMF_NULL; // NULL
+ *enc++ = AMF_NULL; // NULL
packet.m_nBodySize = enc - packet.m_body;
@@ -877,12 +964,13 @@ static bool SendCreateStream(RTMP *r, do
SAVC(FCSubscribe);
-static bool SendFCSubscribe(RTMP *r, AVal *subscribepath)
+static bool
+SendFCSubscribe(RTMP * r, AVal * subscribepath)
{
RTMPPacket packet;
- packet.m_nChannel = 0x03; // control channel (invoke)
+ packet.m_nChannel = 0x03; // control channel (invoke)
packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
- packet.m_packetType = 0x14; // INVOKE
+ packet.m_packetType = 0x14; // INVOKE
packet.m_nInfoField1 = 0;
packet.m_nInfoField2 = 0;
packet.m_hasAbsTimestamp = 0;
@@ -901,13 +989,14 @@ static bool SendFCSubscribe(RTMP *r, AVa
SAVC(deleteStream);
-static bool SendDeleteStream(RTMP *r, double dStreamId)
+static bool
+SendDeleteStream(RTMP * r, double dStreamId)
{
RTMPPacket packet;
- packet.m_nChannel = 0x03; // control channel (invoke)
+ packet.m_nChannel = 0x03; // control channel (invoke)
packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
- packet.m_packetType = 0x14; // INVOKE
+ packet.m_packetType = 0x14; // INVOKE
packet.m_nInfoField1 = 0;
packet.m_nInfoField2 = 0;
packet.m_hasAbsTimestamp = 0;
@@ -926,12 +1015,13 @@ static bool SendDeleteStream(RTMP *r, do
SAVC(pause);
-bool RTMP_SendPause(RTMP *r, bool DoPause, double dTime)
+bool
+RTMP_SendPause(RTMP * r, bool DoPause, double dTime)
{
RTMPPacket packet;
- packet.m_nChannel = 0x08; // video channel
+ packet.m_nChannel = 0x08; // video channel
packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
- packet.m_packetType = 0x14; // invoke
+ packet.m_packetType = 0x14; // invoke
packet.m_nInfoField1 = 0;
packet.m_nInfoField2 = 0;
packet.m_hasAbsTimestamp = 0;
@@ -941,7 +1031,7 @@ bool RTMP_SendPause(RTMP *r, bool DoPaus
enc += AMF_EncodeNumber(enc, 0);
*enc++ = AMF_NULL;
enc += AMF_EncodeBoolean(enc, DoPause);
- enc += AMF_EncodeNumber(enc, (double)dTime);
+ enc += AMF_EncodeNumber(enc, (double) dTime);
packet.m_nBodySize = enc - packet.m_body;
@@ -950,12 +1040,13 @@ bool RTMP_SendPause(RTMP *r, bool DoPaus
SAVC(seek);
-static bool SendSeek(RTMP *r, double dTime)
+static bool
+SendSeek(RTMP * r, double dTime)
{
RTMPPacket packet;
- packet.m_nChannel = 0x08; // video channel
+ packet.m_nChannel = 0x08; // video channel
packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
- packet.m_packetType = 0x14; // invoke
+ packet.m_packetType = 0x14; // invoke
packet.m_nInfoField1 = 0;
packet.m_nInfoField2 = 0;
packet.m_hasAbsTimestamp = 0;
@@ -971,12 +1062,13 @@ static bool SendSeek(RTMP *r, double dTi
return SendRTMP(r, &packet, true);
}
-static bool SendServerBW(RTMP *r)
+static bool
+SendServerBW(RTMP * r)
{
RTMPPacket packet;
- packet.m_nChannel = 0x02; // control channel (invoke)
+ packet.m_nChannel = 0x02; // control channel (invoke)
packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
- packet.m_packetType = 0x05; // Server BW
+ packet.m_packetType = 0x05; // Server BW
packet.m_nInfoField1 = 0;
packet.m_nInfoField2 = 0;
packet.m_hasAbsTimestamp = 0;
@@ -987,19 +1079,20 @@ static bool SendServerBW(RTMP *r)
return SendRTMP(r, &packet, false);
}
-static bool SendBytesReceived(RTMP *r)
+static bool
+SendBytesReceived(RTMP * r)
{
RTMPPacket packet;
- packet.m_nChannel = 0x02; // control channel (invoke)
+ packet.m_nChannel = 0x02; // control channel (invoke)
packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
- packet.m_packetType = 0x03; // bytes in
+ packet.m_packetType = 0x03; // bytes in
packet.m_nInfoField1 = 0;
packet.m_nInfoField2 = 0;
packet.m_hasAbsTimestamp = 0;
packet.m_nBodySize = 4;
- AMF_EncodeInt32(packet.m_body, r->m_nBytesIn); // hard coded for now
+ AMF_EncodeInt32(packet.m_body, r->m_nBytesIn); // hard coded for now
r->m_nBytesInSent = r->m_nBytesIn;
//Log(LOGDEBUG, "Send bytes report. 0x%x (%d bytes)", (unsigned int)m_nBytesIn, m_nBytesIn);
@@ -1008,12 +1101,13 @@ static bool SendBytesReceived(RTMP *r)
SAVC(_checkbw);
-static bool SendCheckBW(RTMP *r)
+static bool
+SendCheckBW(RTMP * r)
{
RTMPPacket packet;
- packet.m_nChannel = 0x03; // control channel (invoke)
+ packet.m_nChannel = 0x03; // control channel (invoke)
packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
- packet.m_packetType = 0x14; // INVOKE
+ packet.m_packetType = 0x14; // INVOKE
packet.m_nInfoField1 = RTMP_GetTime();
packet.m_nInfoField2 = 0;
packet.m_hasAbsTimestamp = 0;
@@ -1031,13 +1125,14 @@ static bool SendCheckBW(RTMP *r)
SAVC(_result);
-static bool SendCheckBWResult(RTMP *r, double txn)
+static bool
+SendCheckBWResult(RTMP * r, double txn)
{
RTMPPacket packet;
- packet.m_nChannel = 0x03; // control channel (invoke)
+ packet.m_nChannel = 0x03; // control channel (invoke)
packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
- packet.m_packetType = 0x14; // INVOKE
- packet.m_nInfoField1 = 0x16 * r->m_nBWCheckCounter; // temp inc value. till we figure it out.
+ packet.m_packetType = 0x14; // INVOKE
+ packet.m_nInfoField1 = 0x16 * r->m_nBWCheckCounter; // temp inc value. till we figure it out.
packet.m_nInfoField2 = 0;
packet.m_hasAbsTimestamp = 0;
@@ -1045,7 +1140,7 @@ static bool SendCheckBWResult(RTMP *r, d
enc += AMF_EncodeString(enc, &av__result);
enc += AMF_EncodeNumber(enc, txn);
*enc++ = AMF_NULL;
- enc += AMF_EncodeNumber(enc, (double)r->m_nBWCheckCounter++);
+ enc += AMF_EncodeNumber(enc, (double) r->m_nBWCheckCounter++);
packet.m_nBodySize = enc - packet.m_body;
@@ -1054,22 +1149,25 @@ static bool SendCheckBWResult(RTMP *r, d
SAVC(play);
-static bool SendPlay(RTMP *r)
+static bool
+SendPlay(RTMP * r)
{
RTMPPacket packet;
- packet.m_nChannel = 0x08; // we make 8 our stream channel
+ packet.m_nChannel = 0x08; // we make 8 our stream channel
packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
- packet.m_packetType = 0x14; // INVOKE
- packet.m_nInfoField2 = r->m_stream_id; //0x01000000;
+ packet.m_packetType = 0x14; // INVOKE
+ packet.m_nInfoField2 = r->m_stream_id; //0x01000000;
packet.m_nInfoField1 = 0;
packet.m_hasAbsTimestamp = 0;
char *enc = packet.m_body;
enc += AMF_EncodeString(enc, &av_play);
- enc += AMF_EncodeNumber(enc, 0.0); // stream id??
+ enc += AMF_EncodeNumber(enc, 0.0); // stream id??
*enc++ = AMF_NULL;
- Log(LOGDEBUG, "%s, seekTime=%.2f, dLength=%d, sending play: %s", __FUNCTION__, r->Link.seekTime, r->Link.length, r->Link.playpath.av_val);
+ Log(LOGDEBUG, "%s, seekTime=%.2f, dLength=%d, sending play: %s",
+ __FUNCTION__, r->Link.seekTime, r->Link.length,
+ r->Link.playpath.av_val);
enc += AMF_EncodeString(enc, &r->Link.playpath);
// Optional parameters start and len.
@@ -1078,27 +1176,29 @@ static bool SendPlay(RTMP *r)
// -2: looks for a live stream, then a recorded stream, if not found any open a live stream
// -1: plays a live stream
// >=0: plays a recorded streams from 'start' milliseconds
- if(r->Link.bLiveStream)
+ if (r->Link.bLiveStream)
enc += AMF_EncodeNumber(enc, -1000.0);
- else {
- if(r->Link.seekTime > 0.0)
- enc += AMF_EncodeNumber(enc, r->Link.seekTime); // resume from here
- else
- enc += AMF_EncodeNumber(enc, 0.0);//-2000.0); // recorded as default, -2000.0 is not reliable since that freezes the player if the stream is not found
- }
-
+ else
+ {
+ if (r->Link.seekTime > 0.0)
+ enc += AMF_EncodeNumber(enc, r->Link.seekTime); // resume from here
+ else
+ enc += AMF_EncodeNumber(enc, 0.0); //-2000.0); // recorded as default, -2000.0 is not reliable since that freezes the player if the stream is not found
+ }
+
// len: -1, 0, positive number
// -1: plays live or recorded stream to the end (default)
// 0: plays a frame 'start' ms away from the beginning
// >0: plays a live or recoded stream for 'len' milliseconds
//enc += EncodeNumber(enc, -1.0); // len
- if(r->Link.length)
- enc += AMF_EncodeNumber(enc, r->Link.length); // len
+ if (r->Link.length)
+ enc += AMF_EncodeNumber(enc, r->Link.length); // len
packet.m_nBodySize = enc - packet.m_body;
return SendRTMP(r, &packet, true);
}
+
/*
from http://jira.red5.org/confluence/display/docs/Ping:
@@ -1115,20 +1215,21 @@ The type of Ping packet is 0x4 and conta
* type 26: SWFVerification request
* type 27: SWFVerification response
*/
-static bool SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime)
+static bool
+SendCtrl(RTMP * r, short nType, unsigned int nObject, unsigned int nTime)
{
- Log(LOGDEBUG, "sending ctrl. type: 0x%04x", (unsigned short)nType);
+ Log(LOGDEBUG, "sending ctrl. type: 0x%04x", (unsigned short) nType);
- RTMPPacket packet;
- packet.m_nChannel = 0x02; // control channel (ping)
+ RTMPPacket packet;
+ packet.m_nChannel = 0x02; // control channel (ping)
packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
- packet.m_packetType = 0x04; // ctrl
+ packet.m_packetType = 0x04; // ctrl
packet.m_nInfoField1 = RTMP_GetTime();
packet.m_nInfoField2 = 0;
packet.m_hasAbsTimestamp = 0;
- int nSize = (nType==0x03?10:6); // type 3 is the buffer time and requires all 3 parameters. all in all 10 bytes.
- if(nType == 0x1B)
+ int nSize = (nType == 0x03 ? 10 : 6); // type 3 is the buffer time and requires all 3 parameters. all in all 10 bytes.
+ if (nType == 0x1B)
nSize = 44;
packet.m_nBodySize = nSize;
@@ -1136,51 +1237,58 @@ static bool SendCtrl(RTMP *r, short nTyp
char *buf = packet.m_body;
buf += AMF_EncodeInt16(buf, nType);
- if(nType == 0x1B) {
+ if (nType == 0x1B)
+ {
#ifdef CRYPTO
- memcpy(buf, r->Link.SWFVerificationResponse, 42);
- Log(LOGDEBUG, "Sending SWFVerification response: ");
- LogHex(LOGDEBUG, packet.m_body, packet.m_nBodySize);
+ memcpy(buf, r->Link.SWFVerificationResponse, 42);
+ Log(LOGDEBUG, "Sending SWFVerification response: ");
+ LogHex(LOGDEBUG, packet.m_body, packet.m_nBodySize);
#endif
- } else {
- if (nSize > 2)
- buf += AMF_EncodeInt32(buf, nObject);
+ }
+ else
+ {
+ if (nSize > 2)
+ buf += AMF_EncodeInt32(buf, nObject);
+
+ if (nSize > 6)
+ buf += AMF_EncodeInt32(buf, nTime);
+ }
- if (nSize > 6)
- buf += AMF_EncodeInt32(buf, nTime);
- }
-
return SendRTMP(r, &packet, false);
}
-static void AV_erase(AVal *vals, int *num, int i, bool freeit)
+static void
+AV_erase(AVal * vals, int *num, int i, bool freeit)
{
if (freeit)
free(vals[i].av_val);
(*num)--;
- for (; i<*num; i++) {
- vals[i] = vals[i+1];
- }
+ for (; i < *num; i++)
+ {
+ vals[i] = vals[i + 1];
+ }
vals[i].av_val = NULL;
vals[i].av_len = 0;
}
-static void AV_queue(AVal **vals, int *num, AVal *av)
+static void
+AV_queue(AVal ** vals, int *num, AVal * av)
{
char *tmp;
if (!(*num & 0x0f))
- *vals = realloc(*vals, (*num+16) * sizeof(AVal));
- tmp = malloc(av->av_len+1);
+ *vals = realloc(*vals, (*num + 16) * sizeof(AVal));
+ tmp = malloc(av->av_len + 1);
memcpy(tmp, av->av_val, av->av_len);
tmp[av->av_len] = '\0';
(*vals)[*num].av_len = av->av_len;
(*vals)[(*num)++].av_val = tmp;
}
-static void AV_clear(AVal *vals, int num)
+static void
+AV_clear(AVal * vals, int num)
{
int i;
- for (i=0;i<num;i++)
+ for (i = 0; i < num; i++)
free(vals[i].av_val);
free(vals);
}
@@ -1197,29 +1305,33 @@ SAVC(level);
SAVC(onStatus);
static const AVal av_NetStream_Failed = AVC("NetStream.Failed");
static const AVal av_NetStream_Play_Failed = AVC("NetStream.Play.Failed");
-static const AVal av_NetStream_Play_StreamNotFound = AVC("NetStream.Play.StreamNotFound");
-static const AVal av_NetConnection_Connect_InvalidApp = AVC("NetConnection.Connect.InvalidApp");
+static const AVal av_NetStream_Play_StreamNotFound =
+AVC("NetStream.Play.StreamNotFound");
+static const AVal av_NetConnection_Connect_InvalidApp =
+AVC("NetConnection.Connect.InvalidApp");
static const AVal av_NetStream_Play_Start = AVC("NetStream.Play.Start");
static const AVal av_NetStream_Play_Complete = AVC("NetStream.Play.Complete");
static const AVal av_NetStream_Play_Stop = AVC("NetStream.Play.Stop");
// Returns 0 for OK/Failed/error, 1 for 'Stop or Complete'
-static int HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
+static int
+HandleInvoke(RTMP * r, const char *body, unsigned int nBodySize)
{
int ret = 0, nRes;
- if (body[0] != 0x02) // make sure it is a string method name we start with
- {
- Log(LOGWARNING, "%s, Sanity failed. no string method in invoke packet", __FUNCTION__);
- return 0;
- }
+ if (body[0] != 0x02) // make sure it is a string method name we start with
+ {
+ Log(LOGWARNING, "%s, Sanity failed. no string method in invoke packet",
+ __FUNCTION__);
+ return 0;
+ }
AMFObject obj;
nRes = AMF_Decode(&obj, body, nBodySize, false);
if (nRes < 0)
- {
- Log(LOGERROR, "%s, error decoding invoke packet", __FUNCTION__);
- return 0;
- }
+ {
+ Log(LOGERROR, "%s, error decoding invoke packet", __FUNCTION__);
+ return 0;
+ }
AMF_Dump(&obj);
AVal method;
@@ -1228,372 +1340,432 @@ static int HandleInvoke(RTMP *r, const c
Log(LOGDEBUG, "%s, server invoking <%s>", __FUNCTION__, method.av_val);
if (AVMATCH(&method, &av__result))
- {
- AVal methodInvoked = r->m_methodCalls[0];
- AV_erase(r->m_methodCalls, &r->m_numCalls, 0, false);
-
- Log(LOGDEBUG, "%s, received result for method call <%s>", __FUNCTION__, methodInvoked.av_val);
-
- if (AVMATCH(&methodInvoked,&av_connect))
{
- SendServerBW(r);
- SendCtrl(r, 3, 0, 300);
+ AVal methodInvoked = r->m_methodCalls[0];
+ AV_erase(r->m_methodCalls, &r->m_numCalls, 0, false);
- SendCreateStream(r, 2.0);
+ Log(LOGDEBUG, "%s, received result for method call <%s>", __FUNCTION__,
+ methodInvoked.av_val);
- // Send the FCSubscribe if live stream or if subscribepath is set
- if (r->Link.subscribepath.av_len)
- SendFCSubscribe(r, &r->Link.subscribepath);
- else if (r->Link.bLiveStream)
- SendFCSubscribe(r, &r->Link.playpath);
+ if (AVMATCH(&methodInvoked, &av_connect))
+ {
+ SendServerBW(r);
+ SendCtrl(r, 3, 0, 300);
+
+ SendCreateStream(r, 2.0);
+
+ // Send the FCSubscribe if live stream or if subscribepath is set
+ if (r->Link.subscribepath.av_len)
+ SendFCSubscribe(r, &r->Link.subscribepath);
+ else if (r->Link.bLiveStream)
+ SendFCSubscribe(r, &r->Link.playpath);
+ }
+ else if (AVMATCH(&methodInvoked, &av_createStream))
+ {
+ r->m_stream_id =
+ (int) AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3));
+
+ SendPlay(r);
+ SendCtrl(r, 3, r->m_stream_id, r->m_nBufferMS);
+ }
+ else if (AVMATCH(&methodInvoked, &av_play))
+ {
+ r->m_bPlaying = true;
+ }
+ free(methodInvoked.av_val);
}
- else if (AVMATCH(&methodInvoked,&av_createStream))
+ else if (AVMATCH(&method, &av_onBWDone))
{
- r->m_stream_id = (int)AMFProp_GetNumber(AMF_GetProp(&obj,NULL,3));
-
- SendPlay(r);
- SendCtrl(r, 3, r->m_stream_id, r->m_nBufferMS);
+ SendCheckBW(r);
}
- else if (AVMATCH(&methodInvoked,&av_play))
+ else if (AVMATCH(&method, &av_onFCSubscribe))
{
- r->m_bPlaying = true;
+ // SendOnFCSubscribe();
}
- free(methodInvoked.av_val);
- }
- else if (AVMATCH(&method,&av_onBWDone))
- {
- SendCheckBW(r);
- }
- else if (AVMATCH(&method,&av_onFCSubscribe))
- {
- // SendOnFCSubscribe();
- }
- else if (AVMATCH(&method,&av_onFCUnsubscribe))
- {
- RTMP_Close(r);
- ret = 1;
- }
- else if (AVMATCH(&method,&av__onbwcheck))
- {
- SendCheckBWResult(r, txn);
- }
- else if (AVMATCH(&method,&av__onbwdone))
- {
- int i;
- for (i=0; i<r->m_numCalls; i++)
- if (AVMATCH(&r->m_methodCalls[i],&av__checkbw)) {
- AV_erase(r->m_methodCalls, &r->m_numCalls, i, true);
- break;
- }
- }
- else if (AVMATCH(&method,&av__error))
- {
- Log(LOGERROR, "rtmp server sent error");
- }
- else if (AVMATCH(&method,&av_close))
- {
- Log(LOGERROR, "rtmp server requested close");
- RTMP_Close(r);
- }
- else if (AVMATCH(&method,&av_onStatus))
- {
- AMFObject obj2;
- AVal code, level;
- AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2);
- AMFProp_GetString(AMF_GetProp(&obj2, &av_code, -1), &code);
- AMFProp_GetString(AMF_GetProp(&obj2, &av_level, -1), &level);
-
- Log(LOGDEBUG, "%s, onStatus: %s", __FUNCTION__, code.av_val );
- if (AVMATCH(&code,&av_NetStream_Failed)
- || AVMATCH(&code,&av_NetStream_Play_Failed)
- || AVMATCH(&code,&av_NetStream_Play_StreamNotFound)
- || AVMATCH(&code,&av_NetConnection_Connect_InvalidApp)) {
- r->m_stream_id = -1;
+ else if (AVMATCH(&method, &av_onFCUnsubscribe))
+ {
RTMP_Close(r);
+ ret = 1;
}
-
- if (AVMATCH(&code, &av_NetStream_Play_Start)) {
+ else if (AVMATCH(&method, &av__onbwcheck))
+ {
+ SendCheckBWResult(r, txn);
+ }
+ else if (AVMATCH(&method, &av__onbwdone))
+ {
int i;
- r->m_bPlaying = true;
- for (i=0; i<r->m_numCalls; i++) {
- if (AVMATCH(&r->m_methodCalls[i], &av_play)) {
- AV_erase(r->m_methodCalls, &r->m_numCalls, i, true);
- break;
- }
- }
+ for (i = 0; i < r->m_numCalls; i++)
+ if (AVMATCH(&r->m_methodCalls[i], &av__checkbw))
+ {
+ AV_erase(r->m_methodCalls, &r->m_numCalls, i, true);
+ break;
+ }
}
-
- // Return 1 if this is a Play.Complete or Play.Stop
- if (AVMATCH(&code,&av_NetStream_Play_Complete)
- || AVMATCH(&code,&av_NetStream_Play_Stop)) {
+ else if (AVMATCH(&method, &av__error))
+ {
+ Log(LOGERROR, "rtmp server sent error");
+ }
+ else if (AVMATCH(&method, &av_close))
+ {
+ Log(LOGERROR, "rtmp server requested close");
RTMP_Close(r);
- ret = 1;
}
- }
+ else if (AVMATCH(&method, &av_onStatus))
+ {
+ AMFObject obj2;
+ AVal code, level;
+ AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2);
+ AMFProp_GetString(AMF_GetProp(&obj2, &av_code, -1), &code);
+ AMFProp_GetString(AMF_GetProp(&obj2, &av_level, -1), &level);
+
+ Log(LOGDEBUG, "%s, onStatus: %s", __FUNCTION__, code.av_val);
+ if (AVMATCH(&code, &av_NetStream_Failed)
+ || AVMATCH(&code, &av_NetStream_Play_Failed)
+ || AVMATCH(&code, &av_NetStream_Play_StreamNotFound)
+ || AVMATCH(&code, &av_NetConnection_Connect_InvalidApp))
+ {
+ r->m_stream_id = -1;
+ RTMP_Close(r);
+ }
+
+ if (AVMATCH(&code, &av_NetStream_Play_Start))
+ {
+ int i;
+ r->m_bPlaying = true;
+ for (i = 0; i < r->m_numCalls; i++)
+ {
+ if (AVMATCH(&r->m_methodCalls[i], &av_play))
+ {
+ AV_erase(r->m_methodCalls, &r->m_numCalls, i, true);
+ break;
+ }
+ }
+ }
+
+ // Return 1 if this is a Play.Complete or Play.Stop
+ if (AVMATCH(&code, &av_NetStream_Play_Complete)
+ || AVMATCH(&code, &av_NetStream_Play_Stop))
+ {
+ RTMP_Close(r);
+ ret = 1;
+ }
+ }
else
- {
+ {
- }
+ }
AMF_Reset(&obj);
return ret;
}
-bool RTMP_FindFirstMatchingProperty(AMFObject *obj, const AVal *name, AMFObjectProperty *p)
+bool
+RTMP_FindFirstMatchingProperty(AMFObject * obj, const AVal * name,
+ AMFObjectProperty * p)
{
- int n;
- /* this is a small object search to locate the "duration" property */
- for (n=0; n<obj->o_num; n++) {
- AMFObjectProperty *prop = AMF_GetProp(obj, NULL, n);
+ int n;
+ /* this is a small object search to locate the "duration" property */
+ for (n = 0; n < obj->o_num; n++)
+ {
+ AMFObjectProperty *prop = AMF_GetProp(obj, NULL, n);
- if(AVMATCH(&prop->p_name, name)) {
- *p = *prop;
- return true;
- }
+ if (AVMATCH(&prop->p_name, name))
+ {
+ *p = *prop;
+ return true;
+ }
- if(prop->p_type == AMF_OBJECT) {
- return RTMP_FindFirstMatchingProperty(&prop->p_vu.p_object, name, p);
- }
+ if (prop->p_type == AMF_OBJECT)
+ {
+ return RTMP_FindFirstMatchingProperty(&prop->p_vu.p_object, name,
+ p);
}
- return false;
+ }
+ return false;
}
-static bool DumpMetaData(AMFObject *obj)
+static bool
+DumpMetaData(AMFObject * obj)
{
- AMFObjectProperty *prop;
- int n;
- for (n=0; n<obj->o_num; n++) {
- prop = AMF_GetProp(obj, NULL, n);
- if ( prop->p_type != AMF_OBJECT ) {
- char str[256]="";
- switch( prop->p_type )
- {
- case AMF_NUMBER:
- snprintf(str, 255, "%.2f", prop->p_vu.p_number);
- break;
- case AMF_BOOLEAN:
- snprintf(str, 255, "%s", prop->p_vu.p_number != 0.?"TRUE":"FALSE");
- break;
- case AMF_STRING:
- snprintf(str, 255, "%.*s", prop->p_vu.p_aval.av_len, prop->p_vu.p_aval.av_val);
- break;
- case AMF_DATE:
- snprintf(str, 255, "timestamp:%.2f", prop->p_vu.p_number);
- break;
- default:
- snprintf(str, 255, "INVALID TYPE 0x%02x", (unsigned char)prop->p_type );
- }
- if ( prop->p_name.av_len ) {
- // chomp
- if ( strlen(str) >= 1 && str[strlen(str)-1 ] == '\n')
- str[strlen(str)-1] = '\0';
- LogPrintf(" %-22.*s%s\n", prop->p_name.av_len, prop->p_name.av_val, str );
- }
- } else {
- if ( prop->p_name.av_len )
- LogPrintf("%.*s:\n", prop->p_name.av_len, prop->p_name.av_val );
- DumpMetaData(&prop->p_vu.p_object);
- }
+ AMFObjectProperty *prop;
+ int n;
+ for (n = 0; n < obj->o_num; n++)
+ {
+ prop = AMF_GetProp(obj, NULL, n);
+ if (prop->p_type != AMF_OBJECT)
+ {
+ char str[256] = "";
+ switch (prop->p_type)
+ {
+ case AMF_NUMBER:
+ snprintf(str, 255, "%.2f", prop->p_vu.p_number);
+ break;
+ case AMF_BOOLEAN:
+ snprintf(str, 255, "%s",
+ prop->p_vu.p_number != 0. ? "TRUE" : "FALSE");
+ break;
+ case AMF_STRING:
+ snprintf(str, 255, "%.*s", prop->p_vu.p_aval.av_len,
+ prop->p_vu.p_aval.av_val);
+ break;
+ case AMF_DATE:
+ snprintf(str, 255, "timestamp:%.2f", prop->p_vu.p_number);
+ break;
+ default:
+ snprintf(str, 255, "INVALID TYPE 0x%02x",
+ (unsigned char) prop->p_type);
+ }
+ if (prop->p_name.av_len)
+ {
+ // chomp
+ if (strlen(str) >= 1 && str[strlen(str) - 1] == '\n')
+ str[strlen(str) - 1] = '\0';
+ LogPrintf(" %-22.*s%s\n", prop->p_name.av_len,
+ prop->p_name.av_val, str);
+ }
}
- return false;
+ else
+ {
+ if (prop->p_name.av_len)
+ LogPrintf("%.*s:\n", prop->p_name.av_len, prop->p_name.av_val);
+ DumpMetaData(&prop->p_vu.p_object);
+ }
+ }
+ return false;
}
SAVC(onMetaData);
SAVC(duration);
-static bool HandleMetadata(RTMP *r, char *body, unsigned int len)
+static bool
+HandleMetadata(RTMP * r, char *body, unsigned int len)
{
- // allright we get some info here, so parse it and print it
- // also keep duration or filesize to make a nice progress bar
+ // allright we get some info here, so parse it and print it
+ // also keep duration or filesize to make a nice progress bar
- AMFObject obj;
- AVal metastring;
- bool ret = false;
+ AMFObject obj;
+ AVal metastring;
+ bool ret = false;
- int nRes = AMF_Decode(&obj, body, len, false);
- if(nRes < 0) {
- Log(LOGERROR, "%s, error decoding meta data packet", __FUNCTION__);
- return false;
- }
+ int nRes = AMF_Decode(&obj, body, len, false);
+ if (nRes < 0)
+ {
+ Log(LOGERROR, "%s, error decoding meta data packet", __FUNCTION__);
+ return false;
+ }
- AMF_Dump(&obj);
- AMFProp_GetString(AMF_GetProp(&obj, NULL, 0), &metastring);
+ AMF_Dump(&obj);
+ AMFProp_GetString(AMF_GetProp(&obj, NULL, 0), &metastring);
- if(AVMATCH(&metastring, &av_onMetaData)) {
- AMFObjectProperty prop;
- // Show metadata
- LogPrintf("\r%s\n", "Metadata: " );
- DumpMetaData(&obj);
- if(RTMP_FindFirstMatchingProperty(&obj, &av_duration, &prop)) {
- r->m_fDuration = prop.p_vu.p_number;
- //Log(LOGDEBUG, "Set duration: %.2f", m_fDuration);
- }
- ret = true;
+ if (AVMATCH(&metastring, &av_onMetaData))
+ {
+ AMFObjectProperty prop;
+ // Show metadata
+ LogPrintf("\r%s\n", "Metadata: ");
+ DumpMetaData(&obj);
+ if (RTMP_FindFirstMatchingProperty(&obj, &av_duration, &prop))
+ {
+ r->m_fDuration = prop.p_vu.p_number;
+ //Log(LOGDEBUG, "Set duration: %.2f", m_fDuration);
}
- AMF_Reset(&obj);
- return ret;
+ ret = true;
+ }
+ AMF_Reset(&obj);
+ return ret;
}
-static void HandleChangeChunkSize(RTMP *r, const RTMPPacket *packet)
+static void
+HandleChangeChunkSize(RTMP * r, const RTMPPacket * packet)
{
if (packet->m_nBodySize >= 4)
- {
- r->m_chunkSize = AMF_DecodeInt32(packet->m_body);
- Log(LOGDEBUG, "%s, received: chunk size change to %d", __FUNCTION__, r->m_chunkSize);
- }
+ {
+ r->m_chunkSize = AMF_DecodeInt32(packet->m_body);
+ Log(LOGDEBUG, "%s, received: chunk size change to %d", __FUNCTION__,
+ r->m_chunkSize);
+ }
}
-static void HandleAudio(RTMP *r, const RTMPPacket *packet)
+static void
+HandleAudio(RTMP * r, const RTMPPacket * packet)
{
}
-static void HandleVideo(RTMP *r, const RTMPPacket *packet)
+static void
+HandleVideo(RTMP * r, const RTMPPacket * packet)
{
}
-static void HandleCtrl(RTMP *r, const RTMPPacket *packet)
+static void
+HandleCtrl(RTMP * r, const RTMPPacket * packet)
{
short nType = -1;
unsigned int tmp;
if (packet->m_body && packet->m_nBodySize >= 2)
nType = AMF_DecodeInt16(packet->m_body);
- Log(LOGDEBUG, "%s, received ctrl. type: %d, len: %d", __FUNCTION__, nType, packet->m_nBodySize);
+ Log(LOGDEBUG, "%s, received ctrl. type: %d, len: %d", __FUNCTION__, nType,
+ packet->m_nBodySize);
//LogHex(packet.m_body, packet.m_nBodySize);
- if (packet->m_nBodySize >= 6) {
- switch(nType) {
- case 0:
- tmp = AMF_DecodeInt32(packet->m_body + 2);
- Log(LOGDEBUG, "%s, Stream Begin %d", __FUNCTION__, tmp);
- break;
+ if (packet->m_nBodySize >= 6)
+ {
+ switch (nType)
+ {
+ case 0:
+ tmp = AMF_DecodeInt32(packet->m_body + 2);
+ Log(LOGDEBUG, "%s, Stream Begin %d", __FUNCTION__, tmp);
+ break;
- case 1:
- tmp = AMF_DecodeInt32(packet->m_body + 2);
- Log(LOGDEBUG, "%s, Stream EOF %d", __FUNCTION__, tmp);
- if (r->m_pausing == 1)
- r->m_pausing = 2;
- break;
+ case 1:
+ tmp = AMF_DecodeInt32(packet->m_body + 2);
+ Log(LOGDEBUG, "%s, Stream EOF %d", __FUNCTION__, tmp);
+ if (r->m_pausing == 1)
+ r->m_pausing = 2;
+ break;
- case 2:
- tmp = AMF_DecodeInt32(packet->m_body + 2);
- Log(LOGDEBUG, "%s, Stream Dry %d", __FUNCTION__, tmp);
- break;
+ case 2:
+ tmp = AMF_DecodeInt32(packet->m_body + 2);
+ Log(LOGDEBUG, "%s, Stream Dry %d", __FUNCTION__, tmp);
+ break;
- case 4:
- tmp = AMF_DecodeInt32(packet->m_body + 2);
- Log(LOGDEBUG, "%s, Stream IsRecorded %d", __FUNCTION__, tmp);
- break;
+ case 4:
+ tmp = AMF_DecodeInt32(packet->m_body + 2);
+ Log(LOGDEBUG, "%s, Stream IsRecorded %d", __FUNCTION__, tmp);
+ break;
- case 6: // server ping. reply with pong.
- tmp = AMF_DecodeInt32(packet->m_body + 2);
- Log(LOGDEBUG, "%s, Ping %d", __FUNCTION__, tmp);
- SendCtrl(r, 0x07, tmp, 0);
- break;
+ case 6: // server ping. reply with pong.
+ tmp = AMF_DecodeInt32(packet->m_body + 2);
+ Log(LOGDEBUG, "%s, Ping %d", __FUNCTION__, tmp);
+ SendCtrl(r, 0x07, tmp, 0);
+ break;
- case 31:
- tmp = AMF_DecodeInt32(packet->m_body + 2);
- Log(LOGDEBUG, "%s, Stream BufferEmpty %d", __FUNCTION__, tmp);
- if (!r->m_pausing) {
- r->m_pauseStamp = r->m_channelTimestamp[r->m_mediaChannel];
- RTMP_SendPause(r, true, r->m_pauseStamp);
- r->m_pausing = 1;
- } else if (r->m_pausing == 2) {
- RTMP_SendPause(r, false, r->m_pauseStamp);
- r->m_pausing = 3;
- }
- break;
+ case 31:
+ tmp = AMF_DecodeInt32(packet->m_body + 2);
+ Log(LOGDEBUG, "%s, Stream BufferEmpty %d", __FUNCTION__, tmp);
+ if (!r->m_pausing)
+ {
+ r->m_pauseStamp = r->m_channelTimestamp[r->m_mediaChannel];
+ RTMP_SendPause(r, true, r->m_pauseStamp);
+ r->m_pausing = 1;
+ }
+ else if (r->m_pausing == 2)
+ {
+ RTMP_SendPause(r, false, r->m_pauseStamp);
+ r->m_pausing = 3;
+ }
+ break;
- case 32:
- tmp = AMF_DecodeInt32(packet->m_body + 2);
- Log(LOGDEBUG, "%s, Stream BufferReady %d", __FUNCTION__, tmp);
- break;
+ case 32:
+ tmp = AMF_DecodeInt32(packet->m_body + 2);
+ Log(LOGDEBUG, "%s, Stream BufferReady %d", __FUNCTION__, tmp);
+ break;
- default:
- tmp = AMF_DecodeInt32(packet->m_body + 2);
- Log(LOGDEBUG, "%s, Stream xx %d", __FUNCTION__, tmp);
- break;
- }
+ default:
+ tmp = AMF_DecodeInt32(packet->m_body + 2);
+ Log(LOGDEBUG, "%s, Stream xx %d", __FUNCTION__, tmp);
+ break;
+ }
- }
+ }
- if (nType == 0x1A) {
- Log(LOGDEBUG, "%s, SWFVerification ping received: ", __FUNCTION__);
- //LogHex(packet.m_body, packet.m_nBodySize);
+ if (nType == 0x1A)
+ {
+ Log(LOGDEBUG, "%s, SWFVerification ping received: ", __FUNCTION__);
+ //LogHex(packet.m_body, packet.m_nBodySize);
- // respond with HMAC SHA256 of decompressed SWF, key is the 30byte player key, also the last 30 bytes of the server handshake are applied
- if(r->Link.SWFHash.av_len) {
+ // respond with HMAC SHA256 of decompressed SWF, key is the 30byte player key, also the last 30 bytes of the server handshake are applied
+ if (r->Link.SWFHash.av_len)
+ {
SendCtrl(r, 0x1B, 0, 0);
- } else {
- Log(LOGWARNING, "%s: Ignoring SWFVerification request, use --swfhash and --swfsize!", __FUNCTION__);
}
- }
+ else
+ {
+ Log(LOGWARNING,
+ "%s: Ignoring SWFVerification request, use --swfhash and --swfsize!",
+ __FUNCTION__);
+ }
+ }
}
-static void HandleServerBW(RTMP *r, const RTMPPacket *packet) {
+static void
+HandleServerBW(RTMP * r, const RTMPPacket * packet)
+{
r->m_nServerBW = AMF_DecodeInt32(packet->m_body);
Log(LOGDEBUG, "%s: server BW = %d", __FUNCTION__, r->m_nServerBW);
}
-static void HandleClientBW(RTMP *r, const RTMPPacket *packet) {
+static void
+HandleClientBW(RTMP * r, const RTMPPacket * packet)
+{
r->m_nClientBW = AMF_DecodeInt32(packet->m_body);
if (packet->m_nBodySize > 4)
r->m_nClientBW2 = packet->m_body[4];
else
r->m_nClientBW2 = -1;
- Log(LOGDEBUG, "%s: client BW = %d %d", __FUNCTION__, r->m_nClientBW, r->m_nClientBW2);
+ Log(LOGDEBUG, "%s: client BW = %d %d", __FUNCTION__, r->m_nClientBW,
+ r->m_nClientBW2);
}
-static bool ReadPacket(RTMP *r, RTMPPacket *packet)
+static bool
+ReadPacket(RTMP * r, RTMPPacket * packet)
{
char type;
- if (ReadN(r, &type,1) == 0)
- {
- Log(LOGERROR, "%s, failed to read RTMP packet header", __FUNCTION__);
- return false;
- }
+ if (ReadN(r, &type, 1) == 0)
+ {
+ Log(LOGERROR, "%s, failed to read RTMP packet header", __FUNCTION__);
+ return false;
+ }
+
+ if (packet->m_nBodySize && RTMPPacket_IsReady(packet))
+ RTMPPacket_Reset(packet);
packet->m_headerType = (type & 0xc0) >> 6;
packet->m_nChannel = (type & 0x3f);
- if ( packet->m_nChannel == 0 )
- {
- if (ReadN(r,&type,1) != 1)
+ if (packet->m_nChannel == 0)
+ {
+ if (ReadN(r, &type, 1) != 1)
{
- Log(LOGERROR, "%s, failed to read RTMP packet header 2nd byte", __FUNCTION__);
+ Log(LOGERROR, "%s, failed to read RTMP packet header 2nd byte",
+ __FUNCTION__);
return false;
- }
- packet->m_nChannel = (unsigned)type;
- packet->m_nChannel += 64;
- } else if ( packet->m_nChannel == 1 )
- {
- char t[2];
- int tmp;
- if (ReadN(r,t,2) != 2)
+ }
+ packet->m_nChannel = (unsigned) type;
+ packet->m_nChannel += 64;
+ }
+ else if (packet->m_nChannel == 1)
+ {
+ char t[2];
+ int tmp;
+ if (ReadN(r, t, 2) != 2)
{
- Log(LOGERROR, "%s, failed to read RTMP packet header 3nd byte", __FUNCTION__);
+ Log(LOGERROR, "%s, failed to read RTMP packet header 3nd byte",
+ __FUNCTION__);
return false;
- }
- tmp = (((unsigned)t[1])<<8) + (unsigned)t[0];
- packet->m_nChannel = tmp + 64;
- Log(LOGDEBUG, "%s, m_nChannel: %0x", __FUNCTION__, packet->m_nChannel);
- }
+ }
+ tmp = (((unsigned) t[1]) << 8) + (unsigned) t[0];
+ packet->m_nChannel = tmp + 64;
+ Log(LOGDEBUG, "%s, m_nChannel: %0x", __FUNCTION__, packet->m_nChannel);
+ }
int nSize = packetSize[packet->m_headerType];
-
- if (nSize == RTMP_LARGE_HEADER_SIZE) // if we get a full header the timestamp is absolute
- packet->m_hasAbsTimestamp = true;
- if (nSize < RTMP_LARGE_HEADER_SIZE) { // using values from the last message of this channel
- if (r->m_vecChannelsIn[packet->m_nChannel])
- memcpy(packet, r->m_vecChannelsIn[packet->m_nChannel], offsetof(RTMPPacket,m_header));
- }
-
+ if (nSize == RTMP_LARGE_HEADER_SIZE) // if we get a full header the timestamp is absolute
+ packet->m_hasAbsTimestamp = true;
+
+ if (nSize < RTMP_LARGE_HEADER_SIZE)
+ { // using values from the last message of this channel
+ if (r->m_vecChannelsIn[packet->m_nChannel])
+ memcpy(packet, r->m_vecChannelsIn[packet->m_nChannel],
+ offsetof(RTMPPacket, m_header));
+ }
+
nSize--;
char *header = packet->m_header;
- if (nSize > 0 && ReadN(r, header,nSize) != nSize)
- {
- Log(LOGERROR, "%s, failed to read RTMP packet header. type: %x", __FUNCTION__, (unsigned int)type);
- return false;
- }
+ if (nSize > 0 && ReadN(r, header, nSize) != nSize)
+ {
+ Log(LOGERROR, "%s, failed to read RTMP packet header. type: %x",
+ __FUNCTION__, (unsigned int) type);
+ return false;
+ }
if (nSize >= 3)
packet->m_nInfoField1 = AMF_DecodeInt24(header);
@@ -1601,67 +1773,72 @@ static bool ReadPacket(RTMP *r, RTMPPack
//Log(LOGDEBUG, "%s, reading RTMP packet chunk on channel %x, headersz %i, timestamp %i, abs timestamp %i", __FUNCTION__, packet.m_nChannel, nSize, packet.m_nInfoField1, packet.m_hasAbsTimestamp);
if (nSize >= 6)
- {
- packet->m_nBodySize = AMF_DecodeInt24(header + 3);
- packet->m_nBytesRead = 0;
- }
-
+ {
+ packet->m_nBodySize = AMF_DecodeInt24(header + 3);
+ packet->m_nBytesRead = 0;
+ }
+
if (nSize > 6)
packet->m_packetType = header[6];
if (nSize == 11)
- packet->m_nInfoField2 = ReadInt32LE(header+7);
+ packet->m_nInfoField2 = ReadInt32LE(header + 7);
int nToRead = packet->m_nBodySize - packet->m_nBytesRead;
int nChunk = r->m_chunkSize;
if (nToRead < nChunk)
- nChunk = nToRead;
+ nChunk = nToRead;
if (ReadN(r, packet->m_body + packet->m_nBytesRead, nChunk) != nChunk)
- {
- Log(LOGERROR, "%s, failed to read RTMP packet body. len: %lu", __FUNCTION__, packet->m_nBodySize);
- return false;
- }
+ {
+ Log(LOGERROR, "%s, failed to read RTMP packet body. len: %lu",
+ __FUNCTION__, packet->m_nBodySize);
+ return false;
+ }
packet->m_nBytesRead += nChunk;
// keep the packet as ref for other packets on this channel
if (!r->m_vecChannelsIn[packet->m_nChannel])
- r->m_vecChannelsIn[packet->m_nChannel] = malloc(offsetof(RTMPPacket,m_header));
- memcpy(r->m_vecChannelsIn[packet->m_nChannel], packet, offsetof(RTMPPacket,m_header));
+ r->m_vecChannelsIn[packet->m_nChannel] =
+ malloc(offsetof(RTMPPacket, m_header));
+ memcpy(r->m_vecChannelsIn[packet->m_nChannel], packet,
+ offsetof(RTMPPacket, m_header));
if (RTMPPacket_IsReady(packet))
- {
- packet->m_nTimeStamp = packet->m_nInfoField1;
-
- // make packet's timestamp absolute
- if (!packet->m_hasAbsTimestamp)
- packet->m_nTimeStamp += r->m_channelTimestamp[packet->m_nChannel]; // timestamps seem to be always relative!!
-
- r->m_channelTimestamp[packet->m_nChannel] = packet->m_nTimeStamp;
-
- // reset the data from the stored packet. we keep the header since we may use it later if a new packet for this channel
- // arrives and requests to re-use some info (small packet header)
- r->m_vecChannelsIn[packet->m_nChannel]->m_nBytesRead = 0;
- r->m_vecChannelsIn[packet->m_nChannel]->m_hasAbsTimestamp = false; // can only be false if we reuse header
- }
+ {
+ packet->m_nTimeStamp = packet->m_nInfoField1;
+
+ // make packet's timestamp absolute
+ if (!packet->m_hasAbsTimestamp)
+ packet->m_nTimeStamp += r->m_channelTimestamp[packet->m_nChannel]; // timestamps seem to be always relative!!
+
+ r->m_channelTimestamp[packet->m_nChannel] = packet->m_nTimeStamp;
+
+ // reset the data from the stored packet. we keep the header since we may use it later if a new packet for this channel
+ // arrives and requests to re-use some info (small packet header)
+ r->m_vecChannelsIn[packet->m_nChannel]->m_nBytesRead = 0;
+ r->m_vecChannelsIn[packet->m_nChannel]->m_hasAbsTimestamp = false; // can only be false if we reuse header
+ }
return true;
}
-static int EncodeString(char *output, const AVal *strName, const AVal *strValue)
+static int
+EncodeString(char *output, const AVal * strName, const AVal * strValue)
{
char *buf = output;
buf += AMF_EncodeInt16(output, strName->av_len);
memcpy(buf, strName->av_val, strName->av_len);
buf += strName->av_len;
-
+
buf += AMF_EncodeString(buf, strValue);
return buf - output;
}
-static int EncodeNumber(char *output, const AVal *strName, double dVal)
+static int
+EncodeNumber(char *output, const AVal * strName, double dVal)
{
char *buf = output;
buf += AMF_EncodeInt16(output, strName->av_len);
@@ -1673,7 +1850,8 @@ static int EncodeNumber(char *output, co
return buf - output;
}
-static int EncodeBoolean(char *output, const AVal *strName, bool bVal)
+static int
+EncodeBoolean(char *output, const AVal * strName, bool bVal)
{
char *buf = output;
buf += AMF_EncodeInt16(output, strName->av_len);
@@ -1689,38 +1867,40 @@ static int EncodeBoolean(char *output, c
#ifdef CRYPTO
#include "hand2.c"
#else
-static bool HandShake(RTMP *r, bool FP9HandShake)
+static bool
+HandShake(RTMP * r, bool FP9HandShake)
{
int i;
- char clientsig[RTMP_SIG_SIZE+1];
+ char clientsig[RTMP_SIG_SIZE + 1];
char serversig[RTMP_SIG_SIZE];
- clientsig[0] = 0x03; // not encrypted
-
+ clientsig[0] = 0x03; // not encrypted
+
uint32_t uptime = htonl(RTMP_GetTime());
memcpy(clientsig + 1, &uptime, 4);
memset(&clientsig[5], 0, 4);
#ifdef _DEBUG
- for (i=9; i<RTMP_SIG_SIZE; i++)
- clientsig[i] = 0xff;
+ for (i = 9; i < RTMP_SIG_SIZE; i++)
+ clientsig[i] = 0xff;
#else
- for (i=9; i<RTMP_SIG_SIZE; i++)
- clientsig[i] = (char)(rand() % 256);
+ for (i = 9; i < RTMP_SIG_SIZE; i++)
+ clientsig[i] = (char) (rand() % 256);
#endif
if (!WriteN(r, clientsig, RTMP_SIG_SIZE + 1))
return false;
char type;
- if (ReadN(r, &type, 1) != 1) // 0x03 or 0x06
+ if (ReadN(r, &type, 1) != 1) // 0x03 or 0x06
return false;
Log(LOGDEBUG, "%s: Type Answer : %02X", __FUNCTION__, type);
-
- if(type != clientsig[0])
- Log(LOGWARNING, "%s: Type mismatch: client sent %d, server answered %d", __FUNCTION__, clientsig[0], type);
+
+ if (type != clientsig[0])
+ Log(LOGWARNING, "%s: Type mismatch: client sent %d, server answered %d",
+ __FUNCTION__, clientsig[0], type);
if (ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
return false;
@@ -1732,7 +1912,8 @@ static bool HandShake(RTMP *r, bool FP9H
suptime = ntohl(suptime);
Log(LOGDEBUG, "%s: Server Uptime : %d", __FUNCTION__, suptime);
- Log(LOGDEBUG, "%s: FMS Version : %d.%d.%d.%d", __FUNCTION__, serversig[4], serversig[5], serversig[6], serversig[7]);
+ Log(LOGDEBUG, "%s: FMS Version : %d.%d.%d.%d", __FUNCTION__, serversig[4],
+ serversig[5], serversig[6], serversig[7]);
// 2nd part of handshake
if (!WriteN(r, serversig, RTMP_SIG_SIZE))
@@ -1744,94 +1925,105 @@ static bool HandShake(RTMP *r, bool FP9H
bool bMatch = (memcmp(resp, clientsig + 1, RTMP_SIG_SIZE) == 0);
if (!bMatch)
- {
- Log(LOGWARNING, "%s, client signature does not match!",__FUNCTION__);
- }
+ {
+ Log(LOGWARNING, "%s, client signature does not match!", __FUNCTION__);
+ }
return true;
}
#endif
-static bool SendRTMP(RTMP *r, RTMPPacket *packet, bool queue)
+static bool
+SendRTMP(RTMP * r, RTMPPacket * packet, bool queue)
{
const RTMPPacket *prevPacket = r->m_vecChannelsOut[packet->m_nChannel];
if (prevPacket && packet->m_headerType != RTMP_PACKET_SIZE_LARGE)
- {
- // compress a bit by using the prev packet's attributes
- if (prevPacket->m_nBodySize == packet->m_nBodySize && packet->m_headerType == RTMP_PACKET_SIZE_MEDIUM)
- packet->m_headerType = RTMP_PACKET_SIZE_SMALL;
+ {
+ // compress a bit by using the prev packet's attributes
+ if (prevPacket->m_nBodySize == packet->m_nBodySize
+ && packet->m_headerType == RTMP_PACKET_SIZE_MEDIUM)
+ packet->m_headerType = RTMP_PACKET_SIZE_SMALL;
- if (prevPacket->m_nInfoField2 == packet->m_nInfoField2 && packet->m_headerType == RTMP_PACKET_SIZE_SMALL)
- packet->m_headerType = RTMP_PACKET_SIZE_MINIMUM;
-
- }
+ if (prevPacket->m_nInfoField2 == packet->m_nInfoField2
+ && packet->m_headerType == RTMP_PACKET_SIZE_SMALL)
+ packet->m_headerType = RTMP_PACKET_SIZE_MINIMUM;
- if (packet->m_headerType > 3) // sanity
- {
- Log(LOGERROR, "sanity failed!! trying to send header of type: 0x%02x.", (unsigned char)packet->m_headerType);
- return false;
- }
+ }
+
+ if (packet->m_headerType > 3) // sanity
+ {
+ Log(LOGERROR, "sanity failed!! trying to send header of type: 0x%02x.",
+ (unsigned char) packet->m_headerType);
+ return false;
+ }
int nSize = packetSize[packet->m_headerType];
int hSize = nSize;
char *header = packet->m_body - nSize;
- header[0] = (char)((packet->m_headerType << 6) | packet->m_nChannel);
+ header[0] = (char) ((packet->m_headerType << 6) | packet->m_nChannel);
if (nSize > 1)
- AMF_EncodeInt24(header+1, packet->m_nInfoField1);
-
+ AMF_EncodeInt24(header + 1, packet->m_nInfoField1);
+
if (nSize > 4)
- {
- AMF_EncodeInt24(header+4, packet->m_nBodySize);
- header[7] = packet->m_packetType;
- }
+ {
+ AMF_EncodeInt24(header + 4, packet->m_nBodySize);
+ header[7] = packet->m_packetType;
+ }
if (nSize > 8)
- EncodeInt32LE(header+8, packet->m_nInfoField2);
+ EncodeInt32LE(header + 8, packet->m_nInfoField2);
nSize = packet->m_nBodySize;
char *buffer = packet->m_body;
int nChunkSize = RTMP_DEFAULT_CHUNKSIZE;
while (nSize)
- {
- int wrote;
+ {
+ int wrote;
- if (nSize < nChunkSize)
- nChunkSize = nSize;
+ if (nSize < nChunkSize)
+ nChunkSize = nSize;
- if (header) {
- wrote=WriteN(r, header, nChunkSize+hSize);
- header = NULL;
- } else {
- wrote=WriteN(r, buffer, nChunkSize);
- }
- if (!wrote)
- return false;
+ if (header)
+ {
+ wrote = WriteN(r, header, nChunkSize + hSize);
+ header = NULL;
+ }
+ else
+ {
+ wrote = WriteN(r, buffer, nChunkSize);
+ }
+ if (!wrote)
+ return false;
- nSize -= nChunkSize;
- buffer += nChunkSize;
+ nSize -= nChunkSize;
+ buffer += nChunkSize;
- if (nSize > 0)
- {
- header = buffer-1;
- hSize = 1;
- *header = (0xc0 | packet->m_nChannel);
+ if (nSize > 0)
+ {
+ header = buffer - 1;
+ hSize = 1;
+ *header = (0xc0 | packet->m_nChannel);
+ }
}
- }
- if (packet->m_packetType == 0x14 && queue) { // we invoked a remote method, keep it in call queue till result arrives
- AVal method;
- AMF_DecodeString(packet->m_body+1, &method);
- AV_queue(&r->m_methodCalls, &r->m_numCalls, &method);
- Log(LOGDEBUG, "Invoking %s", method.av_val);
- }
+ if (packet->m_packetType == 0x14 && queue)
+ { // we invoked a remote method, keep it in call queue till result arrives
+ AVal method;
+ AMF_DecodeString(packet->m_body + 1, &method);
+ AV_queue(&r->m_methodCalls, &r->m_numCalls, &method);
+ Log(LOGDEBUG, "Invoking %s", method.av_val);
+ }
if (!r->m_vecChannelsOut[packet->m_nChannel])
- r->m_vecChannelsOut[packet->m_nChannel] = malloc(offsetof(RTMPPacket,m_header));
- memcpy(r->m_vecChannelsOut[packet->m_nChannel], packet, offsetof(RTMPPacket,m_header));
+ r->m_vecChannelsOut[packet->m_nChannel] =
+ malloc(offsetof(RTMPPacket, m_header));
+ memcpy(r->m_vecChannelsOut[packet->m_nChannel], packet,
+ offsetof(RTMPPacket, m_header));
return true;
}
-void RTMP_Close(RTMP *r)
+void
+RTMP_Close(RTMP * r)
{
int i;
@@ -1848,17 +2040,19 @@ void RTMP_Close(RTMP *r)
r->m_nClientBW2 = 2;
r->m_nServerBW = 2500000;
- for (i=0; i<RTMP_CHANNELS; i++)
- {
- if (r->m_vecChannelsIn[i]) {
+ for (i = 0; i < RTMP_CHANNELS; i++)
+ {
+ if (r->m_vecChannelsIn[i])
+ {
free(r->m_vecChannelsIn[i]);
r->m_vecChannelsIn[i] = NULL;
}
- if (r->m_vecChannelsOut[i]) {
+ if (r->m_vecChannelsOut[i])
+ {
free(r->m_vecChannelsOut[i]);
r->m_vecChannelsOut[i] = NULL;
}
- }
+ }
AV_clear(r->m_methodCalls, r->m_numCalls);
r->m_methodCalls = NULL;
r->m_numCalls = 0;
@@ -1867,29 +2061,31 @@ void RTMP_Close(RTMP *r)
r->m_nBufferSize = 0;
}
-static bool FillBuffer(RTMP *r)
+static bool
+FillBuffer(RTMP * r)
{
- assert(r->m_nBufferSize == 0); // only fill buffer when it's empty
- int nBytes;
+ assert(r->m_nBufferSize == 0); // only fill buffer when it's empty
+ int nBytes;
again:
- nBytes = recv(r->m_socket, r->m_pBuffer, sizeof(r->m_pBuffer), 0);
- if(nBytes != -1) {
- r->m_nBufferSize += nBytes;
- r->m_pBufferStart = r->m_pBuffer;
+ nBytes = recv(r->m_socket, r->m_pBuffer, sizeof(r->m_pBuffer), 0);
+ if (nBytes != -1)
+ {
+ r->m_nBufferSize += nBytes;
+ r->m_pBufferStart = r->m_pBuffer;
}
- else
+ else
{
int sockerr = GetSockError();
- Log(LOGDEBUG, "%s, recv returned %d. GetSockError(): %d (%s)", __FUNCTION__, nBytes,
- sockerr, strerror(sockerr));
+ Log(LOGDEBUG, "%s, recv returned %d. GetSockError(): %d (%s)",
+ __FUNCTION__, nBytes, sockerr, strerror(sockerr));
if (sockerr == EINTR && !bCtrlC)
- goto again;
+ goto again;
if (sockerr == EWOULDBLOCK || sockerr == EAGAIN)
- r->m_bTimedout = true;
+ r->m_bTimedout = true;
else
- RTMP_Close(r);
+ RTMP_Close(r);
return false;
}
Modified: rtmp2.h
==============================================================================
--- rtmp2.h Wed Dec 16 07:26:23 2009 (r63)
+++ rtmp2.h Wed Dec 16 07:26:45 2009 (r64)
@@ -85,7 +85,7 @@ typedef struct RTMPPacket
uint32_t m_nBodySize;
uint32_t m_nBytesRead;
char m_header[RTMP_MAX_HEADER_SIZE];
- char m_body[1024];
+ char m_body[16384];
} RTMPPacket;
void RTMPPacket_Reset(RTMPPacket * p);
Modified: rtmpd2.c
==============================================================================
--- rtmpd2.c Wed Dec 16 07:26:23 2009 (r63)
+++ rtmpd2.c Wed Dec 16 07:26:45 2009 (r64)
@@ -26,7 +26,7 @@
#include <math.h>
#include <unistd.h>
-#include <signal.h> // to catch Ctrl-C
+#include <signal.h> // to catch Ctrl-C
#include <getopt.h>
#ifdef WIN32
@@ -54,28 +54,31 @@ int debuglevel = 1;
#define RD_INCOMPLETE 2
// starts sockets
-bool InitSockets()
+bool
+InitSockets()
{
#ifdef WIN32
- WORD version;
- WSADATA wsaData;
+ WORD version;
+ WSADATA wsaData;
- version = MAKEWORD(1,1);
- return (WSAStartup(version, &wsaData)==0);
+ version = MAKEWORD(1, 1);
+ return (WSAStartup(version, &wsaData) == 0);
#else
- return true;
+ return true;
#endif
}
-inline void CleanupSockets() {
+inline void
+CleanupSockets()
+{
#ifdef WIN32
- WSACleanup();
+ WSACleanup();
#endif
}
#ifdef _DEBUG
uint32_t debugTS = 0;
-int pnum=0;
+int pnum = 0;
FILE *netstackdump = 0;
FILE *netstackdump_read = 0;
@@ -88,1307 +91,1575 @@ uint32_t nIgnoredFrameCounter = 0;
FILE *file = 0;
bool bCtrlC = false;
-void sigIntHandler(int sig) {
- bCtrlC = true;
- LogPrintf("Caught signal: %d, cleaning up, just a second...\n", sig);
- // ignore all these signals now and let the connection close
- signal(SIGHUP, SIG_IGN);
- signal(SIGINT, SIG_IGN);
- signal(SIGPIPE, SIG_IGN);
- signal(SIGTERM, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
+void
+sigIntHandler(int sig)
+{
+ bCtrlC = true;
+ LogPrintf("Caught signal: %d, cleaning up, just a second...\n", sig);
+ // ignore all these signals now and let the connection close
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
}
-int WriteHeader(
- char **buf, // target pointer, maybe preallocated
- unsigned int len // length of buffer if preallocated
- )
+int
+WriteHeader(char **buf, // target pointer, maybe preallocated
+ unsigned int len // length of buffer if preallocated
+ )
{
- char flvHeader[] = { 'F', 'L', 'V', 0x01,
- 0x05, // video + audio, we finalize later if the value is different
- 0x00, 0x00, 0x00, 0x09,
- 0x00, 0x00, 0x00, 0x00 // first prevTagSize=0
- };
+ char flvHeader[] = { 'F', 'L', 'V', 0x01,
+ 0x05, // video + audio, we finalize later if the value is different
+ 0x00, 0x00, 0x00, 0x09,
+ 0x00, 0x00, 0x00, 0x00 // first prevTagSize=0
+ };
- unsigned int size = sizeof(flvHeader);
+ unsigned int size = sizeof(flvHeader);
- if(size > len) {
- *buf = (char *)realloc(*buf, size);
- if(*buf == 0) {
- Log(LOGERROR, "Couldn't reallocate memory!");
- return -1; // fatal error
- }
- }
- memcpy(*buf, flvHeader, sizeof(flvHeader));
- return size;
+ if (size > len)
+ {
+ *buf = (char *) realloc(*buf, size);
+ if (*buf == 0)
+ {
+ Log(LOGERROR, "Couldn't reallocate memory!");
+ return -1; // fatal error
+ }
+ }
+ memcpy(*buf, flvHeader, sizeof(flvHeader));
+ return size;
}
static const AVal av_onMetaData = AVC("onMetaData");
static const AVal av_duration = AVC("duration");
// Returns -3 if Play.Close/Stop, -2 if fatal error, -1 if no more media packets, 0 if ignorable error, >0 if there is a media packet
-int WriteStream(
- RTMP* rtmp,
- char **buf, // target pointer, maybe preallocated
- unsigned int len, // length of buffer if preallocated
- uint32_t *tsm, // pointer to timestamp, will contain timestamp of last video packet returned
- bool bResume, // resuming mode, will not write FLV header and compare metaHeader and first kexframe
- bool bLiveStream, // live mode, will not report absolute timestamps
- uint32_t nResumeTS, // resume keyframe timestamp
- char *metaHeader, // pointer to meta header (if bResume == TRUE)
- uint32_t nMetaHeaderSize, // length of meta header, if zero meta header check omitted (if bResume == TRUE)
- char *initialFrame, // pointer to initial keyframe (no FLV header or tagSize, raw data) (if bResume == TRUE)
- uint8_t initialFrameType, // initial frame type (audio or video)
- uint32_t nInitialFrameSize, // length of initial frame in bytes, if zero initial frame check omitted (if bResume == TRUE)
- uint8_t *dataType // whenever we get a video/audio packet we set an appropriate flag here, this will be later written to the FLV header
- )
+int
+WriteStream(RTMP * rtmp, char **buf, // target pointer, maybe preallocated
+ unsigned int len, // length of buffer if preallocated
+ uint32_t * tsm, // pointer to timestamp, will contain timestamp of last video packet returned
+ bool bResume, // resuming mode, will not write FLV header and compare metaHeader and first kexframe
+ bool bLiveStream, // live mode, will not report absolute timestamps
+ uint32_t nResumeTS, // resume keyframe timestamp
+ char *metaHeader, // pointer to meta header (if bResume == TRUE)
+ uint32_t nMetaHeaderSize, // length of meta header, if zero meta header check omitted (if bResume == TRUE)
+ char *initialFrame, // pointer to initial keyframe (no FLV header or tagSize, raw data) (if bResume == TRUE)
+ uint8_t initialFrameType, // initial frame type (audio or video)
+ uint32_t nInitialFrameSize, // length of initial frame in bytes, if zero initial frame check omitted (if bResume == TRUE)
+ uint8_t * dataType // whenever we get a video/audio packet we set an appropriate flag here, this will be later written to the FLV header
+ )
{
- static bool bStopIgnoring = false;
- static bool bFoundKeyframe = false;
- static bool bFoundFlvKeyframe = false;
+ static bool bStopIgnoring = false;
+ static bool bFoundKeyframe = false;
+ static bool bFoundFlvKeyframe = false;
- uint32_t prevTagSize = 0;
- int rtnGetNextMediaPacket = 0;
- char pbuf[131072];
- RTMPPacket *packet = (RTMPPacket *)pbuf;
+ uint32_t prevTagSize = 0;
+ int rtnGetNextMediaPacket = 0;
+ char pbuf[131072];
+ RTMPPacket *packet = (RTMPPacket *) pbuf;
- rtnGetNextMediaPacket = RTMP_GetNextMediaPacket(rtmp, packet);
- if(rtnGetNextMediaPacket)
- {
- char *packetBody = packet->m_body;
- unsigned int nPacketLen = packet->m_nBodySize;
+ rtnGetNextMediaPacket = RTMP_GetNextMediaPacket(rtmp, packet);
+ if (rtnGetNextMediaPacket)
+ {
+ char *packetBody = packet->m_body;
+ unsigned int nPacketLen = packet->m_nBodySize;
- // Return -3 if this was completed nicely with invoke message Play.Stop or Play.Complete
- if (rtnGetNextMediaPacket == 2) {
- Log(LOGDEBUG, "Got Play.Complete or Play.Stop from server. Assuming stream is complete");
- return -3;
- }
+ // Return -3 if this was completed nicely with invoke message Play.Stop or Play.Complete
+ if (rtnGetNextMediaPacket == 2)
+ {
+ Log(LOGDEBUG,
+ "Got Play.Complete or Play.Stop from server. Assuming stream is complete");
+ return -3;
+ }
- // skip video info/command packets
- if(packet->m_packetType == 0x09 &&
- nPacketLen == 2 &&
- ((*packetBody & 0xf0) == 0x50)) {
- return 0;
- }
+ // skip video info/command packets
+ if (packet->m_packetType == 0x09 &&
+ nPacketLen == 2 && ((*packetBody & 0xf0) == 0x50))
+ {
+ return 0;
+ }
- if(packet->m_packetType == 0x09 && nPacketLen <= 5) {
- Log(LOGWARNING, "ignoring too small video packet: size: %d", nPacketLen);
- return 0;
- }
- if(packet->m_packetType == 0x08 && nPacketLen <= 1) {
- Log(LOGWARNING, "ignoring too small audio packet: size: %d", nPacketLen);
- return 0;
- }
+ if (packet->m_packetType == 0x09 && nPacketLen <= 5)
+ {
+ Log(LOGWARNING, "ignoring too small video packet: size: %d",
+ nPacketLen);
+ return 0;
+ }
+ if (packet->m_packetType == 0x08 && nPacketLen <= 1)
+ {
+ Log(LOGWARNING, "ignoring too small audio packet: size: %d",
+ nPacketLen);
+ return 0;
+ }
#ifdef _DEBUG
- Log(LOGDEBUG, "type: %02X, size: %d, TS: %d ms, abs TS: %d", packet->m_packetType, nPacketLen, packet->m_nTimeStamp, packet->m_hasAbsTimestamp);
- if(packet->m_packetType == 0x09)
- Log(LOGDEBUG, "frametype: %02X", (*packetBody & 0xf0));
+ Log(LOGDEBUG, "type: %02X, size: %d, TS: %d ms, abs TS: %d",
+ packet->m_packetType, nPacketLen, packet->m_nTimeStamp,
+ packet->m_hasAbsTimestamp);
+ if (packet->m_packetType == 0x09)
+ Log(LOGDEBUG, "frametype: %02X", (*packetBody & 0xf0));
#endif
- // check the header if we get one
- if(bResume && packet->m_nTimeStamp == 0) {
- if(nMetaHeaderSize > 0 && packet->m_packetType == 0x12) {
-
- AMFObject metaObj;
- int nRes = AMF_Decode(&metaObj, packetBody, nPacketLen, false);
- if(nRes >= 0) {
- AVal metastring;
- AMFProp_GetString(AMF_GetProp(&metaObj, NULL, 0), &metastring);
+ // check the header if we get one
+ if (bResume && packet->m_nTimeStamp == 0)
+ {
+ if (nMetaHeaderSize > 0 && packet->m_packetType == 0x12)
+ {
- if(AVMATCH(&metastring, &av_onMetaData)) {
- // compare
- if((nMetaHeaderSize != nPacketLen) ||
- (memcmp(metaHeader, packetBody, nMetaHeaderSize) != 0)) {
- return -2;
- }
- }
- }
+ AMFObject metaObj;
+ int nRes = AMF_Decode(&metaObj, packetBody, nPacketLen, false);
+ if (nRes >= 0)
+ {
+ AVal metastring;
+ AMFProp_GetString(AMF_GetProp(&metaObj, NULL, 0),
+ &metastring);
+
+ if (AVMATCH(&metastring, &av_onMetaData))
+ {
+ // compare
+ if ((nMetaHeaderSize != nPacketLen) ||
+ (memcmp(metaHeader, packetBody, nMetaHeaderSize) !=
+ 0))
+ {
+ return -2;
}
+ }
+ }
+ }
- // check first keyframe to make sure we got the right position in the stream!
- // (the first non ignored frame)
- if(nInitialFrameSize > 0) {
+ // check first keyframe to make sure we got the right position in the stream!
+ // (the first non ignored frame)
+ if (nInitialFrameSize > 0)
+ {
- // video or audio data
- if(packet->m_packetType == initialFrameType && nInitialFrameSize == nPacketLen) {
- // we don't compare the sizes since the packet can contain several FLV packets, just make
- // sure the first frame is our keyframe (which we are going to rewrite)
- if(memcmp(initialFrame, packetBody, nInitialFrameSize) == 0) {
- Log(LOGDEBUG, "Checked keyframe successfully!");
- bFoundKeyframe = true;
- return 0; // ignore it! (what about audio data after it? it is handled by ignoring all 0ms frames, see below)
- }
- }
+ // video or audio data
+ if (packet->m_packetType == initialFrameType
+ && nInitialFrameSize == nPacketLen)
+ {
+ // we don't compare the sizes since the packet can contain several FLV packets, just make
+ // sure the first frame is our keyframe (which we are going to rewrite)
+ if (memcmp(initialFrame, packetBody, nInitialFrameSize) ==
+ 0)
+ {
+ Log(LOGDEBUG, "Checked keyframe successfully!");
+ bFoundKeyframe = true;
+ return 0; // ignore it! (what about audio data after it? it is handled by ignoring all 0ms frames, see below)
+ }
+ }
- // hande FLV streams, even though the server resends the keyframe as an extra video packet
- // it is also included in the first FLV stream chunk and we have to compare it and
- // filter it out !!
- //
- if(packet->m_packetType == 0x16) {
- // basically we have to find the keyframe with the correct TS being nResumeTS
- unsigned int pos=0;
- uint32_t ts = 0;
+ // hande FLV streams, even though the server resends the keyframe as an extra video packet
+ // it is also included in the first FLV stream chunk and we have to compare it and
+ // filter it out !!
+ //
+ if (packet->m_packetType == 0x16)
+ {
+ // basically we have to find the keyframe with the correct TS being nResumeTS
+ unsigned int pos = 0;
+ uint32_t ts = 0;
- while(pos+11 < nPacketLen) {
- uint32_t dataSize = AMF_DecodeInt24(packetBody+pos+1); // size without header (11) and prevTagSize (4)
- ts = AMF_DecodeInt24(packetBody+pos+4);
- ts |= (packetBody[pos+7]<<24);
-
-#ifdef _DEBUG
- Log(LOGDEBUG, "keyframe search: FLV Packet: type %02X, dataSize: %d, timeStamp: %d ms",
- packetBody[pos], dataSize, ts);
+ while (pos + 11 < nPacketLen)
+ {
+ uint32_t dataSize = AMF_DecodeInt24(packetBody + pos + 1); // size without header (11) and prevTagSize (4)
+ ts = AMF_DecodeInt24(packetBody + pos + 4);
+ ts |= (packetBody[pos + 7] << 24);
+
+#ifdef _DEBUG
+ Log(LOGDEBUG,
+ "keyframe search: FLV Packet: type %02X, dataSize: %d, timeStamp: %d ms",
+ packetBody[pos], dataSize, ts);
#endif
- // ok, is it a keyframe!!!: well doesn't work for audio!
- if(packetBody[pos /*6928, test 0*/] == initialFrameType /* && (packetBody[11]&0xf0) == 0x10*/) {
- if(ts == nResumeTS) {
- Log(LOGDEBUG, "Found keyframe with resume-keyframe timestamp!");
- if(nInitialFrameSize != dataSize || memcmp(initialFrame, packetBody+pos+11, nInitialFrameSize) != 0) {
- Log(LOGERROR, "FLV Stream: Keyframe doesn't match!");
- return -2;
- }
- bFoundFlvKeyframe = true;
+ // ok, is it a keyframe!!!: well doesn't work for audio!
+ if (packetBody[pos /*6928, test 0 */ ] ==
+ initialFrameType
+ /* && (packetBody[11]&0xf0) == 0x10 */ )
+ {
+ if (ts == nResumeTS)
+ {
+ Log(LOGDEBUG,
+ "Found keyframe with resume-keyframe timestamp!");
+ if (nInitialFrameSize != dataSize
+ || memcmp(initialFrame,
+ packetBody + pos + 11,
+ nInitialFrameSize) != 0)
+ {
+ Log(LOGERROR,
+ "FLV Stream: Keyframe doesn't match!");
+ return -2;
+ }
+ bFoundFlvKeyframe = true;
- // ok, skip this packet
- // check whether skipable:
- if(pos+11+dataSize+4 > nPacketLen) {
- Log(LOGWARNING, "Non skipable packet since it doesn't end with chunk, stream corrupt!");
- return -2;
- }
- packetBody += (pos+11+dataSize+4);
- nPacketLen -= (pos+11+dataSize+4);
+ // ok, skip this packet
+ // check whether skipable:
+ if (pos + 11 + dataSize + 4 > nPacketLen)
+ {
+ Log(LOGWARNING,
+ "Non skipable packet since it doesn't end with chunk, stream corrupt!");
+ return -2;
+ }
+ packetBody += (pos + 11 + dataSize + 4);
+ nPacketLen -= (pos + 11 + dataSize + 4);
- goto stopKeyframeSearch;
+ goto stopKeyframeSearch;
- } else if(nResumeTS < ts) {
- goto stopKeyframeSearch; // the timestamp ts will only increase with further packets, wait for seek
- }
- }
- pos += (11+dataSize+4);
- }
- if(ts < nResumeTS) {
- Log(LOGERROR, "First packet does not contain keyframe, all timestamps are smaller than the keyframe timestamp, so probably the resume seek failed?");
- }
-stopKeyframeSearch:
- ;
- if(!bFoundFlvKeyframe) {
- Log(LOGERROR, "Couldn't find the seeked keyframe in this chunk!");
- return 0;
- }
- }
+ }
+ else if (nResumeTS < ts)
+ {
+ goto stopKeyframeSearch; // the timestamp ts will only increase with further packets, wait for seek
+ }
}
+ pos += (11 + dataSize + 4);
+ }
+ if (ts < nResumeTS)
+ {
+ Log(LOGERROR,
+ "First packet does not contain keyframe, all timestamps are smaller than the keyframe timestamp, so probably the resume seek failed?");
+ }
+ stopKeyframeSearch:
+ ;
+ if (!bFoundFlvKeyframe)
+ {
+ Log(LOGERROR,
+ "Couldn't find the seeked keyframe in this chunk!");
+ return 0;
+ }
}
-
- if(bResume && packet->m_nTimeStamp > 0 && (bFoundFlvKeyframe || bFoundKeyframe)) {
- // another problem is that the server can actually change from 09/08 video/audio packets to an FLV stream
- // or vice versa and our keyframe check will prevent us from going along with the new stream if we resumed
- //
- // in this case set the 'found keyframe' variables to true
- // We assume that if we found one keyframe somewhere and were already beyond TS > 0 we have written
- // data to the output which means we can accept all forthcoming data inclusing the change between 08/09 <-> FLV
- // packets
- bFoundFlvKeyframe = true;
- bFoundKeyframe = true;
- }
+ }
+ }
- // skip till we find out keyframe (seeking might put us somewhere before it)
- if(bResume && !bFoundKeyframe && packet->m_packetType != 0x16) {
- Log(LOGWARNING, "Stream does not start with requested frame, ignoring data... ");
- nIgnoredFrameCounter++;
- if(nIgnoredFrameCounter > MAX_IGNORED_FRAMES)
- return -2; // fatal error, couldn't continue stream
- return 0;
- }
- // ok, do the same for FLV streams
- if(bResume && !bFoundFlvKeyframe && packet->m_packetType == 0x16) {
- Log(LOGWARNING, "Stream does not start with requested FLV frame, ignoring data... ");
- nIgnoredFlvFrameCounter++;
- if(nIgnoredFlvFrameCounter > MAX_IGNORED_FRAMES)
- return -2;
- return 0;
- }
+ if (bResume && packet->m_nTimeStamp > 0
+ && (bFoundFlvKeyframe || bFoundKeyframe))
+ {
+ // another problem is that the server can actually change from 09/08 video/audio packets to an FLV stream
+ // or vice versa and our keyframe check will prevent us from going along with the new stream if we resumed
+ //
+ // in this case set the 'found keyframe' variables to true
+ // We assume that if we found one keyframe somewhere and were already beyond TS > 0 we have written
+ // data to the output which means we can accept all forthcoming data inclusing the change between 08/09 <-> FLV
+ // packets
+ bFoundFlvKeyframe = true;
+ bFoundKeyframe = true;
+ }
- // if bResume, we continue a stream, we have to ignore the 0ms frames since these are the first keyframes, we've got these
- // so don't mess around with multiple copies sent by the server to us! (if the keyframe is found at a later position
- // there is only one copy and it will be ignored by the preceding if clause)
- if(!bStopIgnoring && bResume && packet->m_packetType != 0x16) { // exclude type 0x16 (FLV) since it can conatin several FLV packets
- if(packet->m_nTimeStamp == 0) {
- return 0;
- } else {
- bStopIgnoring = true; // stop ignoring packets
- }
- }
+ // skip till we find out keyframe (seeking might put us somewhere before it)
+ if (bResume && !bFoundKeyframe && packet->m_packetType != 0x16)
+ {
+ Log(LOGWARNING,
+ "Stream does not start with requested frame, ignoring data... ");
+ nIgnoredFrameCounter++;
+ if (nIgnoredFrameCounter > MAX_IGNORED_FRAMES)
+ return -2; // fatal error, couldn't continue stream
+ return 0;
+ }
+ // ok, do the same for FLV streams
+ if (bResume && !bFoundFlvKeyframe && packet->m_packetType == 0x16)
+ {
+ Log(LOGWARNING,
+ "Stream does not start with requested FLV frame, ignoring data... ");
+ nIgnoredFlvFrameCounter++;
+ if (nIgnoredFlvFrameCounter > MAX_IGNORED_FRAMES)
+ return -2;
+ return 0;
+ }
- // calculate packet size and reallocate buffer if necessary
- unsigned int size = nPacketLen
- + ((packet->m_packetType == 0x08 || packet->m_packetType == 0x09 || packet->m_packetType == 0x12) ? 11 : 0)
- + (packet->m_packetType != 0x16 ? 4 : 0);
-
- if(size+4 > len) { // the extra 4 is for the case of an FLV stream without a last prevTagSize (we need extra 4 bytes to append it)
- *buf = (char *)realloc(*buf, size+4);
- if(*buf == 0) {
- Log(LOGERROR, "Couldn't reallocate memory!");
- return -1; // fatal error
- }
- }
- char *ptr = *buf;
+ // if bResume, we continue a stream, we have to ignore the 0ms frames since these are the first keyframes, we've got these
+ // so don't mess around with multiple copies sent by the server to us! (if the keyframe is found at a later position
+ // there is only one copy and it will be ignored by the preceding if clause)
+ if (!bStopIgnoring && bResume && packet->m_packetType != 0x16)
+ { // exclude type 0x16 (FLV) since it can conatin several FLV packets
+ if (packet->m_nTimeStamp == 0)
+ {
+ return 0;
+ }
+ else
+ {
+ bStopIgnoring = true; // stop ignoring packets
+ }
+ }
- uint32_t nTimeStamp = 0; // use to return timestamp of last processed packet
+ // calculate packet size and reallocate buffer if necessary
+ unsigned int size = nPacketLen
+ +
+ ((packet->m_packetType == 0x08 || packet->m_packetType == 0x09
+ || packet->m_packetType ==
+ 0x12) ? 11 : 0) + (packet->m_packetType != 0x16 ? 4 : 0);
- // audio (0x08), video (0x09) or metadata (0x12) packets :
- // construct 11 byte header then add rtmp packet's data
- if(packet->m_packetType == 0x08 || packet->m_packetType == 0x09 || packet->m_packetType == 0x12)
- {
- // set data type
- *dataType |= (((packet->m_packetType == 0x08)<<2)|(packet->m_packetType == 0x09));
+ if (size + 4 > len)
+ { // the extra 4 is for the case of an FLV stream without a last prevTagSize (we need extra 4 bytes to append it)
+ *buf = (char *) realloc(*buf, size + 4);
+ if (*buf == 0)
+ {
+ Log(LOGERROR, "Couldn't reallocate memory!");
+ return -1; // fatal error
+ }
+ }
+ char *ptr = *buf;
- nTimeStamp = nResumeTS + packet->m_nTimeStamp;
- prevTagSize = 11 + nPacketLen;
+ uint32_t nTimeStamp = 0; // use to return timestamp of last processed packet
- *ptr = packet->m_packetType;
- ptr++;
- ptr += AMF_EncodeInt24(ptr, nPacketLen);
+ // audio (0x08), video (0x09) or metadata (0x12) packets :
+ // construct 11 byte header then add rtmp packet's data
+ if (packet->m_packetType == 0x08 || packet->m_packetType == 0x09
+ || packet->m_packetType == 0x12)
+ {
+ // set data type
+ *dataType |=
+ (((packet->m_packetType == 0x08) << 2) | (packet->m_packetType ==
+ 0x09));
- /*if(packet.m_packetType == 0x09) { // video
+ nTimeStamp = nResumeTS + packet->m_nTimeStamp;
+ prevTagSize = 11 + nPacketLen;
- // H264 fix:
- if((packetBody[0] & 0x0f) == 7) { // CodecId = H264
- uint8_t packetType = *(packetBody+1);
-
- uint32_t ts = AMF_DecodeInt24(packetBody+2); // composition time
- int32_t cts = (ts+0xff800000)^0xff800000;
- Log(LOGDEBUG, "cts : %d\n", cts);
+ *ptr = packet->m_packetType;
+ ptr++;
+ ptr += AMF_EncodeInt24(ptr, nPacketLen);
- nTimeStamp -= cts;
- // get rid of the composition time
- CRTMP::EncodeInt24(packetBody+2, 0);
- }
- Log(LOGDEBUG, "VIDEO: nTimeStamp: 0x%08X (%d)\n", nTimeStamp, nTimeStamp);
- }*/
+ /*if(packet.m_packetType == 0x09) { // video
- ptr += AMF_EncodeInt24(ptr, nTimeStamp);
- *ptr = (char)((nTimeStamp & 0xFF000000) >> 24);
- ptr++;
+ // H264 fix:
+ if((packetBody[0] & 0x0f) == 7) { // CodecId = H264
+ uint8_t packetType = *(packetBody+1);
- // stream id
- ptr += AMF_EncodeInt24(ptr, 0);
- }
+ uint32_t ts = AMF_DecodeInt24(packetBody+2); // composition time
+ int32_t cts = (ts+0xff800000)^0xff800000;
+ Log(LOGDEBUG, "cts : %d\n", cts);
- memcpy(ptr, packetBody, nPacketLen);
- unsigned int len = nPacketLen;
-
- // correct tagSize and obtain timestamp if we have an FLV stream
- if(packet->m_packetType == 0x16)
- {
- unsigned int pos=0;
+ nTimeStamp -= cts;
+ // get rid of the composition time
+ CRTMP::EncodeInt24(packetBody+2, 0);
+ }
+ Log(LOGDEBUG, "VIDEO: nTimeStamp: 0x%08X (%d)\n", nTimeStamp, nTimeStamp);
+ } */
- while(pos+11 < nPacketLen)
- {
- uint32_t dataSize = AMF_DecodeInt24(packetBody+pos+1); // size without header (11) and without prevTagSize (4)
- nTimeStamp = AMF_DecodeInt24(packetBody+pos+4);
- nTimeStamp |= (packetBody[pos+7]<<24);
+ ptr += AMF_EncodeInt24(ptr, nTimeStamp);
+ *ptr = (char) ((nTimeStamp & 0xFF000000) >> 24);
+ ptr++;
- /*
- CRTMP::EncodeInt24(ptr+pos+4, nTimeStamp);
- ptr[pos+7] = (nTimeStamp>>24)&0xff;//*/
+ // stream id
+ ptr += AMF_EncodeInt24(ptr, 0);
+ }
- // set data type
- *dataType |= (((*(packetBody+pos) == 0x08)<<2)|(*(packetBody+pos) == 0x09));
+ memcpy(ptr, packetBody, nPacketLen);
+ unsigned int len = nPacketLen;
+
+ // correct tagSize and obtain timestamp if we have an FLV stream
+ if (packet->m_packetType == 0x16)
+ {
+ unsigned int pos = 0;
+
+ while (pos + 11 < nPacketLen)
+ {
+ uint32_t dataSize = AMF_DecodeInt24(packetBody + pos + 1); // size without header (11) and without prevTagSize (4)
+ nTimeStamp = AMF_DecodeInt24(packetBody + pos + 4);
+ nTimeStamp |= (packetBody[pos + 7] << 24);
+
+ /*
+ CRTMP::EncodeInt24(ptr+pos+4, nTimeStamp);
+ ptr[pos+7] = (nTimeStamp>>24)&0xff;// */
+
+ // set data type
+ *dataType |=
+ (((*(packetBody + pos) ==
+ 0x08) << 2) | (*(packetBody + pos) == 0x09));
+
+ if (pos + 11 + dataSize + 4 > nPacketLen)
+ {
+ if (pos + 11 + dataSize > nPacketLen)
+ {
+ Log(LOGERROR,
+ "Wrong data size (%lu), stream corrupted, aborting!",
+ dataSize);
+ return -2;
+ }
+ Log(LOGWARNING, "No tagSize found, appending!");
+
+ // we have to append a last tagSize!
+ prevTagSize = dataSize + 11;
+ AMF_EncodeInt32(ptr + pos + 11 + dataSize, prevTagSize);
+ size += 4;
+ len += 4;
+ }
+ else
+ {
+ prevTagSize =
+ AMF_DecodeInt32(packetBody + pos + 11 + dataSize);
- if(pos+11+dataSize+4 > nPacketLen) {
- if(pos+11+dataSize > nPacketLen) {
- Log(LOGERROR, "Wrong data size (%lu), stream corrupted, aborting!", dataSize);
- return -2;
- }
- Log(LOGWARNING, "No tagSize found, appending!");
-
- // we have to append a last tagSize!
- prevTagSize = dataSize+11;
- AMF_EncodeInt32(ptr+pos+11+dataSize, prevTagSize);
- size+=4; len+=4;
- } else {
- prevTagSize = AMF_DecodeInt32(packetBody+pos+11+dataSize);
-
#ifdef _DEBUG
- Log(LOGDEBUG, "FLV Packet: type %02X, dataSize: %lu, tagSize: %lu, timeStamp: %lu ms",
- (unsigned char)packetBody[pos], dataSize, prevTagSize, nTimeStamp);
+ Log(LOGDEBUG,
+ "FLV Packet: type %02X, dataSize: %lu, tagSize: %lu, timeStamp: %lu ms",
+ (unsigned char) packetBody[pos], dataSize, prevTagSize,
+ nTimeStamp);
#endif
- if(prevTagSize != (dataSize+11)) {
+ if (prevTagSize != (dataSize + 11))
+ {
#ifdef _DEBUG
- Log(LOGWARNING, "Tag and data size are not consitent, writing tag size according to dataSize+11: %d", dataSize+11);
+ Log(LOGWARNING,
+ "Tag and data size are not consitent, writing tag size according to dataSize+11: %d",
+ dataSize + 11);
#endif
- prevTagSize = dataSize+11;
- AMF_EncodeInt32(ptr+pos+11+dataSize, prevTagSize);
- }
- }
-
- pos += prevTagSize+4;//(11+dataSize+4);
- }
+ prevTagSize = dataSize + 11;
+ AMF_EncodeInt32(ptr + pos + 11 + dataSize, prevTagSize);
+ }
}
- ptr += len;
- if(packet->m_packetType != 0x16) { // FLV tag packets contain their own prevTagSize
- AMF_EncodeInt32(ptr, prevTagSize);
- //ptr += 4;
- }
+ pos += prevTagSize + 4; //(11+dataSize+4);
+ }
+ }
+ ptr += len;
- // In non-live this nTimeStamp can contain an absolute TS.
- // Update ext timestamp with this absolute offset in non-live mode otherwise report the relative one
- // LogPrintf("\nDEBUG: type: %02X, size: %d, pktTS: %dms, TS: %dms, bLiveStream: %d", packet.m_packetType, nPacketLen, packet.m_nTimeStamp, nTimeStamp, bLiveStream);
- if(tsm)
- *tsm = bLiveStream ? packet->m_nTimeStamp : nTimeStamp;
+ if (packet->m_packetType != 0x16)
+ { // FLV tag packets contain their own prevTagSize
+ AMF_EncodeInt32(ptr, prevTagSize);
+ //ptr += 4;
+ }
+ // In non-live this nTimeStamp can contain an absolute TS.
+ // Update ext timestamp with this absolute offset in non-live mode otherwise report the relative one
+ // LogPrintf("\nDEBUG: type: %02X, size: %d, pktTS: %dms, TS: %dms, bLiveStream: %d", packet.m_packetType, nPacketLen, packet.m_nTimeStamp, nTimeStamp, bLiveStream);
+ if (tsm)
+ *tsm = bLiveStream ? packet->m_nTimeStamp : nTimeStamp;
- return size;
- }
- return -1; // no more media packets
+ return size;
+ }
+
+ return -1; // no more media packets
}
-int OpenResumeFile(const char *flvFile, // file name [in]
- FILE **file, // opened file [out]
- off_t *size, // size of the file [out]
- char **metaHeader, // meta data read from the file [out]
- uint32_t *nMetaHeaderSize, // length of metaHeader [out]
- double *duration) // duration of the stream in ms [out]
+int
+OpenResumeFile(const char *flvFile, // file name [in]
+ FILE ** file, // opened file [out]
+ off_t * size, // size of the file [out]
+ char **metaHeader, // meta data read from the file [out]
+ uint32_t * nMetaHeaderSize, // length of metaHeader [out]
+ double *duration) // duration of the stream in ms [out]
{
- const size_t bufferSize = 1024;
- char buffer[bufferSize];
+ const size_t bufferSize = 1024;
+ char buffer[bufferSize];
- *nMetaHeaderSize = 0;
- *size = 0;
+ *nMetaHeaderSize = 0;
+ *size = 0;
- *file = fopen(flvFile, "r+b");
- if (!*file)
- return RD_SUCCESS; // RD_SUCCESS, because we go to fresh file mode instead of quiting
-
- fseek(*file, 0, SEEK_END);
- *size = ftello(*file);
- fseek(*file, 0, SEEK_SET);
+ *file = fopen(flvFile, "r+b");
+ if (!*file)
+ return RD_SUCCESS; // RD_SUCCESS, because we go to fresh file mode instead of quiting
- if(*size > 0) {
- // verify FLV format and read header
- uint32_t prevTagSize = 0;
+ fseek(*file, 0, SEEK_END);
+ *size = ftello(*file);
+ fseek(*file, 0, SEEK_SET);
- // check we've got a valid FLV file to continue!
- if(fread(buffer, 1, 13, *file) != 13) {
- Log(LOGERROR, "Couldn't read FLV file header!");
- return RD_FAILED;
- }
- if(buffer[0] != 'F' || buffer[1] != 'L' || buffer[2] != 'V' || buffer[3] != 0x01) {
- Log(LOGERROR, "Inavlid FLV file!");
- return RD_FAILED;
- }
+ if (*size > 0)
+ {
+ // verify FLV format and read header
+ uint32_t prevTagSize = 0;
- if((buffer[4]&0x05) == 0) {
- Log(LOGERROR, "FLV file contains neither video nor audio, aborting!");
- return RD_FAILED;
- }
-
- uint32_t dataOffset = AMF_DecodeInt32(buffer+5);
- fseek(*file, dataOffset, SEEK_SET);
+ // check we've got a valid FLV file to continue!
+ if (fread(buffer, 1, 13, *file) != 13)
+ {
+ Log(LOGERROR, "Couldn't read FLV file header!");
+ return RD_FAILED;
+ }
+ if (buffer[0] != 'F' || buffer[1] != 'L' || buffer[2] != 'V'
+ || buffer[3] != 0x01)
+ {
+ Log(LOGERROR, "Inavlid FLV file!");
+ return RD_FAILED;
+ }
- if(fread(buffer, 1, 4, *file) != 4) {
- Log(LOGERROR, "Invalid FLV file: missing first prevTagSize!");
- return RD_FAILED;
- }
- prevTagSize = AMF_DecodeInt32(buffer);
- if(prevTagSize != 0) {
- Log(LOGWARNING, "First prevTagSize is not zero: prevTagSize = 0x%08X", prevTagSize);
- }
+ if ((buffer[4] & 0x05) == 0)
+ {
+ Log(LOGERROR,
+ "FLV file contains neither video nor audio, aborting!");
+ return RD_FAILED;
+ }
- // go through the file to find the meta data!
- off_t pos = dataOffset+4;
- bool bFoundMetaHeader = false;
+ uint32_t dataOffset = AMF_DecodeInt32(buffer + 5);
+ fseek(*file, dataOffset, SEEK_SET);
- while(pos < *size-4 && !bFoundMetaHeader) {
- fseeko(*file, pos, SEEK_SET);
- if(fread(buffer, 1, 4, *file)!=4)
- break;
+ if (fread(buffer, 1, 4, *file) != 4)
+ {
+ Log(LOGERROR, "Invalid FLV file: missing first prevTagSize!");
+ return RD_FAILED;
+ }
+ prevTagSize = AMF_DecodeInt32(buffer);
+ if (prevTagSize != 0)
+ {
+ Log(LOGWARNING,
+ "First prevTagSize is not zero: prevTagSize = 0x%08X",
+ prevTagSize);
+ }
- uint32_t dataSize = AMF_DecodeInt24(buffer+1);
-
- if(buffer[0] == 0x12) {
- if (dataSize > bufferSize) {
- Log(LOGERROR, "%s: dataSize (%d) > bufferSize (%d)", __FUNCTION__, dataSize, bufferSize);
- return RD_FAILED;
- }
+ // go through the file to find the meta data!
+ off_t pos = dataOffset + 4;
+ bool bFoundMetaHeader = false;
- fseeko(*file, pos+11, SEEK_SET);
- if(fread(buffer, 1, dataSize, *file) != dataSize)
- break;
-
- AMFObject metaObj;
- int nRes = AMF_Decode(&metaObj, buffer, dataSize, false);
- if(nRes < 0) {
- Log(LOGERROR, "%s, error decoding meta data packet", __FUNCTION__);
- break;
- }
-
- AVal metastring;
- AMFProp_GetString(AMF_GetProp(&metaObj, NULL, 0), &metastring);
+ while (pos < *size - 4 && !bFoundMetaHeader)
+ {
+ fseeko(*file, pos, SEEK_SET);
+ if (fread(buffer, 1, 4, *file) != 4)
+ break;
- if(AVMATCH(&metastring, &av_onMetaData)) {
- AMF_Dump(&metaObj);
-
- *nMetaHeaderSize = dataSize;
- if (*metaHeader) free(*metaHeader);
- *metaHeader = (char *)malloc(*nMetaHeaderSize);
- memcpy(*metaHeader, buffer, *nMetaHeaderSize);
+ uint32_t dataSize = AMF_DecodeInt24(buffer + 1);
- // get duration
- AMFObjectProperty prop;
- if(RTMP_FindFirstMatchingProperty(&metaObj, &av_duration, &prop)) {
- *duration = AMFProp_GetNumber(&prop);
- Log(LOGDEBUG, "File has duration: %f", *duration);
- }
+ if (buffer[0] == 0x12)
+ {
+ if (dataSize > bufferSize)
+ {
+ Log(LOGERROR, "%s: dataSize (%d) > bufferSize (%d)",
+ __FUNCTION__, dataSize, bufferSize);
+ return RD_FAILED;
+ }
- bFoundMetaHeader = true;
- break;
- }
- //metaObj.Reset();
- //delete obj;
- }
- pos += (dataSize+11+4);
+ fseeko(*file, pos + 11, SEEK_SET);
+ if (fread(buffer, 1, dataSize, *file) != dataSize)
+ break;
+
+ AMFObject metaObj;
+ int nRes = AMF_Decode(&metaObj, buffer, dataSize, false);
+ if (nRes < 0)
+ {
+ Log(LOGERROR, "%s, error decoding meta data packet",
+ __FUNCTION__);
+ break;
}
- if(!bFoundMetaHeader)
- Log(LOGWARNING, "Couldn't locate meta data!");
+ AVal metastring;
+ AMFProp_GetString(AMF_GetProp(&metaObj, NULL, 0), &metastring);
+
+ if (AVMATCH(&metastring, &av_onMetaData))
+ {
+ AMF_Dump(&metaObj);
+
+ *nMetaHeaderSize = dataSize;
+ if (*metaHeader)
+ free(*metaHeader);
+ *metaHeader = (char *) malloc(*nMetaHeaderSize);
+ memcpy(*metaHeader, buffer, *nMetaHeaderSize);
+
+ // get duration
+ AMFObjectProperty prop;
+ if (RTMP_FindFirstMatchingProperty
+ (&metaObj, &av_duration, &prop))
+ {
+ *duration = AMFProp_GetNumber(&prop);
+ Log(LOGDEBUG, "File has duration: %f", *duration);
+ }
+
+ bFoundMetaHeader = true;
+ break;
+ }
+ //metaObj.Reset();
+ //delete obj;
+ }
+ pos += (dataSize + 11 + 4);
}
- return RD_SUCCESS;
+ if (!bFoundMetaHeader)
+ Log(LOGWARNING, "Couldn't locate meta data!");
+ }
+
+ return RD_SUCCESS;
}
-int GetLastKeyframe(FILE *file, // output file [in]
- int nSkipKeyFrames, // max number of frames to skip when searching for key frame [in]
- uint32_t *dSeek, // offset of the last key frame [out]
- char **initialFrame, // content of the last keyframe [out]
- int *initialFrameType, // initial frame type (audio/video) [out]
- uint32_t *nInitialFrameSize) // length of initialFrame [out]
+int
+GetLastKeyframe(FILE * file, // output file [in]
+ int nSkipKeyFrames, // max number of frames to skip when searching for key frame [in]
+ uint32_t * dSeek, // offset of the last key frame [out]
+ char **initialFrame, // content of the last keyframe [out]
+ int *initialFrameType, // initial frame type (audio/video) [out]
+ uint32_t * nInitialFrameSize) // length of initialFrame [out]
{
- const size_t bufferSize = 16;
- char buffer[bufferSize];
- uint8_t dataType;
- bool bAudioOnly;
- off_t size;
+ const size_t bufferSize = 16;
+ char buffer[bufferSize];
+ uint8_t dataType;
+ bool bAudioOnly;
+ off_t size;
- fseek(file, 0, SEEK_END);
- size = ftello(file);
+ fseek(file, 0, SEEK_END);
+ size = ftello(file);
- fseek(file, 4, SEEK_SET);
- fread(&dataType, sizeof(uint8_t), 1, file);
- bAudioOnly = (dataType & 0x4) && !(dataType & 0x1);
+ fseek(file, 4, SEEK_SET);
+ fread(&dataType, sizeof(uint8_t), 1, file);
+ bAudioOnly = (dataType & 0x4) && !(dataType & 0x1);
- Log(LOGDEBUG, "bAudioOnly: %d, size: %llu", bAudioOnly, (unsigned long long)size);
+ Log(LOGDEBUG, "bAudioOnly: %d, size: %llu", bAudioOnly,
+ (unsigned long long) size);
- // ok, we have to get the timestamp of the last keyframe (only keyframes are seekable) / last audio frame (audio only streams)
+ // ok, we have to get the timestamp of the last keyframe (only keyframes are seekable) / last audio frame (audio only streams)
- //if(!bAudioOnly) // we have to handle video/video+audio different since we have non-seekable frames
- //{
- // find the last seekable frame
- off_t tsize = 0;
- uint32_t prevTagSize = 0;
+ //if(!bAudioOnly) // we have to handle video/video+audio different since we have non-seekable frames
+ //{
+ // find the last seekable frame
+ off_t tsize = 0;
+ uint32_t prevTagSize = 0;
- // go through the file and find the last video keyframe
- do {
- int xread;
-skipkeyframe:
- if(size-tsize < 13) {
- Log(LOGERROR, "Unexpected start of file, error in tag sizes, couldn't arrive at prevTagSize=0");
- return RD_FAILED;
- }
- fseeko(file, size-tsize-4, SEEK_SET);
- xread = fread(buffer, 1, 4, file);
- if(xread != 4) {
- Log(LOGERROR, "Couldn't read prevTagSize from file!");
- return RD_FAILED;
- }
+ // go through the file and find the last video keyframe
+ do
+ {
+ int xread;
+ skipkeyframe:
+ if (size - tsize < 13)
+ {
+ Log(LOGERROR,
+ "Unexpected start of file, error in tag sizes, couldn't arrive at prevTagSize=0");
+ return RD_FAILED;
+ }
+ fseeko(file, size - tsize - 4, SEEK_SET);
+ xread = fread(buffer, 1, 4, file);
+ if (xread != 4)
+ {
+ Log(LOGERROR, "Couldn't read prevTagSize from file!");
+ return RD_FAILED;
+ }
- prevTagSize = AMF_DecodeInt32(buffer);
- //Log(LOGDEBUG, "Last packet: prevTagSize: %d", prevTagSize);
-
- if(prevTagSize == 0) {
- Log(LOGERROR, "Couldn't find keyframe to resume from!");
- return RD_FAILED;
- }
+ prevTagSize = AMF_DecodeInt32(buffer);
+ //Log(LOGDEBUG, "Last packet: prevTagSize: %d", prevTagSize);
- if(prevTagSize < 0 || prevTagSize > size-4-13) {
- Log(LOGERROR, "Last tag size must be greater/equal zero (prevTagSize=%d) and smaller then filesize, corrupt file!", prevTagSize);
- return RD_FAILED;
- }
- tsize += prevTagSize+4;
+ if (prevTagSize == 0)
+ {
+ Log(LOGERROR, "Couldn't find keyframe to resume from!");
+ return RD_FAILED;
+ }
- // read header
- fseeko(file, size-tsize, SEEK_SET);
- if(fread(buffer, 1, 12, file) != 12) {
- Log(LOGERROR, "Couldn't read header!");
- return RD_FAILED;
- }
- //*
+ if (prevTagSize < 0 || prevTagSize > size - 4 - 13)
+ {
+ Log(LOGERROR,
+ "Last tag size must be greater/equal zero (prevTagSize=%d) and smaller then filesize, corrupt file!",
+ prevTagSize);
+ return RD_FAILED;
+ }
+ tsize += prevTagSize + 4;
+
+ // read header
+ fseeko(file, size - tsize, SEEK_SET);
+ if (fread(buffer, 1, 12, file) != 12)
+ {
+ Log(LOGERROR, "Couldn't read header!");
+ return RD_FAILED;
+ }
+ //*
#ifdef _DEBUG
- uint32_t ts = AMF_DecodeInt24(buffer+4);
- ts |= (buffer[7]<<24);
- Log(LOGDEBUG, "%02X: TS: %d ms", buffer[0], ts);
-#endif //*/
+ uint32_t ts = AMF_DecodeInt24(buffer + 4);
+ ts |= (buffer[7] << 24);
+ Log(LOGDEBUG, "%02X: TS: %d ms", buffer[0], ts);
+#endif //*/
- // this just continues the loop whenever the number of skipped frames is > 0,
- // so we look for the next keyframe to continue with
- //
- // this helps if resuming from the last keyframe fails and one doesn't want to start
- // the download from the beginning
- //
- if(nSkipKeyFrames > 0 && !(!bAudioOnly && (buffer[0] != 0x09 || (buffer[11]&0xf0) != 0x10))) {
- #ifdef _DEBUG
- Log(LOGDEBUG, "xxxxxxxxxxxxxxxxxxxxxxxx Well, lets go one more back!");
- #endif
- nSkipKeyFrames--;
- goto skipkeyframe;
- }
+ // this just continues the loop whenever the number of skipped frames is > 0,
+ // so we look for the next keyframe to continue with
+ //
+ // this helps if resuming from the last keyframe fails and one doesn't want to start
+ // the download from the beginning
+ //
+ if (nSkipKeyFrames > 0
+ && !(!bAudioOnly
+ && (buffer[0] != 0x09 || (buffer[11] & 0xf0) != 0x10)))
+ {
+#ifdef _DEBUG
+ Log(LOGDEBUG,
+ "xxxxxxxxxxxxxxxxxxxxxxxx Well, lets go one more back!");
+#endif
+ nSkipKeyFrames--;
+ goto skipkeyframe;
+ }
- } while(
- (bAudioOnly && buffer[0] != 0x08) ||
- (!bAudioOnly && (buffer[0] != 0x09 || (buffer[11]&0xf0) != 0x10))
- ); // as long as we don't have a keyframe / last audio frame
-
- // save keyframe to compare/find position in stream
- *initialFrameType = buffer[0];
- *nInitialFrameSize = prevTagSize-11;
- *initialFrame = (char *)malloc(*nInitialFrameSize);
-
- fseeko(file, size-tsize+11, SEEK_SET);
- if(fread(*initialFrame, 1, *nInitialFrameSize, file) != *nInitialFrameSize) {
- Log(LOGERROR, "Couldn't read last keyframe, aborting!");
- return RD_FAILED;
- }
+ }
+ while ((bAudioOnly && buffer[0] != 0x08) || (!bAudioOnly && (buffer[0] != 0x09 || (buffer[11] & 0xf0) != 0x10))); // as long as we don't have a keyframe / last audio frame
- *dSeek = AMF_DecodeInt24(buffer+4); // set seek position to keyframe tmestamp
- *dSeek |= (buffer[7]<<24);
- //}
- //else // handle audio only, we can seek anywhere we'd like
- //{
- //}
+ // save keyframe to compare/find position in stream
+ *initialFrameType = buffer[0];
+ *nInitialFrameSize = prevTagSize - 11;
+ *initialFrame = (char *) malloc(*nInitialFrameSize);
- if(*dSeek < 0) {
- Log(LOGERROR, "Last keyframe timestamp is negative, aborting, your file is corrupt!");
- return RD_FAILED;
- }
- Log(LOGDEBUG,"Last keyframe found at: %d ms, size: %d, type: %02X", *dSeek, *nInitialFrameSize, *initialFrameType);
+ fseeko(file, size - tsize + 11, SEEK_SET);
+ if (fread(*initialFrame, 1, *nInitialFrameSize, file) != *nInitialFrameSize)
+ {
+ Log(LOGERROR, "Couldn't read last keyframe, aborting!");
+ return RD_FAILED;
+ }
- /*
- // now read the timestamp of the frame before the seekable keyframe:
- fseeko(file, size-tsize-4, SEEK_SET);
- if(fread(buffer, 1, 4, file) != 4) {
- Log(LOGERROR, "Couldn't read prevTagSize from file!");
- goto start;
- }
- uint32_t prevTagSize = RTMP_LIB::AMF_DecodeInt32(buffer);
- fseeko(file, size-tsize-4-prevTagSize+4, SEEK_SET);
- if(fread(buffer, 1, 4, file) != 4) {
- Log(LOGERROR, "Couldn't read previous timestamp!");
- goto start;
- }
- uint32_t timestamp = RTMP_LIB::AMF_DecodeInt24(buffer);
- timestamp |= (buffer[3]<<24);
+ *dSeek = AMF_DecodeInt24(buffer + 4); // set seek position to keyframe tmestamp
+ *dSeek |= (buffer[7] << 24);
+ //}
+ //else // handle audio only, we can seek anywhere we'd like
+ //{
+ //}
- Log(LOGDEBUG, "Previuos timestamp: %d ms", timestamp);
- */
+ if (*dSeek < 0)
+ {
+ Log(LOGERROR,
+ "Last keyframe timestamp is negative, aborting, your file is corrupt!");
+ return RD_FAILED;
+ }
+ Log(LOGDEBUG, "Last keyframe found at: %d ms, size: %d, type: %02X", *dSeek,
+ *nInitialFrameSize, *initialFrameType);
- if(*dSeek != 0) {
- // seek to position after keyframe in our file (we will ignore the keyframes resent by the server
- // since they are sent a couple of times and handling this would be a mess)
- fseeko(file, size-tsize+prevTagSize+4, SEEK_SET);
-
- // make sure the WriteStream doesn't write headers and ignores all the 0ms TS packets
- // (including several meta data headers and the keyframe we seeked to)
- //bNoHeader = true; if bResume==true this is true anyway
- }
+ /*
+ // now read the timestamp of the frame before the seekable keyframe:
+ fseeko(file, size-tsize-4, SEEK_SET);
+ if(fread(buffer, 1, 4, file) != 4) {
+ Log(LOGERROR, "Couldn't read prevTagSize from file!");
+ goto start;
+ }
+ uint32_t prevTagSize = RTMP_LIB::AMF_DecodeInt32(buffer);
+ fseeko(file, size-tsize-4-prevTagSize+4, SEEK_SET);
+ if(fread(buffer, 1, 4, file) != 4) {
+ Log(LOGERROR, "Couldn't read previous timestamp!");
+ goto start;
+ }
+ uint32_t timestamp = RTMP_LIB::AMF_DecodeInt24(buffer);
+ timestamp |= (buffer[3]<<24);
- //}
+ Log(LOGDEBUG, "Previuos timestamp: %d ms", timestamp);
+ */
- return RD_SUCCESS;
+ if (*dSeek != 0)
+ {
+ // seek to position after keyframe in our file (we will ignore the keyframes resent by the server
+ // since they are sent a couple of times and handling this would be a mess)
+ fseeko(file, size - tsize + prevTagSize + 4, SEEK_SET);
+
+ // make sure the WriteStream doesn't write headers and ignores all the 0ms TS packets
+ // (including several meta data headers and the keyframe we seeked to)
+ //bNoHeader = true; if bResume==true this is true anyway
+ }
+
+ //}
+
+ return RD_SUCCESS;
}
-int Download(RTMP *rtmp, // connected RTMP object
- FILE *file,
- uint32_t dSeek,
- uint32_t dLength,
- double duration,
- bool bResume,
- char *metaHeader,
- uint32_t nMetaHeaderSize,
- char *initialFrame,
- int initialFrameType,
- uint32_t nInitialFrameSize,
- int nSkipKeyFrames,
- bool bStdoutMode,
- bool bLiveStream,
- bool bHashes,
- bool bOverrideBufferTime,
- uint32_t bufferTime,
- double *percent) // percentage downloaded [out]
+int
+Download(RTMP * rtmp, // connected RTMP object
+ FILE * file, uint32_t dSeek, uint32_t dLength, double duration, bool bResume, char *metaHeader, uint32_t nMetaHeaderSize, char *initialFrame, int initialFrameType, uint32_t nInitialFrameSize, int nSkipKeyFrames, bool bStdoutMode, bool bLiveStream, bool bHashes, bool bOverrideBufferTime, uint32_t bufferTime, double *percent) // percentage downloaded [out]
{
- uint32_t timestamp = dSeek;
- int32_t now, lastUpdate;
- uint8_t dataType = 0; // will be written into the FLV header (position 4)
- int bufferSize = 1024*1024;
- char *buffer = (char *)malloc(bufferSize);
- int nRead = 0;
- off_t size = ftello(file);
- unsigned long lastPercent = 0;
+ uint32_t timestamp = dSeek;
+ int32_t now, lastUpdate;
+ uint8_t dataType = 0; // will be written into the FLV header (position 4)
+ int bufferSize = 1024 * 1024;
+ char *buffer = (char *) malloc(bufferSize);
+ int nRead = 0;
+ off_t size = ftello(file);
+ unsigned long lastPercent = 0;
- memset(buffer, 0, bufferSize);
+ memset(buffer, 0, bufferSize);
- *percent = 0.0;
+ *percent = 0.0;
- if(timestamp) {
- Log(LOGDEBUG, "Continuing at TS: %d ms\n", timestamp);
- }
+ if (timestamp)
+ {
+ Log(LOGDEBUG, "Continuing at TS: %d ms\n", timestamp);
+ }
- if(bLiveStream) {
- LogPrintf("Starting Live Stream\n");
- } else {
- // print initial status
- // Workaround to exit with 0 if the file is fully (> 99.9%) downloaded
- if( duration > 0 ) {
- if ((double)timestamp >= (double)duration*999.0 ) {
- LogPrintf("Already Completed at: %.3f sec Duration=%.3f sec\n", (double)timestamp/1000.0, (double)duration/1000.0);
- return RD_SUCCESS;
- } else {
- *percent = ((double)timestamp) / (duration*1000.0)*100.0;
- *percent = ((double)(int)(*percent*10.0))/10.0;
- LogPrintf("%s download at: %.3f kB / %.3f sec (%.1f%%)\n",
- bResume ? "Resuming":"Starting",
- (double)size/1024.0, (double)timestamp/1000.0, *percent);
- }
- } else {
- LogPrintf("%s download at: %.3f kB\n", bResume ? "Resuming":"Starting",(double)size/1024.0);
- }
+ if (bLiveStream)
+ {
+ LogPrintf("Starting Live Stream\n");
+ }
+ else
+ {
+ // print initial status
+ // Workaround to exit with 0 if the file is fully (> 99.9%) downloaded
+ if (duration > 0)
+ {
+ if ((double) timestamp >= (double) duration * 999.0)
+ {
+ LogPrintf("Already Completed at: %.3f sec Duration=%.3f sec\n",
+ (double) timestamp / 1000.0,
+ (double) duration / 1000.0);
+ return RD_SUCCESS;
+ }
+ else
+ {
+ *percent = ((double) timestamp) / (duration * 1000.0) * 100.0;
+ *percent = ((double) (int) (*percent * 10.0)) / 10.0;
+ LogPrintf("%s download at: %.3f kB / %.3f sec (%.1f%%)\n",
+ bResume ? "Resuming" : "Starting",
+ (double) size / 1024.0, (double) timestamp / 1000.0,
+ *percent);
+ }
+ }
+ else
+ {
+ LogPrintf("%s download at: %.3f kB\n",
+ bResume ? "Resuming" : "Starting",
+ (double) size / 1024.0);
}
+ }
- if (dLength > 0)
- LogPrintf("For duration: %.3f sec\n", (double)dLength/1000.0);
+ if (dLength > 0)
+ LogPrintf("For duration: %.3f sec\n", (double) dLength / 1000.0);
- // write FLV header if not resuming
- if(!bResume) {
- nRead = WriteHeader(&buffer, bufferSize);
- if(nRead > 0) {
- if(fwrite(buffer, sizeof(unsigned char), nRead, file) != (size_t)nRead) {
- Log(LOGERROR, "%s: Failed writing FLV header, exiting!", __FUNCTION__);
- free(buffer);
- return RD_FAILED;
- }
- size += nRead;
- } else {
- Log(LOGERROR, "Couldn't obtain FLV header, exiting!");
- free(buffer);
- return RD_FAILED;
- }
+ // write FLV header if not resuming
+ if (!bResume)
+ {
+ nRead = WriteHeader(&buffer, bufferSize);
+ if (nRead > 0)
+ {
+ if (fwrite(buffer, sizeof(unsigned char), nRead, file) !=
+ (size_t) nRead)
+ {
+ Log(LOGERROR, "%s: Failed writing FLV header, exiting!",
+ __FUNCTION__);
+ free(buffer);
+ return RD_FAILED;
+ }
+ size += nRead;
+ }
+ else
+ {
+ Log(LOGERROR, "Couldn't obtain FLV header, exiting!");
+ free(buffer);
+ return RD_FAILED;
}
+ }
- now = RTMP_GetTime();
- lastUpdate = now-1000;
- do
+ now = RTMP_GetTime();
+ lastUpdate = now - 1000;
+ do
+ {
+ nRead = WriteStream(rtmp, &buffer, bufferSize, ×tamp, bResume
+ && nInitialFrameSize > 0, bLiveStream, dSeek,
+ metaHeader, nMetaHeaderSize, initialFrame,
+ initialFrameType, nInitialFrameSize, &dataType);
+
+ //LogPrintf("nRead: %d\n", nRead);
+ if (nRead > 0)
{
- nRead = WriteStream(rtmp, &buffer, bufferSize, ×tamp, bResume && nInitialFrameSize > 0, bLiveStream, dSeek, metaHeader, nMetaHeaderSize, initialFrame, initialFrameType, nInitialFrameSize, &dataType);
+ if (fwrite(buffer, sizeof(unsigned char), nRead, file) !=
+ (size_t) nRead)
+ {
+ Log(LOGERROR, "%s: Failed writing, exiting!", __FUNCTION__);
+ free(buffer);
+ return RD_FAILED;
+ }
+ size += nRead;
- //LogPrintf("nRead: %d\n", nRead);
- if(nRead > 0) {
- if(fwrite(buffer, sizeof(unsigned char), nRead, file) != (size_t)nRead) {
- Log(LOGERROR, "%s: Failed writing, exiting!", __FUNCTION__);
- free(buffer);
- return RD_FAILED;
- }
- size += nRead;
-
- //LogPrintf("write %dbytes (%.1f kB)\n", nRead, nRead/1024.0);
- if(duration <= 0) // if duration unknown try to get it from the stream (onMetaData)
- duration = RTMP_GetDuration(rtmp);
+ //LogPrintf("write %dbytes (%.1f kB)\n", nRead, nRead/1024.0);
+ if (duration <= 0) // if duration unknown try to get it from the stream (onMetaData)
+ duration = RTMP_GetDuration(rtmp);
- if(duration > 0) {
- // make sure we claim to have enough buffer time!
- if(!bOverrideBufferTime && bufferTime < (duration*1000.0)) {
- bufferTime = (uint32_t)(duration*1000.0)+5000; // extra 5sec to make sure we've got enough
-
- Log(LOGDEBUG, "Detected that buffer time is less than duration, resetting to: %dms", bufferTime);
- RTMP_SetBufferMS(rtmp, bufferTime);
- RTMP_UpdateBufferMS(rtmp);
- }
- *percent = ((double)timestamp) / (duration*1000.0)*100.0;
- *percent = ((double)(int)(*percent*10.0))/10.0;
- if (bHashes) {
- if ( lastPercent + 1 <= *percent ) {
- LogStatus("#");
- lastPercent = (unsigned long)*percent;
- }
- } else {
- now = RTMP_GetTime();
- if (abs(now - lastUpdate) > 200) {
- LogStatus("\r%.3f kB / %.2f sec (%.1f%%)", (double)size/1024.0, (double)(timestamp)/1000.0, *percent);
- lastUpdate = now;
- }
- }
- } else {
- now = RTMP_GetTime();
- if (abs(now - lastUpdate) > 200) {
- if (bHashes)
- LogStatus("#");
- else
- LogStatus("\r%.3f kB / %.2f sec", (double)size/1024.0, (double)(timestamp)/1000.0);
- lastUpdate = now;
- }
- }
+ if (duration > 0)
+ {
+ // make sure we claim to have enough buffer time!
+ if (!bOverrideBufferTime && bufferTime < (duration * 1000.0))
+ {
+ bufferTime = (uint32_t) (duration * 1000.0) + 5000; // extra 5sec to make sure we've got enough
+
+ Log(LOGDEBUG,
+ "Detected that buffer time is less than duration, resetting to: %dms",
+ bufferTime);
+ RTMP_SetBufferMS(rtmp, bufferTime);
+ RTMP_UpdateBufferMS(rtmp);
}
+ *percent = ((double) timestamp) / (duration * 1000.0) * 100.0;
+ *percent = ((double) (int) (*percent * 10.0)) / 10.0;
+ if (bHashes)
+ {
+ if (lastPercent + 1 <= *percent)
+ {
+ LogStatus("#");
+ lastPercent = (unsigned long) *percent;
+ }
+ }
+ else
+ {
+ now = RTMP_GetTime();
+ if (abs(now - lastUpdate) > 200)
+ {
+ LogStatus("\r%.3f kB / %.2f sec (%.1f%%)",
+ (double) size / 1024.0,
+ (double) (timestamp) / 1000.0, *percent);
+ lastUpdate = now;
+ }
+ }
+ }
+ else
+ {
+ now = RTMP_GetTime();
+ if (abs(now - lastUpdate) > 200)
+ {
+ if (bHashes)
+ LogStatus("#");
+ else
+ LogStatus("\r%.3f kB / %.2f sec", (double) size / 1024.0,
+ (double) (timestamp) / 1000.0);
+ lastUpdate = now;
+ }
+ }
+ }
#ifdef _DEBUG
- else { Log(LOGDEBUG, "zero read!"); }
+ else
+ {
+ Log(LOGDEBUG, "zero read!");
+ }
#endif
- } while(!bCtrlC && nRead > -1 && RTMP_IsConnected(rtmp));
- free(buffer);
+ }
+ while (!bCtrlC && nRead > -1 && RTMP_IsConnected(rtmp));
+ free(buffer);
- Log(LOGDEBUG, "WriteStream returned: %d", nRead);
+ Log(LOGDEBUG, "WriteStream returned: %d", nRead);
- if(bResume && nRead == -2) {
- LogPrintf("Couldn't resume FLV file, try --skip %d\n\n", nSkipKeyFrames+1);
- return RD_FAILED;
- }
+ if (bResume && nRead == -2)
+ {
+ LogPrintf("Couldn't resume FLV file, try --skip %d\n\n",
+ nSkipKeyFrames + 1);
+ return RD_FAILED;
+ }
- // finalize header by writing the correct dataType (video, audio, video+audio)
- if(!bResume && dataType != 0x5 && !bStdoutMode) {
- //Log(LOGDEBUG, "Writing data type: %02X", dataType);
- fseek(file, 4, SEEK_SET);
- fwrite(&dataType, sizeof(unsigned char), 1, file);
- }
+ // finalize header by writing the correct dataType (video, audio, video+audio)
+ if (!bResume && dataType != 0x5 && !bStdoutMode)
+ {
+ //Log(LOGDEBUG, "Writing data type: %02X", dataType);
+ fseek(file, 4, SEEK_SET);
+ fwrite(&dataType, sizeof(unsigned char), 1, file);
+ }
- if(nRead == -3)
- return RD_SUCCESS;
+ if (nRead == -3)
+ return RD_SUCCESS;
- if((duration > 0 && *percent < 99.9) || bCtrlC || nRead < 0 || RTMP_IsTimedout(rtmp)) {
- return RD_INCOMPLETE;
- }
+ if ((duration > 0 && *percent < 99.9) || bCtrlC || nRead < 0
+ || RTMP_IsTimedout(rtmp))
+ {
+ return RD_INCOMPLETE;
+ }
- return RD_SUCCESS;
+ return RD_SUCCESS;
}
#define STR2AVAL(av,str) av.av_val = str; av.av_len = strlen(av.av_val)
-int main(int argc, char **argv)
+int
+main(int argc, char **argv)
{
- extern char *optarg;
+ extern char *optarg;
- int nStatus = RD_SUCCESS;
- double percent = 0;
- double duration = 0.0;
+ int nStatus = RD_SUCCESS;
+ double percent = 0;
+ double duration = 0.0;
- int nSkipKeyFrames = 0; // skip this number of keyframes when resuming
+ int nSkipKeyFrames = 0; // skip this number of keyframes when resuming
- bool bOverrideBufferTime = false; // if the user specifies a buffer time override this is true
- bool bStdoutMode = true;// if true print the stream directly to stdout, messages go to stderr
- bool bResume = false; // true in resume mode
- uint32_t dSeek = 0; // seek position in resume mode, 0 otherwise
- uint32_t bufferTime = 10*60*60*1000; // 10 hours as default
+ bool bOverrideBufferTime = false; // if the user specifies a buffer time override this is true
+ bool bStdoutMode = true; // if true print the stream directly to stdout, messages go to stderr
+ bool bResume = false; // true in resume mode
+ uint32_t dSeek = 0; // seek position in resume mode, 0 otherwise
+ uint32_t bufferTime = 10 * 60 * 60 * 1000; // 10 hours as default
- // meta header and initial frame for the resume mode (they are read from the file and compared with
- // the stream we are trying to continue
- char *metaHeader = 0;
- uint32_t nMetaHeaderSize = 0;
-
- // video keyframe for matching
- char *initialFrame = 0;
- uint32_t nInitialFrameSize = 0;
- int initialFrameType = 0; // tye: audio or video
+ // meta header and initial frame for the resume mode (they are read from the file and compared with
+ // the stream we are trying to continue
+ char *metaHeader = 0;
+ uint32_t nMetaHeaderSize = 0;
- char *hostname = 0;
- AVal playpath = {0,0};
- AVal subscribepath = {0,0};
- int port = -1;
- int protocol = RTMP_PROTOCOL_UNDEFINED;
- bool bLiveStream = false; // is it a live stream? then we can't seek/resume
- bool bHashes = false; // display byte counters not hashes by default
+ // video keyframe for matching
+ char *initialFrame = 0;
+ uint32_t nInitialFrameSize = 0;
+ int initialFrameType = 0; // tye: audio or video
- long int timeout = 120; // timeout connection after 120 seconds
- uint32_t dStartOffset = 0; // seek position in non-live mode
- uint32_t dStopOffset = 0;
- uint32_t dLength = 0; // length to play from stream - calculated from seek position and dStopOffset
+ char *hostname = 0;
+ AVal playpath = { 0, 0 };
+ AVal subscribepath = { 0, 0 };
+ int port = -1;
+ int protocol = RTMP_PROTOCOL_UNDEFINED;
+ bool bLiveStream = false; // is it a live stream? then we can't seek/resume
+ bool bHashes = false; // display byte counters not hashes by default
- char *rtmpurl = 0;
- AVal swfUrl = {0,0};
- AVal tcUrl = {0,0};
- AVal pageUrl = {0,0};
- AVal app = {0,0};
- AVal auth = {0,0};
- AVal swfHash = {0,0};
- uint32_t swfSize = 0;
- AVal flashVer = {0,0};
- char *sockshost = 0;
+ long int timeout = 120; // timeout connection after 120 seconds
+ uint32_t dStartOffset = 0; // seek position in non-live mode
+ uint32_t dStopOffset = 0;
+ uint32_t dLength = 0; // length to play from stream - calculated from seek position and dStopOffset
- char *flvFile = 0;
+ char *rtmpurl = 0;
+ AVal swfUrl = { 0, 0 };
+ AVal tcUrl = { 0, 0 };
+ AVal pageUrl = { 0, 0 };
+ AVal app = { 0, 0 };
+ AVal auth = { 0, 0 };
+ AVal swfHash = { 0, 0 };
+ uint32_t swfSize = 0;
+ AVal flashVer = { 0, 0 };
+ char *sockshost = 0;
- char DEFAULT_FLASH_VER[] = "LNX 10,0,22,87";
-
- signal(SIGHUP, sigIntHandler);
- signal(SIGINT, sigIntHandler);
- signal(SIGPIPE, sigIntHandler);
- signal(SIGTERM, sigIntHandler);
- signal(SIGQUIT, sigIntHandler);
+ char *flvFile = 0;
- /* sleep(30); */
+ char DEFAULT_FLASH_VER[] = "LNX 10,0,22,87";
- // Check for --quiet option before printing any output
- int index = 0;
- while (index < argc)
- {
- if ( strcmp( argv[index], "--quiet")==0 || strcmp( argv[index], "-q")==0 )
- debuglevel = LOGCRIT;
- index++;
- }
+ signal(SIGHUP, sigIntHandler);
+ signal(SIGINT, sigIntHandler);
+ signal(SIGPIPE, sigIntHandler);
+ signal(SIGTERM, sigIntHandler);
+ signal(SIGQUIT, sigIntHandler);
- LogPrintf("RTMPDump %s\n", RTMPDUMP_VERSION);
- LogPrintf("(c) 2009 Andrej Stepanchuk, Howard Chu, The Flvstreamer Team; license: GPL\n");
+ /* sleep(30); */
- int opt;
- struct option longopts[] = {
- {"help", 0, NULL, 'h'},
- {"host", 1, NULL, 'n'},
- {"port", 1, NULL, 'c'},
- {"socks", 1, NULL, 'S'},
- {"protocol",1, NULL, 'l'},
- {"playpath",1, NULL, 'y'},
- {"rtmp", 1, NULL, 'r'},
- {"swfUrl", 1, NULL, 's'},
- {"tcUrl", 1, NULL, 't'},
- {"pageUrl", 1, NULL, 'p'},
- {"app", 1, NULL, 'a'},
- {"auth", 1, NULL, 'u'},
+ // Check for --quiet option before printing any output
+ int index = 0;
+ while (index < argc)
+ {
+ if (strcmp(argv[index], "--quiet") == 0
+ || strcmp(argv[index], "-q") == 0)
+ debuglevel = LOGCRIT;
+ index++;
+ }
+
+ LogPrintf("RTMPDump %s\n", RTMPDUMP_VERSION);
+ LogPrintf
+ ("(c) 2009 Andrej Stepanchuk, Howard Chu, The Flvstreamer Team; license: GPL\n");
+
+ int opt;
+ struct option longopts[] = {
+ {"help", 0, NULL, 'h'},
+ {"host", 1, NULL, 'n'},
+ {"port", 1, NULL, 'c'},
+ {"socks", 1, NULL, 'S'},
+ {"protocol", 1, NULL, 'l'},
+ {"playpath", 1, NULL, 'y'},
+ {"rtmp", 1, NULL, 'r'},
+ {"swfUrl", 1, NULL, 's'},
+ {"tcUrl", 1, NULL, 't'},
+ {"pageUrl", 1, NULL, 'p'},
+ {"app", 1, NULL, 'a'},
+ {"auth", 1, NULL, 'u'},
#ifdef CRYPTO
- {"swfhash", 1, NULL, 'w'},
- {"swfsize", 1, NULL, 'x'},
+ {"swfhash", 1, NULL, 'w'},
+ {"swfsize", 1, NULL, 'x'},
#endif
- {"flashVer",1, NULL, 'f'},
- {"live" ,0, NULL, 'v'},
- {"flv", 1, NULL, 'o'},
- {"resume", 0, NULL, 'e'},
- {"timeout", 1, NULL, 'm'},
- {"buffer", 1, NULL, 'b'},
- {"skip", 1, NULL, 'k'},
- {"subscribe",1,NULL, 'd'},
- {"start", 1, NULL, 'A'},
- {"stop", 1, NULL, 'B'},
- {"hashes", 0, NULL, '#'},
- {"debug", 0, NULL, 'z'},
- {"quiet", 0, NULL, 'q'},
- {"verbose", 0, NULL, 'V'},
- {0,0,0,0}
- };
+ {"flashVer", 1, NULL, 'f'},
+ {"live", 0, NULL, 'v'},
+ {"flv", 1, NULL, 'o'},
+ {"resume", 0, NULL, 'e'},
+ {"timeout", 1, NULL, 'm'},
+ {"buffer", 1, NULL, 'b'},
+ {"skip", 1, NULL, 'k'},
+ {"subscribe", 1, NULL, 'd'},
+ {"start", 1, NULL, 'A'},
+ {"stop", 1, NULL, 'B'},
+ {"hashes", 0, NULL, '#'},
+ {"debug", 0, NULL, 'z'},
+ {"quiet", 0, NULL, 'q'},
+ {"verbose", 0, NULL, 'V'},
+ {0, 0, 0, 0}
+ };
- while((opt = getopt_long(argc, argv, "hVveqzr:s:t:p:a:b:f:o:u:n:c:l:y:m:k:d:A:B:w:x:S:#", longopts, NULL)) != -1) {
- switch(opt) {
- case 'h':
- LogPrintf("\nThis program dumps the media content streamed over rtmp.\n\n");
- LogPrintf("--help|-h Prints this help screen.\n");
- LogPrintf("--rtmp|-r url URL (e.g. rtmp//hotname[:port]/path)\n");
- LogPrintf("--host|-n hostname Overrides the hostname in the rtmp url\n");
- LogPrintf("--port|-c port Overrides the port in the rtmp url\n");
- LogPrintf("--socks|-S host:port Use the specified SOCKS proxy\n");
- LogPrintf("--protocol|-l Overrides the protocol in the rtmp url (0 - RTMP, 3 - RTMPE)\n");
- LogPrintf("--playpath|-y Overrides the playpath parsed from rtmp url\n");
- LogPrintf("--swfUrl|-s url URL to player swf file\n");
- LogPrintf("--tcUrl|-t url URL to played stream (default: \"rtmp://host[:port]/app\")\n");
- LogPrintf("--pageUrl|-p url Web URL of played programme\n");
- LogPrintf("--app|-a app Name of player used\n");
+ while ((opt =
+ getopt_long(argc, argv,
+ "hVveqzr:s:t:p:a:b:f:o:u:n:c:l:y:m:k:d:A:B:w:x:S:#",
+ longopts, NULL)) != -1)
+ {
+ switch (opt)
+ {
+ case 'h':
+ LogPrintf
+ ("\nThis program dumps the media content streamed over rtmp.\n\n");
+ LogPrintf("--help|-h Prints this help screen.\n");
+ LogPrintf
+ ("--rtmp|-r url URL (e.g. rtmp//hotname[:port]/path)\n");
+ LogPrintf
+ ("--host|-n hostname Overrides the hostname in the rtmp url\n");
+ LogPrintf
+ ("--port|-c port Overrides the port in the rtmp url\n");
+ LogPrintf
+ ("--socks|-S host:port Use the specified SOCKS proxy\n");
+ LogPrintf
+ ("--protocol|-l Overrides the protocol in the rtmp url (0 - RTMP, 3 - RTMPE)\n");
+ LogPrintf
+ ("--playpath|-y Overrides the playpath parsed from rtmp url\n");
+ LogPrintf("--swfUrl|-s url URL to player swf file\n");
+ LogPrintf
+ ("--tcUrl|-t url URL to played stream (default: \"rtmp://host[:port]/app\")\n");
+ LogPrintf("--pageUrl|-p url Web URL of played programme\n");
+ LogPrintf("--app|-a app Name of player used\n");
#ifdef CRYPTO
- LogPrintf("--swfhash|-w hexstring SHA256 hash of the decompressed SWF file (32 bytes)\n");
- LogPrintf("--swfsize|-x num Size of the decompressed SWF file, required for SWFVerification\n");
+ LogPrintf
+ ("--swfhash|-w hexstring SHA256 hash of the decompressed SWF file (32 bytes)\n");
+ LogPrintf
+ ("--swfsize|-x num Size of the decompressed SWF file, required for SWFVerification\n");
#endif
- LogPrintf("--auth|-u string Authentication string to be appended to the connect string\n");
- LogPrintf("--flashVer|-f string Flash version string (default: \"%s\")\n", DEFAULT_FLASH_VER);
- LogPrintf("--live|-v Save a live stream, no --resume (seeking) of live streams possible\n");
- LogPrintf("--subscribe|-d string Stream name to subscribe to (otherwise defaults to playpath if live is specifed)\n");
- LogPrintf("--flv|-o string FLV output file name, if the file name is - print stream to stdout\n");
- LogPrintf("--resume|-e Resume a partial RTMP download\n");
- LogPrintf("--timeout|-m num Timeout connection num seconds (default: %lu)\n", timeout);
- LogPrintf("--start|-A num Start at num seconds into stream (not valid when using --live)\n");
- LogPrintf("--stop|-B num Stop at num seconds into stream\n");
- LogPrintf("--hashes|-# Display progress with hashes, not with the byte counter\n");
- LogPrintf("--buffer|-b Buffer time in milliseconds (default: %lu), this option makes only sense in stdout mode (-o -)\n",
- bufferTime);
- LogPrintf("--skip|-k num Skip num keyframes when looking for last keyframe to resume from. Useful if resume fails (default: %d)\n\n",
- nSkipKeyFrames);
- LogPrintf("--quiet|-q Supresses all command output.\n");
- LogPrintf("--verbose|-V Verbose command output.\n");
- LogPrintf("--debug|-z Debug level command output.\n");
- LogPrintf("If you don't pass parameters for swfUrl, pageUrl, app or auth these propertiews will not be included in the connect ");
- LogPrintf("packet.\n\n");
- return RD_SUCCESS;
+ LogPrintf
+ ("--auth|-u string Authentication string to be appended to the connect string\n");
+ LogPrintf
+ ("--flashVer|-f string Flash version string (default: \"%s\")\n",
+ DEFAULT_FLASH_VER);
+ LogPrintf
+ ("--live|-v Save a live stream, no --resume (seeking) of live streams possible\n");
+ LogPrintf
+ ("--subscribe|-d string Stream name to subscribe to (otherwise defaults to playpath if live is specifed)\n");
+ LogPrintf
+ ("--flv|-o string FLV output file name, if the file name is - print stream to stdout\n");
+ LogPrintf
+ ("--resume|-e Resume a partial RTMP download\n");
+ LogPrintf
+ ("--timeout|-m num Timeout connection num seconds (default: %lu)\n",
+ timeout);
+ LogPrintf
+ ("--start|-A num Start at num seconds into stream (not valid when using --live)\n");
+ LogPrintf
+ ("--stop|-B num Stop at num seconds into stream\n");
+ LogPrintf
+ ("--hashes|-# Display progress with hashes, not with the byte counter\n");
+ LogPrintf
+ ("--buffer|-b Buffer time in milliseconds (default: %lu), this option makes only sense in stdout mode (-o -)\n",
+ bufferTime);
+ LogPrintf
+ ("--skip|-k num Skip num keyframes when looking for last keyframe to resume from. Useful if resume fails (default: %d)\n\n",
+ nSkipKeyFrames);
+ LogPrintf
+ ("--quiet|-q Supresses all command output.\n");
+ LogPrintf("--verbose|-V Verbose command output.\n");
+ LogPrintf("--debug|-z Debug level command output.\n");
+ LogPrintf
+ ("If you don't pass parameters for swfUrl, pageUrl, app or auth these propertiews will not be included in the connect ");
+ LogPrintf("packet.\n\n");
+ return RD_SUCCESS;
#ifdef CRYPTO
- case 'w':
- {
- int res = hex2bin(optarg, &swfHash.av_val);
- if(res!=32) {
- swfHash.av_val = NULL;
- Log(LOGWARNING, "Couldn't parse swf hash hex string, not heyxstring or not 32 bytes, ignoring!");
- }
- swfHash.av_len = 32;
- break;
- }
- case 'x':
- {
- int size = atoi(optarg);
- if(size <= 0) {
- Log(LOGERROR, "SWF Size must be at least 1, ignoring\n");
- } else {
- swfSize = size;
- }
- break;
- }
+ case 'w':
+ {
+ int res = hex2bin(optarg, &swfHash.av_val);
+ if (res != 32)
+ {
+ swfHash.av_val = NULL;
+ Log(LOGWARNING,
+ "Couldn't parse swf hash hex string, not heyxstring or not 32 bytes, ignoring!");
+ }
+ swfHash.av_len = 32;
+ break;
+ }
+ case 'x':
+ {
+ int size = atoi(optarg);
+ if (size <= 0)
+ {
+ Log(LOGERROR, "SWF Size must be at least 1, ignoring\n");
+ }
+ else
+ {
+ swfSize = size;
+ }
+ break;
+ }
#endif
- case 'k':
- nSkipKeyFrames = atoi(optarg);
- if(nSkipKeyFrames < 0) {
- Log(LOGERROR, "Number of keyframes skipped must be greater or equal zero, using zero!");
- nSkipKeyFrames = 0;
- } else {
- Log(LOGDEBUG, "Number of skipped key frames for resume: %d", nSkipKeyFrames);
- }
- break;
- case 'b':
- {
- int32_t bt = atol(optarg);
- if(bt < 0) {
- Log(LOGERROR, "Buffer time must be greater than zero, ignoring the specified value %d!", bt);
- } else {
- bufferTime = bt;
- bOverrideBufferTime = true;
- }
- break;
- }
- case 'v':
- bLiveStream = true; // no seeking or resuming possible!
- break;
- case 'd':
- STR2AVAL(subscribepath, optarg);
- break;
- case 'n':
- hostname = optarg;
- break;
- case 'c':
- port = atoi(optarg);
- break;
- case 'l':
- protocol = atoi(optarg);
- if(protocol != RTMP_PROTOCOL_RTMP && protocol != RTMP_PROTOCOL_RTMPE) {
- Log(LOGERROR, "Unknown protocol specified: %d", protocol);
- return RD_FAILED;
- }
- break;
- case 'y':
- STR2AVAL(playpath, optarg);
- break;
- case 'r':
- {
- rtmpurl = optarg;
+ case 'k':
+ nSkipKeyFrames = atoi(optarg);
+ if (nSkipKeyFrames < 0)
+ {
+ Log(LOGERROR,
+ "Number of keyframes skipped must be greater or equal zero, using zero!");
+ nSkipKeyFrames = 0;
+ }
+ else
+ {
+ Log(LOGDEBUG, "Number of skipped key frames for resume: %d",
+ nSkipKeyFrames);
+ }
+ break;
+ case 'b':
+ {
+ int32_t bt = atol(optarg);
+ if (bt < 0)
+ {
+ Log(LOGERROR,
+ "Buffer time must be greater than zero, ignoring the specified value %d!",
+ bt);
+ }
+ else
+ {
+ bufferTime = bt;
+ bOverrideBufferTime = true;
+ }
+ break;
+ }
+ case 'v':
+ bLiveStream = true; // no seeking or resuming possible!
+ break;
+ case 'd':
+ STR2AVAL(subscribepath, optarg);
+ break;
+ case 'n':
+ hostname = optarg;
+ break;
+ case 'c':
+ port = atoi(optarg);
+ break;
+ case 'l':
+ protocol = atoi(optarg);
+ if (protocol != RTMP_PROTOCOL_RTMP
+ && protocol != RTMP_PROTOCOL_RTMPE)
+ {
+ Log(LOGERROR, "Unknown protocol specified: %d", protocol);
+ return RD_FAILED;
+ }
+ break;
+ case 'y':
+ STR2AVAL(playpath, optarg);
+ break;
+ case 'r':
+ {
+ rtmpurl = optarg;
- char *parsedHost = 0;
- unsigned int parsedPort = 0;
- char *parsedPlaypath = 0;
- char *parsedApp = 0;
- int parsedProtocol = RTMP_PROTOCOL_UNDEFINED;
+ char *parsedHost = 0;
+ unsigned int parsedPort = 0;
+ char *parsedPlaypath = 0;
+ char *parsedApp = 0;
+ int parsedProtocol = RTMP_PROTOCOL_UNDEFINED;
- if(!ParseUrl(rtmpurl, &parsedProtocol, &parsedHost, &parsedPort, &parsedPlaypath, &parsedApp)) {
- Log(LOGWARNING, "Couldn't parse the specified url (%s)!", optarg);
- } else {
- if(hostname == 0)
- hostname = parsedHost;
- if(port == -1)
- port = parsedPort;
- if(playpath.av_len == 0 && parsedPlaypath) {
- STR2AVAL(playpath, parsedPlaypath);
- }
- if(protocol == RTMP_PROTOCOL_UNDEFINED)
- protocol = parsedProtocol;
- if(app.av_len == 0 && parsedApp) {
- STR2AVAL(app, parsedApp);
- }
- }
- break;
- }
- case 's':
- STR2AVAL(swfUrl, optarg);
- break;
- case 't':
- STR2AVAL(tcUrl, optarg);
- break;
- case 'p':
- STR2AVAL(pageUrl, optarg);
- break;
- case 'a':
- STR2AVAL(app, optarg);
- break;
- case 'f':
- STR2AVAL(flashVer, optarg);
- break;
- case 'o':
- flvFile = optarg;
- if(strcmp(flvFile, "-"))
- bStdoutMode = false;
+ if (!ParseUrl
+ (rtmpurl, &parsedProtocol, &parsedHost, &parsedPort,
+ &parsedPlaypath, &parsedApp))
+ {
+ Log(LOGWARNING, "Couldn't parse the specified url (%s)!",
+ optarg);
+ }
+ else
+ {
+ if (hostname == 0)
+ hostname = parsedHost;
+ if (port == -1)
+ port = parsedPort;
+ if (playpath.av_len == 0 && parsedPlaypath)
+ {
+ STR2AVAL(playpath, parsedPlaypath);
+ }
+ if (protocol == RTMP_PROTOCOL_UNDEFINED)
+ protocol = parsedProtocol;
+ if (app.av_len == 0 && parsedApp)
+ {
+ STR2AVAL(app, parsedApp);
+ }
+ }
+ break;
+ }
+ case 's':
+ STR2AVAL(swfUrl, optarg);
+ break;
+ case 't':
+ STR2AVAL(tcUrl, optarg);
+ break;
+ case 'p':
+ STR2AVAL(pageUrl, optarg);
+ break;
+ case 'a':
+ STR2AVAL(app, optarg);
+ break;
+ case 'f':
+ STR2AVAL(flashVer, optarg);
+ break;
+ case 'o':
+ flvFile = optarg;
+ if (strcmp(flvFile, "-"))
+ bStdoutMode = false;
- break;
- case 'e':
- bResume = true;
- break;
- case 'u':
- STR2AVAL(auth, optarg);
- break;
- case 'm':
- timeout = atoi(optarg);
- break;
- case 'A':
- dStartOffset = (int)(atof(optarg)*1000.0);
- break;
- case 'B':
- dStopOffset = (int)(atof(optarg)*1000.0);
- break;
- case '#':
- bHashes = true;
- break;
- case 'q':
- debuglevel = LOGCRIT;
- break;
- case 'V':
- debuglevel = LOGDEBUG;
- break;
- case 'z':
- debuglevel = LOGALL;
- break;
- case 'S':
- sockshost = optarg;
- break;
- default:
- LogPrintf("unknown option: %c\n", opt);
- break;
- }
+ break;
+ case 'e':
+ bResume = true;
+ break;
+ case 'u':
+ STR2AVAL(auth, optarg);
+ break;
+ case 'm':
+ timeout = atoi(optarg);
+ break;
+ case 'A':
+ dStartOffset = (int) (atof(optarg) * 1000.0);
+ break;
+ case 'B':
+ dStopOffset = (int) (atof(optarg) * 1000.0);
+ break;
+ case '#':
+ bHashes = true;
+ break;
+ case 'q':
+ debuglevel = LOGCRIT;
+ break;
+ case 'V':
+ debuglevel = LOGDEBUG;
+ break;
+ case 'z':
+ debuglevel = LOGALL;
+ break;
+ case 'S':
+ sockshost = optarg;
+ break;
+ default:
+ LogPrintf("unknown option: %c\n", opt);
+ break;
}
+ }
- if(hostname == 0) {
- Log(LOGERROR, "You must specify a hostname (--host) or url (-r \"rtmp://host[:port]/playpath\") containing a hostname");
- return RD_FAILED;
- }
- if(playpath.av_len == 0) {
- Log(LOGERROR, "You must specify a playpath (--playpath) or url (-r \"rtmp://host[:port]/playpath\") containing a playpath");
- return RD_FAILED;
- }
-
- if(port == -1) {
- Log(LOGWARNING, "You haven't specified a port (--port) or rtmp url (-r), using default port 1935");
- port = 1935;
- }
- if(port == 0) {
- port = 1935;
- }
- if(protocol == RTMP_PROTOCOL_UNDEFINED) {
- Log(LOGWARNING, "You haven't specified a protocol (--protocol) or rtmp url (-r), using default protocol RTMP");
- protocol = RTMP_PROTOCOL_RTMP;
- }
- if(flvFile == 0) {
- Log(LOGWARNING, "You haven't specified an output file (-o filename), using stdout");
- bStdoutMode = true;
- }
+ if (hostname == 0)
+ {
+ Log(LOGERROR,
+ "You must specify a hostname (--host) or url (-r \"rtmp://host[:port]/playpath\") containing a hostname");
+ return RD_FAILED;
+ }
+ if (playpath.av_len == 0)
+ {
+ Log(LOGERROR,
+ "You must specify a playpath (--playpath) or url (-r \"rtmp://host[:port]/playpath\") containing a playpath");
+ return RD_FAILED;
+ }
- if(bStdoutMode && bResume) {
- Log(LOGWARNING, "Can't resume in stdout mode, ignoring --resume option");
- bResume = false;
- }
+ if (port == -1)
+ {
+ Log(LOGWARNING,
+ "You haven't specified a port (--port) or rtmp url (-r), using default port 1935");
+ port = 1935;
+ }
+ if (port == 0)
+ {
+ port = 1935;
+ }
+ if (protocol == RTMP_PROTOCOL_UNDEFINED)
+ {
+ Log(LOGWARNING,
+ "You haven't specified a protocol (--protocol) or rtmp url (-r), using default protocol RTMP");
+ protocol = RTMP_PROTOCOL_RTMP;
+ }
+ if (flvFile == 0)
+ {
+ Log(LOGWARNING,
+ "You haven't specified an output file (-o filename), using stdout");
+ bStdoutMode = true;
+ }
- if(bLiveStream && bResume) {
- Log(LOGWARNING, "Can't resume live stream, ignoring --resume option");
- bResume = false;
- }
+ if (bStdoutMode && bResume)
+ {
+ Log(LOGWARNING,
+ "Can't resume in stdout mode, ignoring --resume option");
+ bResume = false;
+ }
- if(swfHash.av_len == 0 && swfSize > 0) {
- Log(LOGWARNING, "Ignoring SWF size, supply also the hash with --swfhash");
- swfSize=0;
- }
+ if (bLiveStream && bResume)
+ {
+ Log(LOGWARNING, "Can't resume live stream, ignoring --resume option");
+ bResume = false;
+ }
- if(swfHash.av_len != 0 && swfSize == 0) {
- Log(LOGWARNING, "Ignoring SWF hash, supply also the swf size with --swfsize");
- swfHash.av_len = 0;
- swfHash.av_val = NULL;
- }
+ if (swfHash.av_len == 0 && swfSize > 0)
+ {
+ Log(LOGWARNING,
+ "Ignoring SWF size, supply also the hash with --swfhash");
+ swfSize = 0;
+ }
- if(flashVer.av_len == 0) {
- STR2AVAL(flashVer, DEFAULT_FLASH_VER);
- }
+ if (swfHash.av_len != 0 && swfSize == 0)
+ {
+ Log(LOGWARNING,
+ "Ignoring SWF hash, supply also the swf size with --swfsize");
+ swfHash.av_len = 0;
+ swfHash.av_val = NULL;
+ }
- if(!InitSockets()) {
- Log(LOGERROR, "Couldn't load sockets support on your platform, exiting!");
- return RD_FAILED;
- }
+ if (flashVer.av_len == 0)
+ {
+ STR2AVAL(flashVer, DEFAULT_FLASH_VER);
+ }
- if(tcUrl.av_len == 0 && app.av_len != 0) {
- char str[512]={0};
+ if (!InitSockets())
+ {
+ Log(LOGERROR,
+ "Couldn't load sockets support on your platform, exiting!");
+ return RD_FAILED;
+ }
- snprintf(str, 511, "%s://%s:%d/%s", RTMPProtocolStringsLower[protocol], hostname, port, app.av_val);
- tcUrl.av_len = strlen(str);
- tcUrl.av_val = (char *)malloc(tcUrl.av_len+1);
- strcpy(tcUrl.av_val, str);
- }
+ if (tcUrl.av_len == 0 && app.av_len != 0)
+ {
+ char str[512] = { 0 };
- int first = 1;
+ snprintf(str, 511, "%s://%s:%d/%s", RTMPProtocolStringsLower[protocol],
+ hostname, port, app.av_val);
+ tcUrl.av_len = strlen(str);
+ tcUrl.av_val = (char *) malloc(tcUrl.av_len + 1);
+ strcpy(tcUrl.av_val, str);
+ }
- // User defined seek offset
- if (dStartOffset > 0) {
- // Live stream
- if (bLiveStream) {
- Log(LOGWARNING, "Can't seek in a live stream, ignoring --start option");
- dStartOffset = 0;
- }
- }
+ int first = 1;
- RTMP rtmp = {0};
- RTMP_Init(&rtmp);
- RTMP_SetupStream(&rtmp, protocol, hostname, port, sockshost, &playpath, &tcUrl, &swfUrl,
- &pageUrl, &app, &auth, &swfHash, swfSize, &flashVer, &subscribepath,
- dSeek, 0, bLiveStream, timeout);
+ // User defined seek offset
+ if (dStartOffset > 0)
+ {
+ // Live stream
+ if (bLiveStream)
+ {
+ Log(LOGWARNING,
+ "Can't seek in a live stream, ignoring --start option");
+ dStartOffset = 0;
+ }
+ }
- off_t size = 0;
+ RTMP rtmp = { 0 };
+ RTMP_Init(&rtmp);
+ RTMP_SetupStream(&rtmp, protocol, hostname, port, sockshost, &playpath,
+ &tcUrl, &swfUrl, &pageUrl, &app, &auth, &swfHash, swfSize,
+ &flashVer, &subscribepath, dSeek, 0, bLiveStream, timeout);
- // ok, we have to get the timestamp of the last keyframe (only keyframes are seekable) / last audio frame (audio only streams)
- if(bResume) {
- nStatus = OpenResumeFile(flvFile, &file, &size, &metaHeader, &nMetaHeaderSize, &duration);
- if (nStatus == RD_FAILED)
- goto clean;
+ off_t size = 0;
- if (!file) {
- // file does not exist, so go back into normal mode
- bResume = false; // we are back in fresh file mode (otherwise finalizing file won't be done)
- } else {
- nStatus = GetLastKeyframe(file, nSkipKeyFrames,
- &dSeek, &initialFrame,
- &initialFrameType,
- &nInitialFrameSize);
- if (nStatus == RD_FAILED) {
- Log(LOGDEBUG, "Failed to get last keyframe.");
- goto clean;
- }
+ // ok, we have to get the timestamp of the last keyframe (only keyframes are seekable) / last audio frame (audio only streams)
+ if (bResume)
+ {
+ nStatus =
+ OpenResumeFile(flvFile, &file, &size, &metaHeader, &nMetaHeaderSize,
+ &duration);
+ if (nStatus == RD_FAILED)
+ goto clean;
- if (dSeek == 0) {
- Log(LOGDEBUG, "Last keyframe is first frame in stream, switching from resume to normal mode!");
- bResume = false;
- }
- }
+ if (!file)
+ {
+ // file does not exist, so go back into normal mode
+ bResume = false; // we are back in fresh file mode (otherwise finalizing file won't be done)
}
+ else
+ {
+ nStatus = GetLastKeyframe(file, nSkipKeyFrames,
+ &dSeek, &initialFrame,
+ &initialFrameType, &nInitialFrameSize);
+ if (nStatus == RD_FAILED)
+ {
+ Log(LOGDEBUG, "Failed to get last keyframe.");
+ goto clean;
+ }
- if (!file) {
- if(bStdoutMode) {
- file = stdout;
- SET_BINMODE(file);
- } else
- {
- file = fopen(flvFile, "w+b");
- if(file == 0) {
- LogPrintf("Failed to open file! %s\n", flvFile);
- return RD_FAILED;
- }
- }
+ if (dSeek == 0)
+ {
+ Log(LOGDEBUG,
+ "Last keyframe is first frame in stream, switching from resume to normal mode!");
+ bResume = false;
+ }
}
-
-#ifdef _DEBUG
- netstackdump = fopen("netstackdump", "wb");
- netstackdump_read = fopen("netstackdump_read", "wb");
-#endif
+ }
- while (!bCtrlC) {
- Log(LOGDEBUG, "Setting buffer time to: %dms", bufferTime);
- RTMP_SetBufferMS(&rtmp, bufferTime);
+ if (!file)
+ {
+ if (bStdoutMode)
+ {
+ file = stdout;
+ SET_BINMODE(file);
+ }
+ else
+ {
+ file = fopen(flvFile, "w+b");
+ if (file == 0)
+ {
+ LogPrintf("Failed to open file! %s\n", flvFile);
+ return RD_FAILED;
+ }
+ }
+ }
- if (first) {
- first = 0;
- LogPrintf("Connecting ...\n");
+#ifdef _DEBUG
+ netstackdump = fopen("netstackdump", "wb");
+ netstackdump_read = fopen("netstackdump_read", "wb");
+#endif
- if (!RTMP_Connect(&rtmp)) {
- nStatus = RD_FAILED;
- break;
- }
+ while (!bCtrlC)
+ {
+ Log(LOGDEBUG, "Setting buffer time to: %dms", bufferTime);
+ RTMP_SetBufferMS(&rtmp, bufferTime);
- Log(LOGINFO, "Connected...");
+ if (first)
+ {
+ first = 0;
+ LogPrintf("Connecting ...\n");
- // User defined seek offset
- if (dStartOffset > 0) {
- // Don't need the start offset if resuming an existing file
- if (bResume) {
- Log(LOGWARNING, "Can't seek a resumed stream, ignoring --start option");
- dStartOffset = 0;
- } else {
- dSeek = dStartOffset;
- }
- }
+ if (!RTMP_Connect(&rtmp))
+ {
+ nStatus = RD_FAILED;
+ break;
+ }
- // Calculate the length of the stream to still play
- if (dStopOffset > 0) {
- dLength = dStopOffset - dSeek;
+ Log(LOGINFO, "Connected...");
- // Quit if start seek is past required stop offset
- if(dLength <= 0) {
- LogPrintf("Already Completed\n");
- nStatus = RD_SUCCESS;
- break;
- }
- }
+ // User defined seek offset
+ if (dStartOffset > 0)
+ {
+ // Don't need the start offset if resuming an existing file
+ if (bResume)
+ {
+ Log(LOGWARNING,
+ "Can't seek a resumed stream, ignoring --start option");
+ dStartOffset = 0;
+ }
+ else
+ {
+ dSeek = dStartOffset;
+ }
+ }
- if (!RTMP_ConnectStream(&rtmp, dSeek, dLength)) {
- nStatus = RD_FAILED;
- break;
- }
- } else {
- nInitialFrameSize = 0;
+ // Calculate the length of the stream to still play
+ if (dStopOffset > 0)
+ {
+ dLength = dStopOffset - dSeek;
- Log(LOGINFO, "Connection timed out, trying to resume.\n\n");
- if (!RTMP_ToggleStream(&rtmp)) {
- Log(LOGERROR, "Failed to resume the stream\n\n");
- if (!RTMP_IsTimedout(&rtmp))
- nStatus = RD_FAILED;
- else
- nStatus = RD_INCOMPLETE;
- break;
- }
- bResume = true;
+ // Quit if start seek is past required stop offset
+ if (dLength <= 0)
+ {
+ LogPrintf("Already Completed\n");
+ nStatus = RD_SUCCESS;
+ break;
}
+ }
- nStatus = Download(&rtmp, file, dSeek, dLength, duration, bResume,
- metaHeader, nMetaHeaderSize, initialFrame,
- initialFrameType, nInitialFrameSize,
- nSkipKeyFrames, bStdoutMode, bLiveStream, bHashes,
- bOverrideBufferTime, bufferTime, &percent);
- free(initialFrame);
- initialFrame = NULL;
-
- /* If we succeeded, we're done.
- */
- if (nStatus != RD_INCOMPLETE || !RTMP_IsTimedout(&rtmp) || bLiveStream)
- break;
+ if (!RTMP_ConnectStream(&rtmp, dSeek, dLength))
+ {
+ nStatus = RD_FAILED;
+ break;
+ }
}
+ else
+ {
+ nInitialFrameSize = 0;
- if (nStatus == RD_SUCCESS) {
- LogPrintf("Download complete\n");
- } else if (nStatus == RD_INCOMPLETE) {
- LogPrintf("Download may be incomplete (downloaded about %.2f%%), try resuming\n", percent);
+ Log(LOGINFO, "Connection timed out, trying to resume.\n\n");
+ if (!RTMP_ToggleStream(&rtmp))
+ {
+ Log(LOGERROR, "Failed to resume the stream\n\n");
+ if (!RTMP_IsTimedout(&rtmp))
+ nStatus = RD_FAILED;
+ else
+ nStatus = RD_INCOMPLETE;
+ break;
+ }
+ bResume = true;
}
+ nStatus = Download(&rtmp, file, dSeek, dLength, duration, bResume,
+ metaHeader, nMetaHeaderSize, initialFrame,
+ initialFrameType, nInitialFrameSize,
+ nSkipKeyFrames, bStdoutMode, bLiveStream, bHashes,
+ bOverrideBufferTime, bufferTime, &percent);
+ free(initialFrame);
+ initialFrame = NULL;
+
+ /* If we succeeded, we're done.
+ */
+ if (nStatus != RD_INCOMPLETE || !RTMP_IsTimedout(&rtmp) || bLiveStream)
+ break;
+ }
+
+ if (nStatus == RD_SUCCESS)
+ {
+ LogPrintf("Download complete\n");
+ }
+ else if (nStatus == RD_INCOMPLETE)
+ {
+ LogPrintf
+ ("Download may be incomplete (downloaded about %.2f%%), try resuming\n",
+ percent);
+ }
+
clean:
- Log(LOGDEBUG, "Closing connection.\n");
- RTMP_Close(&rtmp);
+ Log(LOGDEBUG, "Closing connection.\n");
+ RTMP_Close(&rtmp);
- if(file != 0)
- fclose(file);
+ if (file != 0)
+ fclose(file);
- CleanupSockets();
+ CleanupSockets();
#ifdef _DEBUG
- if(netstackdump != 0)
- fclose(netstackdump);
- if(netstackdump_read != 0)
- fclose(netstackdump_read);
+ if (netstackdump != 0)
+ fclose(netstackdump);
+ if (netstackdump_read != 0)
+ fclose(netstackdump_read);
#endif
- return nStatus;
+ return nStatus;
}
-
More information about the rtmpdump
mailing list