]> git.vomp.tv Git - vompclient-marten.git/blob - player.cc
*** empty log message ***
[vompclient-marten.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 // ----------------------------------- Called from outside, one offs or info funcs
24
25 Player::Player(MessageQueue* messageQueue, bool tIsRecording, bool tIsRadio)
26 : vfeed(this), afeed(this)
27 {
28   commandMessageQueue = messageQueue;
29   audio = Audio::getInstance();
30   video = Video::getInstance();
31   logger = Log::getInstance();
32   initted = false;
33   paused = false;
34   playing = false;
35   ffwd = false;
36   fbwd = false;
37   lengthBytes = 0;
38   lengthFrames = 0;
39   feedPosition = 0;
40   feedMode = MODE_NORMAL;
41   lastRescan = 0;
42 //  startTS = 0;
43 //  endTS = 0;
44
45   videoStartup = false;
46   preBuffering = false;
47   isRecording = tIsRecording;
48   isRadio = tIsRadio;
49
50   threadBuffer = NULL;
51
52   if (isRadio)
53   {
54     blockSize = 20000;
55     startupBlockSize = 60000;
56     video->turnVideoOff();
57   }
58   else
59   {
60     blockSize = 100000;
61     startupBlockSize = 250000;
62     video->turnVideoOn();
63   }
64 }
65
66 Player::~Player()
67 {
68   if (initted) shutdown();
69 }
70
71 int Player::init()
72 {
73   if (initted) return 0;
74 #ifndef WIN32
75   pthread_mutex_init(&mutex, NULL);
76 #else
77   mutex=CreateMutex(NULL,FALSE,NULL);
78 #endif
79
80   demuxer = new DemuxerVDR();
81   if (!demuxer) return 0;
82
83   if (!demuxer->init(this, audio, video))
84   {
85     logger->log("Player", Log::ERR, "Demuxer failed to init");
86     shutdown();
87     return 0;
88   }
89
90   vfeed.init();
91   afeed.init();
92
93   video->stop();
94   video->blank();
95   audio->stop();
96
97   initted = true;
98   return 1;
99 }
100
101 int Player::shutdown()
102 {
103   if (!initted) return 0;
104   initted = false;
105
106  // copy of stop
107   if (playing)
108   {
109     playing = false;
110     threadStop();
111     video->stop();
112     video->blank();
113     audio->stop();
114     vfeed.stop();
115
116     afeed.stop();
117     video->reset();
118     demuxer->reset();
119     feedPosition = 0;
120   }
121
122   delete demuxer;
123   demuxer = NULL;
124 #ifdef WIN32
125   CloseHandle(mutex);
126 #endif
127
128   return 1;
129 }
130
131 void Player::setStartFrame(ULONG startFrame)
132 {
133   startFrameNum = startFrame;
134   if (startFrameNum)
135   {
136     feedPosition = VDR::getInstance()->positionFromFrameNumber(startFrameNum);
137   }
138   else
139   {
140     feedPosition = 0;
141   }
142 }
143
144 void Player::setLengthBytes(ULLONG length)
145 {
146   lastRescan = time(NULL);
147   lengthBytes = length;
148   logger->log("Player", Log::DEBUG, "Player has received length bytes of %llu", lengthBytes);
149 }
150
151 void Player::setLengthFrames(ULONG length)
152 {
153   lengthFrames = length;
154   logger->log("Player", Log::DEBUG, "Player has received length frames of %lu", lengthFrames);
155 }
156
157 /*
158 ULLONG Player::getEndTS() // FIXME delme - used only by bar clocks until current frame code is done
159 {
160   long long rendTS = endTS - startTS;
161   if (rendTS < 0) rendTS += 8589934592ULL;
162   return (ULLONG)rendTS;
163 }
164 */
165
166 /*
167 hmsf Player::getEndHMSF()
168 {
169   return video->framesToHMSF(lengthFrames);
170 }
171 */
172
173 ULONG Player::getLengthFrames()
174 {
175   return lengthFrames;
176 }
177
178 ULONG Player::getCurrentFrameNum()
179 {
180   if (startup) return 0;
181   return demuxer->getFrameNumFromPTS(video->getCurrentTimestamp());
182 }
183
184 // ----------------------------------- Externally called events
185
186 int Player::play()
187 {
188   lock();
189   bool doUnlock = false;
190   int result = playInt(&doUnlock);
191   if (doUnlock) unLock();
192   return result;
193 }
194
195 void Player::stop()
196 {
197   lock();
198   stopInt();
199   unLock();
200 }
201
202 void Player::togglePause()
203 {
204   lock();
205   togglePauseInt();
206   unLock();
207 }
208
209 void Player::toggleFastForward()
210 {
211   lock();
212   toggleFastForwardInt();
213   unLock();
214 }
215
216 void Player::toggleFastBackward()
217 {
218   lock();
219   toggleFastBackwardInt();
220   unLock();
221 }
222
223 void Player::jumpToPercent(int percent)
224 {
225   lock();
226   jumpToPercentInt(percent);
227 //  unLock(); - let thread unlock this
228 }
229
230 void Player::skipForward(int seconds)
231 {
232   lock();
233   skipForwardInt(seconds);
234 //  unLock(); - let thread unlock this
235 }
236
237 void Player::skipBackward(int seconds)
238 {
239   lock();
240   skipBackwardInt(seconds);
241 //  unLock(); - let thread unlock this
242 }
243
244 // ----------------------------------- Implementations called events
245
246
247 int Player::playInt(bool* doUnlock)
248 {
249   if (!initted) return 0;
250
251   // If we are just paused, unpause!
252   if (paused)
253   {
254     togglePauseInt();
255     *doUnlock = true;
256     return 1;
257   }
258
259   // If we are fast forwarding, set to normal
260   if (ffwd)
261   {
262     toggleFastForwardInt();
263     return 1;
264   }
265
266   // If we are fast backwarding, set to normal
267   if (fbwd)
268   {
269     toggleFastBackwardInt();
270     return 1;
271   }
272
273   // If we are already playing, ignore. no resyncing to do now!
274   if (playing)
275   {
276     *doUnlock = true;
277     return 1;
278   }
279
280   // Standard play start
281   logger->log("Player", Log::DEBUG, "Standard play start");
282
283   startup = true;
284
285   audio->reset();
286   video->reset();
287   demuxer->reset();
288   if (isRecording)
289   {
290     if (startFrameNum > lengthFrames) startFrameNum = 0;
291     demuxer->setFrameNum(startFrameNum);
292   }
293   if (!isRadio) demuxer->seek();
294
295   videoStartup = true;
296   threadStart();
297
298   if (isRecording)
299   {
300     logger->log("Player", Log::DEBUG, "Immediate play");
301     afeed.start();
302     vfeed.start();
303     video->sync();
304     audio->sync();
305     audio->play();
306     video->pause();
307   }
308   else // do prebuffering
309   {
310     logger->log("Player", Log::DEBUG, "Prebuffering...");
311     preBuffering = true;
312   }
313
314   playing = true;
315   return 1;
316 }
317
318 void Player::stopInt()
319 {
320   if (!initted) return;
321   if (!playing) return;
322
323   if (ffwd || fbwd)
324   {
325     ffwd = false;
326     fbwd = false;
327     afeed.enable();
328     video->unFastForward();
329     audio->systemMuteOff();
330     feedMode = MODE_NORMAL;
331   }
332
333   playing = false;
334   paused = false;
335
336   vfeed.stop();
337   afeed.stop();
338   threadStop();
339   video->stop();
340   video->blank();
341   audio->stop();
342   audio->unPause();
343   video->reset();
344   demuxer->reset();
345
346   feedPosition = 0;
347 }
348
349 void Player::togglePauseInt()
350 {
351   if (!initted) return;
352   if (!playing) return;
353
354   if (ffwd) toggleFastForwardInt();
355   if (fbwd) toggleFastBackwardInt();
356
357   if (paused)
358   {
359     video->unPause();
360     audio->unPause();
361     paused = false;
362   }
363   else
364   {
365     video->pause();
366     audio->pause();
367     paused = true;
368   }
369 }
370
371 void Player::toggleFastForwardInt()
372 {
373   if (!initted) return;
374   if (!playing) return;
375
376   if (paused) togglePauseInt();
377   if (fbwd) toggleFastBackwardInt();
378
379   if (ffwd)
380   {
381     ffwd = false;
382     threadStop();
383     vfeed.stop();
384     afeed.stop();
385     video->stop();
386     audio->stop();
387     video->reset();
388     audio->reset();
389     demuxer->flush();
390     if (!isRadio) demuxer->seek();
391
392     videoStartup = true;
393     afeed.enable();
394     afeed.start();
395     vfeed.start();
396     threadStart();
397     audio->play();
398     video->sync();
399     audio->sync();
400     audio->systemMuteOff();
401     audio->doMuting();
402     fbwd = false;
403   }
404   else
405   {
406     ffwd = true;
407 #ifndef WIN32
408     afeed.disable();
409 #endif
410     audio->systemMuteOn();
411     video->fastForward();
412   }
413 }
414
415 void Player::toggleFastBackwardInt()
416 {
417   if (!initted) return;
418   if (!playing) return;
419
420   if (paused) togglePauseInt();
421   if (ffwd) toggleFastForwardInt();
422
423   if (fbwd)
424   {
425     fbwd = false;
426     afeed.enable();
427     audio->systemMuteOff();
428
429 //    threadStop();
430     feedMode = MODE_NORMAL;
431 //    threadStart();
432   }
433   else
434   {
435     fbwd = false;
436 #ifndef WIN32
437     afeed.disable();
438 #endif
439     audio->systemMuteOn();
440
441     threadStop();
442     feedMode = MODE_BACKWARDS;
443     video->reset();
444     video->play();
445     demuxer->flush();
446     if (!isRadio) demuxer->seek();
447
448     threadStart();
449   }
450 }
451
452 void Player::skipForwardInt(int seconds)
453 {
454   logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
455   restartAtFrame(getCurrentFrameNum() + (seconds * video->getFPS()));
456 }
457
458 void Player::skipBackwardInt(int seconds)
459 {
460   logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
461   long newFrameNum = getCurrentFrameNum() - (seconds * video->getFPS());
462   if (newFrameNum < 0) newFrameNum = 0;
463   restartAtFrame(newFrameNum);
464 }
465
466 void Player::jumpToPercentInt(int percent)
467 {
468   logger->log("Player", Log::DEBUG, "JUMP TO %i%%", percent);
469   ULONG newFrame = percent * lengthFrames / 100;
470   restartAtFrame(newFrame);
471 }
472
473
474 // ----------------------------------- Internal functions
475
476 void Player::lock()
477 {
478 #ifndef WIN32
479   pthread_mutex_lock(&mutex);
480   logger->log("Player", Log::DEBUG, "LOCKED");
481
482 #else
483    WaitForSingleObject(mutex, INFINITE );
484 #endif
485 }
486
487 void Player::unLock()
488 {
489 #ifndef WIN32
490   logger->log("Player", Log::DEBUG, "UNLOCKING");
491   pthread_mutex_unlock(&mutex);
492 #else
493    ReleaseMutex(mutex);
494 #endif
495 }
496
497 /*
498 void Player::restartAt(ULLONG timecode)
499 {
500   if (paused) togglePauseInt();
501   if (ffwd) toggleFastForwardInt();
502
503   ULONG wantedFrameNumber = video->timecodeToFrameNumber(timecode);
504   ULLONG newPosition = VDR::getInstance()->positionFromFrameNumber(wantedFrameNumber);
505   if (!VDR::getInstance()->isConnected()) { doConnectionLost(); return; }
506   logger->log("Player", Log::DEBUG, "wantedframe %i feedpos %llu goto %llu", wantedFrameNumber, feedPosition, newPosition);
507
508   vfeed.stop();
509   afeed.stop();
510   threadStop();
511   video->stop();
512   video->reset();
513   audio->reset();
514   demuxer->flush();
515   if (!isRadio) demuxer->seek();
516   feedPosition = newPosition;
517   demuxer->setFrameNum(wantedFrameNumber);
518   videoStartup = true;
519   afeed.start();
520   vfeed.start();
521   threadStart();
522   audio->play();
523   video->sync();
524   audio->sync();
525   audio->systemMuteOff();
526   audio->doMuting();
527   fbwd = false;
528 }
529 */
530
531 void Player::restartAtFrame(ULONG newFrame)
532 {
533   if (paused) togglePauseInt();
534   if (ffwd) toggleFastForwardInt();
535
536   ULLONG newPosition = VDR::getInstance()->positionFromFrameNumber(newFrame);
537   if (!VDR::getInstance()->isConnected()) { doConnectionLost(); return; }
538   logger->log("Player", Log::DEBUG, "wantedframe %i feedpos %llu goto %llu", newFrame, feedPosition, newPosition);
539
540   vfeed.stop();
541   afeed.stop();
542   threadStop();
543   video->stop();
544   video->reset();
545   audio->reset();
546   demuxer->flush();
547   if (!isRadio) demuxer->seek();
548   feedPosition = newPosition;
549   demuxer->setFrameNum(newFrame);
550   videoStartup = true;
551   afeed.start();
552   vfeed.start();
553   threadStart();
554   audio->play();
555   video->sync();
556   audio->sync();
557   audio->systemMuteOff();
558   audio->doMuting();
559   fbwd = false;
560 }
561
562 /*
563 void Player::setStartTS(UINT dataInBuffer)
564 {
565 #ifndef NEW_DEMUXER
566   if (isRecording && feedPosition) // (feedPosition != 0)
567   {
568     // FIXME find out how much data need to get to find a TS
569     // Need to get the actual start of the recording
570
571     UINT thisRead;
572     UCHAR* tempBuffer = VDR::getInstance()->getBlock(0, 100000, &thisRead);
573     if (!tempBuffer && !VDR::getInstance()->isConnected()) { doConnectionLost(); return; }
574     if (!tempBuffer) return;
575     if (thisRead) demuxer->findVideoPTS(tempBuffer, thisRead, &startTS);
576     free(tempBuffer);
577   }
578   else
579   {
580     demuxer->findVideoPTS(threadBuffer, dataInBuffer, &startTS);
581   }
582 #else
583   startTS=0;
584 #endif
585 }
586 */
587
588 /*
589 void Player::setEndTS()
590 {
591   logger->log("Player", Log::DEBUG, "Setting end TS");
592 #ifndef NEW_DEMUXER
593   UINT thisRead;
594   UCHAR* tempBuffer = VDR::getInstance()->getBlock((lengthBytes - 100000), 100000, &thisRead);
595   if (!tempBuffer && !VDR::getInstance()->isConnected()) { doConnectionLost(); return; }
596   if (!tempBuffer) return;
597   if (thisRead) demuxer->findVideoPTS(tempBuffer, thisRead, &endTS);
598   free(tempBuffer);
599  #else //The replacement code relias completely on VDRs timecode and not the pts
600    endTS=video->frameNumberToTimecode(
601     VDR::getInstance()->frameNumberFromPosition((lengthBytes - 100000)));
602  #endif
603   logger->log("Player", Log::DEBUG, "Set end TS");
604 }
605 */
606
607 void Player::doConnectionLost()
608 {
609   Message* m = new Message();
610   m->message = Message::CONNECTION_LOST;
611   m->to = this;
612   commandMessageQueue->postMessage(m);
613 }
614
615 // ----------------------------------- Callback
616
617 void Player::call(void* caller)
618 {
619   if (caller == demuxer)
620   {
621     logger->log("Player", Log::DEBUG, "Callback from demuxer");
622
623     if (video->getTVsize() == Video::ASPECT4X3)
624     {
625       logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
626       return;
627     }
628
629     int dxCurrentAspect = demuxer->getAspectRatio();
630     if (dxCurrentAspect == Demuxer::ASPECT_4_3)
631     {
632       logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
633       video->setAspectRatio(Video::ASPECT4X3);
634     }
635     else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
636     {
637       logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
638       video->setAspectRatio(Video::ASPECT16X9);
639     }
640     else
641     {
642       logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
643     }
644
645   }
646   else
647   {
648     if (videoStartup)
649     {
650       videoStartup = false;
651       video->reset();
652       video->play();
653       video->sync();
654       vfeed.release();
655       unLock();
656     }
657
658     threadSignalNoLock();
659   }
660 }
661
662 // ----------------------------------- Feed thread
663
664 void Player::threadMethod()
665 {
666   UINT thisRead;
667   UINT writeLength;
668   UINT thisWrite;
669   UINT preBufferTotal = 0;
670 #ifdef NEW_DEMUXER
671   ULLONG currentposition;
672 #endif
673
674   VDR* vdr = VDR::getInstance();
675
676   UINT askFor;
677   while(1)
678   {
679     thisRead = 0;
680     writeLength = 0;
681     thisWrite = 0;
682
683     threadCheckExit();
684
685     // If we havn't rescanned for a while..
686     if (isRecording && ((lastRescan + 60) < time(NULL)))
687     {
688       lengthBytes = vdr->rescanRecording(&lengthFrames);
689       if (!vdr->isConnected()) { doConnectionLost(); return; }
690       logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
691       lastRescan = time(NULL);
692 //      setEndTS();
693     }
694
695     if (lengthBytes) // is playing a recording
696     {
697       if (feedPosition >= lengthBytes) break;  // finished playback
698
699       if (startup)
700       {
701         if (startupBlockSize > lengthBytes)
702           askFor = lengthBytes; // is a very small recording!
703         else
704           askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
705       }
706       else
707       {
708         if ((feedPosition + blockSize) > lengthBytes) // last block of recording
709           askFor = lengthBytes - feedPosition;
710         else // normal
711           askFor = blockSize;
712       }
713     }
714     else // is playing live
715     {
716       if (startup)
717         askFor = startupBlockSize; // find audio streams sized block
718       else
719         askFor = blockSize; // normal
720     }
721
722     threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
723 #ifdef NEW_DEMUXER
724   currentposition=feedPosition;
725  #endif
726     if (!vdr->isConnected())
727     {
728       doConnectionLost();
729       return;
730     }
731
732     if (!threadBuffer) break;
733
734     if (startup)
735     {
736       int a_stream = demuxer->scan(threadBuffer, thisRead);
737       demuxer->setAudioStream(a_stream);
738       logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
739
740 //      setStartTS(thisRead);
741
742 //      if (isRecording) setEndTS();
743
744       startup = false;
745     }
746
747     if (preBuffering)
748     {
749       preBufferTotal += thisRead;
750       if (preBufferTotal > 500000)
751       {
752         logger->log("Player", Log::DEBUG, "Got >500K, prebuffering complete");
753
754         preBuffering = false;
755         preBufferTotal = 0;
756
757         audio->sync();
758         audio->play();
759         video->sync();
760         video->pause();
761         afeed.start();
762         vfeed.start();
763 //        unLock(); // thread will be locked by play until here
764         // FIXME - see if this can segfault because it is starting threads out of the master mutex
765       }
766     }
767
768     if (feedMode == MODE_NORMAL)
769     {
770       feedPosition += thisRead;
771     }
772     else if (feedMode == MODE_BACKWARDS)
773     {
774       if (feedPosition >= blockSize)
775       {
776         feedPosition -= blockSize;
777         if (!isRadio) demuxer->seek();
778       }
779       else
780       {
781         // got to the start of the recording.. revert to play mode? how?
782         feedPosition += thisRead;
783       }
784     }
785
786     threadCheckExit();
787
788     while(writeLength < thisRead)
789     {
790 #ifndef NEW_DEMUXER
791       thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
792 #else
793       thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength,
794       currentposition+(ULLONG)writeLength);
795 #endif
796       writeLength += thisWrite;
797 //      logger->log("Player", Log::DEBUG, "Put %i to demuxer", thisWrite);
798
799       if (!thisWrite)
800       {
801 //        logger->log("Player", Log::DEBUG, "DEMUXER FULL!!!");
802         // demuxer is full and can't take anymore
803         threadLock();
804         threadWaitForSignal();
805         threadUnlock();
806 //        logger->log("Player", Log::DEBUG, "BACK FROM WAIT");
807       }
808
809       threadCheckExit();
810     }
811
812     free(threadBuffer);
813     threadBuffer = NULL;
814
815   }
816
817   // end of recording
818   logger->log("Player", Log::DEBUG, "Recording playback ends");
819
820   threadCheckExit();
821
822   Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
823   if (lengthBytes) m->message = Message::STOP_PLAYBACK;  // recording
824   else m->message = Message::STREAM_END;                  // live
825   logger->log("Player", Log::DEBUG, "Posting message to %p...", commandMessageQueue);
826   commandMessageQueue->postMessage(m);
827   logger->log("Player", Log::DEBUG, "Message posted...");
828 }
829
830 void Player::threadPostStopCleanup()
831 {
832   if (threadBuffer)
833   {
834     free(threadBuffer);
835     threadBuffer = NULL;
836   }
837 }
838
839 // ----------------------------------- Dev
840
841 #ifdef DEV
842 void Player::test1()
843 {
844   logger->log("Player", Log::DEBUG, "PLAYER TEST 1");
845   video->play();
846 //  video->setAspectRatio(Video::ASPECT4X3);
847 }
848
849 void Player::test2()
850 {
851   logger->log("Player", Log::DEBUG, "PLAYER TEST 2");
852   video->setAspectRatio(Video::ASPECT16X9);
853 }
854 #endif