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