Working multi-input

This commit is contained in:
Erik Zandvliet 2015-04-02 09:56:47 +02:00
parent 9b6312ca01
commit d370ef4eac
31 changed files with 1264 additions and 690 deletions

View file

@ -21,13 +21,14 @@ namespace Mist {
}
}
void Input::doNothing(char * data, size_t len, unsigned int id){
DEBUG_MSG(DLVL_DONTEVEN, "Doing 'nothing'");
void Input::callbackWrapper(char * data, size_t len, unsigned int id){
singleton->userCallback(data, 30, id);//call the userCallback for this input
}
Input::Input(Util::Config * cfg){
Input::Input(Util::Config * cfg) : InOutBase() {
config = cfg;
standAlone = true;
JSON::Value option;
option["long"] = "json";
option["short"] = "j";
@ -52,7 +53,7 @@ namespace Mist {
option["long"] = "stream";
option["help"] = "The name of the stream that this connector will provide in player mode";
config->addOption("streamname", option);
capa["optional"]["debug"]["name"] = "debug";
capa["optional"]["debug"]["help"] = "The debug level at which messages need to be printed.";
capa["optional"]["debug"]["option"] = "--debug";
@ -97,8 +98,9 @@ namespace Mist {
}
}
int Input::run(){
if (config->getBool("json")){
int Input::run() {
streamName = config->getString("streamname");
if (config->getBool("json")) {
std::cout << capa.toString() << std::endl;
return 0;
}
@ -127,10 +129,10 @@ namespace Mist {
long long int bpos = 0;
seek(0);
getNext();
while (lastPack){
newMeta.updatePosOverride(lastPack, bpos);
file.write(lastPack.getData(), lastPack.getDataLen());
bpos += lastPack.getDataLen();
while (thisPacket){
newMeta.updatePosOverride(thisPacket, bpos);
file.write(thisPacket.getData(), thisPacket.getDataLen());
bpos += thisPacket.getDataLen();
getNext();
}
//close file
@ -143,12 +145,9 @@ namespace Mist {
DEBUG_MSG(DLVL_FAIL,"No filename specified, exiting");
}
}else{
//after this player functionality
metaPage.init(config->getString("streamname"), (isBuffer ? DEFAULT_META_PAGE_SIZE : myMeta.getSendLen()), true);
myMeta.writeTo(metaPage.mapped);
userPage.init(config->getString("streamname") + "_users", PLAY_EX_SIZE, true);
char userPageName[NAME_BUFFER_SIZE];
snprintf(userPageName, NAME_BUFFER_SIZE, SHM_USERS, streamName.c_str());
userPage.init(userPageName, PLAY_EX_SIZE, true);
if (!isBuffer){
for (std::map<unsigned int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
bufferFrame(it->first, 1);
@ -161,7 +160,7 @@ namespace Mist {
while ((Util::bootSecs() - activityCounter) < 10){//10 second timeout
Util::wait(1000);
removeUnused();
userPage.parseEach(doNothing);
userPage.parseEach(callbackWrapper);
if (userPage.amount){
activityCounter = Util::bootSecs();
DEBUG_MSG(DLVL_INSANE, "Connected users: %d", userPage.amount);
@ -169,12 +168,27 @@ namespace Mist {
DEBUG_MSG(DLVL_INSANE, "Timer running");
}
}
finish();
DEBUG_MSG(DLVL_DEVEL,"Closing clean");
//end player functionality
}
return 0;
}
void Input::finish(){
for( std::map<unsigned int, std::map<unsigned int, unsigned int> >::iterator it = pageCounter.begin(); it != pageCounter.end(); it++){
for (std::map<unsigned int, unsigned int>::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++){
it2->second = 1;
}
}
removeUnused();
if (standAlone){
for (std::map<unsigned long, IPC::sharedPage>::iterator it = metaPages.begin(); it != metaPages.end(); it++){
it->second.master = true;
}
}
}
void Input::removeUnused(){
for (std::map<unsigned int, std::map<unsigned int, unsigned int> >::iterator it = pageCounter.begin(); it != pageCounter.end(); it++){
for (std::map<unsigned int, unsigned int>::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++){
@ -185,12 +199,12 @@ namespace Mist {
change = false;
for (std::map<unsigned int, unsigned int>::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++){
if (!it2->second){
dataPages[it->first].erase(it2->first);
bufferRemove(it->first, it2->first);
pageCounter[it->first].erase(it2->first);
for (int i = 0; i < 8192; i += 8){
unsigned int thisKeyNum = ntohl(((((long long int *)(indexPages[it->first].mapped + i))[0]) >> 32) & 0xFFFFFFFF);
unsigned int thisKeyNum = ntohl(((((long long int *)(metaPages[it->first].mapped + i))[0]) >> 32) & 0xFFFFFFFF);
if (thisKeyNum == it2->first){
(((long long int *)(indexPages[it->first].mapped + i))[0]) = 0;
(((long long int *)(metaPages[it->first].mapped + i))[0]) = 0;
}
}
change = true;
@ -227,10 +241,6 @@ namespace Mist {
}
if (hasKeySizes){
for (std::map<unsigned int, DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
char tmpId[20];
sprintf(tmpId, "%u", it->first);
DEBUG_MSG(DLVL_HIGH, "Making page %s", std::string(config->getString("streamname") + tmpId).c_str());
indexPages[it->first].init(config->getString("streamname") + tmpId, 8 * 1024, true);//Pages of 8kb in size, room for 512 parts.
bool newData = true;
for (int i = 0; i < it->second.keys.size(); i++){
if (newData){
@ -253,8 +263,8 @@ namespace Mist {
seek(0);
getNext();
while(lastPack){//loop through all
unsigned int tid = lastPack.getTrackId();
while(thisPacket){//loop through all
unsigned int tid = thisPacket.getTrackId();
if (!tid){
getNext(false);
continue;
@ -271,9 +281,6 @@ namespace Mist {
curData[tid].curOffset = 0;
curData[tid].firstTime = myMeta.tracks[tid].keys[0].getTime();
char tmpId[80];
snprintf(tmpId, 80, "%s%u", config->getString("streamname").c_str(), tid);
indexPages[tid].init(tmpId, 8 * 1024, true);//Pages of 8kb in size, room for 512 parts.
}
if (myMeta.tracks[tid].keys[bookKeeping[tid].curKey].getParts() + 1 == curData[tid].partNum){
if (curData[tid].dataSize > FLIP_DATA_PAGE_SIZE) {
@ -287,10 +294,10 @@ namespace Mist {
curData[tid].keyNum++;
curData[tid].partNum = 0;
}
curData[tid].dataSize += lastPack.getDataLen();
curData[tid].dataSize += thisPacket.getDataLen();
curData[tid].partNum ++;
bookKeeping[tid].curPart ++;
DEBUG_MSG(DLVL_DONTEVEN, "Track %ld:%llu on page %d@%llu (len:%d), being part %d of key %d", lastPack.getTrackId(), lastPack.getTime(), bookKeeping[tid].first, curData[tid].dataSize, lastPack.getDataLen(), curData[tid].partNum, bookKeeping[tid].first+curData[tid].keyNum);
DEBUG_MSG(DLVL_DONTEVEN, "Track %ld:%llu on page %d@%llu (len:%d), being part %lu of key %lu", thisPacket.getTrackId(), thisPacket.getTime(), bookKeeping[tid].first, curData[tid].dataSize, thisPacket.getDataLen(), curData[tid].partNum, bookKeeping[tid].first+curData[tid].keyNum);
getNext(false);
}
for (std::map<unsigned int, DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++) {
@ -304,8 +311,8 @@ namespace Mist {
DEBUG_MSG(DLVL_WARN, "No pages for track %d found", it->first);
}else{
DEBUG_MSG(DLVL_MEDIUM, "Track %d (%s) split into %lu pages", it->first, myMeta.tracks[it->first].codec.c_str(), pagesByTrack[it->first].size());
for (std::map<int, DTSCPageData>::iterator it2 = pagesByTrack[it->first].begin(); it2 != pagesByTrack[it->first].end(); it2++){
DEBUG_MSG(DLVL_VERYHIGH, "Page %u-%u, (%llu bytes)", it2->first, it2->first + it2->second.keyNum - 1, it2->second.dataSize);
for (std::map<unsigned long, DTSCPageData>::iterator it2 = pagesByTrack[it->first].begin(); it2 != pagesByTrack[it->first].end(); it2++){
DEBUG_MSG(DLVL_VERYHIGH, "Page %lu-%lu, (%llu bytes)", it2->first, it2->first + it2->second.keyNum - 1, it2->second.dataSize);
}
}
}
@ -313,79 +320,71 @@ namespace Mist {
bool Input::bufferFrame(unsigned int track, unsigned int keyNum){
if (keyNum >= myMeta.tracks[track].keys.size()){
//End of movie here, returning true to avoid various error messages
return true;
}
if (keyNum < 1){keyNum = 1;}
if (isBuffered(track, keyNum)){
//get corresponding page number
int pageNumber = 0;
for (std::map<unsigned long, DTSCPageData>::iterator it = pagesByTrack[track].begin(); it != pagesByTrack[track].end(); it++){
if (it->first <= keyNum){
pageNumber = it->first;
}else{
break;
}
}
pageCounter[track][pageNumber] = 15;
return true;
}
if (!pagesByTrack.count(track)){
return false;
}
std::map<int, DTSCPageData>::iterator it = pagesByTrack[track].upper_bound(keyNum);
if (it != pagesByTrack[track].begin()){
it--;
//Update keynum to point to the corresponding page
INFO_MSG("Updating keynum %u to %lu", keyNum, (--(pagesByTrack[track].upper_bound(keyNum)))->first);
keyNum = (--(pagesByTrack[track].upper_bound(keyNum)))->first;
if (!bufferStart(track, keyNum)){
return false;
}
unsigned int pageNum = it->first;
pageCounter[track][pageNum] = 15;///Keep page 15seconds in memory after last use
DEBUG_MSG(DLVL_DONTEVEN, "Attempting to buffer page %u key %d->%d", track, keyNum, pageNum);
if (dataPages[track].count(pageNum)){
return true;
}
char pageId[100];
int pageIdLen = snprintf(pageId, 100, "%s%u_%u", config->getString("streamname").c_str(), track, pageNum);
std::string tmpString(pageId, pageIdLen);
dataPages[track][pageNum].init(tmpString, it->second.dataSize, true);
DEBUG_MSG(DLVL_HIGH, "Buffering track %u page %u through %u datasize: %llu", track, pageNum, pageNum-1 + it->second.keyNum, it->second.dataSize);
std::stringstream trackSpec;
trackSpec << track;
trackSelect(trackSpec.str());
unsigned int keyIndex = pageNum-1;
//if (keyIndex > 0){++keyIndex;}
long long unsigned int startTime = myMeta.tracks[track].keys[keyIndex].getTime();
seek(myMeta.tracks[track].keys[keyNum - 1].getTime());
long long unsigned int stopTime = myMeta.tracks[track].lastms + 1;
if ((int)myMeta.tracks[track].keys.size() > keyIndex + it->second.keyNum){
stopTime = myMeta.tracks[track].keys[keyIndex + it->second.keyNum].getTime();
if ((int)myMeta.tracks[track].keys.size() > keyNum - 1 + pagesByTrack[track][keyNum].keyNum){
stopTime = myMeta.tracks[track].keys[keyNum - 1 + pagesByTrack[track][keyNum].keyNum].getTime();
}
DEBUG_MSG(DLVL_HIGH, "Buffering track %d from %d (%llus) to %d (%llus)", track, pageNum, startTime, pageNum-1 + it->second.keyNum, stopTime);
seek(startTime);
it->second.curOffset = 0;
DEBUG_MSG(DLVL_HIGH, "Playing from %llu to %llu", myMeta.tracks[track].keys[keyNum - 1].getTime(), stopTime);
getNext();
//in case earlier seeking was inprecise, seek to the exact point
while (lastPack && lastPack.getTime() < startTime){
while (thisPacket && thisPacket.getTime() < (unsigned long long)myMeta.tracks[track].keys[keyNum - 1].getTime()){
getNext();
}
while (lastPack && lastPack.getTime() < stopTime){
if (it->second.curOffset + lastPack.getDataLen() > pagesByTrack[track][pageNum].dataSize){
DEBUG_MSG(DLVL_WARN, "Trying to write %u bytes on pos %llu where size is %llu (time: %llu / %llu, track %u page %u)", lastPack.getDataLen(), it->second.curOffset, pagesByTrack[track][pageNum].dataSize, lastPack.getTime(), stopTime, track, pageNum);
break;
}else{
// DEBUG_MSG(DLVL_WARN, "Writing %u bytes on pos %llu where size is %llu (time: %llu / %llu, track %u page %u)", lastPack.getDataLen(), it->second.curOffset, pagesByTrack[track][pageNum].dataSize, lastPack.getTime(), stopTime, track, pageNum);
memcpy(dataPages[track][pageNum].mapped + it->second.curOffset, lastPack.getData(), lastPack.getDataLen());
it->second.curOffset += lastPack.getDataLen();
}
while (thisPacket && thisPacket.getTime() < stopTime){
bufferNext(thisPacket);
getNext();
}
for (int i = 0; i < indexPages[track].len / 8; i++){
if (((long long int*)indexPages[track].mapped)[i] == 0){
((long long int*)indexPages[track].mapped)[i] = (((long long int)htonl(pageNum)) << 32) | htonl(it->second.keyNum);
break;
}
}
DEBUG_MSG(DLVL_HIGH, "Done buffering page %u for track %u", pageNum, track);
bufferFinalize(track);
DEBUG_MSG(DLVL_DEVEL, "Done buffering page %d for track %d", keyNum, track);
pageCounter[track][keyNum] = 15;
return true;
}
bool Input::atKeyFrame(){
static std::map<int, unsigned long long> lastSeen;
//not in keyTimes? We're not at a keyframe.
unsigned int c = keyTimes[lastPack.getTrackId()].count(lastPack.getTime());
unsigned int c = keyTimes[thisPacket.getTrackId()].count(thisPacket.getTime());
if (!c){
return false;
}
//skip double times
if (lastSeen.count(lastPack.getTrackId()) && lastSeen[lastPack.getTrackId()] == lastPack.getTime()){
if (lastSeen.count(thisPacket.getTrackId()) && lastSeen[thisPacket.getTrackId()] == thisPacket.getTime()){
return false;
}
//set last seen, and return true
lastSeen[lastPack.getTrackId()] = lastPack.getTime();
lastSeen[thisPacket.getTrackId()] = thisPacket.getTime();
return true;
}

View file

@ -7,35 +7,28 @@
#include <mist/dtsc.h>
#include <mist/shared_memory.h>
namespace Mist {
struct DTSCPageData {
DTSCPageData() : keyNum(0), partNum(0), dataSize(0), curOffset(0), firstTime(0){}
int keyNum;///<The number of keyframes in this page.
int partNum;///<The number of parts in this page.
unsigned long long int dataSize;///<The full size this page should be.
unsigned long long int curOffset;///<The current write offset in the page.
unsigned long long int firstTime;///<The first timestamp of the page.
unsigned long lastKeyTime;///<The last key time encountered on this track.
};
#include "../io.h"
namespace Mist {
struct booking {
int first;
int curKey;
int curPart;
};
class Input {
class Input : public InOutBase {
public:
Input(Util::Config * cfg);
int run();
virtual int run();
virtual ~Input() {};
protected:
static void doNothing(char * data, size_t len, unsigned int id);
static void callbackWrapper(char * data, size_t len, unsigned int id);
virtual bool setup() = 0;
virtual bool readHeader() = 0;
virtual bool atKeyFrame();
virtual void getNext(bool smart = true) {};
virtual void seek(int seekTime){};
virtual void finish();
void play(int until = 0);
void playOnce();
void quitPlay();
@ -53,27 +46,15 @@ namespace Mist {
int playing;
unsigned int playUntil;
unsigned int benchMark;
std::set<unsigned int> selectedTracks;
bool isBuffer;
Util::Config * config;
JSON::Value capa;
DTSC::Meta myMeta;
DTSC::Packet lastPack;
std::map<int,std::set<int> > keyTimes;
IPC::sharedPage metaPage;
//Create server for user pages
IPC::sharedServer userPage;
//TrackIndex pages
std::map<int, IPC::sharedPage> indexPages;
std::map<int, std::map<int, IPC::sharedPage> > dataPages;
//Page Overview
std::map<int, std::map<int, DTSCPageData> > pagesByTrack;
std::map<unsigned int, std::map<unsigned int, unsigned int> > pageCounter;

View file

@ -12,6 +12,10 @@
#include "input_buffer.h"
#ifndef TIMEOUTMULTIPLIER
#define TIMEOUTMULTIPLIER 10
#endif
namespace Mist {
inputBuffer::inputBuffer(Util::Config * cfg) : Input(cfg) {
capa["name"] = "Buffer";
@ -37,49 +41,57 @@ namespace Mist {
singleton = this;
bufferTime = 0;
cutTime = 0;
}
inputBuffer::~inputBuffer(){
if (myMeta.tracks.size()){
inputBuffer::~inputBuffer() {
config->is_active = false;
if (myMeta.tracks.size()) {
DEBUG_MSG(DLVL_DEVEL, "Cleaning up, removing last keyframes");
for(std::map<unsigned int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
while (removeKey(it->first)){}
for (std::map<unsigned int, DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++) {
while (removeKey(it->first)) {}
}
}
}
void inputBuffer::updateMeta(){
void inputBuffer::updateMeta() {
long long unsigned int firstms = 0xFFFFFFFFFFFFFFFFull;
long long unsigned int lastms = 0;
for (std::map<unsigned int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
if (it->second.firstms < firstms){
for (std::map<unsigned int, DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++) {
if (it->second.firstms < firstms) {
firstms = it->second.firstms;
}
if (it->second.firstms > lastms){
if (it->second.firstms > lastms) {
lastms = it->second.lastms;
}
}
myMeta.bufferWindow = lastms - firstms;
myMeta.vod = false;
myMeta.live = true;
IPC::semaphore liveMeta(std::string("liveMeta@" + config->getString("streamname")).c_str(), O_CREAT | O_RDWR, ACCESSPERMS, 1);
static char liveSemName[NAME_BUFFER_SIZE];
snprintf(liveSemName, NAME_BUFFER_SIZE, SHM_STREAM_INDEX, config->getString("streamname").c_str());
IPC::semaphore liveMeta(liveSemName, O_CREAT | O_RDWR, ACCESSPERMS, 1);
liveMeta.wait();
myMeta.writeTo(metaPage.mapped);
memset(metaPage.mapped+myMeta.getSendLen(), 0, metaPage.len > myMeta.getSendLen() ? std::min(metaPage.len-myMeta.getSendLen(), 4ll) : 0);
if (!metaPages.count(0) || !metaPages[0].mapped) {
char pageName[NAME_BUFFER_SIZE];
snprintf(pageName, NAME_BUFFER_SIZE, SHM_STREAM_INDEX, streamName.c_str());
metaPages[0].init(pageName, 8 * 1024 * 1024, true);
metaPages[0].master = false;
}
myMeta.writeTo(metaPages[0].mapped);
memset(metaPages[0].mapped + myMeta.getSendLen(), 0, (metaPages[0].len > myMeta.getSendLen() ? std::min(metaPages[0].len - myMeta.getSendLen(), 4ll) : 0));
liveMeta.post();
}
}
bool inputBuffer::removeKey(unsigned int tid){
if ((myMeta.tracks[tid].keys.size() < 2 || myMeta.tracks[tid].fragments.size() < 2) && config->is_active){
bool inputBuffer::removeKey(unsigned int tid) {
if ((myMeta.tracks[tid].keys.size() < 2 || myMeta.tracks[tid].fragments.size() < 2) && config->is_active) {
return false;
}
if (!myMeta.tracks[tid].keys.size()){
if (!myMeta.tracks[tid].keys.size()) {
return false;
}
DEBUG_MSG(DLVL_HIGH, "Erasing key %d:%d", tid, myMeta.tracks[tid].keys[0].getNumber());
DEBUG_MSG(DLVL_HIGH, "Erasing key %d:%lu", tid, myMeta.tracks[tid].keys[0].getNumber());
//remove all parts of this key
for (int i = 0; i < myMeta.tracks[tid].keys[0].getParts(); i++){
for (int i = 0; i < myMeta.tracks[tid].keys[0].getParts(); i++) {
myMeta.tracks[tid].parts.pop_front();
}
//remove the key itself
@ -88,268 +100,402 @@ namespace Mist {
//re-calculate firstms
myMeta.tracks[tid].firstms = myMeta.tracks[tid].keys[0].getTime();
//delete the fragment if it's no longer fully buffered
if (myMeta.tracks[tid].fragments[0].getNumber() < myMeta.tracks[tid].keys[0].getNumber()){
if (myMeta.tracks[tid].fragments[0].getNumber() < myMeta.tracks[tid].keys[0].getNumber()) {
myMeta.tracks[tid].fragments.pop_front();
myMeta.tracks[tid].missedFrags ++;
}
//if there is more than one page buffered for this track...
if (inputLoc[tid].size() > 1){
if (bufferLocations[tid].size() > 1) {
//Check if the first key starts on the second page or higher
if (myMeta.tracks[tid].keys[0].getNumber() >= (++(inputLoc[tid].begin()))->first){
if (myMeta.tracks[tid].keys[0].getNumber() >= (++(bufferLocations[tid].begin()))->first || !config->is_active) {
//Find page in indexpage and null it
for (int i = 0; i < 8192; i += 8){
unsigned int thisKeyNum = ntohl(((((long long int *)(indexPages[tid].mapped + i))[0]) >> 32) & 0xFFFFFFFF);
if (thisKeyNum < myMeta.tracks[tid].keys[0].getNumber()){
(((long long int *)(indexPages[tid].mapped + i))[0]) = 0;
for (int i = 0; i < 8192; i += 8) {
unsigned int thisKeyNum = ((((long long int *)(metaPages[tid].mapped + i))[0]) >> 32) & 0xFFFFFFFF;
if (thisKeyNum == htonl(pagesByTrack[tid].begin()->first) && ((((long long int *)(metaPages[tid].mapped + i))[0]) != 0)) {
(((long long int *)(metaPages[tid].mapped + i))[0]) = 0;
}
}
DEBUG_MSG(DLVL_DEVEL, "Erasing track %d, keys %lu-%lu from buffer", tid, inputLoc[tid].begin()->first, inputLoc[tid].begin()->first + inputLoc[tid].begin()->second.keyNum - 1);
inputLoc[tid].erase(inputLoc[tid].begin());
dataPages[tid].erase(dataPages[tid].begin());
}else{
DEBUG_MSG(DLVL_HIGH, "%d still on first page (%lu - %lu)", myMeta.tracks[tid].keys[0].getNumber(), inputLoc[tid].begin()->first, inputLoc[tid].begin()->first + inputLoc[tid].begin()->second.keyNum - 1);
DEBUG_MSG(DLVL_DEVEL, "Erasing track %d, keys %lu-%lu from buffer", tid, bufferLocations[tid].begin()->first, bufferLocations[tid].begin()->first + bufferLocations[tid].begin()->second.keyNum - 1);
bufferRemove(tid, bufferLocations[tid].begin()->first);
for (int i = 0; i < 1024; i++) {
int * tmpOffset = (int *)(metaPages[tid].mapped + (i * 8));
int tmpNum = ntohl(tmpOffset[0]);
if (tmpNum == bufferLocations[tid].begin()->first) {
tmpOffset[0] = 0;
tmpOffset[1] = 0;
}
}
curPageNum.erase(tid);
char thisPageName[NAME_BUFFER_SIZE];
snprintf(thisPageName, NAME_BUFFER_SIZE, SHM_TRACK_DATA, config->getString("streamname").c_str(), (unsigned long)tid, bufferLocations[tid].begin()->first);
curPage[tid].init(thisPageName, 20971520);
curPage[tid].master = true;
curPage.erase(tid);
bufferLocations[tid].erase(bufferLocations[tid].begin());
} else {
DEBUG_MSG(DLVL_HIGH, "%lu still on first page (%lu - %lu)", myMeta.tracks[tid].keys[0].getNumber(), bufferLocations[tid].begin()->first, bufferLocations[tid].begin()->first + bufferLocations[tid].begin()->second.keyNum - 1);
}
}
return true;
}
void inputBuffer::removeUnused(){
void inputBuffer::finish() {
Input::finish();
for (std::map<unsigned long, std::map<unsigned long, DTSCPageData> >::iterator it = bufferLocations.begin(); it != bufferLocations.end(); it++) {
for (std::map<unsigned long, DTSCPageData>::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++) {
char thisPageName[NAME_BUFFER_SIZE];
snprintf(thisPageName, NAME_BUFFER_SIZE, SHM_TRACK_DATA, config->getString("streamname").c_str(), it->first, it2->first);
curPage[it->first].init(thisPageName, 20971520, false, false);
curPage[it->first].master = true;
curPage.erase(it->first);
}
}
}
void inputBuffer::removeUnused() {
//first remove all tracks that have not been updated for too long
bool changed = true;
while (changed) {
changed = false;
long long unsigned int time = Util::bootSecs();
for (std::map<unsigned int, DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++) {
bool eraseTrack = false;
long long unsigned int compareFirst = 0xFFFFFFFFFFFFFFFFull;
long long unsigned int compareLast = 0;
if ((time - lastUpdated[it->first]) > 5) {
for (std::map<unsigned int, DTSC::Track>::iterator it2 = myMeta.tracks.begin(); it2 != myMeta.tracks.end(); it2++) {
if (it2->first == it->first) {
continue;
}
if ((time - lastUpdated[it2->first]) > 5) {
continue;
}
if (it2->second.lastms > compareLast) {
compareLast = it2->second.lastms;
}
if (it2->second.firstms < compareFirst) {
compareFirst = it2->second.firstms;
}
}
if (compareLast) {
if ((myMeta.tracks[it->first].firstms - compareLast) > ((TIMEOUTMULTIPLIER * bufferTime) / 1000)) {
eraseTrack = true;
}
if ((compareFirst - myMeta.tracks[it->first].lastms) > ((TIMEOUTMULTIPLIER * bufferTime) / 1000)) {
eraseTrack = true;
}
}
}
if ((time - lastUpdated[it->first]) > ((TIMEOUTMULTIPLIER * bufferTime) / 1000)) {
eraseTrack = true;
}
if (eraseTrack) {
//erase this track
INFO_MSG("Erasing track %d because of timeout", it->first);
lastUpdated.erase(it->first);
bufferLocations.erase(it->first);
curPage[it->first].master = true;
curPage.erase(it->first);
curPageNum.erase(it->first);
metaPages[it->first].master = true;
metaPages.erase(it->first);
activeTracks.erase(it->first);
pushLocation.erase(it->first);
myMeta.tracks.erase(it);
changed = true;
break;
}
}
}
//find the earliest video keyframe stored
unsigned int firstVideo = 1;
for(std::map<unsigned int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
if (it->second.type == "video"){
if (it->second.firstms < firstVideo || firstVideo == 1){
for (std::map<unsigned int, DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++) {
if (it->second.type == "video") {
if (it->second.firstms < firstVideo || firstVideo == 1) {
firstVideo = it->second.firstms;
}
}
}
for(std::map<unsigned int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
for (std::map<unsigned int, DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++) {
//non-video tracks need to have a second keyframe that is <= firstVideo
if (it->second.type != "video"){
if (it->second.keys.size() < 2 || it->second.keys[1].getTime() > firstVideo){
if (it->second.type != "video") {
if (it->second.keys.size() < 2 || it->second.keys[1].getTime() > firstVideo) {
continue;
}
}
//Buffer cutting
while(it->second.keys.size() > 1 && it->second.keys[0].getTime() < cutTime){
if (!removeKey(it->first)){break;}
while (it->second.keys.size() > 1 && it->second.keys[0].getTime() < cutTime) {
if (!removeKey(it->first)) {
break;
}
}
//Buffer size management
while(it->second.keys.size() > 1 && (it->second.lastms - it->second.keys[1].getTime()) > bufferTime){
if (!removeKey(it->first)){break;}
while (it->second.keys.size() > 1 && (it->second.lastms - it->second.keys[1].getTime()) > bufferTime) {
if (!removeKey(it->first)) {
break;
}
}
}
updateMeta();
}
void inputBuffer::userCallback(char * data, size_t len, unsigned int id) {
//Static variable keeping track of the next temporary mapping to use for a track.
static int nextTempId = 1001;
//Get the counter of this user
char counter = (*(data - 1));
for (int index = 0; index < 5; index++){
char* thisData = data + (index * 6);
//Each user can have at maximum 5 elements in their userpage.
for (int index = 0; index < 5; index++) {
char * thisData = data + (index * 6);
//Get the track id from the current element
unsigned long value = ((long)(thisData[0]) << 24) | ((long)(thisData[1]) << 16) | ((long)(thisData[2]) << 8) | thisData[3];
if (value == 0xFFFFFFFF){
//Skip value 0xFFFFFFFF as this indicates a previously declined track
//Skip value 0xFFFFFFFF as this indicates a previously declined track
if (value == 0xFFFFFFFF) {
continue;
}
if (value == 0){
//Skip value 0 as this indicates an empty track
//Skip value 0 as this indicates an empty track
if (value == 0) {
continue;
}
if (pushedLoc[value] == thisData){
if (counter == 126 || counter == 127 || counter == 254 || counter == 255){
pushedLoc.erase(value);
if (negotiateTracks.count(value)){
negotiateTracks.erase(value);
//If the current value indicates a valid trackid, and it is pushed from this user
if (pushLocation[value] == thisData) {
//Check for timeouts, and erase the track if necessary
if (counter == 126 || counter == 127 || counter == 254 || counter == 255) {
pushLocation.erase(value);
if (negotiatingTracks.count(value)) {
negotiatingTracks.erase(value);
metaPages[value].master = true;
metaPages.erase(value);
}
if (data[4] == 0xFF && data[5] == 0xFF && givenTracks.count(value)){
givenTracks.erase(value);
inputLoc.erase(value);
if (data[4] == 0xFF && data[5] == 0xFF && activeTracks.count(value)) {
activeTracks.erase(value);
bufferLocations.erase(value);
}
continue;
}
}
if (value & 0x80000000){
//Track is set to "New track request", assign new track id and create shared memory page
int tmpTid = nextTempId++;
negotiateTracks.insert(tmpTid);
thisData[0] = (tmpTid >> 24) & 0xFF;
thisData[1] = (tmpTid >> 16) & 0xFF;
thisData[2] = (tmpTid >> 8) & 0xFF;
thisData[3] = (tmpTid) & 0xFF;
unsigned long tNum = ((long)(thisData[4]) << 8) | thisData[5];
DEBUG_MSG(DLVL_HIGH, "Assigning temporary ID %d to incoming track %lu for user %d", tmpTid, tNum, id);
char tempMetaName[100];
sprintf(tempMetaName, "liveStream_%s%d", config->getString("streamname").c_str(), tmpTid);
metaPages[tmpTid].init(tempMetaName, DEFAULT_META_PAGE_SIZE, true);
//Track is set to "New track request", assign new track id and create shared memory page
//This indicates that the 'current key' part of the element is set to contain the original track id from the pushing process
if (value & 0x80000000) {
//Set the temporary track id for this item, and increase the temporary value for use with the next track
unsigned long long tempMapping = nextTempId++;
//Add the temporary track id to the list of tracks that are currently being negotiated
negotiatingTracks.insert(tempMapping);
//Write the temporary id to the userpage element
thisData[0] = (tempMapping >> 24) & 0xFF;
thisData[1] = (tempMapping >> 16) & 0xFF;
thisData[2] = (tempMapping >> 8) & 0xFF;
thisData[3] = (tempMapping) & 0xFF;
//Obtain the original track number for the pushing process
unsigned long originalTrack = ((long)(thisData[4]) << 8) | thisData[5];
//Overwrite it with 0xFFFF
thisData[4] = 0xFF;
thisData[5] = 0xFF;
DEBUG_MSG(DLVL_HIGH, "Incoming track %lu from pushing process %d has now been assigned temporary id %llu", originalTrack, id, tempMapping);
}
if (negotiateTracks.count(value)){
//Track is currently under negotiation, check whether the metadata has been submitted
if (metaPages[value].mapped){
unsigned int len = ntohl(((int *)metaPages[value].mapped)[1]);
unsigned int i = 0;
JSON::Value JSONMeta;
JSON::fromDTMI((const unsigned char *)metaPages[value].mapped + 8, len, i, JSONMeta);
DTSC::Meta tmpMeta(JSONMeta);
if (!tmpMeta.tracks.count(value)){//Track not yet added
continue;
}
std::string tempId = tmpMeta.tracks.begin()->second.getIdentifier();
DEBUG_MSG(DLVL_HIGH, "Attempting colision detection for track %s", tempId.c_str());
int finalMap = -1;
if (tmpMeta.tracks.begin()->second.type == "video"){
finalMap = 1;
}
if (tmpMeta.tracks.begin()->second.type == "audio"){
finalMap = 2;
}
//Remove the "negotiate" status in either case
negotiateTracks.erase(value);
metaPages.erase(value);
if (finalMap != -1 && givenTracks.count(finalMap)) {
WARN_MSG("Collision of new track %lu with track %d detected! Declining track", value, finalMap);
thisData[0] = 0xFF;
thisData[1] = 0xFF;
thisData[2] = 0xFF;
thisData[3] = 0xFF;
//The track id is set to the value of a track that we are currently negotiating about
if (negotiatingTracks.count(value)) {
//If the metadata page for this track is not yet registered, initialize it
if (!metaPages.count(value) || !metaPages[value].mapped) {
char tempMetaName[NAME_BUFFER_SIZE];
snprintf(tempMetaName, NAME_BUFFER_SIZE, SHM_TRACK_META, config->getString("streamname").c_str(), value);
metaPages[value].init(tempMetaName, 8388608, false, false);
}
//If this tracks metdata page is not initialize, skip the entire element for now. It will be instantiated later
if (!metaPages[value].mapped) {
///\todo Maybe add a timeout counter here, for when we dont expect the track to appear anymore
continue;
}
//The page exist, now we try to read in the metadata of the track
//Store the size of the dtsc packet to read.
unsigned int len = ntohl(((int *)metaPages[value].mapped)[1]);
//Temporary variable, won't be used again
unsigned int tempForReadingMeta = 0;
//Read in the metadata through a temporary JSON object
///\todo Optimize this part. Find a way to not have to store the metadata in JSON first, but read it from the page immediately
JSON::Value tempJSONForMeta;
JSON::fromDTMI((const unsigned char *)metaPages[value].mapped + 8, len, tempForReadingMeta, tempJSONForMeta);
//Construct a metadata object for the current track
DTSC::Meta trackMeta(tempJSONForMeta);
//If the track metadata does not contain the negotiated track, assume the metadata is currently being written, and skip the element for now. It will be instantiated in the next call.
if (!trackMeta.tracks.count(value)) {
continue;
}
std::string trackIdentifier = trackMeta.tracks.find(value)->second.getIdentifier();
DEBUG_MSG(DLVL_HIGH, "Attempting colision detection for track %s", trackIdentifier.c_str());
//Remove the "negotiate" status in either case
negotiatingTracks.erase(value);
//Set master to true before erasing the page, because we are responsible for cleaning up unused pages
metaPages[value].master = true;
metaPages.erase(value);
int finalMap = (trackMeta.tracks.find(value)->second.type == "video" ? 1 : 2);
//Resume either if we have more than 1 keyframe on the replacement track (assume it was already pushing before the track "dissapeared")
//or if the firstms of the replacement track is later than the lastms on the existing track
if (!myMeta.tracks.count(finalMap) || trackMeta.tracks.find(value)->second.keys.size() > 1 || trackMeta.tracks.find(value)->second.firstms >= myMeta.tracks[finalMap].lastms) {
if (myMeta.tracks.count(finalMap) && myMeta.tracks[finalMap].lastms > 0) {
INFO_MSG("Resume of track %d detected, coming from temporary track %lu of user %u", finalMap, value, id);
} else {
if (finalMap == -1){
WARN_MSG("Invalid track type detected, declining.");
thisData[0] = 0xFF;
thisData[1] = 0xFF;
thisData[2] = 0xFF;
thisData[3] = 0xFF;
continue;
}else{
//Resume either if we have more than 1 keyframe on the replacement track (assume it was already pushing before the track "dissapeared"
//or if the firstms of the replacement track is later than the lastms on the existing track
if (tmpMeta.tracks.begin()->second.keys.size() > 1 || !myMeta.tracks.count(finalMap) || tmpMeta.tracks.begin()->second.firstms >= myMeta.tracks[finalMap].lastms){
if (myMeta.tracks.count(finalMap) && myMeta.tracks[finalMap].lastms > 0){
INFO_MSG("Allowing negotiation track %lu, from user %u, to resume pushing final track number %d", value, id, finalMap);
}else{
INFO_MSG("Allowing negotiation track %lu, from user %u, to start pushing final track number %d", value, id, finalMap);
}
}else{
//Otherwise replace existing track
INFO_MSG("Re-push initiated for track %lu, from user %u, will replace final track number %d", value, id, finalMap);
myMeta.tracks.erase(finalMap);
dataPages.erase(finalMap);
inputLoc.erase(finalMap);
}
}
givenTracks.insert(finalMap);
pushedLoc[finalMap] = thisData;
if (!myMeta.tracks.count(finalMap)){
DEBUG_MSG(DLVL_HIGH, "Inserting metadata for track number %d", finalMap);
myMeta.tracks[finalMap] = tmpMeta.tracks.begin()->second;
myMeta.tracks[finalMap].trackID = finalMap;
}
thisData[0] = (finalMap >> 24) & 0xFF;
thisData[1] = (finalMap >> 16) & 0xFF;
thisData[2] = (finalMap >> 8) & 0xFF;
thisData[3] = (finalMap) & 0xFF;
int keyNum = myMeta.tracks[finalMap].keys.size();
thisData[4] = (keyNum >> 8) & 0xFF;
thisData[5] = keyNum & 0xFF;
updateMeta();
char firstPage[100];
sprintf(firstPage, "%s%d", config->getString("streamname").c_str(), finalMap);
indexPages[finalMap].init(firstPage, 8192, true);
((long long int *)indexPages[finalMap].mapped)[0] = htonl(1000);
sprintf(firstPage, "%s%d_%d", config->getString("streamname").c_str(), finalMap, keyNum);
///\todo Make size dynamic / other solution. 25mb is too much.
dataPages[finalMap][0].init(firstPage, DEFAULT_DATA_PAGE_SIZE, true);
INFO_MSG("New track detected, assigned track id %d, coming from temporary track %lu of user %u", finalMap, value, id);
}
}
//Register the new track as an active track.
activeTracks.insert(finalMap);
//Register the time of registration as initial value for the lastUpdated field.
lastUpdated[finalMap] = Util::bootSecs();
//Register the user thats is pushing this element
pushLocation[finalMap] = thisData;
//Initialize the metadata for this track if it was not in place yet.
if (!myMeta.tracks.count(finalMap)) {
DEBUG_MSG(DLVL_HIGH, "Inserting metadata for track number %d", finalMap);
myMeta.tracks[finalMap] = trackMeta.tracks.begin()->second;
myMeta.tracks[finalMap].trackID = finalMap;
}
//Write the final mapped track number to the user page element
thisData[0] = (finalMap >> 24) & 0xFF;
thisData[1] = (finalMap >> 16) & 0xFF;
thisData[2] = (finalMap >> 8) & 0xFF;
thisData[3] = (finalMap) & 0xFF;
//Write the key number to start pushing from to to the userpage element.
//This is used to resume pushing as well as pushing new tracks
unsigned long keyNum = myMeta.tracks[finalMap].keys.size();
thisData[4] = (keyNum >> 8) & 0xFF;
thisData[5] = keyNum & 0xFF;
//Update the metadata to reflect all changes
updateMeta();
}
if (givenTracks.count(value) && pushedLoc[value] == thisData){
//First check if the previous page has been finished:
if (!inputLoc[value].count(dataPages[value].rbegin()->first) || !inputLoc[value][dataPages[value].rbegin()->first].curOffset){
if (dataPages[value].size() > 1){
int previousPage = (++dataPages[value].rbegin())->first;
updateMetaFromPage(value, previousPage);
}
//If the track is active, and this is the element responsible for pushing it
if (activeTracks.count(value) && pushLocation[value] == thisData) {
//Open the track index page if we dont have it open yet
if (!metaPages.count(value) || !metaPages[value].mapped) {
char firstPage[NAME_BUFFER_SIZE];
snprintf(firstPage, NAME_BUFFER_SIZE, SHM_TRACK_INDEX, config->getString("streamname").c_str(), value);
metaPages[value].init(firstPage, 8192, false, false);
}
//update current page
int currentPage = dataPages[value].rbegin()->first;
updateMetaFromPage(value, currentPage);
if (inputLoc[value][currentPage].curOffset > FLIP_DATA_PAGE_SIZE) {
int nextPage = currentPage + inputLoc[value][currentPage].keyNum;
char nextPageName[100];
sprintf(nextPageName, "%s%lu_%d", config->getString("streamname").c_str(), value, nextPage);
dataPages[value][nextPage].init(nextPageName, DEFAULT_DATA_PAGE_SIZE, true);
DEVEL_MSG("Created page %s, from pos %llu", nextPageName, inputLoc[value][currentPage].curOffset);
bool createdNew = false;
for (int i = 0; i < 8192; i += 8){
unsigned int thisKeyNum = ((((long long int *)(indexPages[value].mapped + i))[0]) >> 32) & 0xFFFFFFFF;
if (thisKeyNum == htonl(currentPage)){
if((ntohl((((long long int*)(indexPages[value].mapped + i))[0]) & 0xFFFFFFFF) == 1000)){
((long long int *)(indexPages[value].mapped + i))[0] &= 0xFFFFFFFF00000000ull;
((long long int *)(indexPages[value].mapped + i))[0] |= htonl(inputLoc[value][currentPage].keyNum);
}
}
if (!createdNew && (((long long int*)(indexPages[value].mapped + i))[0]) == 0){
createdNew = true;
((long long int *)(indexPages[value].mapped + i))[0] = (((long long int)htonl(nextPage)) << 32) | htonl(1000);
}
}
if (!createdNew){
ERROR_MSG("Could not create index for new page - out of empty indexes!");
}
if (metaPages[value].mapped) {
//Update the metadata for this track
updateTrackMeta(value);
}
}
}
}
void inputBuffer::updateMetaFromPage(int tNum, int pageNum){
DTSC::Packet tmpPack;
tmpPack.reInit(dataPages[tNum][pageNum].mapped + inputLoc[tNum][pageNum].curOffset, 0);
if (!tmpPack && inputLoc[tNum][pageNum].curOffset == 0){
return;
}
while (tmpPack) {
myMeta.update(tmpPack);
if (inputLoc[tNum][pageNum].firstTime == 0){
inputLoc[tNum][pageNum].firstTime = tmpPack.getTime();
void inputBuffer::updateTrackMeta(unsigned long tNum) {
//Store a reference for easier access
std::map<unsigned long, DTSCPageData> & locations = bufferLocations[tNum];
//First detect all entries on metaPage
for (int i = 0; i < 8192; i += 8) {
int * tmpOffset = (int *)(metaPages[tNum].mapped + i);
if (tmpOffset[0] == 0 && tmpOffset[1] == 0) {
continue;
}
inputLoc[tNum][pageNum].keyNum += tmpPack.getFlag("keyframe");
inputLoc[tNum][pageNum].curOffset += tmpPack.getDataLen();
tmpPack.reInit(dataPages[tNum][pageNum].mapped + inputLoc[tNum][pageNum].curOffset, 0);
unsigned long keyNum = ntohl(tmpOffset[0]);
//Add an entry into bufferLocations[tNum] for the pages we haven't handled yet.
if (!locations.count(keyNum)) {
locations[keyNum].curOffset = 0;
}
locations[keyNum].pageNum = keyNum;
locations[keyNum].keyNum = ntohl(tmpOffset[1]);
}
//Since the map is ordered by keynumber, this loop updates the metadata for each page from oldest to newest
for (std::map<unsigned long, DTSCPageData>::iterator pageIt = locations.begin(); pageIt != locations.end(); pageIt++) {
updateMetaFromPage(tNum, pageIt->first);
}
updateMeta();
}
void inputBuffer::updateMetaFromPage(unsigned long tNum, unsigned long pageNum) {
DTSCPageData & pageData = bufferLocations[tNum][pageNum];
//If the current page is over its 8mb "splitting" boundary
if (pageData.curOffset > (8 * 1024 * 1024)) {
//And the last keyframe in the parsed metadata is further in the stream than this page
if (pageData.pageNum + pageData.keyNum < myMeta.tracks[tNum].keys.rbegin()->getNumber()) {
//Assume the entire page is already parsed
return;
}
}
//Otherwise open and parse the page
//Open the page if it is not yet open
if (!curPageNum.count(tNum) || curPageNum[tNum] != pageNum) {
//DO NOT ERASE THE PAGE HERE, master is not set to true
curPageNum.erase(tNum);
char nextPageName[NAME_BUFFER_SIZE];
snprintf(nextPageName, NAME_BUFFER_SIZE, SHM_TRACK_DATA, config->getString("streamname").c_str(), tNum, pageNum);
curPage[tNum].init(nextPageName, 20971520);
//If the page can not be opened, stop here
if (!curPage[tNum].mapped) {
///\todo Maybe generate a warning here?
return;
}
curPageNum[tNum] = pageNum;
}
DTSC::Packet tmpPack;
tmpPack.reInit(curPage[tNum].mapped + pageData.curOffset, 0);
//No new data has been written on the page since last update
if (!tmpPack) {
return;
}
lastUpdated[tNum] = Util::bootSecs();
while (tmpPack) {
//Update the metadata with this packet
myMeta.update(tmpPack);
//Set the first time when appropriate
if (pageData.firstTime == 0) {
pageData.firstTime = tmpPack.getTime();
}
//Update the offset on the page with the size of the current packet
pageData.curOffset += tmpPack.getDataLen();
//Attempt to read in the next packet
tmpPack.reInit(curPage[tNum].mapped + pageData.curOffset, 0);
}
}
bool inputBuffer::setup() {
std::string strName = config->getString("streamname");
Util::sanitizeName(strName);
strName = strName.substr(0,(strName.find_first_of("+ ")));
strName = strName.substr(0, (strName.find_first_of("+ ")));
IPC::sharedPage serverCfg("!mistConfig", DEFAULT_CONF_PAGE_SIZE, false, false); ///< Contains server configuration and capabilities
IPC::semaphore configLock("!mistConfLock", O_CREAT | O_RDWR, ACCESSPERMS, 1);
configLock.wait();
DTSC::Scan streamCfg = DTSC::Scan(serverCfg.mapped, serverCfg.len).getMember("streams").getMember(strName);
long long tmpNum;
//if stream is configured and setting is present, use it, always
if (streamCfg && streamCfg.getMember("DVR")){
if (streamCfg && streamCfg.getMember("DVR")) {
tmpNum = streamCfg.getMember("DVR").asInt();
}else{
if (streamCfg){
} else {
if (streamCfg) {
//otherwise, if stream is configured use the default
tmpNum = config->getOption("bufferTime", true)[0u].asInt();
}else{
} else {
//if not, use the commandline argument
tmpNum = config->getOption("bufferTime").asInt();
}
}
//if the new value is different, print a message and apply it
if (bufferTime != tmpNum){
if (bufferTime != tmpNum) {
DEBUG_MSG(DLVL_DEVEL, "Setting bufferTime from %u to new value of %lli", bufferTime, tmpNum);
bufferTime = tmpNum;
}
configLock.post();
configLock.close();
return true;

View file

@ -16,18 +16,20 @@ namespace Mist {
void updateMeta();
bool readHeader();
void getNext(bool smart = true);
void updateMetaFromPage(int tNum, int pageNum);
void updateTrackMeta(unsigned long tNum);
void updateMetaFromPage(unsigned long tNum, unsigned long pageNum);
void seek(int seekTime);
void trackSelect(std::string trackSpec);
bool removeKey(unsigned int tid);
void removeUnused();
void finish();
void userCallback(char * data, size_t len, unsigned int id);
std::set<unsigned long> negotiateTracks;
std::set<unsigned long> givenTracks;
std::map<unsigned long, IPC::sharedPage> metaPages;
std::set<unsigned long> negotiatingTracks;
std::set<unsigned long> activeTracks;
std::map<unsigned long, unsigned long long> lastUpdated;
///Maps trackid to a pagenum->pageData map
std::map<unsigned long, std::map<unsigned long, DTSCPageData> > inputLoc;
std::map<unsigned long, char *> pushedLoc;
std::map<unsigned long, std::map<unsigned long, DTSCPageData> > bufferLocations;
std::map<unsigned long, char *> pushLocation;
inputBuffer * singleton;
};
}

View file

@ -74,7 +74,7 @@ namespace Mist {
}else{
inFile.parseNext();
}
lastPack = inFile.getPacket();
thisPacket = inFile.getPacket();
}
void inputDTSC::seek(int seekTime) {

View file

@ -105,11 +105,11 @@ namespace Mist {
if (FLV::Parse_Error){
FAIL_MSG("FLV error: %s", FLV::Error_Str.c_str());
thisPack.null();
lastPack.null();
thisPacket.null();
return;
}
std::string tmpStr = thisPack.toNetPacked();
lastPack.reInit(tmpStr.data(), tmpStr.size());
thisPacket.reInit(tmpStr.data(), tmpStr.size());
}
void inputFLV::seek(int seekTime) {

View file

@ -86,8 +86,8 @@ namespace Mist {
getNext();
while (lastPack){
myMeta.update(lastPack);
while (thisPacket){
myMeta.update(thisPacket);
getNext();
}
@ -100,7 +100,7 @@ namespace Mist {
}
void inputMP3::getNext(bool smart) {
lastPack.null();
thisPacket.null();
static char packHeader[3000];
size_t filePos = ftell(inFile);
size_t read = fread(packHeader, 1, 3000, inFile);
@ -169,7 +169,7 @@ namespace Mist {
thisPack["time"] = (long long)timestamp;
//Write the json value to lastpack
std::string tmpStr = thisPack.toNetPacked();
lastPack.reInit(tmpStr.data(), tmpStr.size());
thisPacket.reInit(tmpStr.data(), tmpStr.size());
//Update the internal timestamp

View file

@ -217,8 +217,8 @@ namespace Mist {
}
}
getNext();
while (lastPack){
myMeta.update(lastPack);
while (thisPacket){
myMeta.update(thisPacket);
getNext();
}
@ -276,7 +276,7 @@ namespace Mist {
void inputOGG::getNext(bool smart){
if (!currentPositions.size()){
lastPack.null();
thisPacket.null();
return;
}
bool lastCompleteSegment = false;
@ -330,7 +330,7 @@ namespace Mist {
readFullPacket = true;
}
std::string tmpStr = thisSegment.toJSON(oggTracks[thisSegment.tid].codec).toNetPacked();
lastPack.reInit(tmpStr.data(), tmpStr.size());
thisPacket.reInit(tmpStr.data(), tmpStr.size());
if (oggTracks[thisSegment.tid].codec == OGG::VORBIS){
unsigned long blockSize = 0;
@ -351,8 +351,8 @@ namespace Mist {
thisSegment.time = oggTracks[thisSegment.tid].msPerFrame * (parseGranuleUpper + parseGranuleLower - 1);
curPos.time = thisSegment.time;
std::string tmpStr = thisSegment.toJSON(oggTracks[thisSegment.tid].codec).toNetPacked();
lastPack.reInit(tmpStr.data(), tmpStr.size());
// INFO_MSG("thisTime: %d", lastPack.getTime());
thisPacket.reInit(tmpStr.data(), tmpStr.size());
// INFO_MSG("thisTime: %d", thisPacket.getTime());
}
curPos.time += oggTracks[thisSegment.tid].msPerFrame;
}
@ -398,7 +398,7 @@ namespace Mist {
DEBUG_MSG(DLVL_MEDIUM, "Seeking to %dms", seekTime);
//for every track
for (std::set<unsigned int>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){
for (std::set<unsigned long>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){
//find first keyframe before keyframe with ms > seektime
position tmpPos;
tmpPos.trackID = *it;
@ -412,7 +412,7 @@ namespace Mist {
tmpPos.bytepos = ot->getBpos();
}
}
INFO_MSG("Found %dms for track %u at %llu bytepos %llu", seekTime, *it, tmpPos.time, tmpPos.bytepos);
INFO_MSG("Found %dms for track %lu at %llu bytepos %llu", seekTime, *it, tmpPos.time, tmpPos.bytepos);
int backChrs=std::min(280ull, tmpPos.bytepos - 1);
fseek(inFile, tmpPos.bytepos - backChrs, SEEK_SET);
char buffer[300];
@ -422,12 +422,12 @@ namespace Mist {
loc = (char *)memrchr(buffer, 'O', (loc-buffer) -1 );//seek reverse
}
if (!loc){
INFO_MSG("Unable to find a page boundary starting @ %llu, track %u", tmpPos.bytepos, *it);
INFO_MSG("Unable to find a page boundary starting @ %llu, track %lu", tmpPos.bytepos, *it);
continue;
}
tmpPos.segmentNo = backChrs - (loc - buffer);
tmpPos.bytepos -= tmpPos.segmentNo;
INFO_MSG("Track %u, segment %llu found at bytepos %llu", *it, tmpPos.segmentNo, tmpPos.bytepos);
INFO_MSG("Track %lu, segment %llu found at bytepos %llu", *it, tmpPos.segmentNo, tmpPos.bytepos);
currentPositions.insert(tmpPos);
}