From 48bf3d189abc53c0a953f3850e7174c5bb1260e1 Mon Sep 17 00:00:00 2001 From: Thulinma Date: Thu, 23 Aug 2012 17:05:53 +0200 Subject: [PATCH] Half-updated flv_tag with JSON metadata support. --- lib/flv_tag.cpp | 176 ++++++++++++++++++++++-------------------------- lib/flv_tag.h | 11 +-- 2 files changed, 85 insertions(+), 102 deletions(-) diff --git a/lib/flv_tag.cpp b/lib/flv_tag.cpp index 6a70cc06..95070b19 100644 --- a/lib/flv_tag.cpp +++ b/lib/flv_tag.cpp @@ -772,8 +772,8 @@ bool FLV::Tag::FileLoader(FILE * f){ return false; }//FLV_GetPacket -DTSC::DTMI FLV::Tag::toDTSC(DTSC::DTMI & metadata){ - DTSC::DTMI pack_out; // Storage for outgoing DTMI data. +JSON::Value FLV::Tag::toJSON(JSON::Value & metadata){ + JSON::Value pack_out; // Storage for outgoing metadata. if (data[0] == 0x12){ AMF::Object meta_in = AMF::parse((unsigned char*)data+11, len-15); @@ -781,45 +781,59 @@ DTSC::DTMI FLV::Tag::toDTSC(DTSC::DTMI & metadata){ AMF::Object * tmp = meta_in.getContentP(1); if (tmp->getContentP("videocodecid")){ switch ((unsigned int)tmp->getContentP("videocodecid")->NumValue()){ - case 2: Meta_Put(metadata, "video", "codec", "H263"); break; - case 4: Meta_Put(metadata, "video", "codec", "VP6"); break; - case 7: Meta_Put(metadata, "video", "codec", "H264"); break; - default: Meta_Put(metadata, "video", "codec", "?"); break; + case 2: metadata["video"]["codec"] = "H263"; break; + case 4: metadata["video"]["codec"] = "VP6"; break; + case 7: metadata["video"]["codec"] = "H264"; break; + default: metadata["video"]["codec"] = "?"; break; } } if (tmp->getContentP("audiocodecid")){ switch ((unsigned int)tmp->getContentP("audiocodecid")->NumValue()){ - case 2: Meta_Put(metadata, "audio", "codec", "MP3"); break; - case 10: Meta_Put(metadata, "audio", "codec", "AAC"); break; - default: Meta_Put(metadata, "audio", "codec", "?"); break; + case 2: metadata["audio"]["codec"] = "MP3"; break; + case 10: metadata["audio"]["codec"] = "AAC"; break; + default: metadata["audio"]["codec"] = "?"; break; } } if (tmp->getContentP("width")){ - Meta_Put(metadata, "video", "width", (unsigned long long int)tmp->getContentP("width")->NumValue()); + metadata["video"]["width"] = (long long int)tmp->getContentP("width")->NumValue(); } if (tmp->getContentP("height")){ - Meta_Put(metadata, "video", "height", (unsigned long long int)tmp->getContentP("height")->NumValue()); + metadata["video"]["height"] = (long long int)tmp->getContentP("height")->NumValue(); } if (tmp->getContentP("framerate")){ - Meta_Put(metadata, "video", "fpks", (unsigned long long int)tmp->getContentP("framerate")->NumValue()*1000); + metadata["video"]["fpks"] = (long long int)tmp->getContentP("framerate")->NumValue()*1000; } if (tmp->getContentP("videodatarate")){ - Meta_Put(metadata, "video", "bps", (unsigned long long int)(tmp->getContentP("videodatarate")->NumValue()*1024)/8); + metadata["video"]["bps"] = (long long int)(tmp->getContentP("videodatarate")->NumValue()*1024)/8; } if (tmp->getContentP("audiodatarate")){ - Meta_Put(metadata, "audio", "bps", (unsigned long long int)(tmp->getContentP("audiodatarate")->NumValue()*1024)/8); + metadata["audio"]["bps"] = (long long int)(tmp->getContentP("audiodatarate")->NumValue()*1024)/8; } if (tmp->getContentP("audiosamplerate")){ - Meta_Put(metadata, "audio", "rate", (unsigned long long int)tmp->getContentP("audiosamplerate")->NumValue()); + metadata["audio"]["rate"] = (long long int)tmp->getContentP("audiosamplerate")->NumValue(); } if (tmp->getContentP("audiosamplesize")){ - Meta_Put(metadata, "audio", "size", (unsigned long long int)tmp->getContentP("audiosamplesize")->NumValue()); + metadata["audio"]["size"] = (long long int)tmp->getContentP("audiosamplesize")->NumValue(); } if (tmp->getContentP("stereo")){ if (tmp->getContentP("stereo")->NumValue() == 1){ - Meta_Put(metadata, "audio", "channels", 2); + metadata["audio"]["channels"] = 2; }else{ - Meta_Put(metadata, "audio", "channels", 1); + metadata["audio"]["channels"] = 1; + } + } + } + if (!metadata.isMember("length")){metadata["length"] = 0;} + if (metadata.isMember("video")){ + if (!metadata["video"].isMember("width")){metadata["video"]["width"] = 0;} + if (!metadata["video"].isMember("height")){metadata["video"]["height"] = 0;} + if (!metadata["video"].isMember("fpks")){metadata["video"]["fpks"] = 0;} + if (!metadata["video"].isMember("bps")){metadata["video"]["bps"] = 0;} + if (!metadata["video"].isMember("keyms")){metadata["video"]["keyms"] = 0;} + if (!metadata["video"].isMember("keyvar")){metadata["video"]["keyvar"] = 0;} + if (!metadata["video"].isMember("keys")){ + while (metadata["video"]["keys"].size() < 100){ + metadata["video"]["keys"].append(JSON::Value((long long int)0)); } } } @@ -829,48 +843,47 @@ DTSC::DTMI FLV::Tag::toDTSC(DTSC::DTMI & metadata){ char audiodata = data[11]; if (needsInitData() && isInitData()){ if ((audiodata & 0xF0) == 0xA0){ - Meta_Put(metadata, "audio", "init", std::string((char*)data+13, (size_t)len-17)); + metadata["audio"]["init"] = std::string((char*)data+13, (size_t)len-17); }else{ - Meta_Put(metadata, "audio", "init", std::string((char*)data+12, (size_t)len-16)); + metadata["audio"]["init"] = std::string((char*)data+12, (size_t)len-16); } return pack_out;//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", tagTime())); - if (!Meta_Has(metadata, "audio", "codec")){ + pack_out["datatype"] = "audio"; + pack_out["time"] = tagTime(); + if (!metadata["audio"].isMember("codec") || metadata["audio"]["size"].asString() == ""){ switch (audiodata & 0xF0){ - case 0x20: Meta_Put(metadata, "audio", "codec", "MP3"); break; - case 0xA0: Meta_Put(metadata, "audio", "codec", "AAC"); break; - default: Meta_Put(metadata, "audio", "codec", "?"); break; + case 0x20: metadata["audio"]["codec"] = "MP3"; break; + case 0xA0: metadata["audio"]["codec"] = "AAC"; break; + default: metadata["audio"]["codec"] = "?"; break; } } - if (!Meta_Has(metadata, "audio", "rate")){ + if (!metadata["audio"].isMember("rate") || metadata["audio"]["rate"].asInt() < 1){ switch (audiodata & 0x0C){ - case 0x0: Meta_Put(metadata, "audio", "rate", 5512); break; - case 0x4: Meta_Put(metadata, "audio", "rate", 11025); break; - case 0x8: Meta_Put(metadata, "audio", "rate", 22050); break; - case 0xC: Meta_Put(metadata, "audio", "rate", 44100); break; + case 0x0: metadata["audio"]["rate"] = 5512; break; + case 0x4: metadata["audio"]["rate"] = 11025; break; + case 0x8: metadata["audio"]["rate"] = 22050; break; + case 0xC: metadata["audio"]["rate"] = 44100; break; } } - if (!Meta_Has(metadata, "audio", "size")){ + if (!metadata["audio"].isMember("size") || metadata["audio"]["size"].asInt() < 1){ switch (audiodata & 0x02){ - case 0x0: Meta_Put(metadata, "audio", "size", 8); break; - case 0x2: Meta_Put(metadata, "audio", "size", 16); break; + case 0x0: metadata["audio"]["size"] = 8; break; + case 0x2: metadata["audio"]["size"] = 16; break; } } - if (!Meta_Has(metadata, "audio", "channels")){ + if (!metadata["audio"].isMember("channels") || metadata["audio"]["channels"].asInt() < 1){ switch (audiodata & 0x01){ - case 0x0: Meta_Put(metadata, "audio", "channels", 1); break; - case 0x1: Meta_Put(metadata, "audio", "channels", 2); break; + case 0x0: metadata["audio"]["channels"] = 1; break; + case 0x1: metadata["audio"]["channels"] = 2; break; } } if ((audiodata & 0xF0) == 0xA0){ - if (len < 18){return DTSC::DTMI();} - pack_out.addContent(DTSC::DTMI("data", std::string((char*)data+13, (size_t)len-17))); + if (len < 18){return JSON::Value();} + pack_out["data"] = std::string((char*)data+13, (size_t)len-17); }else{ - if (len < 17){return DTSC::DTMI();} - pack_out.addContent(DTSC::DTMI("data", std::string((char*)data+12, (size_t)len-16))); + if (len < 17){return JSON::Value();} + pack_out["data"] = std::string((char*)data+12, (size_t)len-16); } return pack_out; } @@ -878,77 +891,46 @@ DTSC::DTMI FLV::Tag::toDTSC(DTSC::DTMI & metadata){ char videodata = data[11]; if (needsInitData() && isInitData()){ if ((videodata & 0x0F) == 7){ - if (len < 21){return DTSC::DTMI();} - Meta_Put(metadata, "video", "init", std::string((char*)data+16, (size_t)len-20)); + if (len < 21){return JSON::Value();} + metadata["video"]["init"] = std::string((char*)data+16, (size_t)len-20); }else{ - if (len < 17){return DTSC::DTMI();} - Meta_Put(metadata, "video", "init", std::string((char*)data+12, (size_t)len-16)); + if (len < 17){return JSON::Value();} + metadata["video"]["init"] = std::string((char*)data+12, (size_t)len-16); } return pack_out;//skip rest of parsing, get next tag. } - if (!Meta_Has(metadata, "video", "codec")){ + if (!metadata["video"].isMember("codec") || metadata["video"]["codec"].asString() == ""){ switch (videodata & 0x0F){ - case 2: Meta_Put(metadata, "video", "codec", "H263"); break; - case 4: Meta_Put(metadata, "video", "codec", "VP6"); break; - case 7: Meta_Put(metadata, "video", "codec", "H264"); break; - default: Meta_Put(metadata, "video", "codec", "?"); break; + case 2: metadata["video"]["codec"] = "H263"; break; + case 4: metadata["video"]["codec"] = "VP6"; break; + case 7: metadata["video"]["codec"] = "H264"; break; + default: metadata["video"]["codec"] = "?"; break; } } - pack_out = DTSC::DTMI("video", DTSC::DTMI_ROOT); - pack_out.addContent(DTSC::DTMI("datatype", "video")); + pack_out["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: return DTSC::DTMI(); break;//the video info byte we just throw away - useless to us... + case 0x10: pack_out["keyframe"] = 1; break; + case 0x20: pack_out["interframe"] = 1; break; + case 0x30: pack_out["disposableframe"] = 1; break; + case 0x40: pack_out["keyframe"] = 1; break; + case 0x50: return JSON::Value(); break;//the video info byte we just throw away - useless to us... } - pack_out.addContent(DTSC::DTMI("time", tagTime())); + pack_out["time"] = tagTime(); if ((videodata & 0x0F) == 7){ switch (data[12]){ - case 1: pack_out.addContent(DTSC::DTMI("nalu", 1)); break; - case 2: pack_out.addContent(DTSC::DTMI("nalu_end", 1)); break; + case 1: pack_out["nalu"] = 1; break; + case 2: pack_out["nalu_end"] = 1; break; } int offset = (data[13] << 16) + (data[14] << 8) + data[15]; offset = (offset << 8) >> 8; - pack_out.addContent(DTSC::DTMI("offset", offset)); - if (len < 21){return DTSC::DTMI();} - pack_out.addContent(DTSC::DTMI("data", std::string((char*)data+16, (size_t)len-20))); + pack_out["offset"] = offset; + if (len < 21){return JSON::Value();} + pack_out["data"] = std::string((char*)data+16, (size_t)len-20); }else{ - if (len < 17){return DTSC::DTMI();} - pack_out.addContent(DTSC::DTMI("data", std::string((char*)data+12, (size_t)len-16))); + if (len < 17){return JSON::Value();} + pack_out["data"] = std::string((char*)data+12, (size_t)len-16); } return pack_out; } return pack_out;//should never get here -}//FLV::Tag::toDTSC - -/// 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 FLV::Tag::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)); -} - -/// 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 FLV::Tag::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)); -} - -/// 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 FLV::Tag::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; -} +}//FLV::Tag::toJSON diff --git a/lib/flv_tag.h b/lib/flv_tag.h index 6848995c..4e61fc6a 100644 --- a/lib/flv_tag.h +++ b/lib/flv_tag.h @@ -4,6 +4,7 @@ #pragma once #include "socket.h" #include "dtsc.h" +#include "json.h" #include //forward declaration of RTMPStream::Chunk to avoid circular dependencies. @@ -43,7 +44,7 @@ namespace FLV { bool DTSCVideoInit(DTSC::Stream & S); bool DTSCAudioInit(DTSC::Stream & S); bool DTSCMetaInit(DTSC::Stream & S); - DTSC::DTMI toDTSC(DTSC::DTMI & metadata); + JSON::Value toJSON(JSON::Value & metadata); bool MemLoader(char * D, unsigned int S, unsigned int & P); bool SockLoader(int sock); bool SockLoader(Socket::Connection sock); @@ -57,10 +58,10 @@ namespace FLV { bool MemReadUntil(char * buffer, unsigned int count, unsigned int & sofar, char * D, unsigned int S, unsigned int & P); bool SockReadUntil(char * buffer, unsigned int count, unsigned int & sofar, Socket::Connection & sock); bool FileReadUntil(char * buffer, unsigned int count, unsigned int & sofar, FILE * f); - //DTSC writer helpers - void Meta_Put(DTSC::DTMI & meta, std::string cat, std::string elem, std::string val); - void Meta_Put(DTSC::DTMI & meta, std::string cat, std::string elem, uint64_t val); - bool Meta_Has(DTSC::DTMI & meta, std::string cat, std::string elem); + //JSON writer helpers + void Meta_Put(JSON::Value & meta, std::string cat, std::string elem, std::string val); + void Meta_Put(JSON::Value & meta, std::string cat, std::string elem, uint64_t val); + bool Meta_Has(JSON::Value & meta, std::string cat, std::string elem); };//Tag };//FLV namespace