From c848ab793a302dc067663ec4a06395745e443c9d Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sat, 6 Sep 2008 18:00:00 +0200 Subject: =?UTF-8?q?Version=201.7.1=20-=20Adapted=20the=20tuning=20code=20t?= =?UTF-8?q?o=20the=20new=20DVBFE=5FSET=5FDELSYS=20API=20(thanks=20to=20Rei?= =?UTF-8?q?nhard=20Nissl).=20=20=20VDR=20now=20uses=20the=20driver=20from?= =?UTF-8?q?=20http://jusst.de/hg/multiproto=5Fplus.=20-=20Updated=20the=20?= =?UTF-8?q?Italian=20OSD=20texts=20(thanks=20to=20Diego=20Pierotto).=20-?= =?UTF-8?q?=20Removed=20obsolete=20$(NCURSESLIB)=20from=20the=20Makefile.?= =?UTF-8?q?=20-=20Implemented=20handling=20the=20standard=20component=20de?= =?UTF-8?q?scriptor=20for=20AC3=20(stream=3D4),=20as=20it=20=20=20will=20s?= =?UTF-8?q?oon=20be=20used=20by=20the=20German=20ARD=20channels=20(thanks?= =?UTF-8?q?=20to=20Michael=20Pennewi=C3=9F=20for=20=20=20advance=20informa?= =?UTF-8?q?tion=20about=20this=20change).=20The=20previously=20used=20"Pre?= =?UTF-8?q?miere=20pseudo=20=20=20standard"=20(stream=3D2,=20type=3D5)=20s?= =?UTF-8?q?till=20works,=20but=20has=20apparently=20been=20wrongfully=20us?= =?UTF-8?q?ed=20=20=20by=20broadcasters=20from=20the=20beginning.=20-=20Ad?= =?UTF-8?q?ded=20missing=20description=20of=20the=20'S'=20channel=20parame?= =?UTF-8?q?ter=20to=20vdr.5=20(reported=20by=20=20=20Reinhard=20Nissl).=20?= =?UTF-8?q?-=20The=20SVDRP=20signon=20message=20now=20indicates=20the=20ch?= =?UTF-8?q?aracter=20encoding=20in=20use,=20as=20in=20=20=20"220=20video?= =?UTF-8?q?=20SVDRP=20VideoDiskRecorder=201.7.1;=20Fri=20May=20=202=2016:1?= =?UTF-8?q?7:10=202008;=20ISO-8859-1".=20=20=20This=20may=20be=20useful=20?= =?UTF-8?q?for=20instance=20for=20external=20tools=20that=20provide=20EPG?= =?UTF-8?q?=20data,=20so=20that=20=20=20they=20can=20correctly=20encode=20?= =?UTF-8?q?the=20strings.=20-=20No=20longer=20calling=20FcFini()=20to=20av?= =?UTF-8?q?oid=20problems=20with=20older=20(broken)=20versions=20of=20=20?= =?UTF-8?q?=20fontconfig=20(suggested=20by=20Edgar=20Toernig).=20-=20Remov?= =?UTF-8?q?ed=20the=20compile=20time=20option=20VFAT=20to=20allow=20users?= =?UTF-8?q?=20of=20precompiled=20binary=20=20=20distributions=20to=20have?= =?UTF-8?q?=20full=20control=20over=20whether=20or=20not=20to=20use=20the?= =?UTF-8?q?=20--vfat=20option=20=20=20at=20runtime=20(suggested=20by=20Mic?= =?UTF-8?q?hael=20Nork).=20-=20First=20step=20towards=20switching=20to=20T?= =?UTF-8?q?S=20(Transport=20Stream)=20as=20recording=20format:=20=20=20+?= =?UTF-8?q?=20The=20new=20function=20cDevice::PlayTs()=20is=20used=20to=20?= =?UTF-8?q?play=20TS=20packets.=20=20=20+=20The=20new=20functions=20cDevic?= =?UTF-8?q?e::PlayTsVideo()=20and=20cDevice::PlayTsAudio()=20=20=20=20=20a?= =?UTF-8?q?re=20used=20to=20play=20video=20and=20audio=20TS=20packets,=20r?= =?UTF-8?q?espectively.=20=20=20+=20The=20new=20function=20cAudio::PlayTs(?= =?UTF-8?q?)=20is=20used=20to=20play=20audio=20TS=20packets.=20=20=20+=20T?= =?UTF-8?q?he=20new=20class=20cPatPmtGenerator=20is=20used=20to=20generate?= =?UTF-8?q?=20a=20PAT/PMT=20pair=20that=20precedes=20=20=20=20=20the=20TS?= =?UTF-8?q?=20data=20in=20Transfer=20Mode.=20=20=20+=20The=20new=20class?= =?UTF-8?q?=20cPatPmtParser=20is=20used=20by=20cDevice=20to=20parse=20the?= =?UTF-8?q?=20PAT/PMT=20data=20in=20a=20=20=20=20=20TS=20in=20order=20to?= =?UTF-8?q?=20find=20out=20which=20streams=20it=20contains.=20=20=20+=20Th?= =?UTF-8?q?e=20new=20class=20cTsToPes=20is=20used=20to=20convert=20TS=20pa?= =?UTF-8?q?ckets=20to=20a=20PES=20packet.=20=20=20+=20cTransfer=20no=20lon?= =?UTF-8?q?ger=20uses=20cRemux,=20and=20doesn't=20run=20a=20separate=20thr?= =?UTF-8?q?ead=20any=20more.=20=20=20=20=20It=20just=20generates=20a=20PAT?= =?UTF-8?q?/PMT=20and=20sends=20all=20received=20TS=20packets=20to=20the?= =?UTF-8?q?=20primary=20=20=20=20=20device's=20PlayTs().=20=20=20+=20Live?= =?UTF-8?q?=20subtitle=20display=20no=20longer=20uses=20a=20ring=20buffer?= =?UTF-8?q?=20and=20separate=20thread.=20=20=20+=20cPesAssembler=20has=20b?= =?UTF-8?q?een=20removed.=20Old=20VDR=20recordings=20only=20contain=20comp?= =?UTF-8?q?lete=20PES=20=20=20=20=20packets.=20=20=20+=20Since=20a=20TS=20?= =?UTF-8?q?needs=20to=20have=20a=20PAT/PMT,=20which=20requires=20the=20vid?= =?UTF-8?q?eo=20stream=20type=20to=20=20=20=20=20be=20explicitly=20given,?= =?UTF-8?q?=20the=20format=20of=20the=20VPID=20field=20in=20the=20channels?= =?UTF-8?q?.conf=20file=20=20=20=20=20and=20the=20SVDRP=20commands=20NEWC/?= =?UTF-8?q?MODC/LSTC=20has=20been=20extended.=20The=20video=20stream=20typ?= =?UTF-8?q?e=20=20=20=20=20now=20follows=20the=20VPID=20and=20optional=20P?= =?UTF-8?q?PID,=20separated=20by=20an=20'=3D'=20sign.=20-=20Updated=20the?= =?UTF-8?q?=20sources.conf=20file=20(thanks=20to=20Oleg=20Roitburd).=20-?= =?UTF-8?q?=20Fixed=20a=20possible=20integer=20overflow=20in=20GetAbsTime(?= =?UTF-8?q?)=20(thanks=20to=20Alexander=20Rieger).=20-=20Fixed=20a=20probl?= =?UTF-8?q?em=20with=20calling=20isyslog()=20from=20within=20the=20SignalH?= =?UTF-8?q?andler()=20(thanks=20=20=20to=20Udo=20Richter).=20-=20Replaced?= =?UTF-8?q?=20the=20Finnish=20language=20code=20"smi"=20with=20"suo"=20(th?= =?UTF-8?q?anks=20to=20Rolf=20Ahrenberg).=20-=20Fixed=20wrong=20value=20fo?= =?UTF-8?q?r=20TableIdBAT=20in=20libsi/si.h=20(thanks=20to=20Winfried=20K?= =?UTF-8?q?=C3=B6hler).=20-=20Errors=20in=20config=20files=20no=20longer?= =?UTF-8?q?=20keep=20VDR=20from=20starting.=20-=20Removed=20unneeded=20inc?= =?UTF-8?q?lude=20files=20=20und=20=20from=20remu?= =?UTF-8?q?x.h=20=20=20(reported=20by=20Tobias=20Grimm).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- device.c | 286 ++++++++++++++++++++------------------------------------------- 1 file changed, 89 insertions(+), 197 deletions(-) (limited to 'device.c') diff --git a/device.c b/device.c index 12b8dd9..06f6864 100644 --- a/device.c +++ b/device.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: device.c 2.2 2008/04/12 14:12:14 kls Exp $ + * $Id: device.c 2.3 2008/07/06 13:22:21 kls Exp $ */ #include "device.h" @@ -21,16 +21,9 @@ // --- cLiveSubtitle --------------------------------------------------------- -#define LIVESUBTITLEBUFSIZE KILOBYTE(100) - -class cLiveSubtitle : public cReceiver, public cThread { -private: - cRingBufferLinear *ringBuffer; - cRemux *remux; +class cLiveSubtitle : public cReceiver { protected: - virtual void Activate(bool On); virtual void Receive(uchar *Data, int Length); - virtual void Action(void); public: cLiveSubtitle(int SPid); virtual ~cLiveSubtitle(); @@ -38,170 +31,17 @@ public: cLiveSubtitle::cLiveSubtitle(int SPid) :cReceiver(tChannelID(), -1, SPid) -,cThread("live subtitle") { - ringBuffer = new cRingBufferLinear(LIVESUBTITLEBUFSIZE, TS_SIZE * 2, true, "Live Subtitle"); - int NoPids = 0; - int SPids[] = { SPid, 0 }; - remux = new cRemux(0, &NoPids, &NoPids, SPids); } cLiveSubtitle::~cLiveSubtitle() { cReceiver::Detach(); - delete remux; - delete ringBuffer; -} - -void cLiveSubtitle::Activate(bool On) -{ - if (On) - Start(); - else - Cancel(3); } void cLiveSubtitle::Receive(uchar *Data, int Length) { - if (Running()) { - int p = ringBuffer->Put(Data, Length); - if (p != Length && Running()) - ringBuffer->ReportOverflow(Length - p); - } -} - -void cLiveSubtitle::Action(void) -{ - while (Running()) { - int Count; - uchar *b = ringBuffer->Get(Count); - if (b) { - Count = remux->Put(b, Count); - if (Count) - ringBuffer->Del(Count); - } - b = remux->Get(Count); - if (b) { - Count = cDevice::PrimaryDevice()->PlaySubtitle(b, Count); - remux->Del(Count); - } - } -} - -// --- cPesAssembler --------------------------------------------------------- - -class cPesAssembler { -private: - uchar *data; - uint32_t tag; - int length; - int size; - bool Realloc(int Size); -public: - cPesAssembler(void); - ~cPesAssembler(); - int ExpectedLength(void) { return PacketSize(data); } - static int PacketSize(const uchar *data); - int Length(void) { return length; } - const uchar *Data(void) { return data; } // only valid if Length() >= 4 - void Reset(void); - void Put(uchar c); - void Put(const uchar *Data, int Length); - bool IsPes(void); - }; - -cPesAssembler::cPesAssembler(void) -{ - data = NULL; - size = 0; - Reset(); -} - -cPesAssembler::~cPesAssembler() -{ - free(data); -} - -void cPesAssembler::Reset(void) -{ - tag = 0xFFFFFFFF; - length = 0; -} - -bool cPesAssembler::Realloc(int Size) -{ - if (Size > size) { - size = max(Size, 2048); - data = (uchar *)realloc(data, size); - if (!data) { - esyslog("ERROR: can't allocate memory for PES assembler"); - length = 0; - size = 0; - return false; - } - } - return true; -} - -void cPesAssembler::Put(uchar c) -{ - if (length < 4) { - tag = (tag << 8) | c; - if ((tag & 0xFFFFFF00) == 0x00000100) { - if (Realloc(4)) { - *(uint32_t *)data = htonl(tag); - length = 4; - } - } - else if (length < 3) - length++; - } - else if (Realloc(length + 1)) - data[length++] = c; -} - -void cPesAssembler::Put(const uchar *Data, int Length) -{ - while (length < 4 && Length > 0) { - Put(*Data++); - Length--; - } - if (Length && Realloc(length + Length)) { - memcpy(data + length, Data, Length); - length += Length; - } -} - -int cPesAssembler::PacketSize(const uchar *data) -{ - // we need atleast 6 bytes of data here !!! - switch (data[3]) { - default: - case 0x00 ... 0xB8: // video stream start codes - case 0xB9: // Program end - case 0xBC: // Programm stream map - case 0xF0 ... 0xFF: // reserved - return 6; - - case 0xBA: // Pack header - if ((data[4] & 0xC0) == 0x40) // MPEG2 - return 14; - // to be absolutely correct we would have to add the stuffing bytes - // as well, but at this point we only may have 6 bytes of data avail- - // able. So it's up to the higher level to resync... - //return 14 + (data[13] & 0x07); // add stuffing bytes - else // MPEG1 - return 12; - - case 0xBB: // System header - case 0xBD: // Private stream1 - case 0xBE: // Padding stream - case 0xBF: // Private stream2 (navigation data) - case 0xC0 ... 0xCF: // all the rest (the real packets) - case 0xD0 ... 0xDF: - case 0xE0 ... 0xEF: - return 6 + data[4] * 256 + data[5]; - } + cDevice::PrimaryDevice()->PlayTs(Data, Length); } // --- cDevice --------------------------------------------------------------- @@ -241,7 +81,6 @@ cDevice::cDevice(void) startScrambleDetection = 0; player = NULL; - pesAssembler = new cPesAssembler; ClrAvailableTracks(); currentAudioTrack = ttNone; currentAudioTrackMissingCount = 0; @@ -265,7 +104,6 @@ cDevice::~cDevice() DetachAllReceivers(); delete liveSubtitle; delete dvbSubtitleConverter; - delete pesAssembler; } bool cDevice::WaitForAllDevicesReady(int Timeout) @@ -1195,7 +1033,6 @@ bool cDevice::AttachPlayer(cPlayer *Player) Detach(player); DELETENULL(liveSubtitle); DELETENULL(dvbSubtitleConverter); - pesAssembler->Reset(); player = Player; if (!Transferring()) ClrAvailableTracks(false, true); @@ -1256,7 +1093,7 @@ int cDevice::PlaySubtitle(const uchar *Data, int Length) { if (!dvbSubtitleConverter) dvbSubtitleConverter = new cDvbSubtitleConverter; - return dvbSubtitleConverter->Convert(Data, Length); + return dvbSubtitleConverter->ConvertFragments(Data, Length); } int cDevice::PlayPesPacket(const uchar *Data, int Length, bool VideoOnly) @@ -1360,42 +1197,16 @@ pre_1_3_19_PrivateStreamDetected: int cDevice::PlayPes(const uchar *Data, int Length, bool VideoOnly) { if (!Data) { - pesAssembler->Reset(); if (dvbSubtitleConverter) dvbSubtitleConverter->Reset(); return 0; } - int Result = 0; - if (pesAssembler->Length()) { - // Make sure we have a complete PES header: - while (pesAssembler->Length() < 6 && Length > 0) { - pesAssembler->Put(*Data++); - Length--; - Result++; - } - if (pesAssembler->Length() < 6) - return Result; // Still no complete PES header - wait for more - int l = pesAssembler->ExpectedLength(); - int Rest = min(l - pesAssembler->Length(), Length); - pesAssembler->Put(Data, Rest); - Data += Rest; - Length -= Rest; - Result += Rest; - if (pesAssembler->Length() < l) - return Result; // Still no complete PES packet - wait for more - // Now pesAssembler contains one complete PES packet. - int w = PlayPesPacket(pesAssembler->Data(), pesAssembler->Length(), VideoOnly); - if (w > 0) - pesAssembler->Reset(); - return Result > 0 ? Result : w < 0 ? w : 0; - } int i = 0; while (i <= Length - 6) { if (Data[i] == 0x00 && Data[i + 1] == 0x00 && Data[i + 2] == 0x01) { - int l = cPesAssembler::PacketSize(&Data[i]); + int l = PesLength(Data + i); if (i + l > Length) { - // Store incomplete PES packet for later completion: - pesAssembler->Put(Data + i, Length - i); + esyslog("ERROR: incomplete PES packet!"); return Length; } int w = PlayPesPacket(Data + i, l, VideoOnly); @@ -1408,10 +1219,91 @@ int cDevice::PlayPes(const uchar *Data, int Length, bool VideoOnly) i++; } if (i < Length) - pesAssembler->Put(Data + i, Length - i); + esyslog("ERROR: leftover PES data!"); + return Length; +} + +int cDevice::PlayTsVideo(const uchar *Data, int Length) +{ + // Video PES has no explicit length, so we can only determine the end of + // a PES packet when the next TS packet that starts a payload comes in: + if (TsPayloadStart(Data)) { + if (const uchar *p = tsToPesVideo.GetPes(Length)) { + int w = PlayVideo(p, Length); + if (w > 0) + tsToPesVideo.Reset(); + else + return w; + } + } + tsToPesVideo.PutTs(Data, Length); + return Length; +} + +int cDevice::PlayTsAudio(const uchar *Data, int Length) +{ + bool PayloadStart = TsPayloadStart(Data); + for (int Pass = 0; Pass < 2; Pass++) { + if (Pass == 0 && !PayloadStart) // if no new payload is started, we can always put the packet into the converter + tsToPesAudio.PutTs(Data, Length); + if (const uchar *p = tsToPesAudio.GetPes(Length)) { + int w = PlayAudio(p, Length, 0); + if (w > 0) + tsToPesAudio.Reset(); + else if (PayloadStart) + return w; // must get out the old packet before starting a new one + } + if (Pass == 0 && PayloadStart) + tsToPesAudio.PutTs(Data, Length); + } return Length; } +int cDevice::PlayTsSubtitle(const uchar *Data, int Length) +{ + if (!dvbSubtitleConverter) + dvbSubtitleConverter = new cDvbSubtitleConverter; + tsToPesSubtitle.PutTs(Data, Length); + if (const uchar *p = tsToPesSubtitle.GetPes(Length)) { + dvbSubtitleConverter->Convert(p, Length); + tsToPesSubtitle.Reset(); + } + return Length; +} + +//TODO detect and report continuity errors? +int cDevice::PlayTs(const uchar *Data, int Length, bool VideoOnly) +{ + if (Length == TS_SIZE) { + if (!TsHasPayload(Data)) + return Length; // silently ignore TS packets w/o payload + int PayloadOffset = TsPayloadOffset(Data); + if (PayloadOffset < Length) { + int Pid = TsPid(Data); + if (Pid == 0) + patPmtParser.ParsePat(Data + PayloadOffset, Length - PayloadOffset); + else if (Pid == patPmtParser.PmtPid()) + patPmtParser.ParsePmt(Data + PayloadOffset, Length - PayloadOffset); + else if (Pid == patPmtParser.Vpid()) + return PlayTsVideo(Data, Length); + else if (Pid == availableTracks[currentAudioTrack].id) { + if (!VideoOnly || HasIBPTrickSpeed()) { + int w = PlayTsAudio(Data, Length); + if (w > 0) + Audios.PlayTsAudio(Data, Length); + return w; + } + } + else if (Pid == availableTracks[currentSubtitleTrack].id) { + if (!VideoOnly || HasIBPTrickSpeed()) + return PlayTsSubtitle(Data, Length); + } + return Length; + } + } + return -1; +} + int cDevice::Priority(void) const { int priority = IsPrimaryDevice() ? Setup.PrimaryLimit - 1 : DEFAULTPRIORITY; @@ -1448,7 +1340,7 @@ void cDevice::Action(void) uchar *b = NULL; if (GetTSPacket(b)) { if (b) { - int Pid = (((uint16_t)b[1] & PID_MASK_HI) << 8) | b[2]; + int Pid = TsPid(b); // Check whether the TS packets are scrambled: bool DetachReceivers = false; bool DescramblingOk = false; -- cgit v1.2.3