]> git.vomp.tv Git - vompclient.git/blob - playervideo.cc
New timers code
[vompclient.git] / playervideo.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 "playervideo.h"
22
23 PlayerVideo::PlayerVideo(MessageQueue* messageQueue, UCHAR tIsRecording, UCHAR isRadio)
24 : vfeed(this), afeed(this)
25 {
26   commandMessageQueue = messageQueue;
27
28   logger = Log::getInstance();
29   paused = 0;
30   playing = 0;
31   ffwd = 0;
32   fbwd = 0;
33   feedPosition = 0;
34   feedMode = MODE_NORMAL;
35   isRecording = tIsRecording;
36   lastRescan = 0;
37   threadBuffer = NULL;
38
39   if (isRadio)
40   {
41     blockSize = 20000;
42     startupBlockSize = 60000;
43   }
44   else
45   {
46     blockSize = 100000;
47     startupBlockSize = 250000;
48   }
49 }
50
51 PlayerVideo::~PlayerVideo()
52 {
53   if (initted) shutdown();
54 }
55
56 int PlayerVideo::init()
57 {
58   if (initted) return 0;
59
60   video = Video::getInstance();
61
62   if (!demuxer.init(this))
63   {
64     logger->log("Player", Log::ERR, "Demuxer failed to init");
65     shutdown();
66     return 0;
67   }
68
69   vfeed.init(video->getFD());
70   afeed.init(audio->getFD());
71
72   video->stop();
73   video->blank();
74   audio->stop();
75
76   startup = 0;
77   initted = 1;
78   return 1;
79 }
80
81 int PlayerVideo::shutdown()
82 {
83   if (!initted) return 0;
84   initted = 0;
85
86   logger->log("Player", Log::DEBUG, "Player shutdown...");
87
88   // copy of stop
89   if (playing)
90   {
91     playing = 0;
92     threadStop();
93     video->stop();
94     video->blank();
95     audio->stop();
96     vfeed.stop();
97     afeed.stop();
98     video->reset();
99     demuxer.reset();
100     feedPosition = 0;
101   }
102   logger->log("Player", Log::DEBUG, "Player shutdown done");
103
104   return 1;
105 }
106
107 int PlayerVideo::play()
108 {
109   if (!initted) return 0;
110
111   // If we are just paused, unpause!
112   if (paused)
113   {
114     togglePause();
115     return 1;
116   }
117
118   // If we are fast forwarding, set to normal
119   if (ffwd)
120   {
121     toggleFastForward();
122     return 1;
123   }
124
125   // If we are fast backwarding, set to normal
126   if (fbwd)
127   {
128     toggleFastBackward();
129     return 1;
130   }
131
132   // If we are already playing, bail // FIXME - resync?
133   if (playing)
134   {
135     logger->log("Player", Log::DEBUG, "DOING RESYNC");
136
137 /*
138     vfeed.stop();
139     afeed.stop();
140     video->reset();
141     audio->reset();
142     demuxer.flush();
143     demuxer.seek();
144     vfeed.start();
145     afeed.start();
146
147
148     video->play();
149     audio->play();
150     video->sync();
151     audio->sync();
152     call();
153 */
154
155     // resync method 2..
156
157     video->pause();
158     usleep(500000);
159     video->play();
160     video->sync();
161
162
163     return 1;
164   }
165
166   // Standard play start
167
168   audio->reset();
169   video->reset();
170   demuxer.reset();
171   startup = 1;
172
173 // ------------------------ This one works, but doesn't allow any pre-buffering.
174   threadStart();
175   vfeed.start();
176   afeed.start();
177   audio->play();
178   video->play();
179   video->sync();
180   audio->sync();
181
182   video->pause();
183       usleep(500000); // SYNC
184   video->sync();
185   video->unPause();
186   video->sync();
187
188 // ------------------------ This one doesn't work, but it should, and would allow for prebuffering.
189
190 /*
191
192   threadStart();
193   sleep(2);
194
195 //  struct timespec delay;
196 //  delay.tv_sec = 1;
197 //  delay.tv_nsec = 500000000;
198 //  nanosleep(&delay, NULL);
199
200   vfeed.start();
201   afeed.start();
202   video->play();
203   audio->play();
204   video->sync();
205   audio->sync();
206 */
207 // ------------------------------------------------------------------------------------------------
208
209   playing = 1;
210   return 1;
211 }
212
213 void PlayerVideo::stop()
214 {
215   if (!initted) return;
216   if (!playing) return;
217
218   if (ffwd || fbwd)
219   {
220     ffwd = 0;
221     fbwd = 0;
222     afeed.enable();
223     video->unFastForward();
224     audio->systemMuteOff();
225     feedMode = MODE_NORMAL;
226   }
227
228   playing = 0;
229   paused = 0;
230
231   logger->log("PlayerVideo", Log::DEBUG, "Temp 1");
232   threadStop();
233   logger->log("PlayerVideo", Log::DEBUG, "Temp 2");
234   video->stop();
235   logger->log("PlayerVideo", Log::DEBUG, "Temp 3");
236   video->blank();
237   logger->log("PlayerVideo", Log::DEBUG, "Temp 4");
238   audio->stop();
239   logger->log("PlayerVideo", Log::DEBUG, "Temp 5");
240   audio->unPause();
241   logger->log("PlayerVideo", Log::DEBUG, "Temp 6");
242   vfeed.stop();
243   logger->log("PlayerVideo", Log::DEBUG, "Temp 7");
244   afeed.stop();
245   logger->log("PlayerVideo", Log::DEBUG, "Temp 8");
246   video->reset();
247   logger->log("PlayerVideo", Log::DEBUG, "Temp 9");
248   demuxer.reset();
249   logger->log("PlayerVideo", Log::DEBUG, "Temp 10");
250
251   feedPosition = 0;
252 }
253
254 void PlayerVideo::togglePause()
255 {
256   if (!initted) return;
257   if (!playing) return;
258
259   if (ffwd) toggleFastForward();
260   if (fbwd) toggleFastBackward();
261
262   if (paused)
263   {
264     video->unPause();
265     audio->unPause();
266     paused = 0;
267   }
268   else
269   {
270     video->pause();
271     audio->pause();
272     paused = 1;
273   }
274 }
275
276 void PlayerVideo::setPosition(ULLONG position)
277 {
278   feedPosition = position;
279 }
280
281 void PlayerVideo::setLength(ULLONG length)
282 {
283   lastRescan = time(NULL);
284   streamLength = length;
285   logger->log("PlayerVideo", Log::DEBUG, "Player has received length of %llu", streamLength);
286 }
287
288 void PlayerVideo::skipForward(int seconds)
289 {
290   // skip forward 1 minute
291   logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
292
293   if (paused) togglePause();
294
295   ULLONG moveBy = seconds * 500000;
296
297   threadStop();
298   vfeed.stop();
299   afeed.stop();
300   video->stop();
301   video->reset();
302   audio->reset();
303   audio->doMuting();  // ???
304   demuxer.flush();
305   feedPosition += moveBy;
306
307 //  printf("Audio test %i\n", audio->test());
308
309   vfeed.start();
310   afeed.start();
311   threadStart();
312   audio->play();
313   video->play();
314   video->sync();
315   audio->sync();
316
317   video->pause();
318       usleep(500000); // SYNC
319   video->sync();
320   video->unPause();
321   video->sync();
322
323 }
324
325 void PlayerVideo::skipBackward(int seconds)
326 {
327   // skip forward 1 minute
328   logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
329
330   if (paused) togglePause();
331
332   ULLONG moveBy = seconds * 500000;
333
334   threadStop();
335   vfeed.stop();
336   afeed.stop();
337   video->stop();
338   audio->stop();
339   video->reset();
340   audio->reset();
341   audio->doMuting(); // ???
342   demuxer.flush();
343   if (feedPosition > moveBy) feedPosition -= moveBy;
344   vfeed.start();
345   afeed.start();
346   threadStart();
347   audio->play();
348   video->play();
349   video->sync();
350   audio->sync();
351
352   video->pause();
353       usleep(500000); // SYNC
354   video->sync();
355   video->unPause();
356   video->sync();
357
358 }
359
360 void PlayerVideo::toggleFastForward()
361 {
362   if (!initted) return;
363   if (!playing) return;
364
365   if (paused) togglePause();
366   if (fbwd) toggleFastBackward();
367
368   if (ffwd)
369   {
370     ffwd = 0;
371 //    video->unFastForward();
372
373
374     threadStop();
375     vfeed.stop();
376     afeed.stop();
377     video->stop();
378     audio->stop();
379     video->reset();
380     audio->reset();
381     demuxer.flush();
382 //    demuxer.seek();
383     vfeed.start();
384     afeed.enable();
385     afeed.start();
386     threadStart();
387     video->play();
388     audio->play();
389     video->sync();
390     audio->sync();
391
392     audio->systemMuteOff();
393
394     video->pause();
395         usleep(500000); // SYNC
396     video->sync();
397     video->unPause();
398     video->sync();
399
400 /*
401     demuxer.flushAudio();
402     audio->reset();
403     afeed.enable();
404     //video->reset();
405     audio->play();
406     video->play();
407     video->sync();
408     audio->sync();
409     audio->systemMuteOff();
410 */
411   }
412   else
413   {
414     ffwd = 1;
415     afeed.disable();
416     audio->systemMuteOn();
417     video->fastForward();
418   }
419 }
420
421 void PlayerVideo::toggleFastBackward()
422 {
423   if (!initted) return;
424   if (!playing) return;
425
426   if (paused) togglePause();
427   if (ffwd) toggleFastForward();
428
429   if (fbwd)
430   {
431     fbwd = 0;
432     afeed.enable();
433     audio->systemMuteOff();
434
435 //    threadStop();
436     feedMode = MODE_NORMAL;
437 //    threadStart();
438   }
439   else
440   {
441     fbwd = 1;
442     afeed.disable();
443     audio->systemMuteOn();
444
445     threadStop();
446     feedMode = MODE_BACKWARDS;
447     video->reset();
448     video->play();
449     demuxer.flush();
450     threadStart();
451   }
452 }
453
454 void PlayerVideo::jumpToPercent(int percent)
455 {
456   threadStop();
457   vfeed.stop();
458   afeed.stop();
459   video->stop();
460   audio->stop();
461   video->reset();
462   audio->reset();
463   demuxer.flush();
464   demuxer.seek();
465   feedPosition = streamLength * percent / 100;
466   vfeed.start();
467   afeed.start();
468   threadStart();
469   audio->play();
470   video->play();
471   video->sync();
472   audio->sync();
473
474   video->pause();
475       usleep(500000); // SYNC
476   video->sync();
477   video->unPause();
478   video->sync();
479 }
480
481
482 void PlayerVideo::call(void* caller)
483 {
484   if (caller == &demuxer)
485   {
486     logger->log("Player", Log::DEBUG, "Callback from demuxer");
487
488     if (video->getTVsize() == Video::ASPECT4X3)
489     {
490       logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
491       return;
492     }
493
494     int dxCurrentAspect = demuxer.getAspectRatio();
495     if (dxCurrentAspect == Demuxer::ASPECT_4_3)
496     {
497       logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
498       video->setAspectRatio(Video::ASPECT4X3);
499     }
500     else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
501     {
502       logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
503       video->setAspectRatio(Video::ASPECT16X9);
504     }
505     else
506     {
507       logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
508     }
509
510   }
511   else
512   {
513     threadSignalNoLock();
514   }
515 }
516
517 // Feed thread
518
519 void PlayerVideo::threadMethod()
520 {
521   UINT thisRead;
522   UINT writeLength;
523   UINT thisWrite;
524
525   VDR* vdr = VDR::getInstance();
526
527   UINT askFor;
528   while(1)
529   {
530     thisRead = 0;
531     writeLength = 0;
532     thisWrite = 0;
533
534     threadCheckExit();
535
536     // If we havn't rescanned for a while..
537     if (isRecording && ((lastRescan + 60) < time(NULL)))
538     {
539       streamLength = vdr->rescanRecording();
540       Log::getInstance()->log("PlayerVideo", Log::DEBUG, "Rescanned and reset length: %llu", streamLength);
541       lastRescan = time(NULL);
542     }
543
544     if (streamLength) // is playing a recording
545     {
546       if (feedPosition >= streamLength) break;  // finished playback
547
548       if (startup)
549       {
550         if (startupBlockSize > streamLength)
551           askFor = streamLength; // is a very small recording!
552         else
553           askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
554       }
555       else
556       {
557         if ((feedPosition + blockSize) > streamLength) // last block of recording
558           askFor = streamLength - feedPosition;
559         else // normal
560           askFor = blockSize;
561       }
562     }
563     else // is playing live
564     {
565       if (startup)
566         askFor = startupBlockSize; // find audio streams sized block
567       else
568         askFor = blockSize; // normal
569     }
570
571     threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
572     if (!threadBuffer) break;
573
574     if (startup)
575     {
576       int a_stream = demuxer.scan(threadBuffer, thisRead);
577       demuxer.setAudioStream(a_stream);
578       Log::getInstance()->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
579       startup = 0;
580     }
581
582     if (feedMode == MODE_NORMAL)
583     {
584       feedPosition += thisRead;
585     }
586     else if (feedMode == MODE_BACKWARDS)
587     {
588       if (feedPosition >= blockSize)
589       {
590         feedPosition -= blockSize;
591         demuxer.seek();
592       }
593       else
594       {
595         // got to the start of the recording.. revert to play mode? how?
596         feedPosition += thisRead;
597       }
598     }
599
600     threadCheckExit();
601
602     while(writeLength < thisRead)
603     {
604       thisWrite = demuxer.put(threadBuffer + writeLength, thisRead - writeLength);
605       writeLength += thisWrite;
606
607       if (!thisWrite)
608       {
609 //        Log::getInstance()->log("Player", Log::DEBUG, "DEMUXER FULL!!!");
610         // demuxer is full and cant take anymore
611         threadLock();
612         threadWaitForSignal();
613         threadUnlock();
614 //        Log::getInstance()->log("Player", Log::DEBUG, "BACK FROM WAIT");
615       }
616
617       threadCheckExit();
618     }
619
620     free(threadBuffer);
621     threadBuffer = NULL;
622
623   }
624
625   // end of recording
626   Log::getInstance()->log("Player", Log::DEBUG, "Recording playback ends");
627   Message* m = new Message();
628   if (streamLength) m->message = Message::STOP_PLAYBACK;  // recording
629   else m->message = Message::STREAM_END;                  // live
630   Log::getInstance()->log("Player", Log::DEBUG, "Posting message to %p...", commandMessageQueue);
631   commandMessageQueue->postMessage(m);
632   Log::getInstance()->log("Player", Log::DEBUG, "Message posted...");
633 }
634
635 void PlayerVideo::threadPostStopCleanup()
636 {
637   Log::getInstance()->log("Player", Log::DEBUG, "Post stop cleanup 1");
638   if (threadBuffer)
639   {
640     Log::getInstance()->log("Player", Log::DEBUG, "Post stop cleanup 2");
641     free(threadBuffer);
642     threadBuffer = NULL;
643   }
644 }
645
646 #ifdef DEV
647 void PlayerVideo::test1()
648 {
649   Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST 1");
650 }
651
652 void PlayerVideo::test2()
653 {
654   Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST 2");
655 }
656 #endif