]> git.vomp.tv Git - vompclient.git/blob - player.cc
The end of a/v sync problems?! Probably not, but I can hope!
[vompclient.git] / player.cc
1 /*
2     Copyright 2004-2005 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "player.h"
22
23 Player::Player(MessageQueue* messageQueue)
24 : vfeed(this), afeed(this)
25 {
26   initted = 0;
27   commandMessageQueue = messageQueue;
28
29   paused = 0;
30   playing = 0;
31   ffwd = 0;
32   fbwd = 0;
33   feedPosition = 0;
34   feedMode = MODE_NORMAL;
35
36   streamLength = 0;
37   // FIXME - this might need settings back to zero for new live play depending on what is done with it
38 }
39
40 Player::~Player()
41 {
42   if (initted) shutdown();
43 }
44
45 int Player::init()
46 {
47   if (initted) return 0;
48
49   video = Video::getInstance();
50   audio = Audio::getInstance();
51
52   if (demuxer.init()) // inverted
53   {
54     Log::getInstance()->log("Player", Log::ERR, "Demuxer failed to init");
55     shutdown();
56     return 0;
57   }
58
59   vfeed.init(video->getFD());
60   afeed.init(audio->getFD());
61
62   video->stop();
63   video->blank();
64   audio->stop();
65
66   startup = 0;
67   initted = 1;
68   return 1;
69 }
70
71 int Player::shutdown()
72 {
73   if (!initted) return 0;
74   initted = 0;
75
76   Log::getInstance()->log("Player", Log::DEBUG, "Player shutdown...");
77
78   // copy of stop
79   if (playing)
80   {
81     playing = 0;
82     threadStop();
83     video->stop();
84     video->blank();
85     audio->stop();
86     vfeed.stop();
87     afeed.stop();
88     video->reset();
89     demuxer.reset();
90     feedPosition = 0;
91   }
92
93   return 1;
94 }
95
96 int Player::play()
97 {
98   if (!initted) return 0;
99
100   // If we are just paused, unpause!
101   if (paused)
102   {
103     togglePause();
104     return 1;
105   }
106
107   // If we are fast forwarding, set to normal
108   if (ffwd)
109   {
110     toggleFastForward();
111     return 1;
112   }
113
114   // If we are fast backwarding, set to normal
115   if (fbwd)
116   {
117     toggleFastBackward();
118     return 1;
119   }
120
121   // If we are already playing, bail // FIXME - resync?
122   if (playing)
123   {
124     Log::getInstance()->log("Player", Log::DEBUG, "DOING RESYNC");
125
126 /*
127     vfeed.stop();
128     afeed.stop();
129     video->reset();
130     audio->reset();
131     demuxer.flush();
132     demuxer.seek();
133     vfeed.start();
134     afeed.start();
135
136
137     video->play();
138     audio->play();
139     video->sync();
140     audio->sync();
141     call();
142 */
143
144     // resync method 2..
145
146     video->pause();
147     usleep(500000);
148     video->play();
149     video->sync();
150
151
152     return 1;
153   }
154
155   // Standard play start
156
157   audio->reset();
158   video->reset();
159   demuxer.reset();
160   startup = 1;
161
162 // ------------------------ This one works, but doesn't allow any pre-buffering.
163   threadStart();
164   vfeed.start();
165   afeed.start();
166   audio->play();
167   video->play();
168   video->sync();
169   audio->sync();
170
171   video->pause();
172       usleep(500000); // SYNC
173   video->sync();
174   video->unPause();
175   video->sync();
176
177 // ------------------------ This one doesn't work, but it should, and would allow for prebuffering.
178
179 /*
180
181   threadStart();
182   sleep(2);
183
184 //  struct timespec delay;
185 //  delay.tv_sec = 1;
186 //  delay.tv_nsec = 500000000;
187 //  nanosleep(&delay, NULL);
188
189   vfeed.start();
190   afeed.start();
191   video->play();
192   audio->play();
193   video->sync();
194   audio->sync();
195 */
196 // ------------------------------------------------------------------------------------------------
197
198   playing = 1;
199   return 1;
200 }
201
202 void Player::stop()
203 {
204   if (!initted) return;
205   if (!playing) return;
206
207   if (ffwd || fbwd)
208   {
209     ffwd = 0;
210     fbwd = 0;
211     afeed.enable();
212     video->unFastForward();
213     audio->systemMuteOff();
214     feedMode = MODE_NORMAL;
215   }
216
217   playing = 0;
218
219   threadStop();
220   video->stop();
221   video->blank();
222   audio->stop();
223   vfeed.stop();
224   afeed.stop();
225   video->reset();
226   demuxer.reset();
227
228   feedPosition = 0;
229 }
230
231 void Player::togglePause()
232 {
233   if (!initted) return;
234   if (!playing) return;
235
236   if (ffwd) toggleFastForward();
237   if (fbwd) toggleFastBackward();
238
239   if (paused)
240   {
241     video->unPause();
242     audio->unPause();
243     paused = 0;
244   }
245   else
246   {
247     video->pause();
248     audio->pause();
249     paused = 1;
250   }
251 }
252
253 void Player::test()
254 {
255   Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST");
256
257 //  video->test();
258
259 //  static int flipflop = 0;
260
261 //  if (flipflop) video->setAspectRatio(Video::ASPECT16X9);
262 //  else video->setAspectRatio(Video::ASPECT4X3);
263
264 //  flipflop = !flipflop;
265
266
267 }
268
269 void Player::test2()
270 {
271   Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST");
272
273   video->test2();
274 }
275
276 void Player::setPosition(ULLONG position)
277 {
278   feedPosition = position;
279 }
280
281 void Player::setLength(ULLONG length)
282 {
283   streamLength = length;
284   Log::getInstance()->log("Player", Log::DEBUG, "Player has received length of %llu", streamLength);
285 }
286
287 void Player::skipForward(int seconds)
288 {
289   // skip forward 1 minute
290   Log::getInstance()->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
291
292   if (paused) togglePause();
293
294   ULLONG moveBy = seconds * 500000;
295
296   threadStop();
297   vfeed.stop();
298   afeed.stop();
299   video->stop();
300   video->reset();
301   audio->reset();
302   audio->doMuting();  // ???
303   demuxer.flush();
304   feedPosition += moveBy;
305
306   printf("Audio test %i\n", audio->test());
307
308   vfeed.start();
309   afeed.start();
310   threadStart();
311   audio->play();
312   video->play();
313   video->sync();
314   audio->sync();
315
316   video->pause();
317       usleep(500000); // SYNC
318   video->sync();
319   video->unPause();
320   video->sync();
321
322 }
323
324 void Player::skipBackward(int seconds)
325 {
326   // skip forward 1 minute
327   Log::getInstance()->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
328
329   if (paused) togglePause();
330
331   ULLONG moveBy = seconds * 500000;
332
333   threadStop();
334   vfeed.stop();
335   afeed.stop();
336   video->stop();
337   audio->stop();
338   video->reset();
339   audio->reset();
340   audio->doMuting(); // ???
341   demuxer.flush();
342   if (feedPosition > moveBy) feedPosition -= moveBy;
343   vfeed.start();
344   afeed.start();
345   threadStart();
346   audio->play();
347   video->play();
348   video->sync();
349   audio->sync();
350
351   video->pause();
352       usleep(500000); // SYNC
353   video->sync();
354   video->unPause();
355   video->sync();
356
357 }
358
359 void Player::toggleFastForward()
360 {
361   if (!initted) return;
362   if (!playing) return;
363
364   if (paused) togglePause();
365   if (fbwd) toggleFastBackward();
366
367   if (ffwd)
368   {
369     ffwd = 0;
370 //    video->unFastForward();
371
372
373     threadStop();
374     vfeed.stop();
375     afeed.stop();
376     video->stop();
377     audio->stop();
378     video->reset();
379     audio->reset();
380     demuxer.flush();
381 //    demuxer.seek();
382     vfeed.start();
383     afeed.enable();
384     afeed.start();
385     threadStart();
386     video->play();
387     audio->play();
388     video->sync();
389     audio->sync();
390
391     audio->systemMuteOff();
392
393     video->pause();
394         usleep(500000); // SYNC
395     video->sync();
396     video->unPause();
397     video->sync();
398
399 /*
400     demuxer.flushAudio();
401     audio->reset();
402     afeed.enable();
403     //video->reset();
404     audio->play();
405     video->play();
406     video->sync();
407     audio->sync();
408     audio->systemMuteOff();
409 */
410   }
411   else
412   {
413     ffwd = 1;
414     afeed.disable();
415     audio->systemMuteOn();
416     video->fastForward();
417   }
418 }
419
420 void Player::toggleFastBackward()
421 {
422   if (!initted) return;
423   if (!playing) return;
424
425   if (paused) togglePause();
426   if (ffwd) toggleFastForward();
427
428   if (fbwd)
429   {
430     fbwd = 0;
431     afeed.enable();
432     audio->systemMuteOff();
433
434 //    threadStop();
435     feedMode = MODE_NORMAL;
436 //    threadStart();
437   }
438   else
439   {
440     fbwd = 1;
441     afeed.disable();
442     audio->systemMuteOn();
443
444     threadStop();
445     feedMode = MODE_BACKWARDS;
446     video->reset();
447     video->play();
448     demuxer.flush();
449     threadStart();
450   }
451 }
452
453 void Player::jumpToPercent(int percent)
454 {
455   threadStop();
456   vfeed.stop();
457   afeed.stop();
458   video->stop();
459   audio->stop();
460   video->reset();
461   audio->reset();
462   demuxer.flush();
463   demuxer.seek();
464   feedPosition = streamLength * percent / 100;
465   vfeed.start();
466   afeed.start();
467   threadStart();
468   audio->play();
469   video->play();
470   video->sync();
471   audio->sync();
472
473   video->pause();
474       usleep(500000); // SYNC
475   video->sync();
476   video->unPause();
477   video->sync();
478 }
479
480
481 void Player::call()
482 {
483   threadSignalNoLock();
484 }
485
486 // Feed thread
487
488 void Player::threadMethod()
489 {
490   UCHAR buf[blockSize];
491   int thisRead;
492   int writeLength;
493   int thisWrite;
494
495   VDR* vdr = VDR::getInstance();
496
497   int askFor;
498   while(1)
499   {
500     thisRead = 0;
501     writeLength = 0;
502     thisWrite = 0;
503
504     threadCheckExit();
505
506     // a bit hackey. this needs to be split to live and rec players
507     if (streamLength && (feedPosition >= streamLength)) break;
508     askFor = blockSize;
509     if (streamLength && ((feedPosition + blockSize) > streamLength))
510     {
511       askFor = streamLength - feedPosition;
512     }
513     thisRead = vdr->getBlock(buf, feedPosition, askFor);
514     if (startup)
515     {
516       int a_stream = demuxer.scan(buf, thisRead);
517       demuxer.setAudioStream(a_stream);
518       Log::getInstance()->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
519       startup = 0;
520     }
521
522     if (feedMode == MODE_NORMAL)
523     {
524       feedPosition += thisRead;
525     }
526     else if (feedMode == MODE_BACKWARDS)
527     {
528       if (feedPosition >= 100000)
529       {
530         feedPosition -= 100000;
531         demuxer.seek();
532       }
533       else
534       {
535         // got to the start of the recording.. revert to play mode? how?
536         feedPosition += thisRead;
537       }
538     }
539
540     threadCheckExit();
541
542     while(writeLength < thisRead)
543     {
544       thisWrite = demuxer.put(buf + writeLength, thisRead - writeLength);
545       writeLength += thisWrite;
546
547       if (!thisWrite)
548       {
549         Log::getInstance()->log("Player", Log::DEBUG, "DEMUXER FULL!!!");
550         // demuxer is full and cant take anymore
551         threadWaitForSignal();
552         Log::getInstance()->log("Player", Log::DEBUG, "BACK FROM WAIT");
553       }
554
555       threadCheckExit();
556     }
557   }
558
559   // end of recording
560   Log::getInstance()->log("Player", Log::DEBUG, "Recording playback ends");
561   Message* m = new Message();
562   m->message = Message::STOP_PLAYBACK;
563   Log::getInstance()->log("Player", Log::DEBUG, "Posting message...");
564   commandMessageQueue->postMessage(m);
565   Log::getInstance()->log("Player", Log::DEBUG, "Message posted...");
566
567
568 }