Finished FLV2DTSC code, fixed a lot of bugs in new code, added DTSC info tool.
This commit is contained in:
parent
e23fbfd109
commit
1b7ab627b5
7 changed files with 432 additions and 58 deletions
23
DTSC_Analyser/Makefile
Normal file
23
DTSC_Analyser/Makefile
Normal file
|
@ -0,0 +1,23 @@
|
|||
SRC = main.cpp ../util/dtsc.cpp
|
||||
OBJ = $(SRC:.cpp=.o)
|
||||
OUT = DTSC_Info
|
||||
INCLUDES =
|
||||
DEBUG = 4
|
||||
OPTIMIZE = -g
|
||||
CCFLAGS = -Wall -Wextra -funsigned-char $(OPTIMIZE) -DDEBUG=$(DEBUG)
|
||||
CC = $(CROSS)g++
|
||||
LD = $(CROSS)ld
|
||||
AR = $(CROSS)ar
|
||||
LIBS =
|
||||
.SUFFIXES: .cpp
|
||||
.PHONY: clean default
|
||||
default: $(OUT)
|
||||
.cpp.o:
|
||||
$(CC) $(INCLUDES) $(CCFLAGS) $(LIBS) -c $< -o $@
|
||||
$(OUT): $(OBJ)
|
||||
$(CC) $(LIBS) -o $(OUT) $(OBJ)
|
||||
clean:
|
||||
rm -rf $(OBJ) $(OUT) Makefile.bak *~
|
||||
install: $(OUT)
|
||||
cp -f ./$(OUT) /usr/bin/
|
||||
|
38
DTSC_Analyser/main.cpp
Normal file
38
DTSC_Analyser/main.cpp
Normal file
|
@ -0,0 +1,38 @@
|
|||
/// \file DTSC_Analyser/main.cpp
|
||||
/// Contains the code for the DTSC Analysing tool.
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include "../util/dtsc.h" //DTSC support
|
||||
|
||||
/// Reads DTSC from stdin and outputs human-readable information to stderr.
|
||||
int main() {
|
||||
DTSC::Stream Strm;
|
||||
|
||||
std::string inBuffer;
|
||||
char charBuffer[1024*10];
|
||||
unsigned int charCount;
|
||||
bool doneheader = false;
|
||||
|
||||
while(std::cin.good()){
|
||||
//invalidate the current buffer
|
||||
std::cin.read(charBuffer, 1024*10);
|
||||
charCount = std::cin.gcount();
|
||||
inBuffer.append(charBuffer, charCount);
|
||||
if (Strm.parsePacket(inBuffer)){
|
||||
if (!doneheader){
|
||||
doneheader = true;
|
||||
Strm.metadata.Print();
|
||||
}
|
||||
Strm.getPacket().Print();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
23
FLV2DTSC/Makefile
Normal file
23
FLV2DTSC/Makefile
Normal file
|
@ -0,0 +1,23 @@
|
|||
SRC = main.cpp ../util/flv_tag.cpp ../util/dtsc.cpp ../util/amf.cpp ../util/socket.cpp
|
||||
OBJ = $(SRC:.cpp=.o)
|
||||
OUT = DDV_FLV2DTSC
|
||||
INCLUDES =
|
||||
DEBUG = 4
|
||||
OPTIMIZE = -g
|
||||
CCFLAGS = -Wall -Wextra -funsigned-char $(OPTIMIZE) -DDEBUG=$(DEBUG)
|
||||
CC = $(CROSS)g++
|
||||
LD = $(CROSS)ld
|
||||
AR = $(CROSS)ar
|
||||
LIBS =
|
||||
.SUFFIXES: .cpp
|
||||
.PHONY: clean default
|
||||
default: $(OUT)
|
||||
.cpp.o:
|
||||
$(CC) $(INCLUDES) $(CCFLAGS) $(LIBS) -c $< -o $@
|
||||
$(OUT): $(OBJ)
|
||||
$(CC) $(LIBS) -o $(OUT) $(OBJ)
|
||||
clean:
|
||||
rm -rf $(OBJ) $(OUT) Makefile.bak *~
|
||||
install: $(OUT)
|
||||
cp -f ./$(OUT) /usr/bin/
|
||||
|
261
FLV2DTSC/main.cpp
Normal file
261
FLV2DTSC/main.cpp
Normal file
|
@ -0,0 +1,261 @@
|
|||
/// \file FLV2DTSC/main.cpp
|
||||
/// Contains the code that will transform any valid FLV input into valid DTSC.
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include "../util/flv_tag.h" //FLV support
|
||||
#include "../util/dtsc.h" //DTSC support
|
||||
#include "../util/amf.h" //AMF support
|
||||
|
||||
// String onMetaData
|
||||
// ECMA Array
|
||||
// Bool hasVideo 1
|
||||
// Number videocodecid 4 (2 = H263, 4 = VP6, 7 = H264)
|
||||
// Number width 320
|
||||
// Number height 240
|
||||
// Number framerate 23.976 (/ 1000)
|
||||
// Number videodatarate 500.349 (kbps)
|
||||
// Bool hasAudio 1
|
||||
// Bool stereo 1
|
||||
// Number audiodelay 0
|
||||
// Number audiosamplerate 11025
|
||||
// Number audiosamplesize 16
|
||||
// Number audiocodecid 2 (2 = MP3, 10 = AAC)
|
||||
// Number audiodatarate 64.3269 (kbps)
|
||||
|
||||
|
||||
/// Holds all code that converts filetypes to DTSC.
|
||||
namespace Converters{
|
||||
|
||||
/// Inserts std::string type metadata into the passed DTMI object.
|
||||
/// \arg meta The DTMI object to put the metadata into.
|
||||
/// \arg cat Metadata category to insert into.
|
||||
/// \arg elem Element name to put into the category.
|
||||
/// \arg val Value to put into the element name.
|
||||
void Meta_Put(DTSC::DTMI & meta, std::string cat, std::string elem, std::string val){
|
||||
if (meta.getContentP(cat) == 0){meta.addContent(DTSC::DTMI(cat));}
|
||||
meta.getContentP(cat)->addContent(DTSC::DTMI(elem, val));
|
||||
std::cerr << "Metadata " << cat << "." << elem << " = " << val << std::endl;
|
||||
}
|
||||
|
||||
/// Inserts uint64_t type metadata into the passed DTMI object.
|
||||
/// \arg meta The DTMI object to put the metadata into.
|
||||
/// \arg cat Metadata category to insert into.
|
||||
/// \arg elem Element name to put into the category.
|
||||
/// \arg val Value to put into the element name.
|
||||
void Meta_Put(DTSC::DTMI & meta, std::string cat, std::string elem, uint64_t val){
|
||||
if (meta.getContentP(cat) == 0){meta.addContent(DTSC::DTMI(cat));}
|
||||
meta.getContentP(cat)->addContent(DTSC::DTMI(elem, val));
|
||||
std::cerr << "Metadata " << cat << "." << elem << " = " << val << std::endl;
|
||||
}
|
||||
|
||||
/// Returns true if the named category and elementname are available in the metadata.
|
||||
/// \arg meta The DTMI object to check.
|
||||
/// \arg cat Metadata category to check.
|
||||
/// \arg elem Element name to check.
|
||||
bool Meta_Has(DTSC::DTMI & meta, std::string cat, std::string elem){
|
||||
if (meta.getContentP(cat) == 0){return false;}
|
||||
if (meta.getContentP(cat)->getContentP(elem) == 0){return false;}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Reads FLV from STDIN, outputs DTSC to STDOUT.
|
||||
int FLV2DTSC() {
|
||||
FLV::Tag FLV_in; // Temporary storage for incoming FLV data.
|
||||
AMF::Object meta_in; // Temporary storage for incoming metadata.
|
||||
DTSC::DTMI meta_out; // Storage for outgoing DTMI header data.
|
||||
DTSC::DTMI pack_out; // Storage for outgoing DTMI data.
|
||||
std::stringstream prebuffer; // Temporary buffer before sending real data
|
||||
bool sending = false;
|
||||
unsigned int counter = 0;
|
||||
|
||||
while (!feof(stdin)){
|
||||
if (FLV_in.FileLoader(stdin)){
|
||||
if (!sending){
|
||||
counter++;
|
||||
if (counter > 10){
|
||||
sending = true;
|
||||
meta_out.Pack(true);
|
||||
meta_out.packed.replace(0, 4, DTSC::Magic_Header);
|
||||
std::cout << meta_out.packed;
|
||||
std::cout << prebuffer.rdbuf();
|
||||
prebuffer.str("");
|
||||
std::cerr << "Buffer done, starting real-time output..." << std::endl;
|
||||
}
|
||||
}
|
||||
if (FLV_in.data[0] == 0x12){
|
||||
meta_in = AMF::parse((unsigned char*)FLV_in.data+11, FLV_in.len-15);
|
||||
if (meta_in.getContentP(0) && (meta_in.getContentP(0)->StrValue() == "onMetaData") && meta_in.getContentP(1)){
|
||||
AMF::Object * tmp = meta_in.getContentP(1);
|
||||
if (tmp->getContentP("videocodecid")){
|
||||
switch ((unsigned int)tmp->getContentP("videocodecid")->NumValue()){
|
||||
case 2: Meta_Put(meta_out, "video", "codec", "H263"); break;
|
||||
case 4: Meta_Put(meta_out, "video", "codec", "VP6"); break;
|
||||
case 7: Meta_Put(meta_out, "video", "codec", "H264"); break;
|
||||
default: Meta_Put(meta_out, "video", "codec", "?"); break;
|
||||
}
|
||||
}
|
||||
if (tmp->getContentP("audiocodecid")){
|
||||
switch ((unsigned int)tmp->getContentP("audiocodecid")->NumValue()){
|
||||
case 2: Meta_Put(meta_out, "audio", "codec", "MP3"); break;
|
||||
case 10: Meta_Put(meta_out, "audio", "codec", "AAC"); break;
|
||||
default: Meta_Put(meta_out, "audio", "codec", "?"); break;
|
||||
}
|
||||
}
|
||||
if (tmp->getContentP("width")){
|
||||
Meta_Put(meta_out, "video", "width", tmp->getContentP("width")->NumValue());
|
||||
}
|
||||
if (tmp->getContentP("height")){
|
||||
Meta_Put(meta_out, "video", "height", tmp->getContentP("height")->NumValue());
|
||||
}
|
||||
if (tmp->getContentP("framerate")){
|
||||
Meta_Put(meta_out, "video", "fpks", tmp->getContentP("framerate")->NumValue()*1000);
|
||||
}
|
||||
if (tmp->getContentP("videodatarate")){
|
||||
Meta_Put(meta_out, "video", "bps", (tmp->getContentP("videodatarate")->NumValue()*1024)/8);
|
||||
}
|
||||
if (tmp->getContentP("audiodatarate")){
|
||||
Meta_Put(meta_out, "audio", "bps", (tmp->getContentP("audiodatarate")->NumValue()*1024)/8);
|
||||
}
|
||||
if (tmp->getContentP("audiosamplerate")){
|
||||
Meta_Put(meta_out, "audio", "rate", tmp->getContentP("audiosamplerate")->NumValue());
|
||||
}
|
||||
if (tmp->getContentP("audiosamplesize")){
|
||||
Meta_Put(meta_out, "audio", "size", tmp->getContentP("audiosamplesize")->NumValue());
|
||||
}
|
||||
if (tmp->getContentP("stereo")){
|
||||
if (tmp->getContentP("stereo")->NumValue() == 1){
|
||||
Meta_Put(meta_out, "audio", "channels", 2);
|
||||
}else{
|
||||
Meta_Put(meta_out, "audio", "channels", 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (FLV_in.data[0] == 0x08){
|
||||
char audiodata = FLV_in.data[11];
|
||||
if (FLV_in.needsInitData() && FLV_in.isInitData()){
|
||||
if ((audiodata & 0xF0) == 0xA0){
|
||||
Meta_Put(meta_out, "audio", "init", std::string((char*)FLV_in.data+13, (size_t)FLV_in.len-17));
|
||||
}else{
|
||||
Meta_Put(meta_out, "audio", "init", std::string((char*)FLV_in.data+12, (size_t)FLV_in.len-16));
|
||||
}
|
||||
continue;//skip rest of parsing, get next tag.
|
||||
}
|
||||
pack_out = DTSC::DTMI("audio", DTSC::DTMI_ROOT);
|
||||
pack_out.addContent(DTSC::DTMI("datatype", "audio"));
|
||||
pack_out.addContent(DTSC::DTMI("time", FLV_in.tagTime()));
|
||||
if (!Meta_Has(meta_out, "audio", "codec")){
|
||||
switch (audiodata & 0xF0){
|
||||
case 0x20: Meta_Put(meta_out, "audio", "codec", "MP3"); break;
|
||||
case 0xA0: Meta_Put(meta_out, "audio", "codec", "AAC"); break;
|
||||
default: Meta_Put(meta_out, "audio", "codec", "?"); break;
|
||||
}
|
||||
}
|
||||
if (!Meta_Has(meta_out, "audio", "rate")){
|
||||
switch (audiodata & 0x0C){
|
||||
case 0x0: Meta_Put(meta_out, "audio", "rate", 5500); break;
|
||||
case 0x4: Meta_Put(meta_out, "audio", "rate", 11000); break;
|
||||
case 0x8: Meta_Put(meta_out, "audio", "rate", 22000); break;
|
||||
case 0xC: Meta_Put(meta_out, "audio", "rate", 44000); break;
|
||||
}
|
||||
}
|
||||
if (!Meta_Has(meta_out, "audio", "size")){
|
||||
switch (audiodata & 0x02){
|
||||
case 0x0: Meta_Put(meta_out, "audio", "size", 8); break;
|
||||
case 0x2: Meta_Put(meta_out, "audio", "size", 16); break;
|
||||
}
|
||||
}
|
||||
if (!Meta_Has(meta_out, "audio", "channels")){
|
||||
switch (audiodata & 0x01){
|
||||
case 0x0: Meta_Put(meta_out, "audio", "channels", 1); break;
|
||||
case 0x1: Meta_Put(meta_out, "audio", "channels", 2); break;
|
||||
}
|
||||
}
|
||||
if ((audiodata & 0xF0) == 0xA0){
|
||||
pack_out.addContent(DTSC::DTMI("data", std::string((char*)FLV_in.data+13, (size_t)FLV_in.len-17)));
|
||||
}else{
|
||||
pack_out.addContent(DTSC::DTMI("data", std::string((char*)FLV_in.data+12, (size_t)FLV_in.len-16)));
|
||||
}
|
||||
if (sending){
|
||||
std::cout << pack_out.Pack(true);
|
||||
}else{
|
||||
prebuffer << pack_out.Pack(true);
|
||||
}
|
||||
}
|
||||
if (FLV_in.data[0] == 0x09){
|
||||
char videodata = FLV_in.data[11];
|
||||
if (FLV_in.needsInitData() && FLV_in.isInitData()){
|
||||
if ((videodata & 0x0F) == 7){
|
||||
Meta_Put(meta_out, "video", "init", std::string((char*)FLV_in.data+16, (size_t)FLV_in.len-20));
|
||||
}else{
|
||||
Meta_Put(meta_out, "video", "init", std::string((char*)FLV_in.data+12, (size_t)FLV_in.len-16));
|
||||
}
|
||||
continue;//skip rest of parsing, get next tag.
|
||||
}
|
||||
if (!Meta_Has(meta_out, "video", "codec")){
|
||||
switch (videodata & 0x0F){
|
||||
case 2: Meta_Put(meta_out, "video", "codec", "H263"); break;
|
||||
case 4: Meta_Put(meta_out, "video", "codec", "VP6"); break;
|
||||
case 7: Meta_Put(meta_out, "video", "codec", "H264"); break;
|
||||
default: Meta_Put(meta_out, "video", "codec", "?"); break;
|
||||
}
|
||||
}
|
||||
pack_out = DTSC::DTMI("video", DTSC::DTMI_ROOT);
|
||||
pack_out.addContent(DTSC::DTMI("datatype", "video"));
|
||||
switch (videodata & 0xF0){
|
||||
case 0x10: pack_out.addContent(DTSC::DTMI("keyframe", 1)); break;
|
||||
case 0x20: pack_out.addContent(DTSC::DTMI("interframe", 1)); break;
|
||||
case 0x30: pack_out.addContent(DTSC::DTMI("disposableframe", 1)); break;
|
||||
case 0x40: pack_out.addContent(DTSC::DTMI("keyframe", 1)); break;
|
||||
case 0x50: continue; break;//the video info byte we just throw away - useless to us...
|
||||
}
|
||||
if ((videodata & 0x0F) == 7){
|
||||
switch (FLV_in.data[12]){
|
||||
case 1: pack_out.addContent(DTSC::DTMI("nalu", 1)); break;
|
||||
case 2: pack_out.addContent(DTSC::DTMI("nalu_end", 1)); break;
|
||||
}
|
||||
int offset = 0;
|
||||
((char*)(&offset))[0] = FLV_in.data[13];
|
||||
((char*)(&offset))[1] = FLV_in.data[14];
|
||||
((char*)(&offset))[2] = FLV_in.data[15];
|
||||
offset >>= 8;
|
||||
pack_out.addContent(DTSC::DTMI("offset", offset));
|
||||
}
|
||||
pack_out.addContent(DTSC::DTMI("time", FLV_in.tagTime()));
|
||||
pack_out.addContent(DTSC::DTMI("data", std::string((char*)FLV_in.data+12, (size_t)FLV_in.len-16)));
|
||||
if (sending){
|
||||
std::cout << pack_out.Pack(true);
|
||||
}else{
|
||||
prebuffer << pack_out.Pack(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if the FLV input is very short, do output it correctly...
|
||||
if (!sending){
|
||||
std::cerr << "EOF - outputting buffer..." << std::endl;
|
||||
meta_out.Pack(true);
|
||||
meta_out.packed.replace(0, 4, DTSC::Magic_Header);
|
||||
std::cout << meta_out.packed;
|
||||
std::cout << prebuffer.rdbuf();
|
||||
}
|
||||
std::cerr << "Done!" << std::endl;
|
||||
|
||||
return 0;
|
||||
}//FLV2DTSC
|
||||
|
||||
};//Buffer namespace
|
||||
|
||||
/// Entry point for FLV2DTSC, simply calls Converters::FLV2DTSC().
|
||||
int main(){
|
||||
return Converters::FLV2DTSC();
|
||||
}//main
|
134
util/dtsc.cpp
134
util/dtsc.cpp
|
@ -35,6 +35,7 @@ bool DTSC::Stream::parsePacket(std::string & buffer){
|
|||
if (buffer.length() < len+8){return false;}
|
||||
metadata = DTSC::parseDTMI((unsigned char*)buffer.c_str() + 8, len);
|
||||
buffer.erase(0, len+8);
|
||||
return false;
|
||||
}
|
||||
if (memcmp(buffer.c_str(), DTSC::Magic_Packet, 4) == 0){
|
||||
len = ntohl(((uint32_t *)buffer.c_str())[1]);
|
||||
|
@ -56,6 +57,7 @@ bool DTSC::Stream::parsePacket(std::string & buffer){
|
|||
buffer.erase(0, len+8);
|
||||
while (buffers.size() > buffercount){buffers.pop_back();}
|
||||
advanceRings();
|
||||
return true;
|
||||
}
|
||||
#if DEBUG >= 2
|
||||
std::cerr << "Error: Invalid DTMI data! I *will* get stuck!" << std::endl;
|
||||
|
@ -92,25 +94,18 @@ bool DTSC::Stream::hasAudio(){
|
|||
}
|
||||
|
||||
/// Returns a packed DTSC packet, ready to sent over the network.
|
||||
std::string DTSC::Stream::outPacket(unsigned int num){
|
||||
std::string tmp;
|
||||
unsigned int size;
|
||||
tmp = Magic_Packet;
|
||||
size = htonl(buffers[num].Pack().length());
|
||||
tmp.append((char*)&size, 4);
|
||||
tmp.append(buffers[num].Pack());
|
||||
return tmp;
|
||||
std::string & DTSC::Stream::outPacket(unsigned int num){
|
||||
buffers[num].Pack(true);
|
||||
return buffers[num].packed;
|
||||
}
|
||||
|
||||
/// Returns a packed DTSC header, ready to sent over the network.
|
||||
std::string DTSC::Stream::outHeader(){
|
||||
std::string tmp;
|
||||
unsigned int size;
|
||||
tmp = Magic_Header;
|
||||
size = htonl(metadata.Pack().length());
|
||||
tmp.append((char*)&size, 4);
|
||||
tmp.append(metadata.Pack());
|
||||
return tmp;
|
||||
std::string & DTSC::Stream::outHeader(){
|
||||
if ((metadata.packed.length() < 4) || !metadata.netpacked){
|
||||
metadata.Pack(true);
|
||||
metadata.packed.replace(0, 4, Magic_Header);
|
||||
}
|
||||
return metadata.packed;
|
||||
}
|
||||
|
||||
/// advances all given out and internal Ring classes to point to the new buffer, after one has been added.
|
||||
|
@ -198,7 +193,17 @@ int DTSC::DTMI::hasContent(){return contents.size();};
|
|||
|
||||
/// Adds an DTSC::DTMI to this object. Works for all types, but only makes sense for container types.
|
||||
/// This function resets DTMI::packed to an empty string, forcing a repack on the next call to DTMI::Pack.
|
||||
void DTSC::DTMI::addContent(DTSC::DTMI c){contents.push_back(c); packed = "";};
|
||||
/// If the indice name already exists, replaces the indice.
|
||||
void DTSC::DTMI::addContent(DTSC::DTMI c){
|
||||
std::vector<DTMI>::iterator it;
|
||||
for (it = contents.begin(); it != contents.end(); it++){
|
||||
if (it->Indice() == c.Indice()){
|
||||
contents.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
contents.push_back(c); packed = "";
|
||||
};
|
||||
|
||||
/// Returns a pointer to the object held at indice i.
|
||||
/// Returns AMF::AMF0_DDV_CONTAINER of indice "error" if no object is held at this indice.
|
||||
|
@ -237,11 +242,11 @@ DTSC::DTMI::DTMI(){
|
|||
};//default constructor
|
||||
|
||||
/// Constructor for numeric objects.
|
||||
/// The object type is by default AMF::AMF0_NUMBER, but this can be forced to a different value.
|
||||
/// The object type is by default DTMItype::DTMI_INT, but this can be forced to a different value.
|
||||
/// \param indice The string indice of this object in its container, or empty string if none. Numeric indices are automatic.
|
||||
/// \param val The numeric value of this object. Numeric AMF0 objects only support double-type values.
|
||||
/// \param val The numeric value of this object. Numeric objects only support uint64_t values.
|
||||
/// \param setType The object type to force this object to.
|
||||
DTSC::DTMI::DTMI(std::string indice, double val, DTSC::DTMItype setType){//num type initializer
|
||||
DTSC::DTMI::DTMI(std::string indice, uint64_t val, DTSC::DTMItype setType){//num type initializer
|
||||
myIndice = indice;
|
||||
myType = setType;
|
||||
strval = "";
|
||||
|
@ -249,8 +254,6 @@ DTSC::DTMI::DTMI(std::string indice, double val, DTSC::DTMItype setType){//num t
|
|||
};
|
||||
|
||||
/// Constructor for string objects.
|
||||
/// The object type is by default AMF::AMF0_STRING, but this can be forced to a different value.
|
||||
/// There is no need to manually change the type to AMF::AMF0_LONGSTRING, this will be done automatically.
|
||||
/// \param indice The string indice of this object in its container, or empty string if none. Numeric indices are automatic.
|
||||
/// \param val The string value of this object.
|
||||
/// \param setType The object type to force this object to.
|
||||
|
@ -262,8 +265,7 @@ DTSC::DTMI::DTMI(std::string indice, std::string val, DTSC::DTMItype setType){//
|
|||
};
|
||||
|
||||
/// Constructor for container objects.
|
||||
/// The object type is by default AMF::AMF0_OBJECT, but this can be forced to a different value.
|
||||
/// \param indice The string indice of this object in its container, or empty string if none. Numeric indices are automatic.
|
||||
/// \param indice The string indice of this object in its container, or empty string if none.
|
||||
/// \param setType The object type to force this object to.
|
||||
DTSC::DTMI::DTMI(std::string indice, DTSC::DTMItype setType){//object type initializer
|
||||
myIndice = indice;
|
||||
|
@ -290,7 +292,13 @@ void DTSC::DTMI::Print(std::string indent){
|
|||
// print my numeric or string contents
|
||||
switch (myType){
|
||||
case DTMI_INT: std::cerr << numval; break;
|
||||
case DTMI_STRING: std::cerr << strval; break;
|
||||
case DTMI_STRING:
|
||||
if (strval.length() > 200 || ((strval.length() > 1) && ( (strval[0] < 'A') || (strval[0] > 'z') ) )){
|
||||
std::cerr << strval.length() << " bytes of data";
|
||||
}else{
|
||||
std::cerr << strval;
|
||||
}
|
||||
break;
|
||||
default: break;//we don't care about the rest, and don't want a compiler warning...
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
|
@ -303,11 +311,22 @@ void DTSC::DTMI::Print(std::string indent){
|
|||
/// Packs the DTMI to a std::string for transfer over the network.
|
||||
/// If a packed version already exists, does not regenerate it.
|
||||
/// If the object is a container type, this function will call itself recursively and contain all contents.
|
||||
std::string DTSC::DTMI::Pack(){
|
||||
if (packed != ""){return packed;}
|
||||
/// \arg netpack If true, will pack as a full DTMI packet, if false only as the contents without header.
|
||||
std::string DTSC::DTMI::Pack(bool netpack){
|
||||
if (packed != ""){
|
||||
if (netpacked == netpack){return packed;}
|
||||
if (netpacked){
|
||||
packed.erase(0, 8);
|
||||
}else{
|
||||
unsigned int size = htonl(packed.length());
|
||||
packed.insert(0, (char*)&size, 4);
|
||||
packed.insert(0, Magic_Packet);
|
||||
}
|
||||
netpacked = !netpacked;
|
||||
return packed;
|
||||
}
|
||||
std::string r = "";
|
||||
//skip output of DDV container types, they do not exist. Only output their contents.
|
||||
if (myType != DTMI_ROOT){r += myType;}
|
||||
r += myType;
|
||||
//output the properly formatted data stream for this object's contents.
|
||||
switch (myType){
|
||||
case DTMI_INT:
|
||||
|
@ -324,6 +343,7 @@ std::string DTSC::DTMI::Pack(){
|
|||
r += strval;
|
||||
break;
|
||||
case DTMI_OBJECT:
|
||||
case DTMI_ROOT:
|
||||
if (contents.size() > 0){
|
||||
for (std::vector<DTSC::DTMI>::iterator it = contents.begin(); it != contents.end(); it++){
|
||||
r += it->Indice().size() / 256;
|
||||
|
@ -332,20 +352,19 @@ std::string DTSC::DTMI::Pack(){
|
|||
r += it->Pack();
|
||||
}
|
||||
}
|
||||
r += (char)0; r += (char)0; r += (char)9;
|
||||
break;
|
||||
case DTMI_ROOT://only send contents
|
||||
if (contents.size() > 0){
|
||||
for (std::vector<DTSC::DTMI>::iterator it = contents.begin(); it != contents.end(); it++){
|
||||
r += it->Pack();
|
||||
}
|
||||
}
|
||||
r += (char)0x0; r += (char)0x0; r += (char)0xEE;
|
||||
break;
|
||||
case DTMI_OBJ_END:
|
||||
break;
|
||||
}
|
||||
packed = r;
|
||||
return r;
|
||||
netpacked = netpack;
|
||||
if (netpacked){
|
||||
unsigned int size = htonl(packed.length());
|
||||
packed.insert(0, (char*)&size, 4);
|
||||
packed.insert(0, Magic_Packet);
|
||||
}
|
||||
return packed;
|
||||
};//pack
|
||||
|
||||
/// Parses a single AMF0 type - used recursively by the AMF::parse() functions.
|
||||
|
@ -372,7 +391,7 @@ DTSC::DTMI DTSC::parseOneDTMI(const unsigned char *& data, unsigned int &len, un
|
|||
tmpdbl[2] = data[i+6];
|
||||
tmpdbl[1] = data[i+7];
|
||||
tmpdbl[0] = data[i+8];
|
||||
i+=9;//skip 8(a double)+1 forwards
|
||||
i+=9;//skip 8(an uint64_t)+1 forwards
|
||||
return DTSC::DTMI(name, *(uint64_t*)tmpdbl, DTMI_INT);
|
||||
break;
|
||||
case DTMI_STRING:
|
||||
|
@ -382,17 +401,30 @@ DTSC::DTMI DTSC::parseOneDTMI(const unsigned char *& data, unsigned int &len, un
|
|||
i += tmpi + 5;//skip length+size+1 forwards
|
||||
return DTSC::DTMI(name, tmpstr, DTMI_STRING);
|
||||
break;
|
||||
case DTMI_OBJECT:{
|
||||
case DTMI_ROOT:{
|
||||
++i;
|
||||
DTSC::DTMI ret(name, DTMI_OBJECT);
|
||||
while (data[i] + data[i+1] != 0){//while not encountering 0x0000 (we assume 0x000009)
|
||||
DTSC::DTMI ret(name, DTMI_ROOT);
|
||||
while (data[i] + data[i+1] != 0){//while not encountering 0x0000 (we assume 0x0000EE)
|
||||
tmpi = data[i]*256+data[i+1];//set tmpi to the UTF-8 length
|
||||
tmpstr.clear();//clean tmpstr, just to be sure
|
||||
tmpstr.append((const char*)data+i+2, (size_t)tmpi);//add the string data
|
||||
i += tmpi + 2;//skip length+size forwards
|
||||
ret.addContent(parseOneDTMI(data, len, i, tmpstr));//add content, recursively parsed, updating i, setting indice to tmpstr
|
||||
}
|
||||
i += 3;//skip 0x000009
|
||||
i += 3;//skip 0x0000EE
|
||||
return ret;
|
||||
} break;
|
||||
case DTMI_OBJECT:{
|
||||
++i;
|
||||
DTSC::DTMI ret(name, DTMI_OBJECT);
|
||||
while (data[i] + data[i+1] != 0){//while not encountering 0x0000 (we assume 0x0000EE)
|
||||
tmpi = data[i]*256+data[i+1];//set tmpi to the UTF-8 length
|
||||
tmpstr.clear();//clean tmpstr, just to be sure
|
||||
tmpstr.append((const char*)data+i+2, (size_t)tmpi);//add the string data
|
||||
i += tmpi + 2;//skip length+size forwards
|
||||
ret.addContent(parseOneDTMI(data, len, i, tmpstr));//add content, recursively parsed, updating i, setting indice to tmpstr
|
||||
}
|
||||
i += 3;//skip 0x0000EE
|
||||
return ret;
|
||||
} break;
|
||||
}
|
||||
|
@ -403,22 +435,18 @@ DTSC::DTMI DTSC::parseOneDTMI(const unsigned char *& data, unsigned int &len, un
|
|||
}//parseOne
|
||||
|
||||
/// Parses a C-string to a valid DTSC::DTMI.
|
||||
/// This function will find all AMF objects in the string and return
|
||||
/// them all packed in a single AMF::AMF0_DDV_CONTAINER DTSC::DTMI.
|
||||
/// This function will find one DTMI object in the string and return it.
|
||||
DTSC::DTMI DTSC::parseDTMI(const unsigned char * data, unsigned int len){
|
||||
DTSC::DTMI ret("returned", DTMI_ROOT);//container type
|
||||
unsigned int i = 0, j = 0;
|
||||
while (i < len){
|
||||
ret.addContent(parseOneDTMI(data, len, i, ""));
|
||||
if (i > j){j = i;}else{return ret;}
|
||||
}
|
||||
DTSC::DTMI ret;//container type
|
||||
unsigned int i = 0;
|
||||
ret = parseOneDTMI(data, len, i, "");
|
||||
ret.packed = std::string((char*)data, (size_t)len);
|
||||
ret.netpacked = false;
|
||||
return ret;
|
||||
}//parse
|
||||
|
||||
/// Parses a std::string to a valid DTSC::DTMI.
|
||||
/// This function will find all AMF objects in the string and return
|
||||
/// them all packed in a single AMF::AMF0_DDV_CONTAINER DTSC::DTMI.
|
||||
/// This function will find one DTMI object in the string and return it.
|
||||
DTSC::DTMI DTSC::parseDTMI(std::string data){
|
||||
return parseDTMI((const unsigned char*)data.c_str(), data.size());
|
||||
}//parse
|
||||
|
|
|
@ -45,11 +45,12 @@ namespace DTSC{
|
|||
DTMI* getContentP(std::string s);
|
||||
DTMI getContent(std::string s);
|
||||
DTMI();
|
||||
DTMI(std::string indice, double val, DTMItype setType = DTMI_INT);
|
||||
DTMI(std::string indice, uint64_t val, DTMItype setType = DTMI_INT);
|
||||
DTMI(std::string indice, std::string val, DTMItype setType = DTMI_STRING);
|
||||
DTMI(std::string indice, DTMItype setType = DTMI_OBJECT);
|
||||
void Print(std::string indent = "");
|
||||
std::string Pack();
|
||||
std::string Pack(bool netpack = false);
|
||||
bool netpacked;
|
||||
std::string packed;
|
||||
protected:
|
||||
std::string myIndice; ///< Holds this objects indice, if any.
|
||||
|
@ -102,8 +103,8 @@ namespace DTSC{
|
|||
bool hasVideo();
|
||||
bool hasAudio();
|
||||
bool parsePacket(std::string & buffer);
|
||||
std::string outPacket(unsigned int num);
|
||||
std::string outHeader();
|
||||
std::string & outPacket(unsigned int num);
|
||||
std::string & outHeader();
|
||||
Ring * getRing();
|
||||
void dropRing(Ring * ptr);
|
||||
private:
|
||||
|
|
|
@ -109,7 +109,7 @@ std::string FLV::Tag::tagType(){
|
|||
case 4: R += "VP6"; break;
|
||||
case 5: R += "VP6Alpha"; break;
|
||||
case 6: R += "ScreenVideo2"; break;
|
||||
case 7: R += "AVC"; break;
|
||||
case 7: R += "H264"; break;
|
||||
default: R += "unknown"; break;
|
||||
}
|
||||
R += " video ";
|
||||
|
|
Loading…
Add table
Reference in a new issue