From fb5cccb2df60361a18fe3fd572b0fe18f3a4331c Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 9 Jan 2005 18:00:00 +0100 Subject: =?UTF-8?q?Version=201.3.18=20-=20Removed=20an=20unused=20variable?= =?UTF-8?q?=20from=20cTimer::GetWDayFromMDay()=20(thanks=20to=20Wayne=20Ke?= =?UTF-8?q?er=20=20=20for=20reporting=20this=20one).=20-=20Some=20more=20c?= =?UTF-8?q?hanges=20to=20the=20'childTid'=20handling=20in=20cThread=20(bas?= =?UTF-8?q?ed=20on=20suggestions=20by=20=20=20Stefan=20Huelswitt).=20-=20F?= =?UTF-8?q?ixed=20the=20spelling=20of=20'canceling'=20(thanks=20to=20Wayne?= =?UTF-8?q?=20Keer=20for=20reporting=20this=20one).=20-=20Re-introduced=20?= =?UTF-8?q?a=20sleep=20to=20cDvbPlayer::Action()=20to=20avoid=20high=20CPU?= =?UTF-8?q?=20load=20in=20still=20=20=20picture=20mode=20(thanks=20to=20Re?= =?UTF-8?q?inhard=20Nissl=20for=20reporting=20this=20one).=20-=20Fixed=20a?= =?UTF-8?q?=20possible=20race=20condition=20in=20generating=20the=20DVB=20?= =?UTF-8?q?device=20names=20(thanks=20to=20=20=20Rainer=20Zocholl=20for=20?= =?UTF-8?q?reporting=20this=20one).=20-=20Changed=20the=20way=20PES=20pack?= =?UTF-8?q?ets=20are=20played=20to=20allow=20replay=20of=20AC3=20sound=20o?= =?UTF-8?q?ver=20the=20=20=20full=20featured=20DVB=20cards=20(partially=20?= =?UTF-8?q?based=20on=20a=20patch=20from=20Werner=20Fink).=20=20=20+=20The?= =?UTF-8?q?=20new=20function=20cDevice::PlayPes()=20is=20now=20called=20wi?= =?UTF-8?q?th=20the=20complete=20PES=20data=20=20=20=20=20stream=20and=20c?= =?UTF-8?q?alls=20PlayVideo()=20and=20PlayAudio()=20as=20necessary.=20=20?= =?UTF-8?q?=20+=20cDevice::PlayVideo()=20is=20now=20only=20called=20with?= =?UTF-8?q?=20actual=20video=20PES=20packets.=20=20=20+=20cDevice::PlayAud?= =?UTF-8?q?io()=20is=20now=20called=20with=20the=20actual=20audio=20PES=20?= =?UTF-8?q?packets,=20which=20=20=20=20=20can=20be=20either=20"normal"=20a?= =?UTF-8?q?udio=20or=20AC3=20data.=20You=20need=20at=20least=20firmware=20?= =?UTF-8?q?version=20=20=20=20=200x261d=20to=20replay=20AC3=20sound=20over?= =?UTF-8?q?=20a=20full=20featured=20DVB=20card.=20This=20function=20now=20?= =?UTF-8?q?=20=20=20=20has=20an=20'int'=20return=20value.=20=20=20+=20Play?= =?UTF-8?q?Audio()=20of=20derived=20cDevice=20classes=20shall=20no=20longe?= =?UTF-8?q?r=20call=20the=20base=20class=20=20=20=20=20function.=20It=20sh?= =?UTF-8?q?all=20just=20play=20the=20given=20data=20as=20audio.=20=20=20+?= =?UTF-8?q?=20cPlayer::PlayVideo()=20and=20cPlayer::PlayAudio()=20are=20no?= =?UTF-8?q?w=20obsolete=20and=20have=20been=20=20=20=20=20replaced=20with?= =?UTF-8?q?=20cPlayer::PlayPes().=20=20=20+=20All=20StripAudioPackets()=20?= =?UTF-8?q?functions=20are=20now=20obsolete.=20The=20functionality=20has?= =?UTF-8?q?=20been=20=20=20=20=20moved=20into=20cDevice::PlayPes(),=20wher?= =?UTF-8?q?e=20only=20the=20video=20and=20audio=20packets=20that=20are=20?= =?UTF-8?q?=20=20=20=20actually=20required=20will=20be=20processed.=20=20?= =?UTF-8?q?=20+=20All=20audio=20track=20handling=20is=20now=20done=20by=20?= =?UTF-8?q?cDevice;=20cTransfer=20and=20cDvbPlayer=20no=20=20=20=20=20long?= =?UTF-8?q?er=20care=20about=20audio=20tracks.=20cPlayer,=20however,=20sti?= =?UTF-8?q?ll=20has=20the=20virtual=20hooks=20=20=20=20=20for=20audio=20tr?= =?UTF-8?q?ack=20handling=20in=20order=20to=20allow=20plugins=20to=20imple?= =?UTF-8?q?ment=20players=20that=20=20=20=20=20have=20their=20own=20idea?= =?UTF-8?q?=20about=20this.=20=20=20+=20cChannel::[AD]pid[12]()=20have=20b?= =?UTF-8?q?een=20replaced=20with=20cChannel::[AD]pid(int=20i)=20to=20=20?= =?UTF-8?q?=20=20=20allow=20access=20to=20all=20available=20PIDs.=20-=20Es?= =?UTF-8?q?caped=20the=20'-'=20and=20'=C3=B6'=20characters=20in=20the=20ma?= =?UTF-8?q?n=20pages=20(thanks=20to=20Darren=20Salt=20for=20=20=20pointing?= =?UTF-8?q?=20this=20out).=20-=20Completed=20the=20Italian=20OSD=20texts?= =?UTF-8?q?=20(thanks=20to=20Sean=20Carlos).=20-=20Fixed=20setting=20'sync?= =?UTF-8?q?ed'=20in=20cRemux=20when=20recording=20radio=20channels=20(than?= =?UTF-8?q?ks=20to=20=20=20Laurence=20Abbott).=20-=20Removed=20the=20LOCK?= =?UTF-8?q?=5FTHREAD=20from=20the=20LIRC=20thread=20(thanks=20to=20Ludwig?= =?UTF-8?q?=20Nussel).=20-=20Fixed=20genfontfile.c=20(sometimes=20the=20ch?= =?UTF-8?q?aracter=20width=20was=20wrong,=20and=20the=20codes=20were=20=20?= =?UTF-8?q?=20shifted=20one=20too=20far=20to=20the=20left).=20-=20Fixed=20?= =?UTF-8?q?the=20character=20width=20and=20shifted=20the=20codes=20one=20t?= =?UTF-8?q?o=20the=20right=20in=20all=20font=20=20=20files.=20-=20Renamed?= =?UTF-8?q?=20font=3F=3F=3F.c=20to=20font=3F=3F=3F-iso8859-1.c=20for=20sym?= =?UTF-8?q?metry.=20-=20Switched=20the=20character=20set=20to=20iso8859-15?= =?UTF-8?q?=20for=20English,=20German=20and=20Finnish=20(thanks=20=20=20to?= =?UTF-8?q?=20Andreas=20Brugger=20for=20reporting=20the=20missing=20Euro?= =?UTF-8?q?=20sign=20in=20iso8859-1).=20-=20Added=20'channels.conf.terr'?= =?UTF-8?q?=20entries=20for=20L=C3=BCbeck=20(thanks=20to=20Stefan=20Hu?= =?UTF-8?q?=C3=9Ffeldt).=20-=20Fixed=20a=20race=20condition=20in=20startin?= =?UTF-8?q?g=20a=20thread=20(thanks=20to=20Reinhard=20Nissl=20for=20=20=20?= =?UTF-8?q?reporting=20this=20one).=20-=20Replaced=20non-threadsafe=20libr?= =?UTF-8?q?ary=20functions=20with=20their=20threadsafe=20versions=20(thank?= =?UTF-8?q?s=20=20=20to=20Rainer=20Zocholl=20for=20pointing=20this=20out).?= =?UTF-8?q?=20-=20Other=20non-threadsafe=20functions=20have=20been=20repla?= =?UTF-8?q?ced=20by=20threadsafe=20classes=20that=20hide=20=20=20the=20act?= =?UTF-8?q?ual=20buffering.=20In=20particular=20these=20are:=20=20=20readd?= =?UTF-8?q?ir()=20->=20cReadDir=20=20=20readline()=20->=20cReadLine=20-=20?= =?UTF-8?q?Several=20formerly=20non-threadsafe=20functions=20now=20have=20?= =?UTF-8?q?a=20return=20type=20of=20cString:=20=20=20cChannel::ToText()=20?= =?UTF-8?q?=20=20tChannelID::ToString()=20=20=20cEvent::GetDateString()=20?= =?UTF-8?q?=20=20cEvent::GetTimeString()=20=20=20cEvent::GetEndTimeString(?= =?UTF-8?q?)=20=20=20cEvent::GetVpsString()=20=20=20cMark::ToText()=20=20?= =?UTF-8?q?=20cTimer::ToText()=20=20=20cSource::ToString()=20=20=20cTimer:?= =?UTF-8?q?:PrintDay()=20=20=20cTimer::PrintFirstDay()=20=20=20PrefixVideo?= =?UTF-8?q?FileName()=20=20=20IndexToHMSF()=20=20=20ChannelString()=20=20?= =?UTF-8?q?=20strescape()=20=20=20AddDirectory()=20=20=20itoa()=20=20=20We?= =?UTF-8?q?ekDayName()=20=20=20DayDateTime()=20=20=20When=20using=20these?= =?UTF-8?q?=20functions=20in=20a=20'const=20char=20*'=20context=20there=20?= =?UTF-8?q?is=20nothing=20special=20=20=20to=20consider,=20except=20that?= =?UTF-8?q?=20you=20can=20no=20longer=20have=20a=20pointer=20to=20the=20re?= =?UTF-8?q?turn=20value,=20=20=20as=20in=20=20=20const=20char=20*date=20?= =?UTF-8?q?=3D=20DayDateTime();=20=20=20Although=20this=20will=20compile?= =?UTF-8?q?=20without=20error=20message,=20the=20resulting=20'date'=20will?= =?UTF-8?q?=20not=20=20=20be=20valid=20after=20this=20line.=20Use=20this?= =?UTF-8?q?=20instead:=20=20=20cString=20date=20=3D=20DayDateTime();=20=20?= =?UTF-8?q?=20In=20a=20'const=20void=20*'=20context=20(as=20in=20printf()?= =?UTF-8?q?=20etc.)=20the=20result=20needs=20to=20be=20=20=20dereferenced?= =?UTF-8?q?=20with=20a=20'*',=20as=20in=20=20=20printf("%s",=20*DayDateTim?= =?UTF-8?q?e());=20=20=20to=20make=20it=20a=20'const=20char=20*'.=20-=20Re?= =?UTF-8?q?moved=20delay=5Fms(),=20using=20cCondWait::SleepMs()=20instead.?= =?UTF-8?q?=20-=20Replaced=20time=5Fms()=20with=20a=20threadsafe=20and=20n?= =?UTF-8?q?on-overflowing=20cTimeMs=20(thanks=20to=20Rainer=20=20=20Zochol?= =?UTF-8?q?l=20for=20pointing=20out=20this=20problem).=20-=20Added=20cDevi?= =?UTF-8?q?ce::mutexReceiver=20to=20avoid=20a=20race=20condition=20when=20?= =?UTF-8?q?attaching/detaching=20=20=20receivers=20from=20different=20thre?= =?UTF-8?q?ads.=20-=20The=20new=20remote=20control=20button=20"Audio"=20ca?= =?UTF-8?q?n=20be=20used=20to=20switch=20between=20different=20=20=20audio?= =?UTF-8?q?=20tracks.=20The=20"Green"=20button=20in=20the=20"Main"=20menu?= =?UTF-8?q?=20has=20been=20changed=20from=20"Language"=20=20=20to=20"Audio?= =?UTF-8?q?",=20since=20it=20now=20also=20controls=20switching=20between?= =?UTF-8?q?=20normal=20and=20Dolby=20Digital=20=20=20audio=20tracks=20(see?= =?UTF-8?q?=20MANUAL=20for=20details).=20-=20The=20description=20of=20the?= =?UTF-8?q?=20audio=20tracks=20is=20now=20taken=20from=20the=20"component?= =?UTF-8?q?=20descriptors"=20=20=20that=20are=20broadcast=20in=20the=20EPG?= =?UTF-8?q?=20data.=20However=20(as=20no=20big=20surprise),=20not=20all=20?= =?UTF-8?q?channels=20=20=20actually=20provide=20useful=20data=20here,=20s?= =?UTF-8?q?o=20there=20are=20now=20some=20additional=20EPG=20bugfixes,=20?= =?UTF-8?q?=20=20which=20can=20be=20activated=20by=20setting=20the=20"EPG?= =?UTF-8?q?=20bugfix=20level"=20to=203.=20-=20The=20format=20of=20the=20'e?= =?UTF-8?q?pg.data'=20files=20has=20been=20extended=20by=20the=20new=20tag?= =?UTF-8?q?=20'X',=20which=20=20=20contains=20the=20stream=20components=20?= =?UTF-8?q?of=20an=20event=20(see=20man=20vdr(5)=20for=20details).=20-=20T?= =?UTF-8?q?he=20cStatus=20class=20now=20has=20the=20new=20member=20functio?= =?UTF-8?q?n=20SetAudioTrack(),=20which=20can=20be=20=20=20used=20to=20get?= =?UTF-8?q?=20notified=20when=20the=20audio=20track=20has=20been=20switche?= =?UTF-8?q?d,=20and=20the=20new=20member=20=20=20function=20SetAudioChanne?= =?UTF-8?q?l()=20which=20is=20called=20when=20the=20audio=20channel=20is?= =?UTF-8?q?=20changed.=20-=20Skins=20need=20to=20implement=20the=20new=20c?= =?UTF-8?q?SkinDisplayTrack=20class=20to=20display=20the=20audio=20=20=20t?= =?UTF-8?q?rack=20menu.=20-=20The=20ST:TNG=20skin=20now=20displays=20the?= =?UTF-8?q?=20current=20audio=20track=20description=20(if=20any)=20at=20th?= =?UTF-8?q?e=20=20=20botton=20left=20side.=20-=20The=20new=20setup=20optio?= =?UTF-8?q?n=20"DVB/Audio=20languages"=20can=20be=20used=20to=20control=20?= =?UTF-8?q?which=20audio=20=20=20language=20shall=20be=20selected=20in=20c?= =?UTF-8?q?ase=20a=20channel=20broadcasts=20in=20different=20languages=20?= =?UTF-8?q?=20=20(see=20MANUAL=20for=20details).=20-=20The=20"Left"=20and?= =?UTF-8?q?=20"Right"=20keys=20in=20the=20"Audio"=20menu=20can=20be=20used?= =?UTF-8?q?=20to=20switch=20between=20=20=20the=20left=20and=20right=20ste?= =?UTF-8?q?reo=20channels=20in=20case=20there=20are=20different=20audio=20?= =?UTF-8?q?tracks=20=20=20in=20these=20channels=20(see=20MANUAL=20for=20de?= =?UTF-8?q?tails).=20-=20Fixed=20a=20possible=20race=20condition=20in=20cD?= =?UTF-8?q?evice::Action()=20(thanks=20to=20Mattias=20Gr=C3=B6nlund).=20-?= =?UTF-8?q?=20Fixed=20the=20default=20quality=20value=20when=20grabbing=20?= =?UTF-8?q?a=20JPEG=20image=20(thanks=20to=20Patrick=20=20=20Gleichmann).?= =?UTF-8?q?=20-=20Fixed=20deleting=20a=20menu=20item=20in=20case=20the=20n?= =?UTF-8?q?ext=20item=20is=20not=20selectable=20(thanks=20to=20=20=20Dino?= =?UTF-8?q?=20Ravnic).=20-=20Implemented=20displaying=20mandatory=20subtit?= =?UTF-8?q?les=20in=20the=20SPU=20decoder=20(thanks=20to=20Marco=20=20=20S?= =?UTF-8?q?chl=C3=BC=C3=9Fler).=20-=20The=20setup=20option=20"Recording/Re?= =?UTF-8?q?cord=20Dolby=20Digital"=20has=20been=20renamed=20and=20moved=20?= =?UTF-8?q?to=20=20=20"DVB/Use=20Dolby=20Digital".=20It=20now=20controls?= =?UTF-8?q?=20whether=20Dolby=20Digital=20is=20recorded=20and=20=20=20whet?= =?UTF-8?q?her=20an=20available=20DD=20audio=20track=20will=20appear=20in?= =?UTF-8?q?=20the=20"Audio"=20menu.=20-=20Added=20support=20for=20circular?= =?UTF-8?q?=20polarization=20(thanks=20to=20Jonan=20Santiago).=20-=20Thank?= =?UTF-8?q?s=20to=20Werner=20Fink,=20Reinhard=20Nissl,=20Sascha=20Volkenan?= =?UTF-8?q?dt=20and=20Bj=C3=B8rnar=20Nilsen=20for=20=20=20their=20support?= =?UTF-8?q?=20in=20testing=20and=20fine=20tuning=20this=20version.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- device.c | 312 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 291 insertions(+), 21 deletions(-) (limited to 'device.c') diff --git a/device.c b/device.c index 5a750ca..9e60b70 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 1.62 2004/10/30 14:53:38 kls Exp $ + * $Id: device.c 1.73 2005/01/09 12:36:48 kls Exp $ */ #include "device.h" @@ -19,6 +19,87 @@ #include "status.h" #include "transfer.h" +// --- 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 data[4] * 256 + data[5] + 6; } + int Length(void) { return length; } + const uchar *Data(void) { return data; } + 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) { + tag = (tag << 8) | c; + if ((tag & 0xFFFFFF00) == 0x00000100) { + if (Realloc(4)) { + *(uint32_t *)data = htonl(tag); + length = 4; + } + } + } + else if (Realloc(length + 1)) + data[length++] = c; +} + +void cPesAssembler::Put(const uchar *Data, int Length) +{ + while (!length && Length > 0) { + Put(*Data++); + Length--; + } + if (Length && Realloc(length + Length)) { + memcpy(data + length, Data, Length); + length += Length; + } +} + // --- cDevice --------------------------------------------------------------- // The default priority for non-primary devices: @@ -53,6 +134,9 @@ cDevice::cDevice(void) ciHandler = NULL; player = NULL; + pesAssembler = new cPesAssembler; + ClrAvailableTracks(); + currentAudioTrack = ttAudioFirst; for (int i = 0; i < MAXRECEIVERS; i++) receiver[i] = NULL; @@ -74,6 +158,7 @@ cDevice::~cDevice() delete patFilter; delete eitFilter; delete sectionHandler; + delete pesAssembler; } void cDevice::SetUseDevice(int n) @@ -427,7 +512,7 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView) if (CaDevice && CanReplay()) { cStatus::MsgChannelSwitch(this, 0); // only report status if we are actually going to switch the channel if (CaDevice->SetChannel(Channel, false) == scrOk) // calling SetChannel() directly, not SwitchChannel()! - cControl::Launch(new cTransferControl(CaDevice, Channel->Vpid(), Channel->Apid1(), Channel->Apid2(), Channel->Dpid1(), Channel->Dpid2()));//XXX+ + cControl::Launch(new cTransferControl(CaDevice, Channel->Vpid(), Channel->Apid(0), Channel->Apid(1), Channel->Dpid(0), Channel->Dpid(1))); else Result = scrNoTransfer; } @@ -455,8 +540,35 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView) } if (Result == scrOk) { - if (LiveView && IsPrimaryDevice()) + if (LiveView && IsPrimaryDevice()) { currentChannel = Channel->Number(); + // Set the available audio tracks: + ClrAvailableTracks(); + currentAudioTrack = ttAudioFirst; + for (int i = 0; i < MAXAPIDS; i++) { + SetAvailableTrack(ttAudio, i, Channel->Apid(i), Channel->Alang(i)); + if (Setup.UseDolbyDigital) + SetAvailableTrack(ttDolby, i, Channel->Dpid(i), Channel->Dlang(i)); + } + // Select the preferred audio track: + eTrackType PreferredTrack = ttAudioFirst; + int LanguagePreference = -1; + int StartCheck = Setup.CurrentDolby ? ttDolbyFirst : ttAudioFirst; + int EndCheck = ttDolbyLast; + for (int i = StartCheck; i <= EndCheck; i++) { + const tTrackId *TrackId = GetTrack(eTrackType(i)); + if (TrackId && TrackId->id && I18nIsPreferredLanguage(Setup.AudioLanguages, I18nLanguageIndex(TrackId->language), LanguagePreference)) + PreferredTrack = eTrackType(i); + if (Setup.CurrentDolby && i == ttDolbyLast) { + i = ttAudioFirst - 1; + EndCheck = ttAudioLast; + } + } + // Make sure we're set to an available audio track: + const tTrackId *Track = GetTrack(GetCurrentAudioTrack()); + if (!Track || !Track->id || PreferredTrack != GetCurrentAudioTrack()) + SetCurrentAudioTrack(PreferredTrack); + } cStatus::MsgChannelSwitch(this, Channel->Number()); // only report status if channel switch successfull } @@ -478,21 +590,24 @@ bool cDevice::HasProgramme(void) return Replaying() || pidHandles[ptAudio].pid || pidHandles[ptVideo].pid; } -void cDevice::SetVolumeDevice(int Volume) +int cDevice::GetAudioChannelDevice(void) { + return 0; } -int cDevice::NumAudioTracksDevice(void) const +void cDevice::SetAudioChannelDevice(int AudioChannel) { - return 0; } -const char **cDevice::GetAudioTracksDevice(int *CurrentTrack) const +void cDevice::SetVolumeDevice(int Volume) { - return NULL; } -void cDevice::SetAudioTrackDevice(int Index) +void cDevice::SetDigitalAudioDevice(bool On) +{ +} + +void cDevice::SetAudioTrackDevice(eTrackType Type) { } @@ -513,6 +628,18 @@ bool cDevice::ToggleMute(void) return mute; } +int cDevice::GetAudioChannel(void) +{ + int c = GetAudioChannelDevice(); + return (0 <= c && c <= 2) ? c : 0; +} + +void cDevice::SetAudioChannel(int AudioChannel) +{ + if (0 <= AudioChannel && AudioChannel <= 2) + SetAudioChannelDevice(AudioChannel); +} + void cDevice::SetVolume(int Volume, bool Absolute) { volume = min(max(Absolute ? Volume : volume + Volume, 0), MAXVOLUME); @@ -524,22 +651,66 @@ void cDevice::SetVolume(int Volume, bool Absolute) } } -int cDevice::NumAudioTracks(void) const +void cDevice::ClrAvailableTracks(bool DescriptionsOnly) { - return player ? player->NumAudioTracks() : NumAudioTracksDevice(); + if (DescriptionsOnly) { + for (int i = ttNone; i < ttMaxTrackTypes; i++) + *availableTracks[i].description = 0; + } + else + memset(availableTracks, 0, sizeof(availableTracks)); } -const char **cDevice::GetAudioTracks(int *CurrentTrack) const +bool cDevice::SetAvailableTrack(eTrackType Type, int Index, uint16_t Id, const char *Language, const char *Description, uint32_t Flags) { - return player ? player->GetAudioTracks(CurrentTrack) : GetAudioTracksDevice(CurrentTrack); + eTrackType t = eTrackType(Type + Index); + if (Type == ttAudio && IS_AUDIO_TRACK(t) || + Type == ttDolby && IS_DOLBY_TRACK(t)) { + if (Language) + strn0cpy(availableTracks[t].language, Language, sizeof(availableTracks[t].language)); + if (Description) + strn0cpy(availableTracks[t].description, Description, sizeof(availableTracks[t].description)); + if (Id) { + availableTracks[t].flags = Flags; + availableTracks[t].id = Id; // setting 'id' last to avoid the need for extensive locking + } + return true; + } + else + esyslog("ERROR: SetAvailableTrack called with invalid Type/Index (%d/%d)", Type, Index); + return false; } -void cDevice::SetAudioTrack(int Index) +const tTrackId *cDevice::GetTrack(eTrackType Type) { - if (player) - player->SetAudioTrack(Index); - else - SetAudioTrackDevice(Index); + return (ttNone < Type && Type < ttMaxTrackTypes) ? &availableTracks[Type] : NULL; +} + +int cDevice::NumAudioTracks(void) const +{ + int n = 0; + for (int i = ttAudioFirst; i <= ttDolbyLast; i++) { + if (availableTracks[i].id) + n++; + } + return n; +} + +bool cDevice::SetCurrentAudioTrack(eTrackType Type) +{ + if (ttNone < Type && Type < ttDolbyLast) { + if (IS_DOLBY_TRACK(Type)) + SetDigitalAudioDevice(true); + currentAudioTrack = Type; + if (player) + player->SetAudioTrack(currentAudioTrack, GetTrack(currentAudioTrack)); + else + SetAudioTrackDevice(currentAudioTrack); + if (IS_AUDIO_TRACK(Type)) + SetDigitalAudioDevice(false); + return true; + } + return false; } bool cDevice::CanReplay(void) const @@ -595,6 +766,7 @@ bool cDevice::AttachPlayer(cPlayer *Player) if (CanReplay()) { if (player) Detach(player); + ClrAvailableTracks(); player = Player; SetPlayMode(player->playMode); player->device = this; @@ -639,11 +811,107 @@ int cDevice::PlayVideo(const uchar *Data, int Length) return -1; } -void cDevice::PlayAudio(const uchar *Data, int Length) +int cDevice::PlayAudio(const uchar *Data, int Length) +{ + return -1; +} + +int cDevice::PlayPesPacket(const uchar *Data, int Length, bool VideoOnly) { - Audios.PlayAudio(Data, Length); + bool FirstLoop = true; + uchar c = Data[3]; + const uchar *Start = Data; + const uchar *End = Start + Length; + while (Start < End) { + int d = End - Start; + int w = d; + switch (c) { + case 0xE0 ... 0xEF: // video + w = PlayVideo(Start, d); + break; + case 0xC0 ... 0xDF: // audio + SetAvailableTrack(ttAudio, c - 0xC0, c); + if (!VideoOnly && c == availableTracks[currentAudioTrack].id) + w = PlayAudio(Start, d); + break; + case 0xBD: // dolby + if (Setup.UseDolbyDigital) { + SetAvailableTrack(ttDolby, 0, c); + if (!VideoOnly && c == availableTracks[currentAudioTrack].id) { + w = PlayAudio(Start, d); + if (FirstLoop) + Audios.PlayAudio(Data, Length); + } + } + break; + default: + ;//esyslog("ERROR: unexpected packet id %02X", c); + } + if (w > 0) + Start += w; + else if (w <= 0) { + if (Start != Data) + esyslog("ERROR: incomplete PES packet write!"); + return Start == Data ? w : Start - Data; + } + FirstLoop = false; + } + return Length; } +int cDevice::PlayPes(const uchar *Data, int Length, bool VideoOnly) +{ + if (!Data) { + pesAssembler->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 = Data[i + 4] * 256 + Data[i + 5] + 6; + if (i + l > Length) { + // Store incomplete PES packet for later completion: + pesAssembler->Put(Data + i, Length - i); + return Length; + } + int w = PlayPesPacket(Data + i, l, VideoOnly); + if (w > 0) + i += l; + else if (w < 0) + return i == 0 ? w : i; + } + else + i++; + } + if (i < Length) + pesAssembler->Put(Data + i, Length - i); + return Length; + } + int cDevice::Ca(void) const { int ca = 0; @@ -722,8 +990,8 @@ bool cDevice::Receiving(bool CheckAny) const void cDevice::Action(void) { + active = true; if (OpenDvr()) { - active = true; for (; active;) { // Read data from the DVR device: uchar *b = NULL; @@ -770,6 +1038,7 @@ bool cDevice::AttachReceiver(cReceiver *Receiver) esyslog("ERROR: device %d has no lock, can't attach receiver!", CardIndex() + 1); return false; } + cMutexLock MutexLock(&mutexReceiver); for (int i = 0; i < MAXRECEIVERS; i++) { if (!receiver[i]) { for (int n = 0; n < MAXRECEIVEPIDS; n++) { @@ -797,6 +1066,7 @@ void cDevice::Detach(cReceiver *Receiver) if (!Receiver || Receiver->device != this) return; bool receiversLeft = false; + cMutexLock MutexLock(&mutexReceiver); for (int i = 0; i < MAXRECEIVERS; i++) { if (receiver[i] == Receiver) { Receiver->Activate(false); -- cgit v1.2.3