2
mpg I video/audio player plugin
3
Copyright (C) 1999 Martin Vogt
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU Library General Public License as published by
7
the Free Software Foundation.
9
For more information look at the file COPYRIGHT in this package
14
#include "mpegVideoLength.h"
16
#include "../mpegplay/mpegVideoStream.h"
17
#include "../mpegplay/gop.h"
20
#define SEARCH_SIZE 1024*1024*6
21
#define SEEKWINDOW 1024*1024
23
MpegVideoLength::MpegVideoLength(InputStream* input) {
26
this->mpegVideoStream=new MpegVideoStream(input);
31
mpegVideoHeader=new MpegVideoHeader();
38
lHasSystemStream=false;
42
mpegSystemStream=new MpegSystemStream(input);
43
mpegSystemHeader=new MpegSystemHeader();
46
lCanSeek=input->seek(0);
47
if (lCanSeek == false) {
48
cout << "mpegVideoLength: stream does not support seek"<<endl;
50
realLength=input->getByteLength();
52
if (realLength > 1024*1024*600) {
53
upperEnd=1024*1024*600;
58
MpegVideoLength::~MpegVideoLength() {
62
delete mpegVideoStream;
63
delete mpegVideoHeader;
64
delete mpegSystemHeader;
65
delete mpegSystemStream;
70
This long and ugly functions initialize a reader from
71
where to get the time informations.
72
All these switches deal with the problem, that we really should
73
have never a while loop, because this makes the decoder
74
thread unresponsive and can lead to deadlocks.
77
int MpegVideoLength::firstInitialize() {
79
// no seek means no length detection
80
if (lCanSeek==false) {
81
// no detection possible, initialized ready
85
// do we have already a reader from where to get time?
86
if (lHasStream == false) {
87
// still init system ?
88
if (lHasSystemStream == false) {
89
if (mpegSystemStream->firstInitialize(mpegSystemHeader) == true) {
90
lHasSystemStream=true;
92
// if non system, reset everything and work on raw stream
93
if (mpegSystemHeader->getLayer() == _PACKET_SYSLAYER) {
96
if (lSysLayer == false) {
102
// if working on syslayer level we dont need the raw stream
104
if (lSysLayer == true) {
107
if (lHasRawStream == false) {
108
if (mpegVideoStream->firstInitialize(mpegVideoHeader) == true) {
116
if (lHasStart == false) {
117
if (seekToStart() == true) {
121
// clear and jump near the end
122
mpegVideoStream->clear();
123
int success=input->seek(upperEnd-SEARCH_SIZE);
124
if (success == false) {
125
cout << "mpegVideoStreamStream does not support seek"<<endl;
126
// we can't find an upper end, thus we are ready
132
if (lHasResync==false) {
134
if (mpegSystemStream->nextPacket(mpegSystemHeader) == false) {
138
if (mpegVideoStream->nextGOP()==false) {
145
if (lHasEnd == false) {
146
if (seekToEnd() == true) {
148
if (endGOP->substract(startGOP,lengthGOP) == false) {
149
cout << "substract error in final length detection"<<endl;
150
if (startGOP->substract(endGOP,lengthGOP) == true) {
151
cout << "this stream counts the time backwards"<<endl;
153
cout << "couldnt determine stream length"<<endl;
155
dummy.copyTo(lengthGOP);
158
// ok now we have the length but we must calculate
159
// the length of the whole stream
160
// we do not jump ofer 600 MB because this makes problems
162
// here we calculate the real length if upperEnd != realEnd
163
int hour=lengthGOP->getHour();
164
int minute=lengthGOP->getMinutes();
165
long seconds=lengthGOP->getSeconds();
166
seconds=seconds+minute*60+hour*60*60;
168
if (realLength > upperEnd) {
169
float ratio=realLength/upperEnd;
170
float realSeconds=seconds*ratio;
171
hour=(int)(realSeconds/(float)(60*60));
172
realSeconds=realSeconds-hour*60*60;
173
minute=(int)(realSeconds/60.0);
174
realSeconds=realSeconds-minute*60;
175
seconds=(int)realSeconds;
176
lengthGOP->setHour(hour);
177
lengthGOP->setMinute(minute);
178
lengthGOP->setSecond(seconds);
188
long MpegVideoLength::getLength() {
190
back=lengthGOP->getHour()*60*60;
191
back+=lengthGOP->getMinutes()*60;
192
back+=lengthGOP->getSeconds();
199
long MpegVideoLength::getSeekPos(int seconds) {
200
// calculate from seconds to predicted position in stream
204
ratio=(double)realLength*(double)seconds;
205
ratio=ratio/((double)getLength()+1.0);
213
// We try to search the first SEARCH_SIZE KB for a valid picture start.
214
int MpegVideoLength::seekToStart() {
218
If we are a system Layer we calculate the startGOP
219
by the system Packets
221
if (lSysLayer == true) {
222
success=parseToPTS(startGOP);
225
mpegVideoStream->hasBytes(100);
227
success=parseToGOP(startGOP);
230
if (success == false) {
231
cout << "picture startcode not found [START]"<<endl;
234
// we return always true
235
// if we really have the start, fine, otherwithe we can
236
// nothing do about it, nor yet, nor in future, thus
237
// we have even success (in terms of failure)
243
int MpegVideoLength::seekToEnd() {
246
if (lSysLayer == true) {
247
success=parseToPTS(endGOP);
249
mpegVideoStream->hasBytes(100);
250
success=parseToGOP(endGOP);
252
if (success == false) {
253
cout << "picture endcode not found [END]"<<endl;
260
int MpegVideoLength::parseToGOP(GOP* dest) {
262
// we try ten attempts
263
// and the diff between each must be (less) than one second
276
while(successCnt < 4) {
277
if (mpegVideoStream->eof()) {
280
if (input->eof() == true) {
281
cout << "abort"<<endl;
284
if (maxArea > SEARCH_SIZE) {
289
success=seekValue(GOP_START_CODE,area);
291
if (success == false) {
297
currentGOP.copyTo(&lastGOP);
298
// currentGOP.print("current");
300
currentGOP.processGOP(mpegVideoStream);
301
if (currentGOP.substract(&lastGOP,&diffGOP) == false) {
302
cout << "substract error"<<endl;
305
currentGOP.print("current");
306
lastGOP.print("last");
307
diffGOP.print("diff");
309
if (diffGOP.getHour() != 0) {
313
if (diffGOP.getMinutes() != 0) {
317
if (diffGOP.getSeconds() > 8) {
323
currentGOP.copyTo(dest);
332
int MpegVideoLength::seekValue(unsigned int ,long& valueSeeked) {
333
long start=input->getBytePosition();
335
long end=start+SEEKWINDOW;
338
// if we have not enought space we skip
339
// because of the mpeg frame garbage "mb_stuffing,etc..."
341
if (end > upperEnd-SEEKWINDOW){
342
valueSeeked=SEEKWINDOW;
346
while(mpegVideoStream->nextGOP() == false) {
347
if (mpegVideoStream->eof()) {
353
cout << "nothing found"<<area<<endl;
362
int MpegVideoLength::parseToPTS(GOP* dest) {
364
// we try ten attempts
365
// and the diff between each must be (less) than one second
369
long startArea=input->getBytePosition();
378
while(successCnt < 4) {
379
if (input->eof() == true) {
380
cout << "abort"<<endl;
383
maxArea=input->getBytePosition()-startArea;
384
if (maxArea > SEARCH_SIZE) {
387
if (mpegSystemStream->nextPacket(mpegSystemHeader) == false) {
390
if (mpegSystemHeader->getPTSFlag()==false) {
395
currentPTS=mpegSystemHeader->getPTSTimeStamp();
396
diffPTS=currentPTS-lastPTS;
405
// now put it into the gop structure
406
// this is the interface for the time.
407
// a little hack here and there....
408
unsigned int hour=((long)currentPTS) / 3600;
409
currentPTS=currentPTS-hour*3600;
410
unsigned int minute=((long)currentPTS) / 60;
411
currentPTS=currentPTS-minute*60;
412
unsigned int seconds=((long)currentPTS);
416
dest->setMinute(minute);
417
dest->setSecond(seconds);