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