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