Ticket #926: radiopatch.1.patch

File radiopatch.1.patch, 16.7 KB (added by John Pullan <john.pullan@…>, 14 years ago)

Enhanced to allow the scanner to choose (or not) to scan radio services.

  • dvbrecorder.cpp

     
    2323 *            in ::StartRecording, is based upon.
    2424 *      Martin Smith (martin at spamcop.net)
    2525 *          - The signal quality monitor
     26 *      David Matthews (dm at prolingua.co.uk)
     27 *          - Added video stream for radio channels
    2628 *
    2729 *   This program is free software; you can redistribute it and/or modify
    2830 *   it under the terms of the GNU General Public License as published by
     
    9698      // Output stream info
    9799      _pat(NULL), _pmt(NULL), _next_pmt_version(0),
    98100      _ts_packets_until_psip_sync(0),
     101      // Fake video
     102      _video_stream_fd(-1),
    99103      // Statistics
    100104      _continuity_error_count(0), _stream_overflow_count(0),
    101105      _bad_packet_count(0)
     
    237241        _drb->Reset(videodevice, -1);
    238242#endif
    239243
     244        if (_video_stream_fd >= 0)
     245        {
     246            close(_video_stream_fd);
     247            _video_stream_fd = -1;
     248        }
     249
    240250        CloseFilters();
    241251        close(_stream_fd);
    242252        _stream_fd = -1;
     
    272282    // rounded up to the nearest page
    273283    pid_buffer_size = ((pid_buffer_size + 4095) / 4096) * 4096;
    274284
    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));
    277287
    278288    // Open the demux device
    279289    int fd_tmp = open(dvbdevice(DVB_DEV_DEMUX,_card_number_option), O_RDWR);
     
    331341    _pid_infos[pid] = info;
    332342}
    333343
     344#define TS_TICKS_PER_SEC    90000
     345#define DUMMY_VIDEO_PID     VIDEO_PID(0x20)
     346
    334347bool DVBRecorder::OpenFilters(void)
    335348{
     349    bool videoMissing = true;
    336350    CloseFilters();
    337351
    338352    QMutexLocker change_lock(&_pid_lock);
     
    351365
    352366        int pid = (*es).PID;
    353367        dmx_pes_type_t pes_type;
     368
     369        if ((*es).Type == ES_TYPE_VIDEO_MPEG1 || (*es).Type == ES_TYPE_VIDEO_MPEG2)
     370            videoMissing = false;
    354371           
    355372        if (_hw_decoder_option)
    356373        {
     
    399416        OpenFilter(_input_pmt.PCRPID, ES_TYPE_UNKNOWN, DMX_PES_OTHER,
    400417                    (*es).Orig_Type);
    401418
     419    if (_video_stream_fd >= 0)
     420        close(_video_stream_fd);
     421    _video_stream_fd = -1;
    402422
     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
    403458    if (_pid_infos.empty())
    404459    {       
    405460        VERBOSE(VB_GENERAL, LOC_WARN +
     
    615670        }
    616671    }
    617672
     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
    618681    // Create the PMT
    619682    ProgramMapTable *pmt = ProgramMapTable::Create(
    620683        programNumber, PMT_PID, _input_pmt.PCRPID,
     
    779842    if (info->isVideo)
    780843        _buffer_packets = !FindKeyframes(&tspacket);
    781844
     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
    782852    // Sync recording start to first keyframe
    783853    if (_wait_for_keyframe_option && _first_keyframe<0)
    784854        return true;
     
    804874    return true;
    805875}
    806876
     877void 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
     961void 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
    8071043////////////////////////////////////////////////////////////
    8081044// Stuff below this comment will be phased out after 0.20 //
    8091045////////////////////////////////////////////////////////////
  • siparser.cpp

     
    12571257
    12581258#ifdef USING_DVB_EIT
    12591259        if ((s.EITPresent) &&
    1260             (s.ServiceType == SDTObject::TV) &&
     1260            (s.ServiceType == SDTObject::TV || s.ServiceType == SDTObject::RADIO) &&
    12611261            ((!PrivateTypes.GuideOnSingleTransport) ||
    12621262            ((PrivateTypes.GuideOnSingleTransport) &&
    12631263            (PrivateTypes.GuideTransportID ==
  • videosource.h

     
    7878    static QString      GetDefaultInput(uint cardid);
    7979
    8080    static bool         IgnoreEncrypted(uint cardid, const QString &inputname);
     81    static bool         TVOnly(uint cardid, const QString &inputname);
    8182
    8283    static bool         hasV4L2(int videofd);
    8384    static InputNames   probeV4LInputs(int videofd, bool &ok);
  • dvbrecorder.h

     
    118118
    119119    DeviceReadBuffer *_drb;
    120120
     121    void GetTimeStamp(const TSPacket& tspacket);
     122    void CreateFakeVideo();
     123
    121124  private:
    122125    // Options set in SetOption()
    123126    int             _card_number_option;
     
    148151    /// PMT on input side
    149152    PMTObject       _input_pmt;
    150153
     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
    151166    // Statistics
    152167    mutable uint        _continuity_error_count;
    153168    mutable uint        _stream_overflow_count;
  • videosource.cpp

     
    397397    return freetoair;
    398398}
    399399
     400bool 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
    400420bool CardUtil::hasV4L2(int videofd)
    401421{
    402422    (void) videofd;
     
    17201740    };
    17211741};
    17221742
     1743class RadioServices: public CheckBoxSetting, public CISetting {
     1744public:
     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
    17231754class ExternalChannelCommand: public LineEditSetting, public CISetting {
    17241755  public:
    17251756    ExternalChannelCommand(const CardInput& parent):
     
    18831914        group->addChild(lnblofswitch = new LNBLofSwitch(*this));
    18841915        group->addChild(lnblofhi = new LNBLofHi(*this));
    18851916        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);
    18871922    }
    18881923#endif
    18891924
  • scanwizard.cpp

     
    446446        bool ftao = CardUtil::IgnoreEncrypted(
    447447            parent->captureCard(), channel->GetCurrentInput());
    448448        scanner->SetFTAOnly(ftao);
     449        bool tvo = CardUtil::TVOnly(
     450            parent->captureCard(), channel->GetCurrentInput());
     451        scanner->SetTVOnly(tvo);
    449452
    450453        connect(scanner, SIGNAL(ServiceScanComplete(void)),
    451454                this,    SLOT(  scanComplete(void)));
  • dbcheck.cpp

     
    1010#include "mythdbcon.h"
    1111
    1212/// This is the DB schema version expected by the running MythTV instance.
    13 const QString currentDatabaseVersion = "1121";
     13const QString currentDatabaseVersion = "1122";
    1414
    1515static bool UpdateDBVersionNumber(const QString &newnumber);
    1616static bool performActualUpdate(const QString updates[], QString version,
     
    19801980            return false;
    19811981    }
    19821982
     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
    19831994// Drop xvmc_buffer_settings table in 0.20
    19841995// Drop dvb_dmx_buf_size and dvb_pkt_buf_size columns of channel in 0.20
    19851996
  • tv_rec.cpp

     
    15431543        sm->SetStreamData(sd);
    15441544        sd->Reset(progNum);
    15451545        sm->SetProgramNumber(progNum);
    1546         sd->SetVideoStreamsRequired(1);
     1546        sd->SetVideoStreamsRequired(0);
    15471547        sm->SetFTAOnly(fta);
    15481548        sm->AddFlags(kDTVSigMon_WaitForPAT | kDTVSigMon_WaitForPMT);
    15491549