~ubuntu-branches/ubuntu/hoary/kdemultimedia/hoary

« back to all changes in this revision

Viewing changes to mpeglib/lib/mpegplay/mpegVideoLength.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Martin Schulze
  • Date: 2003-01-22 15:00:51 UTC
  • Revision ID: james.westby@ubuntu.com-20030122150051-uihwkdoxf15mi1tn
Tags: upstream-2.2.2
ImportĀ upstreamĀ versionĀ 2.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  mpg I video/audio player plugin
 
3
  Copyright (C) 1999  Martin Vogt
 
4
 
 
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.
 
8
 
 
9
  For more information look at the file COPYRIGHT in this package
 
10
 
 
11
 */
 
12
 
 
13
 
 
14
#include "mpegVideoLength.h"
 
15
 
 
16
#include "../mpegplay/mpegVideoStream.h"
 
17
#include "../mpegplay/gop.h"
 
18
 
 
19
 
 
20
#define SEARCH_SIZE 1024*1024*6
 
21
#define SEEKWINDOW  1024*1024
 
22
 
 
23
MpegVideoLength::MpegVideoLength(InputStream* input) {
 
24
 
 
25
  this->input=input;
 
26
  this->mpegVideoStream=new MpegVideoStream(input);
 
27
 
 
28
  startGOP=new GOP();
 
29
  endGOP=new GOP();
 
30
  lengthGOP=new GOP();
 
31
  mpegVideoHeader=new MpegVideoHeader();
 
32
 
 
33
 
 
34
  lHasStart=false;
 
35
  lHasEnd=false;
 
36
  lHasStream=false;
 
37
  lHasResync=false;
 
38
  lHasSystemStream=false;
 
39
  lHasRawStream=false;
 
40
  lSysLayer=false;
 
41
 
 
42
  mpegSystemStream=new MpegSystemStream(input);
 
43
  mpegSystemHeader=new MpegSystemHeader();
 
44
 
 
45
 
 
46
  lCanSeek=input->seek(0);
 
47
  if (lCanSeek == false) {
 
48
    cout << "mpegVideoLength: stream does not support seek"<<endl;
 
49
  }
 
50
  realLength=input->getByteLength();
 
51
  upperEnd=realLength;
 
52
  if (realLength > 1024*1024*600) {
 
53
    upperEnd=1024*1024*600;
 
54
  }
 
55
}
 
56
 
 
57
 
 
58
MpegVideoLength::~MpegVideoLength() {
 
59
  delete startGOP;
 
60
  delete endGOP;
 
61
  delete lengthGOP;
 
62
  delete mpegVideoStream;
 
63
  delete mpegVideoHeader;
 
64
  delete mpegSystemHeader;
 
65
  delete mpegSystemStream;
 
66
}
 
67
 
 
68
 
 
69
/**
 
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.
 
75
*/
 
76
 
 
77
int MpegVideoLength::firstInitialize() {
 
78
 
 
79
  // no seek means no length detection
 
80
  if (lCanSeek==false) {
 
81
    // no detection possible, initialized ready
 
82
    input->seek(0);
 
83
    return true;
 
84
  }
 
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;
 
91
 
 
92
        // if non system, reset everything and work on raw stream
 
93
        if (mpegSystemHeader->getLayer() == _PACKET_SYSLAYER) {
 
94
          lSysLayer=true;
 
95
        }
 
96
        if (lSysLayer == false) {
 
97
          input->seek(0);
 
98
        }
 
99
      }
 
100
      return false;
 
101
    }
 
102
    // if working on syslayer level we dont need the raw stream
 
103
    // set it to true
 
104
    if (lSysLayer == true) {
 
105
      lHasRawStream=true;
 
106
    }
 
107
    if (lHasRawStream == false) {
 
108
      if (mpegVideoStream->firstInitialize(mpegVideoHeader) == true) {
 
109
        lHasRawStream=true;
 
110
      }
 
111
      return false;
 
112
    }
 
113
    lHasStream=true;
 
114
    return false;
 
115
  }
 
116
  if (lHasStart == false) {
 
117
    if (seekToStart() == true) {
 
118
      lHasStart=true;
 
119
    }
 
120
 
 
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
 
127
      input->seek(0);
 
128
      return true;
 
129
    }
 
