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