LTS Commits

This commit is contained in:
Thulinma 2015-04-05 21:38:36 +02:00
parent f24d97b510
commit 4bdbd82f66
72 changed files with 8245 additions and 105 deletions

632
src/input/input_mp4.cpp Normal file
View file

@ -0,0 +1,632 @@
#include <iostream>
#include <fstream>
#include <cstring>
#include <cerrno>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <mist/stream.h>
#include <mist/flv_tag.h>
#include <mist/defines.h>
#include "input_mp4.h"
namespace Mist {
mp4TrackHeader::mp4TrackHeader(){
initialised = false;
stscStart = 0;
sampleIndex = 0;
deltaIndex = 0;
deltaPos = 0;
deltaTotal = 0;
offsetIndex = 0;
offsetPos = 0;
sttsBox.clear();
cttsBox.clear();
stszBox.clear();
stcoBox.clear();
}
long unsigned int mp4TrackHeader::size(){
if (!stszBox.asBox()){
return 0;
}else{
return stszBox.getSampleCount();
}
}
void mp4TrackHeader::read(MP4::TRAK & trakBox){
initialised = false;
std::string tmp;//temporary string for copying box data
MP4::Box trakLoopPeek;
timeScale = 1;
//for all in trak
for (uint32_t j = 0; j < trakBox.getContentCount(); j++){
trakLoopPeek = MP4::Box(trakBox.getContent(j).asBox(),false);
std::string trakBoxType = trakLoopPeek.getType();
if (trakBoxType == "mdia"){//fi tkhd & if mdia
MP4::Box mdiaLoopPeek;
//for all in mdia
for (uint32_t k = 0; k < ((MP4::MDIA&)trakLoopPeek).getContentCount(); k++){
mdiaLoopPeek = MP4::Box(((MP4::MDIA&)trakLoopPeek).getContent(k).asBox(),false);
std::string mdiaBoxType = mdiaLoopPeek.getType();
if (mdiaBoxType == "mdhd"){
timeScale = ((MP4::MDHD&)mdiaLoopPeek).getTimeScale();
}else if (mdiaBoxType == "minf"){//fi hdlr
//for all in minf
//get all boxes: stco stsz,stss
MP4::Box minfLoopPeek;
for (uint32_t l = 0; l < ((MP4::MINF&)mdiaLoopPeek).getContentCount(); l++){
minfLoopPeek = MP4::Box(((MP4::MINF&)mdiaLoopPeek).getContent(l).asBox(),false);
std::string minfBoxType = minfLoopPeek.getType();
///\todo more stuff here
if (minfBoxType == "stbl"){
MP4::Box stblLoopPeek;
for (uint32_t m = 0; m < ((MP4::STBL&)minfLoopPeek).getContentCount(); m++){
stblLoopPeek = MP4::Box(((MP4::STBL&)minfLoopPeek).getContent(m).asBox(),false);
std::string stblBoxType = stblLoopPeek.getType();
if (stblBoxType == "stts"){
tmp = std::string(stblLoopPeek.asBox() ,stblLoopPeek.boxedSize());
sttsBox.clear();
sttsBox.read(tmp);
}else if (stblBoxType == "ctts"){
tmp = std::string(stblLoopPeek.asBox() ,stblLoopPeek.boxedSize());
cttsBox.clear();
cttsBox.read(tmp);
}else if (stblBoxType == "stsz"){
tmp = std::string(stblLoopPeek.asBox() ,stblLoopPeek.boxedSize());
stszBox.clear();
stszBox.read(tmp);
}else if (stblBoxType == "stco" || stblBoxType == "co64"){
tmp = std::string(stblLoopPeek.asBox() ,stblLoopPeek.boxedSize());
stcoBox.clear();
stcoBox.read(tmp);
}else if (stblBoxType == "stsc"){
tmp = std::string(stblLoopPeek.asBox() ,stblLoopPeek.boxedSize());
stscBox.clear();
stscBox.read(tmp);
}
}//rof stbl
}//fi stbl
}//rof minf
}//fi minf
}//rof mdia
}//fi mdia
}//rof trak
}
void mp4TrackHeader::getPart(long unsigned int index, long long unsigned int & offset,unsigned int& size, long long unsigned int & timestamp, long long unsigned int & timeOffset){
if (index < sampleIndex){
sampleIndex = 0;
stscStart = 0;
}
while (stscStart < stscBox.getEntryCount()){
//check where the next index starts
unsigned long long nextSampleIndex;
if (stscStart + 1 < stscBox.getEntryCount()){
nextSampleIndex = sampleIndex + (stscBox.getSTSCEntry(stscStart+1).firstChunk - stscBox.getSTSCEntry(stscStart).firstChunk) * stscBox.getSTSCEntry(stscStart).samplesPerChunk;
}else{
nextSampleIndex = stszBox.getSampleCount();
}
//if the next one is too far, we're in the right spot
if (nextSampleIndex > index){
break;
}
sampleIndex = nextSampleIndex;
++stscStart;
}
if (sampleIndex > index){
FAIL_MSG("Could not complete seek - not in file (%llu > %lu)", sampleIndex, index);
}
long long unsigned stcoPlace = (stscBox.getSTSCEntry(stscStart).firstChunk - 1 ) + ((index - sampleIndex) / stscBox.getSTSCEntry(stscStart).samplesPerChunk);
long long unsigned stszStart = sampleIndex + (stcoPlace - (stscBox.getSTSCEntry(stscStart).firstChunk - 1)) * stscBox.getSTSCEntry(stscStart).samplesPerChunk;
//set the offset to the correct value
if (stcoBox.getType() == "co64"){
offset = ((MP4::CO64*)&stcoBox)->getChunkOffset(stcoPlace);
}else{
offset = stcoBox.getChunkOffset(stcoPlace);
}
for (int j = stszStart; j < index; j++){
offset += stszBox.getEntrySize(j);
}
if (index < deltaPos){
deltaIndex = 0;
deltaPos = 0;
deltaTotal = 0;
}
MP4::STTSEntry tmpSTTS;
while (deltaIndex < sttsBox.getEntryCount()){
tmpSTTS = sttsBox.getSTTSEntry(deltaIndex);
if ((index - deltaPos) < tmpSTTS.sampleCount){
break;
}else{
deltaTotal += tmpSTTS.sampleCount * tmpSTTS.sampleDelta;
deltaPos += tmpSTTS.sampleCount;
}
++deltaIndex;
}
timestamp = ((deltaTotal + ((index-deltaPos) * tmpSTTS.sampleDelta))*1000) / timeScale;
initialised = true;
if (index < offsetPos){
offsetIndex = 0;
offsetPos = 0;
}
MP4::CTTSEntry tmpCTTS;
while (offsetIndex < cttsBox.getEntryCount()){
tmpCTTS = cttsBox.getCTTSEntry(offsetIndex);
if ((index - offsetPos) < tmpCTTS.sampleCount){
timeOffset = (tmpCTTS.sampleOffset*1000)/timeScale;
break;
}
offsetPos += tmpCTTS.sampleCount;
++offsetIndex;
}
//next lines are common for next-getting and seeking
size = stszBox.getEntrySize(index);
}
inputMP4::inputMP4(Util::Config * cfg) : Input(cfg) {
malSize = 4;//initialise data read buffer to 0;
data = (char*)malloc(malSize);
capa["name"] = "MP4";
capa["decs"] = "Enables MP4 Input";
capa["source_match"] = "/*.mp4";
capa["priority"] = 9ll;
capa["codecs"][0u][0u].append("HEVC");
capa["codecs"][0u][0u].append("H264");
capa["codecs"][0u][0u].append("H263");
capa["codecs"][0u][0u].append("VP6");
capa["codecs"][0u][1u].append("AAC");
capa["codecs"][0u][1u].append("AC3");
capa["codecs"][0u][1u].append("MP3");
}
inputMP4::~inputMP4(){
free(data);
}
bool inputMP4::setup() {
if (config->getString("input") == "-") {
std::cerr << "Input from stdin not yet supported" << std::endl;
return false;
}
if (!config->getString("streamname").size()){
if (config->getString("output") == "-") {
std::cerr << "Output to stdout not yet supported" << std::endl;
return false;
}
}else{
if (config->getString("output") != "-") {
std::cerr << "File output in player mode not supported" << std::endl;
return false;
}
}
//open File
inFile = fopen(config->getString("input").c_str(), "r");
if (!inFile) {
return false;
}
return true;
}
bool inputMP4::readHeader() {
if (!inFile) {
INFO_MSG("inFile failed!");
return false;
}
//make trackmap here from inFile
long long unsigned int trackNo = 0;
std::string tmp;//temp string for reading boxes.
//first we get the necessary header parts
while(!feof(inFile)){
std::string boxType = MP4::readBoxType(inFile);
if (boxType=="moov"){
MP4::MOOV moovBox;
moovBox.read(inFile);
//for all box in moov
MP4::Box moovLoopPeek;
for (uint32_t i = 0; i < moovBox.getContentCount(); i++){
tmp = std::string(moovBox.getContent(i).asBox() ,moovBox.getContent(i).boxedSize());
moovLoopPeek.read(tmp);
//if trak
if (moovLoopPeek.getType() == "trak"){
//create new track entry here
trackNo ++;
headerData[trackNo].read((MP4::TRAK&)moovLoopPeek);
}
}
}else if (boxType == "erro"){
break;
}else{
if (!MP4::skipBox(inFile)){//moving on to next box
DEBUG_MSG(DLVL_FAIL,"Error in skipping box, exiting");
return false;
}
}//fi moov
}//when at the end of the file
//seek file to 0;
fseeko(inFile,0,SEEK_SET);
//See whether a separate header file exists.
DTSC::File tmpdtsh(config->getString("input") + ".dtsh");
if (tmpdtsh){
myMeta = tmpdtsh.getMeta();
return true;
}
trackNo = 0;
std::set<mp4PartBpos> BPosSet;
//Create header file from MP4 data
while(!feof(inFile)){
std::string boxType = MP4::readBoxType(inFile);
if (boxType=="moov"){
MP4::MOOV moovBox;
moovBox.read(inFile);
//for all box in moov
MP4::Box moovLoopPeek;
for (uint32_t i = 0; i < moovBox.getContentCount(); i++){
tmp = std::string(moovBox.getContent(i).asBox(), moovBox.getContent(i).boxedSize());
moovLoopPeek.read(tmp);
//if trak
if (moovLoopPeek.getType() == "trak"){
//create new track entry here
long long unsigned int trackNo = myMeta.tracks.size()+1;
myMeta.tracks[trackNo].trackID = trackNo;
MP4::Box trakLoopPeek;
unsigned long int timeScale = 1;
//for all in trak
for (uint32_t j = 0; j < ((MP4::TRAK&)moovLoopPeek).getContentCount(); j++){
tmp = std::string(((MP4::MOOV&)moovLoopPeek).getContent(j).asBox(),((MP4::MOOV&)moovLoopPeek).getContent(j).boxedSize());
trakLoopPeek.read(tmp);
std::string trakBoxType = trakLoopPeek.getType();
//note: per track: trackID codec, type (vid/aud), init
//if tkhd
if (trakBoxType == "tkhd"){
MP4::TKHD tkhdBox(0,0,0,0);///\todo: this can be done with casting
tmp = std::string(trakLoopPeek.asBox(), trakLoopPeek.boxedSize());
tkhdBox.read(tmp);
//remember stuff for decoding stuff later
if (tkhdBox.getWidth() > 0){
myMeta.tracks[trackNo].width = tkhdBox.getWidth();
myMeta.tracks[trackNo].height = tkhdBox.getHeight();
}
}else if (trakBoxType == "mdia"){//fi tkhd & if mdia
MP4::Box mdiaLoopPeek;
//for all in mdia
for (uint32_t k = 0; k < ((MP4::MDIA&)trakLoopPeek).getContentCount(); k++){
tmp = std::string(((MP4::MDIA&)trakLoopPeek).getContent(k).asBox(),((MP4::MDIA&)trakLoopPeek).getContent(k).boxedSize());
mdiaLoopPeek.read(tmp);
std::string mdiaBoxType = mdiaLoopPeek.getType();
if (mdiaBoxType == "mdhd"){
timeScale = ((MP4::MDHD&)mdiaLoopPeek).getTimeScale();
}else if (mdiaBoxType == "hdlr"){//fi mdhd
std::string handlerType = ((MP4::HDLR&)mdiaLoopPeek).getHandlerType();
if (handlerType != "vide" && handlerType !="soun"){
myMeta.tracks.erase(trackNo);
//skip meta boxes for now
break;
}
}else if (mdiaBoxType == "minf"){//fi hdlr
//for all in minf
//get all boxes: stco stsz,stss
MP4::Box minfLoopPeek;
for (uint32_t l = 0; l < ((MP4::MINF&)mdiaLoopPeek).getContentCount(); l++){
tmp = std::string(((MP4::MINF&)mdiaLoopPeek).getContent(l).asBox(),((MP4::MINF&)mdiaLoopPeek).getContent(l).boxedSize());
minfLoopPeek.read(tmp);
std::string minfBoxType = minfLoopPeek.getType();
///\todo more stuff here
if (minfBoxType == "stbl"){
MP4::Box stblLoopPeek;
MP4::STSS stssBox;
MP4::STTS sttsBox;
MP4::STSZ stszBox;
MP4::STCO stcoBox;
MP4::STSC stscBox;
for (uint32_t m = 0; m < ((MP4::STBL&)minfLoopPeek).getContentCount(); m++){
tmp = std::string(((MP4::STBL&)minfLoopPeek).getContent(m).asBox(),((MP4::STBL&)minfLoopPeek).getContent(m).boxedSize());
std::string stboxRead = tmp;
stblLoopPeek.read(tmp);
std::string stblBoxType = stblLoopPeek.getType();
if (stblBoxType == "stss"){
stssBox.read(stboxRead);
}else if (stblBoxType == "stts"){
sttsBox.read(stboxRead);
}else if (stblBoxType == "stsz"){
stszBox.read(stboxRead);
}else if (stblBoxType == "stco" || stblBoxType == "co64"){
stcoBox.read(stboxRead);
}else if (stblBoxType == "stsc"){
stscBox.read(stboxRead);
}else if (stblBoxType == "stsd"){
//check for codec in here
MP4::Box & tmpBox = ((MP4::STSD&)stblLoopPeek).getEntry(0);
std::string tmpType = tmpBox.getType();
INFO_MSG("Found track of type %s", tmpType.c_str());
if (tmpType == "avc1" || tmpType == "h264" || tmpType == "mp4v"){
myMeta.tracks[trackNo].type = "video";
myMeta.tracks[trackNo].codec = "H264";
myMeta.tracks[trackNo].width = ((MP4::VisualSampleEntry&)tmpBox).getWidth();
myMeta.tracks[trackNo].height = ((MP4::VisualSampleEntry&)tmpBox).getHeight();
MP4::Box tmpBox2 = tmpBox;
MP4::Box tmpContent = ((MP4::VisualSampleEntry&)tmpBox2).getCLAP();
if (tmpContent.getType() == "avcC"){
myMeta.tracks[trackNo].init = std::string(tmpContent.payload(),tmpContent.payloadSize());
}
tmpContent = ((MP4::VisualSampleEntry&)tmpBox2).getPASP();
if (tmpContent.getType() == "avcC"){
myMeta.tracks[trackNo].init = std::string(tmpContent.payload(),tmpContent.payloadSize());
}
}else if (tmpType == "hev1"){
myMeta.tracks[trackNo].type = "video";
myMeta.tracks[trackNo].codec = "HEVC";
myMeta.tracks[trackNo].width = ((MP4::VisualSampleEntry&)tmpBox).getWidth();
myMeta.tracks[trackNo].height = ((MP4::VisualSampleEntry&)tmpBox).getHeight();
MP4::Box tmpBox2 = ((MP4::VisualSampleEntry&)tmpBox).getCLAP();
myMeta.tracks[trackNo].init = std::string(tmpBox2.payload(),tmpBox2.payloadSize());
}else if (tmpType == "mp4a" || tmpType == "aac " || tmpType == "ac-3"){
myMeta.tracks[trackNo].type = "audio";
myMeta.tracks[trackNo].channels = ((MP4::AudioSampleEntry&)tmpBox).getChannelCount();
myMeta.tracks[trackNo].rate = (long long int)(((MP4::AudioSampleEntry&)tmpBox).getSampleRate());
if (tmpType == "ac-3"){
myMeta.tracks[trackNo].codec = "AC3";
}else{
MP4::Box esds = ((MP4::AudioSampleEntry&)tmpBox).getCodecBox();
if (((MP4::ESDS&)esds).isAAC()){
myMeta.tracks[trackNo].codec = "AAC";
myMeta.tracks[trackNo].init = ((MP4::ESDS&)esds).getInitData();
}else{
myMeta.tracks[trackNo].codec = "MP3";
}
}
myMeta.tracks[trackNo].size = 16;///\todo this might be nice to calculate from mp4 file;
//get Visual sample entry -> esds -> startcodes
}else{
myMeta.tracks.erase(trackNo);
}
}
}//rof stbl
uint64_t totaldur = 0;///\todo note: set this to begin time
mp4PartBpos BsetPart;
long long unsigned int entryNo = 0;
long long unsigned int sampleNo = 0;
MP4::STTSEntry tempSTTS;
tempSTTS = sttsBox.getSTTSEntry(entryNo);
long long unsigned int curSTSS = 0;
bool vidTrack = (myMeta.tracks[trackNo].type == "video");
//change to for over all samples
unsigned int stcoIndex = 0;
unsigned int stscIndex = 0;
unsigned int fromSTCOinSTSC = 0;
long long unsigned int tempOffset;
bool stcoIs64 = (stcoBox.getType() == "co64");
if (stcoIs64){
tempOffset = ((MP4::CO64*)&stcoBox)->getChunkOffset(0);
}else{
tempOffset = stcoBox.getChunkOffset(0);
}
long long unsigned int nextFirstChunk;
if (stscBox.getEntryCount() > 1){
nextFirstChunk = stscBox.getSTSCEntry(1).firstChunk - 1;
}else{
if (stcoIs64){
nextFirstChunk = ((MP4::CO64*)&stcoBox)->getEntryCount();
}else{
nextFirstChunk = stcoBox.getEntryCount();
}
}
for(long long unsigned int sampleIndex = 0; sampleIndex < stszBox.getSampleCount(); sampleIndex ++){
if (stcoIndex >= nextFirstChunk){//note
stscIndex ++;
if (stscIndex + 1 < stscBox.getEntryCount()){
nextFirstChunk = stscBox.getSTSCEntry(stscIndex + 1).firstChunk - 1;
}else{
if (stcoIs64){
nextFirstChunk = ((MP4::CO64*)&stcoBox)->getEntryCount();
}else{
nextFirstChunk = stcoBox.getEntryCount();
}
}
}
if (vidTrack && curSTSS < stssBox.getEntryCount() && sampleIndex + 1 == stssBox.getSampleNumber(curSTSS)){
BsetPart.keyframe = true;
curSTSS ++;
}else{
BsetPart.keyframe = false;
}
//in bpos set
BsetPart.stcoNr=stcoIndex;
//bpos = chunkoffset[samplenr] in stco
BsetPart.bpos = tempOffset;
fromSTCOinSTSC ++;
if (fromSTCOinSTSC < stscBox.getSTSCEntry(stscIndex).samplesPerChunk){//as long as we are still in this chunk
tempOffset += stszBox.getEntrySize(sampleIndex);
}else{
stcoIndex ++;
fromSTCOinSTSC = 0;
if (stcoIs64){
tempOffset = ((MP4::CO64*)&stcoBox)->getChunkOffset(stcoIndex);
}else{
tempOffset = stcoBox.getChunkOffset(stcoIndex);
}
}
//time = totaldur + stts[entry][sample]
BsetPart.time = (totaldur*1000)/timeScale;
totaldur += tempSTTS.sampleDelta;
sampleNo++;
if (sampleNo >= tempSTTS.sampleCount){
entryNo++;
sampleNo = 0;
if (entryNo < sttsBox.getEntryCount()){
tempSTTS = sttsBox.getSTTSEntry(entryNo);
}
}
//set size, that's easy
BsetPart.size = stszBox.getEntrySize(sampleIndex);
//trackid
BsetPart.trackID=trackNo;
BPosSet.insert(BsetPart);
}//while over stsc
if (vidTrack){
//something wrong with the time formula, but the answer is right for some reason
/// \todo Fix this. This makes no sense whatsoever.
if (stcoIs64){
myMeta.tracks[trackNo].fpks = (((double)(((MP4::CO64*)&stcoBox)->getEntryCount()*1000))/((totaldur*1000)/timeScale))*1000;
}else{
myMeta.tracks[trackNo].fpks = (((double)(stcoBox.getEntryCount()*1000))/((totaldur*1000)/timeScale))*1000;
}
}
}//fi stbl
}//rof minf
}//fi minf
}//rof mdia
}//fi mdia
}//rof trak
}//endif trak
}//rof moov
}else if (boxType == "erro"){
break;
}else{
if (!MP4::skipBox(inFile)){//moving on to next box
DEBUG_MSG(DLVL_FAIL,"Error in Skipping box, exiting");
return false;
}
}// if moov
}// end while file read
//for all in bpos set, find its data
clearerr(inFile);
for (std::set<mp4PartBpos>::iterator it = BPosSet.begin(); it != BPosSet.end(); it++){
if (!fseeko(inFile,it->bpos,SEEK_SET)){
if (it->size > malSize){
data = (char*)realloc(data, it->size);
malSize = it->size;
}
int tmp = fread(data, it->size, 1, inFile);
if (tmp == 1){
//add data
myMeta.update(it->time, 1, it->trackID, it->size, it->bpos, it->keyframe);
}else{
INFO_MSG("fread did not return 1, bpos: %llu size: %llu keyframe: %d error: %s", it->bpos, it->size, it->keyframe, strerror(errno));
return false;
}
}else{
INFO_MSG("fseek failed!");
return false;
}
}//rof bpos set
//outputting dtsh file
std::ofstream oFile(std::string(config->getString("input") + ".dtsh").c_str());
oFile << myMeta.toJSON().toNetPacked();
oFile.close();
return true;
}
void inputMP4::getNext(bool smart) {//get next part from track in stream
if (curPositions.empty()){
thisPacket.null();
return;
}
//pop uit set
mp4PartTime curPart = *curPositions.begin();
curPositions.erase(curPositions.begin());
bool isKeyframe = false;
if(nextKeyframe[curPart.trackID] < myMeta.tracks[curPart.trackID].keys.size()){
//checking if this is a keyframe
if (myMeta.tracks[curPart.trackID].type == "video" && (long long int) curPart.time == myMeta.tracks[curPart.trackID].keys[(nextKeyframe[curPart.trackID])].getTime()){
isKeyframe = true;
}
//if a keyframe has passed, we find the next keyframe
if (myMeta.tracks[curPart.trackID].keys[(nextKeyframe[curPart.trackID])].getTime() < (long long int)curPart.time){
nextKeyframe[curPart.trackID] ++;
}
}
if (fseeko(inFile,curPart.bpos,SEEK_SET)){
DEBUG_MSG(DLVL_FAIL,"seek unsuccessful; bpos: %llu error: %s",curPart.bpos, strerror(errno));
thisPacket.null();
return;
}
if (curPart.size > malSize){
data = (char*)realloc(data, curPart.size);
malSize = curPart.size;
}
if (fread(data, curPart.size, 1, inFile)!=1){
DEBUG_MSG(DLVL_FAIL,"read unsuccessful at %ld", ftell(inFile));
thisPacket.null();
return;
}
thisPacket.genericFill(curPart.time, curPart.offset, curPart.trackID, data, curPart.size, 0/*Note: no bpos*/, isKeyframe);
//get the next part for this track
curPart.index ++;
if (curPart.index < headerData[curPart.trackID].size()){
headerData[curPart.trackID].getPart(curPart.index, curPart.bpos, curPart.size, curPart.time, curPart.offset);
curPositions.insert(curPart);
}
}
void inputMP4::seek(int seekTime) {//seek to a point
nextKeyframe.clear();
//for all tracks
curPositions.clear();
for (std::set<unsigned long>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){
nextKeyframe[*it] = 0;
mp4PartTime addPart;
addPart.bpos = 0;
addPart.size = 0;
addPart.time = 0;
addPart.trackID = *it;
//for all indexes in those tracks
for (unsigned int i = 0; i < headerData[*it].size(); i++){
//if time > seekTime
headerData[*it].getPart(i, addPart.bpos, addPart.size, addPart.time, addPart.offset);
//check for keyframe time in myMeta and update nextKeyframe
//
if (myMeta.tracks[*it].keys[(nextKeyframe[*it])].getTime() < addPart.time){
nextKeyframe[*it] ++;
}
if (addPart.time >= seekTime){
addPart.index = i;
//use addPart thingy in time set and break
curPositions.insert(addPart);
break;
}//end if time > seektime
}//end for all indexes
}//rof all tracks
}
void inputMP4::trackSelect(std::string trackSpec) {
selectedTracks.clear();
long long int index;
while (trackSpec != "") {
index = trackSpec.find(' ');
selectedTracks.insert(atoi(trackSpec.substr(0, index).c_str()));
VERYHIGH_MSG("Added track %d, index = %lld, (index == npos) = %d", atoi(trackSpec.substr(0, index).c_str()), index, index == std::string::npos);
if (index != std::string::npos) {
trackSpec.erase(0, index + 1);
} else {
trackSpec = "";
}
}
}
}