diff options
Diffstat (limited to 'mpeglib/lib/mpegplay/mpegVideoLength.cpp')
-rw-r--r-- | mpeglib/lib/mpegplay/mpegVideoLength.cpp | 424 |
1 files changed, 424 insertions, 0 deletions
diff --git a/mpeglib/lib/mpegplay/mpegVideoLength.cpp b/mpeglib/lib/mpegplay/mpegVideoLength.cpp new file mode 100644 index 00000000..4befa31a --- /dev/null +++ b/mpeglib/lib/mpegplay/mpegVideoLength.cpp @@ -0,0 +1,424 @@ +/* + mpg I video/audio player plugin + Copyright (C) 1999 Martin Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published by + the Free Software Foundation. + + For more information look at the file COPYRIGHT in this package + + */ + + +#include "mpegVideoLength.h" + +#include "../mpegplay/mpegVideoStream.h" +#include "../mpegplay/gop.h" + +#include <iostream> + +using namespace std; + +#define SEARCH_SIZE 1024*1024*6 +#define SEEKWINDOW 1024*1024 + +MpegVideoLength::MpegVideoLength(InputStream* input) { + + this->input=input; + this->mpegVideoStream=new MpegVideoStream(input); + + startGOP=new GOP(); + endGOP=new GOP(); + lengthGOP=new GOP(); + mpegVideoHeader=new MpegVideoHeader(); + + + lHasStart=false; + lHasEnd=false; + lHasStream=false; + lHasResync=false; + lHasSystemStream=false; + lHasRawStream=false; + lSysLayer=false; + + mpegSystemStream=new MpegSystemStream(input); + mpegSystemHeader=new MpegSystemHeader(); + + + lCanSeek=input->seek(0); + if (lCanSeek == false) { + cout << "mpegVideoLength: stream does not support seek"<<endl; + } + realLength=input->getByteLength(); + upperEnd=realLength; + if (realLength > 1024*1024*600) { + upperEnd=1024*1024*600; + } +} + + +MpegVideoLength::~MpegVideoLength() { + delete startGOP; + delete endGOP; + delete lengthGOP; + delete mpegVideoStream; + delete mpegVideoHeader; + delete mpegSystemHeader; + delete mpegSystemStream; +} + + +/** + This long and ugly functions initialize a reader from + where to get the time informations. + All these switches deal with the problem, that we really should + have never a while loop, because this makes the decoder + thread unresponsive and can lead to deadlocks. +*/ + +int MpegVideoLength::firstInitialize() { + + // no seek means no length detection + if (lCanSeek==false) { + // no detection possible, initialized ready + input->seek(0); + return true; + } + // do we have already a reader from where to get time? + if (lHasStream == false) { + // still init system ? + if (lHasSystemStream == false) { + if (mpegSystemStream->firstInitialize(mpegSystemHeader) == true) { + lHasSystemStream=true; + + // if non system, reset everything and work on raw stream + if (mpegSystemHeader->getLayer() == _PACKET_SYSLAYER) { + lSysLayer=true; + } + if (lSysLayer == false) { + input->seek(0); + } + } + return false; + } + // if working on syslayer level we dont need the raw stream + // set it to true + if (lSysLayer == true) { + lHasRawStream=true; + } + if (lHasRawStream == false) { + if (mpegVideoStream->firstInitialize(mpegVideoHeader) == true) { + lHasRawStream=true; + } + return false; + } + lHasStream=true; + return false; + } + if (lHasStart == false) { + if (seekToStart() == true) { + lHasStart=true; + } + + // clear and jump near the end + mpegVideoStream->clear(); + int success=input->seek(upperEnd-SEARCH_SIZE); + if (success == false) { + cout << "mpegVideoStreamStream does not support seek"<<endl; + // we can't find an upper end, thus we are ready + input->seek(0); + return true; + } + return false; + } + if (lHasResync==false) { + if (lSysLayer) { + if (mpegSystemStream->nextPacket(mpegSystemHeader) == false) { + return false; + } + } else { + if (mpegVideoStream->nextGOP()==false) { + return false; + } + } + lHasResync=true; + return false; + } + if (lHasEnd == false) { + if (seekToEnd() == true) { + lHasEnd=true; + if (endGOP->substract(startGOP,lengthGOP) == false) { + cout << "substract error in final length detection"<<endl; + if (startGOP->substract(endGOP,lengthGOP) == true) { + cout << "this stream counts the time backwards"<<endl; + } else { + cout << "couldnt determine stream length"<<endl; + GOP dummy; + dummy.copyTo(lengthGOP); + } + } + // ok now we have the length but we must calculate + // the length of the whole stream + // we do not jump ofer 600 MB because this makes problems + // on some cdrom. + // here we calculate the real length if upperEnd != realEnd + int hour=lengthGOP->getHour(); + int minute=lengthGOP->getMinutes(); + long seconds=lengthGOP->getSeconds(); + seconds=seconds+minute*60+hour*60*60; + if (upperEnd > 1) { + if (realLength > upperEnd) { + float ratio=realLength/upperEnd; + float realSeconds=seconds*ratio; + hour=(int)(realSeconds/(float)(60*60)); + realSeconds=realSeconds-hour*60*60; + minute=(int)(realSeconds/60.0); + realSeconds=realSeconds-minute*60; + seconds=(int)realSeconds; + lengthGOP->setHour(hour); + lengthGOP->setMinute(minute); + lengthGOP->setSecond(seconds); + } + } + } + } + input->seek(0); + return true; +} + + +long MpegVideoLength::getLength() { + long back=0; + back=lengthGOP->getHour()*60*60; + back+=lengthGOP->getMinutes()*60; + back+=lengthGOP->getSeconds(); + + // length in second + return back; +} + + +long MpegVideoLength::getSeekPos(int seconds) { + // calculate from seconds to predicted position in stream + long back=0; + double ratio; + + ratio=(double)realLength*(double)seconds; + ratio=ratio/((double)getLength()+1.0); + back=(long)ratio; + + return back; + +} + + +// We try to search the first SEARCH_SIZE KB for a valid picture start. +int MpegVideoLength::seekToStart() { + int success; + + /** + If we are a system Layer we calculate the startGOP + by the system Packets + */ + if (lSysLayer == true) { + success=parseToPTS(startGOP); + } else { + + mpegVideoStream->hasBytes(100); + + success=parseToGOP(startGOP); + } + + if (success == false) { + cout << "picture startcode not found [START]"<<endl; + + } + // we return always true + // if we really have the start, fine, otherwithe we can + // nothing do about it, nor yet, nor in future, thus + // we have even success (in terms of failure) + return true; +} + + + +int MpegVideoLength::seekToEnd() { + int success; + + if (lSysLayer == true) { + success=parseToPTS(endGOP); + } else { + mpegVideoStream->hasBytes(100); + success=parseToGOP(endGOP); + } + if (success == false) { + cout << "picture endcode not found [END]"<<endl; + } + + return true; +} + + +int MpegVideoLength::parseToGOP(GOP* dest) { + int success; + // we try ten attempts + // and the diff between each must be (less) than one second + + int successCnt=0; + + + long maxArea=0; + long area=0; + + GOP lastGOP; + GOP currentGOP; + GOP diffGOP; + + + while(successCnt < 4) { + if (mpegVideoStream->eof()) { + return false; + } + if (input->eof() == true) { + cout << "abort"<<endl; + return false; + } + if (maxArea > SEARCH_SIZE) { + return false; + } + + + success=seekValue(GOP_START_CODE,area); + maxArea+=area; + if (success == false) { + continue; + } + + + + currentGOP.copyTo(&lastGOP); + // currentGOP.print("current"); + successCnt++; + currentGOP.processGOP(mpegVideoStream); + if (currentGOP.substract(&lastGOP,&diffGOP) == false) { + cout << "substract error"<<endl; + } + /* + currentGOP.print("current"); + lastGOP.print("last"); + diffGOP.print("diff"); + */ + if (diffGOP.getHour() != 0) { + successCnt=0; + continue; + } + if (diffGOP.getMinutes() != 0) { + successCnt=0; + continue; + } + if (diffGOP.getSeconds() > 8) { + successCnt=0; + continue; + } + + } + currentGOP.copyTo(dest); + return true; +} + + + + + + +int MpegVideoLength::seekValue(unsigned int ,long& valueSeeked) { + long start=input->getBytePosition(); + long cnt=0; + long end=start+SEEKWINDOW; + long area=0; + + // if we have not enough space we skip + // because of the mpeg frame garbage "mb_stuffing,etc..." + + if (end > upperEnd-SEEKWINDOW){ + valueSeeked=SEEKWINDOW; + return false; + } + area=end-start; + while(mpegVideoStream->nextGOP() == false) { + if (mpegVideoStream->eof()) { + return false; + } + cnt++; + if (cnt >= area) { + valueSeeked=cnt; + cout << "nothing found"<<area<<endl; + return false; + } + } + return true; +} + + + +int MpegVideoLength::parseToPTS(GOP* dest) { + + // we try ten attempts + // and the diff between each must be (less) than one second + + int successCnt=0; + + long startArea=input->getBytePosition(); + long maxArea=0; + + + double lastPTS=0; + double currentPTS=0; + double diffPTS=0; + + + while(successCnt < 4) { + if (input->eof() == true) { + cout << "abort"<<endl; + return false; + } + maxArea=input->getBytePosition()-startArea; + if (maxArea > SEARCH_SIZE) { + return false; + } + if (mpegSystemStream->nextPacket(mpegSystemHeader) == false) { + continue; + } + if (mpegSystemHeader->getPTSFlag()==false) { + continue; + } + // we have a packet + lastPTS=currentPTS; + currentPTS=mpegSystemHeader->getPTSTimeStamp(); + diffPTS=currentPTS-lastPTS; + successCnt++; + + if (diffPTS > 1.0) { + successCnt=0; + continue; + } + } + + // now put it into the gop structure + // this is the interface for the time. + // a little hack here and there.... + unsigned int hour=((long)currentPTS) / 3600; + currentPTS=currentPTS-hour*3600; + unsigned int minute=((long)currentPTS) / 60; + currentPTS=currentPTS-minute*60; + unsigned int seconds=((long)currentPTS); + + + dest->setHour(hour); + dest->setMinute(minute); + dest->setSecond(seconds); + return true; +} + + |