]> git.vomp.tv Git - vompclient.git/blob - playervideo.cc
DEV var in Makefile
[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 #ifdef DEV
255 void PlayerVideo::test()
256 {
257   Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST");
258
259 /*
260
261 //  video->test();
262 */
263
264 /*
265   static int flipflop = 0;
266
267   int a;
268   if (flipflop) a = video->setAspectRatio(Video::ASPECT16X9);
269   else a = video->setAspectRatio(Video::ASPECT4X3);
270
271   flipflop = !flipflop;
272
273   printf("A = %i\n", a);
274 */
275 }
276
277 void PlayerVideo::test2()
278 {
279   Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST");
280
281 //  video->test2();
282 }
283 #endif
284
285 void PlayerVideo::setPosition(ULLONG position)
286 {
287   feedPosition = position;
288 }
289
290 void PlayerVideo::setLength(ULLONG length)
291 {
292   lastRescan = time(NULL);
293   streamLength = length;
294   Log::getInstance()->log("PlayerVideo", Log::DEBUG, "Player has received length of %llu", streamLength);
295 }
296
297 void PlayerVideo::skipForward(int seconds)
298 {
299   // skip forward 1 minute
300   Log::getInstance()->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
301
302   if (paused) togglePause();
303
304   ULLONG moveBy = seconds * 500000;
305
306   threadStop();
307   vfeed.stop();
308   afeed.stop();
309   video->stop();
310   video->reset();
311   audio->reset();
312   audio->doMuting();  // ???
313   demuxer.flush();
314   feedPosition += moveBy;
315
316 //  printf("Audio test %i\n", audio->test());
317
318   vfeed.start();
319   afeed.start();
320   threadStart();
321   audio->play();
322   video->play();
323   video->sync();
324   audio->sync();
325
326   video->pause();
327       usleep(500000); // SYNC
328   video->sync();
329   video->unPause();
330   video->sync();
331
332 }
333
334 void PlayerVideo::skipBackward(int seconds)
335 {
336   // skip forward 1 minute
337   Log::getInstance()->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
338
339   if (paused) togglePause();
340
341   ULLONG moveBy = seconds * 500000;
342
343   threadStop();
344   vfeed.stop();
345   afeed.stop();
346   video->stop();
347   audio->stop();
348   video->reset();
349   audio->reset();
350   audio->doMuting(); // ???
351   demuxer.flush();
352   if (feedPosition > moveBy) feedPosition -= moveBy;
353   vfeed.start();
354   afeed.start();
355   threadStart();
356   audio->play();
357   video->play();
358   video->sync();
359   audio->sync();
360
361   video->pause();
362       usleep(500000); // SYNC
363   video->sync();
364   video->unPause();
365   video->sync();
366
367 }
368
369 void PlayerVideo::toggleFastForward()
370 {
371   if (!initted) return;
372   if (!playing) return;
373
374   if (paused) togglePause();
375   if (fbwd) toggleFastBackward();
376
377   if (ffwd)
378   {
379     ffwd = 0;
380 //    video->unFastForward();
381
382
383     threadStop();
384     vfeed.stop();
385     afeed.stop();
386     video->stop();
387     audio->stop();
388     video->reset();
389     audio->reset();
390     demuxer.flush();
391 //    demuxer.seek();
392     vfeed.start();
393     afeed.enable();
394     afeed.start();
395     threadStart();
396     video->play();
397     audio->play();
398     video->sync();
399     audio->sync();
400
401     audio->systemMuteOff();
402
403     video->pause();
404         usleep(500000); // SYNC
405     video->sync();
406     video->unPause();
407     video->sync();
408
409 /*
410     demuxer.flushAudio();
411     audio->reset();
412     afeed.enable();
413     //video->reset();
414     audio->play();
415     video->play();
416     video->sync();
417     audio->sync();
418     audio->systemMuteOff();
419 */
420   }
421   else
422   {
423     ffwd = 1;
424     afeed.disable();
425     audio->systemMuteOn();
426     video->fastForward();
427   }
428 }
429
430 void PlayerVideo::toggleFastBackward()
431 {
432   if (!initted) return;
433   if (!playing) return;
434
435   if (paused) togglePause();
436   if (ffwd) toggleFastForward();
437
438   if (fbwd)
439   {
440     fbwd = 0;
441     afeed.enable();
442     audio->systemMuteOff();
443
444 //    threadStop();
445     feedMode = MODE_NORMAL;
446 //    threadStart();
447   }
448   else
449   {
450     fbwd = 1;
451     afeed.disable();
452     audio->systemMuteOn();
453
454     threadStop();
455     feedMode = MODE_BACKWARDS;
456     video->reset();
457     video->play();
458     demuxer.flush();
459     threadStart();
460   }
461 }
462
463 void PlayerVideo::jumpToPercent(int percent)
464 {
465   threadStop();
466   vfeed.stop();
467   afeed.stop();
468   video->stop();
469   audio->stop();
470   video->reset();
471   audio->reset();
472   demuxer.flush();
473   demuxer.seek();
474   feedPosition = streamLength * percent / 100;
475   vfeed.start();
476   afeed.start();
477   threadStart();
478   audio->play();
479   video->play();
480   video->sync();
481   audio->sync();
482
483   video->pause();
484       usleep(500000); // SYNC
485   video->sync();
486   video->unPause();
487   video->sync();
488 }
489
490
491 void PlayerVideo::call()
492 {
493   threadSignalNoLock();
494 }
495
496 // Feed thread
497
498 void PlayerVideo::threadMethod()
499 {
500   UINT thisRead;
501   UINT writeLength;
502   UINT thisWrite;
503
504   VDR* vdr = VDR::getInstance();
505
506   UINT askFor;
507   while(1)
508   {
509     thisRead = 0;
510     writeLength = 0;
511     thisWrite = 0;
512
513     threadCheckExit();
514
515     // If we havn't rescanned for a while..
516     if (isRecording && ((lastRescan + 60) < time(NULL)))
517     {
518       streamLength = vdr->rescanRecording();
519       Log::getInstance()->log("PlayerVideo", Log::DEBUG, "Rescanned and reset length: %llu", streamLength);
520       lastRescan = time(NULL);
521     }
522
523     if (streamLength) // is playing a recording
524     {
525       if (feedPosition >= streamLength) break;  // finished playback
526
527       if (startup)
528       {
529         if (startupBlockSize > streamLength)
530           askFor = streamLength; // is a very small recording!
531         else
532           askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
533       }
534       else
535       {
536         if ((feedPosition + blockSize) > streamLength) // last block of recording
537           askFor = streamLength - feedPosition;
538         else // normal
539           askFor = blockSize;
540       }
541     }
542     else // is playing live
543     {
544       if (startup)
545         askFor = startupBlockSize; // find audio streams sized block
546       else
547         askFor = blockSize; // normal
548     }
549
550     threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
551     if (!threadBuffer) break;
552
553     if (startup)
554     {
555       int a_stream = demuxer.scan(threadBuffer, thisRead);
556       demuxer.setAudioStream(a_stream);
557       Log::getInstance()->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
558       startup = 0;
559     }
560
561     if (feedMode == MODE_NORMAL)
562     {
563       feedPosition += thisRead;
564     }
565     else if (feedMode == MODE_BACKWARDS)
566     {
567       if (feedPosition >= blockSize)
568       {
569         feedPosition -= blockSize;
570         demuxer.seek();
571       }
572       else
573       {
574         // got to the start of the recording.. revert to play mode? how?
575         feedPosition += thisRead;
576       }
577     }
578
579     threadCheckExit();
580
581     while(writeLength < thisRead)
582     {
583       thisWrite = demuxer.put(threadBuffer + writeLength, thisRead - writeLength);
584       writeLength += thisWrite;
585
586       if (!thisWrite)
587       {
588 //        Log::getInstance()->log("Player", Log::DEBUG, "DEMUXER FULL!!!");
589         // demuxer is full and cant take anymore
590         threadWaitForSignal();
591 //        Log::getInstance()->log("Player", Log::DEBUG, "BACK FROM WAIT");
592       }
593
594       threadCheckExit();
595     }
596
597     free(threadBuffer);
598     threadBuffer = NULL;
599
600   }
601
602   // end of recording
603   Log::getInstance()->log("Player", Log::DEBUG, "Recording playback ends");
604   Message* m = new Message();
605   m->message = Message::STOP_PLAYBACK;
606   Log::getInstance()->log("Player", Log::DEBUG, "Posting message...");
607   commandMessageQueue->postMessage(m);
608   Log::getInstance()->log("Player", Log::DEBUG, "Message posted...");
609 }
610
611 void PlayerVideo::threadPostStopCleanup()
612 {
613   Log::getInstance()->log("Player", Log::DEBUG, "Post stop cleanup 1");
614   if (threadBuffer)
615   {
616     Log::getInstance()->log("Player", Log::DEBUG, "Post stop cleanup 2");
617     free(threadBuffer);
618     threadBuffer = NULL;
619   }
620 }