Ticket #926: radiopatch.1.patch
File radiopatch.1.patch, 16.7 KB (added by , 18 years ago) |
---|
-
dvbrecorder.cpp
23 23 * in ::StartRecording, is based upon. 24 24 * Martin Smith (martin at spamcop.net) 25 25 * - The signal quality monitor 26 * David Matthews (dm at prolingua.co.uk) 27 * - Added video stream for radio channels 26 28 * 27 29 * This program is free software; you can redistribute it and/or modify 28 30 * it under the terms of the GNU General Public License as published by … … 96 98 // Output stream info 97 99 _pat(NULL), _pmt(NULL), _next_pmt_version(0), 98 100 _ts_packets_until_psip_sync(0), 101 // Fake video 102 _video_stream_fd(-1), 99 103 // Statistics 100 104 _continuity_error_count(0), _stream_overflow_count(0), 101 105 _bad_packet_count(0) … … 237 241 _drb->Reset(videodevice, -1); 238 242 #endif 239 243 244 if (_video_stream_fd >= 0) 245 { 246 close(_video_stream_fd); 247 _video_stream_fd = -1; 248 } 249 240 250 CloseFilters(); 241 251 close(_stream_fd); 242 252 _stream_fd = -1; … … 272 282 // rounded up to the nearest page 273 283 pid_buffer_size = ((pid_buffer_size + 4095) / 4096) * 4096; 274 284 275 VERBOSE(VB_RECORD, LOC + QString("Adding pid 0x%2 size(%3) ")276 .arg((int)pid,0,16).arg(pid_buffer_size) );285 VERBOSE(VB_RECORD, LOC + QString("Adding pid 0x%2 size(%3) type(%4)") 286 .arg((int)pid,0,16).arg(pid_buffer_size).arg(type)); 277 287 278 288 // Open the demux device 279 289 int fd_tmp = open(dvbdevice(DVB_DEV_DEMUX,_card_number_option), O_RDWR); … … 331 341 _pid_infos[pid] = info; 332 342 } 333 343 344 #define TS_TICKS_PER_SEC 90000 345 #define DUMMY_VIDEO_PID VIDEO_PID(0x20) 346 334 347 bool DVBRecorder::OpenFilters(void) 335 348 { 349 bool videoMissing = true; 336 350 CloseFilters(); 337 351 338 352 QMutexLocker change_lock(&_pid_lock); … … 351 365 352 366 int pid = (*es).PID; 353 367 dmx_pes_type_t pes_type; 368 369 if ((*es).Type == ES_TYPE_VIDEO_MPEG1 || (*es).Type == ES_TYPE_VIDEO_MPEG2) 370 videoMissing = false; 354 371 355 372 if (_hw_decoder_option) 356 373 { … … 399 416 OpenFilter(_input_pmt.PCRPID, ES_TYPE_UNKNOWN, DMX_PES_OTHER, 400 417 (*es).Orig_Type); 401 418 419 if (_video_stream_fd >= 0) 420 close(_video_stream_fd); 421 _video_stream_fd = -1; 402 422 423 if (videoMissing) 424 { 425 VERBOSE(VB_RECORD, LOC + "Creating dummy video"); 426 // Create a dummy video stream. 427 428 QString p = gContext->GetThemesParentDir(); 429 QString path[] = 430 { p+gContext->GetSetting("Theme", "G.A.N.T.")+"/", p+"default/", }; 431 uint width = 768; 432 uint height = 576; 433 434 _frames_per_sec = 50; 435 436 QString filename = QString("dummy%1x%2p%3.ts") 437 .arg(width).arg(height) 438 .arg(_frames_per_sec, 0, 'f', 2); 439 440 _video_stream_fd = open(path[0]+filename.ascii(), O_RDONLY); 441 if (_video_stream_fd < 0) 442 _video_stream_fd = open(path[1]+filename.ascii(), O_RDONLY); 443 _video_header_pos = 0; 444 _audio_header_pos = 0; 445 _audio_pid = 0; 446 _time_stamp = 0; 447 _next_time_stamp = 0; 448 _video_cc = 0; 449 _ts_change_count = 0; 450 451 PIDInfo *info = new PIDInfo(); 452 info->isVideo = true; 453 454 QMutexLocker change_lock(&_pid_lock); 455 _pid_infos[DUMMY_VIDEO_PID] = info; 456 } 457 403 458 if (_pid_infos.empty()) 404 459 { 405 460 VERBOSE(VB_GENERAL, LOC_WARN + … … 615 670 } 616 671 } 617 672 673 if (_video_stream_fd >= 0) 674 { 675 pdesc.resize(pdesc.size()+1); 676 pdesc.back().clear(); 677 pids.push_back(DUMMY_VIDEO_PID); 678 types.push_back(StreamID::MPEG2Video); 679 } 680 618 681 // Create the PMT 619 682 ProgramMapTable *pmt = ProgramMapTable::Create( 620 683 programNumber, PMT_PID, _input_pmt.PCRPID, … … 779 842 if (info->isVideo) 780 843 _buffer_packets = !FindKeyframes(&tspacket); 781 844 845 // Create dummy video stream if needed 846 if (_video_stream_fd >= 0 && pid != DUMMY_VIDEO_PID) 847 { 848 GetTimeStamp(tspacket); 849 CreateFakeVideo(); 850 } 851 782 852 // Sync recording start to first keyframe 783 853 if (_wait_for_keyframe_option && _first_keyframe<0) 784 854 return true; … … 804 874 return true; 805 875 } 806 876 877 void DVBRecorder::GetTimeStamp(const TSPacket& tspacket) 878 { 879 const uint pid = tspacket.PID(); 880 if (pid != _audio_pid) 881 _audio_header_pos = 0; 882 883 // Find the current audio time stamp. This code is based on DTVRecorder::FindKeyframes. 884 if (tspacket.PayloadStart()) 885 _audio_header_pos = 0; 886 for (uint i = tspacket.AFCOffset(); i < TSPacket::SIZE; i++) 887 { 888 const unsigned char k = tspacket.data()[i]; 889 switch (_audio_header_pos) { 890 case 0: 891 _audio_header_pos = (k == 0x00) ? 1 : 0; 892 break; 893 case 1: 894 _audio_header_pos = (k == 0x00) ? 2 : 0; 895 break; 896 case 2: 897 _audio_header_pos = (k == 0x00) ? 2 : ((k == 0x01) ? 3 : 0); 898 break; 899 case 3: 900 if (k >= PESStreamID::MPEGAudioStreamBegin && k <= PESStreamID::MPEGAudioStreamEnd) 901 _audio_header_pos++; 902 else _audio_header_pos = 0; 903 break; 904 case 4: case 5: case 6: case 8: 905 _audio_header_pos++; 906 break; 907 case 7: 908 _audio_header_pos = (k & 0x80) ? 8 : 0; 909 break; 910 case 9: 911 _audio_header_pos++; 912 _next_time_stamp = (k >> 1) & 0x7; 913 break; 914 case 10: 915 _audio_header_pos++; 916 _next_time_stamp = (_next_time_stamp << 8) | k; 917 break; 918 case 11: 919 _audio_header_pos++; 920 _next_time_stamp = (_next_time_stamp << 7) | ((k >> 1) & 0x7f); 921 break; 922 case 12: 923 _audio_header_pos++; 924 _next_time_stamp = (_next_time_stamp << 8) | k; 925 break; 926 case 13: 927 _next_time_stamp = (_next_time_stamp << 7) | ((k >> 1) & 0x7f); 928 _audio_header_pos = 0; 929 // We've found a time-stamp. Generally the time stamps will increase at a steady rate but 930 // they may jump or wrap round. Because of errors in the stream we may get odd values out 931 // of sequence. 932 if (_next_time_stamp > _time_stamp+TS_TICKS_PER_SEC*5 || _next_time_stamp+TS_TICKS_PER_SEC < _time_stamp) 933 { 934 if (_ts_change_count != 0 && 935 _next_time_stamp > _new_time_stamp && _next_time_stamp <= _new_time_stamp+TS_TICKS_PER_SEC*10) 936 { 937 _ts_change_count++; 938 if (_ts_change_count == 4) 939 { 940 // We've seen 4 stamps in the new sequence. 941 VERBOSE(VB_RECORD, LOC + 942 QString("Time stamp change: was %1 now %2").arg(_time_stamp).arg(_new_time_stamp)); 943 _time_stamp = _new_time_stamp; 944 _ts_change_count = 0; 945 } 946 else _next_time_stamp = _time_stamp; 947 } 948 else { 949 _new_time_stamp = _next_time_stamp; 950 _next_time_stamp = _time_stamp; 951 _ts_change_count = 1; 952 } 953 } 954 else _ts_change_count = 0; 955 } 956 } 957 if (_audio_header_pos != 0) // If we're part way through a packet only continue if it's the same pid 958 _audio_pid = pid; 959 } 960 961 void DVBRecorder::CreateFakeVideo() 962 { 963 if (_video_stream_fd < 0 || _next_time_stamp > _time_stamp + TS_TICKS_PER_SEC*5) 964 return; 965 966 while (_next_time_stamp > _time_stamp) 967 { 968 unsigned char buffer[TSPacket::SIZE]; 969 int len = read(_video_stream_fd, buffer, TSPacket::SIZE); 970 if (len == 0) 971 { 972 // Reached the end - rewind 973 lseek(_video_stream_fd, 0, SEEK_SET); 974 _video_header_pos = 0; 975 continue; 976 } 977 else if (len != (int)TSPacket::SIZE) 978 break; // Something wrong 979 980 TSPacket *pkt = reinterpret_cast<TSPacket*>(buffer); 981 if (pkt->PID() != DUMMY_VIDEO_PID) 982 continue; // Skip the tables 983 // Find the time-stamp field and overwrite it. 984 if (pkt->PayloadStart()) 985 _video_header_pos = 0; 986 for (uint i = pkt->AFCOffset(); i < TSPacket::SIZE; i++) 987 { 988 const unsigned char k = buffer[i]; 989 switch (_video_header_pos) { 990 case 0: 991 _video_header_pos = (k == 0x00) ? 1 : 0; 992 break; 993 case 1: 994 _video_header_pos = (k == 0x00) ? 2 : 0; 995 break; 996 case 2: 997 _video_header_pos = (k == 0x00) ? 2 : ((k == 0x01) ? 3 : 0); 998 break; 999 case 3: 1000 if (k >= PESStreamID::MPEGVideoStreamBegin && k <= PESStreamID::MPEGVideoStreamEnd) 1001 _video_header_pos++; 1002 else if (k == PESStreamID::PictureStartCode) 1003 { 1004 _video_header_pos = 0; 1005 _time_stamp += (int)((double)TS_TICKS_PER_SEC/_frames_per_sec); 1006 } 1007 else _video_header_pos = 0; 1008 break; 1009 case 4: case 5: case 6: case 8: 1010 _video_header_pos++; 1011 break; 1012 case 7: 1013 _video_header_pos = (k & 0x80) ? 8 : 0; // Is there a time-stamp? 1014 break; 1015 case 9: 1016 buffer[i] = (k & 0xf0) | ((_time_stamp >> 29) & 0x0e) | 1; 1017 _video_header_pos++; 1018 break; 1019 case 10: 1020 buffer[i] = (_time_stamp >> 22) & 0xff; 1021 _video_header_pos++; 1022 break; 1023 case 11: 1024 buffer[i] = ((_time_stamp >> 14) & 0xfe) | 1; 1025 _video_header_pos++; 1026 break; 1027 case 12: 1028 buffer[i] = (_time_stamp >> 7) & 0xff; // 7..14 1029 _video_header_pos++; 1030 break; 1031 case 13: 1032 buffer[i] = ((_time_stamp << 1) & 0xfe) | 1; // 0..6 1033 _video_header_pos = 0; 1034 } 1035 } 1036 pkt->SetContinuityCounter(_video_cc); 1037 _video_cc = (_video_cc + 1) & 0xf; 1038 // Recursive call to pass the packet to the ring-buffer 1039 ProcessTSPacket(*pkt); 1040 } 1041 } 1042 807 1043 //////////////////////////////////////////////////////////// 808 1044 // Stuff below this comment will be phased out after 0.20 // 809 1045 //////////////////////////////////////////////////////////// -
siparser.cpp
1257 1257 1258 1258 #ifdef USING_DVB_EIT 1259 1259 if ((s.EITPresent) && 1260 (s.ServiceType == SDTObject::TV ) &&1260 (s.ServiceType == SDTObject::TV || s.ServiceType == SDTObject::RADIO) && 1261 1261 ((!PrivateTypes.GuideOnSingleTransport) || 1262 1262 ((PrivateTypes.GuideOnSingleTransport) && 1263 1263 (PrivateTypes.GuideTransportID == -
videosource.h
78 78 static QString GetDefaultInput(uint cardid); 79 79 80 80 static bool IgnoreEncrypted(uint cardid, const QString &inputname); 81 static bool TVOnly(uint cardid, const QString &inputname); 81 82 82 83 static bool hasV4L2(int videofd); 83 84 static InputNames probeV4LInputs(int videofd, bool &ok); -
dvbrecorder.h
118 118 119 119 DeviceReadBuffer *_drb; 120 120 121 void GetTimeStamp(const TSPacket& tspacket); 122 void CreateFakeVideo(); 123 121 124 private: 122 125 // Options set in SetOption() 123 126 int _card_number_option; … … 148 151 /// PMT on input side 149 152 PMTObject _input_pmt; 150 153 154 // Fake video for audio-only streams 155 uint _audio_header_pos; 156 uint _video_header_pos; 157 uint _audio_pid; 158 int64_t _time_stamp; 159 int64_t _next_time_stamp; 160 int64_t _new_time_stamp; 161 uint _ts_change_count; 162 int _video_stream_fd; 163 double _frames_per_sec; 164 uint _video_cc; 165 151 166 // Statistics 152 167 mutable uint _continuity_error_count; 153 168 mutable uint _stream_overflow_count; -
videosource.cpp
397 397 return freetoair; 398 398 } 399 399 400 bool CardUtil::TVOnly(uint cardid, const QString &input_name) 401 { 402 bool radioservices = true; 403 MSqlQuery query(MSqlQuery::InitCon()); 404 query.prepare( 405 QString("SELECT radioservices FROM cardinput " 406 "WHERE cardid='%1' AND inputname='%2'") 407 .arg(cardid).arg(input_name)); 408 409 if (query.exec() && query.isActive() && query.size() > 0) 410 { 411 query.next(); 412 radioservices = query.value(0).toBool(); 413 } 414 //VERBOSE(VB_IMPORTANT, 415 // QString("CardUtil::TVOnly(%1, %2) -> %3") 416 // .arg(cardid).arg(input_name).arg(radioservices)); 417 return !radioservices; 418 } 419 400 420 bool CardUtil::hasV4L2(int videofd) 401 421 { 402 422 (void) videofd; … … 1720 1740 }; 1721 1741 }; 1722 1742 1743 class RadioServices: public CheckBoxSetting, public CISetting { 1744 public: 1745 RadioServices(const CardInput& parent): 1746 CISetting(parent, "radioservices") 1747 { 1748 setValue(true); 1749 setLabel(QObject::tr("Radio channels.")); 1750 setHelpText(QObject::tr("If set, radio channels will also be included.")); 1751 }; 1752 }; 1753 1723 1754 class ExternalChannelCommand: public LineEditSetting, public CISetting { 1724 1755 public: 1725 1756 ExternalChannelCommand(const CardInput& parent): … … 1883 1914 group->addChild(lnblofswitch = new LNBLofSwitch(*this)); 1884 1915 group->addChild(lnblofhi = new LNBLofHi(*this)); 1885 1916 group->addChild(lnbloflo = new LNBLofLo(*this)); 1886 group->addChild(new FreeToAir(*this)); 1917 HorizontalConfigurationGroup *h1 = 1918 new HorizontalConfigurationGroup(false, false, true, true); 1919 h1->addChild(new FreeToAir(*this)); 1920 h1->addChild(new RadioServices(*this)); 1921 group->addChild(h1); 1887 1922 } 1888 1923 #endif 1889 1924 -
scanwizard.cpp
446 446 bool ftao = CardUtil::IgnoreEncrypted( 447 447 parent->captureCard(), channel->GetCurrentInput()); 448 448 scanner->SetFTAOnly(ftao); 449 bool tvo = CardUtil::TVOnly( 450 parent->captureCard(), channel->GetCurrentInput()); 451 scanner->SetTVOnly(tvo); 449 452 450 453 connect(scanner, SIGNAL(ServiceScanComplete(void)), 451 454 this, SLOT( scanComplete(void))); -
dbcheck.cpp
10 10 #include "mythdbcon.h" 11 11 12 12 /// This is the DB schema version expected by the running MythTV instance. 13 const QString currentDatabaseVersion = "112 1";13 const QString currentDatabaseVersion = "1122"; 14 14 15 15 static bool UpdateDBVersionNumber(const QString &newnumber); 16 16 static bool performActualUpdate(const QString updates[], QString version, … … 1980 1980 return false; 1981 1981 } 1982 1982 1983 if (dbver == "1121") 1984 { 1985 const QString updates[] = { 1986 "ALTER TABLE cardinput ADD COLUMN radioservices TINYINT(1) DEFAULT 1;", 1987 "" 1988 }; 1989 if (!performActualUpdate(updates, "1122", dbver)) 1990 return false; 1991 } 1992 1993 1983 1994 // Drop xvmc_buffer_settings table in 0.20 1984 1995 // Drop dvb_dmx_buf_size and dvb_pkt_buf_size columns of channel in 0.20 1985 1996 -
tv_rec.cpp
1543 1543 sm->SetStreamData(sd); 1544 1544 sd->Reset(progNum); 1545 1545 sm->SetProgramNumber(progNum); 1546 sd->SetVideoStreamsRequired( 1);1546 sd->SetVideoStreamsRequired(0); 1547 1547 sm->SetFTAOnly(fta); 1548 1548 sm->AddFlags(kDTVSigMon_WaitForPAT | kDTVSigMon_WaitForPMT); 1549 1549