Ticket #13251: mythfilerecorder-add-exec.patch

File mythfilerecorder-add-exec.patch, 11.8 KB (added by Dan Wilga <mythtv-users2@…>, 3 years ago)
  • mythtv/programs/mythfilerecorder/commandlineparser.cpp

    diff --git a/mythtv/programs/mythfilerecorder/commandlineparser.cpp b/mythtv/programs/mythfilerecorder/commandlineparser.cpp
    index d9caeab..e8d4ed5 100644
    a b MythFileRecorderCommandLineParser::MythFileRecorderCommandLineParser() : 
    1212
    1313QString MythFileRecorderCommandLineParser::GetHelpHeader(void) const
    1414{
    15     return "MythFilelRecorder's allow a go-between app to interface "
    16         "with a recording device before the data is processed by mythbackend.";
     15    return "MythFileRecorder is a go-between app which interfaces "
     16        "between a recording device and mythbackend.";
    1717}
    1818
    1919void MythFileRecorderCommandLineParser::LoadArguments(void)
    void MythFileRecorderCommandLineParser::LoadArguments(void) 
    2626
    2727    addInFile();
    2828
     29    add(QStringList(QStringList() << "--exec"),
     30        "exec", false,
     31        "Execute infile as a program, rather than opening it. Recording data is expected to be on stdout. --noloop is ignored.", "");
     32
    2933    add(QStringList(QStringList() << "--noloop"),
    3034        "noloop", false,
    3135        "Don't loop input back to beginning on EOF.", "");
    void MythFileRecorderCommandLineParser::LoadArguments(void) 
    3337    add(QStringList(QStringList() << "--data-rate"),
    3438        "data_rate", 188*50000,
    3539        "Rate at which to read data from the file.", "");
     40
     41    add(QStringList(QStringList() << "--tuner"),
     42        "tuner", "",
     43        "Path of another program which will tune the channel requested by MythTV. Must accept the channel number as the last parameter.", "");
    3644}
  • mythtv/programs/mythfilerecorder/mythfilerecorder.cpp

    diff --git a/mythtv/programs/mythfilerecorder/mythfilerecorder.cpp b/mythtv/programs/mythfilerecorder/mythfilerecorder.cpp
    index 6ea4295..521d5f8 100644
    a b using namespace std; 
    1212#include <QCoreApplication>
    1313#include <QTime>
    1414#include <QThread>
     15#include <QProcess>
    1516
    1617#include "commandlineparser.h"
    1718#include "mythfilerecorder.h"
    using namespace std; 
    2324
    2425
    2526#define VERSION "1.0.0"
    26 #define LOC QString("File(%1): ").arg(m_fileName)
     27#define LOC (m_exec_file ? QString("Child program: ") : QString("File(%1): ").arg(m_fileName))
    2728
    2829Streamer::Streamer(Commands *parent, const QString &fname,
    29                    int data_rate, bool loopinput) :
    30     m_parent(parent), m_fileName(fname), m_file(NULL), m_loop(loopinput),
     30                   bool exec_file, int data_rate, bool loopinput) :
     31    m_parent(parent), m_fileName(fname), m_file(NULL),
     32    m_exec_file(exec_file), m_loop(loopinput),
    3133    m_bufferMax(188 * 100000), m_blockSize(m_bufferMax / 4),
    32     m_data_rate(data_rate), m_data_read(0)
     34    m_data_rate(data_rate), m_data_read(0), m_proc(NULL)
    3335{
    3436    setObjectName("Streamer");
    35     OpenFile();
     37    if (!m_exec_file) OpenFile();
    3638    LOG(VB_RECORD, LOG_INFO, LOC + QString("Data Rate: %1").arg(m_data_rate));
    3739}
    3840
    Streamer::~Streamer(void) 
    4547
    4648void Streamer::OpenFile(void)
    4749{
    48     m_file = new QFile(m_fileName);
    49     if (!m_file || !m_file->open(QIODevice::ReadOnly))
     50    if (m_exec_file)
    5051    {
    51         LOG(VB_RECORD, LOG_ERR, LOC + QString("Failed to open '%1' - ")
    52             .arg(m_fileName) + ENO);
     52        m_proc = new QProcess(this);
     53        m_proc->setProcessChannelMode(QProcess::ForwardedOutputChannel);
     54        m_proc->start(m_fileName, QIODevice::ReadOnly|QProcess::Unbuffered);
     55        if (!m_proc->waitForStarted()) {
     56            LOG(VB_RECORD, LOG_ERR, LOC + QString("Failed to execute '%1' - ")
     57                .arg(m_fileName) + ENO);
     58        }
     59        else {
     60            LOG(VB_RECORD, LOG_INFO, LOC + QString("Executed '%1' - pid: %2")
     61                .arg(m_fileName).arg(m_proc->processId()));
     62        }
     63    }
     64    else {
     65        m_file = new QFile(m_fileName);
     66        if (!m_file || !m_file->open(QIODevice::ReadOnly))
     67        {
     68            LOG(VB_RECORD, LOG_ERR, LOC + QString("Failed to open '%1' - ")
     69                .arg(m_fileName) + ENO);
     70        }
    5371    }
    5472}
    5573
    void Streamer::CloseFile(void) 
    6280        delete m_file;
    6381        m_file = NULL;
    6482    }
     83    if (m_proc)
     84    {
     85        m_proc->close();
     86        delete m_proc;
     87        m_proc = NULL;
     88    }
    6589
    6690    LOG(VB_RECORD, LOG_INFO, LOC + "Streamer::Close -- end");
    6791}
    void Streamer::SendBytes(void) 
    7296
    7397    LOG(VB_RECORD, LOG_DEBUG, LOC + "SendBytes -- start");
    7498
     99    if (m_exec_file)
     100    {
     101        if (!m_proc)
     102        {
     103            OpenFile();
     104        }
     105        return;
     106    }
     107
    75108    if (!m_file)
    76109    {
    77110        LOG(VB_GENERAL, LOG_ERR, LOC + "SendBytes -- file not open");
    bool Commands::process_command(QString & cmd) 
    199232    }
    200233    if (cmd.startsWith("HasLock?"))
    201234    {
    202         send_status(m_streamer->IsOpen() ? "OK:Yes" : "OK:No");
     235        send_status(m_exec_file || m_streamer->IsOpen() ? "OK:Yes" : "OK:No");
    203236        return true;
    204237    }
    205238    if (cmd.startsWith("SignalStrengthPercent"))
    206239    {
    207         send_status(m_streamer->IsOpen() ? "OK:100" : "OK:0");
     240        send_status(m_exec_file || m_streamer->IsOpen() ? "OK:100" : "OK:0");
    208241        return true;
    209242    }
    210243    if (cmd.startsWith("LockTimeout"))
    211244    {
    212         send_status("OK:1000");
     245        send_status("OK:5000");
    213246        return true;
    214247    }
    215248    if (cmd.startsWith("HasTuner?"))
    216249    {
    217         send_status("OK:No");
     250        send_status(m_tuner.isEmpty() ? "OK:No" : "OK:Yes");
    218251        return true;
    219252    }
    220253    if (cmd.startsWith("HasPictureAttributes?"))
    bool Commands::process_command(QString & cmd) 
    233266
    234267    if (cmd.startsWith("SendBytes"))
    235268    {
    236         if (!m_streamer->IsOpen())
     269        if (!m_exec_file && !m_streamer->IsOpen())
    237270        {
    238271            send_status("ERR:file not open");
    239272            LOG(VB_RECORD, LOG_ERR, LOC + "SendBytes - file not open.");
    bool Commands::process_command(QString & cmd) 
    241274        else
    242275        {
    243276#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
    244         if (m_eof.loadAcquire() != 0)
     277            if (m_eof.loadAcquire() != 0)
    245278#else
    246         if (m_eof != 0)
     279            if (m_eof != 0)
    247280#endif
    248281                send_status("ERR:End of file");
    249282            else
    bool Commands::process_command(QString & cmd) 
    253286            }
    254287        }
    255288    }
    256 #if 0
    257289    else if (cmd.startsWith("XON"))
    258290    {
    259291        // Used when FlowControl is XON/XOFF
     292        send_status("OK");
    260293    }
    261294    else if (cmd.startsWith("XOFF"))
    262295    {
    263296        // Used when FlowControl is XON/XOFF
     297        send_status("OK");
    264298    }
    265     else if (cmd.startsWith("TuneChannel"))
     299    else if (cmd.startsWith("TuneChannel:"))
    266300    {
    267         // Used if we announce that we have a 'tuner'
    268 
    269         /**
    270          * TODO:  extend to allow to 'tune' to different files.
    271          */
     301        if (!m_tuner.isEmpty())
     302        {
     303            QProcess *p = new QProcess(this);
     304            p->start(QString("%1 %2").arg(m_tuner).arg(cmd.mid(12)));
     305            p->waitForFinished();
     306            delete p;
     307            p = NULL;
     308            send_status("OK");
     309        }
     310        else
     311            send_status(QString("ERR:No tuner has been set"));
    272312    }
    273 #endif
    274313    else if (cmd.startsWith("IsOpen?"))
    275314    {
    276         if (m_streamer->IsOpen())
     315        if (m_exec_file || m_streamer->IsOpen())
    277316            send_status("OK:Open");
    278317        else
    279             send_status(QString("ERR:Not Open: '%2'")
     318            send_status(QString("ERR:Not Open: '%1'")
    280319                        .arg(m_streamer->ErrorString()));
    281320    }
    282321    else if (cmd.startsWith("CloseRecorder"))
    bool Commands::process_command(QString & cmd) 
    304343         * this 'recording' ExternalChannel::EnterPowerSavingMode()
    305344         * will be called, which invokes CloseRecorder() */
    306345        send_status("OK:Stopped");
     346        emit CloseFile();
    307347    }
    308348    else
    309349    {
    bool Commands::process_command(QString & cmd) 
    315355    return true;
    316356}
    317357
    318 bool Commands::Run(const QString & filename, int data_rate, bool loopinput)
     358bool Commands::Run(const QString & filename, bool exec_file, int data_rate, bool loopinput, const QString & tuner)
    319359{
    320360    QString cmd;
    321361
    bool Commands::Run(const QString & filename, int data_rate, bool loopinput) 
    329369    polls[0].revents = 0;
    330370
    331371    m_fileName = filename;
     372    m_exec_file = exec_file;
     373    m_tuner = tuner;
    332374
    333     m_streamer = new Streamer(this, m_fileName, data_rate, loopinput);
     375    m_streamer = new Streamer(this, m_fileName, m_exec_file, data_rate, loopinput);
    334376    QThread *streamThread = new QThread(this);
    335377
    336378    m_streamer->moveToThread(streamThread);
    bool Commands::Run(const QString & filename, int data_rate, bool loopinput) 
    339381
    340382    connect(this, SIGNAL(SendBytes(void)),
    341383            m_streamer, SLOT(SendBytes(void)));
     384    connect(this, SIGNAL(CloseFile(void)),
     385            m_streamer, SLOT(CloseFile(void)));
    342386
    343387    streamThread->start();
    344388
    int main(int argc, char *argv[]) 
    424468    }
    425469
    426470    bool loopinput = !cmdline.toBool("noloop");
     471    bool exec_file = cmdline.toBool("exec");
    427472    int  data_rate = cmdline.toInt("data_rate");
    428473
    429474    QCoreApplication a(argc, argv);
    int main(int argc, char *argv[]) 
    439484    else if (cmdline.GetArgs().size() >= 1)
    440485        filename = cmdline.GetArgs()[0];
    441486
     487    QString tuner = "";
     488    if (!cmdline.toString("tuner").isEmpty())
     489        tuner = cmdline.toString("tuner");
     490
    442491    Commands recorder;
    443     recorder.Run(filename, data_rate, loopinput);
     492    recorder.Run(filename, exec_file, data_rate, loopinput, tuner);
    444493
    445494    return GENERIC_EXIT_OK;
    446495}
  • mythtv/programs/mythfilerecorder/mythfilerecorder.h

    diff --git a/mythtv/programs/mythfilerecorder/mythfilerecorder.h b/mythtv/programs/mythfilerecorder/mythfilerecorder.h
    index 0396bd9..f3d9aa6 100644
    a b  
    44#include <QObject>
    55#include <QFile>
    66#include <QString>
     7#include <QProcess>
    78
    89#include <sys/types.h>
    910#include <unistd.h>
    class Streamer : public QObject 
    2223    void SendBytes(void);
    2324
    2425  public:
    25     Streamer(Commands *parent, const QString &filename, int data_rate,
    26              bool loopinput);
     26    Streamer(Commands *parent, const QString &filename, bool exec_file,
     27             int data_rate, bool loopinput);
    2728    virtual ~Streamer(void);
    2829    void BlockSize(int val) { m_blockSize = val; }
    29     bool IsOpen(void) const { return m_file; }
     30    bool IsOpen(void) const { return m_exec_file ? (bool) m_proc : (bool) m_file; }
    3031    QString ErrorString(void) const { return m_error; }
    3132
    3233  protected:
    class Streamer : public QObject 
    3637    Commands *m_parent;
    3738    QString   m_fileName;
    3839    QFile    *m_file;
     40    bool      m_exec_file;
    3941    bool      m_loop;
    4042
    41     QString m_error;
     43    QString   m_error;
    4244
    43     QByteArray  m_buffer;
    44     int     m_bufferMax;
    45     QAtomicInt  m_blockSize;
     45    QByteArray m_buffer;
     46    int        m_bufferMax;
     47    QAtomicInt m_blockSize;
    4648
    4749    // Regulate data rate
    4850    uint      m_data_rate;  // bytes per second
    4951    QDateTime m_start_time; // When the first packet was processed
    5052    quint64   m_data_read;  // How many bytes have been sent
     53
     54    QProcess *m_proc;
    5155};
    5256
    5357class Commands : public QObject
    class Commands : public QObject 
    6165  public:
    6266    Commands(void);
    6367    virtual ~Commands(void);
    64     bool Run(const QString & filename, int data_rate, bool loopinput);
     68    bool Run(const QString & filename, bool exec_file, int data_rate, bool loopinput, const QString &tuner);
    6569    void setEoF(void) { m_eof = true; }
    6670
    6771  protected:
    class Commands : public QObject 
    6973    bool process_command(QString & cmd);
    7074
    7175  private:
    72     QString   m_fileName;
     76    QString   m_fileName, m_tuner;
    7377    Streamer *m_streamer;
    7478    int       m_timeout;
    7579    bool      m_run;
     80    bool      m_exec_file;
    7681    QAtomicInt m_eof;
    7782};
    7883