Merge branch 'master' of octo.ddvtech.com:pls
This commit is contained in:
commit
7677388841
4 changed files with 100 additions and 27 deletions
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Add table
Reference in a new issue