vdr
1.7.27
|
00001 /* 00002 * dvbsdffdevice.h: The DVB SD Full Featured device interface 00003 * 00004 * See the README file for copyright information and how to reach the author. 00005 * 00006 * $Id: dvbsdffdevice.c 2.33 2012/03/11 13:32:42 kls Exp $ 00007 */ 00008 00009 #include "dvbsdffdevice.h" 00010 #include <errno.h> 00011 #include <limits.h> 00012 #include <linux/videodev2.h> 00013 #include <linux/dvb/audio.h> 00014 #include <linux/dvb/dmx.h> 00015 #include <linux/dvb/video.h> 00016 #include <sys/ioctl.h> 00017 #include <sys/mman.h> 00018 #include <vdr/eitscan.h> 00019 #include <vdr/transfer.h> 00020 #include "dvbsdffosd.h" 00021 00022 // --- cDvbSdFfDevice -------------------------------------------------------- 00023 00024 int cDvbSdFfDevice::devVideoOffset = -1; 00025 00026 cDvbSdFfDevice::cDvbSdFfDevice(int Adapter, int Frontend, bool OutputOnly) 00027 :cDvbDevice(Adapter, Frontend) 00028 { 00029 spuDecoder = NULL; 00030 digitalAudio = false; 00031 playMode = pmNone; 00032 outputOnly = OutputOnly; 00033 00034 // Devices that are only present on cards with decoders: 00035 00036 fd_osd = DvbOpen(DEV_DVB_OSD, adapter, frontend, O_RDWR); 00037 fd_video = DvbOpen(DEV_DVB_VIDEO, adapter, frontend, O_RDWR | O_NONBLOCK); 00038 fd_audio = DvbOpen(DEV_DVB_AUDIO, adapter, frontend, O_RDWR | O_NONBLOCK); 00039 fd_stc = DvbOpen(DEV_DVB_DEMUX, adapter, frontend, O_RDWR); 00040 00041 // The offset of the /dev/video devices: 00042 00043 if (devVideoOffset < 0) { // the first one checks this 00044 FILE *f = NULL; 00045 char buffer[PATH_MAX]; 00046 for (int ofs = 0; ofs < 100; ofs++) { 00047 snprintf(buffer, sizeof(buffer), "/proc/video/dev/video%d", ofs); 00048 if ((f = fopen(buffer, "r")) != NULL) { 00049 if (fgets(buffer, sizeof(buffer), f)) { 00050 if (strstr(buffer, "DVB Board")) { // found the _first_ DVB card 00051 devVideoOffset = ofs; 00052 dsyslog("video device offset is %d", devVideoOffset); 00053 break; 00054 } 00055 } 00056 else 00057 break; 00058 fclose(f); 00059 } 00060 else 00061 break; 00062 } 00063 if (devVideoOffset < 0) 00064 devVideoOffset = 0; 00065 if (f) 00066 fclose(f); 00067 } 00068 devVideoIndex = devVideoOffset >= 0 ? devVideoOffset++ : -1; 00069 } 00070 00071 cDvbSdFfDevice::~cDvbSdFfDevice() 00072 { 00073 delete spuDecoder; 00074 // We're not explicitly closing any device files here, since this sometimes 00075 // caused segfaults. Besides, the program is about to terminate anyway... 00076 } 00077 00078 void cDvbSdFfDevice::MakePrimaryDevice(bool On) 00079 { 00080 if (On) 00081 new cDvbOsdProvider(fd_osd); 00082 cDvbDevice::MakePrimaryDevice(On); 00083 } 00084 00085 bool cDvbSdFfDevice::HasDecoder(void) const 00086 { 00087 return true; 00088 } 00089 00090 bool cDvbSdFfDevice::AvoidRecording(void) const 00091 { 00092 return true; 00093 } 00094 00095 cSpuDecoder *cDvbSdFfDevice::GetSpuDecoder(void) 00096 { 00097 if (!spuDecoder && IsPrimaryDevice()) 00098 spuDecoder = new cDvbSpuDecoder(); 00099 return spuDecoder; 00100 } 00101 00102 uchar *cDvbSdFfDevice::GrabImage(int &Size, bool Jpeg, int Quality, int SizeX, int SizeY) 00103 { 00104 if (devVideoIndex < 0) 00105 return NULL; 00106 char buffer[PATH_MAX]; 00107 snprintf(buffer, sizeof(buffer), "%s%d", DEV_VIDEO, devVideoIndex); 00108 int videoDev = open(buffer, O_RDWR); 00109 if (videoDev >= 0) { 00110 uchar *result = NULL; 00111 // set up the size and RGB 00112 v4l2_format fmt; 00113 memset(&fmt, 0, sizeof(fmt)); 00114 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00115 fmt.fmt.pix.width = SizeX; 00116 fmt.fmt.pix.height = SizeY; 00117 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24; 00118 fmt.fmt.pix.field = V4L2_FIELD_ANY; 00119 if (ioctl(videoDev, VIDIOC_S_FMT, &fmt) == 0) { 00120 v4l2_requestbuffers reqBuf; 00121 memset(&reqBuf, 0, sizeof(reqBuf)); 00122 reqBuf.count = 2; 00123 reqBuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00124 reqBuf.memory = V4L2_MEMORY_MMAP; 00125 if (ioctl(videoDev, VIDIOC_REQBUFS, &reqBuf) >= 0) { 00126 v4l2_buffer mbuf; 00127 memset(&mbuf, 0, sizeof(mbuf)); 00128 mbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00129 mbuf.memory = V4L2_MEMORY_MMAP; 00130 if (ioctl(videoDev, VIDIOC_QUERYBUF, &mbuf) == 0) { 00131 int msize = mbuf.length; 00132 unsigned char *mem = (unsigned char *)mmap(0, msize, PROT_READ | PROT_WRITE, MAP_SHARED, videoDev, 0); 00133 if (mem && mem != (unsigned char *)-1) { 00134 v4l2_buffer buf; 00135 memset(&buf, 0, sizeof(buf)); 00136 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00137 buf.memory = V4L2_MEMORY_MMAP; 00138 buf.index = 0; 00139 if (ioctl(videoDev, VIDIOC_QBUF, &buf) == 0) { 00140 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00141 if (ioctl (videoDev, VIDIOC_STREAMON, &type) == 0) { 00142 memset(&buf, 0, sizeof(buf)); 00143 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00144 buf.memory = V4L2_MEMORY_MMAP; 00145 buf.index = 0; 00146 if (ioctl(videoDev, VIDIOC_DQBUF, &buf) == 0) { 00147 if (ioctl(videoDev, VIDIOC_STREAMOFF, &type) == 0) { 00148 // make RGB out of BGR: 00149 int memsize = fmt.fmt.pix.width * fmt.fmt.pix.height; 00150 unsigned char *mem1 = mem; 00151 for (int i = 0; i < memsize; i++) { 00152 unsigned char tmp = mem1[2]; 00153 mem1[2] = mem1[0]; 00154 mem1[0] = tmp; 00155 mem1 += 3; 00156 } 00157 00158 if (Quality < 0) 00159 Quality = 100; 00160 00161 dsyslog("grabbing to %s %d %d %d", Jpeg ? "JPEG" : "PNM", Quality, fmt.fmt.pix.width, fmt.fmt.pix.height); 00162 if (Jpeg) { 00163 // convert to JPEG: 00164 result = RgbToJpeg(mem, fmt.fmt.pix.width, fmt.fmt.pix.height, Size, Quality); 00165 if (!result) 00166 esyslog("ERROR: failed to convert image to JPEG"); 00167 } 00168 else { 00169 // convert to PNM: 00170 char buf[32]; 00171 snprintf(buf, sizeof(buf), "P6\n%d\n%d\n255\n", fmt.fmt.pix.width, fmt.fmt.pix.height); 00172 int l = strlen(buf); 00173 int bytes = memsize * 3; 00174 Size = l + bytes; 00175 result = MALLOC(uchar, Size); 00176 if (result) { 00177 memcpy(result, buf, l); 00178 memcpy(result + l, mem, bytes); 00179 } 00180 else 00181 esyslog("ERROR: failed to convert image to PNM"); 00182 } 00183 } 00184 else 00185 esyslog("ERROR: video device VIDIOC_STREAMOFF failed"); 00186 } 00187 else 00188 esyslog("ERROR: video device VIDIOC_DQBUF failed"); 00189 } 00190 else 00191 esyslog("ERROR: video device VIDIOC_STREAMON failed"); 00192 } 00193 else 00194 esyslog("ERROR: video device VIDIOC_QBUF failed"); 00195 munmap(mem, msize); 00196 } 00197 else 00198 esyslog("ERROR: failed to memmap video device"); 00199 } 00200 else 00201 esyslog("ERROR: video device VIDIOC_QUERYBUF failed"); 00202 } 00203 else 00204 esyslog("ERROR: video device VIDIOC_REQBUFS failed"); 00205 } 00206 else 00207 esyslog("ERROR: video device VIDIOC_S_FMT failed"); 00208 close(videoDev); 00209 return result; 00210 } 00211 else 00212 LOG_ERROR_STR(buffer); 00213 return NULL; 00214 } 00215 00216 void cDvbSdFfDevice::SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat) 00217 { 00218 cDevice::SetVideoDisplayFormat(VideoDisplayFormat); 00219 if (Setup.VideoFormat) { 00220 CHECK(ioctl(fd_video, VIDEO_SET_DISPLAY_FORMAT, VIDEO_LETTER_BOX)); 00221 } 00222 else { 00223 switch (VideoDisplayFormat) { 00224 case vdfPanAndScan: 00225 CHECK(ioctl(fd_video, VIDEO_SET_DISPLAY_FORMAT, VIDEO_PAN_SCAN)); 00226 break; 00227 case vdfLetterBox: 00228 CHECK(ioctl(fd_video, VIDEO_SET_DISPLAY_FORMAT, VIDEO_LETTER_BOX)); 00229 break; 00230 case vdfCenterCutOut: 00231 CHECK(ioctl(fd_video, VIDEO_SET_DISPLAY_FORMAT, VIDEO_CENTER_CUT_OUT)); 00232 break; 00233 default: esyslog("ERROR: unknown video display format %d", VideoDisplayFormat); 00234 } 00235 } 00236 } 00237 00238 void cDvbSdFfDevice::SetVideoFormat(bool VideoFormat16_9) 00239 { 00240 CHECK(ioctl(fd_video, VIDEO_SET_FORMAT, VideoFormat16_9 ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3)); 00241 SetVideoDisplayFormat(eVideoDisplayFormat(Setup.VideoDisplayFormat)); 00242 } 00243 00244 eVideoSystem cDvbSdFfDevice::GetVideoSystem(void) 00245 { 00246 eVideoSystem VideoSystem = vsPAL; 00247 if (fd_video >= 0) { 00248 video_size_t vs; 00249 if (ioctl(fd_video, VIDEO_GET_SIZE, &vs) == 0) { 00250 if (vs.h == 480 || vs.h == 240) 00251 VideoSystem = vsNTSC; 00252 } 00253 else 00254 LOG_ERROR; 00255 } 00256 return VideoSystem; 00257 } 00258 00259 void cDvbSdFfDevice::GetVideoSize(int &Width, int &Height, double &VideoAspect) 00260 { 00261 if (fd_video >= 0) { 00262 video_size_t vs; 00263 if (ioctl(fd_video, VIDEO_GET_SIZE, &vs) == 0) { 00264 Width = vs.w; 00265 Height = vs.h; 00266 switch (vs.aspect_ratio) { 00267 default: 00268 case VIDEO_FORMAT_4_3: VideoAspect = 4.0 / 3.0; break; 00269 case VIDEO_FORMAT_16_9: VideoAspect = 16.0 / 9.0; break; 00270 case VIDEO_FORMAT_221_1: VideoAspect = 2.21; break; 00271 } 00272 return; 00273 } 00274 else 00275 LOG_ERROR; 00276 } 00277 cDevice::GetVideoSize(Width, Height, VideoAspect); 00278 } 00279 00280 void cDvbSdFfDevice::GetOsdSize(int &Width, int &Height, double &PixelAspect) 00281 { 00282 if (fd_video >= 0) { 00283 video_size_t vs; 00284 if (ioctl(fd_video, VIDEO_GET_SIZE, &vs) == 0) { 00285 Width = 720; 00286 if (vs.h != 480 && vs.h != 240) 00287 Height = 576; // PAL 00288 else 00289 Height = 480; // NTSC 00290 switch (Setup.VideoFormat ? vs.aspect_ratio : VIDEO_FORMAT_4_3) { 00291 default: 00292 case VIDEO_FORMAT_4_3: PixelAspect = 4.0 / 3.0; break; 00293 case VIDEO_FORMAT_221_1: // FF DVB cards only distinguish between 4:3 and 16:9 00294 case VIDEO_FORMAT_16_9: PixelAspect = 16.0 / 9.0; break; 00295 } 00296 PixelAspect /= double(Width) / Height; 00297 return; 00298 } 00299 else 00300 LOG_ERROR; 00301 } 00302 cDevice::GetOsdSize(Width, Height, PixelAspect); 00303 } 00304 00305 bool cDvbSdFfDevice::SetAudioBypass(bool On) 00306 { 00307 if (setTransferModeForDolbyDigital != 1) 00308 return false; 00309 return ioctl(fd_audio, AUDIO_SET_BYPASS_MODE, On) == 0; 00310 } 00311 00312 // ptAudio ptVideo ptPcr ptTeletext ptDolby ptOther 00313 static dmx_pes_type_t PesTypes[] = { DMX_PES_AUDIO, DMX_PES_VIDEO, DMX_PES_PCR, DMX_PES_TELETEXT, DMX_PES_OTHER, DMX_PES_OTHER }; 00314 00315 bool cDvbSdFfDevice::SetPid(cPidHandle *Handle, int Type, bool On) 00316 { 00317 if (Handle->pid) { 00318 dmx_pes_filter_params pesFilterParams; 00319 memset(&pesFilterParams, 0, sizeof(pesFilterParams)); 00320 if (On) { 00321 if (Handle->handle < 0) { 00322 Handle->handle = DvbOpen(DEV_DVB_DEMUX, adapter, frontend, O_RDWR | O_NONBLOCK, true); 00323 if (Handle->handle < 0) { 00324 LOG_ERROR; 00325 return false; 00326 } 00327 } 00328 pesFilterParams.pid = Handle->pid; 00329 pesFilterParams.input = DMX_IN_FRONTEND; 00330 pesFilterParams.output = (Type <= ptTeletext && Handle->used <= 1) ? DMX_OUT_DECODER : DMX_OUT_TS_TAP; 00331 pesFilterParams.pes_type= PesTypes[Type < ptOther ? Type : ptOther]; 00332 pesFilterParams.flags = DMX_IMMEDIATE_START; 00333 if (ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams) < 0) { 00334 LOG_ERROR; 00335 return false; 00336 } 00337 } 00338 else if (!Handle->used) { 00339 CHECK(ioctl(Handle->handle, DMX_STOP)); 00340 if (Type <= ptTeletext) { 00341 pesFilterParams.pid = 0x1FFF; 00342 pesFilterParams.input = DMX_IN_FRONTEND; 00343 pesFilterParams.output = DMX_OUT_DECODER; 00344 pesFilterParams.pes_type= PesTypes[Type]; 00345 pesFilterParams.flags = DMX_IMMEDIATE_START; 00346 CHECK(ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams)); 00347 if (PesTypes[Type] == DMX_PES_VIDEO) // let's only do this once 00348 SetPlayMode(pmNone); // necessary to switch a PID from DMX_PES_VIDEO/AUDIO to DMX_PES_OTHER 00349 } 00350 close(Handle->handle); 00351 Handle->handle = -1; 00352 } 00353 } 00354 return true; 00355 } 00356 00357 bool cDvbSdFfDevice::ProvidesSource(int Source) const 00358 { 00359 if (outputOnly) 00360 return false; 00361 else 00362 return cDvbDevice::ProvidesSource(Source); 00363 } 00364 00365 void cDvbSdFfDevice::TurnOffLiveMode(bool LiveView) 00366 { 00367 if (LiveView) { 00368 // Avoid noise while switching: 00369 CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true)); 00370 CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); 00371 CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER)); 00372 CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER)); 00373 } 00374 00375 // Turn off live PIDs: 00376 00377 DetachAll(pidHandles[ptAudio].pid); 00378 DetachAll(pidHandles[ptVideo].pid); 00379 DetachAll(pidHandles[ptPcr].pid); 00380 DetachAll(pidHandles[ptTeletext].pid); 00381 DelPid(pidHandles[ptAudio].pid); 00382 DelPid(pidHandles[ptVideo].pid); 00383 DelPid(pidHandles[ptPcr].pid, ptPcr); 00384 DelPid(pidHandles[ptTeletext].pid); 00385 DelPid(pidHandles[ptDolby].pid); 00386 } 00387 00388 bool cDvbSdFfDevice::SetChannelDevice(const cChannel *Channel, bool LiveView) 00389 { 00390 int apid = Channel->Apid(0); 00391 int vpid = Channel->Vpid(); 00392 int dpid = Channel->Dpid(0); 00393 00394 bool DoTune = !IsTunedToTransponder(Channel); 00395 00396 bool pidHandlesVideo = pidHandles[ptVideo].pid == vpid; 00397 bool pidHandlesAudio = pidHandles[ptAudio].pid == apid; 00398 00399 bool TurnOffLivePIDs = DoTune 00400 || !IsPrimaryDevice() 00401 || LiveView // for a new live view the old PIDs need to be turned off 00402 || pidHandlesVideo // for recording the PIDs must be shifted from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER 00403 ; 00404 00405 bool StartTransferMode = IsPrimaryDevice() && !DoTune 00406 && (LiveView && HasPid(vpid ? vpid : apid) && (!pidHandlesVideo || (!pidHandlesAudio && (dpid ? pidHandles[ptAudio].pid != dpid : true)))// the PID is already set as DMX_PES_OTHER 00407 || !LiveView && (pidHandlesVideo || pidHandlesAudio) // a recording is going to shift the PIDs from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER 00408 ); 00409 if (CamSlot() && !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), CamSlot()->SlotNumber())) 00410 StartTransferMode |= LiveView && IsPrimaryDevice() && Channel->Ca() >= CA_ENCRYPTED_MIN; 00411 00412 bool TurnOnLivePIDs = !StartTransferMode && LiveView; 00413 00414 // Turn off live PIDs if necessary: 00415 00416 if (TurnOffLivePIDs) 00417 TurnOffLiveMode(LiveView); 00418 00419 // Set the tuner: 00420 00421 if (!cDvbDevice::SetChannelDevice(Channel, LiveView)) 00422 return false; 00423 00424 // PID settings: 00425 00426 if (TurnOnLivePIDs) { 00427 SetAudioBypass(false); 00428 if (!(AddPid(Channel->Ppid(), ptPcr) && AddPid(vpid, ptVideo) && AddPid(apid, ptAudio))) { 00429 esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->Number(), CardIndex() + 1); 00430 return false; 00431 } 00432 if (IsPrimaryDevice()) 00433 AddPid(Channel->Tpid(), ptTeletext); 00434 CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true)); // actually one would expect 'false' here, but according to Marco Schluessler <marco@lordzodiac.de> this works 00435 // to avoid missing audio after replaying a DVD; with 'false' there is an audio disturbance when switching 00436 // between two channels on the same transponder on DVB-S 00437 CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); 00438 } 00439 else if (StartTransferMode) 00440 cControl::Launch(new cTransferControl(this, Channel)); 00441 00442 return true; 00443 } 00444 00445 int cDvbSdFfDevice::GetAudioChannelDevice(void) 00446 { 00447 audio_status_t as; 00448 CHECK(ioctl(fd_audio, AUDIO_GET_STATUS, &as)); 00449 return as.channel_select; 00450 } 00451 00452 void cDvbSdFfDevice::SetAudioChannelDevice(int AudioChannel) 00453 { 00454 CHECK(ioctl(fd_audio, AUDIO_CHANNEL_SELECT, AudioChannel)); 00455 } 00456 00457 void cDvbSdFfDevice::SetVolumeDevice(int Volume) 00458 { 00459 if (digitalAudio) 00460 Volume = 0; 00461 audio_mixer_t am; 00462 // conversion for linear volume response: 00463 am.volume_left = am.volume_right = 2 * Volume - Volume * Volume / 255; 00464 CHECK(ioctl(fd_audio, AUDIO_SET_MIXER, &am)); 00465 } 00466 00467 void cDvbSdFfDevice::SetDigitalAudioDevice(bool On) 00468 { 00469 if (digitalAudio != On) { 00470 if (digitalAudio) 00471 cCondWait::SleepMs(1000); // Wait until any leftover digital data has been flushed 00472 digitalAudio = On; 00473 SetVolumeDevice(On || IsMute() ? 0 : CurrentVolume()); 00474 } 00475 } 00476 00477 void cDvbSdFfDevice::SetAudioTrackDevice(eTrackType Type) 00478 { 00479 const tTrackId *TrackId = GetTrack(Type); 00480 if (TrackId && TrackId->id) { 00481 SetAudioBypass(false); 00482 if (IS_AUDIO_TRACK(Type) || (IS_DOLBY_TRACK(Type) && SetAudioBypass(true))) { 00483 if (pidHandles[ptAudio].pid && pidHandles[ptAudio].pid != TrackId->id) { 00484 DetachAll(pidHandles[ptAudio].pid); 00485 if (CamSlot()) 00486 CamSlot()->SetPid(pidHandles[ptAudio].pid, false); 00487 pidHandles[ptAudio].pid = TrackId->id; 00488 SetPid(&pidHandles[ptAudio], ptAudio, true); 00489 if (CamSlot()) { 00490 CamSlot()->SetPid(pidHandles[ptAudio].pid, true); 00491 CamSlot()->StartDecrypting(); 00492 } 00493 } 00494 } 00495 else if (IS_DOLBY_TRACK(Type)) { 00496 if (setTransferModeForDolbyDigital == 0) 00497 return; 00498 // Currently this works only in Transfer Mode 00499 ForceTransferMode(); 00500 } 00501 } 00502 } 00503 00504 bool cDvbSdFfDevice::CanReplay(void) const 00505 { 00506 return cDevice::CanReplay(); 00507 } 00508 00509 bool cDvbSdFfDevice::SetPlayMode(ePlayMode PlayMode) 00510 { 00511 if (PlayMode != pmExtern_THIS_SHOULD_BE_AVOIDED && fd_video < 0 && fd_audio < 0) { 00512 // reopen the devices 00513 fd_video = DvbOpen(DEV_DVB_VIDEO, adapter, frontend, O_RDWR | O_NONBLOCK); 00514 fd_audio = DvbOpen(DEV_DVB_AUDIO, adapter, frontend, O_RDWR | O_NONBLOCK); 00515 SetVideoFormat(Setup.VideoFormat); 00516 } 00517 00518 switch (PlayMode) { 00519 case pmNone: 00520 // special handling to return from PCM replay: 00521 CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); 00522 CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY)); 00523 CHECK(ioctl(fd_video, VIDEO_PLAY)); 00524 00525 CHECK(ioctl(fd_video, VIDEO_STOP, true)); 00526 CHECK(ioctl(fd_audio, AUDIO_STOP, true)); 00527 CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER)); 00528 CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER)); 00529 CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX)); 00530 CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX)); 00531 CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); 00532 CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false)); 00533 break; 00534 case pmAudioVideo: 00535 case pmAudioOnlyBlack: 00536 if (playMode == pmNone) 00537 TurnOffLiveMode(true); 00538 CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); 00539 CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY)); 00540 CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, PlayMode == pmAudioVideo)); 00541 CHECK(ioctl(fd_audio, AUDIO_PLAY)); 00542 CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY)); 00543 CHECK(ioctl(fd_video, VIDEO_PLAY)); 00544 break; 00545 case pmAudioOnly: 00546 CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); 00547 CHECK(ioctl(fd_audio, AUDIO_STOP, true)); 00548 CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER)); 00549 CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY)); 00550 CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false)); 00551 CHECK(ioctl(fd_audio, AUDIO_PLAY)); 00552 CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false)); 00553 break; 00554 case pmVideoOnly: 00555 CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); 00556 CHECK(ioctl(fd_video, VIDEO_STOP, true)); 00557 CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX)); 00558 CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false)); 00559 CHECK(ioctl(fd_audio, AUDIO_PLAY)); 00560 CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER)); 00561 CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY)); 00562 CHECK(ioctl(fd_video, VIDEO_PLAY)); 00563 break; 00564 case pmExtern_THIS_SHOULD_BE_AVOIDED: 00565 close(fd_video); 00566 close(fd_audio); 00567 fd_video = fd_audio = -1; 00568 break; 00569 default: esyslog("ERROR: unknown playmode %d", PlayMode); 00570 } 00571 playMode = PlayMode; 00572 return true; 00573 } 00574 00575 int64_t cDvbSdFfDevice::GetSTC(void) 00576 { 00577 if (fd_stc >= 0) { 00578 struct dmx_stc stc; 00579 stc.num = 0; 00580 if (ioctl(fd_stc, DMX_GET_STC, &stc) == -1) { 00581 esyslog("ERROR: stc %d: %m", CardIndex() + 1); 00582 return -1; 00583 } 00584 return stc.stc / stc.base; 00585 } 00586 return -1; 00587 } 00588 00589 void cDvbSdFfDevice::TrickSpeed(int Speed) 00590 { 00591 if (fd_video >= 0) 00592 CHECK(ioctl(fd_video, VIDEO_SLOWMOTION, Speed)); 00593 } 00594 00595 void cDvbSdFfDevice::Clear(void) 00596 { 00597 if (fd_video >= 0) 00598 CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER)); 00599 if (fd_audio >= 0) 00600 CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER)); 00601 cDevice::Clear(); 00602 } 00603 00604 void cDvbSdFfDevice::Play(void) 00605 { 00606 if (playMode == pmAudioOnly || playMode == pmAudioOnlyBlack) { 00607 if (fd_audio >= 0) 00608 CHECK(ioctl(fd_audio, AUDIO_CONTINUE)); 00609 } 00610 else { 00611 if (fd_audio >= 0) { 00612 CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); 00613 CHECK(ioctl(fd_audio, AUDIO_CONTINUE)); 00614 } 00615 if (fd_video >= 0) 00616 CHECK(ioctl(fd_video, VIDEO_CONTINUE)); 00617 } 00618 cDevice::Play(); 00619 } 00620 00621 void cDvbSdFfDevice::Freeze(void) 00622 { 00623 if (playMode == pmAudioOnly || playMode == pmAudioOnlyBlack) { 00624 if (fd_audio >= 0) 00625 CHECK(ioctl(fd_audio, AUDIO_PAUSE)); 00626 } 00627 else { 00628 if (fd_audio >= 0) { 00629 CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false)); 00630 CHECK(ioctl(fd_audio, AUDIO_PAUSE)); 00631 } 00632 if (fd_video >= 0) 00633 CHECK(ioctl(fd_video, VIDEO_FREEZE)); 00634 } 00635 cDevice::Freeze(); 00636 } 00637 00638 void cDvbSdFfDevice::Mute(void) 00639 { 00640 if (fd_audio >= 0) { 00641 CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false)); 00642 CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true)); 00643 } 00644 cDevice::Mute(); 00645 } 00646 00647 void cDvbSdFfDevice::StillPicture(const uchar *Data, int Length) 00648 { 00649 if (!Data || Length < TS_SIZE) 00650 return; 00651 if (Data[0] == 0x47) { 00652 // TS data 00653 cDevice::StillPicture(Data, Length); 00654 } 00655 else if (Data[0] == 0x00 && Data[1] == 0x00 && Data[2] == 0x01 && (Data[3] & 0xF0) == 0xE0) { 00656 // PES data 00657 char *buf = MALLOC(char, Length); 00658 if (!buf) 00659 return; 00660 int i = 0; 00661 int blen = 0; 00662 while (i < Length - 6) { 00663 if (Data[i] == 0x00 && Data[i + 1] == 0x00 && Data[i + 2] == 0x01) { 00664 int len = Data[i + 4] * 256 + Data[i + 5]; 00665 if ((Data[i + 3] & 0xF0) == 0xE0) { // video packet 00666 // skip PES header 00667 int offs = i + 6; 00668 // skip header extension 00669 if ((Data[i + 6] & 0xC0) == 0x80) { 00670 // MPEG-2 PES header 00671 if (Data[i + 8] >= Length) 00672 break; 00673 offs += 3; 00674 offs += Data[i + 8]; 00675 len -= 3; 00676 len -= Data[i + 8]; 00677 if (len < 0 || offs + len > Length) 00678 break; 00679 } 00680 else { 00681 // MPEG-1 PES header 00682 while (offs < Length && len > 0 && Data[offs] == 0xFF) { 00683 offs++; 00684 len--; 00685 } 00686 if (offs <= Length - 2 && len >= 2 && (Data[offs] & 0xC0) == 0x40) { 00687 offs += 2; 00688 len -= 2; 00689 } 00690 if (offs <= Length - 5 && len >= 5 && (Data[offs] & 0xF0) == 0x20) { 00691 offs += 5; 00692 len -= 5; 00693 } 00694 else if (offs <= Length - 10 && len >= 10 && (Data[offs] & 0xF0) == 0x30) { 00695 offs += 10; 00696 len -= 10; 00697 } 00698 else if (offs < Length && len > 0) { 00699 offs++; 00700 len--; 00701 } 00702 } 00703 if (blen + len > Length) // invalid PES length field 00704 break; 00705 memcpy(&buf[blen], &Data[offs], len); 00706 i = offs + len; 00707 blen += len; 00708 } 00709 else if (Data[i + 3] >= 0xBD && Data[i + 3] <= 0xDF) // other PES packets 00710 i += len + 6; 00711 else 00712 i++; 00713 } 00714 else 00715 i++; 00716 } 00717 video_still_picture sp = { buf, blen }; 00718 CHECK(ioctl(fd_video, VIDEO_STILLPICTURE, &sp)); 00719 free(buf); 00720 } 00721 else { 00722 // non-PES data 00723 video_still_picture sp = { (char *)Data, Length }; 00724 CHECK(ioctl(fd_video, VIDEO_STILLPICTURE, &sp)); 00725 } 00726 } 00727 00728 bool cDvbSdFfDevice::Poll(cPoller &Poller, int TimeoutMs) 00729 { 00730 Poller.Add((playMode == pmAudioOnly || playMode == pmAudioOnlyBlack) ? fd_audio : fd_video, true); 00731 return Poller.Poll(TimeoutMs); 00732 } 00733 00734 bool cDvbSdFfDevice::Flush(int TimeoutMs) 00735 { 00736 //TODO actually this function should wait until all buffered data has been processed by the card, but how? 00737 return true; 00738 } 00739 00740 int cDvbSdFfDevice::PlayVideo(const uchar *Data, int Length) 00741 { 00742 return WriteAllOrNothing(fd_video, Data, Length, 1000, 10); 00743 } 00744 00745 int cDvbSdFfDevice::PlayAudio(const uchar *Data, int Length, uchar Id) 00746 { 00747 return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10); 00748 } 00749 00750 int cDvbSdFfDevice::PlayTsVideo(const uchar *Data, int Length) 00751 { 00752 return WriteAllOrNothing(fd_video, Data, Length, 1000, 10); 00753 } 00754 00755 int cDvbSdFfDevice::PlayTsAudio(const uchar *Data, int Length) 00756 { 00757 return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10); 00758 } 00759 00760 // --- cDvbSdFfDeviceProbe --------------------------------------------------- 00761 00762 cDvbSdFfDeviceProbe::cDvbSdFfDeviceProbe(void) 00763 { 00764 outputOnly = false; 00765 } 00766 00767 bool cDvbSdFfDeviceProbe::Probe(int Adapter, int Frontend) 00768 { 00769 static uint32_t SubsystemIds[] = { 00770 0x110A0000, // Fujitsu Siemens DVB-C 00771 0x13C20000, // Technotrend/Hauppauge WinTV DVB-S rev1.X or Fujitsu Siemens DVB-C 00772 0x13C20001, // Technotrend/Hauppauge WinTV DVB-T rev1.X 00773 0x13C20002, // Technotrend/Hauppauge WinTV DVB-C rev2.X 00774 0x13C20003, // Technotrend/Hauppauge WinTV Nexus-S rev2.X 00775 0x13C20004, // Galaxis DVB-S rev1.3 00776 0x13C20006, // Fujitsu Siemens DVB-S rev1.6 00777 0x13C20008, // Technotrend/Hauppauge DVB-T 00778 0x13C2000A, // Technotrend/Hauppauge WinTV Nexus-CA rev1.X 00779 0x13C2000E, // Technotrend/Hauppauge WinTV Nexus-S rev2.3 00780 0x13C21002, // Technotrend/Hauppauge WinTV DVB-S rev1.3 SE 00781 0x00000000 00782 }; 00783 uint32_t SubsystemId = GetSubsystemId(Adapter, Frontend); 00784 for (uint32_t *sid = SubsystemIds; *sid; sid++) { 00785 if (*sid == SubsystemId) { 00786 dsyslog("creating cDvbSdFfDevice"); 00787 new cDvbSdFfDevice(Adapter, Frontend, outputOnly); 00788 return true; 00789 } 00790 } 00791 return false; 00792 }