From 78ce2c4180cf34f9be93b2b31096ac961ff1de19 Mon Sep 17 00:00:00 2001 From: Erik Zandvliet Date: Thu, 19 Dec 2013 14:25:05 +0100 Subject: [PATCH] Assorted Fixes --- src/buffer/player.cpp | 22 ++-- src/connectors/conn_http.cpp | 1 - src/connectors/conn_http_smooth.cpp | 154 +++++++++++++++++----------- src/converters/dtscmerge.cpp | 62 ++++++----- 4 files changed, 137 insertions(+), 102 deletions(-) diff --git a/src/buffer/player.cpp b/src/buffer/player.cpp index 17117e5c..2f61f9f2 100644 --- a/src/buffer/player.cpp +++ b/src/buffer/player.cpp @@ -71,12 +71,22 @@ class Stats{ } }; +std::string intToBin(long long int number){ + std::string result; + result.resize(8); + for (int i = 7; i >= 0; i--){ + result[i] = number & 0xFF; + number >>= 8; + } + return result; +} + int main(int argc, char** argv){ Util::Config conf(argv[0], PACKAGE_VERSION); conf.addOption("filename", - JSON::fromString("{\"arg_num\":1, \"help\":\"Name of the file to write to stdout.\"}")); + JSON::fromString("{\"arg_num\":1, \"help\":\"Name of the file to write to stdout.\"}")); conf.addOption("streamname", - JSON::fromString("{\"arg\":\"string\",\"short\":\"s\",\"long\":\"stream\",\"help\":\"The name of the stream that this connector will transmit.\"}")); + JSON::fromString("{\"arg\":\"string\",\"short\":\"s\",\"long\":\"stream\",\"help\":\"The name of the stream that this connector will transmit.\"}")); conf.parseArgs(argc, argv); conf.activate(); int playing = 0; @@ -90,6 +100,7 @@ int main(int argc, char** argv){ return 1; } + std::string streamname = conf.getString("streamname"); source.getMeta().send(in_out); JSON::Value pausemark; @@ -248,11 +259,8 @@ int main(int argc, char** argv){ }else{ lasttime = Util::epoch(); //insert proper header for this type of data - in_out.Send("DTP2"); - //insert the packet length - unsigned int size = htonl( source.getPacket().size()); - in_out.Send((char*) &size, 4); - in_out.SendNow(source.getPacket()); + JSON::Value toSend = source.getJSON(); + toSend.sendTo(in_out); } }else{ Util::sleep(10); diff --git a/src/connectors/conn_http.cpp b/src/connectors/conn_http.cpp index dd590f77..af67976c 100644 --- a/src/connectors/conn_http.cpp +++ b/src/connectors/conn_http.cpp @@ -91,7 +91,6 @@ namespace Connector_HTTP { } } } - connMutex.unlock(); } usleep(1000000); //sleep 1 second and re-check } diff --git a/src/connectors/conn_http_smooth.cpp b/src/connectors/conn_http_smooth.cpp index 1e9d25a2..f3e08109 100644 --- a/src/connectors/conn_http_smooth.cpp +++ b/src/connectors/conn_http_smooth.cpp @@ -25,6 +25,36 @@ #include #include +long long int binToInt(std::string & binary){ + long long int result = 0; + for ( int i = 0; i < 8; i++){ + result <<= 8; + result += binary[i]; + } + return result; +} + +std::string intToBin(long long int number){ + std::string result; + result.resize(8); + for( int i = 7; i >= 0; i--){ + result[i] = number & 0xFF; + number >>= 8; + } + return result; +} + +std::string toUTF16(std::string original){ + std::string result; + result += (char)0xFF; + result += (char)0xFE; + for (std::string::iterator it = original.begin(); it != original.end(); it++){ + result += (*it); + result += (char)0x00; + } + return result; +} + ///\brief Holds everything unique to HTTP Connectors. namespace Connector_HTTP { ///\brief Builds an index file for HTTP Smooth streaming. @@ -32,23 +62,23 @@ namespace Connector_HTTP { ///\return The index file for HTTP Smooth Streaming. std::string smoothIndex(DTSC::Meta & metadata){ std::stringstream Result; - Result << "\n"; + Result << "\n"; Result << " allAudio; - std::map allVideo; + std::deque::iterator> audioIters; + std::deque::iterator> videoIters; long long int maxWidth = 0; long long int maxHeight = 0; long long int minWidth = 99999999; long long int minHeight = 99999999; for (std::map::iterator it = metadata.tracks.begin(); it != metadata.tracks.end(); it++){ - if (it->second.type == "audio" && it->second.codec == "AAC"){ - allAudio.insert(*it); + if (it->second.codec == "AAC"){ + audioIters.push_back(it); } if (it->second.type == "video" && it->second.codec == "H264"){ - allVideo.insert(*it); + videoIters.push_back(it); if (it->second.width > maxWidth){maxWidth = it->second.width;} if (it->second.width < minWidth){minWidth = it->second.width;} if (it->second.height > maxHeight){maxHeight = it->second.height;} @@ -56,7 +86,7 @@ namespace Connector_HTTP { } } if (metadata.vod){ - Result << "Duration=\"" << metadata.tracks[allVideo.begin()->first].lastms << "0000\""; + Result << "Duration=\"" << (*videoIters.begin())->second.lastms << "0000\""; }else{ Result << "Duration=\"0\" " "IsLive=\"TRUE\" " @@ -68,85 +98,89 @@ namespace Connector_HTTP { Result << ">\n"; //Add audio entries - if (allAudio.size()){ + if (audioIters.size()){ Result << "second.keys.size() << "\" " + "Chunks=\"" << (*audioIters.begin())->second.keys.size() << "\" " "Url=\"Q({bitrate},{CustomAttributes})/A({start time})\">\n"; int index = 0; - for (std::map::iterator it = allAudio.begin(); it != allAudio.end(); it++){ + for (std::deque::iterator>::iterator it = audioIters.begin(); it != audioIters.end(); it++){ Result << "second.bps * 8 << "\" " + "Bitrate=\"" << (*it)->second.bps * 8 << "\" " "CodecPrivateData=\"" << std::hex; - for (int i = 0; i < it->second.init.size(); i++){ - Result << std::setfill('0') << std::setw(2) << std::right << (int)it->second.init[i]; + for (int i = 0; i < (*it)->second.init.size(); i++){ + Result << std::setfill('0') << std::setw(2) << std::right << (int)(*it)->second.init[i]; } Result << std::dec << "\" " - "SamplingRate=\"" << it->second.rate << "\" " + "SamplingRate=\"" << (*it)->second.rate << "\" " "Channels=\"2\" " "BitsPerSample=\"16\" " "PacketSize=\"4\" " "AudioTag=\"255\" " "FourCC=\"AACL\" >\n"; Result << "\n" - "first << "\" />" + "first << "\" />" ""; Result << "\n"; index++; } - for (std::deque::iterator it = allAudio.begin()->second.keys.begin(); it != ((allAudio.begin()->second.keys.end()) - 1); it++){ - Result << "second.keys.begin()){ - Result << "t=\"" << it->getTime() * 10000 << "\" "; + if ((*audioIters.begin())->second.keys.size()){ + for (std::deque::iterator it = (*audioIters.begin())->second.keys.begin(); it != (((*audioIters.begin())->second.keys.end()) - 1); it++){ + Result << "second.keys.begin()){ + Result << "t=\"" << it->getTime() * 10000 << "\" "; + } + Result << "d=\"" << it->getLength() * 10000 << "\" />\n"; } - Result << "d=\"" << it->getLength() * 10000 << "\" />\n"; } Result << "\n"; } //Add video entries - if (allVideo.size()){ + if (videoIters.size()){ Result << "second.keys.size() << "\" " + "Chunks=\"" << (*videoIters.begin())->second.keys.size() << "\" " "Url=\"Q({bitrate},{CustomAttributes})/V({start time})\" " "MaxWidth=\"" << maxWidth << "\" " "MaxHeight=\"" << maxHeight << "\" " "DisplayWidth=\"" << maxWidth << "\" " "DisplayHeight=\"" << maxHeight << "\">\n"; int index = 0; - for (std::map::iterator it = allVideo.begin(); it != allVideo.end(); it++){ + for (std::deque::iterator>::iterator it = videoIters.begin(); it != videoIters.end(); it++){ //Add video qualities Result << "second.bps * 8 << "\" " + "Bitrate=\"" << (*it)->second.bps * 8 << "\" " "CodecPrivateData=\"" << std::hex; MP4::AVCC avccbox; - avccbox.setPayload(it->second.init); + avccbox.setPayload((*it)->second.init); std::string tmpString = avccbox.asAnnexB(); for (int i = 0; i < tmpString.size(); i++){ Result << std::setfill('0') << std::setw(2) << std::right << (int)tmpString[i]; } Result << std::dec << "\" " - "MaxWidth=\"" << it->second.width << "\" " - "MaxHeight=\"" << it->second.height << "\" " + "MaxWidth=\"" << (*it)->second.width << "\" " + "MaxHeight=\"" << (*it)->second.height << "\" " "FourCC=\"AVC1\" >\n"; Result << "\n" - "first << "\" />" + "first << "\" />" ""; Result << "\n"; index++; } - for (std::deque::iterator it = allVideo.begin()->second.keys.begin(); it != ((allVideo.begin()->second.keys.end()) - 1); it++){ - Result << "second.keys.begin()){ - Result << "t=\"" << it->getTime() * 10000 << "\" "; + if ((*videoIters.begin())->second.keys.size()){ + for (std::deque::iterator it = (*videoIters.begin())->second.keys.begin(); it != (((*videoIters.begin())->second.keys.end()) - 1); it++){ + Result << "second.keys.begin()){ + Result << "t=\"" << it->getTime() * 10000 << "\" "; + } + Result << "d=\"" << it->getLength() * 10000 << "\" />\n"; } - Result << "d=\"" << it->getLength() * 10000 << "\" />\n"; } Result << "\n"; } @@ -155,7 +189,7 @@ namespace Connector_HTTP { #if DEBUG >= 8 std::cerr << "Sending this manifest:" << std::endl << Result << std::endl; #endif - return Result.str(); + return toUTF16(Result.str()); } //smoothIndex ///\brief Main function for the HTTP Smooth Connector @@ -183,9 +217,6 @@ namespace Connector_HTTP { unsigned int lastStats = 0;//Indicates the last time that we have sent stats to the server socket. conn.setBlocking(false);//Set the client socket to non-blocking - std::map allAudio; - std::map allVideo; - while (conn.connected()){ if ( !handlingRequest){ if (conn.spool() || conn.Received().size()){ @@ -209,18 +240,9 @@ namespace Connector_HTTP { ready4data = false; continue; } - ready4data = true; ss.setBlocking(false); Strm.waitForMeta(ss); - for (std::map::iterator it = Strm.metadata.tracks.begin(); it != Strm.metadata.tracks.end(); it++){ - if (it->second.type == "audio" && it->second.codec == "AAC"){ - allAudio[it->first] = it->second; - } - if (it->second.type == "video" && it->second.codec == "H264"){ - allVideo[it->first] = it->second; - } - } - }; + } if (HTTP_R.url.find(".xap") != std::string::npos){ @@ -317,12 +339,15 @@ namespace Connector_HTTP { //Obtain the corresponding track; DTSC::Track trackRef; - if (wantsVideo){ - trackRef = allVideo.begin()->second; - } - if (wantsAudio){ - trackRef = allAudio.begin()->second; + for (std::map::iterator it = Strm.metadata.tracks.begin(); it != Strm.metadata.tracks.end(); it++){ + if (wantsVideo && it->second.codec == "H264"){ + trackRef = it->second; + } + if (wantsAudio && it->second.codec == "AAC"){ + trackRef = it->second; + } } + static long long int seqNum = 1; //Also obtain the associated keyframe; DTSC::Key keyObj; int partOffset = 0; @@ -355,29 +380,35 @@ namespace Connector_HTTP { //Wrap everything in mp4 boxes MP4::MFHD mfhd_box; - mfhd_box.setSequenceNumber(keyObj.getNumber()); + mfhd_box.setSequenceNumber(((keyObj.getNumber() - 1) * 2) + myRef.trackID); myDuration = keyObj.getLength() * 10000; MP4::TFHD tfhd_box; tfhd_box.setFlags(MP4::tfhdSampleFlag); - tfhd_box.setTrackID(1); - tfhd_box.setDefaultSampleFlags(0x000000C0 | MP4::noIPicture | MP4::noDisposable | MP4::noKeySample); + tfhd_box.setTrackID(myRef.trackID); + if (trackRef.type == "video"){ + tfhd_box.setDefaultSampleFlags(0x00004001); + }else{ + tfhd_box.setDefaultSampleFlags(0x00008002); + } MP4::TRUN trun_box; trun_box.setDataOffset(42); unsigned int keySize = 0; if (trackRef.type == "video"){ - trun_box.setFlags(MP4::trundataOffset | MP4::trunfirstSampleFlags | MP4::trunsampleDuration | MP4::trunsampleSize); + trun_box.setFlags(MP4::trundataOffset | MP4::trunfirstSampleFlags | MP4::trunsampleDuration | MP4::trunsampleSize | MP4::trunsampleOffsets); }else{ trun_box.setFlags(MP4::trundataOffset | MP4::trunsampleDuration | MP4::trunsampleSize); } - trun_box.setFirstSampleFlags(0x00000040 | MP4::noKeySample); - //trun_box.setFirstSampleFlags(0x00000040 | MP4::isIPicture | MP4::noDisposable | MP4::isKeySample); + trun_box.setFirstSampleFlags(0x00004002); for (int i = 0; i < keyObj.getParts(); i++){ MP4::trunSampleInformation trunSample; trunSample.sampleSize = Strm.metadata.tracks[myRef.trackID].parts[i + partOffset].getSize(); keySize += Strm.metadata.tracks[myRef.trackID].parts[i + partOffset].getSize(); trunSample.sampleDuration = Strm.metadata.tracks[myRef.trackID].parts[i + partOffset].getDuration() * 10000; + if (trackRef.type == "video"){ + trunSample.sampleOffset = Strm.metadata.tracks[myRef.trackID].parts[i + partOffset].getOffset() * 10000; + } trun_box.setSampleInformation(trunSample, i); } @@ -419,7 +450,6 @@ namespace Connector_HTTP { MP4::MOOF moof_box; moof_box.setContent(mfhd_box, 0); moof_box.setContent(traf_box, 1); - //Setting the correct offsets. trun_box.setDataOffset(moof_box.boxedSize() + 8); traf_box.setContent(trun_box, 1); @@ -427,6 +457,8 @@ namespace Connector_HTTP { HTTP_S.Clean(); HTTP_S.SetHeader("Content-Type", "video/mp4"); + HTTP_S.SetHeader("Pragma", "IISMS/5.0,IIS Media Services Premium by Microsoft"); + HTTP_S.SetHeader("ETag", "3b517e5a0586303"); HTTP_S.StartResponse(HTTP_R, conn); HTTP_S.Chunkify(moof_box.asBox(), moof_box.boxedSize(), conn); int size = htonl(keySize + 8); diff --git a/src/converters/dtscmerge.cpp b/src/converters/dtscmerge.cpp index 218b1c51..0bf4dd44 100644 --- a/src/converters/dtscmerge.cpp +++ b/src/converters/dtscmerge.cpp @@ -44,7 +44,7 @@ namespace Converters { DTSC::File outFile; JSON::Value meta; - JSON::Value newMeta; + DTSC::Meta newMeta; std::map > trackMapping; bool fullSort = true; @@ -74,11 +74,12 @@ namespace Converters { return 1; } meta = outFile.getMeta().toJSON(); - newMeta = meta; + newMeta = DTSC::Meta(meta); if (meta.isMember("tracks") && meta["tracks"].size() > 0){ for (JSON::ObjIter trackIt = meta["tracks"].ObjBegin(); trackIt != meta["tracks"].ObjEnd(); trackIt++){ - trackMapping[argv[1]].insert(std::pair(trackIt->second["trackid"].asInt(),getNextFree(trackMapping))); - newMeta["tracks"][trackIt->first]["trackid"] = trackMapping[argv[1]][trackIt->second["trackid"].asInt()]; + int nxtMap = getNextFree(trackMapping); + trackMapping[argv[1]].insert(std::pair(trackIt->second["trackid"].asInt(),nxtMap)); + newMeta.tracks[nxtMap].trackID = nxtMap; } } } @@ -86,36 +87,31 @@ namespace Converters { std::multimap allSorted; for (std::map::iterator it = inFiles.begin(); it != inFiles.end(); it++){ - JSON::Value tmpMeta = it->second.getMeta().toJSON(); - if (tmpMeta.isMember("tracks") && tmpMeta["tracks"].size() > 0){ - for (JSON::ObjIter trackIt = tmpMeta["tracks"].ObjBegin(); trackIt != tmpMeta["tracks"].ObjEnd(); trackIt++){ - long long int oldID = trackIt->second["trackid"].asInt(); - long long int mappedID = getNextFree(trackMapping); - trackMapping[it->first].insert(std::pair(oldID,mappedID)); - for (JSON::ArrIter keyIt = trackIt->second["keys"].ArrBegin(); keyIt != trackIt->second["keys"].ArrEnd(); keyIt++){ - keyframeInfo tmpInfo; - tmpInfo.fileName = it->first; - tmpInfo.trackID = oldID; - tmpInfo.keyTime = (*keyIt)["time"].asInt(); - tmpInfo.keyBPos = (*keyIt)["bpos"].asInt(); - tmpInfo.keyNum = (*keyIt)["num"].asInt(); - tmpInfo.keyLen = (*keyIt)["len"].asInt(); - if ((keyIt + 1) != trackIt->second["keys"].ArrEnd()){ - tmpInfo.endBPos = (*(keyIt + 1))["bpos"].asInt(); - }else{ - tmpInfo.endBPos = it->second.getBytePosEOF(); - } - allSorted.insert(std::pair((*keyIt)["time"].asInt(),tmpInfo)); + DTSC::Meta tmpMeta = it->second.getMeta(); + for (std::map::iterator trackIt = tmpMeta.tracks.begin(); trackIt != tmpMeta.tracks.end(); trackIt++){ + long long int oldID = trackIt->first; + long long int mappedID = getNextFree(trackMapping); + trackMapping[it->first].insert(std::pair(oldID,mappedID)); + for (std::deque::iterator keyIt = trackIt->second.keys.begin(); keyIt != trackIt->second.keys.end(); keyIt++){ + keyframeInfo tmpInfo; + tmpInfo.fileName = it->first; + tmpInfo.trackID = oldID; + tmpInfo.keyTime = keyIt->getTime(); + tmpInfo.keyBPos = keyIt->getBpos(); + tmpInfo.keyNum = keyIt->getNumber(); + tmpInfo.keyLen = keyIt->getLength(); + if ((keyIt + 1) != trackIt->second.keys.end()){ + tmpInfo.endBPos = (keyIt + 1)->getBpos(); + }else{ + tmpInfo.endBPos = it->second.getBytePosEOF(); } - std::cerr << it->first << "::" << oldID << ":\n" << trackIt->second.toPrettyString() << std::endl << std::endl; - newMeta["tracks"][it->first + JSON::Value(mappedID).asString()] = trackIt->second; - newMeta["tracks"][it->first + JSON::Value(mappedID).asString()]["trackid"] = mappedID; - newMeta["tracks"][it->first + JSON::Value(mappedID).asString()].removeMember("keys"); - newMeta["tracks"][it->first + JSON::Value(mappedID).asString()].removeMember("frags"); + allSorted.insert(std::pair(keyIt->getTime(),tmpInfo)); } + newMeta.tracks[mappedID] = trackIt->second; + newMeta.tracks[mappedID].trackID = mappedID; + newMeta.tracks[mappedID].reset(); } } - newMeta["allsortedsize"] = (long long int)allSorted.size(); if (fullSort){ meta.null(); @@ -141,11 +137,11 @@ namespace Converters { } if (fullSort || (meta.isMember("merged") && meta["merged"])){ - newMeta["merged"] = true; + newMeta.merged = 1; }else{ - newMeta.removeMember("merged"); + newMeta.merged = 0; } - std::string writeMeta = newMeta.toPacked(); + std::string writeMeta = newMeta.toJSON().toPacked(); meta["moreheader"] = outFile.addHeader(writeMeta); writeMeta = meta.toPacked(); outFile.writeHeader(writeMeta);