Ticket #6322: gridedit.trunk.code.2.patch

File gridedit.trunk.code.2.patch, 89.2 KB (added by anonymous, 11 years ago)
  • mythtv/libs/libmyth/mythdialogs.cpp

    diff -r -u -N -X diff.exclude.noxml -x myth.20136.0308a -x myth.20136.0308b myth.20136.0308a/mythtv/libs/libmyth/mythdialogs.cpp myth.20136.0308b/mythtv/libs/libmyth/mythdialogs.cpp
     
    13271327        rect_to_update = this->geometry();
    13281328    }
    13291329
    1330     redrawRect = redrawRect.unite(r);
     1330    redrawRect = redrawRect.unite(rect_to_update);
    13311331
    13321332    update(redrawRect);
    13331333}
     
    16521652    return GetUIType<UIBlackHoleType>(this, name);
    16531653}
    16541654
     1655UIGridEditImageType* MythThemedDialog::getUIGridEditImageType(const QString &name)
     1656{
     1657    return GetUIType<UIGridEditImageType>(this, name);
     1658}
     1659
     1660UIGridEditSliderType* MythThemedDialog::getUIGridEditSliderType(const QString &name)
     1661{
     1662    return GetUIType<UIGridEditSliderType>(this, name);
     1663}
     1664
    16551665UIImageType* MythThemedDialog::getUIImageType(const QString &name)
    16561666{
    16571667    return GetUIType<UIImageType>(this, name);
  • mythtv/libs/libmyth/mythdialogs.h

    diff -r -u -N -X diff.exclude.noxml -x myth.20136.0308a -x myth.20136.0308b myth.20136.0308a/mythtv/libs/libmyth/mythdialogs.h myth.20136.0308b/mythtv/libs/libmyth/mythdialogs.h
     
    2626class UICheckBoxType;
    2727class UISelectorType;
    2828class UIBlackHoleType;
     29class UIGridEditImageType;
     30class UIGridEditSliderType;
    2931class UIImageType;
    3032class UIImageGridType;
    3133class 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 myth.20136.0308a -x myth.20136.0308b myth.20136.0308a/mythtv/libs/libmyth/uitypes.cpp myth.20136.0308b/mythtv/libs/libmyth/uitypes.cpp
     
    46834683
    46844684// ********************************************************************
    46854685
     4686UIGridEditImageType::UIGridEditImageType(const QString &name)
     4687                     : UIType(name)
     4688{
     4689    cutStatus = 0;
     4690    framenumber = -1;
     4691}
     4692
     4693void UIGridEditImageType::calculateScreenArea()
     4694{
     4695    QRect r = area;
     4696    r.translate(m_parent->GetAreaRect().left(),
     4697                m_parent->GetAreaRect().top());
     4698    screen_area = r;
     4699
     4700    inner_border.setLeft(screen_area.left()+1);
     4701    inner_border.setRight(screen_area.right()-1);
     4702    inner_border.setTop(screen_area.top()+1);
     4703    inner_border.setBottom(screen_area.bottom()-1);
     4704
     4705    outer_border.setLeft(screen_area.left()-1);
     4706    outer_border.setRight(screen_area.right()+1);
     4707    outer_border.setTop(screen_area.top()-1);
     4708    outer_border.setBottom(screen_area.bottom()+1);
     4709}
     4710
     4711void UIGridEditImageType::Draw(QPainter *p, int drawlayer, int context)
     4712{
     4713    if (pmap.isNull())
     4714    {
     4715        QColor drawcolor = QColor( 0, 0, 0);
     4716        p->setBrush(QBrush(Qt::SolidPattern));
     4717        p->setPen(QPen(drawcolor, 2));
     4718        p->drawRect(screen_area);
     4719    }
     4720    else
     4721    {
     4722        p->drawPixmap(screen_area, pmap);
     4723
     4724        p->setBrush(QBrush(Qt::NoBrush));
     4725        p->setPen(QPen(colorSet[cutStatus], 3));
     4726        p->drawRect(inner_border);
     4727        if (cutStatus > 0) {
     4728            p->drawLine(inner_border.topLeft(), inner_border.bottomRight());
     4729            p->drawLine(inner_border.bottomLeft(), inner_border.topRight());
     4730        }
     4731    }
     4732}
     4733
     4734void UIGridEditImageType::setPixmap(QPixmap *new_pmap, long long frame, int new_cutStatus)
     4735{
     4736    // We can get a null new_pmap at the start or end of the video
     4737    if (! new_pmap)
     4738    {
     4739        clearPixmap();
     4740        return;
     4741    }
     4742
     4743    if (frame == framenumber)
     4744    {
     4745        // No change in pixmap (?)
     4746        setCutStatus(new_cutStatus);
     4747        return;
     4748    }
     4749
     4750    pmap = *new_pmap;
     4751    framenumber = frame;
     4752
     4753    if (new_cutStatus >= 0 && new_cutStatus <= 3)
     4754        cutStatus = new_cutStatus;
     4755    else
     4756        cutStatus = 0;
     4757
     4758    refresh();
     4759}
     4760
     4761void UIGridEditImageType::clearPixmap(bool dorefresh)
     4762{
     4763    if (! pmap.isNull())
     4764    {
     4765        pmap = QPixmap();
     4766
     4767        cutStatus = 0;
     4768        framenumber = -1;
     4769        if (dorefresh)
     4770            refresh();
     4771    }
     4772}
     4773
     4774void UIGridEditImageType::setCutStatus(int new_cutStatus)
     4775{
     4776    if (new_cutStatus == cutStatus)
     4777        return;
     4778
     4779    if (new_cutStatus >= 0 && new_cutStatus <= 3)
     4780        cutStatus = new_cutStatus;
     4781    else
     4782        cutStatus = 0;
     4783
     4784    refresh();
     4785}
     4786
     4787// ********************************************************************
     4788
     4789UIGridEditSliderType::UIGridEditSliderType(const QString &name)
     4790                     : UIType(name)
     4791{
     4792    m_drawMap = NULL;
     4793    m_position=0;
     4794}
     4795
     4796void UIGridEditSliderType::calculateScreenArea()
     4797{
     4798    QRect r = area;
     4799    r.translate(m_parent->GetAreaRect().left(),
     4800                m_parent->GetAreaRect().top());
     4801    screen_area = r;
     4802
     4803    if (m_drawMap)
     4804        delete [] m_drawMap;
     4805
     4806    m_drawWidth = area.width();
     4807    m_drawMap = new unsigned char[m_drawWidth];
     4808    for (int i = 0; i < m_drawWidth; i++)
     4809        m_drawMap[i] = 0;
     4810}
     4811
     4812void UIGridEditSliderType::ClearAll()
     4813{
     4814    for (int i = 0; i < m_drawWidth; i++)
     4815        m_drawMap[i] = 0;
     4816    refresh();
     4817}
     4818
     4819void UIGridEditSliderType::SetRange(
     4820        long long fstart, long long fend, long long fcount)
     4821{
     4822    if (fcount <= 0)
     4823    {
     4824        VERBOSE(VB_IMPORTANT, QString("Invalid frame count: %1")
     4825                .arg(fcount));
     4826        return;
     4827    }
     4828    if (fstart < 0)
     4829    {
     4830        VERBOSE(VB_IMPORTANT, QString("Invalid starting frame: %1")
     4831                .arg(fstart));
     4832        return;
     4833    }
     4834    if (fend < 0)
     4835    {
     4836        VERBOSE(VB_IMPORTANT, QString("Invalid ending frame: %1")
     4837                .arg(fend));
     4838        return;
     4839    }
     4840
     4841    if (fstart > fcount) fstart = fcount;
     4842    if (fend > fcount) fend = fcount;
     4843
     4844    int start = (int)((1.0 * fstart * m_drawWidth) / fcount);
     4845    int end   = (int)((1.0 * fend   * m_drawWidth) / fcount);
     4846
     4847    if (start < 0)
     4848        start = 0;
     4849    if (start >= m_drawWidth)
     4850        start = m_drawWidth - 1;
     4851    if (end < 0)
     4852        end = 0;
     4853    if (end >= m_drawWidth)
     4854        end = m_drawWidth - 1;
     4855
     4856    if (end < start)
     4857    {
     4858        int tmp = start;
     4859        start = end;
     4860        end = tmp;
     4861    }
     4862
     4863    for (int i = start; i < end; i++)
     4864        if (m_drawMap[i] < 1)
     4865            m_drawMap[i] = 1;
     4866
     4867    // Mark endpoints
     4868    m_drawMap[start] = 2;
     4869    m_drawMap[end]   = 2;
     4870
     4871    VERBOSE(VB_GENERAL, QString("Range = %1 - %2 (%3 - %4)")
     4872            .arg(start).arg(end)
     4873            .arg(fstart).arg(fend));
     4874    refresh();
     4875}
     4876
     4877void UIGridEditSliderType::SetPosition(
     4878        long long fposition, long long fcount)
     4879{
     4880    if (fcount <= 0)
     4881    {
     4882        VERBOSE(VB_IMPORTANT, QString("Invalid frame count: %1")
     4883                .arg(fcount));
     4884        return;
     4885    }
     4886
     4887    if (fposition < 0)
     4888    {
     4889        VERBOSE(VB_IMPORTANT, QString("Invalid position frame: %1")
     4890                .arg(fposition));
     4891        return;
     4892    }
     4893
     4894    if (fposition > fcount) fposition = fcount;
     4895
     4896    int new_position = (int)(1.0 * fposition * m_drawWidth) / fcount;
     4897
     4898    if (new_position < 0)
     4899        new_position = 0;
     4900    if (new_position >= m_drawWidth)
     4901       new_position = m_drawWidth - 1;
     4902
     4903    if (new_position != m_position)
     4904    {
     4905        m_position = new_position;
     4906        refresh();
     4907    }
     4908}
     4909
     4910void UIGridEditSliderType::Draw(QPainter *p, int drawlayer, int context)
     4911{
     4912    // Draw Background
     4913    p->setPen(QPen(colorSet[0], 2));
     4914    p->setBrush(colorSet[0]);
     4915    p->drawRect(screen_area);
     4916
     4917    // Draw bars
     4918
     4919//    VERBOSE(VB_GENERAL, QString("Starting"));
     4920    int i = 0;
     4921    do {
     4922        int start = 0;
     4923        int end = 0;
     4924
     4925        while (i < m_drawWidth && m_drawMap[i] == 0) i++;
     4926        if (i == m_drawWidth) break;
     4927        start = i;
     4928
     4929        i++;
     4930       
     4931
     4932        while (i < m_drawWidth && m_drawMap[i] == 1) i++;
     4933        end = i;
     4934        if (end == m_drawWidth) end--;
     4935
     4936        // If the next map value is not a normal internal cutpoint
     4937        // increment i so we handle it properly
     4938        if (end+1 < m_drawWidth && m_drawMap[end+1] != 1)
     4939            i++;
     4940
     4941        // start == starting point
     4942        //   end == endingpoint
     4943        {
     4944            QRect r = screen_area;
     4945            r.setLeft(r.left() + start);
     4946            r.setWidth(end - start);
     4947
     4948//            VERBOSE(VB_GENERAL, QString("Cut from (%1, %2) - (%3, %4)")
     4949//                    .arg(r.left()).arg(r.top())
     4950//                    .arg(r.right()).arg(r.bottom()));
     4951
     4952//            VERBOSE(VB_GENERAL, QString("start = %1, m_position = %2, end = %3")
     4953//                    .arg(start)
     4954//                    .arg(m_position)
     4955//                    .arg(end));
     4956           
     4957            if (start <= m_position && m_position <= end)
     4958            {
     4959                p->setPen(QPen(colorSet[4], 2));
     4960                p->setBrush(colorSet[4]);
     4961            }
     4962            else
     4963            {
     4964                p->setPen(QPen(colorSet[1], 2));
     4965                p->setBrush(colorSet[1]);
     4966            }
     4967            p->drawRect(r);
     4968
     4969            p->setPen(QPen(colorSet[2], 2));
     4970            p->setBrush(colorSet[2]);
     4971            if (m_drawMap[start] == 2)
     4972                p->drawLine(r.topLeft(), r.bottomLeft());
     4973            if (m_drawMap[end] == 2)
     4974                p->drawLine(r.topRight(), r.bottomRight());
     4975
     4976        }
     4977    } while (i < m_drawWidth);
     4978
     4979    // Draw Current Position Mark
     4980
     4981    QPoint ptop(screen_area.left() + m_position, screen_area.top());
     4982    QPoint pbot(screen_area.left() + m_position, screen_area.bottom());
     4983
     4984    p->setPen(QPen(colorSet[3], 2));
     4985    p->setBrush(colorSet[3]);
     4986    p->drawLine(ptop, pbot);
     4987}
     4988
     4989// ********************************************************************
     4990
    46864991UIKeyType::UIKeyType(const QString &name)
    46874992         : UIType(name)
    46884993{
  • mythtv/libs/libmyth/uitypes.h

    diff -r -u -N -X diff.exclude.noxml -x myth.20136.0308a -x myth.20136.0308b myth.20136.0308a/mythtv/libs/libmyth/uitypes.h myth.20136.0308b/mythtv/libs/libmyth/uitypes.h
     
    11721172    QRect area;
    11731173};
    11741174
     1175class MPUBLIC UIGridEditImageType : public UIType
     1176{
     1177    Q_OBJECT
     1178
     1179  public:
     1180
     1181    UIGridEditImageType(const QString &name);
     1182    void calculateScreenArea();
     1183    void setArea(QRect an_area)     { area = an_area; };
     1184
     1185    void setOutlineColor(QColor c)  { colorSet[0] = c; };
     1186    void setCutColor(QColor c)      { colorSet[1] = c; };
     1187    void setCutPointColor(QColor c)
     1188    {
     1189         colorSet[2] = c; // Cut before
     1190         colorSet[3] = c; // Cut after
     1191    };
     1192
     1193    virtual void Draw(QPainter *, int, int);
     1194    void setPixmap(QPixmap *new_pmap, long long frame, int new_cutStatus);
     1195 
     1196    void clearPixmap(bool dorefresh=true);
     1197    void setCutStatus(int new_cutStatus);
     1198
     1199    QRect getOuterBorder() { return outer_border; };
     1200  protected:
     1201
     1202    QRect    area;
     1203    QRect    inner_border;
     1204    QRect    outer_border;
     1205    QPixmap  pmap;
     1206    long long framenumber; // for consistency checking
     1207    int      cutStatus;
     1208    QColor   colorSet[4];
     1209};
     1210
     1211class MPUBLIC UIGridEditSliderType : public UIType
     1212{
     1213    Q_OBJECT
     1214
     1215  public:
     1216
     1217    UIGridEditSliderType(const QString &name);
     1218    void calculateScreenArea();
     1219    void setArea(QRect an_area)     { area = an_area; };
     1220
     1221    void setFillColor(QColor c)     { colorSet[0] = c; };
     1222    void setCutColor(QColor c)      { colorSet[1] = c; };
     1223    void setCutPointColor(QColor c) { colorSet[2] = c; };
     1224    void setPositionColor(QColor c) { colorSet[3] = c; };
     1225    void setInCutColor(QColor c)    { colorSet[4] = c; };
     1226
     1227    void ClearAll();
     1228    void SetRange(long long fstart, long long fend, long long fcount);
     1229    void SetPosition(long long fposition, long long fcount);
     1230
     1231    virtual void Draw(QPainter *, int, int);
     1232  protected:
     1233
     1234    QRect          area;
     1235    unsigned char *m_drawMap;
     1236    int            m_drawWidth;
     1237    int            m_position;
     1238
     1239    QColor         colorSet[5];
     1240};
     1241
     1242
    11751243class MPUBLIC UIKeyType : public UIType
    11761244{
    11771245    Q_OBJECT
  • mythtv/libs/libmyth/xmlparse.cpp

    diff -r -u -N -X diff.exclude.noxml -x myth.20136.0308a -x myth.20136.0308b myth.20136.0308a/mythtv/libs/libmyth/xmlparse.cpp myth.20136.0308b/mythtv/libs/libmyth/xmlparse.cpp
     
    13631363            {
    13641364                parseBlackHole(container, info);
    13651365            }
     1366            else if (info.tagName() == "grideditimage")
     1367            {
     1368                parseGridEditImage(container, info);
     1369            }
     1370            else if (info.tagName() == "grideditslider")
     1371            {
     1372                parseGridEditSlider(container, info);
     1373            }
    13661374            else if (info.tagName() == "area")
    13671375            {
    13681376                area = parseRect(getFirstText(info));
     
    31263134    container->AddType(bh);
    31273135}
    31283136
     3137
     3138void XMLParse::parseGridEditImage(LayerSet *container, QDomElement &element)
     3139{
     3140    QRect area;
     3141    QColor outlineColor;
     3142    QColor cutColor;
     3143    QColor cutPointColor;
     3144    bool   haveOutlineColor = false;
     3145    bool   haveCutColor = false;
     3146    bool   haveCutPointColor = false;
     3147
     3148    QString name = element.attribute("name", "");
     3149    if (name.isNull() || name.isEmpty())
     3150    {
     3151        VERBOSE(VB_IMPORTANT, LOC_WARN + "GridEditImage needs a name");
     3152        return;
     3153    }
     3154
     3155    for (QDomNode child = element.firstChild(); !child.isNull();
     3156         child = child.nextSibling())
     3157    {
     3158        QDomElement info = child.toElement();
     3159        if (!info.isNull())
     3160        {
     3161            if (info.tagName() == "area")
     3162            {
     3163                area = parseRect(getFirstText(info));
     3164                normalizeRect(area);
     3165            }
     3166            else if (info.tagName() == "outlinecolor")
     3167            {
     3168                haveOutlineColor = true;
     3169                outlineColor = getFirstText(info);
     3170            }
     3171            else if (info.tagName() == "cutcolor")
     3172            {
     3173                haveCutColor = true;
     3174                cutColor = getFirstText(info);
     3175            }
     3176            else if (info.tagName() == "cutpointcolor")
     3177            {
     3178                haveCutPointColor = true;
     3179                cutPointColor = getFirstText(info);
     3180            }
     3181            else
     3182            {
     3183                VERBOSE(VB_IMPORTANT, LOC_WARN +
     3184                        QString("Unknown tag '%1' in grideditimage '%2'")
     3185                        .arg(info.tagName()).arg(name));
     3186                return;
     3187            }
     3188        }
     3189    }
     3190
     3191    if (!haveOutlineColor)
     3192    {
     3193        VERBOSE(VB_IMPORTANT, LOC_WARN +
     3194                QString("Missing tag 'outlinecolor' in grideditimage '%1'")
     3195                .arg(name));
     3196        return;
     3197    }
     3198
     3199    if (!haveCutColor)
     3200    {
     3201        VERBOSE(VB_IMPORTANT, LOC_WARN +
     3202                QString("Missing tag 'cutcolor' in grideditimage '%1'")
     3203                .arg(name));
     3204        return;
     3205    }
     3206
     3207    if (!haveCutPointColor)
     3208    {
     3209        VERBOSE(VB_IMPORTANT, LOC_WARN +
     3210                QString("Missing tag 'cutpointcolor' in grideditimage '%1'")
     3211                .arg(name));
     3212        return;
     3213    }
     3214
     3215    UIGridEditImageType *gei = new UIGridEditImageType(name);
     3216    gei->SetScreen(wmult, hmult);
     3217    gei->setArea(area);
     3218    gei->setOutlineColor(outlineColor);
     3219    gei->setCutColor(cutColor);
     3220    gei->setCutPointColor(cutPointColor);
     3221    gei->SetParent(container);
     3222    gei->calculateScreenArea();
     3223    gei->clearPixmap(false);
     3224    container->AddType(gei);
     3225}
     3226
     3227void XMLParse::parseGridEditSlider(LayerSet *container, QDomElement &element)
     3228{
     3229    QRect area;
     3230    QColor fillColor;
     3231    QColor cutColor;
     3232    QColor inCutColor;
     3233    QColor cutPointColor;
     3234    QColor positionColor;
     3235    bool   haveFillColor = false;
     3236    bool   haveCutColor = false;
     3237    bool   haveInCutColor = false;
     3238    bool   haveCutPointColor = false;
     3239    bool   havePositionColor = false;
     3240
     3241    QString name = element.attribute("name", "");
     3242    if (name.isNull() || name.isEmpty())
     3243    {
     3244        VERBOSE(VB_IMPORTANT, LOC_WARN + "GridEditSlider needs a name");
     3245        return;
     3246    }
     3247
     3248    for (QDomNode child = element.firstChild(); !child.isNull();
     3249         child = child.nextSibling())
     3250    {
     3251        QDomElement info = child.toElement();
     3252        if (!info.isNull())
     3253        {
     3254            if (info.tagName() == "area")
     3255            {
     3256                area = parseRect(getFirstText(info));
     3257                normalizeRect(area);
     3258            }
     3259            else if (info.tagName() == "fillcolor")
     3260            {
     3261                haveFillColor = true;
     3262                fillColor = getFirstText(info);
     3263            }
     3264            else if (info.tagName() == "cutcolor")
     3265            {
     3266                haveCutColor = true;
     3267                cutColor = getFirstText(info);
     3268            }
     3269            else if (info.tagName() == "incutcolor")
     3270            {
     3271                haveInCutColor = true;
     3272                inCutColor = getFirstText(info);
     3273            }
     3274            else if (info.tagName() == "cutpointcolor")
     3275            {
     3276                haveCutPointColor = true;
     3277                cutPointColor = getFirstText(info);
     3278            }
     3279            else if (info.tagName() == "positioncolor")
     3280            {
     3281                havePositionColor = true;
     3282                positionColor = getFirstText(info);
     3283            }
     3284            else
     3285            {
     3286                VERBOSE(VB_IMPORTANT, LOC_WARN +
     3287                        QString("Unknown tag '%1' in grideditslider '%2'")
     3288                        .arg(info.tagName()).arg(name));
     3289                return;
     3290            }
     3291        }
     3292    }
     3293
     3294    if (!haveFillColor)
     3295    {
     3296        VERBOSE(VB_IMPORTANT, LOC_WARN +
     3297                QString("Missing tag 'fillcolor' in grideditslider '%1'")
     3298                .arg(name));
     3299        return;
     3300    }
     3301
     3302    if (!haveCutColor)
     3303    {
     3304        VERBOSE(VB_IMPORTANT, LOC_WARN +
     3305                QString("Missing tag 'cutcolor' in grideditslider '%1'")
     3306                .arg(name));
     3307        return;
     3308    }
     3309
     3310    if (!haveInCutColor)
     3311    {
     3312        VERBOSE(VB_IMPORTANT, LOC_WARN +
     3313                QString("Missing tag 'incutcolor' in grideditslider '%1'")
     3314                .arg(name));
     3315        return;
     3316    }
     3317
     3318    if (!haveCutPointColor)
     3319    {
     3320        VERBOSE(VB_IMPORTANT, LOC_WARN +
     3321                QString("Missing tag 'cutpointcolor' in grideditslider '%1'")
     3322                .arg(name));
     3323        return;
     3324    }
     3325
     3326    if (!havePositionColor)
     3327    {
     3328        VERBOSE(VB_IMPORTANT, LOC_WARN +
     3329                QString("Missing tag 'positioncolor' in grideditslider '%1'")
     3330                .arg(name));
     3331        return;
     3332    }
     3333
     3334    UIGridEditSliderType *ges = new UIGridEditSliderType(name);
     3335    ges->SetScreen(wmult, hmult);
     3336    ges->setArea(area);
     3337    ges->setFillColor(fillColor);
     3338    ges->setCutColor(cutColor);
     3339    ges->setInCutColor(inCutColor);
     3340    ges->setCutPointColor(cutPointColor);
     3341    ges->setPositionColor(positionColor);
     3342    ges->SetParent(container);
     3343    ges->calculateScreenArea();
     3344    container->AddType(ges);
     3345}
     3346
    31293347void XMLParse::parseListBtnArea(LayerSet *container, QDomElement &element)
    31303348{
    31313349    int context = -1;
  • mythtv/libs/libmyth/xmlparse.h

    diff -r -u -N -X diff.exclude.noxml -x myth.20136.0308a -x myth.20136.0308b myth.20136.0308a/mythtv/libs/libmyth/xmlparse.h myth.20136.0308b/mythtv/libs/libmyth/xmlparse.h
     
    4747    void parseCheckBox(LayerSet *, QDomElement &);
    4848    void parseSelector(LayerSet *, QDomElement &);
    4949    void parseBlackHole(LayerSet *, QDomElement &);
     50    void parseGridEditImage(LayerSet *, QDomElement &);
     51    void parseGridEditSlider(LayerSet *, QDomElement &);
    5052    void parseListBtnArea(LayerSet *, QDomElement &);
    5153    void parseListTreeArea(LayerSet *, QDomElement &);
    5254    void parseKeyboard(LayerSet *, QDomElement &);
  • mythtv/libs/libmythtv/NuppelVideoPlayer.cpp

    diff -r -u -N -X diff.exclude.noxml -x myth.20136.0308a -x myth.20136.0308b myth.20136.0308a/mythtv/libs/libmythtv/NuppelVideoPlayer.cpp myth.20136.0308b/mythtv/libs/libmythtv/NuppelVideoPlayer.cpp
     
    5555#include "mythverbose.h"
    5656#include "myth_imgconvert.h"
    5757
     58#include "grideditcutpoints.h"
     59
    5860extern "C" {
    5961#include "vbitext/vbi.h"
    6062#include "vsync.h"
     
    166168      decoder_thread_alive(true),   killplayer(false),
    167169      killvideo(false),             livetv(false),
    168170      watchingrecording(false),     editmode(false),
     171      hideedits(false),
    169172      resetvideo(false),            using_null_videoout(false),
    170173      no_audio_in(false),           no_audio_out(false),
    171174      transcoding(false),
     
    175178      bookmarkseek(0),              previewFromBookmark(false),
    176179      // Seek
    177180      fftime(0),                    seekamountpos(4),
    178       seekamount(30),               exactseeks(false),
     181      allow_pagesize(false),        half_page(0),
     182      seekamount(30),               seekamounttext("30 Frames"),
     183      exactseeks(false),
    179184      // Playback misc.
    180185      videobuf_retries(0),          framesPlayed(0),
    181186      totalFrames(0),               totalLength(0),
     
    225230      yuv_need_copy(false),         yuv_desired_size(0,0),
    226231      yuv_scaler(NULL),             yuv_frame_scaled(NULL),
    227232      yuv_scaler_in_size(0,0),      yuv_scaler_out_size(0,0),
     233      // Grid Editing
     234      grid_edit_image_buffer(NULL), grid_edit_image_buffer_length(0),
    228235      // Filters
    229236      videoFiltersForProgram(""),   videoFiltersOverride(""),
    230237      postfilt_width(0),            postfilt_height(0),
     
    371378        output_jmeter = NULL;
    372379    }
    373380
     381    if (grid_edit_image_buffer)
     382    {
     383        delete [] grid_edit_image_buffer;
     384        grid_edit_image_buffer = NULL;
     385        grid_edit_image_buffer_length=0;
     386    }
     387
    374388    ShutdownYUVResize();
    375389}
    376390
     
    16051619    return retval;
    16061620}
    16071621
     1622
     1623QImage NuppelVideoPlayer::GetScreenGrabOfCurrentFrame(QSize size)
     1624{
     1625
     1626    unsigned char *data      = NULL;
     1627    VideoFrame    *frame     = NULL;
     1628    AVPicture      orig;
     1629    AVPicture      retbuf;
     1630    bzero(&orig,   sizeof(AVPicture));
     1631    bzero(&retbuf, sizeof(AVPicture));
     1632
     1633    QImage edit_scaled_img;
     1634    int vw, vh;
     1635    if (!(frame = GetCurrentFrame(vw, vh)))
     1636    {
     1637        return edit_scaled_img;
     1638    }
     1639
     1640    if (!(data = frame->buf))
     1641    {
     1642        ReleaseCurrentFrame(frame);
     1643        return edit_scaled_img;
     1644    }
     1645
     1646    avpicture_fill(&orig, data, PIX_FMT_YUV420P,
     1647                   video_dim.width(), video_dim.height());
     1648
     1649    avpicture_deinterlace(&orig, &orig, PIX_FMT_YUV420P,
     1650                          video_dim.width(), video_dim.height());
     1651
     1652    int bufflen = video_dim.width() * video_dim.height() * 4;
     1653    if (!grid_edit_image_buffer)
     1654    {
     1655        grid_edit_image_buffer = new unsigned char[bufflen];
     1656        grid_edit_image_buffer_length = bufflen;
     1657    }
     1658    else if (bufflen > grid_edit_image_buffer_length)
     1659    {
     1660        delete [] grid_edit_image_buffer;
     1661        grid_edit_image_buffer = new unsigned char[bufflen];
     1662        grid_edit_image_buffer_length = bufflen;
     1663    }
     1664
     1665    // Connect outputbuf to retbuf
     1666    avpicture_fill(&retbuf, grid_edit_image_buffer, PIX_FMT_RGBA32,
     1667                   video_dim.width(), video_dim.height());
     1668
     1669    // convert from orig into retbuf(grid_edit_image_buffer)
     1670    img_convert(&retbuf, PIX_FMT_RGBA32, &orig, PIX_FMT_YUV420P,
     1671                video_dim.width(), video_dim.height());
     1672
     1673    QImage tmpimage = QImage(grid_edit_image_buffer, video_dim.width(), video_dim.height(),
     1674                             QImage::Format_RGB32);
     1675
     1676    ReleaseCurrentFrame(frame);
     1677
     1678    edit_scaled_img =  tmpimage.scaled(size, Qt::KeepAspectRatio).rgbSwapped();
     1679   
     1680    return edit_scaled_img;
     1681}
     1682
    16081683void NuppelVideoPlayer::ReleaseCurrentFrame(VideoFrame *frame)
    16091684{
    16101685    if (frame)
     
    49885063
    49895064    dialogname = "";
    49905065
     5066    osd->HideAllExcept("editmode");
     5067
    49915068    QMap<QString, QString> infoMap;
    49925069    player_ctx->LockPlayingInfo(__FILE__, __LINE__);
    49935070    player_ctx->playingInfo->ToMap(infoMap);
     
    50525129    player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
    50535130}
    50545131
     5132bool NuppelVideoPlayer::EditSeekToFrame(long long targetFrame)
     5133{
     5134    bool tmpexactseeks = exactseeks;
     5135    GetDecoder()->setExactSeeks(true);
     5136
     5137//    VERBOSE(VB_GENERAL, QString("Before current frame = %1, going to frame %2")
     5138//           .arg(GetFramesPlayed())
     5139//           .arg(targetFrame));
     5140
     5141    if (framesPlayed > targetFrame)
     5142    {
     5143        // seek back
     5144        rewindtime = framesPlayed - targetFrame;
     5145        while (rewindtime != 0)
     5146            usleep(1000);
     5147    }
     5148    else
     5149    {
     5150        // seek forward
     5151        fftime = targetFrame - framesPlayed;
     5152        while (fftime != 0)
     5153            usleep(1000);
     5154
     5155    }
     5156//    VERBOSE(VB_GENERAL, QString("After current frame = %1")
     5157//           .arg(GetFramesPlayed()));
     5158    GetDecoder()->setExactSeeks(tmpexactseeks);
     5159    return (targetFrame == framesPlayed);
     5160}
     5161
     5162void NuppelVideoPlayer::EditHandleClearMap()
     5163{
     5164    QMap<long long, int>::Iterator it;
     5165    for (it = deleteMap.begin(); it != deleteMap.end(); ++it)
     5166        osd->HideEditArrow(it.key(), *it);
     5167
     5168    deleteMap.clear();
     5169    UpdateEditSlider();
     5170}
     5171
     5172void NuppelVideoPlayer::EditHandleInvertMap()
     5173{
     5174    QMap<long long, int>::Iterator it;
     5175    for (it = deleteMap.begin(); it != deleteMap.end(); ++it)
     5176        ReverseMark(it.key());
     5177
     5178    UpdateEditSlider();
     5179    UpdateTimeDisplay();
     5180}
     5181
     5182void NuppelVideoPlayer::EditHandleLoadCommSkip()
     5183{
     5184    if (hascommbreaktable)
     5185    {
     5186        commBreakMapLock.lock();
     5187        QMap<long long, int>::Iterator it;
     5188        for (it = commBreakMap.begin(); it != commBreakMap.end(); ++it)
     5189        {
     5190            if (!deleteMap.contains(it.key()))
     5191            {
     5192                if (*it == MARK_COMM_START)
     5193                    AddMark(it.key(), MARK_CUT_START);
     5194                else
     5195                    AddMark(it.key(), MARK_CUT_END);
     5196            }
     5197        }
     5198        commBreakMapLock.unlock();
     5199        UpdateEditSlider();
     5200        UpdateTimeDisplay();
     5201    }
     5202}
     5203
    50555204bool NuppelVideoPlayer::DoKeypress(QKeyEvent *e)
    50565205{
    50575206    bool handled = false;
     
    51315280            UpdateTimeDisplay();
    51325281        }
    51335282        else if (action == "CLEARMAP")
    5134         {
    5135             QMap<long long, int>::Iterator it;
    5136             for (it = deleteMap.begin(); it != deleteMap.end(); ++it)
    5137                 osd->HideEditArrow(it.key(), *it);
    5138 
    5139             deleteMap.clear();
    5140             UpdateEditSlider();
    5141         }
     5283            EditHandleClearMap();
    51425284        else if (action == "INVERTMAP")
    5143         {
    5144             QMap<long long, int>::Iterator it;
    5145             for (it = deleteMap.begin(); it != deleteMap.end(); ++it)
    5146                 ReverseMark(it.key());
    5147 
    5148             UpdateEditSlider();
    5149             UpdateTimeDisplay();
    5150         }
     5285            EditHandleInvertMap();
    51515286        else if (action == "LOADCOMMSKIP")
    5152         {
    5153             if (hascommbreaktable)
    5154             {
    5155                 commBreakMapLock.lock();
    5156                 QMap<long long, int>::Iterator it;
    5157                 for (it = commBreakMap.begin(); it != commBreakMap.end(); ++it)
    5158                 {
    5159                     if (!deleteMap.contains(it.key()))
    5160                     {
    5161                         if (*it == MARK_COMM_START)
    5162                             AddMark(it.key(), MARK_CUT_START);
    5163                         else
    5164                             AddMark(it.key(), MARK_CUT_END);
    5165                     }
    5166                 }
    5167                 commBreakMapLock.unlock();
    5168                 UpdateEditSlider();
    5169                 UpdateTimeDisplay();
    5170             }
    5171         }
     5287            EditHandleLoadCommSkip();
    51725288        else if (action == "PREVCUT")
    51735289        {
    51745290            int old_seekamount = seekamount;
     
    52145330            UpdateEditSlider();
    52155331            UpdateTimeDisplay();
    52165332        }
    5217         else if (action == "ESCAPE" || action == "MENU" ||
    5218                  action == "TOGGLEEDIT")
     5333        else if (action == "TOGGLEEDIT" || action == "MENU")
     5334              m_tv->ShowEditRecordingGrid();
     5335        else if (action == "ESCAPE")
    52195336        {
    52205337            DisableEdit();
    52215338            retval = false;
     
    52285345    return retval;
    52295346}
    52305347
     5348void NuppelVideoPlayer::ShowEditRecordingGrid(void)
     5349{
     5350    // Completely hide the OSD
     5351    osd->HideAll();
     5352    hideedits = true;
     5353
     5354    GridEditCutpoints::Run(this);
     5355
     5356    if (grid_edit_image_buffer)
     5357    {
     5358        delete [] grid_edit_image_buffer;
     5359        grid_edit_image_buffer = NULL;
     5360        grid_edit_image_buffer_length = 0;
     5361    }
     5362
     5363    allow_pagesize = false;
     5364    hideedits = false;
     5365
     5366    // Show OSD
     5367
     5368    QMap<QString, QString> infoMap;
     5369    player_ctx->LockPlayingInfo(__FILE__, __LINE__);
     5370    player_ctx->playingInfo->ToMap(infoMap);
     5371    infoMap.detach();
     5372    player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
     5373
     5374    osd->SetText("editmode", infoMap, -1);
     5375
     5376    UpdateEditSlider();
     5377    UpdateTimeDisplay();
     5378    if (seekamountpos == 3 || seekamountpos == 4)
     5379        UpdateSeekAmount(true);
     5380    else
     5381        UpdateSeekAmountDisplay();
     5382
     5383    QMap<long long, int>::Iterator it;
     5384    for (it = deleteMap.begin(); it != deleteMap.end(); ++it)
     5385         AddMark(it.key(), *it);
     5386}
     5387
    52315388AspectOverrideMode NuppelVideoPlayer::GetAspectOverride(void) const
    52325389{
    52335390    if (videoOutput)
     
    53045461
    53055462void NuppelVideoPlayer::UpdateSeekAmount(bool up)
    53065463{
    5307     if (seekamountpos > 0 && !up)
    5308         seekamountpos--;
    5309     if (seekamountpos < 9 && up)
    5310         seekamountpos++;
     5464    if (up)
     5465    {
     5466        if (seekamountpos < 11)
     5467            seekamountpos++;
     5468        if (allow_pagesize)
     5469        {
     5470            if (seekamountpos == 1)
     5471                seekamountpos = 2;
     5472        }
     5473        else
     5474        {
     5475            if (seekamountpos == 3 || seekamountpos == 4)
     5476                seekamountpos = 5;
     5477        }
     5478    }
     5479    else
     5480    {
     5481        if (seekamountpos > 0)
     5482            seekamountpos--;
     5483        if (allow_pagesize)
     5484        {
     5485            if (seekamountpos == 1)
     5486                seekamountpos =0;
     5487        }
     5488        else
     5489        {
     5490            if (seekamountpos == 3 || seekamountpos == 4)
     5491                seekamountpos = 2;
     5492        }
     5493    }
    53115494
    53125495    QString text = "";
    53135496
    53145497    switch (seekamountpos)
    53155498    {
    5316         case 0: text = QObject::tr("cut point"); seekamount = -2; break;
    5317         case 1: text = QObject::tr("keyframe"); seekamount = -1; break;
    5318         case 2: text = QObject::tr("1 frame"); seekamount = 1; break;
    5319         case 3: text = QObject::tr("0.5 seconds"); seekamount = (int)roundf(video_frame_rate / 2); break;
    5320         case 4: text = QObject::tr("%n second(s)", "", 1); seekamount = (int)roundf(video_frame_rate); break;
    5321         case 5: text = QObject::tr("%n second(s)", "", 5); seekamount = (int)roundf(video_frame_rate * 5); break;
    5322         case 6: text = QObject::tr("%n second(s)", "", 20); seekamount = (int)roundf(video_frame_rate * 20); break;
    5323         case 7: text = QObject::tr("%n minute(s)", "", 1); seekamount = (int)roundf(video_frame_rate * 60); break;
    5324         case 8: text = QObject::tr("%n minute(s)", "", 5); seekamount = (int)roundf(video_frame_rate * 300); break;
    5325         case 9: text = QObject::tr("%n minute(s)", "", 10); seekamount = (int)roundf(video_frame_rate * 600); break;
     5499        case  0: text = QObject::tr("cut point"); seekamount = -2; break;
     5500
     5501        // Only for non-edit grid
     5502        case  1: text = QObject::tr("keyframe"); seekamount = -1; break;
     5503        // Only for non-edit grid
     5504
     5505        case  2: text = QObject::tr("1 frame"); seekamount = 1; break;
     5506
     5507        // Case 3 & 4 are for the edit grid only
     5508        case  3: text = QObject::tr("1/2 Page");    seekamount =  half_page; break;
     5509        case  4: text = QObject::tr("Full Page");   seekamount =  2*half_page; break;
     5510        // Case 3 & 4 are for the edit grid only
     5511   
     5512        case  5: text = QObject::tr("0.5 seconds"); seekamount = (int)roundf(video_frame_rate / 2); break;
     5513        case  6: text = QObject::tr("%n second(s)", "", 1); seekamount = (int)roundf(video_frame_rate); break;
     5514        case  7: text = QObject::tr("%n second(s)", "", 5); seekamount = (int)roundf(video_frame_rate * 5); break;
     5515        case  8: text = QObject::tr("%n second(s)", "", 20); seekamount = (int)roundf(video_frame_rate * 20); break;
     5516        case  9: text = QObject::tr("%n minute(s)", "", 1); seekamount = (int)roundf(video_frame_rate * 60); break;
     5517        case 10: text = QObject::tr("%n minute(s)", "", 5); seekamount = (int)roundf(video_frame_rate * 300); break;
     5518        case 11: text = QObject::tr("%n minute(s)", "", 10); seekamount = (int)roundf(video_frame_rate * 600); break;
    53265519        default: text = QObject::tr("error"); seekamount = (int)roundf(video_frame_rate); break;
    53275520    }
    53285521
     5522    seekamounttext = text;
     5523    UpdateSeekAmountDisplay();
     5524}
     5525
     5526void NuppelVideoPlayer::UpdateSeekAmountDisplay(void)
     5527{
    53295528    QMap<QString, QString> infoMap;
    5330     infoMap["seekamount"] = text;
    5331     osd->SetText("editmode", infoMap, -1);
     5529    infoMap["seekamount"] = seekamounttext;
     5530    if (!hideedits)
     5531        osd->SetText("editmode", infoMap, -1);
    53325532}
    53335533
    53345534void NuppelVideoPlayer::UpdateTimeDisplay(void)
     
    53585558    infoMap["timedisplay"] = timestr;
    53595559    infoMap["framedisplay"] = framestr;
    53605560    infoMap["cutindicator"] = cutmarker;
    5361     osd->SetText("editmode", infoMap, -1);
     5561    if (!hideedits)
     5562        osd->SetText("editmode", infoMap, -1);
    53625563}
    53635564
    53645565void NuppelVideoPlayer::HandleSelect(bool allowSelectNear)
     
    54905691
    54915692void NuppelVideoPlayer::UpdateEditSlider(void)
    54925693{
    5493     osd->DoEditSlider(deleteMap, framesPlayed, totalFrames);
     5694    if (!hideedits)
     5695        osd->DoEditSlider(deleteMap, framesPlayed, totalFrames);
    54945696}
    54955697
    54965698void NuppelVideoPlayer::AddMark(long long frames, int type)
    54975699{
    54985700    deleteMap[frames] = type;
    5499     osd->ShowEditArrow(frames, totalFrames, type);
     5701    if (!hideedits)
     5702        osd->ShowEditArrow(frames, totalFrames, type);
    55005703}
    55015704
    55025705void NuppelVideoPlayer::DeleteMark(long long frames)
    55035706{
    5504     osd->HideEditArrow(frames, deleteMap[frames]);
     5707    if (!hideedits)
     5708        osd->HideEditArrow(frames, deleteMap[frames]);
    55055709    deleteMap.remove(frames);
    55065710}
    55075711
    55085712void NuppelVideoPlayer::ReverseMark(long long frames)
    55095713{
    5510     osd->HideEditArrow(frames, deleteMap[frames]);
     5714    if (!hideedits)
     5715        osd->HideEditArrow(frames, deleteMap[frames]);
    55115716
    55125717    if (deleteMap[frames] == MARK_CUT_END)
    55135718        deleteMap[frames] = MARK_CUT_START;
    55145719    else
    55155720        deleteMap[frames] = MARK_CUT_END;
    55165721
    5517     osd->ShowEditArrow(frames, totalFrames, deleteMap[frames]);
     5722    if (!hideedits)
     5723        osd->ShowEditArrow(frames, totalFrames, deleteMap[frames]);
     5724}
     5725
     5726long long NuppelVideoPlayer::CalcCutPointSeek(long long baseframe, bool right)
     5727{
     5728    QMap<long long, int>::Iterator i = deleteMap.begin();                                     
     5729    long long framenum = -1;
     5730    long long seekcount = 0;
     5731    if (right)                                                                                 
     5732    {
     5733        for (; i != deleteMap.end(); ++i)                                                     
     5734        {
     5735            if (i.key() > baseframe)                                                       
     5736            {
     5737                framenum = i.key();                                                           
     5738                break;                                                                         
     5739            }                                                                                 
     5740        }                                                                                     
     5741        if (framenum == -1)
     5742            framenum = totalFrames;
     5743        seekcount = framenum - baseframe;
     5744    }
     5745    else
     5746    {
     5747        for (; i != deleteMap.end(); ++i)
     5748        {
     5749            if (i.key() >= baseframe)
     5750                break;
     5751            framenum = i.key();
     5752        }
     5753        if (framenum == -1)
     5754            framenum = 0;
     5755        seekcount = baseframe - framenum;
     5756    }
     5757    return seekcount;
    55185758}
    55195759
    55205760void NuppelVideoPlayer::HandleArbSeek(bool right)
    55215761{
    55225762    if (seekamount == -2)
    55235763    {
    5524         QMap<long long, int>::Iterator i = deleteMap.begin();
    5525         long long framenum = -1;
     5764        long long seekcount = CalcCutPointSeek(framesPlayed, right);
    55265765        if (right)
    55275766        {
    5528             for (; i != deleteMap.end(); ++i)
    5529             {
    5530                 if (i.key() > framesPlayed)
    5531                 {
    5532                     framenum = i.key();
    5533                     break;
    5534                 }
    5535             }
    5536             if (framenum == -1)
    5537                 framenum = totalFrames;
    5538 
    5539             fftime = framenum - framesPlayed;
     5767            fftime = seekcount;
    55405768            while (fftime > 0)
    55415769                usleep(1000);
    55425770        }
    55435771        else
    55445772        {
    5545             for (; i != deleteMap.end(); ++i)
    5546             {
    5547                 if (i.key() >= framesPlayed)
    5548                     break;
    5549                 framenum = i.key();
    5550             }
    5551             if (framenum == -1)
    5552                 framenum = 0;
    5553 
    5554             rewindtime = framesPlayed - framenum;
     5773            rewindtime = seekcount;
    55555774            while (rewindtime > 0)
    55565775                usleep(1000);
    55575776        }
     
    55825801    UpdateEditSlider();
    55835802}
    55845803
     5804int NuppelVideoPlayer::GetCutStatus(long long testframe) const
     5805{
     5806    int retval = 0;
     5807    QMap<long long, int>::const_iterator i;
     5808    i = deleteMap.find(testframe);
     5809    if (i == deleteMap.end()) {
     5810        // testframe is not an explicit cutpoint
     5811        // See if it is in a deleted area
     5812        if (IsInDelete(testframe))
     5813            retval = 1;
     5814    } else {
     5815        int direction = *i;
     5816        if (direction == 0)
     5817            retval = 2;
     5818        else
     5819            retval = 3;
     5820    }
     5821
     5822    return retval;
     5823}
     5824
    55855825bool NuppelVideoPlayer::IsInDelete(long long testframe) const
    55865826{
    55875827    long long startpos = 0;
  • mythtv/libs/libmythtv/NuppelVideoPlayer.h

    diff -r -u -N -X diff.exclude.noxml -x myth.20136.0308a -x myth.20136.0308b myth.20136.0308a/mythtv/libs/libmythtv/NuppelVideoPlayer.h myth.20136.0308b/mythtv/libs/libmythtv/NuppelVideoPlayer.h
     
    104104class MPUBLIC NuppelVideoPlayer : public CC608Reader, public CC708Reader
    105105{
    106106    friend class PlayerContext;
     107    friend class GridEditCutpoints;
     108    friend class TV;
    107109
    108110  public:
    109111    NuppelVideoPlayer();
     
    282284    bool EnableEdit(void);
    283285    bool DoKeypress(QKeyEvent *e);
    284286    bool GetEditMode(void) const { return editmode; }
     287    bool GetHideEdits(void) const { return hideedits; }
    285288
    286289    // Decoder stuff..
    287290    VideoFrame *GetNextVideoFrame(bool allow_unsafe = true);
     
    301304    void ShutdownYUVResize(void);
    302305    void SaveScreenshot(void);
    303306
     307    // Edit stuff
     308    bool EditSeekToFrame(long long targetFrame);
     309    QImage GetScreenGrabOfCurrentFrame(QSize size); // Get current frame
     310
     311    void       EditHandleClearMap();
     312    void       EditHandleInvertMap();
     313    void       EditHandleLoadCommSkip();
     314
     315    void ShowEditRecordingGrid();
     316
    304317    // Reinit
    305318    void    ReinitOSD(void);
    306319    void    ReinitVideo(void);
     
    420433    bool PosMapFromEnc(unsigned long long          start,
    421434                       QMap<long long, long long> &posMap);
    422435
     436    // Stuf for GridEditCutpoints
     437    long long CalcCutPointSeek(long long baseframe, bool right);
     438    // returns
     439    // 0 - no cut
     440    // 1 - is deleted
     441    // 2 - cut left
     442    // 3 - cut right
     443    int  GetCutStatus(long long testframe) const;
     444    long long GetSeekAmount() { return seekamount; }
     445    QString GetSeekAmountText() { return seekamounttext; }
     446
    423447  protected:
    424448    void DisplayPauseFrame(void);
    425449    void DisplayNormalFrame(void);
     
    503527    void HandleResponse(void);
    504528
    505529    void UpdateTimeDisplay(void);
     530    int  GetSeekAmountPos() { return seekamountpos; }
    506531    void UpdateSeekAmount(bool up);
     532    void SetHalfPageSize(int hp) { allow_pagesize = true; half_page = hp; }
     533    void UpdateSeekAmountDisplay(void);
    507534    void UpdateEditSlider(void);
    508535
    509536    // Private A/V Sync Stuff
     
    576603    bool     livetv;
    577604    bool     watchingrecording;
    578605    bool     editmode;
     606    bool     hideedits;
    579607    bool     resetvideo;
    580608    bool     using_null_videoout;
    581609    bool     no_audio_in;
     
    596624    long long fftime;
    597625    /// 1..9 == keyframe..10 minutes. 0 == cut point
    598626    int       seekamountpos;
     627    ///  Used for Grid Edit logic
     628    bool      allow_pagesize;
     629    int       half_page;
    599630    /// Seekable frame increment when not using exact seeks.
    600631    /// Usually equal to keyframedist.
    601632    int      seekamount;
     633    QString  seekamounttext; // OSD seek units
    602634    /// Iff true we ignore seek amount and try to seek to an
    603635    /// exact frame ignoring key frame restrictions.
    604636    bool     exactseeks;
     
    737769    QMutex              yuv_lock;
    738770    QWaitCondition      yuv_wait;
    739771
     772    // EditGrid still image capture
     773    unsigned char *grid_edit_image_buffer;
     774    int grid_edit_image_buffer_length;
     775
    740776    // Filters
    741777    QMutex   videofiltersLock;
    742778    QString  videoFiltersForProgram;
  • mythtv/libs/libmythtv/grideditcutpoints.cpp

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

    diff -r -u -N -X diff.exclude.noxml -x myth.20136.0308a -x myth.20136.0308b myth.20136.0308a/mythtv/libs/libmythtv/grideditcutpoints.h myth.20136.0308b/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 myth.20136.0308a -x myth.20136.0308b myth.20136.0308a/mythtv/libs/libmythtv/grideditimages.cpp myth.20136.0308b/mythtv/libs/libmythtv/grideditimages.cpp
     
     1#include <math.h>
     2#include <unistd.h>
     3#include <iostream>
     4#include <algorithm>
     5using namespace std;
     6
     7#include <QApplication>
     8#include <QPainter>
     9#include <QFont>
     10#include <QKeyEvent>
     11#include <QEvent>
     12#include <QPixmap>
     13#include <QPaintEvent>
     14#include <QCursor>
     15#include <QImage>
     16#include <QLayout>
     17#include <QLabel>
     18#include <QDateTime>
     19#include <QRect>
     20
     21#include "mythcontext.h"
     22#include "mythdbcon.h"
     23#include "grideditimages.h"
     24#include "grideditcutpoints.h"
     25#include "NuppelVideoPlayer.h"
     26
     27GridEditImages::GridEditImages(GridEditCutpoints *editor, NuppelVideoPlayer *player)
     28{
     29    m_editor = editor;
     30    m_player = player;
     31    usedSubVideoCount = 0;
     32
     33    lastmovewasright= true;
     34
     35    int i;
     36    for (i = stillFrames.minIndex(); i <= stillFrames.maxIndex(); i++)
     37    {
     38        stillFrames[i] = NULL;
     39        stillFramesBig[i] = NULL;
     40        cutFrames[i] = 0;
     41    }
     42
     43    // Get first frames...
     44    stillMainFrameNumber = m_player->GetFramesPlayed();
     45    if (stillMainFrameNumber <= 0)
     46        stillMainFrameNumber = 1;
     47
     48    // maxFrameNumber may be overridden if neccessary
     49    maxFrameNumber = m_player->GetTotalFrameCount();
     50    maxFrameNumberNVP = m_player->GetTotalFrameCount();
     51
     52    if (stillMainFrameNumber <= 0)
     53        stillMainFrameNumber = 1;
     54
     55    if (stillMainFrameNumber > maxFrameNumber)
     56        stillMainFrameNumber = maxFrameNumber;
     57
     58    getImagesTimer = new QTimer(this);
     59    QObject::connect(getImagesTimer, SIGNAL(timeout()),
     60                     this,           SLOT(updateAllFrames()));
     61
     62
     63}
     64
     65GridEditImages::~GridEditImages()
     66{
     67    clearStillFrames();
     68    m_player->EditSeekToFrame(stillMainFrameNumber);
     69}
     70
     71QPixmap *GridEditImages::makeScaledPixmap(const QImage& qim, QSize sz)
     72{
     73    QPixmap *retval;
     74    if (qim.size() == sz)
     75    {
     76        retval = new QPixmap(sz);
     77        retval->fromImage(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.scaled(videoSizeSmall, Qt::KeepAspectRatio),
     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 myth.20136.0308a -x myth.20136.0308b myth.20136.0308a/mythtv/libs/libmythtv/grideditimages.h myth.20136.0308b/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 myth.20136.0308a -x myth.20136.0308b myth.20136.0308a/mythtv/libs/libmythtv/libmythtv.pro myth.20136.0308b/mythtv/libs/libmythtv/libmythtv.pro
     
    363363    # Misc. frontend
    364364    HEADERS += guidegrid.h              infostructs.h
    365365    HEADERS += ttfont.h
     366    HEADERS += grideditcutpoints.h      grideditimages.h
    366367    SOURCES += guidegrid.cpp            infostructs.cpp
    367368    SOURCES += ttfont.cpp
     369    SOURCES += grideditcutpoints.cpp    grideditimages.cpp
    368370
    369371    using_mheg {
    370372        # DSMCC stuff
  • mythtv/libs/libmythtv/tv_play.cpp

    diff -r -u -N -X diff.exclude.noxml -x myth.20136.0308a -x myth.20136.0308b myth.20136.0308a/mythtv/libs/libmythtv/tv_play.cpp myth.20136.0308b/mythtv/libs/libmythtv/tv_play.cpp
     
    2828#include "remoteencoder.h"
    2929#include "remoteutil.h"
    3030#include "guidegrid.h"
     31#include "grideditcutpoints.h"
    3132//#include "progfind.h"
    3233#include "NuppelVideoPlayer.h"
    3334#include "programinfo.h"
     
    573574    REG_KEY("TV Editing", "BIGJUMPFWD", "Jump forward 10x the normal amount",
    574575            ">,.");
    575576    REG_KEY("TV Editing", "TOGGLEEDIT", "Exit out of Edit Mode", "E");
     577    REG_KEY("TV Editing", "SLOWMO", "Slow Motion Play", "Ctrl+P");
     578    REG_KEY("TV Editing", "PAUSE", "Pause", "P");
    576579
    577580    /* Teletext keys */
    578581    REG_KEY("Teletext Menu", "NEXTPAGE",    "Next Page",             "Down");
     
    32323235    if (editmode)
    32333236    {
    32343237        actx->LockDeleteNVP(__FILE__, __LINE__);
     3238        if (actx->nvp && actx->nvp->GetHideEdits())
     3239        {
     3240            actx->UnlockDeleteNVP(__FILE__, __LINE__);
     3241            return;
     3242        }
    32353243        if (actx->nvp && !actx->nvp->DoKeypress(e))
    32363244            editmode = actx->nvp->GetEditMode();
    32373245        actx->UnlockDeleteNVP(__FILE__, __LINE__);
     
    76997707    qApp->postEvent(myWindow, me);
    77007708}
    77017709
     7710void TV::ShowEditRecordingGrid()
     7711{
     7712     // post the request to the main UI thread
     7713     // it will be caught in eventFilter and processed as CustomEvent
     7714     // this will create the program guide window (widget)
     7715     // on the main thread and avoid a deadlock on Win32
     7716
     7717     VERBOSE(VB_GENERAL, "Starting Grid Edit");
     7718     QString message = QString("START_EDIT");
     7719     MythEvent* me = new MythEvent(message);
     7720     qApp->postEvent(myWindow, me);
     7721}
     7722
    77027723void TV::ChangeVolume(PlayerContext *ctx, bool up)
    77037724{
    77047725    ctx->LockDeleteNVP(__FILE__, __LINE__);
     
    83468367        DoEditSchedule(editType);
    83478368    }
    83488369
     8370    if (message.left(10) == "START_EDIT")
     8371    {
     8372        const PlayerContext *mctx =
     8373            GetPlayerReadLock(0, __FILE__, __LINE__);
     8374        mctx->LockDeleteNVP(__FILE__, __LINE__);
     8375        if (mctx->nvp)
     8376            mctx->nvp->ShowEditRecordingGrid();
     8377
     8378        mctx->UnlockDeleteNVP(__FILE__, __LINE__);
     8379        ReturnPlayerLock(mctx);
     8380    }
     8381
    83498382    if (message.left(14) == "COMMFLAG_START")
    83508383    {
    83518384        QString evchanid = QString::null;
  • mythtv/libs/libmythtv/tv_play.h

    diff -r -u -N -X diff.exclude.noxml -x myth.20136.0308a -x myth.20136.0308b myth.20136.0308a/mythtv/libs/libmythtv/tv_play.h myth.20136.0308b/mythtv/libs/libmythtv/tv_play.h
     
    199199    void setInPlayList(bool setting) { inPlaylist = setting; }
    200200    void setUnderNetworkControl(bool setting) { underNetworkControl = setting; }
    201201
     202    void ShowEditRecordingGrid();
    202203    void ShowNoRecorderDialog(const PlayerContext*,
    203204                              NoRecorderMsg msgType = kNoRecorders);
    204205    void FinishRecording(int player_idx); ///< Finishes player's recording