diff --git a/util/amf.cpp b/util/amf.cpp index b5f51fad..a11788fb 100644 --- a/util/amf.cpp +++ b/util/amf.cpp @@ -2,6 +2,7 @@ /// Holds all code for the AMF namespace. #include "amf.h" +#include #include //needed for stderr only /// Returns the std::string Indice for the current object, if available. @@ -105,43 +106,45 @@ AMF::Object::Object(std::string indice, AMF::obj0type setType){//object type ini /// Prints the contents of this object to std::cerr. /// If this object contains other objects, it will call itself recursively /// and print all nested content in a nice human-readable format. -void AMF::Object::Print(std::string indent){ - std::cerr << indent; +std::string AMF::Object::Print(std::string indent){ + std::stringstream st; + st << indent; // print my type switch (myType){ - case AMF::AMF0_NUMBER: std::cerr << "Number"; break; - case AMF::AMF0_BOOL: std::cerr << "Bool"; break; + case AMF::AMF0_NUMBER: st << "Number"; break; + case AMF::AMF0_BOOL: st << "Bool"; break; case AMF::AMF0_STRING://short string - case AMF::AMF0_LONGSTRING: std::cerr << "String"; break; - case AMF::AMF0_OBJECT: std::cerr << "Object"; break; - case AMF::AMF0_MOVIECLIP: std::cerr << "MovieClip"; break; - case AMF::AMF0_NULL: std::cerr << "Null"; break; - case AMF::AMF0_UNDEFINED: std::cerr << "Undefined"; break; - case AMF::AMF0_REFERENCE: std::cerr << "Reference"; break; - case AMF::AMF0_ECMA_ARRAY: std::cerr << "ECMA Array"; break; - case AMF::AMF0_OBJ_END: std::cerr << "Object end"; break; - case AMF::AMF0_STRICT_ARRAY: std::cerr << "Strict Array"; break; - case AMF::AMF0_DATE: std::cerr << "Date"; break; - case AMF::AMF0_UNSUPPORTED: std::cerr << "Unsupported"; break; - case AMF::AMF0_RECORDSET: std::cerr << "Recordset"; break; - case AMF::AMF0_XMLDOC: std::cerr << "XML Document"; break; - case AMF::AMF0_TYPED_OBJ: std::cerr << "Typed Object"; break; - case AMF::AMF0_UPGRADE: std::cerr << "Upgrade to AMF3"; break; - case AMF::AMF0_DDV_CONTAINER: std::cerr << "DDVTech Container"; break; + case AMF::AMF0_LONGSTRING: st << "String"; break; + case AMF::AMF0_OBJECT: st << "Object"; break; + case AMF::AMF0_MOVIECLIP: st << "MovieClip"; break; + case AMF::AMF0_NULL: st << "Null"; break; + case AMF::AMF0_UNDEFINED: st << "Undefined"; break; + case AMF::AMF0_REFERENCE: st << "Reference"; break; + case AMF::AMF0_ECMA_ARRAY: st << "ECMA Array"; break; + case AMF::AMF0_OBJ_END: st << "Object end"; break; + case AMF::AMF0_STRICT_ARRAY: st << "Strict Array"; break; + case AMF::AMF0_DATE: st << "Date"; break; + case AMF::AMF0_UNSUPPORTED: st << "Unsupported"; break; + case AMF::AMF0_RECORDSET: st << "Recordset"; break; + case AMF::AMF0_XMLDOC: st << "XML Document"; break; + case AMF::AMF0_TYPED_OBJ: st << "Typed Object"; break; + case AMF::AMF0_UPGRADE: st << "Upgrade to AMF3"; break; + case AMF::AMF0_DDV_CONTAINER: st << "DDVTech Container"; break; } // print my string indice, if available - std::cerr << " " << myIndice << " "; + st << " " << myIndice << " "; // print my numeric or string contents switch (myType){ - case AMF::AMF0_NUMBER: case AMF::AMF0_BOOL: case AMF::AMF0_REFERENCE: case AMF::AMF0_DATE: std::cerr << numval; break; - case AMF::AMF0_STRING: case AMF::AMF0_LONGSTRING: case AMF::AMF0_XMLDOC: case AMF::AMF0_TYPED_OBJ: std::cerr << strval; break; + case AMF::AMF0_NUMBER: case AMF::AMF0_BOOL: case AMF::AMF0_REFERENCE: case AMF::AMF0_DATE: st << numval; break; + case AMF::AMF0_STRING: case AMF::AMF0_LONGSTRING: case AMF::AMF0_XMLDOC: case AMF::AMF0_TYPED_OBJ: st << strval; break; default: break;//we don't care about the rest, and don't want a compiler warning... } - std::cerr << std::endl; + st << std::endl; // if I hold other objects, print those too, recursively. if (contents.size() > 0){ - for (std::vector::iterator it = contents.begin(); it != contents.end(); it++){it->Print(indent+" ");} + for (std::vector::iterator it = contents.begin(); it != contents.end(); it++){st << it->Print(indent+" ");} } + return st.str(); };//print /// Packs the AMF object to a std::string for transfer over the network. diff --git a/util/amf.h b/util/amf.h index 61f95a8a..836cfdb2 100644 --- a/util/amf.h +++ b/util/amf.h @@ -70,7 +70,7 @@ namespace AMF{ Object(std::string indice, double val, obj0type setType = AMF0_NUMBER); Object(std::string indice, std::string val, obj0type setType = AMF0_STRING); Object(std::string indice, obj0type setType = AMF0_OBJECT); - void Print(std::string indent = ""); + std::string Print(std::string indent = ""); std::string Pack(); protected: std::string myIndice; ///< Holds this objects indice, if any. diff --git a/util/dtsc.h b/util/dtsc.h index f721e6c4..138e3ab4 100644 --- a/util/dtsc.h +++ b/util/dtsc.h @@ -106,9 +106,9 @@ namespace DTSC{ class Ring { public: Ring(unsigned int v); - unsigned int b; ///< Holds current number of buffer. May and is intended to change unexpectedly! - bool waiting; ///< If true, this Ring is currently waiting for a buffer fill. - bool starved; ///< If true, this Ring can no longer receive valid data. + volatile unsigned int b; ///< Holds current number of buffer. May and is intended to change unexpectedly! + volatile bool waiting; ///< If true, this Ring is currently waiting for a buffer fill. + volatile bool starved; ///< If true, this Ring can no longer receive valid data. }; /// Holds temporary data for a DTSC stream and provides functions to utilize it. diff --git a/util/flv_tag.cpp b/util/flv_tag.cpp index cf75e549..bba87754 100644 --- a/util/flv_tag.cpp +++ b/util/flv_tag.cpp @@ -9,6 +9,7 @@ #include //for Tag::FileLoader #include //malloc #include //memcpy +#include /// Holds the last FLV header parsed. /// Defaults to a audio+video header on FLV version 0x01 if no header received yet. @@ -100,80 +101,84 @@ bool FLV::Tag::isInitData(){ /// audio, video or metadata, what encoding is used, and the details /// of the encoding itself. std::string FLV::Tag::tagType(){ - std::string R = ""; + std::stringstream R; + R << len << " bytes of "; switch (data[0]){ case 0x09: switch (data[11] & 0x0F){ - case 1: R += "JPEG"; break; - case 2: R += "H263"; break; - case 3: R += "ScreenVideo1"; break; - case 4: R += "VP6"; break; - case 5: R += "VP6Alpha"; break; - case 6: R += "ScreenVideo2"; break; - case 7: R += "H264"; break; - default: R += "unknown"; break; + case 1: R << "JPEG"; break; + case 2: R << "H263"; break; + case 3: R << "ScreenVideo1"; break; + case 4: R << "VP6"; break; + case 5: R << "VP6Alpha"; break; + case 6: R << "ScreenVideo2"; break; + case 7: R << "H264"; break; + default: R << "unknown"; break; } - R += " video "; + R << " video "; switch (data[11] & 0xF0){ - case 0x10: R += "keyframe"; break; - case 0x20: R += "iframe"; break; - case 0x30: R += "disposableiframe"; break; - case 0x40: R += "generatedkeyframe"; break; - case 0x50: R += "videoinfo"; break; + case 0x10: R << "keyframe"; break; + case 0x20: R << "iframe"; break; + case 0x30: R << "disposableiframe"; break; + case 0x40: R << "generatedkeyframe"; break; + case 0x50: R << "videoinfo"; break; } if ((data[11] & 0x0F) == 7){ switch (data[12]){ - case 0: R += " header"; break; - case 1: R += " NALU"; break; - case 2: R += " endofsequence"; break; + case 0: R << " header"; break; + case 1: R << " NALU"; break; + case 2: R << " endofsequence"; break; } } break; case 0x08: switch (data[11] & 0xF0){ - case 0x00: R += "linear PCM PE"; break; - case 0x10: R += "ADPCM"; break; - case 0x20: R += "MP3"; break; - case 0x30: R += "linear PCM LE"; break; - case 0x40: R += "Nelly16kHz"; break; - case 0x50: R += "Nelly8kHz"; break; - case 0x60: R += "Nelly"; break; - case 0x70: R += "G711A-law"; break; - case 0x80: R += "G711mu-law"; break; - case 0x90: R += "reserved"; break; - case 0xA0: R += "AAC"; break; - case 0xB0: R += "Speex"; break; - case 0xE0: R += "MP38kHz"; break; - case 0xF0: R += "DeviceSpecific"; break; - default: R += "unknown"; break; + case 0x00: R << "linear PCM PE"; break; + case 0x10: R << "ADPCM"; break; + case 0x20: R << "MP3"; break; + case 0x30: R << "linear PCM LE"; break; + case 0x40: R << "Nelly16kHz"; break; + case 0x50: R << "Nelly8kHz"; break; + case 0x60: R << "Nelly"; break; + case 0x70: R << "G711A-law"; break; + case 0x80: R << "G711mu-law"; break; + case 0x90: R << "reserved"; break; + case 0xA0: R << "AAC"; break; + case 0xB0: R << "Speex"; break; + case 0xE0: R << "MP38kHz"; break; + case 0xF0: R << "DeviceSpecific"; break; + default: R << "unknown"; break; } switch (data[11] & 0x0C){ - case 0x0: R += " 5.5kHz"; break; - case 0x4: R += " 11kHz"; break; - case 0x8: R += " 22kHz"; break; - case 0xC: R += " 44kHz"; break; + case 0x0: R << " 5.5kHz"; break; + case 0x4: R << " 11kHz"; break; + case 0x8: R << " 22kHz"; break; + case 0xC: R << " 44kHz"; break; } switch (data[11] & 0x02){ - case 0: R += " 8bit"; break; - case 2: R += " 16bit"; break; + case 0: R << " 8bit"; break; + case 2: R << " 16bit"; break; } switch (data[11] & 0x01){ - case 0: R += " mono"; break; - case 1: R += " stereo"; break; + case 0: R << " mono"; break; + case 1: R << " stereo"; break; } - R += " audio"; + R << " audio"; if ((data[12] == 0) && ((data[11] & 0xF0) == 0xA0)){ - R += " initdata"; + R << " initdata"; } break; - case 0x12: - R += "(meta)data"; + case 0x12:{ + R << "(meta)data: "; + AMF::Object metadata = AMF::parse((unsigned char*)data+11, len-15); + R << metadata.Print(); break; + } default: - R += "unknown"; + R << "unknown"; break; } - return R; + return R.str(); }//FLV::Tag::tagtype /// Returns the 32-bit timestamp of this tag. @@ -297,7 +302,7 @@ bool FLV::Tag::DTSCLoader(DTSC::Stream & S){ if (S.getPacket().getContentP("interframe")){data[11] += 0x20;} if (S.getPacket().getContentP("disposableframe")){data[11] += 0x30;} break; - case DTSC::AUDIO: + case DTSC::AUDIO:{ if ((unsigned int)len == S.lastData().length() + 16){ memcpy(data+12, S.lastData().c_str(), S.lastData().length()); }else{ @@ -307,12 +312,18 @@ bool FLV::Tag::DTSCLoader(DTSC::Stream & S){ data[11] = 0; if (S.metadata.getContentP("audio")->getContentP("codec")->StrValue() == "AAC"){data[11] += 0xA0;} if (S.metadata.getContentP("audio")->getContentP("codec")->StrValue() == "MP3"){data[11] += 0x20;} - if (S.metadata.getContentP("audio")->getContentP("rate")->NumValue() == 11025){data[11] += 0x04;} - if (S.metadata.getContentP("audio")->getContentP("rate")->NumValue() == 22050){data[11] += 0x08;} - if (S.metadata.getContentP("audio")->getContentP("rate")->NumValue() == 44100){data[11] += 0x0C;} + unsigned int datarate = S.metadata.getContentP("audio")->getContentP("rate")->NumValue(); + if (datarate >= 44100){ + data[11] += 0x0C; + }else if(datarate >= 22050){ + data[11] += 0x08; + }else if(datarate >= 11025){ + data[11] += 0x04; + } if (S.metadata.getContentP("audio")->getContentP("size")->NumValue() == 16){data[11] += 0x02;} if (S.metadata.getContentP("audio")->getContentP("channels")->NumValue() > 1){data[11] += 0x01;} break; + } case DTSC::META: memcpy(data+11, S.lastData().c_str(), S.lastData().length()); break; @@ -329,6 +340,9 @@ bool FLV::Tag::DTSCLoader(DTSC::Stream & S){ data[1] = ((len-15) >> 16) & 0xFF; data[2] = ((len-15) >> 8) & 0xFF; data[3] = (len-15) & 0xFF; + data[8] = 0; + data[9] = 0; + data[10] = 0; tagTime(S.getPacket().getContentP("time")->NumValue()); return true; } @@ -336,7 +350,7 @@ bool FLV::Tag::DTSCLoader(DTSC::Stream & S){ /// Helper function that properly sets the tag length from the internal len variable. void FLV::Tag::setLen(){ int len4 = len - 4; - int i = len-1; + int i = len; data[--i] = (len4) & 0xFF; len4 >>= 8; data[--i] = (len4) & 0xFF; @@ -375,6 +389,9 @@ bool FLV::Tag::DTSCVideoInit(DTSC::Stream & S){ data[1] = ((len-15) >> 16) & 0xFF; data[2] = ((len-15) >> 8) & 0xFF; data[3] = (len-15) & 0xFF; + data[8] = 0; + data[9] = 0; + data[10] = 0; tagTime(0); return true; } @@ -402,23 +419,25 @@ bool FLV::Tag::DTSCAudioInit(DTSC::Stream & S){ data[11] = 0; if (S.metadata.getContentP("audio")->getContentP("codec")->StrValue() == "AAC"){data[11] += 0xA0;} if (S.metadata.getContentP("audio")->getContentP("codec")->StrValue() == "MP3"){data[11] += 0x20;} - if (S.metadata.getContentP("audio")->getContentP("rate")->NumValue() == 11000){data[11] += 0x04;} - if (S.metadata.getContentP("audio")->getContentP("rate")->NumValue() == 22000){data[11] += 0x08;} - if (S.metadata.getContentP("audio")->getContentP("rate")->NumValue() == 44000){data[11] += 0x0C;} + unsigned int datarate = S.metadata.getContentP("audio")->getContentP("rate")->NumValue(); + if (datarate >= 44100){ + data[11] += 0x0C; + }else if(datarate >= 22050){ + data[11] += 0x08; + }else if(datarate >= 11025){ + data[11] += 0x04; + } if (S.metadata.getContentP("audio")->getContentP("size")->NumValue() == 16){data[11] += 0x02;} if (S.metadata.getContentP("audio")->getContentP("channels")->NumValue() > 1){data[11] += 0x01;} } setLen(); - switch (S.lastType()){ - case DTSC::VIDEO: data[0] = 0x09; break; - case DTSC::AUDIO: data[0] = 0x08; break; - case DTSC::META: data[0] = 0x12; break; - default: break; - } data[0] = 0x08; data[1] = ((len-15) >> 16) & 0xFF; data[2] = ((len-15) >> 8) & 0xFF; data[3] = (len-15) & 0xFF; + data[8] = 0; + data[9] = 0; + data[10] = 0; tagTime(0); return true; } @@ -501,6 +520,9 @@ bool FLV::Tag::DTSCMetaInit(DTSC::Stream & S){ data[1] = ((len-15) >> 16) & 0xFF; data[2] = ((len-15) >> 8) & 0xFF; data[3] = (len-15) & 0xFF; + data[8] = 0; + data[9] = 0; + data[10] = 0; tagTime(0); return true; }