Ticket #4466: 4466-hack-v2.patch

File 4466-hack-v2.patch, 12.7 KB (added by danielk, 12 years ago)

just stopping streaming on videofd didn't work, so this tries to do it on all ivtv file descriptors, but that doesn't work either. This seems to confirm that there is no less than 1000 line workaround we can do in MythTV. (This is itself a 387 line patch and it is just a proof of concept and doesn't even do proper error checking.)

  • libs/libmythtv/channel.h

     
    1515typedef QMap<int,int>         VidModV4L1;
    1616typedef QMap<int,v4l2_std_id> VidModV4L2;
    1717
     18extern QMutex            mpeg_recorder_ivtv_hack_lock;
     19extern QMap<QString,int> mpeg_recorder_ivtv_hack_chanfd;
     20extern QMap<QString,int> mpeg_recorder_ivtv_hack_readfd;
     21
    1822/** \class Channel
    1923 *  \brief Implements tuning for TV cards using the V4L driver API,
    2024 *         both versions 1 and 2.
  • libs/libmythtv/mpegrecorder.h

     
    88struct AVFormatContext;
    99struct AVPacket;
    1010
     11extern QMutex            mpeg_recorder_ivtv_hack_lock;
     12extern QMap<QString,int> mpeg_recorder_ivtv_hack_chanfd;
     13extern QMap<QString,int> mpeg_recorder_ivtv_hack_readfd;
     14
    1115class MpegRecorder : public RecorderBase
    1216{
    1317  public:
  • libs/libmythtv/mpegrecorder.cpp

     
    7878
    7979const unsigned int MpegRecorder::kBuildBufferMaxSize = 1024 * 1024;
    8080
     81QMutex            mpeg_recorder_ivtv_hack_lock;
     82QMap<QString,int> mpeg_recorder_ivtv_hack_chanfd;
     83QMap<QString,int> mpeg_recorder_ivtv_hack_readfd;
     84
    8185MpegRecorder::MpegRecorder(TVRec *rec) :
    8286    RecorderBase(rec),
    8387    // Debugging variables
     
    123127
    124128void MpegRecorder::TeardownAll(void)
    125129{
     130    QMutexLocker locker(&mpeg_recorder_ivtv_hack_lock);
     131    QString tmp = QDeepCopy<QString>(videodevice);
     132
    126133    if (chanfd >= 0)
    127134    {
    128135        close(chanfd);
    129136        chanfd = -1;
     137        mpeg_recorder_ivtv_hack_chanfd[tmp.ascii()] = -1;
    130138    }
     139
    131140    if (readfd >= 0)
    132141    {
    133142        close(readfd);
    134143        readfd = -1;
     144        mpeg_recorder_ivtv_hack_readfd[tmp.ascii()] = -1;
    135145    }
    136146}
    137147
     
    324334
    325335bool MpegRecorder::OpenV4L2DeviceAsInput(void)
    326336{
    327     chanfd = open(videodevice.ascii(), O_RDWR);
     337    {
     338        QMutexLocker locker(&mpeg_recorder_ivtv_hack_lock);
     339        chanfd = open(videodevice.ascii(), O_RDWR);
     340        QString tmp = QDeepCopy<QString>(videodevice);
     341        mpeg_recorder_ivtv_hack_chanfd[tmp.ascii()] = chanfd;
     342    }
     343
    328344    if (chanfd < 0)
    329345    {
    330346        VERBOSE(VB_IMPORTANT, LOC_ERR + "Can't open video device. " + ENO);
     
    456472
    457473    SetVBIOptions(chanfd);
    458474
    459     readfd = open(videodevice.ascii(), O_RDWR | O_NONBLOCK);
     475    {
     476        QMutexLocker locker(&mpeg_recorder_ivtv_hack_lock);
     477        readfd = open(videodevice.ascii(), O_RDWR | O_NONBLOCK);
     478        QString tmp = QDeepCopy<QString>(videodevice);
     479        mpeg_recorder_ivtv_hack_readfd[tmp.ascii()] = readfd;
     480    }
     481
    460482    if (readfd < 0)
    461483    {
    462484        VERBOSE(VB_IMPORTANT, LOC_ERR + "Can't open video device." + ENO);
     485        {
     486            QMutexLocker locker(&mpeg_recorder_ivtv_hack_lock);
     487            close(chanfd);
     488            chanfd = -1;
     489            QString tmp = QDeepCopy<QString>(videodevice);
     490            mpeg_recorder_ivtv_hack_chanfd[tmp.ascii()] = -1;
     491        }
    463492        return false;
    464493    }
    465494
  • libs/libmythtv/channel.cpp

     
    746746    return fmt;
    747747}
    748748
    749 bool Channel::SetInputAndFormat(int inputNum, QString newFmt)
     749static bool convertx_hack(
     750    const QString &loc_err_msg,
     751    int videofd, int inputNumV4L, int &ioctlval, bool &undo_convertx_hack)
    750752{
    751     InputMap::const_iterator it = inputs.find(inputNum);
    752     if (it == inputs.end() || (*it)->inputNumV4L < 0)
    753         return false;
     753    bool ok = true;
     754    undo_convertx_hack = false;
    754755
    755     int inputNumV4L = (*it)->inputNumV4L;
    756     bool usingv4l1 = !usingv4l2;
     756    // ConvertX (wis-go7007) requires streaming to be disabled
     757    // before an input switch, do this if initial switch failed.
     758    int  streamType = V4L2_BUF_TYPE_VIDEO_CAPTURE;
     759
     760    ioctlval = ioctl(videofd, VIDIOC_STREAMOFF, &streamType);
     761    if (ioctlval < 0)
     762    {
     763        VERBOSE(VB_IMPORTANT, loc_err_msg +
     764                "\n\t\t\twhile disabling streaming (v4l v2)" + ENO);
     765
     766        ok = false;
     767        ioctlval = 0;
     768    }
     769    else
     770    {
     771        undo_convertx_hack = true;
     772
     773        // Resend the input switch ioctl.
     774        ioctlval = ioctl(videofd, VIDIOC_S_INPUT, &inputNumV4L);
     775    }
     776
     777    return ok;
     778}
     779
     780static bool convertx_unhack(const QString &loc_err_msg, int videofd)
     781{
    757782    bool ok = true;
    758783
    759     QString msg =
    760         QString("SetInputAndFormat(%1, %2) ").arg(inputNum).arg(newFmt);
     784    // ConvertX (wis-go7007) requires streaming to be disabled
     785    // before an input switch, here we try to re-enable streaming.
     786    int  streamType = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    761787
    762     if (usingv4l2)
     788    int ioctlval = ioctl(videofd, VIDIOC_STREAMON, &streamType);
     789    if (ioctlval < 0)
    763790    {
    764         VERBOSE(VB_CHANNEL, LOC + msg + "(v4l v2)");
     791        VERBOSE(VB_IMPORTANT, loc_err_msg +
     792                "\n\t\t\twhile reenabling ivtv streaming (v4l v2)" + ENO);
    765793
    766         int ioctlval = ioctl(videofd, VIDIOC_S_INPUT, &inputNumV4L);
     794        ok = false;
     795    }
    767796
    768         // ConvertX (wis-go7007) requires streaming to be disabled
    769         // before an input switch, do this if initial switch failed.
    770         bool streamingDisabled = false;
    771         int  streamType = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    772         if ((ioctlval < 0) && (errno == EBUSY))
     797    return ok;
     798}
     799
     800static bool ivtv_hack(
     801    const QString &loc_err_msg,
     802    int videofd, int chanfd, int readfd,
     803    int inputNumV4L, int &ioctlval, bool &undo_ivtv_hack)
     804{
     805    bool ok = true;
     806    undo_ivtv_hack = false;
     807
     808    // The ivtv 0.10.6+ drivers require streaming to be disabled
     809    // on all open file descriptors before an input switch, do
     810    // this if initial switch failed.
     811    struct v4l2_encoder_cmd command;
     812    memset(&command, 0, sizeof(struct v4l2_encoder_cmd));
     813    command.cmd   = V4L2_ENC_CMD_PAUSE;
     814    command.flags = V4L2_ENC_CMD_STOP_AT_GOP_END;
     815
     816    VERBOSE(VB_CHANNEL, "disabling streaming on videofd");
     817    ioctlval = ioctl(videofd, VIDIOC_ENCODER_CMD, &command);
     818    if (ioctlval < 0)
     819    {
     820        VERBOSE(VB_IMPORTANT, loc_err_msg +
     821                "\n\t\t\twhile disabling ivtv streaming 1 (v4l v2)" + ENO);
     822
     823        ok = false;
     824        ioctlval = 0;
     825    }
     826    else
     827    {
     828        memset(&command, 0, sizeof(struct v4l2_encoder_cmd));
     829        command.cmd   = V4L2_ENC_CMD_PAUSE;
     830        command.flags = V4L2_ENC_CMD_STOP_AT_GOP_END;
     831
     832        VERBOSE(VB_CHANNEL, "disabling streaming on chanfd");
     833        ioctlval = ioctl(chanfd, VIDIOC_ENCODER_CMD, &command);
     834        if (ioctlval < 0)
    773835        {
    774             ioctlval = ioctl(videofd, VIDIOC_STREAMOFF, &streamType);
     836            VERBOSE(VB_IMPORTANT, loc_err_msg +
     837                    "\n\t\t\twhile disabling ivtv streaming 2 (v4l v2)" + ENO);
     838
     839            memset(&command, 0, sizeof(struct v4l2_encoder_cmd));
     840            command.cmd = V4L2_ENC_CMD_RESUME;
     841            ioctlval = ioctl(videofd, VIDIOC_ENCODER_CMD, &command);
     842
     843            ok = false;
     844            ioctlval = 0;
     845        }
     846        else
     847        {
     848            memset(&command, 0, sizeof(struct v4l2_encoder_cmd));
     849            command.cmd   = V4L2_ENC_CMD_PAUSE;
     850            command.flags = V4L2_ENC_CMD_STOP_AT_GOP_END;
     851
     852            VERBOSE(VB_CHANNEL, "disabling streaming on readfd");
     853            ioctlval = ioctl(readfd, VIDIOC_ENCODER_CMD, &command);
    775854            if (ioctlval < 0)
    776855            {
    777                 VERBOSE(VB_IMPORTANT, LOC_ERR + msg +
    778                         "\n\t\t\twhile disabling streaming (v4l v2)" + ENO);
     856                VERBOSE(VB_IMPORTANT, loc_err_msg +
     857                        "\n\t\t\twhile disabling ivtv streaming 3 "
     858                        "(v4l v2)" + ENO);
    779859
     860                memset(&command, 0, sizeof(struct v4l2_encoder_cmd));
     861                command.cmd = V4L2_ENC_CMD_RESUME;
     862                ioctlval = ioctl(chanfd, VIDIOC_ENCODER_CMD, &command);
     863
     864                memset(&command, 0, sizeof(struct v4l2_encoder_cmd));
     865                command.cmd = V4L2_ENC_CMD_RESUME;
     866                ioctlval = ioctl(videofd, VIDIOC_ENCODER_CMD, &command);
     867
    780868                ok = false;
    781869                ioctlval = 0;
    782870            }
    783871            else
    784872            {
    785                 streamingDisabled = true;
     873                undo_ivtv_hack = true;
    786874
    787875                // Resend the input switch ioctl.
     876                VERBOSE(VB_CHANNEL, "resending input changing command");
    788877                ioctlval = ioctl(videofd, VIDIOC_S_INPUT, &inputNumV4L);
    789878            }
    790879        }
     880    }
    791881
     882    return ok;
     883}
     884
     885static bool ivtv_unhack(const QString &loc_err_msg,
     886                        int videofd, int chanfd, int readfd)
     887{
     888    bool ok = true;
     889
     890    // The ivtv 0.10.6+ drivers require streaming to be disabled
     891    // before an input switch, here we try to re-enable streaming.
     892    struct v4l2_encoder_cmd command;
     893    memset(&command, 0, sizeof(struct v4l2_encoder_cmd));
     894    command.cmd = V4L2_ENC_CMD_RESUME;
     895
     896    VERBOSE(VB_CHANNEL, "enabling streaming on readfd");
     897    int ioctlval = ioctl(readfd, VIDIOC_ENCODER_CMD, &command);
     898    if (ioctlval < 0)
     899    {
     900        VERBOSE(VB_IMPORTANT, loc_err_msg +
     901                "\n\t\t\twhile reenabling ivtv streaming 1 (v4l v2)" + ENO);
     902
     903        ok = false;
     904    }
     905
     906    VERBOSE(VB_CHANNEL, "enabling streaming on chanfd");
     907    ioctlval = ioctl(chanfd, VIDIOC_ENCODER_CMD, &command);
     908    if (ioctlval < 0)
     909    {
     910        VERBOSE(VB_IMPORTANT, loc_err_msg +
     911                "\n\t\t\twhile reenabling ivtv streaming 2 (v4l v2)" + ENO);
     912
     913        ok = false;
     914    }
     915
     916    VERBOSE(VB_CHANNEL, "enabling streaming on videofd");
     917    ioctlval = ioctl(videofd, VIDIOC_ENCODER_CMD, &command);
     918    if (ioctlval < 0)
     919    {
     920        VERBOSE(VB_IMPORTANT, loc_err_msg +
     921                "\n\t\t\twhile reenabling ivtv streaming 3 (v4l v2)" + ENO);
     922
     923        ok = false;
     924    }
     925
     926    return ok;
     927}
     928
     929bool Channel::SetInputAndFormat(int inputNum, QString newFmt)
     930{
     931    InputMap::const_iterator it = inputs.find(inputNum);
     932    if (it == inputs.end() || (*it)->inputNumV4L < 0)
     933        return false;
     934
     935    int inputNumV4L = (*it)->inputNumV4L;
     936    bool usingv4l1 = !usingv4l2;
     937    bool ok = true;
     938
     939    QString msg =
     940        QString("SetInputAndFormat(%1, %2) ").arg(inputNum).arg(newFmt);
     941
     942    if (usingv4l2)
     943    {
     944        VERBOSE(VB_CHANNEL, LOC + msg + "(v4l v2)");
     945
     946        VERBOSE(VB_CHANNEL, QString("sending input changing command (%1)")
     947                .arg(driver_name));
     948
     949        int ioctlval = ioctl(videofd, VIDIOC_S_INPUT, &inputNumV4L);
     950
     951        bool undo_convertx_hack = false;
     952        bool undo_ivtv_hack = false;
     953        if ((driver_name == "ivtv") && (ioctlval < 0) && (errno == EBUSY))
     954        {
     955            QMutexLocker locker(&mpeg_recorder_ivtv_hack_lock);
     956            QString tmp = QDeepCopy<QString>(device);
     957            ok = ivtv_hack(LOC_ERR + msg,
     958                           videofd,
     959                           mpeg_recorder_ivtv_hack_chanfd[tmp.ascii()],
     960                           mpeg_recorder_ivtv_hack_readfd[tmp.ascii()],
     961                           inputNumV4L,
     962                           ioctlval, undo_ivtv_hack);
     963        }
     964        else if ((ioctlval < 0) && (errno == EBUSY))
     965        {
     966            ok = convertx_hack(LOC_ERR + msg, videofd, inputNumV4L,
     967                               ioctlval, undo_convertx_hack);
     968        }
     969
    792970        if (ioctlval < 0)
    793971        {
    794972            VERBOSE(VB_IMPORTANT, LOC_ERR + msg +
     
    807985            ok = false;
    808986        }
    809987
    810         // ConvertX (wis-go7007) requires streaming to be disabled
    811         // before an input switch, here we try to re-enable streaming.
    812         if (streamingDisabled)
     988        if (undo_convertx_hack)
     989            ok &= convertx_unhack(LOC_ERR + msg, videofd);
     990        if (undo_ivtv_hack)
    813991        {
    814             ioctlval = ioctl(videofd, VIDIOC_STREAMON, &streamType);
    815             if (ioctlval < 0)
    816             {
    817                 VERBOSE(VB_IMPORTANT, LOC_ERR + msg +
    818                         "\n\t\t\twhile reenabling streaming (v4l v2)" + ENO);
    819 
    820                 ok = false;
    821             }
     992            QMutexLocker locker(&mpeg_recorder_ivtv_hack_lock);
     993            QString tmp = QDeepCopy<QString>(device);
     994            ok = ivtv_unhack(LOC_ERR + msg,
     995                             videofd,
     996                             mpeg_recorder_ivtv_hack_chanfd[tmp.ascii()],
     997                             mpeg_recorder_ivtv_hack_readfd[tmp.ascii()]);
    822998        }
    823999    }
    8241000