vdr
1.7.27
|
00001 /* 00002 * dvbhdffdevice.c: The DVB HD Full Featured device interface 00003 * 00004 * See the README file for copyright information and how to reach the author. 00005 * 00006 * $Id: dvbhdffdevice.c 1.41 2012/03/07 13:52:41 kls Exp $ 00007 */ 00008 00009 #include <stdint.h> 00010 00011 #include "dvbhdffdevice.h" 00012 #include <errno.h> 00013 #include <limits.h> 00014 #include <libsi/si.h> 00015 #include <linux/videodev2.h> 00016 #include <linux/dvb/audio.h> 00017 #include <linux/dvb/dmx.h> 00018 #include <linux/dvb/video.h> 00019 #include <sys/ioctl.h> 00020 #include <sys/mman.h> 00021 #include <vdr/eitscan.h> 00022 #include <vdr/transfer.h> 00023 #include "hdffosd.h" 00024 #include "setup.h" 00025 00026 // --- cDvbHdFfDevice ---------------------------------------------------------- 00027 00028 int cDvbHdFfDevice::devHdffOffset = -1; 00029 00030 cDvbHdFfDevice::cDvbHdFfDevice(int Adapter, int Frontend) 00031 :cDvbDevice(Adapter, Frontend) 00032 { 00033 spuDecoder = NULL; 00034 audioChannel = 0; 00035 playMode = pmNone; 00036 mHdffCmdIf = NULL; 00037 00038 // Devices that are only present on cards with decoders: 00039 00040 fd_osd = DvbOpen(DEV_DVB_OSD, adapter, frontend, O_RDWR); 00041 fd_video = DvbOpen(DEV_DVB_VIDEO, adapter, frontend, O_RDWR | O_NONBLOCK); 00042 fd_audio = DvbOpen(DEV_DVB_AUDIO, adapter, frontend, O_RDWR | O_NONBLOCK); 00043 00044 //TODO missing /dev/video offset calculation 00045 00046 isHdffPrimary = false; 00047 if (devHdffOffset < 0) { 00048 devHdffOffset = adapter; 00049 isHdffPrimary = true; 00050 mHdffCmdIf = new HDFF::cHdffCmdIf(fd_osd); 00051 00052 /* reset some stuff in case the VDR was killed before and had no chance 00053 to clean up. */ 00054 mHdffCmdIf->CmdOsdReset(); 00055 00056 mHdffCmdIf->CmdAvSetVideoSpeed(0, 100); 00057 mHdffCmdIf->CmdAvSetAudioSpeed(0, 100); 00058 00059 mHdffCmdIf->CmdAvEnableVideoAfterStop(0, false); 00060 mHdffCmdIf->CmdAvSetPcrPid(0, 0); 00061 mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF_VIDEO_STREAM_MPEG1); 00062 mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1); 00063 00064 ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX); 00065 mHdffCmdIf->CmdAvSetDecoderInput(0, 0); 00066 mHdffCmdIf->CmdAvEnableSync(0, true); 00067 mHdffCmdIf->CmdAvSetPlayMode(0, true); 00068 /* reset done */ 00069 00070 mHdffCmdIf->CmdAvSetAudioDelay(gHdffSetup.AudioDelay); 00071 mHdffCmdIf->CmdAvSetAudioDownmix((HdffAudioDownmixMode_t) gHdffSetup.AudioDownmix); 00072 mHdffCmdIf->CmdMuxSetVideoOut((HdffVideoOut_t) gHdffSetup.AnalogueVideo); 00073 mHdffCmdIf->CmdHdmiSetVideoMode(gHdffSetup.GetVideoMode()); 00074 00075 HdffHdmiConfig_t hdmiConfig; 00076 memset(&hdmiConfig, 0, sizeof(hdmiConfig)); 00077 hdmiConfig.TransmitAudio = true; 00078 hdmiConfig.ForceDviMode = false; 00079 hdmiConfig.CecEnabled = gHdffSetup.CecEnabled; 00080 strcpy(hdmiConfig.CecDeviceName, "VDR"); 00081 hdmiConfig.VideoModeAdaption = (HdffVideoModeAdaption_t) gHdffSetup.VideoModeAdaption; 00082 mHdffCmdIf->CmdHdmiConfigure(&hdmiConfig); 00083 00084 mHdffCmdIf->CmdRemoteSetProtocol((HdffRemoteProtocol_t) gHdffSetup.RemoteProtocol); 00085 mHdffCmdIf->CmdRemoteSetAddressFilter(gHdffSetup.RemoteAddress >= 0, gHdffSetup.RemoteAddress); 00086 } 00087 } 00088 00089 cDvbHdFfDevice::~cDvbHdFfDevice() 00090 { 00091 delete spuDecoder; 00092 if (isHdffPrimary) 00093 { 00094 if (gHdffSetup.CecEnabled && gHdffSetup.CecTvOff) 00095 { 00096 mHdffCmdIf->CmdHdmiSendCecCommand(HDFF_CEC_COMMAND_TV_OFF); 00097 } 00098 delete mHdffCmdIf; 00099 } 00100 // We're not explicitly closing any device files here, since this sometimes 00101 // caused segfaults. Besides, the program is about to terminate anyway... 00102 } 00103 00104 void cDvbHdFfDevice::MakePrimaryDevice(bool On) 00105 { 00106 if (On) 00107 new cHdffOsdProvider(mHdffCmdIf); 00108 cDvbDevice::MakePrimaryDevice(On); 00109 } 00110 00111 bool cDvbHdFfDevice::HasDecoder(void) const 00112 { 00113 return isHdffPrimary; 00114 } 00115 00116 cSpuDecoder *cDvbHdFfDevice::GetSpuDecoder(void) 00117 { 00118 if (!spuDecoder && IsPrimaryDevice()) 00119 spuDecoder = new cDvbSpuDecoder(); 00120 return spuDecoder; 00121 } 00122 00123 uchar *cDvbHdFfDevice::GrabImage(int &Size, bool Jpeg, int Quality, int SizeX, int SizeY) 00124 { 00125 //TODO 00126 return NULL; 00127 } 00128 00129 void cDvbHdFfDevice::SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat) 00130 { 00131 //TODO??? 00132 cDevice::SetVideoDisplayFormat(VideoDisplayFormat); 00133 } 00134 00135 void cDvbHdFfDevice::SetVideoFormat(bool VideoFormat16_9) 00136 { 00137 HdffVideoFormat_t videoFormat; 00138 videoFormat.AutomaticEnabled = true; 00139 videoFormat.AfdEnabled = true; 00140 videoFormat.TvFormat = (HdffTvFormat_t) gHdffSetup.TvFormat; 00141 videoFormat.VideoConversion = (HdffVideoConversion_t) gHdffSetup.VideoConversion; 00142 mHdffCmdIf->CmdAvSetVideoFormat(0, &videoFormat); 00143 } 00144 00145 eVideoSystem cDvbHdFfDevice::GetVideoSystem(void) 00146 { 00147 eVideoSystem VideoSystem = vsPAL; 00148 if (fd_video >= 0) { 00149 video_size_t vs; 00150 if (ioctl(fd_video, VIDEO_GET_SIZE, &vs) == 0) { 00151 if (vs.h == 480 || vs.h == 240) 00152 VideoSystem = vsNTSC; 00153 } 00154 else 00155 LOG_ERROR; 00156 } 00157 return VideoSystem; 00158 } 00159 00160 void cDvbHdFfDevice::GetVideoSize(int &Width, int &Height, double &VideoAspect) 00161 { 00162 if (fd_video >= 0) { 00163 video_size_t vs; 00164 if (ioctl(fd_video, VIDEO_GET_SIZE, &vs) == 0) { 00165 Width = vs.w; 00166 Height = vs.h; 00167 switch (vs.aspect_ratio) { 00168 default: 00169 case VIDEO_FORMAT_4_3: VideoAspect = 4.0 / 3.0; break; 00170 case VIDEO_FORMAT_16_9: VideoAspect = 16.0 / 9.0; break; 00171 case VIDEO_FORMAT_221_1: VideoAspect = 2.21; break; 00172 } 00173 return; 00174 } 00175 else 00176 LOG_ERROR; 00177 } 00178 cDevice::GetVideoSize(Width, Height, VideoAspect); 00179 } 00180 00181 void cDvbHdFfDevice::GetOsdSize(int &Width, int &Height, double &PixelAspect) 00182 { 00183 gHdffSetup.GetOsdSize(Width, Height, PixelAspect); 00184 } 00185 00186 /*TODO obsolete? 00187 bool cDvbHdFfDevice::SetAudioBypass(bool On) 00188 { 00189 if (setTransferModeForDolbyDigital != 1) 00190 return false; 00191 return ioctl(fd_audio, AUDIO_SET_BYPASS_MODE, On) == 0; 00192 } 00193 TODO*/ 00194 00195 bool cDvbHdFfDevice::SetPid(cPidHandle *Handle, int Type, bool On) 00196 { 00197 if (Handle->pid) { 00198 dmx_pes_filter_params pesFilterParams; 00199 memset(&pesFilterParams, 0, sizeof(pesFilterParams)); 00200 if (On) { 00201 if (Handle->handle < 0) { 00202 Handle->handle = DvbOpen(DEV_DVB_DEMUX, adapter, frontend, O_RDWR | O_NONBLOCK, true); 00203 if (Handle->handle < 0) { 00204 LOG_ERROR; 00205 return false; 00206 } 00207 } 00208 if (Type == ptPcr) 00209 mHdffCmdIf->CmdAvSetPcrPid(0, Handle->pid); 00210 else if (Type == ptVideo) { 00211 if (Handle->streamType == 0x1B) 00212 mHdffCmdIf->CmdAvSetVideoPid(0, Handle->pid, HDFF_VIDEO_STREAM_H264); 00213 else 00214 mHdffCmdIf->CmdAvSetVideoPid(0, Handle->pid, HDFF_VIDEO_STREAM_MPEG2); 00215 } 00216 else if (Type == ptAudio) 00217 mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF_AUDIO_STREAM_MPEG1); 00218 else if (Type == ptDolby) 00219 mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF_AUDIO_STREAM_AC3); 00220 if (!(Type <= ptDolby && Handle->used <= 1)) { 00221 pesFilterParams.pid = Handle->pid; 00222 pesFilterParams.input = DMX_IN_FRONTEND; 00223 pesFilterParams.output = DMX_OUT_TS_TAP; 00224 pesFilterParams.pes_type= DMX_PES_OTHER; 00225 pesFilterParams.flags = DMX_IMMEDIATE_START; 00226 if (ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams) < 0) { 00227 LOG_ERROR; 00228 return false; 00229 } 00230 } 00231 } 00232 else if (!Handle->used) { 00233 CHECK(ioctl(Handle->handle, DMX_STOP)); 00234 if (Type == ptPcr) 00235 mHdffCmdIf->CmdAvSetPcrPid(0, 0); 00236 else if (Type == ptVideo) 00237 mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF_VIDEO_STREAM_MPEG1); 00238 else if (Type == ptAudio) 00239 mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1); 00240 else if (Type == ptDolby) 00241 mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_AC3); 00242 //TODO missing setting to 0x1FFF??? see cDvbDevice::SetPid() 00243 close(Handle->handle); 00244 Handle->handle = -1; 00245 } 00246 } 00247 return true; 00248 } 00249 00250 void cDvbHdFfDevice::TurnOffLiveMode(bool LiveView) 00251 { 00252 // Turn off live PIDs: 00253 00254 DetachAll(pidHandles[ptAudio].pid); 00255 DetachAll(pidHandles[ptVideo].pid); 00256 DetachAll(pidHandles[ptPcr].pid); 00257 DetachAll(pidHandles[ptTeletext].pid); 00258 DelPid(pidHandles[ptAudio].pid); 00259 DelPid(pidHandles[ptVideo].pid); 00260 DelPid(pidHandles[ptPcr].pid, ptPcr); 00261 DelPid(pidHandles[ptTeletext].pid); 00262 DelPid(pidHandles[ptDolby].pid); 00263 } 00264 00265 bool cDvbHdFfDevice::SetChannelDevice(const cChannel *Channel, bool LiveView) 00266 { 00267 int apid = Channel->Apid(0); 00268 int vpid = Channel->Vpid(); 00269 int dpid = Channel->Dpid(0); 00270 00271 bool DoTune = !IsTunedToTransponder(Channel); 00272 00273 bool pidHandlesVideo = pidHandles[ptVideo].pid == vpid; 00274 bool pidHandlesAudio = pidHandles[ptAudio].pid == apid; 00275 00276 bool TurnOffLivePIDs = DoTune 00277 || !IsPrimaryDevice() 00278 || LiveView // for a new live view the old PIDs need to be turned off 00279 || pidHandlesVideo // for recording the PIDs must be shifted from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER 00280 ; 00281 00282 bool StartTransferMode = IsPrimaryDevice() && !DoTune 00283 && (LiveView && HasPid(vpid ? vpid : apid) && (!pidHandlesVideo || (!pidHandlesAudio && (dpid ? pidHandles[ptAudio].pid != dpid : true)))// the PID is already set as DMX_PES_OTHER 00284 || !LiveView && (pidHandlesVideo || pidHandlesAudio) // a recording is going to shift the PIDs from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER 00285 ); 00286 if (CamSlot() && !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), CamSlot()->SlotNumber())) 00287 StartTransferMode |= LiveView && IsPrimaryDevice() && Channel->Ca() >= CA_ENCRYPTED_MIN; 00288 00289 bool TurnOnLivePIDs = !StartTransferMode && LiveView; 00290 00291 // Turn off live PIDs if necessary: 00292 00293 if (TurnOffLivePIDs) 00294 TurnOffLiveMode(LiveView); 00295 00296 // Set the tuner: 00297 00298 if (!cDvbDevice::SetChannelDevice(Channel, LiveView)) 00299 return false; 00300 00301 // PID settings: 00302 00303 if (TurnOnLivePIDs) { 00304 //SetAudioBypass(false);//TODO obsolete? 00305 if (!(AddPid(Channel->Ppid(), ptPcr) && AddPid(vpid, ptVideo, Channel->Vtype()) && AddPid(apid, ptAudio))) { 00306 esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->Number(), CardIndex() + 1); 00307 return false; 00308 } 00309 if (IsPrimaryDevice()) 00310 AddPid(Channel->Tpid(), ptTeletext);//TODO obsolete? 00311 } 00312 else if (StartTransferMode) 00313 cControl::Launch(new cTransferControl(this, Channel)); 00314 00315 return true; 00316 } 00317 00318 int cDvbHdFfDevice::GetAudioChannelDevice(void) 00319 { 00320 return audioChannel; 00321 } 00322 00323 void cDvbHdFfDevice::SetAudioChannelDevice(int AudioChannel) 00324 { 00325 mHdffCmdIf->CmdAvSetAudioChannel(AudioChannel); 00326 audioChannel = AudioChannel; 00327 } 00328 00329 void cDvbHdFfDevice::SetVolumeDevice(int Volume) 00330 { 00331 mHdffCmdIf->CmdMuxSetVolume(Volume * 100 / 255); 00332 } 00333 00334 void cDvbHdFfDevice::SetDigitalAudioDevice(bool On) 00335 { 00336 // not needed 00337 } 00338 00339 void cDvbHdFfDevice::SetAudioTrackDevice(eTrackType Type) 00340 { 00341 //printf("SetAudioTrackDevice %d\n", Type); 00342 const tTrackId *TrackId = GetTrack(Type); 00343 if (TrackId && TrackId->id) { 00344 if (IS_AUDIO_TRACK(Type)) { 00345 if (pidHandles[ptAudio].pid && pidHandles[ptAudio].pid != TrackId->id) { 00346 DetachAll(pidHandles[ptAudio].pid); 00347 if (CamSlot()) 00348 CamSlot()->SetPid(pidHandles[ptAudio].pid, false); 00349 pidHandles[ptAudio].pid = TrackId->id; 00350 SetPid(&pidHandles[ptAudio], ptAudio, true); 00351 if (CamSlot()) { 00352 CamSlot()->SetPid(pidHandles[ptAudio].pid, true); 00353 CamSlot()->StartDecrypting(); 00354 } 00355 } 00356 } 00357 else if (IS_DOLBY_TRACK(Type)) { 00358 pidHandles[ptDolby].pid = TrackId->id; 00359 SetPid(&pidHandles[ptDolby], ptDolby, true); 00360 } 00361 } 00362 } 00363 00364 bool cDvbHdFfDevice::CanReplay(void) const 00365 { 00366 return cDevice::CanReplay(); 00367 } 00368 00369 bool cDvbHdFfDevice::SetPlayMode(ePlayMode PlayMode) 00370 { 00371 if (PlayMode == pmNone) { 00372 mHdffCmdIf->CmdAvSetVideoSpeed(0, 100); 00373 mHdffCmdIf->CmdAvSetAudioSpeed(0, 100); 00374 00375 mHdffCmdIf->CmdAvEnableVideoAfterStop(0, false); 00376 mHdffCmdIf->CmdAvSetPcrPid(0, 0); 00377 mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF_VIDEO_STREAM_MPEG1); 00378 mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1); 00379 00380 ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX); 00381 mHdffCmdIf->CmdAvSetDecoderInput(0, 0); 00382 mHdffCmdIf->CmdAvEnableSync(0, true); 00383 mHdffCmdIf->CmdAvSetPlayMode(0, true); 00384 } 00385 else { 00386 if (playMode == pmNone) 00387 TurnOffLiveMode(true); 00388 00389 mHdffCmdIf->CmdAvSetPlayMode(1, Transferring() || (cTransferControl::ReceiverDevice() == this)); 00390 mHdffCmdIf->CmdAvSetStc(0, 100000); 00391 mHdffCmdIf->CmdAvEnableSync(0, true); 00392 mHdffCmdIf->CmdAvEnableVideoAfterStop(0, true); 00393 00394 playVideoPid = -1; 00395 playAudioPid = -1; 00396 audioCounter = 0; 00397 videoCounter = 0; 00398 freezed = false; 00399 trickMode = false; 00400 00401 mHdffCmdIf->CmdAvSetDecoderInput(0, 2); 00402 ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY); 00403 } 00404 playMode = PlayMode; 00405 return true; 00406 } 00407 00408 int64_t cDvbHdFfDevice::GetSTC(void) 00409 { 00410 if (fd_video >= 0) { 00411 uint64_t pts; 00412 if (ioctl(fd_video, VIDEO_GET_PTS, &pts) == -1) { 00413 esyslog("ERROR: pts %d: %m", CardIndex() + 1); 00414 return -1; 00415 } 00416 return pts; 00417 } 00418 if (fd_audio >= 0) { 00419 uint64_t pts; 00420 if (ioctl(fd_audio, AUDIO_GET_PTS, &pts) == -1) { 00421 esyslog("ERROR: pts %d: %m", CardIndex() + 1); 00422 return -1; 00423 } 00424 return pts; 00425 } 00426 return -1; 00427 } 00428 00429 void cDvbHdFfDevice::TrickSpeed(int Speed) 00430 { 00431 freezed = false; 00432 mHdffCmdIf->CmdAvEnableSync(0, false); 00433 mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1); 00434 playAudioPid = -1; 00435 if (Speed > 0) 00436 mHdffCmdIf->CmdAvSetVideoSpeed(0, 100 / Speed); 00437 trickMode = true; 00438 } 00439 00440 void cDvbHdFfDevice::Clear(void) 00441 { 00442 CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER)); 00443 mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF_VIDEO_STREAM_MPEG1); 00444 mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1); 00445 playVideoPid = -1; 00446 playAudioPid = -1; 00447 cDevice::Clear(); 00448 } 00449 00450 void cDvbHdFfDevice::Play(void) 00451 { 00452 freezed = false; 00453 trickMode = false; 00454 mHdffCmdIf->CmdAvEnableSync(0, true); 00455 mHdffCmdIf->CmdAvSetVideoSpeed(0, 100); 00456 mHdffCmdIf->CmdAvSetAudioSpeed(0, 100); 00457 cDevice::Play(); 00458 } 00459 00460 void cDvbHdFfDevice::Freeze(void) 00461 { 00462 freezed = true; 00463 mHdffCmdIf->CmdAvSetVideoSpeed(0, 0); 00464 mHdffCmdIf->CmdAvSetAudioSpeed(0, 0); 00465 cDevice::Freeze(); 00466 } 00467 00468 void cDvbHdFfDevice::Mute(void) 00469 { 00470 //TODO??? 00471 cDevice::Mute(); 00472 } 00473 00474 static HdffVideoStreamType_t MapVideoStreamTypes(int Vtype) 00475 { 00476 switch (Vtype) { 00477 case 0x01: return HDFF_VIDEO_STREAM_MPEG1; 00478 case 0x02: return HDFF_VIDEO_STREAM_MPEG2; 00479 case 0x1B: return HDFF_VIDEO_STREAM_H264; 00480 default: return HDFF_VIDEO_STREAM_MPEG2; // fallback to MPEG2 00481 } 00482 } 00483 00484 void cDvbHdFfDevice::StillPicture(const uchar *Data, int Length) 00485 { 00486 if (!Data || Length < TS_SIZE) 00487 return; 00488 if (Data[0] == 0x47) { 00489 // TS data 00490 cDevice::StillPicture(Data, Length); 00491 } 00492 else if (Data[0] == 0x00 && Data[1] == 0x00 && Data[2] == 0x01 && (Data[3] & 0xF0) == 0xE0) { 00493 // PES data 00494 char *buf = MALLOC(char, Length); 00495 if (!buf) 00496 return; 00497 int i = 0; 00498 int blen = 0; 00499 while (i < Length - 6) { 00500 if (Data[i] == 0x00 && Data[i + 1] == 0x00 && Data[i + 2] == 0x01) { 00501 int len = Data[i + 4] * 256 + Data[i + 5]; 00502 if ((Data[i + 3] & 0xF0) == 0xE0) { // video packet 00503 // skip PES header 00504 int offs = i + 6; 00505 // skip header extension 00506 if ((Data[i + 6] & 0xC0) == 0x80) { 00507 // MPEG-2 PES header 00508 if (Data[i + 8] >= Length) 00509 break; 00510 offs += 3; 00511 offs += Data[i + 8]; 00512 len -= 3; 00513 len -= Data[i + 8]; 00514 if (len < 0 || offs + len > Length) 00515 break; 00516 } 00517 else { 00518 // MPEG-1 PES header 00519 while (offs < Length && len > 0 && Data[offs] == 0xFF) { 00520 offs++; 00521 len--; 00522 } 00523 if (offs <= Length - 2 && len >= 2 && (Data[offs] & 0xC0) == 0x40) { 00524 offs += 2; 00525 len -= 2; 00526 } 00527 if (offs <= Length - 5 && len >= 5 && (Data[offs] & 0xF0) == 0x20) { 00528 offs += 5; 00529 len -= 5; 00530 } 00531 else if (offs <= Length - 10 && len >= 10 && (Data[offs] & 0xF0) == 0x30) { 00532 offs += 10; 00533 len -= 10; 00534 } 00535 else if (offs < Length && len > 0) { 00536 offs++; 00537 len--; 00538 } 00539 } 00540 if (blen + len > Length) // invalid PES length field 00541 break; 00542 memcpy(&buf[blen], &Data[offs], len); 00543 i = offs + len; 00544 blen += len; 00545 } 00546 else if (Data[i + 3] >= 0xBD && Data[i + 3] <= 0xDF) // other PES packets 00547 i += len + 6; 00548 else 00549 i++; 00550 } 00551 else 00552 i++; 00553 } 00554 mHdffCmdIf->CmdAvShowStillImage(0, (uint8_t *)buf, blen, MapVideoStreamTypes(PatPmtParser()->Vtype())); 00555 free(buf); 00556 } 00557 else { 00558 // non-PES data 00559 mHdffCmdIf->CmdAvShowStillImage(0, Data, Length, MapVideoStreamTypes(PatPmtParser()->Vtype())); 00560 } 00561 } 00562 00563 bool cDvbHdFfDevice::Poll(cPoller &Poller, int TimeoutMs) 00564 { 00565 Poller.Add(fd_video, true); 00566 return Poller.Poll(TimeoutMs); 00567 } 00568 00569 bool cDvbHdFfDevice::Flush(int TimeoutMs) 00570 { 00571 //TODO actually this function should wait until all buffered data has been processed by the card, but how? 00572 return true; 00573 } 00574 00575 void cDvbHdFfDevice::BuildTsPacket(uint8_t * TsBuffer, bool PusiSet, uint16_t Pid, uint8_t Counter, const uint8_t * Data, uint32_t Length) 00576 { 00577 TsBuffer[0] = 0x47; 00578 TsBuffer[1] = PusiSet ? 0x40 : 0x00; 00579 TsBuffer[1] |= Pid >> 8; 00580 TsBuffer[2] = Pid & 0xFF; 00581 if (Length >= 184) 00582 { 00583 TsBuffer[3] = 0x10 | Counter; 00584 memcpy(TsBuffer + 4, Data, 184); 00585 } 00586 else 00587 { 00588 uint8_t adaptationLength; 00589 00590 TsBuffer[3] = 0x30 | Counter; 00591 adaptationLength = 183 - Length; 00592 TsBuffer[4] = adaptationLength; 00593 if (adaptationLength > 0) 00594 { 00595 TsBuffer[5] = 0x00; 00596 memset(TsBuffer + 6, 0xFF, adaptationLength - 1); 00597 } 00598 memcpy(TsBuffer + 5 + adaptationLength, Data, Length); 00599 } 00600 } 00601 00602 uint32_t cDvbHdFfDevice::PesToTs(uint8_t * TsBuffer, uint16_t Pid, uint8_t & Counter, const uint8_t * Data, uint32_t Length) 00603 { 00604 uint32_t tsOffset; 00605 uint32_t i; 00606 00607 tsOffset = 0; 00608 i = 0; 00609 while (Length > 0) 00610 { 00611 BuildTsPacket(TsBuffer + tsOffset, i == 0, Pid, Counter, Data + i * 184, Length); 00612 if (Length >= 184) 00613 Length -= 184; 00614 else 00615 Length = 0; 00616 Counter = (Counter + 1) & 15; 00617 tsOffset += 188; 00618 i++; 00619 } 00620 return tsOffset; 00621 } 00622 00623 int cDvbHdFfDevice::PlayVideo(const uchar *Data, int Length) 00624 { 00625 if (freezed) 00626 return -1; 00627 //TODO: support greater Length 00628 uint8_t tsBuffer[188 * 16]; 00629 uint32_t tsLength; 00630 int pid = 100; 00631 00632 tsLength = PesToTs(tsBuffer, pid, videoCounter, Data, Length); 00633 00634 if (pid != playVideoPid) { 00635 playVideoPid = pid; 00636 mHdffCmdIf->CmdAvSetVideoPid(0, playVideoPid, HDFF_VIDEO_STREAM_MPEG2, true); 00637 } 00638 if (WriteAllOrNothing(fd_video, tsBuffer, tsLength, 1000, 10) <= 0) 00639 Length = 0; 00640 return Length; 00641 } 00642 00643 int cDvbHdFfDevice::PlayAudio(const uchar *Data, int Length, uchar Id) 00644 { 00645 if (freezed) 00646 return -1; 00647 if (trickMode) 00648 return Length; 00649 uint8_t streamId; 00650 uint8_t tsBuffer[188 * 16]; 00651 uint32_t tsLength; 00652 HdffAudioStreamType_t streamType = HDFF_AUDIO_STREAM_MPEG1; 00653 HdffAvContainerType_t containerType = HDFF_AV_CONTAINER_PES; 00654 int pid; 00655 00656 streamId = Data[3]; 00657 if (streamId >= 0xC0 && streamId <= 0xDF) 00658 { 00659 streamType = HDFF_AUDIO_STREAM_MPEG1; 00660 } 00661 else if (streamId == 0xBD) 00662 { 00663 const uint8_t * payload = Data + 9 + Data[8]; 00664 if ((payload[0] & 0xF8) == 0xA0) 00665 { 00666 containerType = HDFF_AV_CONTAINER_PES_DVD; 00667 streamType = HDFF_AUDIO_STREAM_PCM; 00668 } 00669 else if ((payload[0] & 0xF8) == 0x88) 00670 { 00671 containerType = HDFF_AV_CONTAINER_PES_DVD; 00672 streamType = HDFF_AUDIO_STREAM_DTS; 00673 } 00674 else if ((payload[0] & 0xF8) == 0x80) 00675 { 00676 containerType = HDFF_AV_CONTAINER_PES_DVD; 00677 streamType = HDFF_AUDIO_STREAM_AC3; 00678 } 00679 else 00680 { 00681 streamType = HDFF_AUDIO_STREAM_AC3; 00682 } 00683 } 00684 pid = 200 + (int) streamType; 00685 tsLength = PesToTs(tsBuffer, pid, audioCounter, Data, Length); 00686 00687 if (pid != playAudioPid) { 00688 playAudioPid = pid; 00689 mHdffCmdIf->CmdAvSetAudioPid(0, playAudioPid, streamType, containerType); 00690 } 00691 if (WriteAllOrNothing(fd_video, tsBuffer, tsLength, 1000, 10) <= 0) 00692 Length = 0; 00693 return Length; 00694 } 00695 00696 int cDvbHdFfDevice::PlayTsVideo(const uchar *Data, int Length) 00697 { 00698 if (freezed) 00699 return -1; 00700 int pid = TsPid(Data); 00701 if (pid != playVideoPid) { 00702 PatPmtParser(); 00703 if (pid == PatPmtParser()->Vpid()) { 00704 playVideoPid = pid; 00705 mHdffCmdIf->CmdAvSetVideoPid(0, playVideoPid, MapVideoStreamTypes(PatPmtParser()->Vtype()), true); 00706 } 00707 } 00708 return WriteAllOrNothing(fd_video, Data, Length, 1000, 10); 00709 } 00710 00711 static HdffAudioStreamType_t MapAudioStreamTypes(int Atype) 00712 { 00713 switch (Atype) { 00714 case 0x03: return HDFF_AUDIO_STREAM_MPEG1; 00715 case 0x04: return HDFF_AUDIO_STREAM_MPEG2; 00716 case SI::AC3DescriptorTag: return HDFF_AUDIO_STREAM_AC3; 00717 case SI::EnhancedAC3DescriptorTag: return HDFF_AUDIO_STREAM_EAC3; 00718 case 0x0F: return HDFF_AUDIO_STREAM_AAC; 00719 case 0x11: return HDFF_AUDIO_STREAM_HE_AAC; 00720 default: return HDFF_AUDIO_STREAM_MPEG1; 00721 } 00722 } 00723 00724 int cDvbHdFfDevice::PlayTsAudio(const uchar *Data, int Length) 00725 { 00726 if (freezed) 00727 return -1; 00728 if (trickMode) 00729 return Length; 00730 int pid = TsPid(Data); 00731 if (pid != playAudioPid) { 00732 playAudioPid = pid; 00733 int AudioStreamType = -1; 00734 for (int i = 0; PatPmtParser()->Apid(i); i++) { 00735 if (playAudioPid == PatPmtParser()->Apid(i)) { 00736 AudioStreamType = PatPmtParser()->Atype(i); 00737 break; 00738 } 00739 } 00740 if (AudioStreamType < 0) { 00741 for (int i = 0; PatPmtParser()->Dpid(i); i++) { 00742 if (playAudioPid == PatPmtParser()->Dpid(i)) { 00743 AudioStreamType = PatPmtParser()->Dtype(i); 00744 break; 00745 } 00746 } 00747 } 00748 mHdffCmdIf->CmdAvSetAudioPid(0, playAudioPid, MapAudioStreamTypes(AudioStreamType)); 00749 } 00750 return WriteAllOrNothing(fd_video, Data, Length, 1000, 10); 00751 } 00752 00753 HDFF::cHdffCmdIf *cDvbHdFfDevice::GetHdffCmdHandler(void) 00754 { 00755 //TODO why not just keep a pointer? 00756 if (devHdffOffset >= 0) { 00757 cDvbHdFfDevice *device = (cDvbHdFfDevice *)GetDevice(devHdffOffset); 00758 if (device) 00759 return device->mHdffCmdIf; 00760 } 00761 return NULL; 00762 } 00763 00764 // --- cDvbHdFfDeviceProbe --------------------------------------------------- 00765 00766 bool cDvbHdFfDeviceProbe::Probe(int Adapter, int Frontend) 00767 { 00768 static uint32_t SubsystemIds[] = { 00769 0x13C23009, // Technotrend S2-6400 HDFF development samples 00770 0x13C2300A, // Technotrend S2-6400 HDFF production version 00771 0x00000000 00772 }; 00773 cString FileName; 00774 cReadLine ReadLine; 00775 FILE *f = NULL; 00776 uint32_t SubsystemId = 0; 00777 FileName = cString::sprintf("/sys/class/dvb/dvb%d.frontend%d/device/subsystem_vendor", Adapter, Frontend); 00778 if ((f = fopen(FileName, "r")) != NULL) { 00779 if (char *s = ReadLine.Read(f)) 00780 SubsystemId = strtoul(s, NULL, 0) << 16; 00781 fclose(f); 00782 } 00783 FileName = cString::sprintf("/sys/class/dvb/dvb%d.frontend%d/device/subsystem_device", Adapter, Frontend); 00784 if ((f = fopen(FileName, "r")) != NULL) { 00785 if (char *s = ReadLine.Read(f)) 00786 SubsystemId |= strtoul(s, NULL, 0); 00787 fclose(f); 00788 } 00789 for (uint32_t *sid = SubsystemIds; *sid; sid++) { 00790 if (*sid == SubsystemId) { 00791 FileName = cString::sprintf("/dev/dvb/adapter%d/osd0", Adapter); 00792 int fd = open(FileName, O_RDWR); 00793 if (fd != -1) { //TODO treat the second path of the S2-6400 as a budget device 00794 close(fd); 00795 dsyslog("creating cDvbHdFfDevice"); 00796 new cDvbHdFfDevice(Adapter, Frontend); 00797 return true; 00798 } 00799 } 00800 } 00801 return false; 00802 }