130
    return false;
 
131
  }
 
132
  if (lHasResync==false) {
 
133
    if (lSysLayer) {
 
134
      if (mpegSystemStream->nextPacket(mpegSystemHeader) == false) {
 
135
        return false;
 
136
      } 
 
137
    } else {
 
138
      if (mpegVideoStream->nextGOP()==false) {
 
139
        return false;
 
140
      }
 
141
    }
 
142
    lHasResync=true;
 
143
    return false;
 
144
  }
 
145
  if (lHasEnd == false) {
 
146
    if (seekToEnd() == true) {
 
147
      lHasEnd=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;
 
152
        } else {
 
153
          cout << "couldnt determine stream length"<<endl;
 
154
          GOP dummy;
 
155
          dummy.copyTo(lengthGOP);
 
156
        }
 
157
      }
 
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
 
161
      // on some cdrom.
 
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;
 
167
      if (upperEnd > 1) {
 
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);
 
179
        }
 
180
      }
 
181
    }
 
182
  }
 
183
  input->seek(0);
 
184
  return true;
 
185
}
 
186
 
 
187
 
 
188
long MpegVideoLength::getLength() {
 
189
  long back=0;
 
190
  back=lengthGOP->getHour()*60*60;
 
191
  back+=lengthGOP->getMinutes()*60;
 
192
  back+=lengthGOP->getSeconds();
 
193
 
 
194
  // length in second
 
195
  return back;
 
196
}
 
197
 
 
198
 
 
199
long MpegVideoLength::getSeekPos(int seconds) {
 
200
  // calculate from seconds to predicted position in stream
 
201
  long back=0;
 
202
  double ratio;
 
203
 
 
204
  ratio=(double)realLength*(double)seconds;
 
205
  ratio=ratio/((double)getLength()+1.0);
 
206
  back=(long)ratio;
 
207
 
 
208
  return back;
 
209
    
 
210
}
 
211
 
 
212
 
 
213
// We try to search the first SEARCH_SIZE KB for a valid picture start.
 
214
int MpegVideoLength::seekToStart() {
 
215
  int success;
 
216
 
 
217
  /**
 
218
     If we are a system Layer we calculate the startGOP
 
219
     by the system Packets
 
220
  */
 
221
  if (lSysLayer == true) {
 
222
    success=parseToPTS(startGOP);
 
223
  } else {
 
224
  
 
225
    mpegVideoStream->hasBytes(100);
 
226
 
 
227
    success=parseToGOP(startGOP);
 
228
  }
 
229
 
 
230
  if (success == false) {
 
231
    cout << "picture startcode not found [START]"<<endl;
 
232
    
 
233
  }
 
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) 
 
238
  return true;
 
239
}
 
240
 
 
241
 
 
242
 
 
243
int MpegVideoLength::seekToEnd() {
 
244
  int success;
 
245
 
 
246
  if (lSysLayer == true) {
 
247
    success=parseToPTS(endGOP);
 
248
  } else {
 
249
    mpegVideoStream->hasBytes(100);
 
250
    success=parseToGOP(endGOP);
 
251
  }
 
252
  if (success == false) {
 
253
    cout << "picture endcode not found [END]"<<endl;
 
254
  }
 
255
 
 
256
  return true;
 
257
}
 
