Hi, the motivation for this patch was to speed up zapping channels when using vdr-xine, i. e. to shorten the time from pressing the remote button till audio and video appear. FF card users may only see the effect of this patch when the FF card is running in transfer mode. The idea is to not wait for the first I frame in transfer mode. Although output devices "can't" decode any frames before the first I frame, the contained PTS in the PES packets allows the device to synchronize audio and video even before the first video frame appears on screen. Another issue which is addressed by this patch is that audio packets were not delivered to the device immediately after switching the channel, so the above change didn't have any effect. Calling EnsureAudioTrack() fixes this. How much speed up can be expected? Well, it varies from zap to zap as it depends on a couple of parameters like the offset of audio and video PTS, whether a PTS is available per frame, the number of frames till the next I frame arrives, etc. But a speed up should be noticeable. BTW: Testers of plugin ** should comment out the following line in cTSBuffer::Get() in file device.c, like that: // if(!device->***) device->***=new c***; This change is highly recommended if you experience buffer overflows while switching channels, though they are not related to the sync early patch. Bye. -- Dipl.-Inform. (FH) Reinhard Nissl mailto:rnissl@xxxxxx
diff -Nurp ../vdr-1.4.6-1-orig/device.c ./device.c --- ../vdr-1.4.6-1-orig/device.c 2006-09-03 12:13:25.000000000 +0200 +++ ./device.c 2007-05-06 21:22:52.000000000 +0200 @@ -691,7 +691,7 @@ eSetChannelResult cDevice::SetChannel(co for (int i = 0; i < MAXDPIDS; i++) SetAvailableTrack(ttDolby, i, Channel->Dpid(i), Channel->Dlang(i)); } - if (!NeedsTransferMode) + if (!NeedsTransferMode || GetCurrentAudioTrack() == ttNone) EnsureAudioTrack(true); } cStatus::MsgChannelSwitch(this, Channel->Number()); // only report status if channel switch successfull diff -Nurp ../vdr-1.4.6-1-orig/remux.c ./remux.c --- ../vdr-1.4.6-1-orig/remux.c 2006-12-01 15:46:25.000000000 +0100 +++ ./remux.c 2007-05-06 21:22:52.000000000 +0200 @@ -1853,12 +1853,13 @@ void cTS2PES::ts_to_pes(const uint8_t *B #define RESULTBUFFERSIZE KILOBYTE(256) -cRemux::cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure) +cRemux::cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure, bool SyncEarly) { exitOnFailure = ExitOnFailure; isRadio = VPid == 0 || VPid == 1 || VPid == 0x1FFF; numUPTerrors = 0; synced = false; + syncEarly = SyncEarly; skipped = 0; numTracks = 0; resultSkipped = 0; @@ -2062,12 +2063,14 @@ uchar *cRemux::Get(int &Count, uchar *Pi cThread::EmergencyExit(true); } else if (!synced) { - if (pt == I_FRAME) { + if (pt == I_FRAME || syncEarly) { if (PictureType) *PictureType = pt; resultSkipped = i; // will drop everything before this position - SetBrokenLink(data + i, l); synced = true; + if (pt == I_FRAME) // syncEarly: it's ok but there is no need to call SetBrokenLink() + SetBrokenLink(data + i, l); +else fprintf(stderr, "video: synced early\n"); } } else if (Count) @@ -2080,12 +2083,13 @@ uchar *cRemux::Get(int &Count, uchar *Pi l = GetPacketLength(data, resultCount, i); if (l < 0) return resultData; - if (isRadio) { + if (isRadio || !synced && syncEarly) { if (!synced) { - if (PictureType) + if (PictureType && isRadio) *PictureType = I_FRAME; resultSkipped = i; // will drop everything before this position synced = true; +if (!isRadio) fprintf(stderr, "audio: synced early\n"); } else if (Count) return resultData; diff -Nurp ../vdr-1.4.6-1-orig/remux.h ./remux.h --- ../vdr-1.4.6-1-orig/remux.h 2006-03-25 13:27:30.000000000 +0100 +++ ./remux.h 2007-05-06 21:22:52.000000000 +0200 @@ -40,6 +40,7 @@ private: bool isRadio; int numUPTerrors; bool synced; + bool syncEarly; int skipped; cTS2PES *ts2pes[MAXTRACKS]; int numTracks; @@ -47,12 +48,13 @@ private: int resultSkipped; int GetPid(const uchar *Data); public: - cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure = false); + cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure = false, bool SyncEarly = false); ///< Creates a new remuxer for the given PIDs. VPid is the video PID, while ///< APids, DPids and SPids are pointers to zero terminated lists of audio, ///< dolby and subtitle PIDs (the pointers may be NULL if there is no such ///< PID). If ExitOnFailure is true, the remuxer will initiate an "emergency - ///< exit" in case of problems with the data stream. + ///< exit" in case of problems with the data stream. SyncEarly causes cRemux + ///< to sync as soon as a video or audio frame is seen. ~cRemux(); void SetTimeouts(int PutTimeout, int GetTimeout) { resultBuffer->SetTimeouts(PutTimeout, GetTimeout); } ///< By default cRemux assumes that Put() and Get() are called from different diff -Nurp ../vdr-1.4.6-1-orig/transfer.c ./transfer.c --- ../vdr-1.4.6-1-orig/transfer.c 2006-01-29 18:24:39.000000000 +0100 +++ ./transfer.c 2007-05-06 21:23:35.000000000 +0200 @@ -19,7 +19,7 @@ cTransfer::cTransfer(int VPid, const int ,cThread("transfer") { ringBuffer = new cRingBufferLinear(TRANSFERBUFSIZE, TS_SIZE * 2, true, "Transfer"); - remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids); + remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids, false, true); } cTransfer::~cTransfer()
diff -Nurp ../vdr-1.5.2-orig/device.c ./device.c --- ../vdr-1.5.2-orig/device.c 2007-01-13 13:05:00.000000000 +0100 +++ ./device.c 2007-05-06 21:13:58.000000000 +0200 @@ -735,7 +735,7 @@ eSetChannelResult cDevice::SetChannel(co for (int i = 0; i < MAXDPIDS; i++) SetAvailableTrack(ttDolby, i, Channel->Dpid(i), Channel->Dlang(i)); } - if (!NeedsTransferMode) + if (!NeedsTransferMode || GetCurrentAudioTrack() == ttNone) EnsureAudioTrack(true); } cStatus::MsgChannelSwitch(this, Channel->Number()); // only report status if channel switch successfull diff -Nurp ../vdr-1.5.2-orig/remux.c ./remux.c --- ../vdr-1.5.2-orig/remux.c 2007-02-24 17:36:10.000000000 +0100 +++ ./remux.c 2007-05-06 21:13:58.000000000 +0200 @@ -1853,12 +1853,13 @@ void cTS2PES::ts_to_pes(const uint8_t *B #define RESULTBUFFERSIZE KILOBYTE(256) -cRemux::cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure) +cRemux::cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure, bool SyncEarly) { exitOnFailure = ExitOnFailure; isRadio = VPid == 0 || VPid == 1 || VPid == 0x1FFF; numUPTerrors = 0; synced = false; + syncEarly = SyncEarly; skipped = 0; numTracks = 0; resultSkipped = 0; @@ -2062,12 +2063,14 @@ uchar *cRemux::Get(int &Count, uchar *Pi ShutdownHandler.RequestEmergencyExit(); } else if (!synced) { - if (pt == I_FRAME) { + if (pt == I_FRAME || syncEarly) { if (PictureType) *PictureType = pt; resultSkipped = i; // will drop everything before this position - SetBrokenLink(data + i, l); synced = true; + if (pt == I_FRAME) // syncEarly: it's ok but there is no need to call SetBrokenLink() + SetBrokenLink(data + i, l); +else fprintf(stderr, "video: synced early\n"); } } else if (Count) @@ -2080,12 +2083,13 @@ uchar *cRemux::Get(int &Count, uchar *Pi l = GetPacketLength(data, resultCount, i); if (l < 0) return resultData; - if (isRadio) { + if (isRadio || !synced && syncEarly) { if (!synced) { - if (PictureType) + if (PictureType && isRadio) *PictureType = I_FRAME; resultSkipped = i; // will drop everything before this position synced = true; +if (!isRadio) fprintf(stderr, "audio: synced early\n"); } else if (Count) return resultData; diff -Nurp ../vdr-1.5.2-orig/remux.h ./remux.h --- ../vdr-1.5.2-orig/remux.h 2006-03-25 13:27:30.000000000 +0100 +++ ./remux.h 2007-05-06 21:13:58.000000000 +0200 @@ -40,6 +40,7 @@ private: bool isRadio; int numUPTerrors; bool synced; + bool syncEarly; int skipped; cTS2PES *ts2pes[MAXTRACKS]; int numTracks; @@ -47,12 +48,13 @@ private: int resultSkipped; int GetPid(const uchar *Data); public: - cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure = false); + cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure = false, bool SyncEarly = false); ///< Creates a new remuxer for the given PIDs. VPid is the video PID, while ///< APids, DPids and SPids are pointers to zero terminated lists of audio, ///< dolby and subtitle PIDs (the pointers may be NULL if there is no such ///< PID). If ExitOnFailure is true, the remuxer will initiate an "emergency - ///< exit" in case of problems with the data stream. + ///< exit" in case of problems with the data stream. SyncEarly causes cRemux + ///< to sync as soon as a video or audio frame is seen. ~cRemux(); void SetTimeouts(int PutTimeout, int GetTimeout) { resultBuffer->SetTimeouts(PutTimeout, GetTimeout); } ///< By default cRemux assumes that Put() and Get() are called from different diff -Nurp ../vdr-1.5.2-orig/transfer.c ./transfer.c --- ../vdr-1.5.2-orig/transfer.c 2007-01-05 11:45:28.000000000 +0100 +++ ./transfer.c 2007-05-06 21:14:39.000000000 +0200 @@ -19,7 +19,7 @@ cTransfer::cTransfer(tChannelID ChannelI ,cThread("transfer") { ringBuffer = new cRingBufferLinear(TRANSFERBUFSIZE, TS_SIZE * 2, true, "Transfer"); - remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids); + remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids, false, true); } cTransfer::~cTransfer()
_______________________________________________ vdr mailing list vdr@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr