Merge branch 'master' of octo.ddvtech.com:pls

This commit is contained in:
Erik Zandvliet 2011-08-24 09:11:34 +02:00
commit 7677388841
4 changed files with 100 additions and 27 deletions

View file

@ -2,13 +2,17 @@
/// Holds all code for the FLV namespace. /// Holds all code for the FLV namespace.
#include "flv_tag.h" #include "flv_tag.h"
#include "rtmpchunks.h"
#include <stdio.h> //for Tag::FileLoader #include <stdio.h> //for Tag::FileLoader
#include <unistd.h> //for Tag::FileLoader #include <unistd.h> //for Tag::FileLoader
#include <fcntl.h> //for Tag::FileLoader #include <fcntl.h> //for Tag::FileLoader
#include <stdlib.h> //malloc #include <stdlib.h> //malloc
#include <string.h> //memcpy #include <string.h> //memcpy
char FLV::Header[13]; ///< Holds the last FLV header parsed. /// Holds the last FLV header parsed.
/// Defaults to a audio+video header on FLV version 0x01 if no header received yet.
char FLV::Header[13] = {'F', 'L', 'V', 0x01, 0x05, 0, 0, 0, 0x09, 0, 0, 0, 0};
bool FLV::Parse_Error = false; ///< This variable is set to true if a problem is encountered while parsing the FLV. bool FLV::Parse_Error = false; ///< This variable is set to true if a problem is encountered while parsing the FLV.
std::string FLV::Error_Str = ""; std::string FLV::Error_Str = "";
@ -209,6 +213,16 @@ FLV::Tag::Tag(const Tag& O){
isKeyframe = O.isKeyframe; isKeyframe = O.isKeyframe;
}//copy constructor }//copy constructor
/// Copy constructor from a RTMP chunk.
/// Copies the contents of a RTMP chunk into a valid FLV tag.
/// Exactly the same as making a chunk by through the default (empty) constructor
/// and then calling FLV::Tag::ChunkLoader with the chunk as argument.
FLV::Tag::Tag(const RTMPStream::Chunk& O){
len = 0; buf = 0; data = 0; isKeyframe = false; done = true; sofar = 0;
ChunkLoader(O);
}
/// Assignment operator - works exactly like the copy constructor. /// Assignment operator - works exactly like the copy constructor.
/// This operator checks for self-assignment. /// This operator checks for self-assignment.
FLV::Tag & FLV::Tag::operator= (const FLV::Tag& O){ FLV::Tag & FLV::Tag::operator= (const FLV::Tag& O){
@ -231,6 +245,32 @@ FLV::Tag & FLV::Tag::operator= (const FLV::Tag& O){
return *this; return *this;
}//assignment operator }//assignment operator
/// FLV loader function from chunk.
/// Copies the contents and wraps it in a FLV header.
bool FLV::Tag::ChunkLoader(const RTMPStream::Chunk& O){
len = O.len + 15;
if (len > 0){
if (!data){
data = (char*)malloc(len);
buf = len;
}else{
if (buf < len){
data = (char*)realloc(data, len);
buf = len;
}
}
memcpy(data+11, &(O.data[0]), O.len);
}
((unsigned int *)(data+len-4))[0] = O.len;
data[0] = O.msg_type_id;
data[3] = O.len & 0xFF;
data[2] = (O.len >> 8) & 0xFF;
data[1] = (O.len >> 16) & 0xFF;
tagTime(O.timestamp);
return true;
}
/// Helper function for FLV::MemLoader. /// Helper function for FLV::MemLoader.
/// This function will try to read count bytes from data buffer D into buffer. /// This function will try to read count bytes from data buffer D into buffer.
/// This function should be called repeatedly until true. /// This function should be called repeatedly until true.

View file

@ -5,6 +5,11 @@
#include "socket.h" #include "socket.h"
#include <string> #include <string>
//forward declaration of RTMPStream::Chunk to avoid circular dependencies.
namespace RTMPStream{
class Chunk;
};
/// This namespace holds all FLV-parsing related functionality. /// This namespace holds all FLV-parsing related functionality.
namespace FLV { namespace FLV {
//variables //variables
@ -30,7 +35,9 @@ namespace FLV {
Tag(); ///< Constructor for a new, empty, tag. Tag(); ///< Constructor for a new, empty, tag.
Tag(const Tag& O); ///< Copy constructor, copies the contents of an existing tag. Tag(const Tag& O); ///< Copy constructor, copies the contents of an existing tag.
Tag & operator= (const Tag& O); ///< Assignment operator - works exactly like the copy constructor. Tag & operator= (const Tag& O); ///< Assignment operator - works exactly like the copy constructor.
Tag(const RTMPStream::Chunk& O); ///<Copy constructor from a RTMP chunk.
//loader functions //loader functions
bool ChunkLoader(const RTMPStream::Chunk& O);
bool MemLoader(char * D, unsigned int S, unsigned int & P); bool MemLoader(char * D, unsigned int S, unsigned int & P);
bool SockLoader(int sock); bool SockLoader(int sock);
bool SockLoader(Socket::Connection sock); bool SockLoader(Socket::Connection sock);

View file

@ -2,6 +2,7 @@
/// Holds all code for the RTMPStream namespace. /// Holds all code for the RTMPStream namespace.
#include "rtmpchunks.h" #include "rtmpchunks.h"
#include "flv_tag.h"
#include "crypto.h" #include "crypto.h"
char versionstring[] = "WWW.DDVTECH.COM "; ///< String that is repeated in the RTMP handshake char versionstring[] = "WWW.DDVTECH.COM "; ///< String that is repeated in the RTMP handshake
@ -41,7 +42,7 @@ std::string RTMPStream::Chunk::Pack(){
RTMPStream::Chunk prev = lastsend[cs_id]; RTMPStream::Chunk prev = lastsend[cs_id];
unsigned int tmpi; unsigned int tmpi;
unsigned char chtype = 0x00; unsigned char chtype = 0x00;
timestamp -= firsttime; //timestamp -= firsttime;
if ((prev.msg_type_id > 0) && (prev.cs_id == cs_id)){ if ((prev.msg_type_id > 0) && (prev.cs_id == cs_id)){
if (msg_stream_id == prev.msg_stream_id){ if (msg_stream_id == prev.msg_stream_id){
chtype = 0x40;//do not send msg_stream_id chtype = 0x40;//do not send msg_stream_id
@ -54,6 +55,8 @@ std::string RTMPStream::Chunk::Pack(){
} }
} }
} }
//override - we always sent type 0x00 if the timestamp has decreased since last chunk in this channel
if (timestamp < prev.timestamp){chtype = 0x00;}
} }
if (cs_id <= 63){ if (cs_id <= 63){
output += (unsigned char)(chtype | cs_id); output += (unsigned char)(chtype | cs_id);
@ -76,15 +79,15 @@ std::string RTMPStream::Chunk::Pack(){
tmpi = timestamp - prev.timestamp; tmpi = timestamp - prev.timestamp;
} }
if (tmpi >= 0x00ffffff){ntime = tmpi; tmpi = 0x00ffffff;} if (tmpi >= 0x00ffffff){ntime = tmpi; tmpi = 0x00ffffff;}
output += (unsigned char)(tmpi / (256*256)); output += (unsigned char)((tmpi >> 16) & 0xff);
output += (unsigned char)(tmpi / 256); output += (unsigned char)((tmpi >> 8) & 0xff);
output += (unsigned char)(tmpi % 256); output += (unsigned char)(tmpi & 0xff);
if (chtype != 0x80){ if (chtype != 0x80){
//len //len
tmpi = len; tmpi = len;
output += (unsigned char)(tmpi / (256*256)); output += (unsigned char)((tmpi >> 16) & 0xff);
output += (unsigned char)(tmpi / 256); output += (unsigned char)((tmpi >> 8) & 0xff);
output += (unsigned char)(tmpi % 256); output += (unsigned char)(tmpi & 0xff);
//msg type id //msg type id
output += (unsigned char)msg_type_id; output += (unsigned char)msg_type_id;
if (chtype != 0x40){ if (chtype != 0x40){
@ -98,10 +101,10 @@ std::string RTMPStream::Chunk::Pack(){
} }
//support for 0x00ffffff timestamps //support for 0x00ffffff timestamps
if (ntime){ if (ntime){
output += (unsigned char)(ntime % 256); output += (unsigned char)(ntime & 0xff);
output += (unsigned char)(ntime / 256); output += (unsigned char)((ntime >> 8) & 0xff);
output += (unsigned char)(ntime / (256*256)); output += (unsigned char)((ntime >> 16) & 0xff);
output += (unsigned char)(ntime / (256*256*256)); output += (unsigned char)((ntime >> 24) & 0xff);
} }
len_left = 0; len_left = 0;
while (len_left < len){ while (len_left < len){
@ -162,7 +165,7 @@ std::string RTMPStream::SendChunk(unsigned int cs_id, unsigned char msg_type_id,
/// \param ts Timestamp of the media data, relative to current system time. /// \param ts Timestamp of the media data, relative to current system time.
std::string RTMPStream::SendMedia(unsigned char msg_type_id, unsigned char * data, int len, unsigned int ts){ std::string RTMPStream::SendMedia(unsigned char msg_type_id, unsigned char * data, int len, unsigned int ts){
RTMPStream::Chunk ch; RTMPStream::Chunk ch;
ch.cs_id = msg_type_id; ch.cs_id = msg_type_id+42;
ch.timestamp = ts; ch.timestamp = ts;
ch.len = len; ch.len = len;
ch.real_len = len; ch.real_len = len;
@ -173,6 +176,21 @@ std::string RTMPStream::SendMedia(unsigned char msg_type_id, unsigned char * dat
return ch.Pack(); return ch.Pack();
}//SendMedia }//SendMedia
/// Packs up a chunk with media contents.
/// \param tag FLV::Tag with media to send.
std::string RTMPStream::SendMedia(FLV::Tag & tag){
RTMPStream::Chunk ch;
ch.cs_id = ((unsigned char)tag.data[0]);
ch.timestamp = tag.tagTime();
ch.len = tag.len-15;
ch.real_len = tag.len-15;
ch.len_left = 0;
ch.msg_type_id = (unsigned char)tag.data[0];
ch.msg_stream_id = 1;
ch.data.append(tag.data+11, (size_t)(tag.len-15));
return ch.Pack();
}//SendMedia
/// Packs up a chunk for a control message with 1 argument. /// Packs up a chunk for a control message with 1 argument.
std::string RTMPStream::SendCTL(unsigned char type, unsigned int data){ std::string RTMPStream::SendCTL(unsigned char type, unsigned int data){
RTMPStream::Chunk ch; RTMPStream::Chunk ch;
@ -199,7 +217,7 @@ std::string RTMPStream::SendCTL(unsigned char type, unsigned int data, unsigned
ch.msg_type_id = type; ch.msg_type_id = type;
ch.msg_stream_id = 0; ch.msg_stream_id = 0;
ch.data.resize(5); ch.data.resize(5);
*(int*)((char*)ch.data.c_str()) = htonl(data); *(unsigned int*)((char*)ch.data.c_str()) = htonl(data);
ch.data[4] = data2; ch.data[4] = data2;
return ch.Pack(); return ch.Pack();
}//SendCTL }//SendCTL
@ -215,7 +233,7 @@ std::string RTMPStream::SendUSR(unsigned char type, unsigned int data){
ch.msg_type_id = 4; ch.msg_type_id = 4;
ch.msg_stream_id = 0; ch.msg_stream_id = 0;
ch.data.resize(6); ch.data.resize(6);
*(int*)((char*)ch.data.c_str()+2) = htonl(data); *(unsigned int*)(((char*)ch.data.c_str())+2) = htonl(data);
ch.data[0] = 0; ch.data[0] = 0;
ch.data[1] = type; ch.data[1] = type;
return ch.Pack(); return ch.Pack();
@ -232,8 +250,8 @@ std::string RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigned
ch.msg_type_id = 4; ch.msg_type_id = 4;
ch.msg_stream_id = 0; ch.msg_stream_id = 0;
ch.data.resize(10); ch.data.resize(10);
*(int*)((char*)ch.data.c_str()+2) = htonl(data); *(unsigned int*)(((char*)ch.data.c_str())+2) = htonl(data);
*(int*)((char*)ch.data.c_str()+6) = htonl(data2); *(unsigned int*)(((char*)ch.data.c_str())+6) = htonl(data2);
ch.data[0] = 0; ch.data[0] = 0;
ch.data[1] = type; ch.data[1] = type;
return ch.Pack(); return ch.Pack();
@ -274,7 +292,8 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
RTMPStream::Chunk prev = lastrecv[cs_id]; RTMPStream::Chunk prev = lastrecv[cs_id];
//process the rest of the header, for each chunk type //process the rest of the header, for each chunk type
switch (chunktype & 0xC0){ headertype = chunktype & 0xC0;
switch (headertype){
case 0x00: case 0x00:
if (indata.size() < i+11) return false; //can't read whole header if (indata.size() < i+11) return false; //can't read whole header
timestamp = indata[i++]*256*256; timestamp = indata[i++]*256*256;
@ -296,7 +315,7 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
timestamp = indata[i++]*256*256; timestamp = indata[i++]*256*256;
timestamp += indata[i++]*256; timestamp += indata[i++]*256;
timestamp += indata[i++]; timestamp += indata[i++];
timestamp += prev.timestamp; if (timestamp != 0x00ffffff){timestamp += prev.timestamp;}
len = indata[i++]*256*256; len = indata[i++]*256*256;
len += indata[i++]*256; len += indata[i++]*256;
len += indata[i++]; len += indata[i++];
@ -310,7 +329,7 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
timestamp = indata[i++]*256*256; timestamp = indata[i++]*256*256;
timestamp += indata[i++]*256; timestamp += indata[i++]*256;
timestamp += indata[i++]; timestamp += indata[i++];
timestamp += prev.timestamp; if (timestamp != 0x00ffffff){timestamp += prev.timestamp;}
len = prev.len; len = prev.len;
len_left = prev.len_left; len_left = prev.len_left;
msg_type_id = prev.msg_type_id; msg_type_id = prev.msg_type_id;

View file

@ -9,6 +9,11 @@
#include <string> #include <string>
#include <arpa/inet.h> #include <arpa/inet.h>
//forward declaration of FLV::Tag to avoid circular dependencies.
namespace FLV{
class Tag;
};
/// Contains all functions and classes needed for RTMP connections. /// Contains all functions and classes needed for RTMP connections.
namespace RTMPStream{ namespace RTMPStream{
@ -30,6 +35,7 @@ namespace RTMPStream{
/// Holds a single RTMP chunk, either send or receive direction. /// Holds a single RTMP chunk, either send or receive direction.
class Chunk{ class Chunk{
public: public:
unsigned char headertype; ///< For input chunks, the type of header. This is calculated automatically for output chunks.
unsigned int cs_id; ///< ContentStream ID unsigned int cs_id; ///< ContentStream ID
unsigned int timestamp; ///< Timestamp of this chunk. unsigned int timestamp; ///< Timestamp of this chunk.
unsigned int len; ///< Length of the complete chunk. unsigned int len; ///< Length of the complete chunk.
@ -50,6 +56,7 @@ namespace RTMPStream{
std::string SendChunk(unsigned int cs_id, unsigned char msg_type_id, unsigned int msg_stream_id, std::string data); std::string SendChunk(unsigned int cs_id, unsigned char msg_type_id, unsigned int msg_stream_id, std::string data);
std::string SendMedia(unsigned char msg_type_id, unsigned char * data, int len, unsigned int ts); std::string SendMedia(unsigned char msg_type_id, unsigned char * data, int len, unsigned int ts);
std::string SendMedia(FLV::Tag & tag);
std::string SendCTL(unsigned char type, unsigned int data); std::string SendCTL(unsigned char type, unsigned int data);
std::string SendCTL(unsigned char type, unsigned int data, unsigned char data2); std::string SendCTL(unsigned char type, unsigned int data, unsigned char data2);
std::string SendUSR(unsigned char type, unsigned int data); std::string SendUSR(unsigned char type, unsigned int data);