]> git.vomp.tv Git - vompclient.git/blob - playervideo.cc
*** empty log message ***
[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)
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
40 PlayerVideo::~PlayerVideo()
41 {
42   if (initted) shutdown();
43 }
44
45 int PlayerVideo::init()
46 {
47   if (initted) return 0;
48
49   video = Video::getInstance();
50
51   if (!demuxer.init(this))
52   {
53     logger->log("Player", Log::ERR, "Demuxer failed to init");
54     shutdown();
55     return 0;
56   }
57
58   vfeed.init(video->getFD());
59   afeed.init(audio->getFD());
60
61   video->stop();
62   video->blank();
63   audio->stop();
64
65   startup = 0;
66   initted = 1;
67   return 1;
68 }
69
70 int PlayerVideo::shutdown()
71 {
72   if (!initted) return 0;
73   initted = 0;
74
75   logger->log("Player", Log::DEBUG, "Player shutdown...");
76
77   // copy of stop
78   if (playing)
79   {
80     playing = 0;
81     threadStop();
82     video->stop();
83     video->blank();
84     audio->stop();
85     vfeed.stop();
86     afeed.stop();
87     video->reset();
88     demuxer.reset();
89     feedPosition = 0;
90   }
91   logger->log("Player", Log::DEBUG, "Player shutdown done");
92
93   return 1;
94 }
95
96 int PlayerVideo::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     logger->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 PlayerVideo::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   paused = 0;
219
220   logger->log("PlayerVideo", Log::DEBUG, "Temp 1");
221   threadStop();
222   logger->log("PlayerVideo", Log::DEBUG, "Temp 2");
223   video->stop();
224   logger->log("PlayerVideo", Log::DEBUG, "Temp 3");
225   video->blank();
226   logger->log("PlayerVideo", Log::DEBUG, "Temp 4");
227   audio->stop();
228   logger->log("PlayerVideo", Log::DEBUG, "Temp 5");
229   audio->unPause();
230   logger->log("PlayerVideo", Log::DEBUG, "Temp 6");
231   vfeed.stop();
232   logger->log("PlayerVideo", Log::DEBUG, "Temp 7");
233   afeed.stop();
234   logger->log("PlayerVideo", Log::DEBUG, "Temp 8");
235   video->reset();
236   logger->log("PlayerVideo", Log::DEBUG, "Temp 9");
237   demuxer.reset();
238   logger->log("PlayerVideo", Log::DEBUG, "Temp 10");
239
240   feedPosition = 0;
241 }
242
243 void PlayerVideo::togglePause()
244 {
245   if (!initted) return;
246   if (!playing) return;
247
248   if (ffwd) toggleFastForward();
249   if (fbwd) toggleFastBackward();
250
251   if (paused)
252   {
253     video->unPause();
254     audio->unPause();
255     paused = 0;
256   }
257   else
258   {
259     video->pause();
260     audio->pause();
261     paused = 1;
262   }
263 }
264
265 void PlayerVideo::setPosition(ULLONG position)
266 {
267   feedPosition = position;
268 }
269
270 void PlayerVideo::setLength(ULLONG length)
271 {
272   lastRescan = time(NULL);
273   streamLength = length;
274   logger->log("PlayerVideo", Log::DEBUG, "Player has received length of %llu", streamLength);
275 }
276
277 void PlayerVideo::skipForward(int seconds)
278 {
279   // skip forward 1 minute
280   logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
281
282   if (paused) togglePause();
283
284   ULLONG moveBy = seconds * 500000;
285
286   threadStop();
287   vfeed.stop();
288   afeed.stop();
289   video->stop();
290   video->reset();
291   audio->reset();
292   audio->doMuting();  // ???
293   demuxer.flush();
294   feedPosition += moveBy;
295
296 //  printf("Audio test %i\n", audio->test());
297
298   vfeed.start();
299   afeed.start();
300   threadStart();
301   audio->play();
302   video->play();
303   video->sync();
304   audio->sync();
305
306   video->pause();
307       usleep(500000); // SYNC
308   video->sync();
309   video->unPause();
310   video->sync();
311
312 }
313
314 void PlayerVideo::skipBackward(int seconds)
315 {
316   // skip forward 1 minute
317   logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
318
319   if (paused) togglePause();
320
321   ULLONG moveBy = seconds * 500000;
322
323   threadStop();
324   vfeed.stop();
325   afeed.stop();
326   video->stop();
327   audio->stop();
328   video->reset();
329   audio->reset();
330   audio->doMuting(); // ???
331   demuxer.flush();
332   if (feedPosition > moveBy) feedPosition -= moveBy;
333   vfeed.start();
334   afeed.start();
335   threadStart();
336   audio->play();
337   video->play();
338   video->sync();
339   audio->sync();
340
341   video->pause();
342       usleep(500000); // SYNC
343   video->sync();
344   video->unPause();
345   video->sync();
346
347 }
348
349 void PlayerVideo::toggleFastForward()
350 {
351   if (!initted) return;
352   if (!playing) return;
353
354   if (paused) togglePause();
355   if (fbwd) toggleFastBackward();
356
357   if (ffwd)
358   {
359     ffwd = 0;
360 //    video->unFastForward();
361
362
363     threadStop();
364     vfeed.stop();
365     afeed.stop();
366     video->stop();
367     audio->stop();
368     video->reset();
369     audio->reset();
370     demuxer.flush();
371 //    demuxer.seek();
372     vfeed.start();
373     afeed.enable();
374     afeed.start();
375     threadStart();
376     video->play();
377     audio->play();
378     video->sync();
379     audio->sync();
380
381     audio->systemMuteOff();
382
383     video->pause();
384         usleep(500000); // SYNC
385     video->sync();
386     video->unPause();
387     video->sync();
388
389 /*
390     demuxer.flushAudio();
391     audio->reset();
392     afeed.enable();
393     //video->reset();
394     audio->play();
395     video->play();
396     video->sync();
397     audio->sync();
398     audio->systemMuteOff();
399 */
400   }
401   else
402   {
403     ffwd = 1;
404     afeed.disable();
405     audio->systemMuteOn();
406     video->fastForward();
407   }
408 }
409
410 void PlayerVideo::toggleFastBackward()
411 {
412   if (!initted) return;
413   if (!playing) return;
414
415   if (paused) togglePause();
416   if (ffwd) toggleFastForward();
417
418   if (fbwd)
419   {
420     fbwd = 0;
421     afeed.enable();
422     audio->systemMuteOff();
423
424 //    threadStop();
425     feedMode = MODE_NORMAL;
426 //    threadStart();
427   }
428   else
429   {
430     fbwd = 1;
431     afeed.disable();
432     audio->systemMuteOn();
433
434     threadStop();
435     feedMode = MODE_BACKWARDS;
436     video->reset();
437     video->play();
438     demuxer.flush();
439     threadStart();
440   }
441 }
442
443 void PlayerVideo::jumpToPercent(int percent)
444 {
445   threadStop();
446   vfeed.stop();
447   afeed.stop();
448   video->stop();
449   audio->stop();
450   video->reset();
451   audio->reset();
452   demuxer.flush();
453   demuxer.seek();
454   feedPosition = streamLength * percent / 100;
455   vfeed.start();
456   afeed.start();
457   threadStart();
458   audio->play();
459   video->play();
460   video->sync();
461   audio->sync();
462
463   video->pause();
464       usleep(500000); // SYNC
465   video->sync();
466   video->unPause();
467   video->sync();
468 }
469
470
471 void PlayerVideo::call(void* caller)
472 {
473   if (caller == &demuxer)
474   {
475     logger->log("Player", Log::DEBUG, "Callback from demuxer");
476
477     if (video->getTVsize() == Video::ASPECT4X3)
478     {
479       logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
480       return;
481     }
482
483     int dxCurrentAspect = demuxer.getAspectRatio();
484     if (dxCurrentAspect == Demuxer::ASPECT_4_3)
485     {
486       logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
487       video->setAspectRatio(Video::ASPECT4X3);
488     }
489     else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
490     {
491       logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
492       video->setAspectRatio(Video::ASPECT16X9);
493     }
494     else
495     {
496       logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
497     }
498
499   }
500   else
501   {
502     threadSignalNoLock();
503   }
504 }
505
506 // Feed thread
507
508 void PlayerVideo::threadMethod()
509 {
510   UINT thisRead;
511   UINT writeLength;
512   UINT thisWrite;
513
514   VDR* vdr = VDR::getInstance();
515
516   UINT askFor;
517   while(1)
518   {
519     thisRead = 0;
520     writeLength = 0;
521     thisWrite = 0;
522
523     threadCheckExit();
524
525     // If we havn't rescanned for a while..
526     if (isRecording && ((lastRescan + 60) < time(NULL)))
527     {
528       streamLength = vdr->rescanRecording();
529       Log::getInstance()->log("PlayerVideo", Log::DEBUG, "Rescanned and reset length: %llu", streamLength);
530       lastRescan = time(NULL);
531     }
532
533     if (streamLength) // is playing a recording
534     {
535       if (feedPosition >= streamLength) break;  // finished playback
536
537       if (startup)
538       {
539         if (startupBlockSize > streamLength)
540           askFor = streamLength; // is a very small recording!
541         else
542           askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
543       }
544       else
545       {
546         if ((feedPosition + blockSize) > streamLength) // last block of recording
547           askFor = streamLength - feedPosition;
548         else // normal
549           askFor = blockSize;
550       }
551     }
552     else // is playing live
553     {
554       if (startup)
555         askFor = startupBlockSize; // find audio streams sized block
556       else
557         askFor = blockSize; // normal
558     }
559
560     threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
561     if (!threadBuffer) break;
562
563     if (startup)
564     {
565       int a_stream = demuxer.scan(threadBuffer, thisRead);
566       demuxer.setAudioStream(a_stream);
567       Log::getInstance()->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
568       startup = 0;
569     }
570
571     if (feedMode == MODE_NORMAL)
572     {
573       feedPosition += thisRead;
574     }
575     else if (feedMode == MODE_BACKWARDS)
576     {
577       if (feedPosition >= blockSize)
578       {
579         feedPosition -= blockSize;
580         demuxer.seek();
581       }
582       else
583       {
584         // got to the start of the recording.. revert to play mode? how?
585         feedPosition += thisRead;
586       }
587     }
588
589     threadCheckExit();
590
591     while(writeLength < thisRead)
592     {
593       thisWrite = demuxer.put(threadBuffer + writeLength, thisRead - writeLength);
594       writeLength += thisWrite;
595
596       if (!thisWrite)
597       {
598 //        Log::getInstance()->log("Player", Log::DEBUG, "DEMUXER FULL!!!");
599         // demuxer is full and cant take anymore
600         threadWaitForSignal();
601 //        Log::getInstance()->log("Player", Log::DEBUG, "BACK FROM WAIT");
602       }
603
604       threadCheckExit();
605     }
606
607     free(threadBuffer);
608     threadBuffer = NULL;
609
610   }
611
612   // end of recording
613   Log::getInstance()->log("Player", Log::DEBUG, "Recording playback ends");
614   Message* m = new Message();
615   if (streamLength) m->message = Message::STOP_PLAYBACK;  // recording
616   else m->message = Message::STREAM_END;                  // live
617   Log::getInstance()->log("Player", Log::DEBUG, "Posting message to %p...", commandMessageQueue);
618   commandMessageQueue->postMessage(m);
619   Log::getInstance()->log("Player", Log::DEBUG, "Message posted...");
620 }
621
622 void PlayerVideo::threadPostStopCleanup()
623 {
624   Log::getInstance()->log("Player", Log::DEBUG, "Post stop cleanup 1");
625   if (threadBuffer)
626   {
627     Log::getInstance()->log("Player", Log::DEBUG, "Post stop cleanup 2");
628     free(threadBuffer);
629     threadBuffer = NULL;
630   }
631 }
632
633 #ifdef DEV
634 void PlayerVideo::test1()
635 {
636   Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST 1");
637 }
638
639 void PlayerVideo::test2()
640 {
641   Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST 2");
642 }
643 #endif