258
 
 
259
 
 
260
int MpegVideoLength::parseToGOP(GOP* dest) {
 
261
  int success;
 
262
  // we try ten attempts
 
263
  // and the diff between each must be (less) than one second
 
264
 
 
265
  int successCnt=0;
 
266
 
 
267
 
 
268
  long maxArea=0;
 
269
  long area=0;
 
270
 
 
271
  GOP lastGOP;
 
272
  GOP currentGOP;
 
273
  GOP diffGOP;
 
274
 
 
275
 
 
276
  while(successCnt < 4) {
 
277
    if (mpegVideoStream->eof()) {
 
278
      return false;
 
279
    }
 
280
    if (input->eof() == true) {
 
281
      cout << "abort"<<endl;
 
282
      return false;
 
283
    }
 
284
    if (maxArea > SEARCH_SIZE) {
 
285
      return false;
 
286
    }
 
287
 
 
288
 
 
289
    success=seekValue(GOP_START_CODE,area);
 
290
    maxArea+=area;
 
291
    if (success == false) {
 
292
      continue;
 
293
    }
 
294
 
 
295
    
 
296
 
 
297
    currentGOP.copyTo(&lastGOP);
 
298
    //    currentGOP.print("current");
 
299
    successCnt++;
 
300
    currentGOP.processGOP(mpegVideoStream);
 
301
    if (currentGOP.substract(&lastGOP,&diffGOP) == false) {
 
302
      cout << "substract error"<<endl;
 
303
    }
 
304
    /*
 
305
    currentGOP.print("current");
 
306
    lastGOP.print("last");
 
307
    diffGOP.print("diff");
 
308
    */
 
309
    if (diffGOP.getHour() != 0) {
 
310
      successCnt=0;
 
311
      continue;
 
312
    }
 
313
    if (diffGOP.getMinutes() != 0) {
 
314
      successCnt=0;
 
315
      continue;
 
316
    }
 
317
    if (diffGOP.getSeconds() > 8) {
 
318
      successCnt=0;
 
319
      continue;
 
320
    }   
 
321
    
 
322
  }
 
323
  currentGOP.copyTo(dest);
 
324
  return true;
 
325
}
 
326
 
 
327
 
 
328
 
 
329
 
 
330
 
 
331
 
 
332
int MpegVideoLength::seekValue(unsigned int ,long& valueSeeked) {
 
333
  long start=input->getBytePosition();
 
334
  long cnt=0;
 
335
  long end=start+SEEKWINDOW;
 
336
  long area=0;
 
337
 
 
338
  // if we have not enought space we skip
 
339
  // because of the mpeg frame garbage "mb_stuffing,etc..."
 
340
 
 
341
  if (end > upperEnd-SEEKWINDOW){
 
342
    valueSeeked=SEEKWINDOW;
 
343
    return false;
 
344
  }
 
345
  area=end-start;
 
346
  while(mpegVideoStream->nextGOP() == false) {
 
347
    if (mpegVideoStream->eof()) {
 
348
      return false;
 
349
    }
 
350
    cnt++;
 
351
    if (cnt >= area) {
 
352
      valueSeeked=cnt;
 
353
      cout << "nothing found"<<area<<endl;
 
354
      return false;
 
355
    }
 
356
  }
 
357
  return true;
 
358
}
 
359
 
 
360
 
 
361
 
 
362
int MpegVideoLength::parseToPTS(GOP* dest) {
 
363
 
 
364
  // we try ten attempts
 
365
  // and the diff between each must be (less) than one second
 
366
 
 
367
  int successCnt=0;
 
368
 
 
369
  long startArea=input->getBytePosition();
 
370
  long maxArea=0;
 
371
 
 
372
 
 
373
  double lastPTS=0;
 
374
  double currentPTS=0;
 
375
  double diffPTS=0;
 
376
 
 
377
 
 
378
  while(successCnt < 4) {
 
379
    if (input->eof() == true) {
 
380
      cout << "abort"<<endl;
 
381
      return false;
 
382
    }
 
383
    maxArea=input->getBytePosition()-startArea;
 
384
    if (maxArea > SEARCH_SIZE) {
 
385
      return false;
 
386
    }
 
387
    if (mpegSystemStream->nextPacket(mpegSystemHeader) == false) {
 
388
      continue;
 
389
    }
 
390
    if (mpegSystemHeader->getPTSFlag()==false) {
 
391
      continue;
 
392
    }
 
393
    // we have a packet
 
394
    lastPTS=currentPTS;
 
395
    currentPTS=mpegSystemHeader->getPTSTimeStamp();
 
396
    diffPTS=currentPTS-lastPTS;
 
397
    successCnt++;
 
398
 
 
399
    if (diffPTS > 1.0) {
 
400
      successCnt=0;
 
401
      continue;
 
402
    }
 
403
  }
 
404
 
 
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);
 
413
 
 
414
 
 
415
  dest->setHour(hour);
 
416
  dest->setMinute(minute);
 
417
  dest->setSecond(seconds);
 
418
  return true;
 
419
}
 
420
 
 
421