Ticket #6322: 137-editgrid.seekamount.code.16.patch

File 137-editgrid.seekamount.code.16.patch, 85.7 KB (added by cizek@…, 15 years ago)
  • mythtv/libs/libmyth/mythdialogs.cpp

    diff -r -u -N -X diff.exclude -x release.20019.0219a -x release.20019.0219b release.20019.0219a/mythtv/libs/libmyth/mythdialogs.cpp release.20019.0219b/mythtv/libs/libmyth/mythdialogs.cpp
     
    12581258        rect_to_update = this->geometry();
    12591259    }
    12601260
    1261     redrawRect = redrawRect.unite(r);
     1261    redrawRect = redrawRect.unite(rect_to_update);
    12621262
    12631263    update(redrawRect);
    12641264}
     
    16001600    return GetUIType<UIBlackHoleType>(this, name);
    16011601}
    16021602
     1603UIGridEditImageType* MythThemedDialog::getUIGridEditImageType(const QString &name)
     1604{
     1605    return GetUIType<UIGridEditImageType>(this, name);
     1606}
     1607
     1608UIGridEditSliderType* MythThemedDialog::getUIGridEditSliderType(const QString &name)
     1609{
     1610    return GetUIType<UIGridEditSliderType>(this, name);
     1611}
     1612
    16031613UIImageType* MythThemedDialog::getUIImageType(const QString &name)
    16041614{
    16051615    return GetUIType<UIImageType>(this, name);
  • mythtv/libs/libmyth/mythdialogs.h

    diff -r -u -N -X diff.exclude -x release.20019.0219a -x release.20019.0219b release.20019.0219a/mythtv/libs/libmyth/mythdialogs.h release.20019.0219b/mythtv/libs/libmyth/mythdialogs.h
     
    3333class UICheckBoxType;
    3434class UISelectorType;
    3535class UIBlackHoleType;
     36class UIGridEditImageType;
     37class UIGridEditSliderType;
    3638class UIImageType;
    3739class UIImageGridType;
    3840class UIStatusBarType;
     
    373375    UICheckBoxType *getUICheckBoxType(const QString &name);
    374376    UISelectorType *getUISelectorType(const QString &name);
    375377    UIBlackHoleType *getUIBlackHoleType(const QString &name);
     378    UIGridEditImageType *getUIGridEditImageType(const QString &name);
     379    UIGridEditSliderType *getUIGridEditSliderType(const QString &name);
    376380    UIImageGridType *getUIImageGridType(const QString &name);
    377381    UIImageType *getUIImageType(const QString &name);
    378382    UIStatusBarType *getUIStatusBarType(const QString &name);
  • mythtv/libs/libmyth/uitypes.cpp

    diff -r -u -N -X diff.exclude -x release.20019.0219a -x release.20019.0219b release.20019.0219a/mythtv/libs/libmyth/uitypes.cpp release.20019.0219b/mythtv/libs/libmyth/uitypes.cpp
     
    53385338
    53395339// ********************************************************************
    53405340
     5341UIGridEditImageType::UIGridEditImageType(const QString &name)
     5342                     : UIType(name)
     5343{
     5344    cutStatus = 0;
     5345    framenumber = -1;
     5346}
     5347
     5348void UIGridEditImageType::calculateScreenArea()
     5349{
     5350    QRect r = area;
     5351    r.moveBy(m_parent->GetAreaRect().left(),
     5352             m_parent->GetAreaRect().top());
     5353    screen_area = r;
     5354
     5355    inner_border.setLeft(screen_area.left()+1);
     5356    inner_border.setRight(screen_area.right()-1);
     5357    inner_border.setTop(screen_area.top()+1);
     5358    inner_border.setBottom(screen_area.bottom()-1);
     5359
     5360    outer_border.setLeft(screen_area.left()-1);
     5361    outer_border.setRight(screen_area.right()+1);
     5362    outer_border.setTop(screen_area.top()-1);
     5363    outer_border.setBottom(screen_area.bottom()+1);
     5364}
     5365
     5366void UIGridEditImageType::Draw(QPainter *p, int drawlayer, int context)
     5367{
     5368    if (pmap.isNull())
     5369    {
     5370        QColor drawcolor = QColor( 0, 0, 0);
     5371        p->setBrush(QBrush(Qt::SolidPattern));
     5372        p->setPen(QPen(drawcolor, 2));
     5373        p->drawRect(screen_area);
     5374    }
     5375    else
     5376    {
     5377        p->drawPixmap(screen_area, pmap);
     5378
     5379        p->setBrush(QBrush(Qt::NoBrush));
     5380        p->setPen(QPen(colorSet[cutStatus], 3));
     5381        p->drawRect(inner_border);
     5382        if (cutStatus > 0) {
     5383            p->drawLine(inner_border.topLeft(), inner_border.bottomRight());
     5384            p->drawLine(inner_border.bottomLeft(), inner_border.topRight());
     5385        }
     5386    }
     5387}
     5388
     5389void UIGridEditImageType::setPixmap(QPixmap *new_pmap, long long frame, int new_cutStatus)
     5390{
     5391    // We can get a null new_pmap at the start or end of the video
     5392    if (! new_pmap)
     5393    {
     5394        clearPixmap();
     5395        return;
     5396    }
     5397
     5398    if (frame == framenumber)
     5399    {
     5400        // No change in pixmap (?)
     5401        setCutStatus(new_cutStatus);
     5402        return;
     5403    }
     5404
     5405    pmap = *new_pmap;
     5406    framenumber = frame;
     5407
     5408    if (new_cutStatus >= 0 && new_cutStatus <= 3)
     5409        cutStatus = new_cutStatus;
     5410    else
     5411        cutStatus = 0;
     5412
     5413    refresh();
     5414}
     5415
     5416void UIGridEditImageType::clearPixmap(bool dorefresh)
     5417{
     5418    if (! pmap.isNull())
     5419    {
     5420        pmap = QPixmap();
     5421
     5422        cutStatus = 0;
     5423        framenumber = -1;
     5424        if (dorefresh)
     5425            refresh();
     5426    }
     5427}
     5428
     5429void UIGridEditImageType::setCutStatus(int new_cutStatus)
     5430{
     5431    if (new_cutStatus == cutStatus)
     5432        return;
     5433
     5434    if (new_cutStatus >= 0 && new_cutStatus <= 3)
     5435        cutStatus = new_cutStatus;
     5436    else
     5437        cutStatus = 0;
     5438
     5439    refresh();
     5440}
     5441
     5442// ********************************************************************
     5443
     5444UIGridEditSliderType::UIGridEditSliderType(const QString &name)
     5445                     : UIType(name)
     5446{
     5447    m_drawMap = NULL;
     5448    m_position=0;
     5449}
     5450
     5451void UIGridEditSliderType::calculateScreenArea()
     5452{
     5453    QRect r = area;
     5454    r.moveBy(m_parent->GetAreaRect().left(),
     5455             m_parent->GetAreaRect().top());
     5456    screen_area = r;
     5457
     5458    if (m_drawMap)
     5459        delete [] m_drawMap;
     5460
     5461    m_drawWidth = area.width();
     5462    m_drawMap = new unsigned char[m_drawWidth];
     5463    for (int i = 0; i < m_drawWidth; i++)
     5464        m_drawMap[i] = 0;
     5465}
     5466
     5467void UIGridEditSliderType::ClearAll()
     5468{
     5469    for (int i = 0; i < m_drawWidth; i++)
     5470        m_drawMap[i] = 0;
     5471    refresh();
     5472}
     5473
     5474void UIGridEditSliderType::SetRange(
     5475        long long fstart, long long fend, long long fcount)
     5476{
     5477    if (fcount <= 0)
     5478    {
     5479        VERBOSE(VB_IMPORTANT, QString("Invalid frame count: %1")
     5480                .arg(fcount));
     5481        return;
     5482    }
     5483    if (fstart < 0)
     5484    {
     5485        VERBOSE(VB_IMPORTANT, QString("Invalid starting frame: %1")
     5486                .arg(fstart));
     5487        return;
     5488    }
     5489    if (fend < 0)
     5490    {
     5491        VERBOSE(VB_IMPORTANT, QString("Invalid ending frame: %1")
     5492                .arg(fend));
     5493        return;
     5494    }
     5495
     5496    if (fstart > fcount) fstart = fcount;
     5497    if (fend > fcount) fend = fcount;
     5498
     5499    int start = (int)((1.0 * fstart * m_drawWidth) / fcount);
     5500    int end   = (int)((1.0 * fend   * m_drawWidth) / fcount);
     5501
     5502    if (start < 0)
     5503        start = 0;
     5504    if (start >= m_drawWidth)
     5505        start = m_drawWidth - 1;
     5506    if (end < 0)
     5507        end = 0;
     5508    if (end >= m_drawWidth)
     5509        end = m_drawWidth - 1;
     5510
     5511    if (end < start)
     5512    {
     5513        int tmp = start;
     5514        start = end;
     5515        end = tmp;
     5516    }
     5517
     5518    for (int i = start; i < end; i++)
     5519        if (m_drawMap[i] < 1)
     5520            m_drawMap[i] = 1;
     5521
     5522    // Mark endpoints
     5523    m_drawMap[start] = 2;
     5524    m_drawMap[end]   = 2;
     5525
     5526    VERBOSE(VB_GENERAL, QString("Range = %1 - %2 (%3 - %4)")
     5527            .arg(start).arg(end)
     5528            .arg(fstart).arg(fend));
     5529    refresh();
     5530}
     5531
     5532void UIGridEditSliderType::SetPosition(
     5533        long long fposition, long long fcount)
     5534{
     5535    if (fcount <= 0)
     5536    {
     5537        VERBOSE(VB_IMPORTANT, QString("Invalid frame count: %1")
     5538                .arg(fcount));
     5539        return;
     5540    }
     5541
     5542    if (fposition < 0)
     5543    {
     5544        VERBOSE(VB_IMPORTANT, QString("Invalid position frame: %1")
     5545                .arg(fposition));
     5546        return;
     5547    }
     5548
     5549    if (fposition > fcount) fposition = fcount;
     5550
     5551    int new_position = (int)(1.0 * fposition * m_drawWidth) / fcount;
     5552
     5553    if (new_position < 0)
     5554        new_position = 0;
     5555    if (new_position >= m_drawWidth)
     5556       new_position = m_drawWidth - 1;
     5557
     5558    if (new_position != m_position)
     5559    {
     5560        m_position = new_position;
     5561        refresh();
     5562    }
     5563}
     5564
     5565void UIGridEditSliderType::Draw(QPainter *p, int drawlayer, int context)
     5566{
     5567    // Draw Background
     5568    p->setPen(QPen(colorSet[0], 2));
     5569    p->setBrush(colorSet[0]);
     5570    p->drawRect(screen_area);
     5571
     5572    // Draw bars
     5573
     5574//    VERBOSE(VB_GENERAL, QString("Starting"));
     5575    int i = 0;
     5576    do {
     5577        int start = 0;
     5578        int end = 0;
     5579
     5580        while (i < m_drawWidth && m_drawMap[i] == 0) i++;
     5581        if (i == m_drawWidth) break;
     5582        start = i;
     5583
     5584        i++;
     5585       
     5586
     5587        while (i < m_drawWidth && m_drawMap[i] == 1) i++;
     5588        end = i;
     5589        if (end == m_drawWidth) end--;
     5590
     5591        // If the next map value is not a normal internal cutpoint
     5592        // increment i so we handle it properly
     5593        if (end+1 < m_drawWidth && m_drawMap[end+1] != 1)
     5594            i++;
     5595
     5596        // start == starting point
     5597        //   end == endingpoint
     5598        {
     5599            QRect r = screen_area;
     5600            r.setLeft(r.left() + start);
     5601            r.setWidth(end - start);
     5602
     5603//            VERBOSE(VB_GENERAL, QString("Cut from (%1, %2) - (%3, %4)")
     5604//                    .arg(r.left()).arg(r.top())
     5605//                    .arg(r.right()).arg(r.bottom()));
     5606
     5607//            VERBOSE(VB_GENERAL, QString("start = %1, m_position = %2, end = %3")
     5608//                    .arg(start)
     5609//                    .arg(m_position)
     5610//                    .arg(end));
     5611           
     5612            if (start <= m_position && m_position <= end)
     5613            {
     5614                p->setPen(QPen(colorSet[4], 2));
     5615                p->setBrush(colorSet[4]);
     5616            }
     5617            else
     5618            {
     5619                p->setPen(QPen(colorSet[1], 2));
     5620                p->setBrush(colorSet[1]);
     5621            }
     5622            p->drawRect(r);
     5623
     5624            p->setPen(QPen(colorSet[2], 2));
     5625            p->setBrush(colorSet[2]);
     5626            if (m_drawMap[start] == 2)
     5627                p->drawLine(r.topLeft(), r.bottomLeft());
     5628            if (m_drawMap[end] == 2)
     5629                p->drawLine(r.topRight(), r.bottomRight());
     5630
     5631        }
     5632    } while (i < m_drawWidth);
     5633
     5634    // Draw Current Position Mark
     5635
     5636    QPoint ptop(screen_area.left() + m_position, screen_area.top());
     5637    QPoint pbot(screen_area.left() + m_position, screen_area.bottom());
     5638
     5639    p->setPen(QPen(colorSet[3], 2));
     5640    p->setBrush(colorSet[3]);
     5641    p->drawLine(ptop, pbot);
     5642}
     5643
     5644// ********************************************************************
     5645
    53415646UIKeyType::UIKeyType(const QString &name)
    53425647         : UIType(name)
    53435648{
  • mythtv/libs/libmyth/uitypes.h

    diff -r -u -N -X diff.exclude -x release.20019.0219a -x release.20019.0219b release.20019.0219a/mythtv/libs/libmyth/uitypes.h release.20019.0219b/mythtv/libs/libmyth/uitypes.h
     
    13851385    QRect area;
    13861386};
    13871387
     1388class MPUBLIC UIGridEditImageType : public UIType
     1389{
     1390    Q_OBJECT
     1391
     1392  public:
     1393
     1394    UIGridEditImageType(const QString &name);
     1395    void calculateScreenArea();
     1396    void setArea(QRect an_area)     { area = an_area; };
     1397
     1398    void setOutlineColor(QColor c)  { colorSet[0] = c; };
     1399    void setCutColor(QColor c)      { colorSet[1] = c; };
     1400    void setCutPointColor(QColor c)
     1401    {
     1402         colorSet[2] = c; // Cut before
     1403         colorSet[3] = c; // Cut after
     1404    };
     1405
     1406    virtual void Draw(QPainter *, int, int);
     1407    void setPixmap(QPixmap *new_pmap, long long frame, int new_cutStatus);
     1408 
     1409    void clearPixmap(bool dorefresh=true);
     1410    void setCutStatus(int new_cutStatus);
     1411
     1412    QRect getOuterBorder() { return outer_border; };
     1413  protected:
     1414
     1415    QRect    area;
     1416    QRect    inner_border;
     1417    QRect    outer_border;
     1418    QPixmap  pmap;
     1419    long long framenumber; // for consistency checking
     1420    int      cutStatus;
     1421    QColor   colorSet[4];
     1422};
     1423
     1424class MPUBLIC UIGridEditSliderType : public UIType
     1425{
     1426    Q_OBJECT
     1427
     1428  public:
     1429
     1430    UIGridEditSliderType(const QString &name);
     1431    void calculateScreenArea();
     1432    void setArea(QRect an_area)     { area = an_area; };
     1433
     1434    void setFillColor(QColor c)     { colorSet[0] = c; };
     1435    void setCutColor(QColor c)      { colorSet[1] = c; };
     1436    void setCutPointColor(QColor c) { colorSet[2] = c; };
     1437    void setPositionColor(QColor c) { colorSet[3] = c; };
     1438    void setInCutColor(QColor c)    { colorSet[4] = c; };
     1439
     1440    void ClearAll();
     1441    void SetRange(long long fstart, long long fend, long long fcount);
     1442    void SetPosition(long long fposition, long long fcount);
     1443
     1444    virtual void Draw(QPainter *, int, int);
     1445  protected:
     1446
     1447    QRect          area;
     1448    unsigned char *m_drawMap;
     1449    int            m_drawWidth;
     1450    int            m_position;
     1451
     1452    QColor         colorSet[5];
     1453};
     1454
     1455
    13881456class MPUBLIC UIKeyType : public UIType
    13891457{
    13901458    Q_OBJECT
  • mythtv/libs/libmyth/xmlparse.cpp

    diff -r -u -N -X diff.exclude -x release.20019.0219a -x release.20019.0219b release.20019.0219a/mythtv/libs/libmyth/xmlparse.cpp release.20019.0219b/mythtv/libs/libmyth/xmlparse.cpp
     
    14421442            {
    14431443                parseBlackHole(container, info);
    14441444            }
     1445            else if (info.tagName() == "grideditimage")
     1446            {
     1447                parseGridEditImage(container, info);
     1448            }
     1449            else if (info.tagName() == "grideditslider")
     1450            {
     1451                parseGridEditSlider(container, info);
     1452            }
    14451453            else if (info.tagName() == "area")
    14461454            {
    14471455                area = parseRect(getFirstText(info));
     
    34453453    container->AddType(bh);
    34463454}
    34473455
     3456void XMLParse::parseGridEditImage(LayerSet *container, QDomElement &element)
     3457{
     3458    QRect area;
     3459    QColor outlineColor;
     3460    QColor cutColor;
     3461    QColor cutPointColor;
     3462    bool   haveOutlineColor = false;
     3463    bool   haveCutColor = false;
     3464    bool   haveCutPointColor = false;
     3465
     3466    QString name = element.attribute("name", "");
     3467    if (name.isNull() || name.isEmpty())
     3468    {
     3469        cerr << "GridEditImage needs a name\n";
     3470        return;
     3471    }
     3472
     3473    for (QDomNode child = element.firstChild(); !child.isNull();
     3474         child = child.nextSibling())
     3475    {
     3476        QDomElement info = child.toElement();
     3477        if (!info.isNull())
     3478        {
     3479            if (info.tagName() == "area")
     3480            {
     3481                area = parseRect(getFirstText(info));
     3482                normalizeRect(area);
     3483            }
     3484            else if (info.tagName() == "outlinecolor")
     3485            {
     3486                haveOutlineColor = true;
     3487                outlineColor = getFirstText(info);
     3488            }
     3489            else if (info.tagName() == "cutcolor")
     3490            {
     3491                haveCutColor = true;
     3492                cutColor = getFirstText(info);
     3493            }
     3494            else if (info.tagName() == "cutpointcolor")
     3495            {
     3496                haveCutPointColor = true;
     3497                cutPointColor = getFirstText(info);
     3498            }
     3499            else
     3500            {
     3501                cerr << "Unknown: " << info.tagName() << " in Grid Edit Image\n";
     3502                return;
     3503            }
     3504        }
     3505    }
     3506
     3507    if (!haveOutlineColor)
     3508    {
     3509        cerr << "Missing outlinecolor in Grid Edit Image\n";
     3510        return;
     3511    }
     3512
     3513    if (!haveCutColor)
     3514    {
     3515        cerr << "Missing cutcolor in Grid Edit Image\n";
     3516        return;
     3517    }
     3518
     3519    if (!haveCutPointColor)
     3520    {
     3521        cerr << "Missing cutpointcolor in Grid Edit Image\n";
     3522        return;
     3523    }
     3524
     3525    UIGridEditImageType *gei = new UIGridEditImageType(name);
     3526    gei->SetScreen(wmult, hmult);
     3527    gei->setArea(area);
     3528    gei->setOutlineColor(outlineColor);
     3529    gei->setCutColor(cutColor);
     3530    gei->setCutPointColor(cutPointColor);
     3531    gei->SetParent(container);
     3532    gei->calculateScreenArea();
     3533    gei->clearPixmap(false);
     3534    container->AddType(gei);
     3535}
     3536
     3537void XMLParse::parseGridEditSlider(LayerSet *container, QDomElement &element)
     3538{
     3539    QRect area;
     3540    QColor fillColor;
     3541    QColor cutColor;
     3542    QColor inCutColor;
     3543    QColor cutPointColor;
     3544    QColor positionColor;
     3545    bool   haveFillColor = false;
     3546    bool   haveCutColor = false;
     3547    bool   haveInCutColor = false;
     3548    bool   haveCutPointColor = false;
     3549    bool   havePositionColor = false;
     3550
     3551    QString name = element.attribute("name", "");
     3552    if (name.isNull() || name.isEmpty())
     3553    {
     3554        cerr << "GridEditSlider needs a name\n";
     3555        return;
     3556    }
     3557
     3558    for (QDomNode child = element.firstChild(); !child.isNull();
     3559         child = child.nextSibling())
     3560    {
     3561        QDomElement info = child.toElement();
     3562        if (!info.isNull())
     3563        {
     3564            if (info.tagName() == "area")
     3565            {
     3566                area = parseRect(getFirstText(info));
     3567                normalizeRect(area);
     3568            }
     3569            else if (info.tagName() == "fillcolor")
     3570            {
     3571                haveFillColor = true;
     3572                fillColor = getFirstText(info);
     3573            }
     3574            else if (info.tagName() == "cutcolor")
     3575            {
     3576                haveCutColor = true;
     3577                cutColor = getFirstText(info);
     3578            }
     3579            else if (info.tagName() == "incutcolor")
     3580            {
     3581                haveInCutColor = true;
     3582                inCutColor = getFirstText(info);
     3583            }
     3584            else if (info.tagName() == "cutpointcolor")
     3585            {
     3586                haveCutPointColor = true;
     3587                cutPointColor = getFirstText(info);
     3588            }
     3589            else if (info.tagName() == "positioncolor")
     3590            {
     3591                havePositionColor = true;
     3592                positionColor = getFirstText(info);
     3593            }
     3594            else
     3595            {
     3596                cerr << "Unknown: " << info.tagName() << " in Grid Edit Slider\n";
     3597                return;
     3598            }
     3599        }
     3600    }
     3601
     3602    if (!haveFillColor)
     3603    {
     3604        cerr << "Missing fillcolor in Grid Edit Slider\n";
     3605        return;
     3606    }
     3607
     3608    if (!haveCutColor)
     3609    {
     3610        cerr << "Missing cutcolor in Grid Edit Slider\n";
     3611        return;
     3612    }
     3613
     3614    if (!haveInCutColor)
     3615    {
     3616        cerr << "Missing incutcolor in Grid Edit Slider\n";
     3617        return;
     3618    }
     3619
     3620    if (!haveCutPointColor)
     3621    {
     3622        cerr << "Missing cutpointcolor in Grid Edit Slider\n";
     3623        return;
     3624    }
     3625
     3626    if (!havePositionColor)
     3627    {
     3628        cerr << "Missing positioncolor in Grid Edit Slider\n";
     3629        return;
     3630    }
     3631
     3632    UIGridEditSliderType *ges = new UIGridEditSliderType(name);
     3633    ges->SetScreen(wmult, hmult);
     3634    ges->setArea(area);
     3635    ges->setFillColor(fillColor);
     3636    ges->setCutColor(cutColor);
     3637    ges->setInCutColor(inCutColor);
     3638    ges->setCutPointColor(cutPointColor);
     3639    ges->setPositionColor(positionColor);
     3640    ges->SetParent(container);
     3641    ges->calculateScreenArea();
     3642    container->AddType(ges);
     3643}
     3644
    34483645void XMLParse::parseListBtnArea(LayerSet *container, QDomElement &element)
    34493646{
    34503647    int context = -1;
  • mythtv/libs/libmyth/xmlparse.h

    diff -r -u -N -X diff.exclude -x release.20019.0219a -x release.20019.0219b release.20019.0219a/mythtv/libs/libmyth/xmlparse.h release.20019.0219b/mythtv/libs/libmyth/xmlparse.h
     
    4949    void parseCheckBox(LayerSet *, QDomElement &);
    5050    void parseSelector(LayerSet *, QDomElement &);
    5151    void parseBlackHole(LayerSet *, QDomElement &);
     52    void parseGridEditImage(LayerSet *, QDomElement &);
     53    void parseGridEditSlider(LayerSet *, QDomElement &);
    5254    void parseListBtnArea(LayerSet *, QDomElement &);
    5355    void parseListTreeArea(LayerSet *, QDomElement &);
    5456    void parseKeyboard(LayerSet *, QDomElement &);
  • mythtv/libs/libmythtv/NuppelVideoPlayer.cpp

    diff -r -u -N -X diff.exclude -x release.20019.0219a -x release.20019.0219b release.20019.0219a/mythtv/libs/libmythtv/NuppelVideoPlayer.cpp release.20019.0219b/mythtv/libs/libmythtv/NuppelVideoPlayer.cpp
     
    5353#include "interactivetv.h"
    5454#include "util-osx-cocoa.h"
    5555
     56#include "grideditcutpoints.h"
     57
    5658extern "C" {
    5759#include "vbitext/vbi.h"
    5860#include "vsync.h"
     
    157159      decoder_thread_alive(true),   killplayer(false),
    158160      killvideo(false),             livetv(false),
    159161      watchingrecording(false),     editmode(false),
     162      hideedits(false),
    160163      resetvideo(false),            using_null_videoout(false),
    161164      no_audio_in(false),           no_audio_out(false),
    162165      transcoding(false),
     
    166169      bookmarkseek(0),              previewFromBookmark(false),
    167170      // Seek
    168171      fftime(0),                    seekamountpos(4),
    169       seekamount(30),               exactseeks(false),
     172      allow_pagesize(false),        half_page(0),
     173      seekamount(30),               seekamounttext("30 Frames"),
     174      exactseeks(false),
    170175      // Playback misc.
    171176      videobuf_retries(0),          framesPlayed(0),
    172177      totalFrames(0),               totalLength(0),
     
    218223      yuv_need_copy(false),         yuv_desired_size(0,0),
    219224      yuv_scaler(NULL),             yuv_frame_scaled(NULL),
    220225      yuv_scaler_in_size(0,0),      yuv_scaler_out_size(0,0),
     226      // Grid Editing
     227      grid_edit_image_buffer(NULL), grid_edit_image_buffer_length(0),
    221228      // Filters
    222229      videoFiltersForProgram(""),   videoFiltersOverride(""),
    223230      postfilt_width(0),            postfilt_height(0),
     
    388395        output_jmeter = NULL;
    389396    }
    390397
     398    if (grid_edit_image_buffer)
     399    {
     400        delete [] grid_edit_image_buffer;
     401        grid_edit_image_buffer = NULL;
     402        grid_edit_image_buffer_length=0;
     403    }
     404
    391405    ShutdownYUVResize();
    392406}
    393407
     
    15261540    return retval;
    15271541}
    15281542
     1543
     1544QImage NuppelVideoPlayer::GetScreenGrabOfCurrentFrame(QSize size)
     1545{
     1546
     1547    unsigned char *data      = NULL;
     1548    VideoFrame    *frame     = NULL;
     1549    AVPicture      orig;
     1550    AVPicture      retbuf;
     1551    bzero(&orig,   sizeof(AVPicture));
     1552    bzero(&retbuf, sizeof(AVPicture));
     1553
     1554    QImage edit_scaled_img;
     1555    int vw, vh;
     1556    if (!(frame = GetCurrentFrame(vw, vh)))
     1557    {
     1558        return edit_scaled_img;
     1559    }
     1560
     1561    if (!(data = frame->buf))
     1562    {
     1563        ReleaseCurrentFrame(frame);
     1564        return edit_scaled_img;
     1565    }
     1566
     1567    avpicture_fill(&orig, data, PIX_FMT_YUV420P,
     1568                   video_dim.width(), video_dim.height());
     1569
     1570    avpicture_deinterlace(&orig, &orig, PIX_FMT_YUV420P,
     1571                          video_dim.width(), video_dim.height());
     1572
     1573    int bufflen = video_dim.width() * video_dim.height() * 4;
     1574    if (!grid_edit_image_buffer)
     1575    {
     1576        grid_edit_image_buffer = new unsigned char[bufflen];
     1577        grid_edit_image_buffer_length = bufflen;
     1578    }
     1579    else if (bufflen > grid_edit_image_buffer_length)
     1580    {
     1581        delete [] grid_edit_image_buffer;
     1582        grid_edit_image_buffer = new unsigned char[bufflen];
     1583        grid_edit_image_buffer_length = bufflen;
     1584    }
     1585
     1586    // Connect outputbuf to retbuf
     1587    avpicture_fill(&retbuf, grid_edit_image_buffer, PIX_FMT_RGBA32,
     1588                   video_dim.width(), video_dim.height());
     1589
     1590    // convert from orig into retbuf(grid_edit_image_buffer)
     1591    img_convert(&retbuf, PIX_FMT_RGBA32, &orig, PIX_FMT_YUV420P,
     1592                video_dim.width(), video_dim.height());
     1593
     1594    QImage tmpimage = QImage(grid_edit_image_buffer, video_dim.width(), video_dim.height(),
     1595                             32, NULL, 65536 * 65536, QImage::LittleEndian);
     1596
     1597    ReleaseCurrentFrame(frame);
     1598
     1599    edit_scaled_img =  tmpimage.scale(size, QImage::ScaleMin).swapRGB();
     1600   
     1601    return edit_scaled_img;
     1602}
     1603
    15291604void NuppelVideoPlayer::ReleaseCurrentFrame(VideoFrame *frame)
    15301605{
    15311606    if (frame)
     
    49895064
    49905065    dialogname = "";
    49915066
     5067    osd->HideAllExcept("editmode");
     5068
    49925069    QMap<QString, QString> infoMap;
    49935070    m_playbackinfo->ToMap(infoMap);
    49945071    osd->SetText("editmode", infoMap, -1);
     
    50445121    m_playbackinfo->SetEditing(false);
    50455122}
    50465123
     5124bool NuppelVideoPlayer::EditSeekToFrame(long long targetFrame)
     5125{
     5126    bool tmpexactseeks = exactseeks;
     5127    GetDecoder()->setExactSeeks(true);
     5128
     5129//    VERBOSE(VB_GENERAL, QString("Before current frame = %1, going to frame %2")
     5130//           .arg(GetFramesPlayed())
     5131//           .arg(targetFrame));
     5132
     5133    if (framesPlayed > targetFrame)
     5134    {
     5135        // seek back
     5136        rewindtime = framesPlayed - targetFrame;
     5137        while (rewindtime != 0)
     5138            usleep(1000);
     5139    }
     5140    else
     5141    {
     5142        // seek forward
     5143        fftime = targetFrame - framesPlayed;
     5144        while (fftime != 0)
     5145            usleep(1000);
     5146
     5147    }
     5148//    VERBOSE(VB_GENERAL, QString("After current frame = %1")
     5149//           .arg(GetFramesPlayed()));
     5150    GetDecoder()->setExactSeeks(tmpexactseeks);
     5151    return (targetFrame == framesPlayed);
     5152}
     5153
     5154void NuppelVideoPlayer::EditHandleClearMap()
     5155{
     5156    QMap<long long, int>::Iterator it;
     5157    for (it = deleteMap.begin(); it != deleteMap.end(); ++it)
     5158        osd->HideEditArrow(it.key(), it.data());
     5159
     5160    deleteMap.clear();
     5161    UpdateEditSlider();
     5162}
     5163
     5164void NuppelVideoPlayer::EditHandleInvertMap()
     5165{
     5166    QMap<long long, int>::Iterator it;
     5167    for (it = deleteMap.begin(); it != deleteMap.end(); ++it)
     5168        ReverseMark(it.key());
     5169
     5170    UpdateEditSlider();
     5171    UpdateTimeDisplay();
     5172}
     5173
     5174void NuppelVideoPlayer::EditHandleLoadCommSkip()
     5175{
     5176    if (hascommbreaktable)
     5177    {
     5178        commBreakMapLock.lock();
     5179        QMap<long long, int>::Iterator it;
     5180        for (it = commBreakMap.begin(); it != commBreakMap.end(); ++it)
     5181        {
     5182            if (!deleteMap.contains(it.key()))
     5183            {
     5184                if (it.data() == MARK_COMM_START)
     5185                    AddMark(it.key(), MARK_CUT_START);
     5186                else
     5187                    AddMark(it.key(), MARK_CUT_END);
     5188            }
     5189        }
     5190        commBreakMapLock.unlock();
     5191        UpdateEditSlider();
     5192        UpdateTimeDisplay();
     5193    }
     5194}
     5195
    50475196bool NuppelVideoPlayer::DoKeypress(QKeyEvent *e)
    50485197{
    50495198    bool handled = false;
     
    51235272            UpdateTimeDisplay();
    51245273        }
    51255274        else if (action == "CLEARMAP")
    5126         {
    5127             QMap<long long, int>::Iterator it;
    5128             for (it = deleteMap.begin(); it != deleteMap.end(); ++it)
    5129                 osd->HideEditArrow(it.key(), it.data());
    5130 
    5131             deleteMap.clear();
    5132             UpdateEditSlider();
    5133         }
     5275            EditHandleClearMap();
    51345276        else if (action == "INVERTMAP")
    5135         {
    5136             QMap<long long, int>::Iterator it;
    5137             for (it = deleteMap.begin(); it != deleteMap.end(); ++it)
    5138                 ReverseMark(it.key());
    5139 
    5140             UpdateEditSlider();
    5141             UpdateTimeDisplay();
    5142         }
     5277            EditHandleInvertMap();
    51435278        else if (action == "LOADCOMMSKIP")
    5144         {
    5145             if (hascommbreaktable)
    5146             {
    5147                 commBreakMapLock.lock();
    5148                 QMap<long long, int>::Iterator it;
    5149                 for (it = commBreakMap.begin(); it != commBreakMap.end(); ++it)
    5150                 {
    5151                     if (!deleteMap.contains(it.key()))
    5152                     {
    5153                         if (it.data() == MARK_COMM_START)
    5154                             AddMark(it.key(), MARK_CUT_START);
    5155                         else
    5156                             AddMark(it.key(), MARK_CUT_END);
    5157                     }
    5158                 }
    5159                 commBreakMapLock.unlock();
    5160                 UpdateEditSlider();
    5161                 UpdateTimeDisplay();
    5162             }
    5163         }
     5279            EditHandleLoadCommSkip();
    51645280        else if (action == "PREVCUT")
    51655281        {
    51665282            int old_seekamount = seekamount;
     
    52065322            UpdateEditSlider();
    52075323            UpdateTimeDisplay();
    52085324        }
    5209         else if (action == "ESCAPE" || action == "MENU" ||
    5210                  action == "TOGGLEEDIT")
     5325        else if (action == "TOGGLEEDIT" || action == "MENU")
     5326              m_tv->ShowEditRecordingGrid();
     5327        else if (action == "ESCAPE")
    52115328        {
    52125329            DisableEdit();
    52135330            retval = false;
     
    52205337    return retval;
    52215338}
    52225339
     5340void NuppelVideoPlayer::ShowEditRecordingGrid(void)
     5341{
     5342    // Completely hide the OSD
     5343    osd->HideAll();
     5344    hideedits = true;
     5345
     5346    GridEditCutpoints::Run(this);
     5347
     5348    if (grid_edit_image_buffer)
     5349    {
     5350        delete [] grid_edit_image_buffer;
     5351        grid_edit_image_buffer = NULL;
     5352        grid_edit_image_buffer_length = 0;
     5353    }
     5354
     5355    allow_pagesize = false;
     5356    hideedits = false;
     5357
     5358    // Show OSD
     5359
     5360    QMap<QString, QString> infoMap;
     5361    m_playbackinfo->ToMap(infoMap);
     5362    osd->SetText("editmode", infoMap, -1);
     5363
     5364    UpdateEditSlider();
     5365    UpdateTimeDisplay();
     5366    if (seekamountpos == 3 || seekamountpos == 4)
     5367        UpdateSeekAmount(true);
     5368    else
     5369        UpdateSeekAmountDisplay();
     5370
     5371    QMap<long long, int>::Iterator it;
     5372    for (it = deleteMap.begin(); it != deleteMap.end(); ++it)
     5373         AddMark(it.key(), it.data());
     5374}
     5375
    52235376AspectOverrideMode NuppelVideoPlayer::GetAspectOverride(void) const
    52245377{
    52255378    if (videoOutput)
     
    53115464
    53125465void NuppelVideoPlayer::UpdateSeekAmount(bool up)
    53135466{
    5314     if (seekamountpos > 0 && !up)
    5315         seekamountpos--;
    5316     if (seekamountpos < 9 && up)
    5317         seekamountpos++;
     5467    if (up)
     5468    {
     5469        if (seekamountpos < 11)
     5470            seekamountpos++;
     5471        if (allow_pagesize)
     5472        {
     5473            if (seekamountpos == 1)
     5474                seekamountpos = 2;
     5475        }
     5476        else
     5477        {
     5478            if (seekamountpos == 3 || seekamountpos == 4)
     5479                seekamountpos = 5;
     5480        }
     5481    }
     5482    else
     5483    {
     5484        if (seekamountpos > 0)
     5485            seekamountpos--;
     5486        if (allow_pagesize)
     5487        {
     5488            if (seekamountpos == 1)
     5489                seekamountpos =0;
     5490        }
     5491        else
     5492        {
     5493            if (seekamountpos == 3 || seekamountpos == 4)
     5494                seekamountpos = 2;
     5495        }
     5496    }
    53185497
    5319     QString text = "";
     5498    QString text;
    53205499
    53215500    switch (seekamountpos)
    53225501    {
    5323         case 0: text = QObject::tr("cut point"); seekamount = -2; break;
    5324         case 1: text = QObject::tr("keyframe"); seekamount = -1; break;
    5325         case 2: text = QObject::tr("1 frame"); seekamount = 1; break;
    5326         case 3: text = QObject::tr("0.5 seconds"); seekamount = (int)roundf(video_frame_rate / 2); break;
    5327         case 4: text = QObject::tr("1 second"); seekamount = (int)roundf(video_frame_rate); break;
    5328         case 5: text = QObject::tr("5 seconds"); seekamount = (int)roundf(video_frame_rate * 5); break;
    5329         case 6: text = QObject::tr("20 seconds"); seekamount = (int)roundf(video_frame_rate * 20); break;
    5330         case 7: text = QObject::tr("1 minute"); seekamount = (int)roundf(video_frame_rate * 60); break;
    5331         case 8: text = QObject::tr("5 minutes"); seekamount = (int)roundf(video_frame_rate * 300); break;
    5332         case 9: text = QObject::tr("10 minutes"); seekamount = (int)roundf(video_frame_rate * 600); break;
    5333         default: text = QObject::tr("error"); seekamount = (int)roundf(video_frame_rate); break;
     5502        case  0: text = QObject::tr("cut point");   seekamount = -2; break;
     5503
     5504        // Only for non-edit grid
     5505        case  1: text = QObject::tr("keyframe");    seekamount = -1; break;
     5506        // Only for non-edit grid
     5507
     5508        case  2: text = QObject::tr("1 frame");     seekamount =  1; break;
     5509
     5510        // Case 3 & 4 are for the edit grid only
     5511        case  3: text = QObject::tr("1/2 Page");    seekamount =  half_page; break;
     5512        case  4: text = QObject::tr("Full Page");   seekamount =  2*half_page; break;
     5513        // Case 3 & 4 are for the edit grid only
     5514
     5515        case  5: text = QObject::tr("0.5 seconds"); seekamount = (int)roundf(video_frame_rate / 2); break;
     5516        case  6: text = QObject::tr("1 second");    seekamount = (int)roundf(video_frame_rate); break;
     5517        case  7: text = QObject::tr("5 seconds");   seekamount = (int)roundf(video_frame_rate * 5); break;
     5518        case  8: text = QObject::tr("20 seconds");  seekamount = (int)roundf(video_frame_rate * 20); break;
     5519        case  9: text = QObject::tr("1 minute");    seekamount = (int)roundf(video_frame_rate * 60); break;
     5520        case 10: text = QObject::tr("5 minutes");   seekamount = (int)roundf(video_frame_rate * 300); break;
     5521        case 11: text = QObject::tr("10 minutes");  seekamount = (int)roundf(video_frame_rate * 600); break;
     5522        default: text = QObject::tr("error");       seekamount = (int)roundf(video_frame_rate); break;
    53345523    }
    53355524
     5525    seekamounttext = text;
     5526    UpdateSeekAmountDisplay();
     5527}
     5528
     5529void NuppelVideoPlayer::UpdateSeekAmountDisplay(void)
     5530{
    53365531    QMap<QString, QString> infoMap;
    5337     infoMap["seekamount"] = text;
    5338     osd->SetText("editmode", infoMap, -1);
     5532    infoMap["seekamount"] = seekamounttext;
     5533    if (!hideedits)
     5534        osd->SetText("editmode", infoMap, -1);
    53395535}
    53405536
    53415537void NuppelVideoPlayer::UpdateTimeDisplay(void)
     
    53655561    infoMap["timedisplay"] = timestr;
    53665562    infoMap["framedisplay"] = framestr;
    53675563    infoMap["cutindicator"] = cutmarker;
    5368     osd->SetText("editmode", infoMap, -1);
     5564    if (!hideedits)
     5565        osd->SetText("editmode", infoMap, -1);
    53695566}
    53705567
    53715568void NuppelVideoPlayer::HandleSelect(bool allowSelectNear)
     
    54975694
    54985695void NuppelVideoPlayer::UpdateEditSlider(void)
    54995696{
    5500     osd->DoEditSlider(deleteMap, framesPlayed, totalFrames);
     5697    if (!hideedits)
     5698        osd->DoEditSlider(deleteMap, framesPlayed, totalFrames);
    55015699}
    55025700
    55035701void NuppelVideoPlayer::AddMark(long long frames, int type)
    55045702{
    55055703    deleteMap[frames] = type;
    5506     osd->ShowEditArrow(frames, totalFrames, type);
     5704    if (!hideedits)
     5705        osd->ShowEditArrow(frames, totalFrames, type);
    55075706}
    55085707
    55095708void NuppelVideoPlayer::DeleteMark(long long frames)
    55105709{
    5511     osd->HideEditArrow(frames, deleteMap[frames]);
     5710    if (!hideedits)
     5711        osd->HideEditArrow(frames, deleteMap[frames]);
    55125712    deleteMap.remove(frames);
    55135713}
    55145714
    55155715void NuppelVideoPlayer::ReverseMark(long long frames)
    55165716{
    5517     osd->HideEditArrow(frames, deleteMap[frames]);
     5717    if (!hideedits)
     5718        osd->HideEditArrow(frames, deleteMap[frames]);
    55185719
    55195720    if (deleteMap[frames] == MARK_CUT_END)
    55205721        deleteMap[frames] = MARK_CUT_START;
    55215722    else
    55225723        deleteMap[frames] = MARK_CUT_END;
    55235724
    5524     osd->ShowEditArrow(frames, totalFrames, deleteMap[frames]);
     5725    if (!hideedits)
     5726        osd->ShowEditArrow(frames, totalFrames, deleteMap[frames]);
     5727}
     5728
     5729long long NuppelVideoPlayer::CalcCutPointSeek(long long baseframe, bool right)
     5730{
     5731    QMap<long long, int>::Iterator i = deleteMap.begin();                                     
     5732    long long framenum = -1;
     5733    long long seekcount = 0;
     5734    if (right)                                                                                 
     5735    {
     5736        for (; i != deleteMap.end(); ++i)                                                     
     5737        {
     5738            if (i.key() > baseframe)                                                       
     5739            {
     5740                framenum = i.key();                                                           
     5741                break;                                                                         
     5742            }                                                                                 
     5743        }                                                                                     
     5744        if (framenum == -1)
     5745            framenum = totalFrames;
     5746        seekcount = framenum - baseframe;
     5747    }
     5748    else
     5749    {
     5750        for (; i != deleteMap.end(); ++i)
     5751        {
     5752            if (i.key() >= baseframe)
     5753                break;
     5754            framenum = i.key();
     5755        }
     5756        if (framenum == -1)
     5757            framenum = 0;
     5758        seekcount = baseframe - framenum;
     5759    }
     5760    return seekcount;
    55255761}
    55265762
    55275763void NuppelVideoPlayer::HandleArbSeek(bool right)
    55285764{
    55295765    if (seekamount == -2)
    55305766    {
    5531         QMap<long long, int>::Iterator i = deleteMap.begin();
    5532         long long framenum = -1;
     5767        long long seekcount = CalcCutPointSeek(framesPlayed, right);
    55335768        if (right)
    55345769        {
    5535             for (; i != deleteMap.end(); ++i)
    5536             {
    5537                 if (i.key() > framesPlayed)
    5538                 {
    5539                     framenum = i.key();
    5540                     break;
    5541                 }
    5542             }
    5543             if (framenum == -1)
    5544                 framenum = totalFrames;
    5545 
    5546             fftime = framenum - framesPlayed;
     5770            fftime = seekcount;
    55475771            while (fftime > 0)
    55485772                usleep(1000);
    55495773        }
    55505774        else
    55515775        {
    5552             for (; i != deleteMap.end(); ++i)
    5553             {
    5554                 if (i.key() >= framesPlayed)
    5555                     break;
    5556                 framenum = i.key();
    5557             }
    5558             if (framenum == -1)
    5559                 framenum = 0;
    5560 
    5561             rewindtime = framesPlayed - framenum;
     5776            rewindtime = seekcount;
    55625777            while (rewindtime > 0)
    55635778                usleep(1000);
    55645779        }
     
    55895804    UpdateEditSlider();
    55905805}
    55915806
     5807int NuppelVideoPlayer::GetCutStatus(long long testframe) const
     5808{
     5809    int retval = 0;
     5810    QMap<long long, int>::const_iterator i;
     5811    i = deleteMap.find(testframe);
     5812    if (i == deleteMap.end()) {
     5813        // testframe is not an explicit cutpoint
     5814        // See if it is in a deleted area
     5815        if (IsInDelete(testframe))
     5816            retval = 1;
     5817    } else {
     5818        int direction = i.data();
     5819        if (direction == 0)
     5820            retval = 2;
     5821        else
     5822            retval = 3;
     5823    }
     5824
     5825    return retval;
     5826}
     5827
    55925828bool NuppelVideoPlayer::IsInDelete(long long testframe) const
    55935829{
    55945830    long long startpos = 0;
  • mythtv/libs/libmythtv/NuppelVideoPlayer.h

    diff -r -u -N -X diff.exclude -x release.20019.0219a -x release.20019.0219b release.20019.0219a/mythtv/libs/libmythtv/NuppelVideoPlayer.h release.20019.0219b/mythtv/libs/libmythtv/NuppelVideoPlayer.h
     
    102102
    103103class MPUBLIC NuppelVideoPlayer : public CC608Reader, public CC708Reader
    104104{
     105 friend class GridEditCutpoints;
     106 friend class TV;
    105107 public:
    106108    NuppelVideoPlayer(QString inUseID = "Unknown",
    107109                      const ProgramInfo *info = NULL);
     
    270272    bool EnableEdit(void);
    271273    bool DoKeypress(QKeyEvent *e);
    272274    bool GetEditMode(void) const { return editmode; }
     275    bool GetHideEdits(void) const { return hideedits; }
    273276
    274277    // Decoder stuff..
    275278    VideoFrame *GetNextVideoFrame(bool allow_unsafe = true);
     
    289292    void ShutdownYUVResize(void);
    290293    void SaveScreenshot(void);
    291294
     295    // Edit stuff
     296    bool EditSeekToFrame(long long targetFrame);
     297    QImage GetScreenGrabOfCurrentFrame(QSize size); // Get current frame
     298
     299    void       EditHandleClearMap();
     300    void       EditHandleInvertMap();
     301    void       EditHandleLoadCommSkip();
     302
     303    void ShowEditRecordingGrid();
     304
    292305    // Reinit
    293306    void    ReinitOSD(void);
    294307    void    ReinitVideo(void);
     
    406419        hidedvdbutton = hide;
    407420    }
    408421
     422    // Stuf for GridEditCutpoints
     423    long long CalcCutPointSeek(long long baseframe, bool right);
     424    // returns
     425    // 0 - no cut
     426    // 1 - is deleted
     427    // 2 - cut left
     428    // 3 - cut right
     429    int  GetCutStatus(long long testframe) const;
     430    long long GetSeekAmount() { return seekamount; }
     431    QString GetSeekAmountText() { return seekamounttext; }
     432
    409433  protected:
    410434    void DisplayPauseFrame(void);
    411435    void DisplayNormalFrame(void);
     
    488512    void HandleResponse(void);
    489513
    490514    void UpdateTimeDisplay(void);
     515    int  GetSeekAmountPos() { return seekamountpos; }
    491516    void UpdateSeekAmount(bool up);
     517    void SetHalfPageSize(int hp) { allow_pagesize = true; half_page = hp; }
     518    void UpdateSeekAmountDisplay(void);
    492519    void UpdateEditSlider(void);
    493520
    494521    // Private A/V Sync Stuff
     
    560587    bool     livetv;
    561588    bool     watchingrecording;
    562589    bool     editmode;
     590    bool     hideedits;
    563591    bool     resetvideo;
    564592    bool     using_null_videoout;
    565593    bool     no_audio_in;
     
    579607    long long fftime;
    580608    /// 1..9 == keyframe..10 minutes. 0 == cut point
    581609    int       seekamountpos;
     610    ///  Used for Grid Edit logic
     611    bool      allow_pagesize;
     612    int       half_page;
    582613    /// Seekable frame increment when not using exact seeks.
    583614    /// Usually equal to keyframedist.
    584615    int      seekamount;
     616    QString  seekamounttext; // OSD seek units
    585617    /// Iff true we ignore seek amount and try to seek to an
    586618    /// exact frame ignoring key frame restrictions.
    587619    bool     exactseeks;
     
    714746    QMutex              yuv_lock;
    715747    QWaitCondition      yuv_wait;
    716748
     749    // EditGrid still image capture
     750    unsigned char *grid_edit_image_buffer;
     751    int grid_edit_image_buffer_length;
     752
    717753    // Filters
    718754    QMutex   videofiltersLock;
    719755    QString  videoFiltersForProgram;
  • mythtv/libs/libmythtv/grideditcutpoints.cpp

    diff -r -u -N -X diff.exclude -x release.20019.0219a -x release.20019.0219b release.20019.0219a/mythtv/libs/libmythtv/grideditcutpoints.cpp release.20019.0219b/mythtv/libs/libmythtv/grideditcutpoints.cpp
     
     1#include <qapplication.h>
     2#include <qpainter.h>
     3#include <qfont.h>
     4#include <qsqldatabase.h>
     5#include <qsqlquery.h>
     6#include <math.h>
     7#include <qcursor.h>
     8#include <qapplication.h>
     9#include <qimage.h>
     10#include <qlayout.h>
     11#include <qlabel.h>
     12#include <qdatetime.h>
     13#include <qvgroupbox.h>
     14#include <qheader.h>
     15#include <qrect.h>
     16
     17#include <unistd.h>
     18#include <iostream>
     19#include <algorithm>
     20using namespace std;
     21
     22#include "mythcontext.h"
     23#include "mythdbcon.h"
     24#include "grideditcutpoints.h"
     25#include "grideditimages.h"
     26#include "NuppelVideoPlayer.h"
     27
     28void GridEditCutpoints::Run(NuppelVideoPlayer *player)
     29{
     30    VERBOSE(VB_GENERAL, "Starting");
     31    gContext->addCurrentLocation("GridEditCutpoints");
     32
     33    GridEditCutpoints *er = new GridEditCutpoints(gContext->GetMainWindow(),
     34                                  player, "editrecording");
     35
     36    er->Show();
     37    er->displayInitialFrame();
     38    er->exec();
     39
     40    delete er;
     41
     42    gContext->removeCurrentLocation();
     43    VERBOSE(VB_GENERAL, "Ending");
     44}
     45
     46GridEditCutpoints::GridEditCutpoints(MythMainWindow *parent,
     47                     NuppelVideoPlayer *player, const char *name)
     48         : MythThemedDialog(parent, "edit", "", name)
     49{
     50    m_player = player;
     51    images = new GridEditImages(this, player);
     52
     53    int i;
     54    for (i = m_gridimages.minIndex(); i < m_gridimages.maxIndex(); i++)
     55    {
     56        m_gridimages[i] = NULL;
     57    }
     58
     59    usedSubVideoCount=0;
     60
     61    QSize videoSizeMain, videoSizeSmall;
     62
     63    m_gridimages[0] = getUIGridEditImageType("mainvideo");
     64    if (m_gridimages[0])
     65        videoSizeMain = m_gridimages[0]->getScreenArea().size();
     66    else
     67        VERBOSE(VB_IMPORTANT, "FATAL: Couldn't find mainedit:mainvideo");
     68
     69    for (i = 1; i < m_gridimages.maxIndex(); i++)
     70    {
     71        QString p = QString("videop%1").arg(i);
     72        QString m = QString("videom%1").arg(i);
     73
     74        // Minus frame i
     75        m_gridimages[-i] = getUIGridEditImageType(m);
     76        if (m_gridimages[-i])
     77        {
     78            QSize tmpVideoSizeSmall = m_gridimages[-i]->getScreenArea().size();
     79            if (videoSizeSmall.isValid() && videoSizeSmall != tmpVideoSizeSmall)
     80                VERBOSE(VB_IMPORTANT,
     81                        QString("Multiple sizes found for edit videos (%1)").arg(m));
     82            else
     83                videoSizeSmall = tmpVideoSizeSmall;
     84            if (i > usedSubVideoCount) usedSubVideoCount=i;
     85        }
     86
     87        m_gridimages[i] = getUIGridEditImageType(p);
     88        if (m_gridimages[i])
     89        {
     90            QSize tmpVideoSizeSmall = m_gridimages[i]->getScreenArea().size();
     91            if (videoSizeSmall.isValid() && videoSizeSmall != tmpVideoSizeSmall)
     92                VERBOSE(VB_IMPORTANT,
     93                        QString("Multiple sizes found for edit videos (%1)").arg(p));
     94            else
     95                videoSizeSmall = tmpVideoSizeSmall;
     96            if (i > usedSubVideoCount) usedSubVideoCount=i;
     97        }
     98    }
     99    images->SetVideoInfo(usedSubVideoCount, videoSizeMain, videoSizeSmall);
     100
     101    m_player->SetHalfPageSize(usedSubVideoCount);
     102    m_slider = getUIGridEditSliderType("positionbar");
     103    if (!m_slider)
     104        VERBOSE(VB_GENERAL, "Missing positionbar for GridEditCutpoints");
     105
     106    // Get Status boxes
     107    {
     108        m_framenum    = getUITextType("framenum");
     109        m_time        = getUITextType("time");
     110        m_cutind      = getUITextType("cutind");
     111        m_jumpstyle   = getUITextType("jumpstyle");
     112        m_updatingind = getUITextType("updatingind");
     113    }
     114
     115    VERBOSE(VB_GENERAL, QString("main = (%1, %2) small = (%3, %4)")
     116                       .arg(videoSizeMain.width()).arg(videoSizeMain.height())
     117                       .arg(videoSizeSmall.width()).arg(videoSizeSmall.height()));
     118
     119    slowMotionDirection = 1; // start off play forward
     120    slowMotionActive = false;
     121    readyForNextFrame = false;
     122    slowMotionTimer = new QTimer(this);
     123    QObject::connect(slowMotionTimer, SIGNAL(timeout()),
     124                     this,           SLOT(updateSlowMotion()));
     125
     126    movingCutpoint = false;
     127    // Create blank pixmaps...
     128 
     129    updateBackground();
     130
     131    updateStats();
     132
     133    setNoErase();
     134    gContext->addListener(this);
     135   
     136    updateForeground();
     137}
     138
     139GridEditCutpoints::~GridEditCutpoints()
     140{
     141    if (images)
     142    {
     143        delete images;
     144        images = NULL;
     145    }
     146    gContext->removeListener(this);
     147}
     148
     149void GridEditCutpoints::displayInitialFrame()
     150{
     151    images->getMainStillFrame();
     152    refreshImages(true);
     153    refreshCutList();
     154    updateStats();
     155    SetUpdating(false);
     156    images->getImagesTimer->start(0);
     157}
     158
     159void GridEditCutpoints::updateSlowMotion()
     160{
     161    if (!slowMotionActive)
     162        slowMotionTimer->stop();
     163    else if (readyForNextFrame && slowMotionDirection != 0)
     164    {
     165        readyForNextFrame=false;
     166
     167        if (slowMotionDirection > 0)
     168            images->EditHandleRight();
     169        else if (slowMotionDirection < 0)
     170            images->EditHandleLeft();
     171    }
     172}
     173
     174
     175void GridEditCutpoints::setSlowMotionSpeed()
     176{
     177    // slowMotionDirection is max FPS
     178
     179    if (slowMotionDirection != 0)
     180    {
     181        int smd = slowMotionDirection;
     182        if (smd < 0) smd = -smd;
     183        int timeout = 1000 / smd;
     184
     185        slowMotionTimer->start(timeout);
     186    }
     187    SetUpdating(true, QString("%1 FPS max").arg(slowMotionDirection));
     188}
     189
     190
     191void GridEditCutpoints::keyPressEvent(QKeyEvent *e)
     192{
     193    // keyDown limits keyrepeats to prevent continued scrolling
     194    // after key is released. Note: Qt's keycompress should handle
     195    // this but will fail with fast key strokes and keyboard repeat
     196    // enabled. Keys will not be marked as autorepeat and flood buffer.
     197    // setFocusPolicy(QWidget::ClickFocus) in constructor is important
     198    // or keyRelease events will not be received after a refocus.
     199   
     200    bool handled = false;
     201
     202    QStringList actions;
     203    gContext->GetMainWindow()->TranslateKeyPress("TV Editing", e, actions);
     204
     205    {
     206        for (unsigned int i = 0; i < actions.size() && !handled; i++)
     207        {
     208            QString action = actions[i];
     209            handled = true;
     210
     211            if (action == "SELECT")
     212            {
     213                if (slowMotionActive)
     214                {
     215                    slowMotionActive = false;
     216                    slowMotionTimer->stop();
     217                }
     218                else if (movingCutpoint)
     219                {
     220                    // Move cutpoint
     221                    m_player->DeleteMark(savedCutpoint);
     222                    m_player->AddMark(images->stillMainFrameNumber, savedCutType);
     223                    movingCutpoint = false;
     224                    refreshCutList();
     225                    refreshImages();
     226                }
     227                else
     228                    handleSelect();
     229            }
     230            else if (action == "PAUSE")
     231            {
     232                if (movingCutpoint)
     233                    MythPopupBox::showOkPopup(gContext->GetMainWindow(),
     234                                              "Moving Cutpoint",
     235                                              "Slow Motion Unavailable when moving cutpoint");
     236                else if (slowMotionActive)
     237                {
     238                    slowMotionActive = false;
     239                    slowMotionTimer->stop();
     240                }
     241            }
     242            else if (action == "SLOWMO")
     243            {
     244                if (movingCutpoint)
     245                    MythPopupBox::showOkPopup(gContext->GetMainWindow(),
     246                                              "Moving Cutpoint",
     247                                              "Slow Motion Unavailable when moving cutpoint");
     248                else
     249                {
     250                    if (slowMotionActive)
     251                    {
     252                        slowMotionActive = false;
     253                        slowMotionTimer->stop();
     254                    }
     255                    else
     256                    {
     257                        slowMotionActive = true;
     258                        readyForNextFrame = true;
     259                        slowMotionDirection = 1;
     260
     261                        // force to either 1 frame. 1/2 page or full page motion
     262                        int i;
     263                        // move to 1 frame if on cutpoint
     264                        for (i = 0; m_player->GetSeekAmountPos() < 2 && i < 10; i++)
     265                            m_player->UpdateSeekAmount(false);
     266
     267                        // move to fullpage if higher
     268                        for (i = 0; m_player->GetSeekAmountPos() > 4 && i < 10; i++)
     269                            m_player->UpdateSeekAmount(true);
     270
     271                        setSlowMotionSpeed();
     272                    }
     273                }
     274            }
     275            else if (action == "LEFT")
     276            {
     277                if (slowMotionActive)
     278                {
     279                    slowMotionDirection--;
     280                    setSlowMotionSpeed();
     281                }
     282                else
     283                {
     284                    SetUpdating(true);
     285
     286                    images->EditHandleLeft();
     287                    refreshImages(false);
     288                }
     289            }
     290            else if (action == "RIGHT" )
     291            {
     292                if (slowMotionActive)
     293                {
     294                    slowMotionDirection++;
     295                    setSlowMotionSpeed();
     296                }
     297                else
     298                {
     299                    SetUpdating(true);
     300
     301                    images->EditHandleRight();
     302                    refreshImages(false);
     303                }
     304            }
     305            else if (action == "UP")
     306                m_player->UpdateSeekAmount(true);
     307            else if (action == "DOWN")
     308            {
     309                if ((movingCutpoint || slowMotionActive) && m_player->GetSeekAmountPos() == 2)
     310                    MythPopupBox::showOkPopup(gContext->GetMainWindow(),
     311                                              "Moving Cutpoint",
     312                                              "CutPoint skip Unavailable");
     313                else
     314                    m_player->UpdateSeekAmount(false);
     315            }
     316            else if (action == "CLEARMAP")
     317            {
     318                if (movingCutpoint || slowMotionActive)
     319                    MythPopupBox::showOkPopup(gContext->GetMainWindow(),
     320                                              "Moving Cutpoint",
     321                                              "Clear Cut Map Unavailable");
     322                else
     323                {
     324                    SetUpdating(true);
     325                    m_player->EditHandleClearMap();
     326                    refreshCutList();
     327                }
     328            }
     329            else if (action == "INVERTMAP")
     330            {
     331                if (movingCutpoint || slowMotionActive)
     332                    MythPopupBox::showOkPopup(gContext->GetMainWindow(),
     333                                              "Moving Cutpoint",
     334                                              "Invert Cut Map Unavailable");
     335                else
     336                {
     337                    SetUpdating(true);
     338                    m_player->EditHandleInvertMap();
     339                    refreshCutList();
     340                }
     341            }
     342            else if (action == "LOADCOMMSKIP")
     343            {
     344                if (movingCutpoint || slowMotionActive)
     345                    MythPopupBox::showOkPopup(gContext->GetMainWindow(),
     346                                              "Moving Cutpoint",
     347                                              "Load Comm Skip Map Unavailable");
     348                else
     349                {
     350                    SetUpdating(true);
     351                    m_player->EditHandleLoadCommSkip();
     352                    refreshCutList();
     353                }
     354            }
     355            else if (action == "PREVCUT")
     356            {
     357                if (movingCutpoint || slowMotionActive)
     358                    MythPopupBox::showOkPopup(gContext->GetMainWindow(),
     359                                              "Moving Cutpoint",
     360                                              "Prev Cut Unavailable");
     361                else
     362                {
     363                    SetUpdating(true);
     364                    images->EditHandlePrevCut();
     365                    refreshImages(false);
     366                }
     367            }
     368            else if (action == "NEXTCUT")
     369            {
     370                if (movingCutpoint || slowMotionActive)
     371                    MythPopupBox::showOkPopup(gContext->GetMainWindow(),
     372                                              "Moving Cutpoint",
     373                                              "Next Cut Unavailable");
     374                else
     375                {
     376                    SetUpdating(true);
     377                    images->EditHandleNextCut();
     378                    refreshImages(false);
     379                }
     380            }
     381            else if (action == "BIGJUMPREW")
     382            {
     383                SetUpdating(true);
     384                images->EditHandleBigJumpRew();
     385                refreshImages(false);
     386            }
     387            else if (action == "BIGJUMPFWD")
     388            {
     389                SetUpdating(true);
     390                images->EditHandleBigJumpFwd();
     391                refreshImages(false);
     392            }
     393            else if (action == "ESCAPE" && movingCutpoint)
     394                movingCutpoint = false;
     395            else if (action == "ESCAPE" || action == "TOGGLEEDIT" ||
     396                     action == "MENU")
     397                escape();
     398            else
     399                handled = false;
     400
     401            if (handled)
     402                updateStats();
     403            if (movingCutpoint)
     404                SetUpdating(true, "Moving Cutpoint");
     405            else if (!slowMotionActive)
     406                SetUpdating(false);
     407        }
     408    }
     409
     410    if (!handled)
     411        MythDialog::keyPressEvent(e);
     412}
     413
     414void GridEditCutpoints::handleSelect(void)
     415{
     416    bool needupdate = false;
     417    // add / update cutpoint
     418    // -or-
     419    // delete / flip / move cutpoint
     420
     421    // if no cut points on screen
     422    //    "Delete Before"
     423    //    "Delete After"
     424
     425    // if on existing cutpoint
     426    //    "Delete cutpoint"
     427    //    "Flip directions"
     428
     429    // FIXME
     430    // if a cutpoint exists on the screen but not on the current frame
     431    //    "Move to current frame"
     432    //    "Add new"
     433
     434    MythPopupBox *pub = new MythPopupBox(gContext->GetMainWindow(), "EDIT_SELECT");
     435    if (images->cutFrames[0] >= 2)
     436    {
     437        pub->addLabel("Cutpoint exists:");
     438        pub->addButton("Delete cutpoint?");
     439        pub->addButton("Move cutpoint?");
     440        if (images->cutFrames[0] == 2)
     441            pub->addButton("Flip directions (Cut After)?");
     442        else
     443            pub->addButton("Flip directions (Cut Before)?");
     444        DialogCode dc = pub->ExecPopup();
     445
     446        if (dc != kDialogCodeRejected)
     447        {
     448            needupdate = true;
     449            if (dc == kDialogCodeButton0)
     450                // Delete cutpoint
     451                m_player->DeleteMark(images->stillMainFrameNumber);
     452
     453            else if (dc == kDialogCodeButton1)
     454            {
     455                // Move cutpoint
     456                savedCutpoint = images->stillMainFrameNumber;
     457                savedCutType = m_player->deleteMap[images->stillMainFrameNumber];
     458                movingCutpoint = true;
     459                // Ensure we're at least at 1 frame motion
     460                int i;
     461                for (i = 0; m_player->GetSeekAmountPos() < 2 && i < 10; i++)
     462                    m_player->UpdateSeekAmount(true);
     463                   
     464            }
     465            else if (dc == kDialogCodeButton2)
     466                // Flip
     467                m_player->ReverseMark(images->stillMainFrameNumber);
     468        }
     469    }
     470    else
     471    {
     472        pub->addLabel("Insert a new cut point?");
     473        pub->addButton("Delete before this frame");
     474        pub->addButton("Delete after this frame");
     475        DialogCode dc = pub->ExecPopup();
     476
     477        if (dc != kDialogCodeRejected)
     478        {
     479            needupdate = true;
     480            if (dc == kDialogCodeButton0)
     481                // Delete left
     482                m_player->AddMark(images->stillMainFrameNumber, MARK_CUT_END);
     483
     484            else if (dc == kDialogCodeButton1)
     485                // Delete Right
     486                m_player->AddMark(images->stillMainFrameNumber, MARK_CUT_START);
     487        }
     488    }
     489
     490    pub->deleteLater();
     491    if (needupdate)
     492    {
     493        refreshCutList();
     494        refreshImages();
     495    }
     496}
     497
     498void GridEditCutpoints::customEvent(QCustomEvent *e)
     499{
     500    if ((MythEvent::Type)(e->type()) == MythEvent::MythEventMessage)
     501    {
     502        MythEvent *me = (MythEvent *)e;
     503        QString message = me->Message();
     504    }
     505}
     506
     507void GridEditCutpoints::refreshImages(bool mainFrameOnly)
     508{
     509    m_gridimages[0]->setPixmap(images->stillFramesBig[0],
     510                               images->stillMainFrameNumber,
     511                               images->cutFrames[0]);
     512
     513    if (mainFrameOnly)
     514    {
     515        repaint(m_gridimages[0]->getOuterBorder(), false);
     516        updateStats(true);
     517        return;
     518    }
     519
     520
     521    int i;
     522    for (i = -usedSubVideoCount; i <= usedSubVideoCount; i++)
     523        if (i != 0) // index 0 done above already
     524            m_gridimages[i]->setPixmap(images->stillFrames[i],
     525                                       (images->stillMainFrameNumber + i),
     526                                       images->cutFrames[i]);
     527}
     528
     529void GridEditCutpoints::printStillFrameStats(QString caption)
     530{
     531    images->printStillFrameStats(caption);
     532}
     533
     534void GridEditCutpoints::refreshCutList()
     535{
     536    if (images->refreshCutList())
     537    {
     538        int i;
     539        for (i = -usedSubVideoCount; i <= usedSubVideoCount; i++)
     540            m_gridimages[i]->setCutStatus(images->cutFrames[i]);
     541    }
     542    refreshSlider();
     543}
     544
     545void GridEditCutpoints::refreshSlider()
     546{
     547    if (!m_slider)
     548        return;
     549
     550    m_slider->ClearAll();
     551
     552    const int CUT_LEFT = 0;
     553    const int CUT_RIGHT = 1;
     554
     555    long long startpos = 0;
     556    long long endpos = 0;
     557   
     558    int       lastdirection = CUT_LEFT;
     559
     560    QMap<long long, int> & deleteMap = m_player->deleteMap;
     561    QMap<long long, int>::Iterator i = deleteMap.begin();
     562    for (; i != deleteMap.end(); ++i)
     563    {
     564        long long frame = i.key();
     565        int direction = i.data();
     566
     567        if (direction == CUT_LEFT)
     568        {
     569            endpos = frame;
     570            m_slider->SetRange(startpos, endpos, images->maxFrameNumber);
     571
     572            startpos = frame;
     573            lastdirection = CUT_LEFT;
     574        }
     575        else if (direction == CUT_RIGHT)
     576        {
     577            if (lastdirection == CUT_RIGHT)
     578            {
     579                // continuing within a cutpoint
     580                endpos = frame;
     581                m_slider->SetRange(startpos, endpos, images->maxFrameNumber);
     582            }
     583
     584            startpos = frame;
     585            lastdirection = CUT_RIGHT;
     586        }
     587    }
     588
     589    if (lastdirection == CUT_RIGHT)
     590    {
     591        // continuing within a cutpoint
     592        endpos = images->maxFrameNumber;
     593        m_slider->SetRange(startpos, endpos, images->maxFrameNumber);
     594    }
     595}
     596
     597void GridEditCutpoints::updateStats(bool forcerepaint)
     598{
     599    int secs, frames, ss, mm, hh;
     600
     601    secs = (int)(images->stillMainFrameNumber / m_player->GetFrameRate());
     602    frames = images->stillMainFrameNumber - (int)(secs * m_player->GetFrameRate());
     603
     604    ss = secs;
     605    mm = ss / 60;
     606    ss %= 60;
     607    hh = mm / 60;
     608    mm %= 60;
     609
     610    char timestr[128];
     611    sprintf(timestr, "%d:%02d:%02d.%02d", hh, mm, ss, frames);
     612
     613    char framestr[128];
     614    sprintf(framestr, "%lld", images->stillMainFrameNumber);
     615
     616    if (m_time)
     617    {
     618        m_time->SetText(timestr);
     619        if (forcerepaint)
     620            repaint(m_time->getScreenArea());
     621    }
     622    if (m_framenum)
     623    {
     624        m_framenum->SetText(framestr);
     625        if (forcerepaint)
     626            repaint(m_framenum->getScreenArea());
     627    }
     628    if (m_cutind)
     629    {
     630        switch (images->cutFrames[0]) {
     631            case 0: m_cutind->SetText("");           break;
     632            case 1: m_cutind->SetText("Cut");        break;
     633            case 2: m_cutind->SetText("Cut Before"); break;
     634            case 3: m_cutind->SetText("Cut After");  break;
     635        }
     636        if (forcerepaint)
     637            repaint(m_cutind->getScreenArea());
     638    }
     639
     640    // Don't need to force update this
     641    if (m_jumpstyle)
     642        m_jumpstyle->SetText(m_player->GetSeekAmountText());
     643
     644    if (m_slider)
     645        m_slider->SetPosition(images->stillMainFrameNumber, images->maxFrameNumber);
     646
     647}
     648
     649void GridEditCutpoints::escape()
     650{
     651    // Make sure we're on the right frame when we go back to
     652    // Normal edit mode
     653    m_player->EditSeekToFrame(images->stillMainFrameNumber);
     654    unsetCursor();
     655    accept();
     656}
     657
     658void GridEditCutpoints::SetUpdating(bool active, QString text)
     659{
     660    if (m_updatingind)
     661    {
     662        //VERBOSE(VB_GENERAL, QString("Updating to %1").arg(active));
     663        if (active)
     664        {
     665            m_updatingind->show();
     666            m_updatingind->SetText(text);
     667        }
     668        else
     669            m_updatingind->hide();
     670        repaint(m_updatingind->getScreenArea());
     671    }
     672}
     673
     674void GridEditCutpoints::allFramesUpdated()
     675{
     676    if (slowMotionActive)
     677    {
     678        readyForNextFrame=true;
     679        if (!slowMotionTimer->isActive())
     680            slowMotionTimer->start(0);
     681    }
     682}
     683
  • mythtv/libs/libmythtv/grideditcutpoints.h

    diff -r -u -N -X diff.exclude -x release.20019.0219a -x release.20019.0219b release.20019.0219a/mythtv/libs/libmythtv/grideditcutpoints.h release.20019.0219b/mythtv/libs/libmythtv/grideditcutpoints.h
     
     1// -*- Mode: c++ -*-
     2#ifndef GRIDEDITCUTPOINTS_H_
     3#define GRIDEDITCUTPOINTS_H_
     4
     5#include <qstring.h>
     6
     7#include "libmyth/mythwidgets.h"
     8#include "uitypes.h"
     9
     10#include "grideditimages.h"
     11
     12using namespace std;
     13
     14class QTimer;
     15class NuppelVideoPlayer;
     16class GridEditImages;
     17
     18class MPUBLIC GridEditCutpoints : public MythThemedDialog
     19{
     20    Q_OBJECT
     21
     22  public:
     23    // Use this function to instantiate an GridEditCutpoints instance.
     24    static void Run(NuppelVideoPlayer            *player);
     25
     26  protected slots:
     27    void escape();
     28    void customEvent(QCustomEvent *e);
     29
     30  protected:
     31    GridEditCutpoints(MythMainWindow *parent,
     32              NuppelVideoPlayer *player, const char *name = "GridEditCutpoints");
     33   ~GridEditCutpoints();
     34
     35    void displayInitialFrame();
     36
     37    void handleSelect();
     38    int getNearestCutpoint();
     39
     40    void updateStats(bool forcerepaint = false);
     41
     42  private:
     43    void keyPressEvent(QKeyEvent *e);
     44
     45    int   usedSubVideoCount;
     46
     47    myArray<UIGridEditImageType*, MAX_SUB_VIDEOS> m_gridimages;
     48
     49  public:
     50    void refreshImages(bool mainFrameOnly = false);
     51    void allFramesUpdated();
     52  private:
     53    void refreshCutList();
     54    void refreshSlider();
     55
     56
     57    GridEditImages *images;
     58
     59    void printStillFrameStats(QString );
     60  private:
     61    void SetUpdating(bool active, QString text = "Updating");
     62
     63  protected slots:
     64    void updateSlowMotion();
     65
     66  private:
     67    void setSlowMotionSpeed();
     68
     69    NuppelVideoPlayer *m_player;
     70
     71    long long savedCutpoint;
     72    int       savedCutType;
     73    bool      movingCutpoint;
     74
     75    UITextType   *m_framenum;
     76    UITextType   *m_time;
     77    UITextType   *m_cutind;
     78    UITextType   *m_jumpstyle;
     79    UITextType   *m_updatingind;
     80 
     81    UIGridEditSliderType  *m_slider;
     82    QTimer                *slowMotionTimer;
     83    int                    slowMotionDirection;
     84    bool                   slowMotionActive;
     85    bool                   readyForNextFrame;
     86};
     87
     88#endif
  • mythtv/libs/libmythtv/grideditimages.cpp

    diff -r -u -N -X diff.exclude -x release.20019.0219a -x release.20019.0219b release.20019.0219a/mythtv/libs/libmythtv/grideditimages.cpp release.20019.0219b/mythtv/libs/libmythtv/grideditimages.cpp
     
     1#include <qapplication.h>
     2#include <qpainter.h>
     3#include <qfont.h>
     4#include <qsqldatabase.h>
     5#include <qsqlquery.h>
     6#include <math.h>
     7#include <qcursor.h>
     8#include <qapplication.h>
     9#include <qimage.h>
     10#include <qlayout.h>
     11#include <qlabel.h>
     12#include <qdatetime.h>
     13#include <qvgroupbox.h>
     14#include <qheader.h>
     15#include <qrect.h>
     16
     17#include <unistd.h>
     18#include <iostream>
     19#include <algorithm>
     20using namespace std;
     21
     22#include "mythcontext.h"
     23#include "mythdbcon.h"
     24#include "grideditimages.h"
     25#include "grideditcutpoints.h"
     26#include "NuppelVideoPlayer.h"
     27
     28GridEditImages::GridEditImages(GridEditCutpoints *editor, NuppelVideoPlayer *player)
     29{
     30    m_editor = editor;
     31    m_player = player;
     32    usedSubVideoCount = 0;
     33
     34    lastmovewasright= true;
     35
     36    int i;
     37    for (i = stillFrames.minIndex(); i <= stillFrames.maxIndex(); i++)
     38    {
     39        stillFrames[i] = NULL;
     40        stillFramesBig[i] = NULL;
     41        cutFrames[i] = 0;
     42    }
     43
     44    // Get first frames...
     45    stillMainFrameNumber = m_player->GetFramesPlayed();
     46    if (stillMainFrameNumber <= 0)
     47        stillMainFrameNumber = 1;
     48
     49    // maxFrameNumber may be overridden if neccessary
     50    maxFrameNumber = m_player->GetTotalFrameCount();
     51    maxFrameNumberNVP = m_player->GetTotalFrameCount();
     52
     53    if (stillMainFrameNumber <= 0)
     54        stillMainFrameNumber = 1;
     55
     56    if (stillMainFrameNumber > maxFrameNumber)
     57        stillMainFrameNumber = maxFrameNumber;
     58
     59    getImagesTimer = new QTimer(this);
     60    QObject::connect(getImagesTimer, SIGNAL(timeout()),
     61                     this,           SLOT(updateAllFrames()));
     62
     63
     64}
     65
     66GridEditImages::~GridEditImages()
     67{
     68    clearStillFrames();
     69}
     70
     71QPixmap *GridEditImages::makeScaledPixmap(const QImage& qim, QSize sz)
     72{
     73    QPixmap *retval;
     74    if (qim.size() == sz)
     75    {
     76        retval = new QPixmap(qim);
     77    }
     78    else
     79    {
     80        retval = new QPixmap(sz);
     81        retval->fill(Qt::black);
     82        QPainter p(retval);
     83
     84        int tl_left = 0;
     85        int tl_top = 0;
     86        if (sz.width() > qim.width())
     87            tl_left += (sz.width() - qim.width()) / 2;
     88
     89        if (sz.height() > qim.height())
     90            tl_top += (sz.height() - qim.height()) / 2;
     91
     92//        VERBOSE(VB_GENERAL, QString("Size mismatch qim(%1, %2) != sz(%3, %4) Shift to (%5, %6)")
     93//             .arg(qim.width()).arg(qim.height())
     94//             .arg(sz.width()).arg(sz.height())
     95//             .arg(tl_left).arg(tl_top));
     96
     97        p.drawImage(tl_left, tl_top, qim);
     98    }
     99    return retval;
     100}
     101
     102#define FRAME_DEBUG 0
     103
     104void GridEditImages::getMainStillFrame()
     105{
     106    if (!stillFrames[0])
     107        getSpecificFrame(0);
     108}
     109
     110bool GridEditImages::getStillFrames(bool obeyPreCacheLimits, int maxcount)
     111{
     112    //
     113    // returns true if no more frames to get
     114
     115    // This will fill in all the missing frames in the cache
     116
     117    int i;
     118
     119    // Get Boundaries for Minus and Plus arrays
     120    int starti = stillFrames.minIndex();
     121    int endi   = stillFrames.maxIndex();
     122    if (obeyPreCacheLimits)
     123    {
     124        starti = -preCacheCountLeft;
     125        endi   = preCacheCountRight;
     126    }
     127
     128    // Make sure we don't fall of the front of the file
     129    if (stillMainFrameNumber + starti <= 0)
     130        starti = -(stillMainFrameNumber-1);
     131
     132    // ... or the back of the file
     133    if (endi > (maxFrameNumber - stillMainFrameNumber))
     134        endi = (maxFrameNumber - stillMainFrameNumber);
     135
     136    if (! obeyPreCacheLimits && lastmovewasright)
     137    {
     138        // If we're filling out the cache and the last move was to the right
     139        // grab future frames first before and past frames
     140        for (i = 1; i <= endi; i++)
     141        {
     142            if (!stillFrames[i])
     143            {
     144                getSpecificFrame(i);
     145                if (--maxcount == 0) return false;
     146            }
     147        }
     148    }
     149
     150    // grab all appropriate frames
     151
     152    for (i = starti; i <= endi; i++)
     153    {
     154        if (!stillFrames[i])
     155        {
     156            getSpecificFrame(i);
     157            if (--maxcount == 0) return false;
     158        }
     159    }
     160
     161    return true;
     162}
     163
     164void GridEditImages::getSpecificFrame(int i)
     165{
     166    // i is the index withou the cache of frames
     167    if (!stillFrames[i])
     168    {
     169        // get this frame
     170        long long targetFrame = stillMainFrameNumber + i;
     171
     172        if (!m_player->EditSeekToFrame(targetFrame))
     173        {
     174            VERBOSE(VB_GENERAL, QString("Error seeking to Frame[%1] (frame # %2)")
     175                                .arg(i).arg(targetFrame));
     176            checkMaxFrameCount();
     177
     178            stillFramesBig[i] = new QPixmap(videoSizeMain);
     179            stillFramesBig[i]->fill(Qt::gray);
     180
     181            stillFrames[i] = new QPixmap(videoSizeSmall);
     182            stillFrames[i]->fill(Qt::gray);
     183        }
     184        else
     185        {
     186            cutFrames[i] = m_player->GetCutStatus(targetFrame);
     187            QImage qim = m_player->GetScreenGrabOfCurrentFrame(videoSizeMain);
     188
     189            stillFramesBig[i] = makeScaledPixmap(qim, videoSizeMain);
     190            stillFrames[i]    = makeScaledPixmap(qim.scale(videoSizeSmall, QImage::ScaleMin),
     191                                                 videoSizeSmall);
     192
     193#if FRAME_DEBUG
     194            VERBOSE(VB_GENERAL, QString("stillFrames[%1] = %2 (%3)")
     195                    .arg(i)
     196                    .arg(targetFrame)
     197                    .arg(cutFrames[i]));
     198#endif
     199        }
     200    }
     201}
     202
     203void GridEditImages::SetVideoInfo(int vcount, QSize sizeMain, QSize sizeSmall)
     204{
     205    usedSubVideoCount = vcount;
     206    preCacheCountLeft = vcount+1;
     207    preCacheCountRight = vcount+1;
     208    videoSizeMain = sizeMain;
     209    videoSizeSmall = sizeSmall;
     210}
     211
     212void GridEditImages::SetPreCacheLeft(int pccount)
     213{
     214    preCacheCountLeft = usedSubVideoCount + pccount;
     215    preCacheCountRight = usedSubVideoCount + 1;
     216    // pccount is too big, then it's a waste of tim to precache
     217    // i.e. 1 second jumps...
     218    // We'll end up just throwing the extra frames away
     219    if (preCacheCountLeft > stillFrames.maxIndex())
     220        preCacheCountLeft = usedSubVideoCount + 1;
     221}
     222
     223void GridEditImages::SetPreCacheRight(int pccount)
     224{
     225    preCacheCountLeft = usedSubVideoCount + 1;
     226    preCacheCountRight = usedSubVideoCount + pccount;
     227    // pccount is too big, then it's a waste of tim to precache
     228    // i.e. 1 second jumps...
     229    // We'll end up just throwing the extra frames away
     230    if (preCacheCountRight > stillFrames.maxIndex())
     231        preCacheCountRight = usedSubVideoCount + 1;
     232}
     233
     234void GridEditImages::updateAllFrames()
     235{
     236    // First call is to grab frames to be actively displayed
     237    bool done = getStillFrames(true, 1);
     238    if (done)
     239    {
     240        m_editor->allFramesUpdated();
     241
     242        // Second call willi be called to fill the image cache completely
     243        done = getStillFrames(false, 1);
     244        if (done)
     245            getImagesTimer->stop();
     246    }
     247
     248    m_editor->refreshImages();
     249
     250}
     251
     252void GridEditImages::clearStillFrames()
     253{
     254    int i;
     255    for (i = stillFrames.minIndex(); i <= stillFrames.maxIndex(); i++)
     256    {
     257        if (stillFrames[i])
     258        {
     259            delete stillFrames[i];
     260            stillFrames[i] = NULL;
     261        }
     262        if (stillFramesBig[i])
     263        {
     264            delete stillFramesBig[i];
     265            stillFramesBig[i] = NULL;
     266        }
     267        cutFrames[i] = 0;
     268    }
     269}
     270
     271bool GridEditImages::shiftStillFramesLeft(long long offset)
     272{
     273    if (offset > 2 * stillFrames.maxIndex())
     274    {
     275        // Dump all cached data and re-get it
     276        clearStillFrames();
     277    }
     278    else if (offset < 0)
     279    {
     280        VERBOSE(VB_IMPORTANT, QString("Offset (%1) < 0").arg(offset));
     281        // Dump all cached data and re-get it
     282        clearStillFrames();
     283        offset = 0;
     284    }
     285    else if (offset != 0)
     286    {
     287        // Shift backwards in the stream by offset
     288
     289        // All frames will actually shift to the right.
     290        // frame 'n' will become frame 'n+1'
     291        // frame stillFrameMinus[1] will become mainframe
     292        // frame stillFramePlus[max] will drop off
     293
     294        // shove extra frames into the excess space above usedSubVideos
     295
     296        if (offset >= stillMainFrameNumber)
     297            offset = (stillMainFrameNumber-1);
     298
     299        //    printStillFrameStats("Before SL");
     300        int i,j;
     301        int minIndex = stillFrames.minIndex();
     302        int maxIndex = stillFrames.maxIndex();
     303        for (i = 0; i < offset; i++)
     304        {
     305           
     306            if (stillFrames[maxIndex])
     307            {
     308                delete stillFrames[maxIndex];
     309                delete stillFramesBig[maxIndex];
     310            }
     311
     312            for (j = maxIndex; j > minIndex; j--) {
     313                stillFrames[j]    = stillFrames[j-1];
     314                stillFramesBig[j] = stillFramesBig[j-1];
     315                cutFrames[j]      = cutFrames[j-1];
     316            }
     317
     318             stillFrames[minIndex]    = NULL;
     319             stillFramesBig[minIndex] = NULL;
     320             cutFrames[minIndex]      = 0;
     321        }
     322
     323        //   printStillFrameStats("After SL");
     324
     325    }
     326
     327    stillMainFrameNumber -= offset;
     328    if (stillMainFrameNumber < 1)
     329        stillMainFrameNumber = 1;
     330
     331    return (stillFramesBig[0] != NULL);
     332}
     333
     334bool GridEditImages::shiftStillFramesRight(long long offset)
     335{
     336    //VERBOSE(VB_GENERAL, QString("Offset =  %1").arg(offset));
     337    if (offset > 2 * stillFrames.maxIndex())
     338    {
     339        // Dump all cached data and re-get it
     340        clearStillFrames();
     341    }
     342    else if (offset < 0)
     343    {
     344        VERBOSE(VB_IMPORTANT, QString("Offset (%1) < 0").arg(offset));
     345        // Dump all cached data and re-get it
     346        clearStillFrames();
     347        offset = 0;
     348    }
     349    else if (offset != 0)
     350    {
     351
     352        // Shift forwards in the stream by offset
     353
     354        // All frames will actually shift to the left.
     355        // frame 'n' will become frame 'n-1'
     356        // frame stillFramePlus[1] will become mainframe
     357        // frame stillFrameMinus[max] will drop off
     358
     359        // shove extra frames into the excess space above usedSubVideos
     360
     361        if (stillMainFrameNumber + offset > maxFrameNumber)
     362        {
     363            offset = (maxFrameNumber - stillMainFrameNumber);
     364            VERBOSE(VB_GENERAL, QString("new Offset =  %1").arg(offset));
     365        }
     366        //printStillFrameStats("Before SR");
     367
     368        int i,j;
     369        int minIndex = stillFrames.minIndex();
     370        int maxIndex = stillFrames.maxIndex();
     371
     372        for (i = 0; i < offset; i++)
     373        {
     374            if (stillFrames[minIndex])
     375            {
     376                delete stillFrames[minIndex];
     377                delete stillFramesBig[minIndex];
     378            }
     379
     380            for (j = minIndex; j < maxIndex; j++) {
     381                stillFrames[j]    = stillFrames[j+1];
     382                stillFramesBig[j] = stillFramesBig[j+1];
     383                cutFrames[j]      = cutFrames[j+1];
     384            }
     385
     386             stillFrames[maxIndex]    = NULL;
     387             stillFramesBig[maxIndex] = NULL;
     388             cutFrames[maxIndex]      = 0;
     389        }
     390
     391        //printStillFrameStats("After SR");
     392
     393    }
     394    stillMainFrameNumber += offset;
     395    if (stillMainFrameNumber > maxFrameNumber )
     396        stillMainFrameNumber = maxFrameNumber;
     397
     398    return (stillFramesBig[0] != NULL);
     399}
     400
     401void GridEditImages::printStillFrameStats(QString caption)
     402{
     403    int i;
     404    // Debug info for frame cache
     405    QString foundframes= caption + " Found Frames: ";
     406
     407    for (i = stillFrames.minIndex(); i <= stillFrames.maxIndex(); i++)
     408        if (stillFrames[i])
     409            foundframes += QString("%1 ").arg(i);
     410
     411    VERBOSE(VB_GENERAL, foundframes);
     412}
     413
     414bool GridEditImages::refreshCutList()
     415{
     416    // return true if the on-screen cutlist has changed
     417    bool needupdate = false;
     418
     419    int i;
     420    for (i = stillFrames.minIndex(); i <= stillFrames.maxIndex(); i++)
     421    {
     422        if (stillFrames[i])
     423        {
     424            int oldcutvalue = cutFrames[i];
     425            cutFrames[i] = m_player->GetCutStatus(stillMainFrameNumber+i);
     426            if (oldcutvalue != cutFrames[i] && frameIsDisplayed(i))
     427                needupdate = true;
     428        }
     429    }
     430
     431    return needupdate;
     432}
     433
     434// Back up x frames
     435void GridEditImages::EditHandleLeft(int seektype)
     436{
     437    lastmovewasright = false;
     438    getImagesTimer->stop();
     439    long long seekamount = m_player->GetSeekAmount();
     440
     441    if (seektype == -2 || seekamount == -2)
     442    {
     443        // CutPoint seek
     444        seekamount = m_player->CalcCutPointSeek(stillMainFrameNumber, false);
     445    }
     446    else
     447    {
     448        // seektype == 1 for normal, 10 for bigjump
     449        seekamount *= seektype;
     450    }
     451
     452    if (seekamount < 0) // Invalid -- keyframe
     453        seekamount = 1;
     454
     455    SetPreCacheLeft(seekamount);
     456    if (!shiftStillFramesLeft(seekamount))
     457    {
     458        //VERBOSE(VB_GENERAL, QString("shiftStillFramesLeft(%1) == false")
     459        //                           .arg(seekamount));
     460        // Need to grab the main frame
     461
     462        getMainStillFrame();
     463    }
     464
     465    m_editor->refreshImages(true);
     466
     467    getImagesTimer->start(0);
     468
     469}
     470
     471void GridEditImages::EditHandleRight(int seektype)
     472{
     473    lastmovewasright = true;
     474    getImagesTimer->stop();
     475    long long seekamount = m_player->GetSeekAmount();
     476
     477    if (seektype == -2 || seekamount == -2)
     478    {
     479        // CutPoint seek
     480        seekamount = m_player->CalcCutPointSeek(stillMainFrameNumber, true);
     481    }
     482    else
     483    {
     484        // seektype == 1 for normal, 10 for bigjump
     485        seekamount *= seektype;
     486    }
     487
     488    if (seekamount < 0) // Invalid -- keyframe
     489        seekamount = 1;
     490
     491    SetPreCacheRight(seekamount);
     492    if (!shiftStillFramesRight(seekamount))
     493    {
     494        // Need to grab the main frame
     495        //VERBOSE(VB_GENERAL, QString("shiftStillFramesRight(%1) == false")
     496        //                           .arg(seekamount));
     497
     498        getMainStillFrame();
     499    }
     500    m_editor->refreshImages(true);
     501
     502    getImagesTimer->start(0);
     503}
     504
     505void GridEditImages::checkMaxFrameCount()
     506{
     507    long long tfc = m_player->GetTotalFrameCount();
     508    if (tfc != maxFrameNumberNVP)
     509    {
     510       VERBOSE(VB_GENERAL, QString("Updating: tfc %1, mfn %2, mfnNVP %3")
     511            .arg(tfc).arg(maxFrameNumber).arg(maxFrameNumberNVP));
     512        // Check to see if things changed
     513        maxFrameNumber = tfc;
     514        maxFrameNumberNVP = tfc;
     515    }
     516}
     517
  • mythtv/libs/libmythtv/grideditimages.h

    diff -r -u -N -X diff.exclude -x release.20019.0219a -x release.20019.0219b release.20019.0219a/mythtv/libs/libmythtv/grideditimages.h release.20019.0219b/mythtv/libs/libmythtv/grideditimages.h
     
     1// -*- Mode: c++ -*-
     2#ifndef GRIDEDITIMAGES_H_
     3#define GRIDEDITIMAGES_H_
     4
     5#include <qstring.h>
     6
     7#include "libmyth/mythwidgets.h"
     8
     9using namespace std;
     10
     11class QTimer;
     12class NuppelVideoPlayer;
     13class GridEditCutpoints;
     14
     15#define MAX_SUB_VIDEOS 25
     16
     17// Simple class to allow array indexing from -MAX_SUB_VIDEOS to +MAX_SUB_VIDEOS
     18template<class T, int COUNT> class myArray
     19{
     20    public:
     21        myArray() { memset(_array, 0, sizeof(_array));};
     22
     23        T& operator[](int i) { return _array[COUNT+i]; };
     24        int minIndex() const { return -COUNT; };
     25        int maxIndex() const { return  COUNT; };
     26
     27    private:
     28        T _array[2*COUNT+1];
     29};
     30
     31
     32class MPUBLIC GridEditImages : public QObject
     33{
     34    Q_OBJECT
     35
     36    public:
     37        GridEditImages(GridEditCutpoints *er, NuppelVideoPlayer *player);
     38        ~GridEditImages();
     39
     40        void clearStillFrames();
     41        // return true if anything changed
     42        bool shiftStillFramesLeft(long long offset);
     43        bool shiftStillFramesRight(long long offset);
     44
     45        void printStillFrameStats(QString caption);
     46        // return true if anything chagned
     47        bool refreshCutList();
     48
     49        // seektype == -2 - cutpoint seek
     50        // seektype ==  1 - normal seek
     51        // seektype == 10 - large seek
     52        void EditHandleLeft(int seektype = 1);
     53        void EditHandleRight(int seektype = 1);
     54        void EditHandlePrevCut()    { EditHandleLeft(-2); };
     55        void EditHandleNextCut()    { EditHandleRight(-2); };
     56        void EditHandleBigJumpRew() { EditHandleLeft(10); };
     57        void EditHandleBigJumpFwd() { EditHandleRight(10); };
     58
     59        void checkMaxFrameCount();
     60
     61        QPixmap *makeScaledPixmap(const QImage& qim, QSize sz);
     62
     63        bool getStillFrames(bool overPreCacheLimits, int maxcount = 1000);
     64        void getMainStillFrame();
     65        void getSpecificFrame(int frameindex);
     66
     67        void SetVideoInfo(int vcount, QSize sizeMain, QSize sizeSmall);
     68        void SetPreCacheLeft(int pccount);
     69        void SetPreCacheRight(int pccount);
     70
     71        // These frames are in the cutlist
     72        // 0 == not cut
     73        // 1 == cut
     74        // 2 == cutpoint (cut left)
     75        // 3 == cutpoint (cut right)
     76        myArray<int, MAX_SUB_VIDEOS> cutFrames;
     77
     78        myArray<QPixmap *, MAX_SUB_VIDEOS> stillFrames;
     79        myArray<QPixmap *, MAX_SUB_VIDEOS> stillFramesBig;
     80
     81        // return true if the specified index is displayed on screen
     82        bool frameIsDisplayed(int i) { return (-usedSubVideoCount <= i && i <= usedSubVideoCount);};
     83
     84        QSize videoSizeMain;
     85        QSize videoSizeSmall;
     86        int   usedSubVideoCount;
     87        int   preCacheCountLeft;
     88        int   preCacheCountRight;
     89
     90        long long stillMainFrameNumber; // frame number for big still picture
     91        long long currentFrameNumberNVP; // frame number the NVP should be on
     92        long long maxFrameNumber;       // max frame number override for NVP
     93        long long maxFrameNumberNVP;    // Original NVP number
     94
     95        QTimer            *getImagesTimer;
     96        bool lastmovewasright;
     97    protected slots:
     98        void updateAllFrames();
     99
     100    private:
     101        GridEditCutpoints *m_editor;
     102        NuppelVideoPlayer *m_player;
     103
     104
     105};
     106
     107#endif
  • mythtv/libs/libmythtv/libmythtv.pro

    diff -r -u -N -X diff.exclude -x release.20019.0219a -x release.20019.0219b release.20019.0219a/mythtv/libs/libmythtv/libmythtv.pro release.20019.0219b/mythtv/libs/libmythtv/libmythtv.pro
     
    319319    # Misc. frontend
    320320    HEADERS += guidegrid.h              infostructs.h
    321321    HEADERS += progfind.h               ttfont.h
     322    HEADERS += grideditcutpoints.h      grideditimages.h
    322323    SOURCES += guidegrid.cpp            infostructs.cpp
    323324    SOURCES += progfind.cpp             ttfont.cpp
     325    SOURCES += grideditcutpoints.cpp    grideditimages.cpp
    324326
    325327    # DSMCC stuff
    326328    HEADERS += dsmcc.h                  dsmcccache.h
  • mythtv/libs/libmythtv/tv_play.cpp

    diff -r -u -N -X diff.exclude -x release.20019.0219a -x release.20019.0219b release.20019.0219a/mythtv/libs/libmythtv/tv_play.cpp release.20019.0219b/mythtv/libs/libmythtv/tv_play.cpp
     
    2525#include "remoteencoder.h"
    2626#include "remoteutil.h"
    2727#include "guidegrid.h"
     28#include "grideditcutpoints.h"
    2829#include "progfind.h"
    2930#include "NuppelVideoPlayer.h"
    3031#include "programinfo.h"
     
    440441    REG_KEY("TV Editing", "BIGJUMPFWD", "Jump forward 10x the normal amount",
    441442            ">,.");
    442443    REG_KEY("TV Editing", "TOGGLEEDIT", "Exit out of Edit Mode", "E");
     444    REG_KEY("TV Editing", "SLOWMO", "Slow Motion Play", "Ctrl+P");
     445    REG_KEY("TV Editing", "PAUSE", "Pause", "P");
    443446
    444447    /* Teletext keys */
    445448    REG_KEY("Teletext Menu", "NEXTPAGE",    "Next Page",             "Down");
     
    26062609
    26072610    if (editmode)
    26082611    {   
     2612        if (nvp->GetHideEdits())
     2613            return;   
    26092614        if (!nvp->DoKeypress(e))
    26102615            editmode = nvp->GetEditMode();
    26112616        if (!editmode)
     
    59925997    qApp->postEvent(myWindow, me);
    59935998}
    59945999
     6000void TV::ShowEditRecordingGrid()
     6001{
     6002    // post the request to the main UI thread
     6003    // it will be caught in eventFilter and processed as CustomEvent
     6004    // this will create the program guide window (widget)
     6005    // on the main thread and avoid a deadlock on Win32
     6006
     6007    VERBOSE(VB_GENERAL, "Starting Grid Edit");
     6008    QString message = QString("START_EDIT");
     6009    MythEvent* me = new MythEvent(message);
     6010    qApp->postEvent(myWindow, me);
     6011}
     6012
    59956013void TV::ChangeVolume(bool up)
    59966014{
    59976015    AudioOutput *aud = nvp->getAudioOutput();
     
    65256543            int editType = tokens[1].toInt();
    65266544            doEditSchedule(editType);
    65276545        }
     6546        else if (message.left(10) == "START_EDIT")
     6547        {
     6548            nvp->ShowEditRecordingGrid();
     6549        }
    65286550
    65296551        pbinfoLock.lock();
    65306552        if (playbackinfo && message.left(14) == "COMMFLAG_START")
  • mythtv/libs/libmythtv/tv_play.h

    diff -r -u -N -X diff.exclude -x release.20019.0219a -x release.20019.0219b release.20019.0219a/mythtv/libs/libmythtv/tv_play.h release.20019.0219b/mythtv/libs/libmythtv/tv_play.h
     
    158158    void setUnderNetworkControl(bool setting) { underNetworkControl = setting; }
    159159    bool IsSameProgram(ProgramInfo *p);
    160160
     161    void ShowEditRecordingGrid();
    161162    void ShowNoRecorderDialog(void);
    162163    void FinishRecording(void);
    163164    void AskAllowRecording(const QStringList&, int, bool, bool);