vdr  2.0.6
dvbplayer.c
Go to the documentation of this file.
1 /*
2  * dvbplayer.c: The DVB player
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: dvbplayer.c 2.35 2013/03/08 13:44:19 kls Exp $
8  */
9 
10 #include "dvbplayer.h"
11 #include <math.h>
12 #include <stdlib.h>
13 #include "recording.h"
14 #include "remux.h"
15 #include "ringbuffer.h"
16 #include "thread.h"
17 #include "tools.h"
18 
19 // --- cPtsIndex -------------------------------------------------------------
20 
21 #define PTSINDEX_ENTRIES 500
22 
23 class cPtsIndex {
24 private:
25  struct tPtsIndex {
26  uint32_t pts; // no need for 33 bit - some devices don't even supply the msb
27  int index;
28  };
30  int w, r;
31  int lastFound;
33 public:
34  cPtsIndex(void);
35  void Clear(void);
36  bool IsEmpty(void);
37  void Put(uint32_t Pts, int Index);
38  int FindIndex(uint32_t Pts);
39  };
40 
42 {
43  lastFound = 0;
44  Clear();
45 }
46 
47 void cPtsIndex::Clear(void)
48 {
49  cMutexLock MutexLock(&mutex);
50  w = r = 0;
51 }
52 
54 {
55  cMutexLock MutexLock(&mutex);
56  return w == r;
57 }
58 
59 void cPtsIndex::Put(uint32_t Pts, int Index)
60 {
61  cMutexLock MutexLock(&mutex);
62  pi[w].pts = Pts;
63  pi[w].index = Index;
64  w = (w + 1) % PTSINDEX_ENTRIES;
65  if (w == r)
66  r = (r + 1) % PTSINDEX_ENTRIES;
67 }
68 
69 int cPtsIndex::FindIndex(uint32_t Pts)
70 {
71  cMutexLock MutexLock(&mutex);
72  if (w == r)
73  return lastFound; // list is empty, let's not jump way off the last known position
74  uint32_t Delta = 0xFFFFFFFF;
75  int Index = -1;
76  for (int i = w; i != r; ) {
77  if (--i < 0)
78  i = PTSINDEX_ENTRIES - 1;
79  uint32_t d = pi[i].pts < Pts ? Pts - pi[i].pts : pi[i].pts - Pts;
80  if (d > 0x7FFFFFFF)
81  d = 0xFFFFFFFF - d; // handle rollover
82  if (d < Delta) {
83  Delta = d;
84  Index = pi[i].index;
85  }
86  }
87  lastFound = Index;
88  return Index;
89 }
90 
91 // --- cNonBlockingFileReader ------------------------------------------------
92 
94 private:
97  int wanted;
98  int length;
102 protected:
103  void Action(void);
104 public:
107  void Clear(void);
108  void Request(cUnbufferedFile *File, int Length);
109  int Result(uchar **Buffer);
110  bool Reading(void) { return buffer; }
111  bool WaitForDataMs(int msToWait);
112  };
113 
115 :cThread("non blocking file reader")
116 {
117  f = NULL;
118  buffer = NULL;
119  wanted = length = 0;
120  Start();
121 }
122 
124 {
125  newSet.Signal();
126  Cancel(3);
127  free(buffer);
128 }
129 
131 {
132  Lock();
133  f = NULL;
134  free(buffer);
135  buffer = NULL;
136  wanted = length = 0;
137  Unlock();
138 }
139 
141 {
142  Lock();
143  Clear();
144  wanted = Length;
146  f = File;
147  Unlock();
148  newSet.Signal();
149 }
150 
152 {
153  LOCK_THREAD;
154  if (buffer && length == wanted) {
155  *Buffer = buffer;
156  buffer = NULL;
157  return wanted;
158  }
159  errno = EAGAIN;
160  return -1;
161 }
162 
164 {
165  while (Running()) {
166  Lock();
167  if (f && buffer && length < wanted) {
168  int r = f->Read(buffer + length, wanted - length);
169  if (r > 0)
170  length += r;
171  else if (r == 0) { // r == 0 means EOF
172  if (length > 0)
173  wanted = length; // already read something, so return the rest
174  else
175  length = wanted = 0; // report EOF
176  }
177  else if (FATALERRNO) {
178  LOG_ERROR;
179  length = wanted = r; // this will forward the error status to the caller
180  }
181  if (length == wanted) {
182  cMutexLock NewDataLock(&newDataMutex);
184  }
185  }
186  Unlock();
187  newSet.Wait(1000);
188  }
189 }
190 
192 {
193  cMutexLock NewDataLock(&newDataMutex);
194  if (buffer && length == wanted)
195  return true;
196  return newDataCond.TimedWait(newDataMutex, msToWait);
197 }
198 
199 // --- cDvbPlayer ------------------------------------------------------------
200 
201 #define PLAYERBUFSIZE MEGABYTE(1)
202 
203 #define RESUMEBACKUP 10 // number of seconds to back up when resuming an interrupted replay session
204 #define MAXSTUCKATEOF 3 // max. number of seconds to wait in case the device doesn't play the last frame
205 
206 class cDvbPlayer : public cPlayer, cThread {
207 private:
210  static int Speeds[];
219  bool pauseLive;
220  bool eof;
231  void TrickSpeed(int Increment);
232  void Empty(void);
233  bool NextFile(uint16_t FileNumber = 0, off_t FileOffset = -1);
234  int Resume(void);
235  bool Save(void);
236 protected:
237  virtual void Activate(bool On);
238  virtual void Action(void);
239 public:
240  cDvbPlayer(const char *FileName, bool PauseLive);
241  virtual ~cDvbPlayer();
242  bool Active(void) { return cThread::Running(); }
243  void Pause(void);
244  void Play(void);
245  void Forward(void);
246  void Backward(void);
247  int SkipFrames(int Frames);
248  void SkipSeconds(int Seconds);
249  void Goto(int Position, bool Still = false);
250  virtual double FramesPerSecond(void) { return framesPerSecond; }
251  virtual void SetAudioTrack(eTrackType Type, const tTrackId *TrackId);
252  virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false);
253  virtual bool GetReplayMode(bool &Play, bool &Forward, int &Speed);
254  };
255 
256 #define MAX_VIDEO_SLOWMOTION 63 // max. arg to pass to VIDEO_SLOWMOTION // TODO is this value correct?
257 #define NORMAL_SPEED 4 // the index of the '1' entry in the following array
258 #define MAX_SPEEDS 3 // the offset of the maximum speed from normal speed in either direction
259 #define SPEED_MULT 12 // the speed multiplier
260 int cDvbPlayer::Speeds[] = { 0, -2, -4, -8, 1, 2, 4, 12, 0 };
261 
262 cDvbPlayer::cDvbPlayer(const char *FileName, bool PauseLive)
263 :cThread("dvbplayer")
264 {
265  nonBlockingFileReader = NULL;
266  ringBuffer = NULL;
267  index = NULL;
268  cRecording Recording(FileName);
269  framesPerSecond = Recording.FramesPerSecond();
270  isPesRecording = Recording.IsPesRecording();
271  pauseLive = PauseLive;
272  eof = false;
273  firstPacket = true;
274  playMode = pmPlay;
275  playDir = pdForward;
277  readIndex = -1;
278  readIndependent = false;
279  readFrame = NULL;
280  playFrame = NULL;
281  dropFrame = NULL;
282  resyncAfterPause = false;
283  isyslog("replay %s", FileName);
284  fileName = new cFileName(FileName, false, false, isPesRecording);
285  replayFile = fileName->Open();
286  if (!replayFile)
287  return;
289  // Create the index file:
290  index = new cIndexFile(FileName, false, isPesRecording, pauseLive);
291  if (!index)
292  esyslog("ERROR: can't allocate index");
293  else if (!index->Ok()) {
294  delete index;
295  index = NULL;
296  }
297  else if (PauseLive)
298  framesPerSecond = cRecording(FileName).FramesPerSecond(); // the fps rate might have changed from the default
299 }
300 
302 {
303  Save();
304  Detach();
305  delete readFrame; // might not have been stored in the buffer in Action()
306  delete index;
307  delete fileName;
308  delete ringBuffer;
309 }
310 
311 void cDvbPlayer::TrickSpeed(int Increment)
312 {
313  int nts = trickSpeed + Increment;
314  if (Speeds[nts] == 1) {
315  trickSpeed = nts;
316  if (playMode == pmFast)
317  Play();
318  else
319  Pause();
320  }
321  else if (Speeds[nts]) {
322  trickSpeed = nts;
323  int Mult = (playMode == pmSlow && playDir == pdForward) ? 1 : SPEED_MULT;
324  int sp = (Speeds[nts] > 0) ? Mult / Speeds[nts] : -Speeds[nts] * Mult;
325  if (sp > MAX_VIDEO_SLOWMOTION)
327  DeviceTrickSpeed(sp);
328  }
329 }
330 
332 {
333  LOCK_THREAD;
336  if (!firstPacket) // don't set the readIndex twice if Empty() is called more than once
337  readIndex = ptsIndex.FindIndex(DeviceGetSTC()) - 1; // Action() will first increment it!
338  delete readFrame; // might not have been stored in the buffer in Action()
339  readFrame = NULL;
340  playFrame = NULL;
341  dropFrame = NULL;
342  ringBuffer->Clear();
343  ptsIndex.Clear();
344  DeviceClear();
345  firstPacket = true;
346 }
347 
348 bool cDvbPlayer::NextFile(uint16_t FileNumber, off_t FileOffset)
349 {
350  if (FileNumber > 0)
351  replayFile = fileName->SetOffset(FileNumber, FileOffset);
352  else if (replayFile && eof)
354  eof = false;
355  return replayFile != NULL;
356 }
357 
359 {
360  if (index) {
361  int Index = index->GetResume();
362  if (Index >= 0) {
363  uint16_t FileNumber;
364  off_t FileOffset;
365  if (index->Get(Index, &FileNumber, &FileOffset) && NextFile(FileNumber, FileOffset))
366  return Index;
367  }
368  }
369  return -1;
370 }
371 
373 {
374  if (index) {
375  int Index = ptsIndex.FindIndex(DeviceGetSTC());
376  if (Index >= 0) {
377  Index -= int(round(RESUMEBACKUP * framesPerSecond));
378  if (Index > 0)
379  Index = index->GetNextIFrame(Index, false);
380  else
381  Index = 0;
382  if (Index >= 0)
383  return index->StoreResume(Index);
384  }
385  }
386  return false;
387 }
388 
389 void cDvbPlayer::Activate(bool On)
390 {
391  if (On) {
392  if (replayFile)
393  Start();
394  }
395  else
396  Cancel(9);
397 }
398 
400 {
401  uchar *p = NULL;
402  int pc = 0;
403 
404  readIndex = Resume();
405  if (readIndex >= 0)
406  isyslog("resuming replay at index %d (%s)", readIndex, *IndexToHMSF(readIndex, true, framesPerSecond));
407 
409  int Length = 0;
410  bool Sleep = false;
411  bool WaitingForData = false;
412  time_t StuckAtEof = 0;
413  uint32_t LastStc = 0;
414  int LastReadIFrame = -1;
415  int SwitchToPlayFrame = 0;
416 
417  if (pauseLive)
418  Goto(0, true);
419  while (Running()) {
420  if (WaitingForData)
421  WaitingForData = !nonBlockingFileReader->WaitForDataMs(3); // this keeps the CPU load low, but reacts immediately on new data
422  else if (Sleep) {
423  cPoller Poller;
424  DevicePoll(Poller, 10);
425  Sleep = false;
426  if (playMode == pmStill || playMode == pmPause)
428  }
429  {
430  LOCK_THREAD;
431 
432  // Read the next frame from the file:
433 
434  if (playMode != pmStill && playMode != pmPause) {
435  if (!readFrame && (replayFile || readIndex >= 0)) {
436  if (!nonBlockingFileReader->Reading()) {
437  if (!SwitchToPlayFrame && (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward))) {
438  uint16_t FileNumber;
439  off_t FileOffset;
440  bool TimeShiftMode = index->IsStillRecording();
441  int Index = -1;
442  readIndependent = false;
444  if (index->Get(readIndex + 1, &FileNumber, &FileOffset, &readIndependent, &Length))
445  Index = readIndex + 1;
446  }
447  else {
448  int d = int(round(0.4 * framesPerSecond));
449  if (playDir != pdForward)
450  d = -d;
451  int NewIndex = readIndex + d;
452  if (NewIndex <= 0 && readIndex > 0)
453  NewIndex = 1; // make sure the very first frame is delivered
454  NewIndex = index->GetNextIFrame(NewIndex, playDir == pdForward, &FileNumber, &FileOffset, &Length);
455  if (NewIndex < 0 && TimeShiftMode && playDir == pdForward)
456  SwitchToPlayFrame = readIndex;
457  Index = NewIndex;
458  readIndependent = true;
459  }
460  if (Index >= 0) {
461  readIndex = Index;
462  if (!NextFile(FileNumber, FileOffset))
463  continue;
464  }
465  else if (!(TimeShiftMode && playDir == pdForward))
466  eof = true;
467  }
468  else if (index) {
469  uint16_t FileNumber;
470  off_t FileOffset;
471  if (index->Get(readIndex + 1, &FileNumber, &FileOffset, &readIndependent, &Length) && NextFile(FileNumber, FileOffset))
472  readIndex++;
473  else
474  eof = true;
475  }
476  else // allows replay even if the index file is missing
477  Length = MAXFRAMESIZE;
478  if (Length == -1)
479  Length = MAXFRAMESIZE; // this means we read up to EOF (see cIndex)
480  else if (Length > MAXFRAMESIZE) {
481  esyslog("ERROR: frame larger than buffer (%d > %d)", Length, MAXFRAMESIZE);
482  Length = MAXFRAMESIZE;
483  }
484  if (!eof)
486  }
487  if (!eof) {
488  uchar *b = NULL;
489  int r = nonBlockingFileReader->Result(&b);
490  if (r > 0) {
491  WaitingForData = false;
492  uint32_t Pts = 0;
493  if (readIndependent) {
494  Pts = isPesRecording ? PesGetPts(b) : TsGetPts(b, r);
495  LastReadIFrame = readIndex;
496  }
497  readFrame = new cFrame(b, -r, ftUnknown, readIndex, Pts); // hands over b to the ringBuffer
498  }
499  else if (r < 0) {
500  if (errno == EAGAIN)
501  WaitingForData = true;
502  else if (FATALERRNO) {
503  LOG_ERROR;
504  break;
505  }
506  }
507  else
508  eof = true;
509  }
510  }
511 
512  // Store the frame in the buffer:
513 
514  if (readFrame) {
515  if (ringBuffer->Put(readFrame))
516  readFrame = NULL;
517  else
518  Sleep = true;
519  }
520  }
521  else
522  Sleep = true;
523 
524  if (dropFrame) {
525  if (!eof || (playDir != pdForward && dropFrame->Index() > 0) || (playDir == pdForward && dropFrame->Index() < readIndex)) {
526  ringBuffer->Drop(dropFrame); // the very first and last frame are continuously repeated to flush data through the device
527  dropFrame = NULL;
528  }
529  }
530 
531  // Get the next frame from the buffer:
532 
533  if (!playFrame) {
534  playFrame = ringBuffer->Get();
535  p = NULL;
536  pc = 0;
537  }
538 
539  // Play the frame:
540 
541  if (playFrame) {
542  if (!p) {
543  p = playFrame->Data();
544  pc = playFrame->Count();
545  if (p) {
546  if (playFrame->Index() >= 0 && playFrame->Pts() != 0)
548  if (firstPacket) {
549  if (isPesRecording) {
550  PlayPes(NULL, 0);
551  cRemux::SetBrokenLink(p, pc);
552  }
553  else
554  PlayTs(NULL, 0);
555  firstPacket = false;
556  }
557  }
558  }
559  if (p) {
560  int w;
561  bool VideoOnly = (dropFrame || playMode != pmPlay && !(playMode == pmSlow && playDir == pdForward)) && DeviceIsPlayingVideo();
562  if (isPesRecording)
563  w = PlayPes(p, pc, VideoOnly);
564  else
565  w = PlayTs(p, pc, VideoOnly);
566  if (w > 0) {
567  p += w;
568  pc -= w;
569  }
570  else if (w < 0 && FATALERRNO)
571  LOG_ERROR;
572  else
573  Sleep = true;
574  }
575  if (pc <= 0) {
577  playFrame = NULL;
578  p = NULL;
579  }
580  }
581  else
582  Sleep = true;
583 
584  // Handle hitting begin/end of recording:
585 
586  if (eof || SwitchToPlayFrame) {
587  bool SwitchToPlay = false;
588  uint32_t Stc = DeviceGetSTC();
589  if (Stc != LastStc || playMode == pmPause)
590  StuckAtEof = 0;
591  else if (!StuckAtEof)
592  StuckAtEof = time(NULL);
593  else if (time(NULL) - StuckAtEof > MAXSTUCKATEOF) {
594  if (playDir == pdForward)
595  break; // automatically stop at end of recording
596  SwitchToPlay = true;
597  }
598  LastStc = Stc;
599  int Index = ptsIndex.FindIndex(Stc);
600  if (playDir == pdForward && !SwitchToPlayFrame) {
601  if (Index >= LastReadIFrame)
602  break; // automatically stop at end of recording
603  }
604  else if (Index <= 0 || SwitchToPlayFrame && Index >= SwitchToPlayFrame)
605  SwitchToPlay = true;
606  if (SwitchToPlay) {
607  if (!SwitchToPlayFrame)
608  Empty();
609  DevicePlay();
610  playMode = pmPlay;
611  playDir = pdForward;
612  SwitchToPlayFrame = 0;
613  }
614  }
615  }
616  }
617 
619  nonBlockingFileReader = NULL;
620  delete nbfr;
621 }
622 
624 {
625  if (playMode == pmPause || playMode == pmStill)
626  Play();
627  else {
628  LOCK_THREAD;
629  if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) {
631  Empty();
632  }
633  DeviceFreeze();
634  playMode = pmPause;
635  }
636 }
637 
639 {
640  if (playMode != pmPlay) {
641  LOCK_THREAD;
642  if (playMode == pmStill || playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) {
644  Empty();
645  }
646  DevicePlay();
647  playMode = pmPlay;
648  playDir = pdForward;
649  if (resyncAfterPause) {
650  int Current, Total;
651  if (GetIndex(Current, Total, true))
652  Goto(Current);
653  resyncAfterPause = false;
654  }
655  }
656 }
657 
659 {
660  if (index) {
661  switch (playMode) {
662  case pmFast:
663  if (Setup.MultiSpeedMode) {
664  TrickSpeed(playDir == pdForward ? 1 : -1);
665  break;
666  }
667  else if (playDir == pdForward) {
668  Play();
669  break;
670  }
671  // run into pmPlay
672  case pmPlay: {
673  LOCK_THREAD;
675  Empty();
676  if (DeviceIsPlayingVideo())
677  DeviceMute();
678  playMode = pmFast;
679  playDir = pdForward;
682  }
683  break;
684  case pmSlow:
685  if (Setup.MultiSpeedMode) {
686  TrickSpeed(playDir == pdForward ? -1 : 1);
687  break;
688  }
689  else if (playDir == pdForward) {
690  Pause();
691  break;
692  }
693  Empty();
694  // run into pmPause
695  case pmStill:
696  case pmPause:
697  DeviceMute();
698  playMode = pmSlow;
699  playDir = pdForward;
702  break;
703  default: esyslog("ERROR: unknown playMode %d (%s)", playMode, __FUNCTION__);
704  }
705  }
706 }
707 
709 {
710  if (index) {
711  switch (playMode) {
712  case pmFast:
713  if (Setup.MultiSpeedMode) {
714  TrickSpeed(playDir == pdBackward ? 1 : -1);
715  break;
716  }
717  else if (playDir == pdBackward) {
718  Play();
719  break;
720  }
721  // run into pmPlay
722  case pmPlay: {
723  LOCK_THREAD;
724  Empty();
725  if (DeviceIsPlayingVideo())
726  DeviceMute();
727  playMode = pmFast;
731  }
732  break;
733  case pmSlow:
734  if (Setup.MultiSpeedMode) {
735  TrickSpeed(playDir == pdBackward ? -1 : 1);
736  break;
737  }
738  else if (playDir == pdBackward) {
739  Pause();
740  break;
741  }
742  Empty();
743  // run into pmPause
744  case pmStill:
745  case pmPause: {
746  LOCK_THREAD;
747  Empty();
748  DeviceMute();
749  playMode = pmSlow;
753  }
754  break;
755  default: esyslog("ERROR: unknown playMode %d (%s)", playMode, __FUNCTION__);
756  }
757  }
758 }
759 
760 int cDvbPlayer::SkipFrames(int Frames)
761 {
762  if (index && Frames) {
763  int Current, Total;
764  GetIndex(Current, Total, true);
765  int OldCurrent = Current;
766  // As GetNextIFrame() increments/decrements at least once, the
767  // destination frame (= Current + Frames) must be adjusted by
768  // -1/+1 respectively.
769  Current = index->GetNextIFrame(Current + Frames + (Frames > 0 ? -1 : 1), Frames > 0);
770  return Current >= 0 ? Current : OldCurrent;
771  }
772  return -1;
773 }
774 
775 void cDvbPlayer::SkipSeconds(int Seconds)
776 {
777  if (index && Seconds) {
778  LOCK_THREAD;
779  int Index = ptsIndex.FindIndex(DeviceGetSTC());
780  Empty();
781  if (Index >= 0) {
782  Index = max(Index + SecondsToFrames(Seconds, framesPerSecond), 0);
783  if (Index > 0)
784  Index = index->GetNextIFrame(Index, false, NULL, NULL, NULL);
785  if (Index >= 0)
786  readIndex = Index - 1; // Action() will first increment it!
787  }
788  Play();
789  }
790 }
791 
792 void cDvbPlayer::Goto(int Index, bool Still)
793 {
794  if (index) {
795  LOCK_THREAD;
796  Empty();
797  if (++Index <= 0)
798  Index = 1; // not '0', to allow GetNextIFrame() below to work!
799  uint16_t FileNumber;
800  off_t FileOffset;
801  int Length;
802  Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset, &Length);
803  if (Index >= 0 && NextFile(FileNumber, FileOffset) && Still) {
804  uchar b[MAXFRAMESIZE];
805  int r = ReadFrame(replayFile, b, Length, sizeof(b));
806  if (r > 0) {
807  if (playMode == pmPause)
808  DevicePlay();
809  DeviceStillPicture(b, r);
810  ptsIndex.Put(isPesRecording ? PesGetPts(b) : TsGetPts(b, r), Index);
811  }
812  playMode = pmStill;
813  }
814  readIndex = Index;
815  }
816 }
817 
819 {
820  if (!cThread::IsMainThread())
821  return; // only do this upon user interaction
822  if (playMode == pmPlay) {
823  if (!ptsIndex.IsEmpty()) {
824  int Current, Total;
825  if (GetIndex(Current, Total, true))
826  Goto(Current);
827  }
828  }
829  else if (playMode == pmPause)
830  resyncAfterPause = true;
831 }
832 
833 bool cDvbPlayer::GetIndex(int &Current, int &Total, bool SnapToIFrame)
834 {
835  if (index) {
836  Current = ptsIndex.FindIndex(DeviceGetSTC());
837  if (SnapToIFrame) {
838  int i1 = index->GetNextIFrame(Current + 1, false);
839  int i2 = index->GetNextIFrame(Current, true);
840  Current = (abs(Current - i1) <= abs(Current - i2)) ? i1 : i2;
841  }
842  Total = index->Last();
843  return true;
844  }
845  Current = Total = -1;
846  return false;
847 }
848 
849 bool cDvbPlayer::GetReplayMode(bool &Play, bool &Forward, int &Speed)
850 {
851  Play = (playMode == pmPlay || playMode == pmFast);
852  Forward = (playDir == pdForward);
853  if (playMode == pmFast || playMode == pmSlow)
854  Speed = Setup.MultiSpeedMode ? abs(trickSpeed - NORMAL_SPEED) : 0;
855  else
856  Speed = -1;
857  return true;
858 }
859 
860 // --- cDvbPlayerControl -----------------------------------------------------
861 
862 cDvbPlayerControl::cDvbPlayerControl(const char *FileName, bool PauseLive)
863 :cControl(player = new cDvbPlayer(FileName, PauseLive))
864 {
865 }
866 
868 {
869  Stop();
870 }
871 
873 {
874  return player && player->Active();
875 }
876 
878 {
879  delete player;
880  player = NULL;
881 }
882 
884 {
885  if (player)
886  player->Pause();
887 }
888 
890 {
891  if (player)
892  player->Play();
893 }
894 
896 {
897  if (player)
898  player->Forward();
899 }
900 
902 {
903  if (player)
904  player->Backward();
905 }
906 
908 {
909  if (player)
910  player->SkipSeconds(Seconds);
911 }
912 
914 {
915  if (player)
916  return player->SkipFrames(Frames);
917  return -1;
918 }
919 
920 bool cDvbPlayerControl::GetIndex(int &Current, int &Total, bool SnapToIFrame)
921 {
922  if (player) {
923  player->GetIndex(Current, Total, SnapToIFrame);
924  return true;
925  }
926  return false;
927 }
928 
929 bool cDvbPlayerControl::GetReplayMode(bool &Play, bool &Forward, int &Speed)
930 {
931  return player && player->GetReplayMode(Play, Forward, Speed);
932 }
933 
934 void cDvbPlayerControl::Goto(int Position, bool Still)
935 {
936  if (player)
937  player->Goto(Position, Still);
938 }
unsigned char uchar
Definition: tools.h:30
int FindIndex(uint32_t Pts)
Definition: dvbplayer.c:69
cFrame * dropFrame
Definition: dvbplayer.c:229
cIndexFile * index
Definition: dvbplayer.c:215
void DeviceClear(void)
Definition: player.h:31
cRingBufferFrame * ringBuffer
Definition: dvbplayer.c:212
bool firstPacket
Definition: dvbplayer.c:221
int MultiSpeedMode
Definition: config.h:330
#define SPEED_MULT
Definition: dvbplayer.c:259
virtual void Activate(bool On)
Definition: dvbplayer.c:389
virtual void Clear(void)
Definition: ringbuffer.c:430
#define LOG_ERROR
Definition: tools.h:38
int lastFound
Definition: dvbplayer.c:31
#define MAX_SPEEDS
Definition: dvbplayer.c:258
void Pause(void)
Definition: dvbplayer.c:623
void Play(void)
Definition: dvbplayer.c:889
void Play(void)
Definition: dvbplayer.c:638
double FramesPerSecond(void) const
Definition: recording.h:125
ssize_t Read(void *Data, size_t Size)
Definition: tools.c:1705
cUnbufferedFile * SetOffset(int Number, off_t Offset=0)
Definition: recording.c:2342
virtual ~cDvbPlayer()
Definition: dvbplayer.c:301
void Signal(void)
Signals a caller of Wait() that the condition it is waiting for is met.
Definition: thread.c:85
int64_t PesGetPts(const uchar *p)
Definition: remux.h:181
int GetNextIFrame(int Index, bool Forward, uint16_t *FileNumber=NULL, off_t *FileOffset=NULL, int *Length=NULL)
Definition: recording.c:2093
int Count(void) const
Definition: ringbuffer.h:123
cNonBlockingFileReader * nonBlockingFileReader
Definition: dvbplayer.c:211
void Goto(int Position, bool Still=false)
Definition: dvbplayer.c:792
void SkipSeconds(int Seconds)
Definition: dvbplayer.c:775
#define esyslog(a...)
Definition: tools.h:34
#define PTSINDEX_ENTRIES
Definition: dvbplayer.c:21
cFileName * fileName
Definition: dvbplayer.c:214
void Drop(cFrame *Frame)
Definition: ringbuffer.c:475
#define MAXSTUCKATEOF
Definition: dvbplayer.c:204
static tThreadId IsMainThread(void)
Definition: thread.h:125
cUnbufferedFile * NextFile(void)
Definition: recording.c:2384
bool Save(void)
Definition: dvbplayer.c:372
T max(T a, T b)
Definition: tools.h:55
bool Ok(void)
Definition: recording.h:308
void DevicePlay(void)
Definition: player.h:32
int ReadFrame(cUnbufferedFile *f, uchar *b, int Length, int Max)
Definition: recording.c:2425
tPtsIndex pi[PTSINDEX_ENTRIES]
Definition: dvbplayer.c:29
eTrackType
Definition: device.h:65
int Last(void)
Returns the index of the last entry in this file, or -1 if the file is empty.
Definition: recording.h:318
virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame=false)
Definition: dvbplayer.c:833
void Empty(void)
Definition: dvbplayer.c:331
int PlayPes(const uchar *Data, int Length, bool VideoOnly=false)
Definition: player.c:26
virtual void Action(void)
A derived cThread class must implement the code it wants to execute as a separate thread in this func...
Definition: dvbplayer.c:399
cUnbufferedFile is used for large files that are mainly written or read in a streaming manner...
Definition: tools.h:408
bool DeviceHasIBPTrickSpeed(void)
Definition: player.h:28
double framesPerSecond
Definition: dvbplayer.c:217
void Backward(void)
Definition: dvbplayer.c:708
#define NORMAL_SPEED
Definition: dvbplayer.c:257
cFrame * playFrame
Definition: dvbplayer.c:228
cPtsIndex ptsIndex
Definition: dvbplayer.c:213
void Detach(void)
Definition: player.c:34
void Action(void)
A derived cThread class must implement the code it wants to execute as a separate thread in this func...
Definition: dvbplayer.c:163
cString IndexToHMSF(int Index, bool WithFrame, double FramesPerSecond)
Definition: recording.c:2391
#define MALLOC(type, size)
Definition: tools.h:46
static int Speeds[]
Definition: dvbplayer.c:210
void DeviceFreeze(void)
Definition: player.h:33
virtual double FramesPerSecond(void)
Definition: dvbplayer.c:250
void Clear(void)
Definition: dvbplayer.c:47
uchar * Data(void) const
Definition: ringbuffer.h:122
virtual ~cDvbPlayerControl()
Definition: dvbplayer.c:867
void Unlock(void)
Definition: thread.h:93
Definition: player.h:16
cDvbPlayerControl(const char *FileName, bool PauseLive=false)
Definition: dvbplayer.c:862
virtual bool GetReplayMode(bool &Play, bool &Forward, int &Speed)
Definition: dvbplayer.c:849
int Result(uchar **Buffer)
Definition: dvbplayer.c:151
void Broadcast(void)
Definition: thread.c:135
bool NextFile(uint16_t FileNumber=0, off_t FileOffset=-1)
Definition: dvbplayer.c:348
bool isPesRecording
Definition: dvbplayer.c:218
void DeviceStillPicture(const uchar *Data, int Length)
Definition: player.h:36
void Pause(void)
Definition: dvbplayer.c:883
void Backward(void)
Definition: dvbplayer.c:901
cFrame * Get(void)
Definition: ringbuffer.c:461
static void SleepMs(int TimeoutMs)
Creates a cCondWait object and uses it to sleep for TimeoutMs milliseconds, immediately giving up the...
Definition: thread.c:57
void bool Start(void)
Actually starts the thread.
Definition: thread.c:273
cDvbPlayer(const char *FileName, bool PauseLive)
Definition: dvbplayer.c:262
cUnbufferedFile * Open(void)
Definition: recording.c:2309
cSetup Setup
Definition: config.c:372
uint32_t Pts(void) const
Definition: ringbuffer.h:126
bool Running(void)
Returns false if a derived cThread object shall leave its Action() function.
Definition: thread.h:99
bool Wait(int TimeoutMs=0)
Waits at most TimeoutMs milliseconds for a call to Signal(), or forever if TimeoutMs is 0...
Definition: thread.c:63
Definition: thread.h:63
bool TimedWait(cMutex &Mutex, int TimeoutMs)
Definition: thread.c:117
void Request(cUnbufferedFile *File, int Length)
Definition: dvbplayer.c:140
bool GetIndex(int &Current, int &Total, bool SnapToIFrame=false)
Definition: dvbplayer.c:920
bool Active(void)
Definition: dvbplayer.c:872
virtual void SetAudioTrack(eTrackType Type, const tTrackId *TrackId)
Definition: dvbplayer.c:818
bool StoreResume(int Index)
Definition: recording.h:321
bool DevicePoll(cPoller &Poller, int TimeoutMs=0)
Definition: player.h:26
bool GetReplayMode(bool &Play, bool &Forward, int &Speed)
Definition: dvbplayer.c:929
cDvbPlayer * player
Definition: dvbplayer.h:20
static void SetBrokenLink(uchar *Data, int Length)
Definition: remux.c:102
bool DeviceIsPlayingVideo(void)
Definition: player.h:29
#define PLAYERBUFSIZE
Definition: dvbplayer.c:201
bool Put(cFrame *Frame)
Definition: ringbuffer.c:441
int readIndex
Definition: dvbplayer.c:225
void Put(uint32_t Pts, int Index)
Definition: dvbplayer.c:59
void DeviceTrickSpeed(int Speed)
Definition: player.h:30
cFrame * readFrame
Definition: dvbplayer.c:227
ePlayModes playMode
Definition: dvbplayer.c:222
int PlayTs(const uchar *Data, int Length, bool VideoOnly=false)
Definition: player.h:47
void Stop(void)
Definition: dvbplayer.c:877
uint64_t DeviceGetSTC(void)
Definition: player.h:37
bool IsEmpty(void)
Definition: dvbplayer.c:53
#define FATALERRNO
Definition: tools.h:51
int Index(void) const
Definition: ringbuffer.h:125
int GetResume(void)
Definition: recording.h:320
#define MAXFRAMESIZE
Definition: recording.h:277
int Resume(void)
Definition: dvbplayer.c:358
void Forward(void)
Definition: dvbplayer.c:895
bool Active(void)
Definition: dvbplayer.c:242
int64_t TsGetPts(const uchar *p, int l)
Definition: remux.c:147
#define isyslog(a...)
Definition: tools.h:35
Definition: thread.h:77
int SecondsToFrames(int Seconds, double FramesPerSecond)
Definition: recording.c:2418
cPtsIndex(void)
Definition: dvbplayer.c:41
bool WaitForDataMs(int msToWait)
Definition: dvbplayer.c:191
bool Get(int Index, uint16_t *FileNumber, off_t *FileOffset, bool *Independent=NULL, int *Length=NULL)
Definition: recording.c:2067
void DeviceMute(void)
Definition: player.h:34
bool pauseLive
Definition: dvbplayer.c:219
bool resyncAfterPause
Definition: dvbplayer.c:230
bool IsStillRecording(void)
Definition: recording.c:2173
int trickSpeed
Definition: dvbplayer.c:224
void Goto(int Index, bool Still=false)
Definition: dvbplayer.c:934
#define LOCK_THREAD
Definition: thread.h:161
int SkipFrames(int Frames)
Definition: dvbplayer.c:913
#define MAX_VIDEO_SLOWMOTION
Definition: dvbplayer.c:256
cUnbufferedFile * f
Definition: dvbplayer.c:95
bool readIndependent
Definition: dvbplayer.c:226
int SkipFrames(int Frames)
Definition: dvbplayer.c:760
Definition: tools.h:347
void Cancel(int WaitSeconds=0)
Cancels the thread by first setting 'running' to false, so that the Action() loop can finish in an or...
Definition: thread.c:323
void SkipSeconds(int Seconds)
Definition: dvbplayer.c:907
#define RESUMEBACKUP
Definition: dvbplayer.c:203
void TrickSpeed(int Increment)
Definition: dvbplayer.c:311
bool IsPesRecording(void) const
Definition: recording.h:136
bool eof
Definition: dvbplayer.c:220
cUnbufferedFile * replayFile
Definition: dvbplayer.c:216
cMutex mutex
Definition: dvbplayer.c:32
void Lock(void)
Definition: thread.h:92
ePlayDirs playDir
Definition: dvbplayer.c:223
void Forward(void)
Definition: dvbplayer.c:658