]> git.vomp.tv Git - vompclient-marten.git/blob - player.cc
Resume functionality switched to frame numbers
[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 (startFrameNum > lengthFrames) startFrameNum = 0;
289   demuxer->setFrameNum(startFrameNum);
290   if (!isRadio) demuxer->seek();
291
292   videoStartup = true;
293   threadStart();
294
295   if (isRecording)
296   {
297     logger->log("Player", Log::DEBUG, "Immediate play");
298     afeed.start();
299     vfeed.start();
300     video->sync();
301     audio->sync();
302     audio->play();
303     video->pause();
304   }
305   else // do prebuffering
306   {
307     logger->log("Player", Log::DEBUG, "Prebuffering...");
308     preBuffering = true;
309   }
310
311   playing = true;
312   return 1;
313 }
314
315 void Player::stopInt()
316 {
317   if (!initted) return;
318   if (!playing) return;
319
320   if (ffwd || fbwd)
321   {
322     ffwd = false;
323     fbwd = false;
324     afeed.enable();
325     video->unFastForward();
326     audio->systemMuteOff();
327     feedMode = MODE_NORMAL;
328   }
329
330   playing = false;
331   paused = false;
332
333   vfeed.stop();
334   afeed.stop();
335   threadStop();
336   video->stop();
337   video->blank();
338   audio->stop();
339   audio->unPause();
340   video->reset();
341   demuxer->reset();
342
343   feedPosition = 0;
344 }
345
346 void Player::togglePauseInt()
347 {
348   if (!initted) return;
349   if (!playing) return;
350
351   if (ffwd) toggleFastForwardInt();
352   if (fbwd) toggleFastBackwardInt();
353
354   if (paused)
355   {
356     video->unPause();
357     audio->unPause();
358     paused = false;
359   }
360   else
361   {
362     video->pause();
363     audio->pause();
364     paused = true;
365   }
366 }
367
368 void Player::toggleFastForwardInt()
369 {
370   if (!initted) return;
371   if (!playing) return;
372
373   if (paused) togglePauseInt();
374   if (fbwd) toggleFastBackwardInt();
375
376   if (ffwd)
377   {
378     ffwd = false;
379     threadStop();
380     vfeed.stop();
381     afeed.stop();
382     video->stop();
383     audio->stop();
384     video->reset();
385     audio->reset();
386     demuxer->flush();
387     if (!isRadio) demuxer->seek();
388
389     videoStartup = true;
390     afeed.enable();
391     afeed.start();
392     vfeed.start();
393     threadStart();
394     audio->play();
395     video->sync();
396     audio->sync();
397     audio->systemMuteOff();
398     audio->doMuting();
399     fbwd = false;
400   }
401   else
402   {
403     ffwd = true;
404 #ifndef WIN32
405     afeed.disable();
406 #endif
407     audio->systemMuteOn();
408     video->fastForward();
409   }
410 }
411
412 void Player::toggleFastBackwardInt()
413 {
414   if (!initted) return;
415   if (!playing) return;
416
417   if (paused) togglePauseInt();
418   if (ffwd) toggleFastForwardInt();
419
420   if (fbwd)
421   {
422     fbwd = false;
423     afeed.enable();
424     audio->systemMuteOff();
425
426 //    threadStop();
427     feedMode = MODE_NORMAL;
428 //    threadStart();
429   }
430   else
431   {
432     fbwd = false;
433 #ifndef WIN32
434     afeed.disable();
435 #endif
436     audio->systemMuteOn();
437
438     threadStop();
439     feedMode = MODE_BACKWARDS;
440     video->reset();
441     video->play();
442     demuxer->flush();
443     if (!isRadio) demuxer->seek();
444
445     threadStart();
446   }
447 }
448
449 void Player::skipForwardInt(int seconds)
450 {
451   logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
452   restartAtFrame(getCurrentFrameNum() + (seconds * video->getFPS()));
453 }
454
455 void Player::skipBackwardInt(int seconds)
456 {
457   logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
458   long newFrameNum = getCurrentFrameNum() - (seconds * video->getFPS());
459   if (newFrameNum < 0) newFrameNum = 0;
460   restartAtFrame(newFrameNum);
461 }
462
463 void Player::jumpToPercentInt(int percent)
464 {
465   logger->log("Player", Log::DEBUG, "JUMP TO %i%%", percent);
466   ULONG newFrame = percent * lengthFrames / 100;
467   restartAtFrame(newFrame);
468 }
469
470
471 // ----------------------------------- Internal functions
472
473 void Player::lock()
474 {
475 #ifndef WIN32
476   pthread_mutex_lock(&mutex);
477   logger->log("Player", Log::DEBUG, "LOCKED");
478
479 #else
480    WaitForSingleObject(mutex, INFINITE );
481 #endif
482 }
483
484 void Player::unLock()
485 {
486 #ifndef WIN32
487   logger->log("Player", Log::DEBUG, "UNLOCKING");
488   pthread_mutex_unlock(&mutex);
489 #else
490    ReleaseMutex(mutex);
491 #endif
492 }
493
494 void Player::restartAt(ULLONG timecode)
495 {
496   if (paused) togglePauseInt();
497   if (ffwd) toggleFastForwardInt();
498
499   ULONG wantedFrameNumber = video->timecodeToFrameNumber(timecode);
500   ULLONG newPosition = VDR::getInstance()->positionFromFrameNumber(wantedFrameNumber);
501   if (!VDR::getInstance()->isConnected()) { doConnectionLost(); return; }
502   logger->log("Player", Log::DEBUG, "wantedframe %i feedpos %llu goto %llu", wantedFrameNumber, feedPosition, newPosition);
503
504   vfeed.stop();
505   afeed.stop();
506   threadStop();
507   video->stop();
508   video->reset();
509   audio->reset();
510   demuxer->flush();
511   if (!isRadio) demuxer->seek();
512   feedPosition = newPosition;
513   demuxer->setFrameNum(wantedFrameNumber);
514   videoStartup = true;
515   afeed.start();
516   vfeed.start();
517   threadStart();
518   audio->play();
519   video->sync();
520   audio->sync();
521   audio->systemMuteOff();
522   audio->doMuting();
523   fbwd = false;
524 }
525
526 void Player::restartAtFrame(ULONG newFrame)
527 {
528   if (paused) togglePauseInt();
529   if (ffwd) toggleFastForwardInt();
530
531   ULLONG newPosition = VDR::getInstance()->positionFromFrameNumber(newFrame);
532   if (!VDR::getInstance()->isConnected()) { doConnectionLost(); return; }
533   logger->log("Player", Log::DEBUG, "wantedframe %i feedpos %llu goto %llu", newFrame, feedPosition, newPosition);
534
535   vfeed.stop();
536   afeed.stop();
537   threadStop();
538   video->stop();
539   video->reset();
540   audio->reset();
541   demuxer->flush();
542   if (!isRadio) demuxer->seek();
543   feedPosition = newPosition;
544   demuxer->setFrameNum(newFrame);
545   videoStartup = true;
546   afeed.start();
547   vfeed.start();
548   threadStart();
549   audio->play();
550   video->sync();
551   audio->sync();
552   audio->systemMuteOff();
553   audio->doMuting();
554   fbwd = false;
555 }
556
557 /*
558 void Player::setStartTS(UINT dataInBuffer)
559 {
560 #ifndef NEW_DEMUXER
561   if (isRecording && feedPosition) // (feedPosition != 0)
562   {
563     // FIXME find out how much data need to get to find a TS
564     // Need to get the actual start of the recording
565
566     UINT thisRead;
567     UCHAR* tempBuffer = VDR::getInstance()->getBlock(0, 100000, &thisRead);
568     if (!tempBuffer && !VDR::getInstance()->isConnected()) { doConnectionLost(); return; }
569     if (!tempBuffer) return;
570     if (thisRead) demuxer->findVideoPTS(tempBuffer, thisRead, &startTS);
571     free(tempBuffer);
572   }
573   else
574   {
575     demuxer->findVideoPTS(threadBuffer, dataInBuffer, &startTS);
576   }
577 #else
578   startTS=0;
579 #endif
580 }
581 */
582
583 /*
584 void Player::setEndTS()
585 {
586   logger->log("Player", Log::DEBUG, "Setting end TS");
587 #ifndef NEW_DEMUXER
588   UINT thisRead;
589   UCHAR* tempBuffer = VDR::getInstance()->getBlock((lengthBytes - 100000), 100000, &thisRead);
590   if (!tempBuffer && !VDR::getInstance()->isConnected()) { doConnectionLost(); return; }
591   if (!tempBuffer) return;
592   if (thisRead) demuxer->findVideoPTS(tempBuffer, thisRead, &endTS);
593   free(tempBuffer);
594  #else //The replacement code relias completely on VDRs timecode and not the pts
595    endTS=video->frameNumberToTimecode(
596     VDR::getInstance()->frameNumberFromPosition((lengthBytes - 100000)));
597  #endif
598   logger->log("Player", Log::DEBUG, "Set end TS");
599 }
600 */
601
602 void Player::doConnectionLost()
603 {
604   Message* m = new Message();
605   m->message = Message::CONNECTION_LOST;
606   m->to = this;
607   commandMessageQueue->postMessage(m);
608 }
609
610 // ----------------------------------- Callback
611
612 void Player::call(void* caller)
613 {
614   if (caller == demuxer)
615   {
616     logger->log("Player", Log::DEBUG, "Callback from demuxer");
617
618     if (video->getTVsize() == Video::ASPECT4X3)
619     {
620       logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
621       return;
622     }
623
624     int dxCurrentAspect = demuxer->getAspectRatio();
625     if (dxCurrentAspect == Demuxer::ASPECT_4_3)
626     {
627       logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
628       video->setAspectRatio(Video::ASPECT4X3);
629     }
630     else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
631     {
632       logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
633       video->setAspectRatio(Video::ASPECT16X9);
634     }
635     else
636     {
637       logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
638     }
639
640   }
641   else
642   {
643     if (videoStartup)
644     {
645       videoStartup = false;
646       video->reset();
647       video->play();
648       video->sync();
649       vfeed.release();
650       unLock();
651     }
652
653     threadSignalNoLock();
654   }
655 }
656
657 // ----------------------------------- Feed thread
658
659 void Player::threadMethod()
660 {
661   UINT thisRead;
662   UINT writeLength;
663   UINT thisWrite;
664   UINT preBufferTotal = 0;
665 #ifdef NEW_DEMUXER
666   ULLONG currentposition;
667 #endif
668
669   VDR* vdr = VDR::getInstance();
670
671   UINT askFor;
672   while(1)
673   {
674     thisRead = 0;
675     writeLength = 0;
676     thisWrite = 0;
677
678     threadCheckExit();
679
680     // If we havn't rescanned for a while..
681     if (isRecording && ((lastRescan + 60) < time(NULL)))
682     {
683       lengthBytes = vdr->rescanRecording(&lengthFrames);
684       if (!vdr->isConnected()) { doConnectionLost(); return; }
685       logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
686       lastRescan = time(NULL);
687 //      setEndTS();
688     }
689
690     if (lengthBytes) // is playing a recording
691     {
692       if (feedPosition >= lengthBytes) break;  // finished playback
693
694       if (startup)
695       {
696         if (startupBlockSize > lengthBytes)
697           askFor = lengthBytes; // is a very small recording!
698         else
699           askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
700       }
701       else
702       {
703         if ((feedPosition + blockSize) > lengthBytes) // last block of recording
704           askFor = lengthBytes - feedPosition;
705         else // normal
706           askFor = blockSize;
707       }
708     }
709     else // is playing live
710     {
711       if (startup)
712         askFor = startupBlockSize; // find audio streams sized block
713       else
714         askFor = blockSize; // normal
715     }
716
717     threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
718 #ifdef NEW_DEMUXER
719   currentposition=feedPosition;
720  #endif
721     if (!vdr->isConnected())
722     {
723       doConnectionLost();
724       return;
725     }
726
727     if (!threadBuffer) break;
728
729     if (startup)
730     {
731       int a_stream = demuxer->scan(threadBuffer, thisRead);
732       demuxer->setAudioStream(a_stream);
733       logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
734
735 //      setStartTS(thisRead);
736
737 //      if (isRecording) setEndTS();
738
739       startup = false;
740     }
741
742     if (preBuffering)
743     {
744       preBufferTotal += thisRead;
745       if (preBufferTotal > 500000)
746       {
747         logger->log("Player", Log::DEBUG, "Got >500K, prebuffering complete");
748
749         preBuffering = false;
750         preBufferTotal = 0;
751
752         audio->sync();
753         audio->play();
754         video->sync();
755         video->pause();
756         afeed.start();
757         vfeed.start();
758 //        unLock(); // thread will be locked by play until here
759         // FIXME - see if this can segfault because it is starting threads out of the master mutex
760       }
761     }
762
763     if (feedMode == MODE_NORMAL)
764     {
765       feedPosition += thisRead;
766     }
767     else if (feedMode == MODE_BACKWARDS)
768     {
769       if (feedPosition >= blockSize)
770       {
771         feedPosition -= blockSize;
772         if (!isRadio) demuxer->seek();
773       }
774       else
775       {
776         // got to the start of the recording.. revert to play mode? how?
777         feedPosition += thisRead;
778       }
779     }
780
781     threadCheckExit();
782
783     while(writeLength < thisRead)
784     {
785 #ifndef NEW_DEMUXER
786       thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
787 #else
788       thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength,
789       currentposition+(ULLONG)writeLength);
790 #endif
791       writeLength += thisWrite;
792 //      logger->log("Player", Log::DEBUG, "Put %i to demuxer", thisWrite);
793
794       if (!thisWrite)
795       {
796 //        logger->log("Player", Log::DEBUG, "DEMUXER FULL!!!");
797         // demuxer is full and can't take anymore
798         threadLock();
799         threadWaitForSignal();
800         threadUnlock();
801 //        logger->log("Player", Log::DEBUG, "BACK FROM WAIT");
802       }
803
804       threadCheckExit();
805     }
806
807     free(threadBuffer);
808     threadBuffer = NULL;
809
810   }
811
812   // end of recording
813   logger->log("Player", Log::DEBUG, "Recording playback ends");
814
815   threadCheckExit();
816
817   Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
818   if (lengthBytes) m->message = Message::STOP_PLAYBACK;  // recording
819   else m->message = Message::STREAM_END;                  // live
820   logger->log("Player", Log::DEBUG, "Posting message to %p...", commandMessageQueue);
821   commandMessageQueue->postMessage(m);
822   logger->log("Player", Log::DEBUG, "Message posted...");
823 }
824
825 void Player::threadPostStopCleanup()
826 {
827   if (threadBuffer)
828   {
829     free(threadBuffer);
830     threadBuffer = NULL;
831   }
832 }
833
834 // ----------------------------------- Dev
835
836 #ifdef DEV
837 void Player::test1()
838 {
839   logger->log("Player", Log::DEBUG, "PLAYER TEST 1");
840   video->play();
841 //  video->setAspectRatio(Video::ASPECT4X3);
842 }
843
844 void Player::test2()
845 {
846   logger->log("Player", Log::DEBUG, "PLAYER TEST 2");
847   video->setAspectRatio(Video::ASPECT16X9);
848 }
849 #endif