Ticket #6322: 137-editgrid.fixes.code.2.patch

File 137-editgrid.fixes.code.2.patch, 90.1 KB (added by anonymous, 11 years ago)
  • mythtv/libs/libmyth/mythdialogs.cpp

    diff -r -u -N -X diff.exclude.noxml -x release.20115.0305base -x release.20115.0305gridedit release.20115.0305base/mythtv/libs/libmyth/mythdialogs.cpp release.20115.0305gridedit/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.noxml -x release.20115.0305base -x release.20115.0305gridedit release.20115.0305base/mythtv/libs/libmyth/mythdialogs.h release.20115.0305gridedit/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.noxml -x release.20115.0305base -x release.20115.0305gridedit release.20115.0305base/mythtv/libs/libmyth/uitypes.cpp release.20115.0305gridedit/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.noxml -x release.20115.0305base -x release.20115.0305gridedit release.20115.0305base/mythtv/libs/libmyth/uitypes.h release.20115.0305gridedit/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.noxml -x release.20115.0305base -x release.20115.0305gridedit release.20115.0305base/mythtv/libs/libmyth/xmlparse.cpp release.20115.0305gridedit/mythtv/libs/libmyth/xmlparse.cpp
     
    1313#undef LoadImage
    1414#endif
    1515
     16#define LOC QString("XMLParse: ")
     17#define LOC_WARN QString("XMLParse, Warning: ")
     18#define LOC_ERR QString("XMLParse, Error: ")
     19
    1620MPUBLIC QMap<QString, fontProp> globalFontMap;
    1721
    1822XMLParse::XMLParse(void)
     
    14421446            {
    14431447                parseBlackHole(container, info);
    14441448            }
     1449            else if (info.tagName() == "grideditimage")
     1450            {
     1451                parseGridEditImage(container, info);
     1452            }
     1453            else if (info.tagName() == "grideditslider")
     1454            {
     1455                parseGridEditSlider(container, info);
     1456            }
    14451457            else if (info.tagName() == "area")
    14461458            {
    14471459                area = parseRect(getFirstText(info));
     
    34453457    container->AddType(bh);
    34463458}
    34473459
     3460
     3461void XMLParse::parseGridEditImage(LayerSet *container, QDomElement &element)
     3462{
     3463    QRect area;
     3464    QColor outlineColor;
     3465    QColor cutColor;
     3466    QColor cutPointColor;
     3467    bool   haveOutlineColor = false;
     3468    bool   haveCutColor = false;
     3469    bool   haveCutPointColor = false;
     3470
     3471    QString name = element.attribute("name", "");
     3472    if (name.isNull() || name.isEmpty())
     3473    {
     3474        VERBOSE(VB_IMPORTANT, LOC_WARN + "GridEditImage needs a name");
     3475        return;
     3476    }
     3477
     3478    for (QDomNode child = element.firstChild(); !child.isNull();
     3479         child = child.nextSibling())
     3480    {
     3481        QDomElement info = child.toElement();
     3482        if (!info.isNull())
     3483        {
     3484            if (info.tagName() == "area")
     3485            {
     3486                area = parseRect(getFirstText(info));
     3487                normalizeRect(area);
     3488            }
     3489            else if (info.tagName() == "outlinecolor")
     3490            {
     3491                haveOutlineColor = true;
     3492                outlineColor = getFirstText(info);
     3493            }
     3494            else if (info.tagName() == "cutcolor")
     3495            {
     3496                haveCutColor = true;
     3497                cutColor = getFirstText(info);
     3498            }
     3499            else if (info.tagName() == "cutpointcolor")
     3500            {
     3501                haveCutPointColor = true;
     3502                cutPointColor = getFirstText(info);
     3503            }
     3504            else
     3505            {
     3506                VERBOSE(VB_IMPORTANT, LOC_WARN +
     3507                        QString("Unknown tag '%1' in grideditimage '%2'")
     3508                        .arg(info.tagName()).arg(name));
     3509                return;
     3510            }
     3511        }
     3512    }
     3513
     3514    if (!haveOutlineColor)
     3515    {
     3516        VERBOSE(VB_IMPORTANT, LOC_WARN +
     3517                QString("Missing tag 'outlinecolor' in grideditimage '%1'")
     3518                .arg(name));
     3519        return;
     3520    }
     3521
     3522    if (!haveCutColor)
     3523    {
     3524        VERBOSE(VB_IMPORTANT, LOC_WARN +
     3525                QString("Missing tag 'cutcolor' in grideditimage '%1'")
     3526                .arg(name));
     3527        return;
     3528    }
     3529
     3530    if (!haveCutPointColor)
     3531    {
     3532        VERBOSE(VB_IMPORTANT, LOC_WARN +
     3533                QString("Missing tag 'cutpointcolor' in grideditimage '%1'")
     3534                .arg(name));
     3535        return;
     3536    }
     3537
     3538    UIGridEditImageType *gei = new UIGridEditImageType(name);
     3539    gei->SetScreen(wmult, hmult);
     3540    gei->setArea(area);
     3541    gei->setOutlineColor(outlineColor);
     3542    gei->setCutColor(cutColor);
     3543    gei->setCutPointColor(cutPointColor);
     3544    gei->SetParent(container);
     3545    gei->calculateScreenArea();
     3546    gei->clearPixmap(false);
     3547    container->AddType(gei);
     3548}
     3549
     3550void XMLParse::parseGridEditSlider(LayerSet *container, QDomElement &element)
     3551{
     3552    QRect area;
     3553    QColor fillColor;
     3554    QColor cutColor;
     3555    QColor inCutColor;
     3556    QColor cutPointColor;
     3557    QColor positionColor;
     3558    bool   haveFillColor = false;
     3559    bool   haveCutColor = false;
     3560    bool   haveInCutColor = false;
     3561    bool   haveCutPointColor = false;
     3562    bool   havePositionColor = false;
     3563
     3564    QString name = element.attribute("name", "");
     3565    if (name.isNull() || name.isEmpty())
     3566    {
     3567        VERBOSE(VB_IMPORTANT, LOC_WARN + "GridEditSlider needs a name");
     3568        return;
     3569    }
     3570
     3571    for (QDomNode child = element.firstChild(); !child.isNull();
     3572         child = child.nextSibling())
     3573    {
     3574        QDomElement info = child.toElement();
     3575        if (!info.isNull())
     3576        {
     3577            if (info.tagName() == "area")
     3578            {
     3579                area = parseRect(getFirstText(info));
     3580                normalizeRect(area);
     3581            }
     3582            else if (info.tagName() == "fillcolor")
     3583            {
     3584                haveFillColor = true;
     3585                fillColor = getFirstText(info);
     3586            }
     3587            else if (info.tagName() == "cutcolor")
     3588            {
     3589                haveCutColor = true;
     3590                cutColor = getFirstText(info);
     3591            }
     3592            else if (info.tagName() == "incutcolor")
     3593            {
     3594                haveInCutColor = true;
     3595                inCutColor = getFirstText(info);
     3596            }
     3597            else if (info.tagName() == "cutpointcolor")
     3598            {
     3599                haveCutPointColor = true;
     3600                cutPointColor = getFirstText(info);
     3601            }
     3602            else if (info.tagName() == "positioncolor")
     3603            {
     3604                havePositionColor = true;
     3605                positionColor = getFirstText(info);
     3606            }
     3607            else
     3608            {
     3609                VERBOSE(VB_IMPORTANT, LOC_WARN +
     3610                        QString("Unknown tag '%1' in grideditslider '%2'")
     3611                        .arg(info.tagName()).arg(name));
     3612                return;
     3613            }
     3614        }
     3615    }
     3616
     3617    if (!haveFillColor)
     3618    {
     3619        VERBOSE(VB_IMPORTANT, LOC_WARN +
     3620                QString("Missing tag 'fillcolor' in grideditslider '%1'")
     3621                .arg(name));
     3622        return;
     3623    }
     3624
     3625    if (!haveCutColor)
     3626    {
     3627        VERBOSE(VB_IMPORTANT, LOC_WARN +
     3628                QString("Missing tag 'cutcolor' in grideditslider '%1'")
     3629                .arg(name));
     3630        return;
     3631    }
     3632
     3633    if (!haveInCutColor)
     3634    {
     3635        VERBOSE(VB_IMPORTANT, LOC_WARN +
     3636                QString("Missing tag 'incutcolor' in grideditslider '%1'")
     3637                .arg(name));
     3638        return;
     3639    }
     3640
     3641    if (!haveCutPointColor)
     3642    {
     3643        VERBOSE(VB_IMPORTANT, LOC_WARN +
     3644                QString("Missing tag 'cutpointcolor' in grideditslider '%1'")
     3645                .arg(name));
     3646        return;
     3647    }
     3648
     3649    if (!havePositionColor)
     3650    {
     3651        VERBOSE(VB_IMPORTANT, LOC_WARN +
     3652                QString("Missing tag 'positioncolor' in grideditslider '%1'")
     3653                .arg(name));
     3654        return;
     3655    }
     3656
     3657    UIGridEditSliderType *ges = new UIGridEditSliderType(name);
     3658    ges->SetScreen(wmult, hmult);
     3659    ges->setArea(area);
     3660    ges->setFillColor(fillColor);
     3661    ges->setCutColor(cutColor);
     3662    ges->setInCutColor(inCutColor);
     3663    ges->setCutPointColor(cutPointColor);
     3664    ges->setPositionColor(positionColor);
     3665    ges->SetParent(container);
     3666    ges->calculateScreenArea();
     3667    container->AddType(ges);
     3668}
     3669
    34483670void XMLParse::parseListBtnArea(LayerSet *container, QDomElement &element)
    34493671{
    34503672    int context = -1;
  • mythtv/libs/libmyth/xmlparse.h

    diff -r -u -N -X diff.exclude.noxml -x release.20115.0305base -x release.20115.0305gridedit release.20115.0305base/mythtv/libs/libmyth/xmlparse.h release.20115.0305gridedit/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.noxml -x release.20115.0305base -x release.20115.0305gridedit release.20115.0305base/mythtv/libs/libmythtv/NuppelVideoPlayer.cpp release.20115.0305gridedit/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.noxml -x release.20115.0305base -x release.20115.0305gridedit release.20115.0305base/mythtv/libs/libmythtv/NuppelVideoPlayer.h release.20115.0305gridedit/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.noxml -x release.20115.0305base -x release.20115.0305gridedit release.20115.0305base/mythtv/libs/libmythtv/grideditcutpoints.cpp release.20115.0305gridedit/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, "grideditcutpoints", "", name)
     49{
     50    m_player = player;
     51    m_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    m_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 (m_images)
     142    {
     143        delete m_images;
     144        m_images = NULL;
     145    }
     146    gContext->removeListener(this);
     147}
     148
     149void GridEditCutpoints::displayInitialFrame()
     150{
     151    refreshImages(true);
     152    refreshCutList();
     153    updateStats();
     154    SetUpdating(false);
     155}
     156
     157void GridEditCutpoints::updateSlowMotion()
     158{
     159    if (!slowMotionActive)
     160        slowMotionTimer->stop();
     161    else if (readyForNextFrame && slowMotionDirection != 0)
     162    {
     163        readyForNextFrame=false;
     164
     165        if (slowMotionDirection > 0)
     166            EditHandleRight();
     167        else if (slowMotionDirection < 0)
     168            EditHandleLeft();
     169    }
     170}
     171
     172
     173void GridEditCutpoints::setSlowMotionSpeed()
     174{
     175    // slowMotionDirection is max FPS
     176
     177    if (slowMotionDirection != 0)
     178    {
     179        int smd = slowMotionDirection;
     180        if (smd < 0) smd = -smd;
     181        int timeout = 1000 / smd;
     182
     183        slowMotionTimer->start(timeout);
     184    }
     185    SetUpdating(true, QString("%1 FPS max").arg(slowMotionDirection));
     186}
     187
     188
     189void GridEditCutpoints::keyPressEvent(QKeyEvent *e)
     190{
     191    // keyDown limits keyrepeats to prevent continued scrolling
     192    // after key is released. Note: Qt's keycompress should handle
     193    // this but will fail with fast key strokes and keyboard repeat
     194    // enabled. Keys will not be marked as autorepeat and flood buffer.
     195    // setFocusPolicy(QWidget::ClickFocus) in constructor is important
     196    // or keyRelease events will not be received after a refocus.
     197   
     198    bool handled = false;
     199
     200    QStringList actions;
     201    gContext->GetMainWindow()->TranslateKeyPress("TV Editing", e, actions);
     202
     203    {
     204        for (unsigned int i = 0; i < actions.size() && !handled; i++)
     205        {
     206            QString action = actions[i];
     207            handled = true;
     208
     209            if (action == "SELECT")
     210            {
     211                if (slowMotionActive)
     212                {
     213                    slowMotionActive = false;
     214                    slowMotionTimer->stop();
     215                }
     216                else if (movingCutpoint)
     217                {
     218                    // Move cutpoint
     219                    m_player->DeleteMark(savedCutpoint);
     220                    m_player->AddMark(m_images->GetCurrentFrameNumber(), savedCutType);
     221                    movingCutpoint = false;
     222                    refreshCutList();
     223                    refreshImages();
     224                }
     225                else
     226                    handleSelect();
     227            }
     228            else if (action == "PAUSE")
     229            {
     230                if (movingCutpoint)
     231                    MythPopupBox::showOkPopup(gContext->GetMainWindow(),
     232                                              "Moving Cutpoint",
     233                                              "Slow Motion Unavailable when moving cutpoint");
     234                else if (slowMotionActive)
     235                {
     236                    slowMotionActive = false;
     237                    slowMotionTimer->stop();
     238                }
     239            }
     240            else if (action == "SLOWMO")
     241            {
     242                if (movingCutpoint)
     243                    MythPopupBox::showOkPopup(gContext->GetMainWindow(),
     244                                              "Moving Cutpoint",
     245                                              "Slow Motion Unavailable when moving cutpoint");
     246                else
     247                {
     248                    if (slowMotionActive)
     249                    {
     250                        slowMotionActive = false;
     251                        slowMotionTimer->stop();
     252                    }
     253                    else
     254                    {
     255                        slowMotionActive = true;
     256                        readyForNextFrame = true;
     257                        slowMotionDirection = 1;
     258
     259                        // force to either 1 frame. 1/2 page or full page motion
     260                        int i;
     261                        // move to 1 frame if on cutpoint
     262                        for (i = 0; m_player->GetSeekAmountPos() < 2 && i < 10; i++)
     263                            m_player->UpdateSeekAmount(false);
     264
     265                        // move to fullpage if higher
     266                        for (i = 0; m_player->GetSeekAmountPos() > 4 && i < 10; i++)
     267                            m_player->UpdateSeekAmount(true);
     268
     269                        setSlowMotionSpeed();
     270                    }
     271                }
     272            }
     273            else if (action == "LEFT")
     274            {
     275                if (slowMotionActive)
     276                {
     277                    slowMotionDirection--;
     278                    setSlowMotionSpeed();
     279                }
     280                else
     281                {
     282                    SetUpdating(true);
     283
     284                    EditHandleLeft();
     285                    refreshImages(false);
     286                }
     287            }
     288            else if (action == "RIGHT" )
     289            {
     290                if (slowMotionActive)
     291                {
     292                    slowMotionDirection++;
     293                    setSlowMotionSpeed();
     294                }
     295                else
     296                {
     297                    SetUpdating(true);
     298
     299                    EditHandleRight();
     300                    refreshImages(false);
     301                }
     302            }
     303            else if (action == "UP")
     304                m_player->UpdateSeekAmount(true);
     305            else if (action == "DOWN")
     306            {
     307                if ((movingCutpoint || slowMotionActive) && m_player->GetSeekAmountPos() == 2)
     308                    MythPopupBox::showOkPopup(gContext->GetMainWindow(),
     309                                              "Moving Cutpoint",
     310                                              "CutPoint skip Unavailable");
     311                else
     312                    m_player->UpdateSeekAmount(false);
     313            }
     314            else if (action == "CLEARMAP")
     315            {
     316                if (movingCutpoint || slowMotionActive)
     317                    MythPopupBox::showOkPopup(gContext->GetMainWindow(),
     318                                              "Moving Cutpoint",
     319                                              "Clear Cut Map Unavailable");
     320                else
     321                {
     322                    SetUpdating(true);
     323                    m_player->EditHandleClearMap();
     324                    refreshCutList();
     325                }
     326            }
     327            else if (action == "INVERTMAP")
     328            {
     329                if (movingCutpoint || slowMotionActive)
     330                    MythPopupBox::showOkPopup(gContext->GetMainWindow(),
     331                                              "Moving Cutpoint",
     332                                              "Invert Cut Map Unavailable");
     333                else
     334                {
     335                    SetUpdating(true);
     336                    m_player->EditHandleInvertMap();
     337                    refreshCutList();
     338                }
     339            }
     340            else if (action == "LOADCOMMSKIP")
     341            {
     342                if (movingCutpoint || slowMotionActive)
     343                    MythPopupBox::showOkPopup(gContext->GetMainWindow(),
     344                                              "Moving Cutpoint",
     345                                              "Load Comm Skip Map Unavailable");
     346                else
     347                {
     348                    SetUpdating(true);
     349                    m_player->EditHandleLoadCommSkip();
     350                    refreshCutList();
     351                }
     352            }
     353            else if (action == "PREVCUT")
     354            {
     355                if (movingCutpoint || slowMotionActive)
     356                    MythPopupBox::showOkPopup(gContext->GetMainWindow(),
     357                                              "Moving Cutpoint",
     358                                              "Prev Cut Unavailable");
     359                else
     360                {
     361                    SetUpdating(true);
     362                    EditHandlePrevCut();
     363                    refreshImages(false);
     364                }
     365            }
     366            else if (action == "NEXTCUT")
     367            {
     368                if (movingCutpoint || slowMotionActive)
     369                    MythPopupBox::showOkPopup(gContext->GetMainWindow(),
     370                                              "Moving Cutpoint",
     371                                              "Next Cut Unavailable");
     372                else
     373                {
     374                    SetUpdating(true);
     375                    EditHandleNextCut();
     376                    refreshImages(false);
     377                }
     378            }
     379            else if (action == "BIGJUMPREW")
     380            {
     381                SetUpdating(true);
     382                EditHandleBigJumpRew();
     383                refreshImages(false);
     384            }
     385            else if (action == "BIGJUMPFWD")
     386            {
     387                SetUpdating(true);
     388                EditHandleBigJumpFwd();
     389                refreshImages(false);
     390            }
     391            else if (action == "ESCAPE" && movingCutpoint)
     392                movingCutpoint = false;
     393            else if (action == "ESCAPE" || action == "TOGGLEEDIT" ||
     394                     action == "MENU")
     395                escape();
     396            else
     397                handled = false;
     398
     399            if (handled)
     400                updateStats();
     401            if (movingCutpoint)
     402                SetUpdating(true, "Moving Cutpoint");
     403            else if (!slowMotionActive)
     404                SetUpdating(false);
     405        }
     406    }
     407
     408    if (!handled)
     409        MythDialog::keyPressEvent(e);
     410}
     411
     412void GridEditCutpoints::EditHandleLeft(int seektype)
     413{
     414    long long seekamount = m_player->GetSeekAmount();
     415    bool cutpointseek = false;
     416
     417    if (seektype == -2 || seekamount == -2)
     418        cutpointseek = true;
     419    else
     420    {
     421        // seektype == 1 for normal, 10 for bigjump
     422        seekamount *= seektype;
     423    }
     424
     425    if (seekamount < 0) // Invalid -- keyframe
     426        seekamount = 1;
     427
     428    m_images->SeekLeft(seekamount, cutpointseek);
     429
     430    refreshImages(true);
     431
     432}
     433
     434void GridEditCutpoints::EditHandleRight(int seektype)
     435{
     436    long long seekamount = m_player->GetSeekAmount();
     437    bool cutpointseek=false;
     438
     439    if (seektype == -2 || seekamount == -2)
     440        cutpointseek = true;
     441    else
     442    {
     443        // seektype == 1 for normal, 10 for bigjump
     444        seekamount *= seektype;
     445    }
     446
     447    if (seekamount < 0) // Invalid -- keyframe
     448        seekamount = 1;
     449
     450    m_images->SeekRight(seekamount, cutpointseek);
     451
     452    refreshImages(true);
     453
     454}
     455
     456void GridEditCutpoints::handleSelect(void)
     457{
     458    bool needupdate = false;
     459    // add / update cutpoint
     460    // -or-
     461    // delete / flip / move cutpoint
     462
     463    // if no cut points on screen
     464    //    "Delete Before"
     465    //    "Delete After"
     466
     467    // if on existing cutpoint
     468    //    "Delete cutpoint"
     469    //    "Flip directions"
     470
     471    // FIXME
     472    // if a cutpoint exists on the screen but not on the current frame
     473    //    "Move to current frame"
     474    //    "Add new"
     475
     476    FrameStats fs = m_images->GetMainFrameStats();
     477    //MythPopupBox *pub = new MythPopupBox(gContext->GetMainWindow(), "EDIT_SELECT");
     478    if (fs.cutInd >= 2)
     479    {
     480/*
     481        pub->addLabel("Cutpoint exists:");
     482        pub->addButton("Delete cutpoint?");
     483        pub->addButton("Move cutpoint?");
     484        if (fs.cutInd == 2)
     485            pub->addButton("Flip directions (Cut After)?");
     486        else
     487            pub->addButton("Flip directions (Cut Before)?");
     488        DialogCode dc = pub->ExecPopup();
     489*/
     490        QString title = "";
     491        QString message = "Cutpoint exists:";
     492        QStringList buttons;
     493        buttons.append("Delete cutpoint?");
     494        buttons.append("Move cutpoint?");
     495        if (fs.cutInd == 2)
     496            buttons.append("Flip directions (Cut After)?");
     497        else
     498            buttons.append("Flip directions (Cut Before)?");
     499
     500        DialogCode dc = MythPopupBox::ShowButtonPopup(gContext->GetMainWindow(),
     501                                                      title, message, buttons, kDialogCodeButton0);
     502
     503
     504        if (dc != kDialogCodeRejected)
     505        {
     506            needupdate = true;
     507            if (dc == kDialogCodeButton0)
     508                // Delete cutpoint
     509                m_player->DeleteMark(fs.frameNumber);
     510
     511            else if (dc == kDialogCodeButton1)
     512            {
     513                // Move cutpoint
     514                savedCutpoint = fs.frameNumber;
     515                savedCutType = m_player->deleteMap[fs.frameNumber];
     516                movingCutpoint = true;
     517                // Ensure we're at least at 1 frame motion
     518                int i;
     519                for (i = 0; m_player->GetSeekAmountPos() < 2 && i < 10; i++)
     520                    m_player->UpdateSeekAmount(true);
     521                   
     522            }
     523            else if (dc == kDialogCodeButton2)
     524                // Flip
     525                m_player->ReverseMark(fs.frameNumber);
     526        }
     527    }
     528    else
     529    {
     530/*
     531        pub->addLabel("Insert a new cut point?");
     532        pub->addButton("Delete before this frame");
     533        pub->addButton("Delete after this frame");
     534        DialogCode dc = pub->ExecPopup();
     535*/
     536        QString title = "";
     537        QString message = "Insert New Cutpoint?";
     538        QStringList buttons;
     539        buttons.append("Delete before this frame");
     540        buttons.append("Delete after this frame");
     541        DialogCode dc = MythPopupBox::ShowButtonPopup(gContext->GetMainWindow(),
     542                                                      title, message, buttons, kDialogCodeButton0);
     543
     544        if (dc != kDialogCodeRejected)
     545        {
     546            needupdate = true;
     547            if (dc == kDialogCodeButton0)
     548                // Delete left
     549                m_player->AddMark(fs.frameNumber, MARK_CUT_END);
     550
     551            else if (dc == kDialogCodeButton1)
     552                // Delete Right
     553                m_player->AddMark(fs.frameNumber, MARK_CUT_START);
     554        }
     555    }
     556
     557//    pub->deleteLater();
     558    if (needupdate)
     559    {
     560        refreshCutList();
     561        refreshImages();
     562    }
     563}
     564
     565void GridEditCutpoints::refreshImages(bool mainFrameOnly)
     566{
     567//    VERBOSE(VB_GENERAL, "Refreshing");
     568    m_images->refreshImages(m_gridimages, mainFrameOnly);
     569    if (mainFrameOnly)
     570    {
     571        repaint(m_gridimages[0]->getOuterBorder(), false);
     572        updateStats(true);
     573    }
     574}
     575
     576void GridEditCutpoints::refreshCutList()
     577{
     578    m_images->refreshCutList(m_gridimages);
     579    refreshSlider();
     580}
     581
     582void GridEditCutpoints::refreshSlider()
     583{
     584    if (!m_slider)
     585        return;
     586
     587    m_slider->ClearAll();
     588
     589    const int CUT_LEFT = 0;
     590    const int CUT_RIGHT = 1;
     591
     592    long long startpos = 0;
     593    long long endpos = 0;
     594   
     595    int       lastdirection = CUT_LEFT;
     596
     597    QMap<long long, int> & deleteMap = m_player->deleteMap;
     598    QMap<long long, int>::Iterator i = deleteMap.begin();
     599    for (; i != deleteMap.end(); ++i)
     600    {
     601        long long frame = i.key();
     602        int direction = i.data();
     603
     604        if (direction == CUT_LEFT)
     605        {
     606            endpos = frame;
     607            m_slider->SetRange(startpos, endpos, m_images->GetMaxFrameNumber());
     608
     609            startpos = frame;
     610            lastdirection = CUT_LEFT;
     611        }
     612        else if (direction == CUT_RIGHT)
     613        {
     614            if (lastdirection == CUT_RIGHT)
     615            {
     616                // continuing within a cutpoint
     617                endpos = frame;
     618                m_slider->SetRange(startpos, endpos, m_images->GetMaxFrameNumber());
     619            }
     620
     621            startpos = frame;
     622            lastdirection = CUT_RIGHT;
     623        }
     624    }
     625
     626    if (lastdirection == CUT_RIGHT)
     627    {
     628        // continuing within a cutpoint
     629        endpos = m_images->GetMaxFrameNumber();
     630        m_slider->SetRange(startpos, endpos, m_images->GetMaxFrameNumber());
     631    }
     632}
     633
     634void GridEditCutpoints::updateStats(bool forcerepaint)
     635{
     636    int secs, frames, ss, mm, hh;
     637
     638    FrameStats fs = m_images->GetMainFrameStats();
     639
     640    secs = (int)(fs.frameNumber / m_player->GetFrameRate());
     641    frames = fs.frameNumber - (int)(secs * m_player->GetFrameRate());
     642
     643    ss = secs;
     644    mm = ss / 60;
     645    ss %= 60;
     646    hh = mm / 60;
     647    mm %= 60;
     648
     649    char timestr[128];
     650    sprintf(timestr, "%d:%02d:%02d.%02d", hh, mm, ss, frames);
     651
     652    char framestr[128];
     653    sprintf(framestr, "%lld", fs.frameNumber);
     654
     655    if (m_time)
     656    {
     657        m_time->SetText(timestr);
     658        if (forcerepaint)
     659            repaint(m_time->getScreenArea());
     660    }
     661    if (m_framenum)
     662    {
     663        m_framenum->SetText(framestr);
     664        if (forcerepaint)
     665            repaint(m_framenum->getScreenArea());
     666    }
     667    if (m_cutind)
     668    {
     669        switch (fs.cutInd) {
     670            case 0: m_cutind->SetText("");           break;
     671            case 1: m_cutind->SetText("Cut");        break;
     672            case 2: m_cutind->SetText("Cut Before"); break;
     673            case 3: m_cutind->SetText("Cut After");  break;
     674        }
     675        if (forcerepaint)
     676            repaint(m_cutind->getScreenArea());
     677    }
     678
     679    // Don't need to force update this
     680    if (m_jumpstyle)
     681        m_jumpstyle->SetText(m_player->GetSeekAmountText());
     682
     683    if (m_slider)
     684        m_slider->SetPosition(fs.frameNumber, fs.maxFrameNumber);
     685
     686}
     687
     688void GridEditCutpoints::escape()
     689{
     690    // Make sure we're on the right frame when we go back to
     691    // Normal edit mode
     692    unsetCursor();
     693    accept();
     694}
     695
     696void GridEditCutpoints::SetUpdating(bool active, QString text)
     697{
     698    if (m_updatingind)
     699    {
     700        //VERBOSE(VB_GENERAL, QString("Updating to %1").arg(active));
     701        if (active)
     702        {
     703            m_updatingind->show();
     704            m_updatingind->SetText(text);
     705        }
     706        else
     707            m_updatingind->hide();
     708        repaint(m_updatingind->getScreenArea());
     709    }
     710}
     711
     712void GridEditCutpoints::displayedFramesAreReady()
     713{
     714    if (slowMotionActive)
     715    {
     716        readyForNextFrame=true;
     717        if (!slowMotionTimer->isActive())
     718            slowMotionTimer->start(0);
     719    }
     720}
     721
  • mythtv/libs/libmythtv/grideditcutpoints.h

    diff -r -u -N -X diff.exclude.noxml -x release.20115.0305base -x release.20115.0305gridedit release.20115.0305base/mythtv/libs/libmythtv/grideditcutpoints.h release.20115.0305gridedit/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    void refreshImages(bool mainFrameOnly = false);
     27    void displayedFramesAreReady();
     28
     29  protected:
     30    GridEditCutpoints(MythMainWindow *parent,
     31              NuppelVideoPlayer *player, const char *name = "GridEditCutpoints");
     32   ~GridEditCutpoints();
     33
     34    void displayInitialFrame();
     35
     36    void handleSelect();
     37
     38    void updateStats(bool forcerepaint = false);
     39
     40  protected slots:
     41    void escape();
     42    void updateSlowMotion();
     43
     44  private:
     45    void keyPressEvent(QKeyEvent *e);
     46
     47    // seektype == -2 - cutpoint seek
     48    // seektype ==  1 - normal seek
     49    // seektype == 10 - large seek
     50    void EditHandleLeft(int seektype = 1);
     51    void EditHandleRight(int seektype = 1);
     52    void EditHandlePrevCut()    { EditHandleLeft(-2); };
     53    void EditHandleNextCut()    { EditHandleRight(-2); };
     54    void EditHandleBigJumpRew() { EditHandleLeft(10); };
     55    void EditHandleBigJumpFwd() { EditHandleRight(10); };
     56    void setSlowMotionSpeed();
     57    void refreshCutList();
     58    void refreshSlider();
     59
     60    void SetUpdating(bool active, QString text = "Updating");
     61
     62    // Private Data
     63
     64    NuppelVideoPlayer *m_player;
     65    GridEditImages *m_images;
     66
     67    int   usedSubVideoCount;
     68    myArray<UIGridEditImageType*, MAX_SUB_VIDEOS> m_gridimages;
     69
     70    long long savedCutpoint;
     71    int       savedCutType;
     72    bool      movingCutpoint;
     73
     74    UITextType   *m_framenum;
     75    UITextType   *m_time;
     76    UITextType   *m_cutind;
     77    UITextType   *m_jumpstyle;
     78    UITextType   *m_updatingind;
     79 
     80    UIGridEditSliderType  *m_slider;
     81    QTimer                *slowMotionTimer;
     82    int                    slowMotionDirection;
     83    bool                   slowMotionActive;
     84    bool                   readyForNextFrame;
     85};
     86
     87#endif
  • mythtv/libs/libmythtv/grideditimages.cpp

    diff -r -u -N -X diff.exclude.noxml -x release.20115.0305base -x release.20115.0305gridedit release.20115.0305base/mythtv/libs/libmythtv/grideditimages.cpp release.20115.0305gridedit/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    m_player->EditSeekToFrame(stillMainFrameNumber);
     70}
     71
     72QPixmap *GridEditImages::makeScaledPixmap(const QImage& qim, QSize sz)
     73{
     74    QPixmap *retval;
     75    if (qim.size() == sz)
     76    {
     77        retval = new QPixmap(qim);
     78    }
     79    else
     80    {
     81        retval = new QPixmap(sz);
     82        retval->fill(Qt::black);
     83        QPainter p(retval);
     84
     85        int tl_left = 0;
     86        int tl_top = 0;
     87        if (sz.width() > qim.width())
     88            tl_left += (sz.width() - qim.width()) / 2;
     89
     90        if (sz.height() > qim.height())
     91            tl_top += (sz.height() - qim.height()) / 2;
     92
     93//        VERBOSE(VB_GENERAL, QString("Size mismatch qim(%1, %2) != sz(%3, %4) Shift to (%5, %6)")
     94//             .arg(qim.width()).arg(qim.height())
     95//             .arg(sz.width()).arg(sz.height())
     96//             .arg(tl_left).arg(tl_top));
     97
     98        p.drawImage(tl_left, tl_top, qim);
     99    }
     100    return retval;
     101}
     102
     103#define FRAME_DEBUG 0
     104
     105void GridEditImages::getMainStillFrame()
     106{
     107    if (!stillFrames[0])
     108        getSpecificFrame(0);
     109}
     110
     111bool GridEditImages::getStillFrames(int limits, int maxcount)
     112{
     113    //
     114    // returns true if no more frames to get
     115
     116    // This will fill in all the missing frames in the cache
     117
     118    int i;
     119    bool getFutureFramesFirst = false;
     120
     121    // Get Boundaries for Minus and Plus arrays
     122    // Don't go to absolute end  - it'll slow down seeking
     123    // when you go 1 frame left and right
     124
     125    // Note starti is negative
     126    // Negative frames are before the main frame
     127    // Frame #0 is the main frame
     128    // Positive frames are after the main frame
     129    int starti = stillFrames.minIndex() + 4;
     130    int endi   = stillFrames.maxIndex() - 4;
     131    if (limits == 0) // Current Display only
     132    {
     133        starti = -(usedSubVideoCount+1);
     134        endi   =   usedSubVideoCount+1;
     135
     136    }
     137    else if (limits == 1) // PreCache only
     138    {
     139        starti = -preCacheCountLeft;
     140        endi   = preCacheCountRight;
     141        getFutureFramesFirst = lastmovewasright;
     142    }
     143
     144    // Make sure we don't fall of the front of the file
     145    if (stillMainFrameNumber + starti <= 0)
     146        starti = -(stillMainFrameNumber-1);
     147
     148    // ... or the back of the file
     149    if (endi > (maxFrameNumber - stillMainFrameNumber))
     150        endi = (maxFrameNumber - stillMainFrameNumber);
     151
     152    if (getFutureFramesFirst)
     153    {
     154        // If we're filling out the cache and the last move was to the right
     155        // grab future frames first before and past frames
     156        for (i = 1; i <= endi; i++)
     157        {
     158            if (!stillFrames[i])
     159            {
     160                getSpecificFrame(i);
     161                if (--maxcount == 0) return false;
     162            }
     163        }
     164    }
     165
     166    // grab all appropriate frames
     167
     168    for (i = starti; i <= endi; i++)
     169    {
     170        if (!stillFrames[i])
     171        {
     172            getSpecificFrame(i);
     173            if (--maxcount == 0) return false;
     174        }
     175    }
     176
     177    return true;
     178}
     179
     180void GridEditImages::getSpecificFrame(int i)
     181{
     182    // i is the index withou the cache of frames
     183    if (!stillFrames[i])
     184    {
     185        // get this frame
     186        long long targetFrame = stillMainFrameNumber + i;
     187
     188        if (!m_player->EditSeekToFrame(targetFrame))
     189        {
     190            VERBOSE(VB_GENERAL, QString("Error seeking to Frame[%1] (frame # %2)")
     191                                .arg(i).arg(targetFrame));
     192            checkMaxFrameCount();
     193
     194            stillFramesBig[i] = new QPixmap(videoSizeMain);
     195            stillFramesBig[i]->fill(Qt::gray);
     196
     197            stillFrames[i] = new QPixmap(videoSizeSmall);
     198            stillFrames[i]->fill(Qt::gray);
     199        }
     200        else
     201        {
     202            cutFrames[i] = m_player->GetCutStatus(targetFrame);
     203            QImage qim = m_player->GetScreenGrabOfCurrentFrame(videoSizeMain);
     204
     205            stillFramesBig[i] = makeScaledPixmap(qim, videoSizeMain);
     206            stillFrames[i]    = makeScaledPixmap(qim.scale(videoSizeSmall, QImage::ScaleMin),
     207                                                 videoSizeSmall);
     208
     209#if FRAME_DEBUG
     210            VERBOSE(VB_GENERAL, QString("stillFrames[%1] = %2 (%3)")
     211                    .arg(i)
     212                    .arg(targetFrame)
     213                    .arg(cutFrames[i]));
     214#endif
     215        }
     216    }
     217}
     218
     219void GridEditImages::SetVideoInfo(int vcount, QSize sizeMain, QSize sizeSmall)
     220{
     221    usedSubVideoCount = vcount;
     222    preCacheCountLeft = vcount+1;
     223    preCacheCountRight = vcount+1;
     224    videoSizeMain = sizeMain;
     225    videoSizeSmall = sizeSmall;
     226
     227    // start to grab the current images
     228    getMainStillFrame();
     229    getImagesTimer->start(0);
     230}
     231
     232void GridEditImages::SetPreCacheLeft(int pccount)
     233{
     234    preCacheCountLeft = usedSubVideoCount + pccount;
     235    preCacheCountRight = usedSubVideoCount + 1;
     236    // pccount is too big, then it's a waste of tim to precache
     237    // i.e. 1 second jumps...
     238    // We'll end up just throwing the extra frames away
     239    if (preCacheCountLeft > stillFrames.maxIndex())
     240        preCacheCountLeft = usedSubVideoCount + 1;
     241}
     242
     243void GridEditImages::SetPreCacheRight(int pccount)
     244{
     245    preCacheCountLeft = usedSubVideoCount + 1;
     246    preCacheCountRight = usedSubVideoCount + pccount;
     247    // pccount is too big, then it's a waste of tim to precache
     248    // i.e. 1 second jumps...
     249    // We'll end up just throwing the extra frames away
     250    if (preCacheCountRight > stillFrames.maxIndex())
     251        preCacheCountRight = usedSubVideoCount + 1;
     252}
     253
     254void GridEditImages::updateAllFrames()
     255{
     256    // getStillFrames() returns 'true' when it's gotten all requested frames
     257
     258    // First call is to grab frames to be actively displayed
     259    if (getStillFrames(0, 1))
     260    {
     261        // Tell the editor that all of the currently display frames are ready
     262        m_editor->displayedFramesAreReady();
     263
     264        if (getStillFrames(1, 1)) // Second, try for pre-cache frames
     265        {
     266            if (getStillFrames(2, 1)) // Third, get any other frames till we've filled our storage
     267            {
     268                getImagesTimer->stop();
     269            }
     270        }
     271    }
     272
     273    m_editor->refreshImages();
     274
     275}
     276
     277void GridEditImages::clearStillFrames()
     278{
     279    int i;
     280    for (i = stillFrames.minIndex(); i <= stillFrames.maxIndex(); i++)
     281    {
     282        if (stillFrames[i])
     283        {
     284            delete stillFrames[i];
     285            stillFrames[i] = NULL;
     286        }
     287        if (stillFramesBig[i])
     288        {
     289            delete stillFramesBig[i];
     290            stillFramesBig[i] = NULL;
     291        }
     292        cutFrames[i] = 0;
     293    }
     294}
     295
     296bool GridEditImages::shiftStillFramesLeft(long long offset)
     297{
     298    if (offset > 2 * stillFrames.maxIndex())
     299    {
     300        // Dump all cached data and re-get it
     301        clearStillFrames();
     302    }
     303    else if (offset < 0)
     304    {
     305        VERBOSE(VB_IMPORTANT, QString("Offset (%1) < 0").arg(offset));
     306        // Dump all cached data and re-get it
     307        clearStillFrames();
     308        offset = 0;
     309    }
     310    else if (offset != 0)
     311    {
     312        // Shift backwards in the stream by offset
     313
     314        // All frames will actually shift to the right.
     315        // frame 'n' will become frame 'n+1'
     316        // frame stillFrameMinus[1] will become mainframe
     317        // frame stillFramePlus[max] will drop off
     318
     319        // shove extra frames into the excess space above usedSubVideos
     320
     321        if (offset >= stillMainFrameNumber)
     322            offset = (stillMainFrameNumber-1);
     323
     324        //    printStillFrameStats("Before SL");
     325        int i,j;
     326        int minIndex = stillFrames.minIndex();
     327        int maxIndex = stillFrames.maxIndex();
     328        for (i = 0; i < offset; i++)
     329        {
     330           
     331            if (stillFrames[maxIndex])
     332            {
     333                delete stillFrames[maxIndex];
     334                delete stillFramesBig[maxIndex];
     335            }
     336
     337            for (j = maxIndex; j > minIndex; j--) {
     338                stillFrames[j]    = stillFrames[j-1];
     339                stillFramesBig[j] = stillFramesBig[j-1];
     340                cutFrames[j]      = cutFrames[j-1];
     341            }
     342
     343             stillFrames[minIndex]    = NULL;
     344             stillFramesBig[minIndex] = NULL;
     345             cutFrames[minIndex]      = 0;
     346        }
     347
     348        //   printStillFrameStats("After SL");
     349
     350    }
     351
     352    stillMainFrameNumber -= offset;
     353    if (stillMainFrameNumber < 1)
     354        stillMainFrameNumber = 1;
     355
     356    return (stillFramesBig[0] != NULL);
     357}
     358
     359bool GridEditImages::shiftStillFramesRight(long long offset)
     360{
     361    //VERBOSE(VB_GENERAL, QString("Offset =  %1").arg(offset));
     362    if (offset > 2 * stillFrames.maxIndex())
     363    {
     364        // Dump all cached data and re-get it
     365        clearStillFrames();
     366    }
     367    else if (offset < 0)
     368    {
     369        VERBOSE(VB_IMPORTANT, QString("Offset (%1) < 0").arg(offset));
     370        // Dump all cached data and re-get it
     371        clearStillFrames();
     372        offset = 0;
     373    }
     374    else if (offset != 0)
     375    {
     376
     377        // Shift forwards in the stream by offset
     378
     379        // All frames will actually shift to the left.
     380        // frame 'n' will become frame 'n-1'
     381        // frame stillFramePlus[1] will become mainframe
     382        // frame stillFrameMinus[max] will drop off
     383
     384        // shove extra frames into the excess space above usedSubVideos
     385
     386        if (stillMainFrameNumber + offset > maxFrameNumber)
     387        {
     388            offset = (maxFrameNumber - stillMainFrameNumber);
     389            VERBOSE(VB_GENERAL, QString("new Offset =  %1").arg(offset));
     390        }
     391        //printStillFrameStats("Before SR");
     392
     393        int i,j;
     394        int minIndex = stillFrames.minIndex();
     395        int maxIndex = stillFrames.maxIndex();
     396
     397        for (i = 0; i < offset; i++)
     398        {
     399            if (stillFrames[minIndex])
     400            {
     401                delete stillFrames[minIndex];
     402                delete stillFramesBig[minIndex];
     403            }
     404
     405            for (j = minIndex; j < maxIndex; j++) {
     406                stillFrames[j]    = stillFrames[j+1];
     407                stillFramesBig[j] = stillFramesBig[j+1];
     408                cutFrames[j]      = cutFrames[j+1];
     409            }
     410
     411             stillFrames[maxIndex]    = NULL;
     412             stillFramesBig[maxIndex] = NULL;
     413             cutFrames[maxIndex]      = 0;
     414        }
     415
     416        //printStillFrameStats("After SR");
     417
     418    }
     419    stillMainFrameNumber += offset;
     420    if (stillMainFrameNumber > maxFrameNumber )
     421        stillMainFrameNumber = maxFrameNumber;
     422
     423    return (stillFramesBig[0] != NULL);
     424}
     425
     426void GridEditImages::printStillFrameStats(QString caption)
     427{
     428    int i;
     429    // Debug info for frame cache
     430    QString foundframes= caption + " Found Frames: ";
     431
     432    for (i = stillFrames.minIndex(); i <= stillFrames.maxIndex(); i++)
     433        if (stillFrames[i])
     434            foundframes += QString("%1 ").arg(i);
     435
     436    VERBOSE(VB_GENERAL, foundframes);
     437}
     438
     439void GridEditImages::refreshCutList(myArray<UIGridEditImageType*, MAX_SUB_VIDEOS> &gridimages)
     440{
     441    int i;
     442    for (i = stillFrames.minIndex(); i <= stillFrames.maxIndex(); i++)
     443    {
     444        if (stillFrames[i])
     445        {
     446            cutFrames[i] = m_player->GetCutStatus(stillMainFrameNumber+i);
     447            if (gridimages[i])
     448                gridimages[i]->setCutStatus(cutFrames[i]);
     449        }
     450    }
     451}
     452
     453bool GridEditImages::refreshImages(myArray<UIGridEditImageType*, MAX_SUB_VIDEOS> &gridimages,
     454                                   bool mainFrameOnly)
     455{
     456//    VERBOSE(VB_GENERAL, "Start");
     457    bool alldone = true;
     458    if (!stillFramesBig[0])
     459        VERBOSE(VB_GENERAL, QString("Null Big Main frame %1").arg(stillMainFrameNumber));
     460    gridimages[0]->setPixmap(stillFramesBig[0],
     461                             stillMainFrameNumber,
     462                             cutFrames[0]);
     463
     464    if (!mainFrameOnly)
     465    {
     466        int i;
     467        for (i = -usedSubVideoCount; i <= usedSubVideoCount; i++)
     468        {
     469            if (i != 0) // index 0 done above already
     470            {
     471               if (stillFrames[i] == NULL)
     472                   alldone = false;
     473               gridimages[i]->setPixmap(stillFrames[i],
     474                                        (stillMainFrameNumber + i),
     475                                        cutFrames[i]);
     476            }
     477        }
     478    }
     479
     480//    VERBOSE(VB_GENERAL, "Finish");
     481    return alldone;
     482}
     483
     484
     485// Back up x frames
     486void GridEditImages::SeekLeft(long long seekamount, bool cutpointseek)
     487{
     488    lastmovewasright = false;
     489    getImagesTimer->stop();
     490
     491    if (cutpointseek)
     492        seekamount = m_player->CalcCutPointSeek(stillMainFrameNumber, false);
     493
     494    //VERBOSE(VB_GENERAL, QString("SeekLeft %1, cutpoint = %2").arg(seekamount).arg(cutpointseek));
     495    SetPreCacheLeft(seekamount);
     496    if (!shiftStillFramesLeft(seekamount))
     497    {
     498        //VERBOSE(VB_GENERAL, QString("shiftStillFramesLeft(%1) == false")
     499        //                           .arg(seekamount));
     500        // Need to grab the main frame
     501
     502        getMainStillFrame();
     503    }
     504
     505    getImagesTimer->start(0);
     506}
     507
     508void GridEditImages::SeekRight(long long seekamount, bool cutpointseek)
     509{
     510    lastmovewasright = true;
     511    getImagesTimer->stop();
     512
     513    if (cutpointseek)
     514        seekamount = m_player->CalcCutPointSeek(stillMainFrameNumber, true);
     515
     516    //VERBOSE(VB_GENERAL, QString("SeekRight %1, cutpoint = %2").arg(seekamount).arg(cutpointseek));
     517    SetPreCacheLeft(seekamount);
     518    if (!shiftStillFramesRight(seekamount))
     519    {
     520        //VERBOSE(VB_GENERAL, QString("shiftStillFramesLeft(%1) == false")
     521        //                           .arg(seekamount));
     522        // Need to grab the main frame
     523
     524        getMainStillFrame();
     525    }
     526
     527    getImagesTimer->start(0);
     528}
     529
     530void GridEditImages::checkMaxFrameCount()
     531{
     532    long long tfc = m_player->GetTotalFrameCount();
     533    if (tfc != maxFrameNumberNVP)
     534    {
     535       VERBOSE(VB_GENERAL, QString("Updating: tfc %1, mfn %2, mfnNVP %3")
     536            .arg(tfc).arg(maxFrameNumber).arg(maxFrameNumberNVP));
     537        // Check to see if things changed
     538        maxFrameNumber = tfc;
     539        maxFrameNumberNVP = tfc;
     540    }
     541}
     542
     543FrameStats GridEditImages::GetMainFrameStats()
     544{
     545    FrameStats result;
     546
     547    result.frameNumber = stillMainFrameNumber;
     548    result.cutInd  = cutFrames[0];
     549    result.maxFrameNumber = maxFrameNumber;
     550
     551    return result;
     552}
     553
  • mythtv/libs/libmythtv/grideditimages.h

    diff -r -u -N -X diff.exclude.noxml -x release.20115.0305base -x release.20115.0305gridedit release.20115.0305base/mythtv/libs/libmythtv/grideditimages.h release.20115.0305gridedit/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
     31class FrameStats
     32{
     33    public:
     34        long long frameNumber;
     35        int cutInd;
     36        long long maxFrameNumber;
     37};
     38
     39class MPUBLIC GridEditImages : public QObject
     40{
     41    Q_OBJECT
     42
     43    public:
     44        GridEditImages(GridEditCutpoints *er, NuppelVideoPlayer *player);
     45        ~GridEditImages();
     46
     47        void refreshCutList(myArray<UIGridEditImageType*, MAX_SUB_VIDEOS> &gridimages);
     48
     49        // return true if anything changed
     50        bool refreshImages(myArray<UIGridEditImageType*, MAX_SUB_VIDEOS> &gridimages,
     51                           bool mainFrameOnly);
     52
     53        void SeekLeft(long long seekamount, bool cutpointseek = false);
     54        void SeekRight(long long seekamount, bool cutpointseek = false);
     55
     56        FrameStats GetMainFrameStats();
     57        long long GetCurrentFrameNumber() const { return stillMainFrameNumber; }
     58        long long GetMaxFrameNumber() const { return maxFrameNumber; }
     59
     60        void SetVideoInfo(int vcount, QSize sizeMain, QSize sizeSmall);
     61
     62    protected slots:
     63        void updateAllFrames();
     64
     65    private:
     66        // Private functions
     67        void clearStillFrames();
     68        void printStillFrameStats(QString caption);
     69        void checkMaxFrameCount();
     70
     71        // 'limits' paramter for getStillFrames():
     72        //  0 = get on screen Frames only
     73        //  1 = get preCache Frames only
     74        //  2 = get any necessary frames
     75        bool getStillFrames(int limits, int maxcount = 1000);
     76        void getMainStillFrame();
     77        void getSpecificFrame(int frameindex);
     78
     79        // return true if anything changed
     80        bool shiftStillFramesLeft(long long offset);
     81        bool shiftStillFramesRight(long long offset);
     82
     83        QPixmap *makeScaledPixmap(const QImage& qim, QSize sz);
     84
     85        void SetPreCacheLeft(int pccount);
     86        void SetPreCacheRight(int pccount);
     87
     88        // Private data
     89        // These frames are in the cutlist
     90        // 0 == not cut
     91        // 1 == cut
     92        // 2 == cutpoint (cut left)
     93        // 3 == cutpoint (cut right)
     94        myArray<int, MAX_SUB_VIDEOS> cutFrames;
     95
     96        myArray<QPixmap *, MAX_SUB_VIDEOS> stillFrames;
     97        myArray<QPixmap *, MAX_SUB_VIDEOS> stillFramesBig;
     98
     99        QSize videoSizeMain;
     100        QSize videoSizeSmall;
     101        int   usedSubVideoCount;
     102        int   preCacheCountLeft;
     103        int   preCacheCountRight;
     104        bool lastmovewasright;
     105
     106        long long stillMainFrameNumber; // frame number for big still picture
     107        long long currentFrameNumberNVP; // frame number the NVP should be on
     108        long long maxFrameNumber;       // max frame number override for NVP
     109        long long maxFrameNumberNVP;    // Original NVP number
     110
     111        GridEditCutpoints *m_editor;
     112        NuppelVideoPlayer *m_player;
     113
     114        QTimer            *getImagesTimer;
     115
     116};
     117
     118#endif
  • mythtv/libs/libmythtv/libmythtv.pro

    diff -r -u -N -X diff.exclude.noxml -x release.20115.0305base -x release.20115.0305gridedit release.20115.0305base/mythtv/libs/libmythtv/libmythtv.pro release.20115.0305gridedit/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.noxml -x release.20115.0305base -x release.20115.0305gridedit release.20115.0305base/mythtv/libs/libmythtv/tv_play.cpp release.20115.0305gridedit/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.noxml -x release.20115.0305base -x release.20115.0305gridedit release.20115.0305base/mythtv/libs/libmythtv/tv_play.h release.20115.0305gridedit/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);