#include "dtsc.h" namespace DTSC { long Part::getSize(){ return ((long)data[0] << 16) | ((long)data[1] << 8) | data[2]; } void Part::setSize(long newSize){ data[0] = (newSize & 0xFF0000) >> 16; data[1] = (newSize & 0x00FF00) >> 8; data[2] = (newSize & 0x0000FF); } short Part::getDuration(){ return ntohs(((short*)(data+3))[0]); } void Part::setDuration(short newDuration){ ((short*)(data+3))[0] = htons(newDuration); } long Part::getOffset(){ return ntohl(((int*)(data+5))[0]); } void Part::setOffset(long newOffset){ ((int*)(data+5))[0] = htonl(newOffset); } char* Part::getData(){ return data; } long long unsigned int Key::getBpos(){ return (((long long unsigned int)data[0] << 32) | (data[1] << 24) | (data[2] << 16) | (data[3] << 8) | data[4]); } void Key::setBpos(long long unsigned int newBpos){ data[4] = newBpos & 0xFF; data[3] = (newBpos >> 8) & 0xFF; data[2] = (newBpos >> 16) & 0xFF; data[1] = (newBpos >> 24) & 0xFF; data[0] = (newBpos >> 32) & 0xFF; } long Key::getLength(){ return ((data[5] << 16) | (data[6] << 8) | data[7]); } void Key::setLength(long newLength){ data[7] = newLength & 0xFF; data[6] = (newLength >> 8) & 0xFF; data[5] = (newLength >> 16) & 0xFF; } short Key::getNumber(){ return ntohs(((short*)(data+8))[0]); } void Key::setNumber(short newNumber){ ((short*)(data+8))[0] = htons(newNumber); } short Key::getParts(){ return ntohs(((short*)(data+10))[0]); } void Key::setParts(short newParts){ ((short*)(data+10))[0] = htons(newParts); } long Key::getTime(){ return ntohl(((int*)(data+12))[0]); } void Key::setTime(long newTime){ ((int*)(data+12))[0] = htonl(newTime); } char* Key::getData(){ return data; } long Fragment::getDuration(){ return ntohl(((int*)data)[0]); } void Fragment::setDuration(long newDuration){ ((int*)data)[0] = htonl(newDuration); } char Fragment::getLength(){ return data[4]; } void Fragment::setLength(char newLength){ data[4] = newLength; } short Fragment::getNumber(){ return ntohs(((short*)(data+5))[0]); } void Fragment::setNumber(short newNumber){ ((short*)(data+5))[0] = htons(newNumber); } long Fragment::getSize(){ return ntohl(((int*)(data+7))[0]); } void Fragment::setSize(long newSize){ ((int*)(data+7))[0] = htonl(newSize); } char* Fragment::getData(){ return data; } readOnlyTrack::readOnlyTrack(){ fragments = NULL; fragLen = 0; keys = NULL; keyLen = 0; parts = NULL; partLen = 0; missedFrags = 0; } readOnlyTrack::readOnlyTrack(JSON::Value & trackRef){ if (trackRef.isMember("fragments")){ fragments = (Fragment*)trackRef["fragments"].asString().data(); fragLen = trackRef["fragments"].asString().size() / 11; }else{ fragments = 0; fragLen = 0; } if (trackRef.isMember("keys")){ keys = (Key*)trackRef["keys"].asString().data(); keyLen = trackRef["keys"].asString().size() / 16; }else{ keys = 0; keyLen = 0; } if (trackRef.isMember("parts")){ parts = (Part*)trackRef["parts"].asString().data(); partLen = trackRef["parts"].asString().size() / 9; }else{ parts = 0; partLen = 0; } trackID = trackRef["trackid"].asInt(); length = trackRef["length"].asInt(); firstms = trackRef["firstms"].asInt(); lastms = trackRef["lastms"].asInt(); bps = trackRef["bps"].asInt(); missedFrags = trackRef["missed_fags"].asInt(); codec = trackRef["codec"].asString(); type = trackRef["type"].asString(); init = trackRef["init"].asString(); if (type == "audio"){ rate = trackRef["rate"].asInt(); size = trackRef["size"].asInt(); channels = trackRef["channels"].asInt(); } if (type == "video"){ width = trackRef["width"].asInt(); height = trackRef["height"].asInt(); fpks = trackRef["fpks"].asInt(); } if (codec == "vorbis" || codec == "theora"){ idHeader = trackRef["idheader"].asString(); commentHeader = trackRef["commentheader"].asString(); } } Track::Track(){} Track::Track(const readOnlyTrack & rhs){ trackID = rhs.trackID; length = rhs.length; firstms = rhs.firstms; lastms = rhs.lastms; bps = rhs.bps; missedFrags = rhs.missedFrags; init = rhs.init; codec = rhs.codec; type = rhs.type; rate = rhs.rate; size = rhs.size; channels = rhs.channels; width = rhs.width; height = rhs.height; fpks = rhs.fpks; idHeader = rhs.idHeader; commentHeader = rhs.commentHeader; if (rhs.fragments && rhs.fragLen){ fragments = std::deque(rhs.fragments, rhs.fragments + rhs.fragLen); } if (rhs.keys && rhs.keyLen){ keys = std::deque(rhs.keys, rhs.keys + rhs.keyLen); } if (rhs.parts && rhs.partLen){ parts = std::deque(rhs.parts, rhs.parts + rhs.partLen); } } Track::Track(JSON::Value & trackRef){ if (trackRef.isMember("fragments") && trackRef["fragments"].isString()){ Fragment* tmp = (Fragment*)trackRef["fragments"].asString().data(); fragments = std::deque(tmp,tmp + (trackRef["fragments"].asString().size() / 11)); } if (trackRef.isMember("keys") && trackRef["keys"].isString()){ Key* tmp = (Key*)trackRef["keys"].asString().data(); keys = std::deque(tmp,tmp + (trackRef["keys"].asString().size() / 16)); } if (trackRef.isMember("parts") && trackRef["parts"].isString()){ Part* tmp = (Part*)trackRef["parts"].asString().data(); parts = std::deque(tmp,tmp + (trackRef["parts"].asString().size() / 9)); } trackID = trackRef["trackid"].asInt(); length = trackRef["length"].asInt(); firstms = trackRef["firstms"].asInt(); lastms = trackRef["lastms"].asInt(); bps = trackRef["bps"].asInt(); missedFrags = trackRef["missed_fags"].asInt(); codec = trackRef["codec"].asString(); type = trackRef["type"].asString(); init = trackRef["init"].asString(); if (type == "audio"){ rate = trackRef["rate"].asInt(); size = trackRef["size"].asInt(); channels = trackRef["channels"].asInt(); } if (type == "video"){ width = trackRef["width"].asInt(); height = trackRef["height"].asInt(); fpks = trackRef["fpks"].asInt(); } if (codec == "vorbis" || codec == "theora"){ idHeader = trackRef["idheader"].asString(); commentHeader = trackRef["commentheader"].asString(); } } void Track::update(JSON::Value & pack){ Part newPart; newPart.setSize(pack["data"].asString().size()); newPart.setOffset(pack["offset"].asInt()); if (parts.size()){ parts[parts.size()-1].setDuration(pack["time"].asInt() - lastms); newPart.setDuration(pack["time"].asInt() - lastms); }else{ newPart.setDuration(0); } if (pack["time"].asInt() > firstms){ firstms = pack["time"].asInt(); } parts.push_back(newPart); lastms = pack["time"].asInt(); if (pack.isMember("keyframe") || !keys.size() || (type != "video" && pack["time"].asInt() - 5000 > keys[keys.size() - 1].getTime())){ Key newKey; newKey.setTime(pack["time"].asInt()); newKey.setParts(0); newKey.setLength(pack["time"].asInt()); if (keys.size()){ newKey.setNumber(keys[keys.size() - 1].getNumber() + 1); keys[keys.size() - 1].setLength(pack["time"].asInt() - keys[keys.size() - 1].getLength()); }else{ newKey.setNumber(1); } if (pack.isMember("bpos")){//For VoD newKey.setBpos(pack["bpos"].asInt()); }else{ newKey.setBpos(0); } keys.push_back(newKey); if (!fragments.size() || pack["time"].asInt() - 10000 >= getKey(fragments.rbegin()->getNumber()).getTime()){ //new fragment Fragment newFrag; newFrag.setDuration(0); newFrag.setLength(1); newFrag.setNumber(keys[keys.size() - 1].getNumber()); if (fragments.size()){ fragments[fragments.size() - 1].setDuration(pack["time"].asInt() - fragments[fragments.size() - 1].getDuration()); } newFrag.setDuration(pack["time"].asInt()); newFrag.setSize(0); fragments.push_back(newFrag); }else{ Fragment & lastFrag = fragments[fragments.size() - 1]; lastFrag.setLength(lastFrag.getLength() + 1); } } keys.rbegin()->setParts(keys.rbegin()->getParts() + 1); fragments.rbegin()->setSize(fragments.rbegin()->getSize() + pack["data"].asString().size()); bps += pack["data"].asString().size(); } Key & Track::getKey(int keyNum){ static Key empty; if (keyNum < keys[0].getNumber()){ return empty; } if ((keyNum - keys[0].getNumber()) > keys.size()){ return empty; } return keys[keyNum - keys[0].getNumber()]; } std::string readOnlyTrack::getIdentifier(){ std::stringstream result; if (type == ""){ result << "Metadata_" << trackID; return result.str(); } result << type << "_"; result << codec << "_"; result << (bps / 1024) << "kbit_"; if (type == "audio"){ result << channels << "ch_"; result << rate << "hz"; }else if (type == "video"){ result << width << "x" << height << "_"; result << (double)fpks / 1000 << "fps"; } return result.str(); } std::string Track::getIdentifier(){ std::stringstream result; if (type == ""){ result << "Metadata_" << trackID; return result.str(); } result << type << "_"; result << codec << "_"; result << (bps / 1024) << "kbit_"; if (type == "audio"){ result << channels << "ch_"; result << rate << "hz"; }else if (type == "video"){ result << width << "x" << height << "_"; result << (double)fpks / 1000 << "fps"; } return result.str(); } void Track::reset(){ fragments.clear(); parts.clear(); keys.clear(); bps = 0; firstms = 999; lastms = 0; } readOnlyMeta::readOnlyMeta(){ vod = false; live = false; moreheader = 0; length = 0; merged = false; bufferWindow = 0; } readOnlyMeta::readOnlyMeta(JSON::Value & meta){ vod = meta.isMember("vod") && meta["vod"]; live = meta.isMember("live") && meta["live"]; length = 0; merged = meta.isMember("merged") && meta["merged"]; bufferWindow = 0; if (meta.isMember("buffer_window")){ bufferWindow = meta["buffer_window"].asInt(); } for (JSON::ObjIter it = meta["tracks"].ObjBegin(); it != meta["tracks"].ObjEnd(); it++){ if (it->second.isMember("trackid") && it->second["trackid"]){ tracks[it->second["trackid"].asInt()] = readOnlyTrack(it->second); if (length < (it->second["lastms"].asInt() - it->second["firstms"].asInt())){ length = (it->second["lastms"].asInt() - it->second["firstms"].asInt()); } } } moreheader = meta["moreheader"].asInt(); } Meta::Meta(){ vod = false; live = false; moreheader = 0; length = 0; merged = false; bufferWindow = 0; } Meta::Meta(const readOnlyMeta & rhs){ vod = rhs.vod; live = rhs.live; merged = rhs.merged; length = rhs.length; bufferWindow = rhs.bufferWindow; for (std::map::const_iterator it = rhs.tracks.begin(); it != rhs.tracks.end(); it++){ tracks[it->first] = it->second; } moreheader = rhs.moreheader; } Meta::Meta(JSON::Value & meta){ vod = meta.isMember("vod") && meta["vod"]; live = meta.isMember("live") && meta["live"]; merged = meta.isMember("merged") && meta["merged"]; bufferWindow = 0; if (meta.isMember("buffer_window")){ bufferWindow = meta["buffer_window"].asInt(); } for (JSON::ObjIter it = meta["tracks"].ObjBegin(); it != meta["tracks"].ObjEnd(); it++){ if(it->second["trackid"].asInt()){ tracks[it->second["trackid"].asInt()] = Track(it->second); if (length < (it->second["lastms"].asInt() - it->second["firstms"].asInt())){ length = (it->second["lastms"].asInt() - it->second["firstms"].asInt()); } } } moreheader = meta["moreheader"].asInt(); } void Meta::update(JSON::Value & pack){ vod = pack.isMember("bpos"); live = !vod; if (pack["trackid"].asInt()){ tracks[pack["trackid"].asInt()].update(pack); } } char * convertShort(short input){ static char result[2]; result[0] = (input >> 8) & 0xFF; result[1] = (input) & 0xFF; return result; } char * convertInt(int input){ static char result[4]; result[0] = (input >> 24) & 0xFF; result[1] = (input >> 16) & 0xFF; result[2] = (input >> 8) & 0xFF; result[3] = (input) & 0xFF; return result; } char * convertLongLong(long long int input){ static char result[8]; result[0] = (input >> 56) & 0xFF; result[1] = (input >> 48) & 0xFF; result[2] = (input >> 40) & 0xFF; result[3] = (input >> 32) & 0xFF; result[4] = (input >> 24) & 0xFF; result[5] = (input >> 16) & 0xFF; result[6] = (input >> 8) & 0xFF; result[7] = (input) & 0xFF; return result; } int readOnlyTrack::getSendLen(){ int result = 163 + init.size() + codec.size() + type.size() + getIdentifier().size(); result += fragLen * 11; result += keyLen * 16; result += partLen * 9; if (type == "audio"){ result += 49; }else if (type == "video"){ result += 48; } if (codec == "vorbis" || codec == "theora"){ result += 15 + idHeader.size();//idheader result += 20 + commentHeader.size();//commentheader } return result; } int Track::getSendLen(){ int result = 163 + init.size() + codec.size() + type.size() + getIdentifier().size(); result += fragments.size() * 11; result += keys.size() * 16; result += parts.size() * 9; if (type == "audio"){ result += 49; }else if (type == "video"){ result += 48; } if (codec == "vorbis" || codec == "theora"){ result += 15 + idHeader.size();//idheader result += 20 + commentHeader.size();//commentheader } return result; } void readOnlyTrack::send(Socket::Connection & conn){ conn.SendNow(convertShort(getIdentifier().size()), 2); conn.SendNow(getIdentifier()); conn.SendNow("\340", 1);//Begin track object conn.SendNow("\000\011fragments\002", 12); conn.SendNow(convertInt(fragLen*11), 4); conn.SendNow((char*)fragments, fragLen*11); conn.SendNow("\000\004keys\002", 7); conn.SendNow(convertInt(keyLen*16), 4); conn.SendNow((char*)keys, keyLen*16); conn.SendNow("\000\005parts\002", 8); conn.SendNow(convertInt(partLen*9), 4); conn.SendNow((char*)parts, partLen*9); conn.SendNow("\000\007trackid\001", 10); conn.SendNow(convertLongLong(trackID), 8); conn.SendNow("\000\006length\001", 9); conn.SendNow(convertLongLong(length), 8); conn.SendNow("\000\007firstms\001", 10); conn.SendNow(convertLongLong(firstms), 8); conn.SendNow("\000\006lastms\001", 9); conn.SendNow(convertLongLong(lastms), 8); conn.SendNow("\000\003bps\001", 6); conn.SendNow(convertLongLong(bps), 8); conn.SendNow("\000\004init\002", 7); conn.SendNow(convertInt(init.size()), 4); conn.SendNow(init); conn.SendNow("\000\005codec\002", 8); conn.SendNow(convertInt(codec.size()), 4); conn.SendNow(codec); conn.SendNow("\000\004type\002", 7); conn.SendNow(convertInt(type.size()), 4); conn.SendNow(type); if (type == "audio"){ conn.SendNow("\000\004rate\001", 7); conn.SendNow(convertLongLong(rate), 8); conn.SendNow("\000\004size\001", 7); conn.SendNow(convertLongLong(size), 8); conn.SendNow("\000\010channels\001", 11); conn.SendNow(convertLongLong(channels), 8); }else if (type == "video"){ conn.SendNow("\000\005width\001", 8); conn.SendNow(convertLongLong(width), 8); conn.SendNow("\000\006height\001", 9); conn.SendNow(convertLongLong(height), 8); conn.SendNow("\000\004fpks\001", 7); conn.SendNow(convertLongLong(fpks), 8); } if (codec == "vorbis" || codec == "theora"){ conn.SendNow("\000\010idheader\002", 11); conn.SendNow(convertInt(idHeader.size()), 4); conn.SendNow(idHeader); conn.SendNow("\000\015commentheader\002", 16); conn.SendNow(convertInt(commentHeader.size()), 4); conn.SendNow(commentHeader); } conn.SendNow("\000\000\356", 3);//End this track Object } void Track::send(Socket::Connection & conn){ conn.SendNow(convertShort(getIdentifier().size()), 2); conn.SendNow(getIdentifier()); conn.SendNow("\340", 1);//Begin track object conn.SendNow("\000\011fragments\002", 12); conn.SendNow(convertInt(fragments.size()*11), 4); for (std::deque::iterator it = fragments.begin(); it != fragments.end(); it++){ conn.SendNow(it->getData(), 11); } conn.SendNow("\000\004keys\002", 7); conn.SendNow(convertInt(keys.size()*16), 4); for (std::deque::iterator it = keys.begin(); it != keys.end(); it++){ conn.SendNow(it->getData(), 16); } conn.SendNow("\000\005parts\002", 8); conn.SendNow(convertInt(parts.size()*9), 4); for (std::deque::iterator it = parts.begin(); it != parts.end(); it++){ conn.SendNow(it->getData(), 9); } conn.SendNow("\000\007trackid\001", 10); conn.SendNow(convertLongLong(trackID), 8); conn.SendNow("\000\006length\001", 9); conn.SendNow(convertLongLong(length), 8); conn.SendNow("\000\007firstms\001", 10); conn.SendNow(convertLongLong(firstms), 8); conn.SendNow("\000\006lastms\001", 9); conn.SendNow(convertLongLong(lastms), 8); conn.SendNow("\000\003bps\001", 6); conn.SendNow(convertLongLong(bps), 8); conn.SendNow("\000\004init\002", 7); conn.SendNow(convertInt(init.size()), 4); conn.SendNow(init); conn.SendNow("\000\005codec\002", 8); conn.SendNow(convertInt(codec.size()), 4); conn.SendNow(codec); conn.SendNow("\000\004type\002", 7); conn.SendNow(convertInt(type.size()), 4); conn.SendNow(type); if (type == "audio"){ conn.SendNow("\000\004rate\001", 7); conn.SendNow(convertLongLong(rate), 8); conn.SendNow("\000\004size\001", 7); conn.SendNow(convertLongLong(size), 8); conn.SendNow("\000\010channels\001", 11); conn.SendNow(convertLongLong(channels), 8); }else if (type == "video"){ conn.SendNow("\000\005width\001", 8); conn.SendNow(convertLongLong(width), 8); conn.SendNow("\000\006height\001", 9); conn.SendNow(convertLongLong(height), 8); conn.SendNow("\000\004fpks\001", 7); conn.SendNow(convertLongLong(fpks), 8); } if (codec == "vorbis" || codec == "theora"){ conn.SendNow("\000\010idheader\002", 11); conn.SendNow(convertInt(idHeader.size()), 4); conn.SendNow(idHeader); conn.SendNow("\000\015commentheader\002", 16); conn.SendNow(convertInt(commentHeader.size()), 4); conn.SendNow(commentHeader); } conn.SendNow("\000\000\356", 3);//End this track Object } void readOnlyMeta::send(Socket::Connection & conn){ int dataLen = 16 + (vod ? 14 : 0) + (live ? 15 : 0) + (merged ? 17 : 0) + 21; for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++){ dataLen += it->second.getSendLen(); } conn.SendNow(DTSC::Magic_Header, 4); conn.SendNow(convertInt(dataLen), 4); conn.SendNow("\340\000\006tracks\340", 10); for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++){ it->second.send(conn); } conn.SendNow("\000\000\356", 3); if (vod){ conn.SendNow("\000\003vod\001", 6); conn.SendNow(convertLongLong(1), 8); } if (live){ conn.SendNow("\000\004live\001", 7); conn.SendNow(convertLongLong(1), 8); } if (merged){ conn.SendNow("\000\006merged\001", 9); conn.SendNow(convertLongLong(1), 8); } conn.SendNow("\000\012moreheader\001", 13); conn.SendNow(convertLongLong(moreheader), 8); conn.SendNow("\000\000\356", 3);//End global object } void Meta::send(Socket::Connection & conn){ int dataLen = 16 + (vod ? 14 : 0) + (live ? 15 : 0) + (merged ? 17 : 0) + 21; for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++){ dataLen += it->second.getSendLen(); } conn.SendNow(DTSC::Magic_Header, 4); conn.SendNow(convertInt(dataLen), 4); conn.SendNow("\340\000\006tracks\340", 10); for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++){ it->second.send(conn); } conn.SendNow("\000\000\356", 3);//End tracks object if (vod){ conn.SendNow("\000\003vod\001", 6); conn.SendNow(convertLongLong(1), 8); } if (live){ conn.SendNow("\000\004live\001", 7); conn.SendNow(convertLongLong(1), 8); } if (merged){ conn.SendNow("\000\006merged\001", 9); conn.SendNow(convertLongLong(1), 8); } conn.SendNow("\000\012moreheader\001", 13); conn.SendNow(convertLongLong(moreheader), 8); conn.SendNow("\000\000\356", 3);//End global object } JSON::Value readOnlyTrack::toJSON(){ JSON::Value result; if (fragments){ result["fragments"] = std::string((char*)fragments, fragLen * 11); } if (keys){ result["keys"] = std::string((char*)keys, keyLen * 16); } if (parts){ result["parts"] = std::string((char*)parts, partLen * 9); } result["trackid"] = trackID; result["length"] = length; result["firstms"] = firstms; result["lastms"] = lastms; result["bps"] = bps; if (missedFrags){ result["missed_frags"] = missedFrags; } result["codec"] = codec; result["type"] = type; result["init"] = init; if (type == "audio"){ result["rate"] = rate; result["size"] = size; result["channels"] = channels; }else if (type == "video"){ result["width"] = width; result["height"] = height; result["fpks"] = fpks; } if (codec == "vorbis" || codec == "theora"){ result["idheader"] = idHeader; result["commentheader"] = commentHeader; } return result; } JSON::Value Track::toJSON(){ JSON::Value result; std::string tmp; tmp.reserve(fragments.size() * 11); for (std::deque::iterator it = fragments.begin(); it != fragments.end(); it++){ tmp.append(it->getData(), 11); } result["fragments"] = tmp; tmp = ""; tmp.reserve(keys.size() * 16); for (std::deque::iterator it = keys.begin(); it != keys.end(); it++){ tmp.append(it->getData(), 16); } result["keys"] = tmp; tmp = ""; tmp.reserve(parts.size() * 9); for (std::deque::iterator it = parts.begin(); it != parts.end(); it++){ tmp.append(it->getData(), 9); } result["parts"] = tmp; result["trackid"] = trackID; result["length"] = length; result["firstms"] = firstms; result["lastms"] = lastms; result["bps"] = bps; if (missedFrags){ result["missed_frags"] = missedFrags; } result["codec"] = codec; result["type"] = type; result["init"] = init; if (type == "audio"){ result["rate"] = rate; result["size"] = size; result["channels"] = channels; }else if (type == "video"){ result["width"] = width; result["height"] = height; result["fpks"] = fpks; } if (codec == "vorbis" || codec == "theora"){ result["idheader"] = idHeader; result["commentheader"] = commentHeader; } return result; } JSON::Value Meta::toJSON(){ JSON::Value result; for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++){ if (!it->second.trackID){continue;} result["tracks"][it->second.getIdentifier()] = it->second.toJSON(); } if (vod){ result["vod"] = 1ll; } if (live){ result["live"] = 1ll; } if (merged){ result["merged"] = 1ll; } if (bufferWindow){ result["buffer_window"]; } result["moreheader"] = moreheader; return result; } JSON::Value readOnlyMeta::toJSON(){ JSON::Value result; for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++){ if (!it->second.trackID){continue;} result["tracks"][it->second.getIdentifier()] = it->second.toJSON(); } if (vod){ result["vod"] = 1ll; } if (live){ result["live"] = 1ll; } if (merged){ result["merged"] = 1ll; } result["moreheader"] = moreheader; if (bufferWindow){ result["buffer_window"]; } return result; } void Meta::reset(){ for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++){ it->second.reset(); } } bool readOnlyMeta::isFixed(){ for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++){ if ( !it->second.keyLen || !(it->second.keys[it->second.keyLen - 1].getBpos())){ return false; } } return true; } bool Meta::isFixed(){ for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++){ if (it->second.type == "meta" || it->second.type == ""){ continue; } if (!it->second.keys.size() || !(it->second.keys.rbegin()->getBpos())){ std::cerr << "Not fixed while track " << it->first << " has " << it->second.keys.size() << "keyframes" << std::endl; return false; } } return true; } }