From a3bae914865b273512da234120506afd248093ed Mon Sep 17 00:00:00 2001 From: Erik Zandvliet Date: Mon, 27 May 2013 13:45:42 +0200 Subject: [PATCH] Upgrade FLV output --- lib/dtsc.cpp | 25 ++++++++-- lib/flv_tag.cpp | 127 ++++++++++++++++++++++++++---------------------- lib/flv_tag.h | 4 +- 3 files changed, 92 insertions(+), 64 deletions(-) diff --git a/lib/dtsc.cpp b/lib/dtsc.cpp index 534852ce..4312c01f 100644 --- a/lib/dtsc.cpp +++ b/lib/dtsc.cpp @@ -703,8 +703,12 @@ void DTSC::File::readHeader(int pos){ } long int DTSC::File::getBytePosEOF(){ - fseek(F, 0, SEEK_END); - return ftell(F); + static long int endPos = 0; + if ( !endPos){ + fseek(F, 0, SEEK_END); + endPos = ftell(F); + } + return endPos; } long int DTSC::File::getBytePos(){ @@ -719,8 +723,13 @@ bool DTSC::File::reachedEOF(){ /// If the packet could not be read for any reason, the reason is printed to stderr. /// Reading the packet means the file position is increased to the next packet. void DTSC::File::seekNext(){ - fseek(F,currentPositions.begin()->seekPos, SEEK_SET); + if ( !currentPositions.size()){ + strbuffer = ""; + jsonbuffer.null(); + return; + } seek_time(currentPositions.begin()->seekTime + 1, currentPositions.begin()->trackID); + fseek(F,currentPositions.begin()->seekPos, SEEK_SET); currentPositions.erase(currentPositions.begin()); lastreadpos = ftell(F); if (fread(buffer, 4, 1, F) != 1){ @@ -796,6 +805,8 @@ JSON::Value & DTSC::File::getJSON(){ bool DTSC::File::seek_time(int ms, int trackNo){ seekPos tmpPos; tmpPos.trackID = trackNo; + tmpPos.seekTime = metadata["tracks"][trackMapping[trackNo]]["keytime"][0u].asInt(); + tmpPos.seekPos = metadata["tracks"][trackMapping[trackNo]]["keybpos"][0u].asInt(); for (int i = 0; i < metadata["tracks"][trackMapping[trackNo]]["keynum"].size(); i++){ if (metadata["tracks"][trackMapping[trackNo]]["keytime"][i].asInt() > ms){ break; @@ -805,6 +816,9 @@ bool DTSC::File::seek_time(int ms, int trackNo){ } bool foundPacket = false; while ( !foundPacket){ + if (tmpPos.seekPos == getBytePosEOF()){ + return false; + } //Seek to first packet after ms. seek_bpos(tmpPos.seekPos); //read the header @@ -829,7 +843,6 @@ bool DTSC::File::seek_time(int ms, int trackNo){ } } currentPositions.insert(tmpPos); - fprintf(stderr, "TrackID %d, Time seek %d -- retrieved bytepos %d, timestamp %d\n", trackNo, ms, tmpPos.seekPos, tmpPos.seekTime); } /// Attempts to seek to the given time in ms within the file. @@ -865,7 +878,7 @@ bool DTSC::File::atKeyframe(){ } bool inHeader = false; for (JSON::ObjIter oIt = metadata["tracks"].ObjBegin(); oIt != metadata["tracks"].ObjEnd(); oIt++){ - for (JSON::ArrIter aIt = oIt->second["keynum"].ArrBegin(); aIt != oIt->second["keynum"].ArrEnd(); aIt++){ + for (JSON::ArrIter aIt = oIt->second["keybpos"].ArrBegin(); aIt != oIt->second["keybpos"].ArrEnd(); aIt++){ if ((*aIt).asInt() == getBytePos()){ inHeader = true; break; @@ -878,6 +891,8 @@ bool DTSC::File::atKeyframe(){ void DTSC::File::selectTracks(std::set & tracks){ currentPositions.clear(); selectedTracks = tracks; + for (std::set::iterator it = tracks.begin(); it != tracks.end(); it++){ + } } /// Close the file if open diff --git a/lib/flv_tag.cpp b/lib/flv_tag.cpp index 69041804..8ca1ae2a 100644 --- a/lib/flv_tag.cpp +++ b/lib/flv_tag.cpp @@ -500,18 +500,22 @@ void FLV::Tag::setLen(){ /// Takes the DTSC Video init data and makes it into FLV. /// Assumes init data is available - so check before calling! bool FLV::Tag::DTSCVideoInit(DTSC::Stream & S){ + return DTSCVideoInit(S.metadata["video"]); +} + +bool FLV::Tag::DTSCVideoInit(JSON::Value & video){ //Unknown? Assume H264. - if (S.metadata["video"]["codec"].asString() == "?"){ - S.metadata["video"]["codec"] = "H264"; + if (video["codec"].asString() == "?"){ + video["codec"] = "H264"; } - if (S.metadata["video"]["codec"].asString() == "H264"){ - len = S.metadata["video"]["init"].asString().length() + 20; + if (video["codec"].asString() == "H264"){ + len = video["init"].asString().length() + 20; } if (len > 0){ if ( !checkBufferSize()){ return false; } - memcpy(data + 16, S.metadata["video"]["init"].asString().c_str(), len - 20); + memcpy(data + 16, video["init"].asString().c_str(), len - 20); data[12] = 0; //H264 sequence header data[13] = 0; data[14] = 0; @@ -534,28 +538,32 @@ bool FLV::Tag::DTSCVideoInit(DTSC::Stream & S){ /// Takes the DTSC Audio init data and makes it into FLV. /// Assumes init data is available - so check before calling! bool FLV::Tag::DTSCAudioInit(DTSC::Stream & S){ + return DTSCAudioInit(S.metadata["audio"]); +} + +bool FLV::Tag::DTSCAudioInit(JSON::Value & audio){ len = 0; //Unknown? Assume AAC. - if (S.metadata["audio"]["codec"].asString() == "?"){ - S.metadata["audio"]["codec"] = "AAC"; + if (audio["codec"].asString() == "?"){ + audio["codec"] = "AAC"; } - if (S.metadata["audio"]["codec"].asString() == "AAC"){ - len = S.metadata["audio"]["init"].asString().length() + 17; + if (audio["codec"].asString() == "AAC"){ + len = audio["init"].asString().length() + 17; } if (len > 0){ if ( !checkBufferSize()){ return false; } - memcpy(data + 13, S.metadata["audio"]["init"].asString().c_str(), len - 17); + memcpy(data + 13, audio["init"].asString().c_str(), len - 17); data[12] = 0; //AAC sequence header data[11] = 0; - if (S.metadata["audio"]["codec"].asString() == "AAC"){ + if (audio["codec"].asString() == "AAC"){ data[11] += 0xA0; } - if (S.metadata["audio"]["codec"].asString() == "MP3"){ + if (audio["codec"].asString() == "MP3"){ data[11] += 0x20; } - unsigned int datarate = S.metadata["audio"]["rate"].asInt(); + unsigned int datarate = audio["rate"].asInt(); if (datarate >= 44100){ data[11] += 0x0C; }else if (datarate >= 22050){ @@ -563,11 +571,12 @@ bool FLV::Tag::DTSCAudioInit(DTSC::Stream & S){ }else if (datarate >= 11025){ data[11] += 0x04; } - if (S.metadata["audio"]["size"].asInt() == 16){ + if (audio["size"].asInt() == 16){ data[11] += 0x02; } - if (S.metadata["audio"]["channels"].asInt() > 1){ + if (audio["channels"].asInt() > 1){ data[11] += 0x01; + } } setLen(); @@ -585,14 +594,16 @@ bool FLV::Tag::DTSCAudioInit(DTSC::Stream & S){ /// FLV metadata loader function from DTSC. /// Takes the DTSC metadata and makes it into FLV. /// Assumes metadata is available - so check before calling! -bool FLV::Tag::DTSCMetaInit(DTSC::Stream & S){ +bool FLV::Tag::DTSCMetaInit(DTSC::Stream & S, std::string vidName, std::string audName){ + JSON::Value & videoRef = S.metadata["tracks"][vidName]; + JSON::Value & audioRef = S.metadata["tracks"][audName]; //Unknown? Assume AAC. - if (S.metadata.isMember("audio") && S.metadata["audio"]["codec"].asString() == "?"){ - S.metadata["audio"]["codec"] = "AAC"; + if (audioRef["codec"].asString() == "?"){ + audioRef["codec"] = "AAC"; } //Unknown? Assume H264. - if (S.metadata.isMember("video") && S.metadata["video"]["codec"].asString() == "?"){ - S.metadata["video"]["codec"] = "H264"; + if (videoRef["codec"].asString() == "?"){ + videoRef["codec"] = "H264"; } AMF::Object amfdata("root", AMF::AMF0_DDV_CONTAINER); @@ -606,11 +617,11 @@ bool FLV::Tag::DTSCMetaInit(DTSC::Stream & S){ keys.addContent(AMF::Object("filepositions", AMF::AMF0_STRICT_ARRAY)); keys.addContent(AMF::Object("times", AMF::AMF0_STRICT_ARRAY)); int total_byterate = 0; - if (S.metadata.isMember("video")){ - total_byterate += S.metadata["video"]["bps"].asInt(); + if (vidName != ""){ + total_byterate += videoRef["bps"].asInt(); } - if (S.metadata.isMember("audio")){ - total_byterate += S.metadata["audio"]["bps"].asInt(); + if (audName != ""){ + total_byterate += audioRef["bps"].asInt(); } for (int i = 0; i < S.metadata["length"].asInt(); ++i){ //for each second in the file keys.getContentP(0)->addContent(AMF::Object("", i * total_byterate, AMF::AMF0_NUMBER)); //multiply by byterate for fake byte positions @@ -618,81 +629,81 @@ bool FLV::Tag::DTSCMetaInit(DTSC::Stream & S){ } amfdata.getContentP(1)->addContent(keys); } - if (S.metadata.isMember("video")){ + if (vidName != ""){ amfdata.getContentP(1)->addContent(AMF::Object("hasVideo", 1, AMF::AMF0_BOOL)); - if (S.metadata["video"]["codec"].asString() == "H264"){ + if (videoRef["codec"].asString() == "H264"){ amfdata.getContentP(1)->addContent(AMF::Object("videocodecid", (std::string)"avc1")); } - if (S.metadata["video"]["codec"].asString() == "VP6"){ + if (videoRef["codec"].asString() == "VP6"){ amfdata.getContentP(1)->addContent(AMF::Object("videocodecid", 4, AMF::AMF0_NUMBER)); } - if (S.metadata["video"]["codec"].asString() == "H263"){ + if (videoRef["codec"].asString() == "H263"){ amfdata.getContentP(1)->addContent(AMF::Object("videocodecid", 2, AMF::AMF0_NUMBER)); } - if (S.metadata["video"].isMember("width")){ - amfdata.getContentP(1)->addContent(AMF::Object("width", S.metadata["video"]["width"].asInt(), AMF::AMF0_NUMBER)); + if (videoRef.isMember("width")){ + amfdata.getContentP(1)->addContent(AMF::Object("width", videoRef["width"].asInt(), AMF::AMF0_NUMBER)); } - if (S.metadata["video"].isMember("height")){ - amfdata.getContentP(1)->addContent(AMF::Object("height", S.metadata["video"]["height"].asInt(), AMF::AMF0_NUMBER)); + if (videoRef.isMember("height")){ + amfdata.getContentP(1)->addContent(AMF::Object("height", videoRef["height"].asInt(), AMF::AMF0_NUMBER)); } - if (S.metadata["video"].isMember("fpks")){ - amfdata.getContentP(1)->addContent(AMF::Object("videoframerate", (double)S.metadata["video"]["fpks"].asInt() / 1000.0, AMF::AMF0_NUMBER)); + if (videoRef.isMember("fpks")){ + amfdata.getContentP(1)->addContent(AMF::Object("videoframerate", (double)videoRef["fpks"].asInt() / 1000.0, AMF::AMF0_NUMBER)); } - if (S.metadata["video"].isMember("bps")){ - amfdata.getContentP(1)->addContent(AMF::Object("videodatarate", (double)S.metadata["video"]["bps"].asInt() * 128.0, AMF::AMF0_NUMBER)); + if (videoRef.isMember("bps")){ + amfdata.getContentP(1)->addContent(AMF::Object("videodatarate", (double)videoRef["bps"].asInt() * 128.0, AMF::AMF0_NUMBER)); } } - if (S.metadata.isMember("audio")){ + if (audName != ""){ amfdata.getContentP(1)->addContent(AMF::Object("hasAudio", 1, AMF::AMF0_BOOL)); amfdata.getContentP(1)->addContent(AMF::Object("audiodelay", 0, AMF::AMF0_NUMBER)); - if (S.metadata["audio"]["codec"].asString() == "AAC"){ + if (audioRef["codec"].asString() == "AAC"){ amfdata.getContentP(1)->addContent(AMF::Object("audiocodecid", (std::string)"mp4a")); } - if (S.metadata["audio"]["codec"].asString() == "MP3"){ + if (audioRef["codec"].asString() == "MP3"){ amfdata.getContentP(1)->addContent(AMF::Object("audiocodecid", (std::string)"mp3")); } - if (S.metadata["audio"].isMember("channels")){ - amfdata.getContentP(1)->addContent(AMF::Object("audiochannels", S.metadata["audio"]["channels"].asInt(), AMF::AMF0_NUMBER)); + if (audioRef.isMember("channels")){ + amfdata.getContentP(1)->addContent(AMF::Object("audiochannels", audioRef["channels"].asInt(), AMF::AMF0_NUMBER)); } - if (S.metadata["audio"].isMember("rate")){ - amfdata.getContentP(1)->addContent(AMF::Object("audiosamplerate", S.metadata["audio"]["rate"].asInt(), AMF::AMF0_NUMBER)); + if (audioRef.isMember("rate")){ + amfdata.getContentP(1)->addContent(AMF::Object("audiosamplerate", audioRef["rate"].asInt(), AMF::AMF0_NUMBER)); } - if (S.metadata["audio"].isMember("size")){ - amfdata.getContentP(1)->addContent(AMF::Object("audiosamplesize", S.metadata["audio"]["size"].asInt(), AMF::AMF0_NUMBER)); + if (audioRef.isMember("size")){ + amfdata.getContentP(1)->addContent(AMF::Object("audiosamplesize", audioRef["size"].asInt(), AMF::AMF0_NUMBER)); } - if (S.metadata["audio"].isMember("bps")){ - amfdata.getContentP(1)->addContent(AMF::Object("audiodatarate", (double)S.metadata["audio"]["bps"].asInt() * 128.0, AMF::AMF0_NUMBER)); + if (audioRef.isMember("bps")){ + amfdata.getContentP(1)->addContent(AMF::Object("audiodatarate", (double)audioRef["bps"].asInt() * 128.0, AMF::AMF0_NUMBER)); } } AMF::Object trinfo = AMF::Object("trackinfo", AMF::AMF0_STRICT_ARRAY); int i = 0; - if (S.metadata.isMember("audio")){ + if (audName != ""){ trinfo.addContent(AMF::Object("", AMF::AMF0_OBJECT)); trinfo.getContentP(i)->addContent( - AMF::Object("length", ((double)S.metadata["length"].asInt()) * ((double)S.metadata["audio"]["rate"].asInt()), AMF::AMF0_NUMBER)); - trinfo.getContentP(i)->addContent(AMF::Object("timescale", S.metadata["audio"]["rate"].asInt(), AMF::AMF0_NUMBER)); + AMF::Object("length", ((double)S.metadata["length"].asInt()) * ((double)audioRef["rate"].asInt()), AMF::AMF0_NUMBER)); + trinfo.getContentP(i)->addContent(AMF::Object("timescale", audioRef["rate"].asInt(), AMF::AMF0_NUMBER)); trinfo.getContentP(i)->addContent(AMF::Object("sampledescription", AMF::AMF0_STRICT_ARRAY)); - if (S.metadata["audio"]["codec"].asString() == "AAC"){ + if (audioRef["codec"].asString() == "AAC"){ trinfo.getContentP(i)->getContentP(2)->addContent(AMF::Object("sampletype", (std::string)"mp4a")); } - if (S.metadata["audio"]["codec"].asString() == "MP3"){ + if (audioRef["codec"].asString() == "MP3"){ trinfo.getContentP(i)->getContentP(2)->addContent(AMF::Object("sampletype", (std::string)"mp3")); } ++i; } - if (S.metadata.isMember("video")){ + if (vidName != ""){ trinfo.addContent(AMF::Object("", AMF::AMF0_OBJECT)); trinfo.getContentP(i)->addContent( - AMF::Object("length", ((double)S.metadata["length"].asInt()) * ((double)S.metadata["video"]["fkps"].asInt() / 1000.0), AMF::AMF0_NUMBER)); - trinfo.getContentP(i)->addContent(AMF::Object("timescale", ((double)S.metadata["video"]["fkps"].asInt() / 1000.0), AMF::AMF0_NUMBER)); + AMF::Object("length", ((double)S.metadata["length"].asInt()) * ((double)videoRef["fkps"].asInt() / 1000.0), AMF::AMF0_NUMBER)); + trinfo.getContentP(i)->addContent(AMF::Object("timescale", ((double)videoRef["fkps"].asInt() / 1000.0), AMF::AMF0_NUMBER)); trinfo.getContentP(i)->addContent(AMF::Object("sampledescription", AMF::AMF0_STRICT_ARRAY)); - if (S.metadata["video"]["codec"].asString() == "H264"){ + if (videoRef["codec"].asString() == "H264"){ trinfo.getContentP(i)->getContentP(2)->addContent(AMF::Object("sampletype", (std::string)"avc1")); } - if (S.metadata["video"]["codec"].asString() == "VP6"){ + if (videoRef["codec"].asString() == "VP6"){ trinfo.getContentP(i)->getContentP(2)->addContent(AMF::Object("sampletype", (std::string)"vp6")); } - if (S.metadata["video"]["codec"].asString() == "H263"){ + if (videoRef["codec"].asString() == "H263"){ trinfo.getContentP(i)->getContentP(2)->addContent(AMF::Object("sampletype", (std::string)"h263")); } ++i; diff --git a/lib/flv_tag.h b/lib/flv_tag.h index 5959982c..5433068a 100644 --- a/lib/flv_tag.h +++ b/lib/flv_tag.h @@ -46,8 +46,10 @@ namespace FLV { bool ChunkLoader(const RTMPStream::Chunk& O); bool DTSCLoader(DTSC::Stream & S); bool DTSCVideoInit(DTSC::Stream & S); + bool DTSCVideoInit(JSON::Value & video); bool DTSCAudioInit(DTSC::Stream & S); - bool DTSCMetaInit(DTSC::Stream & S); + bool DTSCAudioInit(JSON::Value & audio); + bool DTSCMetaInit(DTSC::Stream & S, std::string vidName = "", std::string audName = ""); JSON::Value toJSON(JSON::Value & metadata); bool MemLoader(char * D, unsigned int S, unsigned int & P); bool FileLoader(FILE * f);