Ticket #9556: EditGrid.all.1.patch

File EditGrid.all.1.patch, 127.3 KB (added by Bill Stuff <billstuff2001@…>, 9 years ago)
  • myththemes/metallurgy/osd.xml

    old new --- Hunk 1 mythbuild/myththemes/metallurgy/osd.xml 
    266266                <type>roundbox</type>
    267267                <cornerradius>13</cornerradius>
    268268            </shape>
     269            <shape name="incut">
     270                <area>0,4,100%,28</area>
     271                <fill color="#40a3cC" />
     272                <type>roundbox</type>
     273                <cornerradius>13</cornerradius>
     274            </shape>
    269275            <shape name="cuttoright">
    270276                <area>0,2,5,32</area>
    271277                <fill color="#00233C" />
  • mythtv/libs/libmyth/mythdialogs.cpp

    old new bool MythPopupBox::showOkPopup( --- Hunk 1 mythbuild/mythtv/libs/libmyth/mythdialogs.cpp 
    725725}
    726726
    727727bool MythPopupBox::showOkCancelPopup(MythMainWindow *parent, QString title,
    728                                      QString message, bool focusOk)
     728                                     QString message, bool focusOk,
     729                                     QString okLabel, QString cancelLabel)
    729730{
    730731    MythPopupBox *popup = new MythPopupBox(parent, title.toAscii().constData());
    731732
    732733    popup->addLabel(message, Medium, true);
    733     QAbstractButton *okButton     = popup->addButton(tr("OK"),     popup, SLOT(accept()));
    734     QAbstractButton *cancelButton = popup->addButton(tr("Cancel"), popup, SLOT(reject()));
     734    QAbstractButton *okButton     = popup->addButton(okLabel,     popup, SLOT(accept()));
     735    QAbstractButton *cancelButton = popup->addButton(cancelLabel, popup, SLOT(reject()));
    735736
    736737    if (focusOk)
    737738        okButton->setFocus();
  • mythtv/libs/libmyth/mythdialogs.h

    old new class MPUBLIC MythPopupBox : public Myth --- Hunk 1 mythbuild/mythtv/libs/libmyth/mythdialogs.h 
    165165                            QString         button_msg = QString()) MDEPRECATED;
    166166
    167167    static bool showOkCancelPopup(MythMainWindow *parent, QString title,
    168                                   QString message, bool focusOk) MDEPRECATED;
     168                                  QString message, bool focusOk,
     169                                  QString okLabel     = "OK",
     170                                  QString cancelLabel = "Cancel") MDEPRECATED;
    169171
    170172    static DialogCode Show2ButtonPopup(
    171173        MythMainWindow *parent,
  • mythtv/libs/libmythtv/deletemap.cpp

    old new bool DeleteMap::HandleAction(QString &ac --- Hunk 1 mythbuild/mythtv/libs/libmythtv/deletemap.cpp 
    2828        MoveRelative(frame, total, false);
    2929    else if (action == "MOVENEXT")
    3030        MoveRelative(frame, total, true);
     31    else if (action == "MOVECUT")
     32        MoveCut(frame, total);
    3133    else if (action == "CUTTOBEGINNING")
    3234        Add(frame, total, MARK_CUT_END);
    3335    else if (action == "CUTTOEND")
    bool DeleteMap::HandleAction(QString &ac --- Hunk 2 mythbuild/mythtv/libs/libmythtv/deletemap.cpp 
    4143    return handled;
    4244}
    4345
     46void DeleteMap::SetAllowPagesize(double framerate, int hps)
     47{
     48
     49    m_allowpagesize=true;
     50    m_halfpage = hps;
     51    if (m_seekamountpos == 1)
     52         UpdateSeekAmount(+1, framerate);
     53
     54}
     55
     56void DeleteMap::ClearAllowPagesize(double framerate)
     57{
     58
     59    m_allowpagesize=false;
     60    if (m_seekamountpos == 3 || m_seekamountpos == 4)
     61         UpdateSeekAmount(+1, framerate);
     62
     63}
     64
    4465void DeleteMap::UpdateSeekAmount(int change, double framerate)
    4566{
    4667    m_seekamountpos += change;
    47     if (m_seekamountpos > 9)
    48         m_seekamountpos = 9;
     68    if (m_seekamountpos > 11)
     69        m_seekamountpos = 11;
    4970    if (m_seekamountpos < 0)
    5071        m_seekamountpos = 0;
    5172
     73    if (change > 0)
     74    {
     75        if (m_allowpagesize)
     76        {
     77            if (m_seekamountpos == 1)
     78                m_seekamountpos = 2;
     79        }
     80        else
     81        {
     82            if (m_seekamountpos == 3 || m_seekamountpos == 4)
     83                m_seekamountpos = 5;
     84        }
     85    }
     86    else
     87    {
     88        if (m_allowpagesize)
     89        {
     90            if (m_seekamountpos == 1)
     91                m_seekamountpos = 0;
     92        }
     93        else
     94        {
     95            if (m_seekamountpos == 3 || m_seekamountpos == 4)
     96                m_seekamountpos = 2;
     97        }
     98    }
     99
    52100    m_seekText = "";
    53101    switch (m_seekamountpos)
    54102    {
    55         case 0: m_seekText = QObject::tr("cut point"); m_seekamount = -2; break;
    56         case 1: m_seekText = QObject::tr("keyframe"); m_seekamount = -1; break;
    57         case 2: m_seekText = QObject::tr("1 frame"); m_seekamount = 1; break;
    58         case 3: m_seekText = QObject::tr("0.5 seconds"); m_seekamount = (int)roundf(framerate / 2); break;
    59         case 4: m_seekText = QObject::tr("%n second(s)", "", 1); m_seekamount = (int)roundf(framerate); break;
    60         case 5: m_seekText = QObject::tr("%n second(s)", "", 5); m_seekamount = (int)roundf(framerate * 5); break;
    61         case 6: m_seekText = QObject::tr("%n second(s)", "", 20); m_seekamount = (int)roundf(framerate * 20); break;
    62         case 7: m_seekText = QObject::tr("%n minute(s)", "", 1); m_seekamount = (int)roundf(framerate * 60); break;
    63         case 8: m_seekText = QObject::tr("%n minute(s)", "", 5); m_seekamount = (int)roundf(framerate * 300); break;
    64         case 9: m_seekText = QObject::tr("%n minute(s)", "", 10); m_seekamount = (int)roundf(framerate * 600); break;
     103        case  0: m_seekText = QObject::tr("cut point"); m_seekamount = -2; break;
     104
     105        // Only for non-edit grid
     106        case  1: m_seekText = QObject::tr("keyframe"); m_seekamount = -1; break;
     107        // Only for non-edit grid
     108
     109        case  2: m_seekText = QObject::tr("1 frame"); m_seekamount = 1; break;
     110
     111        // Case 3 & 4 are for the edit grid only
     112        case  3: m_seekText = QObject::tr("1/2 Page"); m_seekamount = m_halfpage; break;
     113        case  4: m_seekText = QObject::tr("Full Page"); m_seekamount = m_halfpage * 2; break;
     114        // Case 3 & 4 are for the edit grid only
     115
     116        case  5: m_seekText = QObject::tr("0.5 seconds"); m_seekamount = (int)roundf(framerate / 2); break;
     117        case  6: m_seekText = QObject::tr("%n second(s)", "", 1); m_seekamount = (int)roundf(framerate); break;
     118        case  7: m_seekText = QObject::tr("%n second(s)", "", 5); m_seekamount = (int)roundf(framerate * 5); break;
     119        case  8: m_seekText = QObject::tr("%n second(s)", "", 20); m_seekamount = (int)roundf(framerate * 20); break;
     120        case  9: m_seekText = QObject::tr("%n minute(s)", "", 1); m_seekamount = (int)roundf(framerate * 60); break;
     121        case 10: m_seekText = QObject::tr("%n minute(s)", "", 5); m_seekamount = (int)roundf(framerate * 300); break;
     122        case 11: m_seekText = QObject::tr("%n minute(s)", "", 10); m_seekamount = (int)roundf(framerate * 600); break;
    65123        default: m_seekText = QObject::tr("error"); m_seekamount = (int)roundf(framerate); break;
    66124    }
    67125}
    void DeleteMap::Reverse(uint64_t frame, --- Hunk 3 mythbuild/mythtv/libs/libmythtv/deletemap.cpp 
    281339    Add(frame, total, type == MARK_CUT_END ? MARK_CUT_START : MARK_CUT_END);
    282340}
    283341
     342/// Move an existing cut marker (that starts or ends a cut region)
     343/// This sets the marker at the *other* end of the
     344/// cut area to be a temporary marker, and allows the user to
     345/// re-place this marker.
     346void DeleteMap::MoveCut(uint64_t frame, uint64_t total)
     347{
     348    EDIT_CHECK
     349    int type = Delete(frame);
     350    uint64_t othermark;
     351    if (type == MARK_CUT_END)
     352        othermark = GetNearestMark(frame, total, false);
     353    else // if (type == MARK_CUT_START)
     354        othermark = GetNearestMark(frame, total, true);
     355
     356    Add(othermark, MARK_PLACEHOLDER);
     357
     358}
     359
    284360/// Add a new cut marker (to start or end a cut region)
    285361void DeleteMap::NewCut(uint64_t frame, uint64_t total)
    286362{
    MarkTypes DeleteMap::Delete(uint64_t fra --- Hunk 4 mythbuild/mythtv/libs/libmythtv/deletemap.cpp 
    449525 * \brief Returns true if the given frame is deemed to be within a region
    450526 *        that should be cut.
    451527 */
    452 bool DeleteMap::IsInDelete(uint64_t frame)
     528bool DeleteMap::IsInDelete(uint64_t frame, bool includeTempMark, uint64_t altmark)
    453529{
    454530    if (m_deleteMap.isEmpty())
    455531        return false;
    456532
     533    // Check to see if we're moving / adding a cutpoint and the requested frame is within
     534    // the temporary cut area.
     535    if (includeTempMark)
     536    {
     537        int64_t tmpmark = GetTemporaryMark();
     538        if (tmpmark != -1 && ((tmpmark <= frame && frame <= altmark) ||
     539                              (tmpmark >= frame && frame >= altmark)))
     540            return true;
     541    }
     542
    457543    frm_dir_map_t::Iterator it = m_deleteMap.find(frame);
    458544    if (it != m_deleteMap.end())
    459545        return true;
    bool DeleteMap::IsInDelete(uint64_t fram --- Hunk 5 mythbuild/mythtv/libs/libmythtv/deletemap.cpp 
    473559    return false;
    474560}
    475561
     562int DeleteMap::GetCutStatus(uint64_t testframe, bool includeTempMark, uint64_t altmark)
     563{
     564    if (includeTempMark && testframe == altmark && HasTemporaryMark())
     565        // testframe is the mark we're moving
     566        return 2;
     567
     568    else if (IsTemporaryMark(testframe))
     569        // testframe is the temporary mark
     570        return 2;
     571
     572    else if (IsMarked(testframe))
     573        // testframe is a cutpoint
     574        return 2;
     575
     576    else if (IsInDelete(testframe, includeTempMark, altmark))
     577        // testframe is within a cut area
     578        return 1;
     579
     580    else
     581        // testframe is uncut
     582        return 0;
     583}
     584
    476585/**
    477586 * \brief Returns true if the given frame is a temporary/placeholder mark
    478587 */
    bool DeleteMap::IsTemporaryMark(uint64_t --- Hunk 6 mythbuild/mythtv/libs/libmythtv/deletemap.cpp 
    486595}
    487596
    488597/**
     598 * \brief Returns true if the given frame is a normal mark
     599 */
     600bool DeleteMap::IsMarked(uint64_t frame)
     601{
     602    if (m_deleteMap.isEmpty())
     603        return false;
     604
     605    frm_dir_map_t::Iterator it = m_deleteMap.find(frame);
     606    return (it != m_deleteMap.end()) && ((MARK_CUT_START == it.value()) ||
     607                                         (MARK_CUT_END   == it.value()));
     608}
     609
     610/**
    489611 * \brief Returns the next or previous mark. If these do not exist, returns
    490612 *        either zero (the first frame) or total (the last frame).
    491613 */
    bool DeleteMap::HasTemporaryMark(void) --- Hunk 7 mythbuild/mythtv/libs/libmythtv/deletemap.cpp 
    530652}
    531653
    532654/**
     655 * \brief Returns the frame of the temporary placeholder mark.
     656 */
     657int64_t DeleteMap::GetTemporaryMark(void)
     658{
     659    if (!m_deleteMap.isEmpty())
     660    {
     661        frm_dir_map_t::Iterator it = m_deleteMap.begin();
     662        for ( ; it != m_deleteMap.end(); ++it)
     663            if (MARK_PLACEHOLDER == it.value())
     664                return it.key();;
     665    }
     666
     667    return -1;
     668}
     669
     670void DeleteMap::ClearTemporaryMark()
     671{
     672    int64_t tmark = GetTemporaryMark();
     673
     674    if (tmark != -1)
     675        Delete(tmark);
     676}
     677
     678/**
    533679 * \brief Removes redundant marks and ensures the markup sequence is valid.
    534680 *        A valid sequence is 1 or more marks of alternating values and does
    535681 *        not include the first or last frames.
  • mythtv/libs/libmythtv/deletemap.h

    old new class DeleteMap --- Hunk 1 mythbuild/mythtv/libs/libmythtv/deletemap.h 
    88{
    99  public:
    1010    DeleteMap(): m_editing(false),   m_nextCutStart(0), m_changed(true),
    11                  m_seekamountpos(4), m_seekamount(30) { }
     11                 m_seekamountpos(4), m_seekamount(30), m_allowpagesize(false) {}
    1212
    1313    bool HandleAction(QString &action, uint64_t frame, uint64_t played,
    1414                      uint64_t total, double rate);
    1515    int  GetSeekAmount(void) { return m_seekamount; }
     16    QString GetSeekAmountText(void) { return m_seekText; }
    1617    void UpdateSeekAmount(int change, double framerate);
    1718    void SetSeekAmount(int amount) { m_seekamount = amount; }
    1819
     20    void SetAllowPagesize(double framerate, int svc);
     21    void ClearAllowPagesize(double framerate);
     22
    1923    void UpdateOSD(uint64_t frame, uint64_t total, double frame_rate,
    2024                   PlayerContext *ctx, OSD *osd);
    2125
    class DeleteMap --- Hunk 2 mythbuild/mythtv/libs/libmythtv/deletemap.h 
    3539    void ReverseAll(uint64_t total);
    3640    void Add(uint64_t frame, uint64_t total, MarkTypes type);
    3741    void NewCut(uint64_t frame, uint64_t total);
     42    void MoveCut(uint64_t frame, uint64_t total);
    3843    void Delete(uint64_t frame, uint64_t total);
    3944    void Reverse(uint64_t frame, uint64_t total);
    4045    void MoveRelative(uint64_t frame, uint64_t total, bool right);
    4146    void Move(uint64_t frame, uint64_t to, uint64_t total);
    4247
    43     bool     IsInDelete(uint64_t frame);
     48    bool     IsInDelete(uint64_t frame, bool includeTempMark = false, uint64_t altmark = 0);
    4449    uint64_t GetNearestMark(uint64_t frame, uint64_t total, bool right);
    4550    bool     IsTemporaryMark(uint64_t frame);
     51    bool     IsMarked(uint64_t frame);
    4652    bool     HasTemporaryMark(void);
     53    int64_t  GetTemporaryMark();
     54    void     ClearTemporaryMark();
    4755    uint64_t GetLastFrame(uint64_t total);
    4856
    4957    void TrackerReset(uint64_t frame, uint64_t total);
    5058    bool TrackerWantsToJump(uint64_t frame, uint64_t total, uint64_t &to);
    5159
     60    frm_dir_map_t GetDeleteMap() { return m_deleteMap; }
     61    int GetCutStatus(uint64_t frame, bool includeTempMark = false, uint64_t altmark = 0);
    5262  private:
    5363    void Add(uint64_t frame, MarkTypes type);
    5464    MarkTypes Delete(uint64_t frame);
    class DeleteMap --- Hunk 3 mythbuild/mythtv/libs/libmythtv/deletemap.h 
    6070    bool          m_changed;
    6171    int           m_seekamountpos;
    6272    int           m_seekamount;
     73    bool          m_allowpagesize;
     74    int           m_halfpage;
    6375};
    6476
    6577#endif // DELETEMAP_H
  • new file mythbuild/mythtv/libs/libmythtv/grideditcutpoints.cpp

    - + --- Hunk 1 mythbuild/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 "mythplayer.h"
     26#include "mythuieditbar.h"
     27#include "mythdialogbox.h"
     28#include "tv_play.h"
     29
     30#ifndef FUNCTIONLOGGER
     31#define FUNCTIONLOGGER
     32#define FUNCTIONLOGGER_MARK
     33#define FUNCTIONLOGGER_TIMED
     34#define FUNCTIONLOGGER_TAGGED(s)
     35#define FUNCTIONLOGGER_TMTAG(s)
     36#endif
     37
     38
     39void GridEditCutpoints::RunGridEditCutpoints(TV *tv)
     40{
     41    FUNCTIONLOGGER;
     42    MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
     43
     44    GridEditCutpoints *er = new GridEditCutpoints(mainStack, "editrecording", tv);
     45
     46    if (er->Create())
     47    {
     48        mainStack->AddScreen(er);
     49    }
     50    else
     51    {
     52        VERBOSE(VB_GENERAL, "Create failed");
     53        delete er;
     54    }
     55}
     56
     57GridEditCutpoints::GridEditCutpoints(MythScreenStack *parent, QString name, TV *tv)
     58         : MythScreenType(parent, name, true)
     59{
     60FUNCTIONLOGGER;
     61    m_tv = tv;
     62
     63    const PlayerContext *mctx =
     64        m_tv->GetPlayerReadLock(0, __FILE__, __LINE__);
     65    mctx->LockDeletePlayer(__FILE__, __LINE__);
     66    m_player = mctx->player;
     67    m_deleteMap = m_player->GetDeleteMap();
     68    mctx->UnlockDeletePlayer(__FILE__, __LINE__);
     69    tv->ReturnPlayerLock(mctx);
     70
     71    m_images = new GridEditImages(this, m_player);
     72}
     73
     74GridEditCutpoints::~GridEditCutpoints()
     75{
     76    FUNCTIONLOGGER;
     77    gCoreContext->removeListener(this);
     78    if (m_images)
     79    {
     80        delete m_images;
     81        m_images = NULL;
     82    }
     83
     84    if (m_tv)
     85    {
     86        QString message = QString("GRIDEDIT_EXITING");
     87        qApp->postEvent(m_tv, new MythEvent(message));
     88    }
     89
     90}
     91
     92bool GridEditCutpoints::Create()
     93{
     94    FUNCTIONLOGGER
     95
     96    if (!LoadWindowFromXML("recordings-ui.xml", "grideditcutpoints", this))
     97        return false;
     98
     99    int i;
     100    m_gridimagemain = NULL;
     101    for (i = m_gridimages.minIndex(); i < m_gridimages.maxIndex(); i++)
     102    {
     103        m_gridimages[i] = NULL;
     104    }
     105
     106    usedSubVideoCount=0;
     107
     108    QSize videoSizeMain, videoSizeSmall;
     109
     110    MythUIShape* tmpshape = dynamic_cast<MythUIShape *> (GetChild("mainvideo"));
     111    MythUIStateType* tmpstate = dynamic_cast<MythUIStateType *> (GetChild("mainvideostate"));
     112    if (!tmpstate)
     113    {
     114        VERBOSE(VB_IMPORTANT, "FATAL: Couldn't find grideditcutpoints:mainvideostate");
     115        return false;
     116    }
     117
     118    tmpshape = dynamic_cast<MythUIShape *> (GetChild("mainvideo"));
     119    if (!tmpshape)
     120    {
     121        VERBOSE(VB_IMPORTANT, "FATAL: Couldn't find grideditcutpoints:mainvideo");
     122        return false;
     123    }
     124
     125    m_gridimagemain = new CutPointImage(tmpstate, tmpshape);
     126    videoSizeMain = tmpshape->GetArea().size();
     127
     128    // Small version of main frame
     129    tmpstate = dynamic_cast<MythUIStateType *> (GetChild("video0state"));
     130    tmpshape = dynamic_cast<MythUIShape *> (GetChild("video0"));
     131
     132    if (tmpstate && tmpshape)
     133    {
     134        m_gridimages[0] = new CutPointImage(tmpstate, tmpshape);
     135        videoSizeSmall = tmpshape->GetArea().size();
     136    }
     137
     138    for (i = 1; i < m_gridimages.maxIndex(); i++)
     139    {
     140        QString p  = QString("videop%1").arg(i);
     141        QString m  = QString("videom%1").arg(i);
     142        QString ps = QString("videop%1state").arg(i);
     143        QString ms = QString("videom%1state").arg(i);
     144
     145        // Minus frame i
     146        tmpshape = dynamic_cast<MythUIShape *> (GetChild(m));
     147        tmpstate = dynamic_cast<MythUIStateType *> (GetChild(ms));
     148        if (tmpshape && tmpstate)
     149        {
     150            m_gridimages[-i] = new CutPointImage(tmpstate, tmpshape);
     151
     152            QSize tmpVideoSizeSmall = tmpshape->GetArea().size();
     153            if (videoSizeSmall.isValid() && videoSizeSmall != tmpVideoSizeSmall)
     154                VERBOSE(VB_IMPORTANT,
     155                        QString("Multiple sizes found for edit videos (%1)").arg(m));
     156            else
     157                videoSizeSmall = tmpVideoSizeSmall;
     158            if (i > usedSubVideoCount) usedSubVideoCount=i;
     159        }
     160
     161        tmpshape = dynamic_cast<MythUIShape *> (GetChild(p));
     162        tmpstate = dynamic_cast<MythUIStateType *> (GetChild(ps));
     163        if (tmpshape && tmpstate)
     164        {
     165            m_gridimages[i] = new CutPointImage(tmpstate, tmpshape);
     166
     167            QSize tmpVideoSizeSmall = tmpshape->GetArea().size();
     168            if (videoSizeSmall.isValid() && videoSizeSmall != tmpVideoSizeSmall)
     169                VERBOSE(VB_IMPORTANT,
     170                        QString("Multiple sizes found for edit videos (%1)").arg(p));
     171            else
     172                videoSizeSmall = tmpVideoSizeSmall;
     173            if (i > usedSubVideoCount) usedSubVideoCount=i;
     174        }
     175    }
     176
     177    m_slider = dynamic_cast<MythUIEditBar *> (GetChild("positionbar"));
     178    if (!m_slider)
     179        VERBOSE(VB_GENERAL, "Missing positionbar for GridEditCutpoints");
     180
     181    // Get Status boxes
     182    {
     183        m_framenum    = dynamic_cast<MythUIText *> (GetChild("framenum"));
     184        m_time        = dynamic_cast<MythUIText *> (GetChild("time"));
     185        m_cutind      = dynamic_cast<MythUIText *> (GetChild("cutind"));
     186        m_jumpstyle   = dynamic_cast<MythUIText *> (GetChild("jumpstyle"));
     187        m_updatingind = dynamic_cast<MythUIText *> (GetChild("updatingind"));
     188    }
     189    VERBOSE(VB_GENERAL, QString("Framenum %1, time %2, cutind %3, jumpstyle %4, updating %5")
     190                        .arg(m_framenum != NULL)
     191                        .arg(m_time != NULL)
     192                        .arg(m_cutind != NULL)
     193                        .arg(m_jumpstyle != NULL)
     194                        .arg(m_updatingind != NULL));
     195
     196    VERBOSE(VB_GENERAL, QString("main = (%1, %2) small = (%3, %4)")
     197                       .arg(videoSizeMain.width()).arg(videoSizeMain.height())
     198                       .arg(videoSizeSmall.width()).arg(videoSizeSmall.height()));
     199
     200    addingCutarea = m_deleteMap->HasTemporaryMark();
     201    movingCutarea = false;
     202    // Create blank pixmaps...
     203
     204    m_images->SetVideoInfo(usedSubVideoCount, videoSizeMain, videoSizeSmall);
     205
     206    m_player->StartEditRecordingGrid(usedSubVideoCount);
     207
     208    LoadInBackground();
     209    return true;
     210}
     211
     212void GridEditCutpoints::Load()
     213{
     214    FUNCTIONLOGGER;
     215}
     216
     217void GridEditCutpoints::Init()
     218{
     219    FUNCTIONLOGGER;
     220
     221    // Ensure we're not on keyframe seek
     222
     223    m_player->StartEditRecordingGrid(usedSubVideoCount);
     224
     225    refreshImages();
     226    refreshCutList();
     227    updateStats();
     228
     229    gCoreContext->addListener(this);
     230}
     231
     232void GridEditCutpoints::Close()
     233{
     234    FUNCTIONLOGGER;
     235
     236    GetScreenStack()->PopScreen(this, false);
     237}
     238
     239void GridEditCutpoints::displayInitialFrame()
     240{
     241    refreshImages();
     242    refreshCutList();
     243    updateStats();
     244}
     245
     246void GridEditCutpoints::refreshFrameCount()
     247{
     248    refreshImages();
     249    refreshSlider();
     250    updateStats();
     251}
     252
     253bool GridEditCutpoints::keyPressEvent(QKeyEvent *event)
     254{
     255    FUNCTIONLOGGER;
     256
     257    QStringList actions;
     258    bool handled = false;
     259    handled = GetMythMainWindow()->TranslateKeyPress("TV Editing", event, actions);
     260
     261    if (handled)
     262        return true;
     263
     264    bool skipMost=false;
     265
     266    for (unsigned int i = 0; i < actions.size() && !handled; i++)
     267    {
     268        QString action = actions[i];
     269        handled = true;
     270
     271        VERBOSE(VB_GENERAL, QString("key[%1] = '%2'").arg(i).arg(action));
     272
     273        if (action == "SELECT" && !skipMost)
     274        {
     275            if (m_deleteMap->IsInDelete(m_images->GetCurrentFrameNumber()) &&
     276                !m_deleteMap->HasTemporaryMark())
     277
     278                // Do "What to do with this cutpoint" menu
     279                // Event handler will set movingCutpoint if appropriate.
     280                handleSelect();
     281            else
     282                m_deleteMap->NewCut(m_images->GetCurrentFrameNumber(), m_player->GetTotalFrameCount());
     283
     284
     285            int64_t tmark = m_deleteMap->GetTemporaryMark();
     286            if (tmark == -1)
     287            {
     288                addingCutarea = false;
     289                movingCutarea = false;
     290                SetUpdating(false);
     291            }
     292            else
     293            {
     294                addingCutarea = true;
     295                savedCutpoint = tmark;
     296            }
     297
     298            refreshCutList();
     299            refreshImages();
     300        }
     301        else if (action == "LEFT" && !skipMost)
     302            EditHandleLeft();
     303
     304        else if (action == "RIGHT" && !skipMost)
     305            EditHandleRight();
     306
     307        else if (action == "UP" && !skipMost)
     308        {
     309            m_deleteMap->UpdateSeekAmount(1, m_player->GetFrameRate());
     310            m_images->UpdateSeekAmount();
     311            updateStats();
     312        }
     313        else if (action == "DOWN" && !skipMost)
     314        {
     315            m_deleteMap->UpdateSeekAmount(-1, m_player->GetFrameRate());
     316            m_images->UpdateSeekAmount();
     317            updateStats();
     318        }
     319        else if (action == "CLEARMAP" && !skipMost)
     320        {
     321            if (addingCutarea || movingCutarea)
     322                ShowOkPopup(QString("Clear Cut Map Unavailable when %1 Cut Area")
     323                                   .arg(addingCutarea ? "Adding" : "Moving"));
     324            else
     325            {
     326                bool doclear = true;
     327                if (!m_deleteMap->IsEmpty())
     328                    doclear = MythPopupBox::showOkCancelPopup(GetMythMainWindow(),
     329                                                              "Clear Cutmap",
     330                                                              "Clear the entire Cutmap?", false,
     331                                                              "Yes", "No");
     332                if (doclear)
     333                {
     334                    SetUpdating(true);
     335                    m_deleteMap->Clear();
     336                    refreshCutList();
     337                    updateStats();
     338                    SetUpdating(false);
     339                }
     340            }
     341        }
     342        else if (action == "INVERTMAP" && !skipMost)
     343        {
     344            if (addingCutarea || movingCutarea)
     345                ShowOkPopup(QString("Invert Cut Map Unavailable when %1 Cut Area")
     346                                   .arg(addingCutarea ? "Adding" : "Moving"));
     347            else
     348            {
     349                SetUpdating(true);
     350                m_deleteMap->ReverseAll(m_player->GetTotalFrameCount());
     351                refreshCutList();
     352                updateStats();
     353                SetUpdating(false);
     354            }
     355        }
     356        else if (action == "LOADCOMMSKIP" && !skipMost)
     357        {
     358            if (addingCutarea || movingCutarea)
     359                ShowOkPopup(QString("Load Comm Skip Map Unavailable when %1 Cut Area")
     360                                   .arg(addingCutarea ? "Adding" : "Moving"));
     361            else
     362            {
     363                bool doload = true;
     364                if (!m_deleteMap->IsEmpty())
     365                        doload = MythPopupBox::showOkCancelPopup(GetMythMainWindow(),
     366                                                   "Load Cutmap",
     367                                                   "Load the Commflag into the Cutmap?", false,
     368                                                   "Yes", "No");
     369
     370                if (doload)
     371                {
     372                    SetUpdating(true);
     373                    m_player->EditHandleLoadCommSkip();
     374                    refreshCutList();
     375                    updateStats();
     376                    SetUpdating(false);
     377                }
     378            }
     379        }
     380        else if (action == "PREVCUT" && !skipMost)
     381            EditHandlePrevCut();
     382
     383        else if (action == "NEXTCUT" && !skipMost)
     384            EditHandleNextCut();
     385
     386        else if (action == "BIGJUMPREW" && !skipMost)
     387            EditHandleBigJumpRew();
     388
     389        else if (action == "BIGJUMPFWD" && !skipMost)
     390            EditHandleBigJumpFwd();
     391
     392        else if (action == "ESCAPE" && (addingCutarea || movingCutarea))
     393        {
     394            m_deleteMap->ClearTemporaryMark();
     395            addingCutarea = false;
     396            movingCutarea = false;
     397            SetUpdating(false);
     398            refreshImages();
     399            refreshCutList();
     400        }
     401        else if (action == "ESCAPE" || action == "TOGGLEEDIT" ||
     402                 action == "MENU")
     403            Close();
     404        else
     405            handled = false;
     406
     407        if (addingCutarea || movingCutarea)
     408        {
     409            QString tag = (addingCutarea ? "Add" : "Move");
     410            long long diff = m_images->GetCurrentFrameNumber() - savedCutpoint;
     411            if (diff > 0)
     412                SetUpdating(true, QString("%1 Cut +%2").arg(tag).arg(diff));
     413            else
     414                SetUpdating(true, QString("%1 Cut %2").arg(tag).arg(diff));
     415        }
     416    }
     417
     418    if (!handled && MythScreenType::keyPressEvent(event))
     419        handled = true;
     420
     421    return handled;
     422}
     423
     424void GridEditCutpoints::customEvent(QEvent *event)
     425{
     426FUNCTIONLOGGER;
     427    bool needupdate = false;
     428
     429    VERBOSE(VB_GENERAL, QString("Got Event %1").arg(event->type()));
     430
     431    if (event->type() == DialogCompletionEvent::kEventType)
     432    {
     433        DialogCompletionEvent *dce = (DialogCompletionEvent*)(event);
     434
     435        QString resultid   = dce->GetId();
     436        QString resulttext = dce->GetResultText();
     437        int     buttonnum  = dce->GetResult();
     438
     439        QString data = dce->GetData().toString();
     440        // split data from 'command_frame' into 'command' 'frame'
     441        QStringList commandstr = data.split("_");
     442        QString command;
     443        uint64_t frame;
     444        if (commandstr.count() != 2)
     445        {
     446            VERBOSE(VB_IMPORTANT, QString("Got invalid response: '%1' '%2' %3 '%4'")
     447                    .arg(resultid).arg(resulttext).arg(buttonnum).arg(data));
     448        }
     449        else
     450        {
     451            command = commandstr.first();
     452            frame = commandstr.last().toULongLong();
     453            uint64_t total_frames = m_player->GetTotalFrameCount();
     454
     455            VERBOSE(VB_GENERAL, QString("Got '%1' '%2' %3 '%4 -> %5, %6'")
     456                    .arg(resultid).arg(resulttext).arg(buttonnum).arg(data)
     457                    .arg(command).arg(frame));
     458
     459            needupdate=true;
     460            if (command == "MOVEPREV")
     461                m_deleteMap->MoveRelative(frame, total_frames, false);
     462            if (command == "CUTTOBEGINNING")
     463                m_deleteMap->Add(frame, total_frames, MARK_CUT_END);
     464            if (command == "CUTTOEND")
     465                m_deleteMap->Add(frame, total_frames, MARK_CUT_START);
     466            if (command == "MOVENEXT")
     467                m_deleteMap->MoveRelative(frame, total_frames, true);
     468            if (command == "DELETE")
     469                m_deleteMap->Delete(frame, total_frames);
     470            if (command == "NEWCUT")
     471                m_deleteMap->NewCut(frame, total_frames);
     472            if (command == "MOVECUT")
     473            {
     474                m_deleteMap->MoveCut(frame, total_frames);
     475                movingCutarea = true;
     476                savedCutpoint = m_deleteMap->GetTemporaryMark();
     477            }
     478            if (command == "CANCEL")
     479                needupdate=false;
     480        }
     481    } else
     482        MythScreenType::customEvent(event);
     483
     484    if (needupdate)
     485    {
     486        refreshCutList();
     487        refreshImages();
     488
     489        if (addingCutarea || movingCutarea)
     490        {
     491            QString tag = (addingCutarea ? "Add" : "Move");
     492            long long diff = m_images->GetCurrentFrameNumber() - savedCutpoint;
     493            if (diff > 0)
     494                SetUpdating(true, QString("%1 Cut +%2").arg(tag).arg(diff));
     495            else
     496                SetUpdating(true, QString("%1 Cut %2").arg(tag).arg(diff));
     497        }
     498
     499    }
     500}
     501
     502void GridEditCutpoints::EditHandleLeft(int seektype)
     503{
     504    bool cutpointseek = false;
     505    bool bigseek = false;
     506
     507    if (seektype == -2)
     508        cutpointseek = true;
     509    else if (seektype == 10)
     510        // seektype == 1 for normal, 10 for bigjump
     511        bigseek = true;
     512
     513    m_images->SeekLeft(bigseek, cutpointseek);
     514
     515    if (addingCutarea || movingCutarea)
     516        refreshCutList();
     517    refreshImages();
     518    updateStats();
     519}
     520
     521void GridEditCutpoints::EditHandleRight(int seektype)
     522{
     523    bool cutpointseek=false;
     524    bool bigseek = false;
     525
     526    if (seektype == -2)
     527        cutpointseek = true;
     528    else if (seektype == 10)
     529        // seektype == 1 for normal, 10 for bigjump
     530        bigseek = true;
     531
     532    m_images->SeekRight(bigseek, cutpointseek);
     533
     534    if (addingCutarea || movingCutarea)
     535        refreshCutList();
     536    refreshImages();
     537    updateStats();
     538}
     539
     540enum button_items {
     541    CANCEL,
     542    MOVEPREV,
     543    CUTTOBEGINNING,
     544    CUTTOEND,
     545    MOVENEXT,
     546    DELETE,
     547    NEWCUT,
     548    MOVECUT
     549};
     550
     551DialogCode operator++(DialogCode& dc, int i) {
     552    DialogCode orig = dc;
     553    dc = (DialogCode) ( (int) dc + 1);
     554    return orig;
     555}
     556void GridEditCutpoints::handleSelect(void)
     557{
     558    uint64_t frame   = m_images->GetCurrentFrameNumber();
     559    uint64_t previous_cut = m_player->GetNearestMark(frame, false);
     560    uint64_t next_cut = m_player->GetNearestMark(frame, true);
     561    uint64_t total_frames = m_player->GetTotalFrameCount();
     562
     563//    FrameStats fs = m_images->GetMainFrameStats();
     564// BILL    DeletePointInfo dpi;// = //m_player->GetDeletePointInfo(fs.frameNumber, true);
     565
     566#if 0 // old vs new popup style
     567    QStringList button_labels;
     568
     569    QMap<DialogCode, button_items> button_actions;
     570    DialogCode dialog_code = kDialogCodeListStart;
     571
     572    button_actions[kDialogCodeRejected] = CANCEL;
     573
     574    if (m_deleteMap->IsInDelete(frame))
     575    {
     576        if (m_deleteMap->IsTemporaryMark(frame))
     577        {
     578
     579            if (previous_cut > 0)
     580            {
     581                button_labels << QObject::tr("Move Previous Cut End Here");
     582                button_actions[dialog_code++] = MOVEPREV;
     583            }
     584            else
     585            {
     586                button_labels << QObject::tr("Cut to Beginning");
     587                button_actions[dialog_code++] = CUTTOBEGINNING;
     588            }
     589
     590            if (next_cut == total_frames)
     591            {
     592                button_labels << QObject::tr("Cut to End");
     593                button_actions[dialog_code++] = CUTTOEND;
     594            }
     595            else
     596            {
     597                button_labels << QObject::tr("Move Next Cut Start Here");
     598                button_actions[dialog_code++] = MOVENEXT;
     599            }
     600        }
     601        else
     602        {
     603            if (m_deleteMap->IsMarked(frame))
     604            {
     605                button_labels << QObject::tr("Move this Cutpoint");
     606                button_actions[dialog_code++] = MOVECUT;
     607            }
     608            button_labels << QObject::tr("Move Start of Cut Here");
     609            button_actions[dialog_code++] = MOVEPREV;
     610
     611            button_labels << QObject::tr("Move End of Cut Here");
     612            button_actions[dialog_code++] = MOVENEXT;
     613        }
     614
     615        button_labels << QObject::tr("Delete This Cut");
     616        button_actions[dialog_code++] = DELETE;
     617    }
     618    else
     619    {
     620        if (previous_cut > 0)
     621        {
     622            button_labels << QObject::tr("Move Previous Cut End Here");
     623            button_actions[dialog_code++] = MOVEPREV;
     624        }
     625        else
     626        {
     627            button_labels << QObject::tr("Cut to Beginning");
     628            button_actions[dialog_code++] = CUTTOBEGINNING;
     629        }
     630
     631        if (next_cut == total_frames)
     632        {
     633            button_labels << QObject::tr("Cut to End");
     634            button_actions[dialog_code++] = CUTTOEND;
     635        }
     636        else
     637        {
     638            button_labels << QObject::tr("Move Next Cut Start Here");
     639            button_actions[dialog_code++] = MOVENEXT;
     640        }
     641
     642        button_labels << QObject::tr("Add New Cut");
     643        button_actions[dialog_code++] = NEWCUT;
     644    }
     645
     646    DialogCode dc = MythPopupBox::ShowButtonPopup(GetMythMainWindow(),
     647                                                "Edit Cut Points","Edit Cut Points",
     648                                                button_labels, kDialogCodeListStart);
     649
     650    dialog_code = dc;
     651    VERBOSE(VB_GENERAL, QString("Got %1 (%2)").arg(dialog_code).arg(button_actions[dialog_code]));
     652
     653    switch (button_actions[dialog_code]) {
     654        case MOVEPREV:       m_deleteMap->MoveRelative(frame, total_frames, false); break;
     655        case CUTTOBEGINNING: m_deleteMap->Add(frame, total_frames, MARK_CUT_END);   break;
     656        case CUTTOEND:       m_deleteMap->Add(frame, total_frames, MARK_CUT_START); break;
     657        case MOVENEXT:       m_deleteMap->MoveRelative(frame, total_frames, true);  break;
     658        case DELETE:         m_deleteMap->Delete(frame, total_frames);              break;
     659        case NEWCUT:         m_deleteMap->NewCut(frame, total_frames);              break;
     660        case MOVECUT:        m_deleteMap->MoveCut(frame, total_frames);             break;
     661        case CANCEL:         VERBOSE(VB_GENERAL, "Doing Nothing");                  break;
     662    }
     663#else
     664
     665    MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
     666
     667    MythDialogBox *menuPopup = new MythDialogBox("Edit Cut Points", popupStack, "menuPopup");
     668
     669    if (!menuPopup->Create())
     670    {
     671        delete menuPopup;
     672        menuPopup = NULL;
     673        return;
     674    }
     675
     676    if (m_deleteMap->IsInDelete(frame))
     677    {
     678        if (m_deleteMap->IsTemporaryMark(frame))
     679        {
     680
     681            if (previous_cut > 0)
     682                menuPopup->AddButton(QObject::tr("Move Previous Cut End Here"),
     683                                     QString("MOVEPREV_%1").arg(frame));
     684            else
     685                menuPopup->AddButton(QObject::tr("Cut to Beginning"),
     686                                     QString("CUTTOBEGINNING_%1").arg(frame));
     687
     688            if (next_cut == total_frames)
     689                menuPopup->AddButton(QObject::tr("Cut to End"),
     690                                     QString("CUTTOEND_%1").arg(frame));
     691            else
     692                menuPopup->AddButton(QObject::tr("Move Next Cut Start Here"),
     693                                         QString("MOVENEXT_%1").arg(frame));
     694        }
     695        else if (m_deleteMap->IsMarked(frame))
     696            menuPopup->AddButton(QObject::tr("Move this Cutpoint"),
     697                                 QString("MOVECUT_%1").arg(frame));
     698        else
     699        {
     700            menuPopup->AddButton(QObject::tr("Move Start of Cut Here"),
     701                                 QString("MOVEPREV_%1").arg(frame));
     702            menuPopup->AddButton(QObject::tr("Move End of Cut Here"),
     703                                 QString("MOVENEXT_%1").arg(frame));
     704        }
     705
     706        menuPopup->AddButton(QObject::tr("Delete This Cut"),
     707                             QString("DELETE_%1").arg(frame));
     708    }
     709    else
     710    {
     711        if (previous_cut > 0)
     712            menuPopup->AddButton(QObject::tr("Move Previous Cut End Here"),
     713                                 QString("MOVEPREV_%1")
     714                                         .arg(frame));
     715        else
     716            menuPopup->AddButton(QObject::tr("Cut to Beginning"),
     717                              QString("CUTTOBEGINNING_%1")
     718                                      .arg(frame));
     719        if (next_cut == total_frames)
     720            menuPopup->AddButton(QObject::tr("Cut to End"),
     721                                 QString("CUTTOEND_%1")
     722                                         .arg(frame));
     723        else
     724            menuPopup->AddButton(QObject::tr("Move Next Cut Start Here"),
     725                                 QString("MOVENEXT_%1")
     726                                         .arg(frame));
     727        menuPopup->AddButton(QObject::tr("Add New Cut"),
     728                             QString("NEWCUT_%1")
     729                                     .arg(frame));
     730    }
     731
     732   menuPopup->SetReturnEvent(this, "handleSelect");
     733   popupStack->AddScreen(menuPopup);
     734#endif
     735}
     736
     737void GridEditCutpoints::refreshImages(bool mainonly)
     738{
     739//   FUNCTIONLOGGER;
     740    m_images->refreshImages(m_gridimagemain, m_gridimages, false);
     741}
     742
     743void GridEditCutpoints::refreshCutList()
     744{
     745    m_images->refreshCutList(m_gridimagemain, m_gridimages);
     746    refreshSlider();
     747}
     748
     749void GridEditCutpoints::refreshSlider()
     750{
     751    if (!m_slider)
     752        return;
     753
     754    m_slider->ClearRegions();
     755    m_slider->SetTotal(m_images->GetMaxFrameNumber());
     756
     757    // MARK_PLACEHOLDER = -2 // Temporary mark
     758    // MARK_CUT_END     =  0
     759    // MARK_CUT_START   =  1
     760
     761    long long startpos = 0;
     762    long long endpos = 0;
     763    long long tmppos = 0;
     764    long long curpos = 0;
     765
     766    int       lastdirection = MARK_CUT_END;
     767
     768    frm_dir_map_t deleteMap = m_deleteMap->GetDeleteMap();
     769    frm_dir_map_t::const_iterator i = deleteMap.begin();
     770    for (; i != deleteMap.end(); ++i)
     771    {
     772        uint64_t frame = i.key();
     773        int direction = *i;
     774
     775        if (direction == MARK_CUT_END)
     776        {
     777            endpos = frame;
     778            m_slider->AddRegion(startpos, endpos);
     779
     780            startpos = frame;
     781            lastdirection = MARK_CUT_END;
     782        }
     783        else if (direction == MARK_CUT_START)
     784        {
     785            if (lastdirection == MARK_CUT_START)
     786            {
     787                // continuing within a cutpoint
     788                endpos = frame;
     789                m_slider->AddRegion(startpos, endpos);
     790            }
     791
     792            startpos = frame;
     793            lastdirection = MARK_CUT_START;
     794        }
     795        else if (direction == MARK_PLACEHOLDER)
     796        {
     797            tmppos = frame;
     798            curpos = m_images->GetCurrentFrameNumber();
     799
     800            if (tmppos < curpos)
     801                m_slider->AddRegion(tmppos, curpos);
     802            else
     803                m_slider->AddRegion(curpos, tmppos);
     804        }
     805    }
     806
     807    if (lastdirection == MARK_CUT_START)
     808    {
     809        // continuing within a cutpoint
     810        endpos = m_images->GetMaxFrameNumber();
     811        m_slider->AddRegion(startpos, endpos);
     812    }
     813    m_slider->Display();
     814}
     815
     816void GridEditCutpoints::updateStats()
     817{
     818FUNCTIONLOGGER;
     819    int secs, frames, ss, mm, hh;
     820
     821    FrameStats fs = m_images->GetMainFrameStats();
     822
     823    secs = (int)(fs.frameNumber / m_player->GetFrameRate());
     824    frames = fs.frameNumber - (int)(secs * m_player->GetFrameRate());
     825
     826    ss = secs;
     827    mm = ss / 60;
     828    ss %= 60;
     829    hh = mm / 60;
     830    mm %= 60;
     831
     832    char timestr[128];
     833    sprintf(timestr, "%d:%02d:%02d.%02d", hh, mm, ss, frames);
     834
     835    char framestr[128];
     836    sprintf(framestr, "%lld", fs.frameNumber);
     837
     838    if (m_time)
     839        m_time->SetText(timestr);
     840
     841    if (m_framenum)
     842        m_framenum->SetText(framestr);
     843
     844    if (m_cutind)
     845        m_cutind->SetText(fs.cutInd == 0 ? "" : "Cut");
     846
     847    if (m_jumpstyle)
     848        m_jumpstyle->SetText(m_deleteMap->GetSeekAmountText());
     849
     850    if (m_slider)
     851        m_slider->SetPosition(fs.frameNumber);
     852}
     853
     854void GridEditCutpoints::escape()
     855{
     856    // Make sure we're on the right frame when we go back to
     857    // Normal edit mode
     858//    unsetCursor();
     859//    accept();
     860}
     861
     862void GridEditCutpoints::displayCacheStatus(int level)
     863{
     864    // 0 - onscreen frames
     865    // 1 - precache frames
     866    // 2 - fill-out-the buffer frames
     867
     868    if (!addingCutarea && !movingCutarea)
     869        switch (level) {
     870            case 0: SetUpdating(true, "Displaying"); break;
     871            case 1: SetUpdating(true, "Pre-Caching"); break;
     872            case 2: SetUpdating(true, "Caching"); break;
     873            default: SetUpdating(false);
     874        }
     875}
     876
     877void GridEditCutpoints::SetUpdating(bool active, QString text)
     878{
     879
     880    if (m_updatingind)
     881    {
     882        //VERBOSE(VB_GENERAL, QString("Updating to %1").arg(active));
     883        if (active)
     884        {
     885            m_updatingind->Show();
     886            m_updatingind->SetText(text);
     887        }
     888        else
     889            m_updatingind->Hide();
     890    }
     891}
     892
     893void GridEditCutpoints::aboutToHide(void)
     894{
     895    if (m_player)
     896        GetMythMainWindow()->GetPaintWindow()->clearMask();
     897
     898    MythScreenType::aboutToHide();
     899}
     900
     901void GridEditCutpoints::aboutToShow(void)
     902{
     903FUNCTIONLOGGER;
     904    if (m_tv)
     905    {
     906        //QRect videoRect(10,120,320,180);
     907        QRect videoRect(0,0,0,0);
     908        PlayerContext *ctx = m_tv->GetPlayerReadLock(-1, __FILE__, __LINE__);
     909        bool usingNullVideo =
     910            !m_tv->StartEmbedding(ctx, GetMythMainWindow()->GetPaintWindow()->winId(), videoRect);
     911        if (!usingNullVideo)
     912        {
     913FUNCTIONLOGGER_MARK;
     914            QRegion r1 = QRegion(m_Area);
     915            QRegion r2 = QRegion(videoRect);
     916            GetMythMainWindow()->GetPaintWindow()->setMask(r1.xored(r2));
     917            m_tv->DrawUnusedRects();
     918        } else {
     919FUNCTIONLOGGER_MARK;
     920        }
     921        m_tv->ReturnPlayerLock(ctx);
     922    }
     923
     924    MythScreenType::aboutToShow();
     925}
     926
     927// CutPointImage stuff
     928
     929CutPointImage::CutPointImage(MythUIStateType *state, MythUIShape *shape)
     930{
     931    m_state = state;
     932    m_image = shape;
     933
     934    m_cutStatus = 0;
     935    m_framenumber = -1;
     936}
     937
     938CutPointImage::~CutPointImage()
     939{}
     940
     941void CutPointImage::Reset()
     942{
     943    if (m_image)
     944        m_image->Reset();
     945    if (m_state)
     946        m_state->Reset();
     947}
     948
     949void CutPointImage::SetPixmap(QPixmap * new_pmap, long long frame, int new_cutStatus)
     950{
     951//FUNCTIONLOGGER_TAGGED(QString("new_pm = 0x%1 Frame = %2").arg((int)new_pmap, 0, 16).arg(frame));
     952    if (! new_pmap)
     953    {
     954        clearPixmap();
     955        return;
     956    }
     957
     958    if (frame == m_framenumber)
     959    {
     960        // No change in pixmap (?)
     961        setCutStatus(new_cutStatus);
     962        return;
     963    }
     964
     965    m_pmap = *new_pmap;
     966    m_framenumber = frame;
     967
     968    if (new_cutStatus >= 0 && new_cutStatus <= 2)
     969        m_cutStatus = new_cutStatus;
     970    else
     971        m_cutStatus = 0;
     972
     973    UpdateImage();
     974}
     975
     976void CutPointImage::clearPixmap(bool dorefresh)
     977{
     978    if (! m_pmap.isNull())
     979    {
     980        m_pmap = QPixmap();
     981
     982        m_cutStatus = 0;
     983        m_framenumber = -1;
     984        UpdateImage();
     985    }
     986}
     987
     988void CutPointImage::setCutStatus(int new_cutStatus)
     989{
     990    // Cut status:
     991    // 0 = no cut
     992    // 1 = in cut area
     993    // 2 = cutpoint
     994    if (new_cutStatus == m_cutStatus)
     995        return;
     996
     997    if (new_cutStatus >= 0 && new_cutStatus <= 2)
     998        m_cutStatus = new_cutStatus;
     999    else
     1000        m_cutStatus = 0;
     1001
     1002    UpdateImage();
     1003}
     1004
     1005void CutPointImage::UpdateImage()
     1006{
     1007    m_image->SetPixmap(&m_pmap);
     1008    bool sresult=false;
     1009    switch (m_cutStatus)
     1010    {
     1011        case 0: sresult=m_state->DisplayState("normal"); break;
     1012        case 1: sresult=m_state->DisplayState("incut"); break;
     1013        case 2: sresult=m_state->DisplayState("cutpoint"); break;
     1014    }
     1015
     1016//    VERBOSE(VB_GENERAL, QString(" cutStat = %1, DisplayState = %2").arg(m_cutStatus).arg(sresult));
     1017}
  • new file mythbuild/mythtv/libs/libmythtv/grideditcutpoints.h

    - + --- Hunk 1 mythbuild/mythtv/libs/libmythtv/grideditcutpoints.h 
     1// -*- Mode: c++ -*-
     2#ifndef GRIDEDITCUTPOINTS_H_
     3#define GRIDEDITCUTPOINTS_H_
     4
     5#include <QObject>
     6#include <QEvent>
     7
     8//#include "libmyth/mythwidgets.h"
     9//#include "uitypes.h"
     10
     11#include "mythscreentype.h"
     12#include "grideditimages.h"
     13#include "programtypes.h"
     14
     15
     16class QTimer;
     17class MythPlayer;
     18class GridEditImages;
     19class MythUIEditBar;
     20class MythUIText;
     21class TV;
     22class DeleteMap;
     23class MythUIShape;
     24class MythUIStateType;
     25
     26//wrapper around MythUI types
     27class CutPointImage {
     28
     29  public:
     30    CutPointImage(MythUIStateType* st, MythUIShape *parent);
     31    ~CutPointImage();
     32
     33    void Reset(void);
     34
     35    void SetPixmap(QPixmap * new_pmap, long long frame, int new_cutStatus);
     36
     37    void clearPixmap(bool dorefresh=true);
     38    void setCutStatus(int new_cutStatus);
     39
     40  protected:
     41
     42    void UpdateImage();
     43
     44  private:
     45    MythUIStateType   *m_state;
     46    MythUIShape       *m_image;
     47
     48    QPixmap        m_pmap;
     49    long long      m_framenumber; // for consistency checking
     50    int            m_cutStatus;
     51};
     52
     53class GridEditCutpoints : public MythScreenType
     54{
     55  Q_OBJECT
     56  public:
     57    // Use this function to instantiate an GridEditCutpoints instance.
     58    static void RunGridEditCutpoints(TV *tv);
     59
     60    void refreshImages(bool mainOnly = false);
     61    bool isValid() { return ((usedSubVideoCount > 0) && (m_gridimagemain != NULL)); };
     62    void displayCacheStatus(int level);
     63
     64    void refreshFrameCount();
     65
     66    GridEditCutpoints(MythScreenStack *parent, QString name, TV *tv);
     67   ~GridEditCutpoints();
     68
     69    bool Create(void);
     70    virtual void Load(void);
     71    virtual void Init(void);
     72    virtual void Close(void);
     73
     74    virtual void aboutToHide(void);
     75    virtual void aboutToShow(void);
     76
     77  protected:
     78    void displayInitialFrame();
     79
     80    void handleSelect();
     81
     82    void updateStats();
     83
     84  protected slots:
     85    void escape();
     86
     87    void customEvent(QEvent *event);
     88
     89  private:
     90    bool keyPressEvent(QKeyEvent *e);
     91
     92    // seektype == -2 - cutpoint seek
     93    // seektype ==  1 - normal seek
     94    // seektype == 10 - large seek
     95    void EditHandleLeft(int seektype = 1);
     96    void EditHandleRight(int seektype = 1);
     97    void EditHandlePrevCut()    { EditHandleLeft(-2); };
     98    void EditHandleNextCut()    { EditHandleRight(-2); };
     99    void EditHandleBigJumpRew() { EditHandleLeft(10); };
     100    void EditHandleBigJumpFwd() { EditHandleRight(10); };
     101    void setSlowMotionSpeed();
     102    void refreshCutList();
     103    void refreshSlider();
     104
     105    void SetUpdating(bool active, QString text = "Updating");
     106
     107    // Private Data
     108
     109    MythPlayer *m_player;
     110    DeleteMap *m_deleteMap;
     111    TV *m_tv;
     112    GridEditImages *m_images;
     113
     114    int   usedSubVideoCount;
     115    myArray<CutPointImage*, MAX_SUB_VIDEOS> m_gridimages;
     116    // The main Big image
     117    CutPointImage* m_gridimagemain;
     118
     119    long long savedCutpoint;
     120    bool      addingCutarea;
     121    bool      movingCutarea;
     122
     123    MythUIText   *m_framenum;
     124    MythUIText   *m_time;
     125    MythUIText   *m_cutind;
     126    MythUIText   *m_jumpstyle;
     127    MythUIText   *m_updatingind;
     128
     129    MythUIEditBar         *m_slider;
     130};
     131
     132#endif
  • new file mythbuild/mythtv/libs/libmythtv/grideditimages.cpp

    - + --- Hunk 1 mythbuild/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 "mythplayer.h"
     26
     27#define FRAME_DEBUG 0
     28#define CACHE_DEBUG 0
     29
     30#ifndef FUNCTIONLOGGER
     31#define FUNCTIONLOGGER
     32#define FUNCTIONLOGGER_MARK
     33#define FUNCTIONLOGGER_TIMED
     34#define FUNCTIONLOGGER_TAGGED(s)
     35#define FUNCTIONLOGGER_TMTAG(s)
     36#endif
     37
     38const QEvent::Type GotImageEvent::kEventType    = (QEvent::Type) QEvent::registerEventType(9999);
     39const QEvent::Type CacheStatusEvent::kEventType = (QEvent::Type) QEvent::registerEventType(9998);
     40
     41
     42GridEditImages::GridEditImages(GridEditCutpoints *editor, MythPlayer *player)
     43{
     44    m_editor = editor;
     45    m_player = player;
     46    m_deleteMap = m_player->GetDeleteMap();
     47    usedSubVideoCount = 0;
     48
     49    lastmovewasright= true;
     50
     51    lastImage = NULL;
     52    lastImageBig = NULL;
     53    lastImageFrameNumber = 0;
     54
     55    // Get first frames...
     56    stillMainFrameNumber = m_player->GetFramesPlayed();
     57    if (stillMainFrameNumber <= 0)
     58        stillMainFrameNumber = 1;
     59
     60    seekamount = m_deleteMap->GetSeekAmount();
     61    if (seekamount < 0) seekamount = 1;
     62
     63    // maxFrameNumber may be overridden if neccessary
     64    maxFrameNumber = m_player->GetTotalFrameCount();
     65    maxFrameNumberNVP = m_player->GetTotalFrameCount();
     66
     67    if (stillMainFrameNumber <= 0)
     68        stillMainFrameNumber = 1;
     69
     70    if (stillMainFrameNumber > maxFrameNumber)
     71        stillMainFrameNumber = maxFrameNumber;
     72
     73    frameIndexLeft=0;
     74    frameIndexRight=0;
     75    runGetImages = true;
     76    getImagesDone = false;
     77    pauseGetImages = true;
     78    gridCacheThread.SetGEI(this);
     79    gridCacheThread.start();
     80
     81    bumpRightTimer = new QTimer(this);
     82    QObject::connect(bumpRightTimer, SIGNAL(timeout()),
     83                     this,           SLOT(bumpRight()));
     84}
     85
     86GridEditImages::~GridEditImages()
     87{
     88    // Fix Me - just join the thread instead
     89    {
     90        FUNCTIONLOGGER;
     91        QMutexLocker l(&getImagesLock);
     92        runGetImages = false;
     93        getImagesCondition.wakeAll();
     94        while (! getImagesDone)
     95            getImagesCondition.wait(&getImagesLock, 1000);
     96//        gridCacheThread.wait();
     97    }
     98
     99    clearStillFrames();
     100    m_player->EditSeekToFrame(stillMainFrameNumber);
     101    if (lastImage) delete lastImage;
     102    if (lastImageBig) delete lastImageBig;
     103}
     104
     105void GridCacheThread::run() {
     106    _gei->getImagesThread();
     107}
     108
     109void GridEditImages::customEvent(QEvent *event)
     110{
     111    if (event->type() == GotImageEvent::kEventType) {
     112        GotImageEvent *gie = (GotImageEvent*) event;
     113//        VERBOSE(VB_GENERAL, QString("Got GotImageEvent: %1").arg(gie->framenumber));
     114
     115        if (gie->framenumber == 0)
     116            m_editor->refreshImages(true);
     117        else
     118            m_editor->refreshImages(false);
     119
     120    } else if (event->type() == CacheStatusEvent::kEventType) {
     121        CacheStatusEvent *cse = (CacheStatusEvent*) event;
     122//        VERBOSE(VB_GENERAL, QString("Got CacheStatusEvent: %1").arg(cse->newlevel));
     123
     124        m_editor->displayCacheStatus(cse->newlevel);
     125
     126    } else {
     127        QObject::customEvent(event);
     128    }
     129}
     130
     131void* GridEditImages::getImagesHelper(void *d)
     132{
     133    GridEditImages* g = (GridEditImages*) d;
     134    return g->getImagesThread();
     135}
     136
     137void* GridEditImages::getImagesThread(void)
     138{
     139    // Let the GUI thread handle shifting left and right.  This thread
     140    // will just run continuously to fill in the missing frames
     141    while (runGetImages) {
     142
     143        // check to see if we need to stop or pause
     144        {
     145            QMutexLocker l(&getImagesLock);
     146            while (runGetImages && pauseGetImages) {
     147                getImagesCondition.wait(&getImagesLock, 1000);
     148            }
     149        }
     150        if (runGetImages)
     151            updateAllFrames();
     152    }
     153    {
     154        QMutexLocker l(&getImagesLock);
     155        getImagesDone = true;
     156        getImagesCondition.wakeAll();
     157    }
     158    return NULL;
     159}
     160
     161
     162QPixmap *GridEditImages::makeScaledPixmap(const QImage& qim, QSize sz)
     163{
     164    QPixmap *retval;
     165    if (qim.size() == sz)
     166    {
     167        retval = new QPixmap(sz);
     168        QPainter p(retval);
     169        p.drawImage(0, 0, qim);
     170    }
     171    else
     172    {
     173        retval = new QPixmap(sz);
     174        retval->fill(Qt::black);
     175        QPainter p(retval);
     176
     177        int tl_left = 0;
     178        int tl_top = 0;
     179        if (sz.width() > qim.width())
     180            tl_left += (sz.width() - qim.width()) / 2;
     181
     182        if (sz.height() > qim.height())
     183            tl_top += (sz.height() - qim.height()) / 2;
     184
     185//        VERBOSE(VB_GENERAL, QString("Size mismatch qim(%1, %2) != sz(%3, %4) Shift to (%5, %6)")
     186//             .arg(qim.width()).arg(qim.height())
     187//             .arg(sz.width()).arg(sz.height())
     188//             .arg(tl_left).arg(tl_top));
     189
     190        p.drawImage(tl_left, tl_top, qim);
     191    }
     192    return retval;
     193}
     194
     195void GridEditImages::displayCacheStatus(int newlevel)
     196{
     197    CacheStatusEvent *event = new CacheStatusEvent();
     198
     199    event->newlevel = newlevel;
     200    QApplication::postEvent(this, event);
     201}
     202
     203bool GridEditImages::getFrameIndexes(int newlevel)
     204{
     205    // levels:
     206    // 0 - onscreen frames
     207    // 1 - precache frames
     208    // 2 - fill-out-the buffer frames
     209
     210    displayCacheStatus(newlevel);
     211    if (newlevel > 2)
     212        return false;
     213
     214
     215    // This gets the upper and lower indexes of the frames we need to get.
     216    // Note these indexes maybe negative
     217    // Negative frames are before the main frame
     218    // Frame #0 is the main frame
     219    // Positive frames are after the main frame
     220
     221    // Basic initialization
     222    // Doesn't go to absolute end because it slows down seeking
     223    // when you go 1 frame left and right
     224    frameIndexLeft       = stillFrames.minIndex() + 2;
     225    frameIndexRight      = stillFrames.maxIndex() - 2;
     226    getFutureFramesFirst = lastmovewasright;
     227
     228    if (newlevel == 0) // Main Frame
     229    {
     230        frameIndexLeft  = 0;
     231        frameIndexRight = 0;
     232    }
     233    else if (newlevel == 1) // Current Display only
     234    {
     235        frameIndexLeft  = -(usedSubVideoCount+1);
     236        frameIndexRight =  (usedSubVideoCount+1);
     237    }
     238
     239    // Make sure we don't fall of the front of the file
     240    while (stillMainFrameNumber + (frameIndexLeft * seekamount) <= 0 && frameIndexLeft < 0)
     241        frameIndexLeft++;
     242
     243    // ... or the back of the file
     244    while ((frameIndexRight*seekamount) > (maxFrameNumber - stillMainFrameNumber) && frameIndexRight > 0)
     245        frameIndexRight--;
     246
     247#if CACHE_DEBUG
     248    VERBOSE(VB_GENERAL, QString("Getting frames from %1 to %2 (%3 to %4) for level %5 (sa = %6)")
     249            .arg(frameIndexLeft).arg(frameIndexRight)
     250            .arg(stillMainFrameNumber + (frameIndexLeft * seekamount))
     251            .arg(stillMainFrameNumber + (frameIndexRight * seekamount))
     252            .arg(newlevel).arg(seekamount));
     253#endif
     254    return true;
     255}
     256
     257bool GridEditImages::getStillFrames(int maxcount)
     258{
     259//FUNCTIONLOGGER;
     260    // returns true if no more frames to get
     261
     262    // This will fill in all the missing frames in the cache
     263
     264    int i;
     265    if (getFutureFramesFirst && frameIndexLeft < 0)
     266    {
     267        // If we're filling out the cache and the last move was to the right
     268        // grab future frames first before any past frames
     269        for (i = 1; i <= frameIndexRight; i++)
     270            if (getSpecificFrame(i))
     271                if (--maxcount == 0) return false;
     272    }
     273
     274    // grab all appropriate frames
     275
     276    for (i = frameIndexLeft; i <= frameIndexRight; i++)
     277        if (getSpecificFrame(i))
     278            if (--maxcount == 0) return false;
     279
     280    return true;
     281}
     282
     283bool GridEditImages::bufferIsFull()
     284{
     285    int i;
     286    for (i = -usedSubVideoCount; i <= usedSubVideoCount; i++)
     287    {
     288        if (!stillFrames[i] && !stillImages[i]) return false;
     289    }
     290    return true;
     291}
     292
     293bool GridEditImages::bufferIsEmpty()
     294{
     295    int i;
     296    for (i = -usedSubVideoCount; i <= usedSubVideoCount; i++)
     297    {
     298        if (i != 0 && (stillFrames[i] || stillImages[i])) return false;
     299    }
     300    return true;
     301}
     302
     303
     304bool GridEditImages::getSpecificFrame(int i)
     305{
     306    // i is the index within the cache of frames
     307
     308    // If we're outside of the normal boundaries of the buffer,
     309    // see if we've precached this frame
     310    if (i < stillFrames.minIndex() || i > stillFrames.maxIndex())
     311    {
     312        VERBOSE(VB_IMPORTANT, QString("Invalid index %1 [%2, %3]")
     313                            .arg(i).arg(stillFrames.minIndex()).arg(stillFrames.maxIndex()));
     314        return true;
     315    }
     316
     317    int64_t targetFrame = stillMainFrameNumber + i * seekamount;
     318    if (targetFrame <= maxFrameNumber && !stillFrames[i] && !stillImages[i])
     319    {
     320        int tmpCutFrame;
     321        QImage *tmpStillImage = NULL;
     322        QImage *tmpStillImageBig = NULL;
     323
     324        int64_t gotFrame = getFrame(i, tmpCutFrame, tmpStillImage, tmpStillImageBig);
     325        {
     326            VERBOSE(VB_GENERAL, QString("target = %1, got %2, index = %3, skamnt %4")
     327                    .arg(targetFrame).arg(gotFrame).arg(i).arg(seekamount));
     328            QMutexLocker l(&getImagesLock);
     329            if (runGetImages && !pauseGetImages && !wasPaused) {
     330                cutFrames[i] = tmpCutFrame;
     331                stillImages[i] = tmpStillImage;
     332                stillImagesBig[i] = tmpStillImageBig;
     333            } else {
     334                if (lastImage) {
     335                    delete lastImage;
     336                    delete lastImageBig;
     337                }
     338                lastImage = tmpStillImage;
     339                lastImageBig = tmpStillImageBig;
     340                lastCut = tmpCutFrame;
     341                lastImageFrameNumber = gotFrame;
     342           }
     343           wasPaused = false;
     344        }
     345        return true;
     346    }
     347
     348    return false;
     349}
     350
     351int64_t GridEditImages::getFrame(int64_t i,
     352        int &cutFrame,
     353        QImage * &stillImage,
     354        QImage * &stillImageBig)
     355{
     356    // get this frame
     357    int64_t targetFrame = stillMainFrameNumber + i * seekamount;
     358
     359    if (lastImage && lastImageFrameNumber == targetFrame) {
     360        VERBOSE(VB_GENERAL, QString("Found Cache to %1 Frame[%2] (frame # %3)")
     361                            .arg(i).arg(i*seekamount).arg(targetFrame));
     362        cutFrame = lastCut;
     363        stillImage = lastImage;
     364        stillImageBig = lastImageBig;
     365        lastImage = NULL;
     366        lastImageBig = NULL;
     367        lastImageFrameNumber = -1;
     368        return targetFrame;
     369    }
     370
     371    if (!m_player->EditSeekToFrame(targetFrame))
     372    {
     373        VERBOSE(VB_GENERAL, QString("Error seeking to Frame[%1] (frame # %2)")
     374                            .arg(i).arg(targetFrame));
     375        checkMaxFrameCount(targetFrame);
     376    }
     377    else
     378    {
     379        cutFrame = m_deleteMap->GetCutStatus(targetFrame, true, stillMainFrameNumber);
     380
     381        stillImageBig = new QImage();
     382        stillImage = new QImage();
     383        m_player->GetScreenGrabsOfCurrentFrame(*stillImageBig, *stillImage);
     384
     385#if FRAME_DEBUG
     386        VERBOSE(VB_GENERAL, QString("stillFrames[%1] = %2 (%3)")
     387                .arg(i)
     388                .arg(targetFrame)
     389                .arg(cutFrame));
     390#endif
     391    }
     392    return targetFrame;
     393}
     394
     395void GridEditImages::SetVideoInfo(int vcount, QSize sizeMain, QSize sizeSmall)
     396{
     397    usedSubVideoCount = vcount;
     398    videoSizeMain = sizeMain;
     399    videoSizeSmall = sizeSmall;
     400
     401    m_player->SetScreenGrabSizes(videoSizeMain, videoSizeSmall);
     402
     403    // start to grab the current images
     404    startFrameCaching();
     405}
     406
     407void GridEditImages::startFrameCaching()
     408{
     409    frameCacheLevel=0;
     410    getFrameIndexes(frameCacheLevel);
     411    {
     412        QMutexLocker l(&getImagesLock);
     413        pauseGetImages = false;
     414        getImagesCondition.wakeAll();
     415    }
     416}
     417
     418void GridEditImages::stopFrameCaching()
     419{
     420    {
     421        QMutexLocker l(&getImagesLock);
     422        pauseGetImages = true;
     423        wasPaused = true;
     424    }
     425}
     426
     427void GridEditImages::refreshAllFrames()
     428{
     429
     430    int i;
     431    bool alldone;
     432    for (i = -usedSubVideoCount; i <= usedSubVideoCount; i++)
     433    {
     434        if (stillFrames[i] == NULL)
     435            alldone = false;
     436    }
     437
     438    if (alldone)
     439        m_editor->refreshImages();
     440}
     441
     442void GridEditImages::updateAllFrames()
     443{
     444    // getStillFrames() returns 'true' on the next call after it's gotten all requested frames
     445
     446    if (getStillFrames(1))
     447    {
     448        if (frameCacheLevel == 1)
     449        {
     450            GotImageEvent *event = new GotImageEvent();
     451            //if (frameCacheLevel == -2 && ! bufferIsEmpty())
     452            //    event->framenumber = 0;
     453            //else
     454                event->framenumber = frameCacheLevel;
     455            QApplication::postEvent(this, event);
     456        }
     457
     458        frameCacheLevel++;
     459        // if we were on 0, then wait to see if we seek again
     460        if ( 0 && frameCacheLevel == 1)
     461        {
     462            QMutexLocker l(&getImagesLock);
     463            getImagesCondition.wait(&getImagesLock, 1000);
     464            if (pauseGetImages) return;
     465        }
     466
     467        if (getFrameIndexes(frameCacheLevel))
     468            getStillFrames(1);
     469        else
     470            stopFrameCaching();
     471    }
     472
     473    if (frameCacheLevel < 2)
     474    {
     475        GotImageEvent *event = new GotImageEvent();
     476        //if (frameCacheLevel == -2 && ! bufferIsEmpty())
     477        //    event->framenumber = 0;
     478        //else
     479            event->framenumber = frameCacheLevel;
     480        QApplication::postEvent(this, event);
     481    }
     482//    m_editor->refreshImages();
     483}
     484
     485void GridEditImages::clearStillFrames(bool skipMain)
     486{
     487FUNCTIONLOGGER;
     488    QMutexLocker l(&getImagesLock);
     489    int i;
     490    for (i = stillFrames.minIndex(); i <= stillFrames.maxIndex(); i++)
     491    {
     492        if (skipMain && i == 0)
     493            continue;
     494        if (stillFrames[i])
     495        {
     496            delete stillFrames[i];
     497            stillFrames[i] = NULL;
     498        }
     499        if (stillFramesBig[i])
     500        {
     501            delete stillFramesBig[i];
     502            stillFramesBig[i] = NULL;
     503        }
     504        if (stillImages[i])
     505        {
     506            delete stillImages[i];
     507            stillImages[i] = NULL;
     508        }
     509        if (stillImagesBig[i])
     510        {
     511            delete stillImagesBig[i];
     512            stillImagesBig[i] = NULL;
     513        }
     514        cutFrames[i] = 0;
     515    }
     516}
     517
     518bool GridEditImages::shiftStillFramesLeft(int offset)
     519{
     520FUNCTIONLOGGER_TAGGED(QString("Offset = %1").arg(offset));
     521    // offset should be 1 or 10 (* seekamount)
     522    // but the images are already cached by seekamount
     523
     524    if (offset > 2 * stillFrames.maxIndex())
     525    {
     526        // Dump all cached data and re-get it
     527        clearStillFrames();
     528    }
     529    else if (offset < 0)
     530    {
     531        VERBOSE(VB_IMPORTANT, QString("Offset (%1) < 0").arg(offset));
     532        // Dump all cached data and re-get it
     533        clearStillFrames();
     534        offset = 0;
     535    }
     536    else if (offset != 0)
     537    {
     538        // Shift backwards in the stream by offset
     539
     540        // All frames will actually shift to the right.
     541        // frame 'n' will become frame 'n+1'
     542        // frame stillFrameMinus[1] will become mainframe
     543        // frame stillFramePlus[max] will drop off
     544
     545        // shove extra frames into the excess space above usedSubVideos
     546
     547        stillMainFrameNumber -= offset * seekamount;
     548
     549        //    printStillFrameStats("Before SL");
     550        int i,j;
     551        int minIndex = stillFrames.minIndex();
     552        int maxIndex = stillFrames.maxIndex();
     553        for (i = 0; i < offset; i++)
     554        {
     555
     556            if (stillFrames[maxIndex])
     557            {
     558                delete stillFrames[maxIndex];
     559                delete stillFramesBig[maxIndex];
     560            }
     561            if (stillImages[maxIndex])
     562            {
     563                delete stillImages[maxIndex];
     564                delete stillImagesBig[maxIndex];
     565            }
     566
     567            for (j = maxIndex; j > minIndex; j--) {
     568                cutFrames[j]      = cutFrames[j-1];
     569                stillFrames[j]    = stillFrames[j-1];
     570                stillFramesBig[j] = stillFramesBig[j-1];
     571                stillImages[j]    = stillImages[j-1];
     572                stillImagesBig[j] = stillImagesBig[j-1];
     573            }
     574
     575             stillFrames[minIndex]    = NULL;
     576             stillFramesBig[minIndex] = NULL;
     577             stillImages[minIndex]    = NULL;
     578             stillImagesBig[minIndex] = NULL;
     579             cutFrames[minIndex]      = 0;
     580        }
     581
     582        //   printStillFrameStats("After SL");
     583
     584    }
     585
     586
     587    return (stillFramesBig[0] != NULL);
     588}
     589
     590bool GridEditImages::shiftStillFramesRight(int offset)
     591{
     592FUNCTIONLOGGER_TAGGED(QString("Offset = %1").arg(offset));
     593    // offset should be 1 or 10 (* seekamount)
     594    // but the images are already cached by seekamount
     595
     596    //VERBOSE(VB_GENERAL, QString("Offset =  %1").arg(offset));
     597    if (offset > 2 * stillFrames.maxIndex())
     598    {
     599        // Dump all cached data and re-get it
     600        clearStillFrames();
     601    }
     602    else if (offset < 0)
     603    {
     604        VERBOSE(VB_IMPORTANT, QString("Offset (%1) < 0").arg(offset));
     605        // Dump all cached data and re-get it
     606        clearStillFrames();
     607        offset = 0;
     608    }
     609    else if (offset != 0)
     610    {
     611
     612        // Shift forwards in the stream by offset
     613
     614        // All frames will actually shift to the left.
     615        // frame 'n' will become frame 'n-1'
     616        // frame stillFramePlus[1] will become mainframe
     617        // frame stillFrameMinus[max] will drop off
     618
     619        // shove extra frames into the excess space above usedSubVideos
     620
     621        stillMainFrameNumber += offset * seekamount;
     622
     623        //printStillFrameStats("Before SR");
     624
     625        int i,j;
     626        int minIndex = stillFrames.minIndex();
     627        int maxIndex = stillFrames.maxIndex();
     628
     629        for (i = 0; i < offset; i++)
     630        {
     631            if (stillFrames[minIndex])
     632            {
     633                delete stillFrames[minIndex];
     634                delete stillFramesBig[minIndex];
     635            }
     636
     637            if (stillImages[minIndex])
     638            {
     639                delete stillImages[minIndex];
     640                delete stillImagesBig[minIndex];
     641            }
     642
     643            for (j = minIndex; j < maxIndex; j++) {
     644                cutFrames[j]      = cutFrames[j+1];
     645                stillFrames[j]    = stillFrames[j+1];
     646                stillFramesBig[j] = stillFramesBig[j+1];
     647                stillImages[j]    = stillImages[j+1];
     648                stillImagesBig[j] = stillImagesBig[j+1];
     649            }
     650
     651             stillFrames[maxIndex]    = NULL;
     652             stillFramesBig[maxIndex] = NULL;
     653             stillImages[maxIndex]    = NULL;
     654             stillImagesBig[maxIndex] = NULL;
     655             cutFrames[maxIndex]      = 0;
     656        }
     657
     658        //printStillFrameStats("After SR");
     659
     660    }
     661
     662    return (stillFramesBig[0] != NULL);
     663}
     664
     665void GridEditImages::printStillFrameStats(QString caption)
     666{
     667    int i;
     668    // Debug info for frame cache
     669    QString foundframes= caption + " Found Frames: ";
     670
     671    for (i = stillFrames.minIndex(); i <= stillFrames.maxIndex(); i++)
     672        if (stillFrames[i])
     673            foundframes += QString("%1 ").arg(i);
     674
     675    VERBOSE(VB_GENERAL, foundframes);
     676}
     677
     678void GridEditImages::refreshCutList(CutPointImage* gridimagemain,
     679                                    myArray<CutPointImage*, MAX_SUB_VIDEOS> &gridimages)
     680{
     681    int i;
     682
     683    for (i = stillFrames.minIndex(); i <= stillFrames.maxIndex(); i++)
     684    {
     685        if (stillFrames[i])
     686        {
     687            cutFrames[i] = m_deleteMap->GetCutStatus(stillMainFrameNumber+i*seekamount,
     688                                                     true, stillMainFrameNumber);
     689            if (gridimages[i])
     690                gridimages[i]->setCutStatus(cutFrames[i]);
     691        }
     692    }
     693    gridimagemain->setCutStatus(cutFrames[0]);
     694}
     695
     696void GridEditImages::UpdateImages(int index)
     697{
     698    // getImagesLock should be locked here
     699
     700    if (stillImagesBig[index]) {
     701       if (stillFramesBig[index])
     702           delete stillFramesBig[index];
     703       stillFramesBig[index] = makeScaledPixmap(*stillImagesBig[index], videoSizeMain);
     704       delete stillImagesBig[index];
     705       stillImagesBig[index] = NULL;
     706    }
     707
     708    if (stillImages[index]) {
     709       if (stillFrames[index])
     710           delete stillFrames[index];
     711       stillFrames[index] = makeScaledPixmap(*stillImages[index], videoSizeSmall);
     712       delete stillImages[index];
     713       stillImages[index] = NULL;
     714    }
     715
     716//    if (!stillFramesBig[index]) {
     717//        stillFramesBig[index] = new QPixmap(videoSizeMain);
     718//        stillFramesBig[index]->fill(Qt::gray);
     719//    }
     720
     721//    if (!stillFrames[index]) {
     722//        stillFrames[index] = new QPixmap(videoSizeSmall);
     723//        stillFrames[index]->fill(Qt::gray);
     724//    }
     725}
     726
     727bool GridEditImages::refreshImages(CutPointImage* gridimagemain,
     728                                   myArray<CutPointImage*, MAX_SUB_VIDEOS> &gridimages,
     729                                   bool mainFrameOnly)
     730{
     731//FUNCTIONLOGGER;
     732    QMutexLocker l(&getImagesLock);
     733    bool alldone = true;
     734
     735//        stillFrameBig = makeScaledPixmap(normal, videoSizeMain);
     736//        stillFrame    = makeScaledPixmap(small, videoSizeSmall);
     737
     738    UpdateImages(0);
     739//    if (!stillFramesBig[0])
     740//        VERBOSE(VB_GENERAL, QString("Null Big Main frame %1").arg(stillMainFrameNumber));
     741    gridimagemain->SetPixmap(stillFramesBig[0],
     742                             stillMainFrameNumber,
     743                             cutFrames[0]);
     744
     745    if (mainFrameOnly && gridimages[0])
     746        gridimages[0]->SetPixmap(stillFrames[0],
     747                                 stillMainFrameNumber,
     748                                 cutFrames[0]);
     749
     750
     751    if (!mainFrameOnly)
     752    {
     753//FUNCTIONLOGGER_MARK;
     754        int i;
     755        for (i = -usedSubVideoCount; i <= usedSubVideoCount; i++)
     756        {
     757            UpdateImages(i);
     758            if (stillFrames[i] == NULL)
     759                alldone = false;
     760            if (gridimages[i])
     761                gridimages[i]->SetPixmap(stillFrames[i],
     762                                         (stillMainFrameNumber + i * seekamount),
     763                                         cutFrames[i]);
     764        }
     765    }
     766    return alldone;
     767}
     768
     769// Back up x frames
     770void GridEditImages::SeekLeft(bool bigseek, bool cutpointseek)
     771{
     772    if (stillMainFrameNumber == 1)
     773        return; // Already on the first frame
     774
     775    int64_t seekcount = (bigseek ? 10 : 1);
     776    lastmovewasright = false;
     777    stopFrameCaching();
     778    m_editor->displayCacheStatus(0);
     779
     780    if (cutpointseek)
     781    {
     782        int64_t cutframe = m_deleteMap->GetNearestMark(stillMainFrameNumber, maxFrameNumber, false);
     783        seekcount = stillMainFrameNumber - cutframe;
     784    }
     785
     786    VERBOSE(VB_GENERAL, QString("SeekLeft %1, cutpoint = %2").arg(seekamount).arg(cutpointseek));
     787
     788    if (cutpointseek)
     789    {
     790        stillMainFrameNumber -= seekcount;
     791        if (stillMainFrameNumber < 1 )
     792            stillMainFrameNumber = 1;
     793        clearStillFrames();
     794    }
     795    else if ((stillMainFrameNumber - seekcount * seekamount) < 1)
     796    {
     797        // We tried to seek before the first frame
     798        stillMainFrameNumber = 1;
     799        clearStillFrames();
     800    }
     801    else
     802        shiftStillFramesLeft(seekcount);
     803
     804    startFrameCaching();
     805}
     806
     807void GridEditImages::SeekRight(bool bigseek, bool cutpointseek)
     808{
     809    if ( stillMainFrameNumber == maxFrameNumber)
     810        return; // Already on the last frame
     811
     812    int64_t seekcount = (bigseek ? 10 : 1);
     813    lastmovewasright = true;
     814    stopFrameCaching();
     815    m_editor->displayCacheStatus(0);
     816
     817    if (cutpointseek)
     818    {
     819        int64_t cutframe = m_deleteMap->GetNearestMark(stillMainFrameNumber, maxFrameNumber, true);
     820        seekcount = cutframe - stillMainFrameNumber;
     821    }
     822
     823    VERBOSE(VB_GENERAL, QString("SeekRight %1, cutpoint = %2").arg(seekamount).arg(cutpointseek));
     824
     825    if (cutpointseek)
     826    {
     827        stillMainFrameNumber += seekcount;
     828        if (stillMainFrameNumber > maxFrameNumber )
     829            stillMainFrameNumber = maxFrameNumber;
     830        clearStillFrames();
     831    }
     832    else if (( stillMainFrameNumber + seekcount * seekamount) > maxFrameNumber)
     833    {
     834        stillMainFrameNumber = maxFrameNumber;
     835        clearStillFrames();
     836    }
     837    else
     838        shiftStillFramesRight(seekcount);
     839
     840    if (!stillFrames[0])
     841        bumpRightTimer->start(500); // 1/2 second
     842
     843    startFrameCaching();
     844}
     845
     846void GridEditImages::bumpRight()
     847{
     848    // VERBOSE(VB_GENERAL, "bumpRight");
     849    stopFrameCaching();
     850    if (stillFrames[0]) {
     851
     852        // Cancel the timer
     853        bumpRightTimer->stop();
     854    }
     855    else if (stillMainFrameNumber > maxFrameNumber)
     856    {
     857        stillMainFrameNumber = maxFrameNumber;
     858        clearStillFrames();
     859
     860        m_editor->refreshFrameCount();
     861
     862        // Cancel the timer
     863        bumpRightTimer->stop();
     864    }
     865    startFrameCaching();
     866}
     867
     868void GridEditImages::UpdateSeekAmount()
     869{
     870FUNCTIONLOGGER;
     871    int64_t newseekamount = m_deleteMap->GetSeekAmount();
     872
     873    if (newseekamount < 0 || newseekamount == seekamount)
     874        return;
     875
     876    stopFrameCaching();
     877    m_editor->displayCacheStatus(0);
     878
     879    SetNewSeekAmount(newseekamount);
     880
     881    startFrameCaching();
     882}
     883
     884void GridEditImages::SetNewSeekAmount(int64_t newseekamount)
     885{
     886    myArray<int, MAX_SUB_VIDEOS> newCutFrames;
     887    myArray<QPixmap *, MAX_SUB_VIDEOS> newStillFrames;
     888    myArray<QPixmap *, MAX_SUB_VIDEOS> newStillFramesBig;
     889    myArray<QImage  *, MAX_SUB_VIDEOS> newStillImages;
     890    myArray<QImage  *, MAX_SUB_VIDEOS> newStillImagesBig;
     891
     892    newCutFrames[0]      = cutFrames[0];      cutFrames[0] = 0;
     893    newStillFrames[0]    = stillFrames[0];    stillFrames[0] = NULL;
     894    newStillFramesBig[0] = stillFramesBig[0]; stillFramesBig[0] = NULL;
     895    newStillImages[0]    = stillImages[0];    stillImages[0] = NULL;
     896    newStillImagesBig[0] = stillImagesBig[0]; stillImagesBig[0] = NULL;
     897
     898    int dest = 1, source = 1;
     899
     900    int copied=1;
     901    while (dest < stillFrames.maxIndex() && source < stillFrames.maxIndex()) {
     902
     903        if (dest * newseekamount < source * seekamount) {
     904            dest++;
     905        } else if (dest * newseekamount > source * seekamount) {
     906            source++;
     907        } else {
     908            newCutFrames[dest]      = cutFrames[source];        cutFrames[source] = 0;
     909            newStillFrames[dest]    = stillFrames[source];      stillFrames[source] = NULL;
     910            newStillFramesBig[dest] = stillFramesBig[source];   stillFramesBig[source] = NULL;
     911            newStillImages[dest]    = stillImages[source];      stillImages[source] = NULL;
     912            newStillImagesBig[dest] = stillImagesBig[source];   stillImagesBig[source] = NULL;
     913
     914            newCutFrames[-dest]      = cutFrames[-source];      cutFrames[-source] = 0;
     915            newStillFrames[-dest]    = stillFrames[-source];    stillFrames[-source] = NULL;
     916            newStillFramesBig[-dest] = stillFramesBig[-source]; stillFramesBig[-source] = NULL;
     917            newStillImages[-dest]    = stillImages[-source];    stillImages[-source] = NULL;
     918            newStillImagesBig[-dest] = stillImagesBig[-source]; stillImagesBig[-source] = NULL;
     919            dest++;
     920            source++;
     921            copied+=2;
     922        }
     923    }
     924
     925    VERBOSE(VB_GENERAL, QString("Seekamount %1 -> %2").arg(seekamount).arg(newseekamount));
     926    seekamount = newseekamount;
     927
     928    clearStillFrames();
     929
     930    cutFrames.CopyFrom(newCutFrames);
     931    stillFrames.CopyFrom(newStillFrames);
     932    stillFramesBig.CopyFrom(newStillFramesBig);
     933    stillImages.CopyFrom(newStillImages);
     934    stillImagesBig.CopyFrom(newStillImagesBig);
     935
     936    VERBOSE(VB_GENERAL, QString("Copied %1 images to for new seekamount").arg(copied));
     937}
     938
     939void GridEditImages::checkMaxFrameCount(int64_t errorFrame)
     940{
     941    uint64_t tfc = m_player->GetTotalFrameCount();
     942    uint64_t tfp = m_player->GetFramesPlayed();
     943    VERBOSE(VB_GENERAL, QString("Before: tfc %1, mfn %2, mfnNVP %3, ef %4, tfp %5")
     944            .arg(tfc).arg(maxFrameNumber).arg(maxFrameNumberNVP).arg(errorFrame).arg(tfp));
     945return;
     946    if (tfc != maxFrameNumberNVP)
     947    {
     948       VERBOSE(VB_GENERAL, QString("Updating: tfc %1, mfn %2, mfnNVP %3")
     949            .arg(tfc).arg(maxFrameNumber).arg(maxFrameNumberNVP));
     950        // Check to see if things changed
     951        maxFrameNumber = tfc;
     952        maxFrameNumberNVP = tfc;
     953    }
     954    if (tfp > 0 && maxFrameNumber >= tfp)
     955    {
     956       VERBOSE(VB_GENERAL, QString("Updating: tfc %1, mfn %2 -> tfp %5, mfnNVP %3 ef %4")
     957            .arg(tfc).arg(maxFrameNumber).arg(maxFrameNumberNVP).arg(errorFrame).arg(tfp));
     958        // Check to see if things changed
     959        maxFrameNumber = tfp;
     960        maxFrameNumberNVP = tfc;
     961    }
     962//    VERBOSE(VB_GENERAL, QString("After: tfc %1, mfn %2, mfnNVP %3 ef %4")
     963//            .arg(tfc).arg(maxFrameNumber).arg(maxFrameNumberNVP).arg(errorFrame));
     964
     965}
     966
     967FrameStats GridEditImages::GetMainFrameStats()
     968{
     969    FrameStats result;
     970
     971    result.valid = (stillFrames[0] != NULL);
     972    result.frameNumber = stillMainFrameNumber;
     973    result.cutInd  = cutFrames[0];
     974    result.maxFrameNumber = maxFrameNumber;
     975
     976    return result;
     977}
     978
  • new file mythbuild/mythtv/libs/libmythtv/grideditimages.h

    - + --- Hunk 1 mythbuild/mythtv/libs/libmythtv/grideditimages.h 
     1// -*- Mode: c++ -*-
     2#ifndef GRIDEDITIMAGES_H_
     3#define GRIDEDITIMAGES_H_
     4
     5#include <QString>
     6
     7#include "libmyth/mythwidgets.h"
     8
     9#include <QEvent>
     10#include <QThread>
     11#include <QMutex>
     12#include <QWaitCondition>
     13
     14using namespace std;
     15
     16class QTimer;
     17class MythPlayer;
     18class GridEditCutpoints;
     19class CutPointImage;
     20class DeleteMap;
     21
     22#define MAX_SUB_VIDEOS 25
     23
     24// Simple class to allow array indexing from -MAX_SUB_VIDEOS to +MAX_SUB_VIDEOS
     25template<class T, int COUNT> class myArray
     26{
     27    public:
     28        myArray() { memset(_array, 0, sizeof(_array));};
     29
     30        T& operator[](int i) { return _array[COUNT+i]; };
     31        int minIndex() const { return -COUNT; };
     32        int maxIndex() const { return  COUNT; };
     33
     34        void CopyFrom(myArray<T, COUNT> const & other) { memcpy(_array, other._array, sizeof(_array)); }
     35
     36    private:
     37        T _array[2*COUNT+1];
     38};
     39
     40class FrameStats
     41{
     42    public:
     43        bool valid;
     44        long long frameNumber;
     45        int cutInd;
     46        long long maxFrameNumber;
     47};
     48
     49class GotImageEvent: public QEvent
     50{
     51    public:
     52        GotImageEvent() : QEvent(kEventType) {};
     53        long long framenumber;
     54
     55        static const Type kEventType;
     56};
     57
     58class CacheStatusEvent: public QEvent
     59{
     60    public:
     61        CacheStatusEvent() : QEvent(kEventType) {};
     62        int newlevel;
     63
     64        static const Type kEventType;
     65};
     66
     67class GridEditImages;
     68class GridCacheThread : public QThread
     69{
     70
     71    public:
     72        virtual void run();
     73        void SetGEI( GridEditImages* gei) { _gei = gei; }
     74
     75    private:
     76        GridEditImages* _gei;
     77};
     78
     79class MPUBLIC GridEditImages : public QObject
     80{
     81    Q_OBJECT
     82
     83    public:
     84        GridEditImages(GridEditCutpoints *er, MythPlayer *player);
     85        ~GridEditImages();
     86
     87        void refreshCutList(CutPointImage* gridimagemain,
     88                            myArray<CutPointImage*, MAX_SUB_VIDEOS> &gridimages);
     89
     90        // return true if anything changed
     91        bool refreshImages(CutPointImage* gridimagemain,
     92                           myArray<CutPointImage*, MAX_SUB_VIDEOS> &gridimages,
     93                           bool mainFrameOnly);
     94
     95        void SeekLeft(bool bigseek = false, bool cutpointseek = false);
     96        void SeekRight(bool bigseek = false, bool cutpointseek = false);
     97        void UpdateSeekAmount();
     98
     99        FrameStats GetMainFrameStats();
     100        long long GetCurrentFrameNumber() const { return stillMainFrameNumber; }
     101        long long GetMaxFrameNumber() const { return maxFrameNumber; }
     102
     103        void SetVideoInfo(int vcount, QSize sizeMain, QSize sizeSmall);
     104
     105    protected slots:
     106        void refreshAllFrames();
     107        void bumpRight();
     108
     109    protected: // slots:
     110        void updateAllFrames();
     111        void UpdateImages(int index);
     112
     113        void customEvent(QEvent *event);
     114
     115    private:
     116        // Private functions
     117        void clearStillFrames(bool skipMain = false);
     118        void SetNewSeekAmount(int64_t newseekamount);
     119        void printStillFrameStats(QString caption);
     120        void checkMaxFrameCount(int64_t errorframe);
     121
     122        // 'newlevel' paramter for getStillFrames():
     123        //  0 = get on screen Frames only
     124        //  1 = get preCache Frames only
     125        //  2 = get any necessary frames
     126        //  3 = done
     127        bool getFrameIndexes(int newlevel);
     128        void displayCacheStatus(int newlevel);
     129
     130        bool getStillFrames(int maxcount = 1000);
     131        bool bufferIsFull();
     132        bool bufferIsEmpty();
     133        bool getSpecificFrame(int frameindex);
     134        int64_t getFrame(int64_t i, int &cutFrame, QImage* &stillImage, QImage* &stillImageBig);
     135
     136        // return true if anything changed
     137        bool shiftStillFramesLeft(int offset);  // offset is the number of index positions to shift
     138        bool shiftStillFramesRight(int offset); // offset is the number of index positions to shift
     139        void startFrameCaching();
     140        void stopFrameCaching();
     141        QTimer  *bumpRightTimer;
     142
     143
     144        QPixmap *makeScaledPixmap(const QImage& qim, QSize sz);
     145
     146        // Private data
     147        // These frames are in the cutlist
     148        // 0 == not cut
     149        // 1 == cut
     150        // 2 == cutpoint (cut left)
     151        // 3 == cutpoint (cut right)
     152        myArray<int, MAX_SUB_VIDEOS> cutFrames;
     153        myArray<QPixmap *, MAX_SUB_VIDEOS> stillFrames;
     154        myArray<QPixmap *, MAX_SUB_VIDEOS> stillFramesBig;
     155        myArray<QImage  *, MAX_SUB_VIDEOS> stillImages;
     156        myArray<QImage  *, MAX_SUB_VIDEOS> stillImagesBig;
     157
     158        int     lastCut;
     159        QImage *lastImage;
     160        QImage *lastImageBig;
     161        int64_t lastImageFrameNumber;
     162
     163        int64_t seekamount;
     164
     165        QSize     videoSizeMain;
     166        QSize     videoSizeSmall;
     167        int       usedSubVideoCount;
     168        int64_t   frameIndexLeft;
     169        int64_t   frameIndexRight;
     170        bool      lastmovewasright;
     171        bool      getFutureFramesFirst;
     172        int       frameCacheLevel;
     173
     174        int64_t stillMainFrameNumber; // frame number for big still picture
     175        int64_t currentFrameNumberNVP; // frame number the NVP should be on
     176        int64_t maxFrameNumber;       // max frame number override for NVP
     177        int64_t maxFrameNumberNVP;    // Original NVP number
     178
     179        GridEditCutpoints *m_editor;
     180        MythPlayer *m_player;
     181        DeleteMap *m_deleteMap;
     182
     183        QMutex             getImagesLock;
     184        QWaitCondition     getImagesCondition;
     185        bool               runGetImages;
     186        bool               pauseGetImages;
     187        bool               getImagesDone;
     188        bool               gotScreenFrames;
     189        bool               wasPaused;
     190        static void*       getImagesHelper(void*);
     191
     192public:
     193        void *             getImagesThread(void);
     194
     195        GridCacheThread    gridCacheThread;
     196
     197};
     198
     199#endif
  • mythtv/libs/libmythtv/libmythtv.pro

    old new using_frontend { --- Hunk 1 mythbuild/mythtv/libs/libmythtv/libmythtv.pro 
    355355    # Misc. frontend
    356356    HEADERS += DetectLetterbox.h
    357357    SOURCES += DetectLetterbox.cpp
     358    HEADERS += grideditcutpoints.h      grideditimages.h
     359    SOURCES += grideditcutpoints.cpp    grideditimages.cpp
    358360
    359361    using_mheg {
    360362        # DSMCC stuff
  • mythtv/libs/libmythtv/mythplayer.cpp

    old new int isnan(double); --- Hunk 1 mythbuild/mythtv/libs/libmythtv/mythplayer.cpp 
    8282}
    8383#endif
    8484
     85#ifndef FUNCTIONLOGGER
     86#define FUNCTIONLOGGER
     87#define FUNCTIONLOGGER_MARK
     88#define FUNCTIONLOGGER_TIMED
     89#define FUNCTIONLOGGER_TAGGED(s)
     90#define FUNCTIONLOGGER_TMTAG(s)
     91#endif
     92
    8593static unsigned dbg_ident(const MythPlayer*);
    8694
    8795#define LOC      QString("Player(%1): ").arg(dbg_ident(this),0,36)
    MythPlayer::MythPlayer(bool muted) --- Hunk 2 mythbuild/mythtv/libs/libmythtv/mythplayer.cpp 
    183191      audio(this, muted),
    184192      // Picture-in-Picture stuff
    185193      pip_active(false),            pip_visible(true),
     194      // Grid Editing
     195      grid_edit_image_scaler(NULL), grid_edit_image_small_scaler(NULL),
     196      grid_edit_image_buffer_yuv(NULL), grid_edit_image_small_buffer_yuv(NULL),
     197      grid_edit_image_buffer_rgb(NULL), grid_edit_image_small_buffer_rgb(NULL),
     198      grid_edit_image_buffer_length(0), grid_edit_image_small_buffer_length(0),
     199      grid_edit_image_in_size(-1, -1),
     200
    186201      // Filters
    187202      videoFiltersForProgram(""),   videoFiltersOverride(""),
    188203      postfilt_width(0),            postfilt_height(0),
    MythPlayer::~MythPlayer(void) --- Hunk 3 mythbuild/mythtv/libs/libmythtv/mythplayer.cpp 
    291306        delete detect_letter_box;
    292307        detect_letter_box = NULL;
    293308    }
     309
     310    ClearScreenGrab();
    294311}
    295312
    296313void MythPlayer::SetWatchingRecording(bool mode)
    void MythPlayer::UnpauseBuffer(void) --- Hunk 4 mythbuild/mythtv/libs/libmythtv/mythplayer.cpp 
    325342
    326343bool MythPlayer::Pause(void)
    327344{
     345FUNCTIONLOGGER;
    328346    if (!pauseLock.tryLock(100))
    329347    {
    330348        VERBOSE(VB_PLAYBACK, LOC + "Waited 100ms to get pause lock.");
    void MythPlayer::EventLoop(void) --- Hunk 5 mythbuild/mythtv/libs/libmythtv/mythplayer.cpp 
    26432661    }
    26442662
    26452663    // Handle cutlist skipping
    2646     if (deleteMap.TrackerWantsToJump(framesPlayed, totalFrames, jumpto) &&
    2647         (ffrew_skip == 1))
     2664    if ((ffrew_skip == 1) && deleteMap.TrackerWantsToJump(framesPlayed, totalFrames, jumpto))
    26482665    {
    26492666        if (jumpto == totalFrames)
    26502667        {
    void MythPlayer::ClearAfterSeek(bool cle --- Hunk 6 mythbuild/mythtv/libs/libmythtv/mythplayer.cpp 
    34553472    needNewPauseFrame = true;
    34563473}
    34573474
     3475// Stuff for GridEditCutpoints
     3476
     3477void MythPlayer::SetScreenGrabSizes(QSize normal, QSize small)
     3478{
     3479    grid_edit_image_size = normal;
     3480    grid_edit_image_small_size = small;
     3481
     3482    SetupScreenGrab();
     3483    VERBOSE(VB_GENERAL, QString("Main Image = (%1, %2) from (%3, %4)")
     3484                        .arg(grid_edit_image_size.width())
     3485                        .arg(grid_edit_image_size.height())
     3486                        .arg(normal.width()).arg(normal.height()));
     3487    VERBOSE(VB_GENERAL, QString("Small Image = (%1, %2) from (%3, %4)")
     3488                        .arg(grid_edit_image_small_size.width())
     3489                        .arg(grid_edit_image_small_size.height())
     3490                        .arg(small.width()).arg(small.height()));
     3491}
     3492
     3493bool MythPlayer::EditSeekToFrame(uint64_t targetFrame)
     3494{
     3495    bool tmpexactseeks = exactseeks;
     3496    decoder->setExactSeeks(true);
     3497    ClearAfterSeek();
     3498    int64_t before_frame = GetFramesPlayed();
     3499
     3500    DiscardVideoFrame(videoOutput->GetLastDecodedFrame());
     3501    DoJumpToFrame(targetFrame, true, true);
     3502    int tries = 0;
     3503    while (!videoOutput->ValidVideoFrames() && ((tries++) < 500))
     3504    {
     3505        decodeOneFrame = true;
     3506        usleep(10000);
     3507        if ((tries & 10) == 10)
     3508            VERBOSE(VB_PLAYBACK, LOC + QString("Waited 100ms for video frame"));
     3509    }
     3510
     3511    if (targetFrame != GetFramesPlayed())
     3512        VERBOSE(VB_GENERAL, QString("Error: Before current frame = %1, going to frame %2, got %3")
     3513                .arg(before_frame)
     3514                .arg(targetFrame)
     3515                .arg(GetFramesPlayed()));
     3516
     3517    RefreshPauseFrame();
     3518
     3519    decoder->setExactSeeks(tmpexactseeks);
     3520    return (targetFrame == GetFramesPlayed());
     3521}
     3522
     3523bool MythPlayer::GetScreenGrabsOfCurrentFrame(QImage &normal, QImage &small)
     3524{
     3525    FUNCTIONLOGGER;
     3526    VERBOSE(VB_GENERAL, QString("Frame = %1").arg(framesPlayed));
     3527    unsigned char *data      = NULL;
     3528    VideoFrame    *frame     = NULL;
     3529    AVPicture      orig;
     3530    AVPicture      scaled_yuv;
     3531    AVPicture      scaled_rgb;
     3532    AVPicture      scaled_yuv_small;
     3533    AVPicture      scaled_rgb_small;
     3534    bzero(&orig,         sizeof(AVPicture));
     3535    bzero(&scaled_yuv,       sizeof(AVPicture));
     3536    bzero(&scaled_rgb,       sizeof(AVPicture));
     3537    bzero(&scaled_yuv_small, sizeof(AVPicture));
     3538    bzero(&scaled_rgb_small, sizeof(AVPicture));
     3539
     3540    int vw, vh;
     3541    if (!(frame = videoOutput->GetLastDecodedFrame()))
     3542    {
     3543        return false;
     3544    }
     3545
     3546    if (!(data = frame->buf))
     3547    {
     3548        DiscardVideoFrame(frame);
     3549        return false;
     3550    }
     3551
     3552    {
     3553        QMutexLocker l(&videofiltersLock);
     3554
     3555        // Check to see if the screen dimensions have changed
     3556        // Probably shouldn't happen in normal use.
     3557        if (grid_edit_image_in_size != video_dim)
     3558            SetupScreenGrab();
     3559
     3560        avpicture_fill(&orig, data, PIX_FMT_YUV420P,
     3561                       video_dim.width(), video_dim.height());
     3562
     3563        avpicture_deinterlace(&orig, &orig, PIX_FMT_YUV420P,
     3564                              video_dim.width(), video_dim.height());
     3565
     3566        // Rescale to the normal size
     3567        avpicture_fill(&scaled_yuv, grid_edit_image_buffer_yuv, PIX_FMT_YUV420P,
     3568                       grid_edit_image_size.width(),
     3569                       grid_edit_image_size.height());
     3570
     3571        avpicture_fill(&scaled_rgb, grid_edit_image_buffer_rgb, PIX_FMT_RGB32,
     3572                       grid_edit_image_size.width(),
     3573                       grid_edit_image_size.height());
     3574
     3575        sws_scale(grid_edit_image_scaler, orig.data, orig.linesize, 0,
     3576                  video_dim.height(),
     3577                  scaled_yuv.data, scaled_yuv.linesize);
     3578
     3579        myth_sws_img_convert(
     3580            &scaled_rgb, PIX_FMT_RGB32, &scaled_yuv, PIX_FMT_YUV420P,
     3581                    grid_edit_image_size.width(), grid_edit_image_size.height());
     3582
     3583
     3584        // Rescale to the small size
     3585        avpicture_fill(&scaled_yuv_small, grid_edit_image_small_buffer_yuv, PIX_FMT_YUV420P,
     3586                       grid_edit_image_small_size.width(),
     3587                       grid_edit_image_small_size.height());
     3588
     3589        avpicture_fill(&scaled_rgb_small, grid_edit_image_small_buffer_rgb, PIX_FMT_RGB32,
     3590                       grid_edit_image_small_size.width(),
     3591                       grid_edit_image_small_size.height());
     3592
     3593        sws_scale(grid_edit_image_small_scaler, orig.data, orig.linesize, 0,
     3594                  video_dim.height(),
     3595                  scaled_yuv_small.data, scaled_yuv_small.linesize);
     3596
     3597        myth_sws_img_convert(
     3598            &scaled_rgb_small, PIX_FMT_RGB32, &scaled_yuv_small, PIX_FMT_YUV420P,
     3599                    grid_edit_image_small_size.width(), grid_edit_image_small_size.height());
     3600
     3601    }
     3602
     3603    // Don't need the current frame anymore so release it
     3604    DiscardVideoFrame(frame);
     3605
     3606
     3607#ifdef MMX
     3608#define _RGBSWAP .rgbSwapped()
     3609#endif
     3610
     3611    normal = QImage(grid_edit_image_buffer_rgb,
     3612                    grid_edit_image_size.width(), grid_edit_image_size.height(),
     3613                    QImage::Format_RGB32)_RGBSWAP;
     3614
     3615    small = QImage(grid_edit_image_small_buffer_rgb,
     3616                   grid_edit_image_small_size.width(), grid_edit_image_small_size.height(),
     3617                   QImage::Format_RGB32)_RGBSWAP;
     3618
     3619    return true;
     3620}
     3621
     3622void MythPlayer::ClearScreenGrab()
     3623{
     3624    if (grid_edit_image_scaler)
     3625    {
     3626        sws_freeContext(grid_edit_image_scaler);
     3627        grid_edit_image_scaler = NULL;
     3628    }
     3629
     3630    if (grid_edit_image_small_scaler)
     3631    {
     3632        sws_freeContext(grid_edit_image_small_scaler);
     3633        grid_edit_image_small_scaler=NULL;
     3634    }
     3635
     3636    if (grid_edit_image_buffer_yuv)
     3637    {
     3638        delete grid_edit_image_buffer_yuv;
     3639        grid_edit_image_buffer_yuv=NULL;
     3640    }
     3641
     3642    if (grid_edit_image_small_buffer_yuv)
     3643    {
     3644        delete grid_edit_image_small_buffer_yuv;
     3645        grid_edit_image_small_buffer_yuv=NULL;
     3646    }
     3647
     3648    if (grid_edit_image_buffer_rgb)
     3649    {
     3650        delete grid_edit_image_buffer_rgb;
     3651        grid_edit_image_buffer_rgb=NULL;
     3652    }
     3653
     3654    if (grid_edit_image_small_buffer_rgb)
     3655    {
     3656        delete grid_edit_image_small_buffer_rgb;
     3657        grid_edit_image_small_buffer_rgb=NULL;
     3658    }
     3659}
     3660
     3661void MythPlayer::SetupScreenGrab()
     3662{
     3663    ClearScreenGrab();
     3664    grid_edit_image_in_size = video_dim;
     3665
     3666    // Normalize the output sizes.
     3667    // This is necessary to preserve the aspect ratio
     3668
     3669    QSize tmpsize = grid_edit_image_size;
     3670    grid_edit_image_size =  video_dim;
     3671    grid_edit_image_size.scale(tmpsize, Qt::KeepAspectRatio);
     3672
     3673    tmpsize = grid_edit_image_small_size;
     3674    grid_edit_image_small_size = video_dim;
     3675    grid_edit_image_small_size.scale(tmpsize, Qt::KeepAspectRatio);
     3676
     3677    grid_edit_image_size = QSize(grid_edit_image_size.width() & ~0x7,
     3678                                 grid_edit_image_size.height() & ~0x7);
     3679    grid_edit_image_small_size = QSize(grid_edit_image_small_size.width() & ~0x7,
     3680                                       grid_edit_image_small_size.height() & ~0x7);
     3681
     3682    // Do normal first
     3683    uint sz = grid_edit_image_size.width() * grid_edit_image_size.height();
     3684    grid_edit_image_buffer_yuv = new unsigned char[(sz * 3 / 2) + 128];
     3685    grid_edit_image_buffer_rgb = new unsigned char[sz * 4 + 128];
     3686
     3687    //grid_edit_image_scaler = img_resample_init(
     3688    //            grid_edit_image_size.width(), grid_edit_image_size.height(),
     3689    //            grid_edit_image_in_size.width(),  grid_edit_image_in_size.height());
     3690
     3691    grid_edit_image_scaler = sws_getCachedContext(grid_edit_image_scaler,
     3692                grid_edit_image_in_size.width(), grid_edit_image_in_size.height(),
     3693                PIX_FMT_YUV420P,
     3694                grid_edit_image_size.width(),  grid_edit_image_size.height(),
     3695                PIX_FMT_YUV420P,
     3696                SWS_FAST_BILINEAR, NULL, NULL, NULL);
     3697
     3698    // Then small
     3699    sz = grid_edit_image_small_size.width() * grid_edit_image_small_size.height();
     3700    grid_edit_image_small_buffer_yuv = new unsigned char[(sz * 3 / 2) + 128];
     3701    grid_edit_image_small_buffer_rgb = new unsigned char[sz * 4 + 128];
     3702
     3703    // Resize from normal to small
     3704    //grid_edit_image_small_scaler = img_resample_init(
     3705    //            grid_edit_image_small_size.width(), grid_edit_image_small_size.height(),
     3706    //            grid_edit_image_size.width(),  grid_edit_image_size.height());
     3707
     3708    grid_edit_image_small_scaler = sws_getCachedContext(grid_edit_image_small_scaler,
     3709                grid_edit_image_in_size.width(), grid_edit_image_in_size.height(),
     3710                PIX_FMT_YUV420P,
     3711                grid_edit_image_small_size.width(),  grid_edit_image_small_size.height(),
     3712                PIX_FMT_YUV420P,
     3713                SWS_FAST_BILINEAR, NULL, NULL, NULL);
     3714}
     3715
     3716
     3717// Stuff for GridEditCutpoints
     3718
    34583719void MythPlayer::SetPlayerInfo(TV *tv, QWidget *widget,
    34593720                               bool frame_exact_seek, PlayerContext *ctx)
    34603721{
    void MythPlayer::SetPlayerInfo(TV *tv, Q --- Hunk 7 mythbuild/mythtv/libs/libmythtv/mythplayer.cpp 
    34673728
    34683729bool MythPlayer::EnableEdit(void)
    34693730{
     3731FUNCTIONLOGGER;
    34703732    deleteMap.SetEditing(false);
    34713733
    34723734    if (!hasFullPositionMap)
    bool MythPlayer::EnableEdit(void) --- Hunk 8 mythbuild/mythtv/libs/libmythtv/mythplayer.cpp 
    35043766
    35053767void MythPlayer::DisableEdit(bool save)
    35063768{
     3769FUNCTIONLOGGER;
    35073770    QMutexLocker locker(&osdLock);
    35083771    if (!osd)
    35093772        return;
    bool MythPlayer::HandleProgramEditorActi --- Hunk 9 mythbuild/mythtv/libs/libmythtv/mythplayer.cpp 
    35553818        }
    35563819        else if (action == "LOADCOMMSKIP")
    35573820        {
    3558             if (commBreakMap.HasMap())
    3559             {
    3560                 frm_dir_map_t map;
    3561                 commBreakMap.GetMap(map);
    3562                 deleteMap.LoadCommBreakMap(totalFrames, map);
    3563             }
     3821            EditHandleLoadCommSkip();
    35643822        }
    35653823        else if (action == "PREVCUT")
    35663824        {
    bool MythPlayer::HandleProgramEditorActi --- Hunk 10 mythbuild/mythtv/libs/libmythtv/mythplayer.cpp 
    36513909    return handled;
    36523910}
    36533911
     3912void MythPlayer::StartEditRecordingGrid(int svc)
     3913{
     3914    deleteMap.SetAllowPagesize(video_frame_rate, svc);
     3915}
     3916
     3917void MythPlayer::EndEditRecordingGrid()
     3918{
     3919    ClearScreenGrab();
     3920
     3921    deleteMap.ClearAllowPagesize(video_frame_rate);
     3922
     3923    osdLock.lock();
     3924    if (osd)
     3925    {
     3926        deleteMap.UpdateOSD(framesPlayed, totalFrames, video_frame_rate,
     3927                            player_ctx, osd);
     3928    }
     3929    osdLock.unlock();
     3930}
     3931
     3932void MythPlayer::EditHandleLoadCommSkip()
     3933{
     3934    if (commBreakMap.HasMap())
     3935    {
     3936        frm_dir_map_t map;
     3937        commBreakMap.GetMap(map);
     3938        deleteMap.LoadCommBreakMap(totalFrames, map);
     3939    }
     3940}
     3941
    36543942bool MythPlayer::IsInDelete(uint64_t frame)
    36553943{
    36563944    return deleteMap.IsInDelete(frame);
    bool MythPlayer::HasTemporaryMark(void) --- Hunk 11 mythbuild/mythtv/libs/libmythtv/mythplayer.cpp 
    36713959    return deleteMap.HasTemporaryMark();
    36723960}
    36733961
     3962bool MythPlayer::IsMarked(uint64_t frame)
     3963{
     3964    return deleteMap.IsMarked(frame);
     3965}
     3966
    36743967void MythPlayer::HandleArbSeek(bool right)
    36753968{
    36763969    if (deleteMap.GetSeekAmount() == -2)
  • mythtv/libs/libmythtv/mythplayer.h

    old new class MPUBLIC MythPlayer --- Hunk 1 mythbuild/mythtv/libs/libmythtv/mythplayer.h 
    107107    friend class TV;
    108108    friend class DetectLetterbox;
    109109    friend class PlayerThread;
     110    friend class GridEditCutpoints;
     111    friend class GridEditImages;
    110112
    111113  public:
    112114    MythPlayer(bool muted = false);
    class MPUBLIC MythPlayer --- Hunk 2 mythbuild/mythtv/libs/libmythtv/mythplayer.h 
    233235    // Preview Image stuff
    234236    void SaveScreenshot(void);
    235237
     238    // Edit stuff
     239    bool EditSeekToFrame(uint64_t targetFrame);
     240    void SetScreenGrabSizes(QSize normal, QSize small);
     241    bool GetScreenGrabsOfCurrentFrame(QImage & normal, QImage &small); // Get current frame
     242    void SetupScreenGrab();
     243    void ClearScreenGrab();
     244
     245//    void       EditHandleClearMap();
     246//    void       EditHandleInvertMap();
     247    void  EditHandleLoadCommSkip();
     248
     249    void StartEditRecordingGrid(int svc);
     250    void EndEditRecordingGrid();
     251
    236252    // Reinit
    237253    void ReinitVideo(void);
    238254
    class MPUBLIC MythPlayer --- Hunk 3 mythbuild/mythtv/libs/libmythtv/mythplayer.h 
    389405    bool EnableEdit(void);
    390406    bool HandleProgramEditorActions(QStringList &actions, long long frame = -1);
    391407    bool GetEditMode(void) { return deleteMap.IsEditing(); }
     408    DeleteMap* GetDeleteMap() { return &deleteMap; }
    392409    void DisableEdit(bool save = true);
    393410    bool IsInDelete(uint64_t frame);
    394411    uint64_t GetNearestMark(uint64_t frame, bool right);
    395412    bool IsTemporaryMark(uint64_t frame);
    396413    bool HasTemporaryMark(void);
     414    bool IsMarked(uint64_t frame);
    397415
    398416    // Reinit
    399417    void ReinitOSD(void);
    class MPUBLIC MythPlayer --- Hunk 4 mythbuild/mythtv/libs/libmythtv/mythplayer.h 
    653671    volatile bool  pip_active;
    654672    volatile bool  pip_visible;
    655673
     674    // EditGrid still image capture
     675    struct SwsContext  *grid_edit_image_scaler;
     676    struct SwsContext  *grid_edit_image_small_scaler;
     677    unsigned char      *grid_edit_image_buffer_yuv;
     678    unsigned char      *grid_edit_image_small_buffer_yuv;
     679    unsigned char      *grid_edit_image_buffer_rgb;
     680    unsigned char      *grid_edit_image_small_buffer_rgb;
     681    int                 grid_edit_image_buffer_length;
     682    int                 grid_edit_image_small_buffer_length;
     683    QSize               grid_edit_image_in_size;
     684    QSize               grid_edit_image_size;
     685    QSize               grid_edit_image_small_size;
     686    QMutex              grid_edit_lock;
     687
    656688    // Filters
    657689    QMutex   videofiltersLock;
    658690    QString  videoFiltersForProgram;
  • mythtv/libs/libmythtv/tv_play.cpp

    old new using namespace std; --- Hunk 1 mythbuild/mythtv/libs/libmythtv/tv_play.cpp 
    5959#include "mythdialogbox.h"
    6060#include "mythdirs.h"
    6161#include "tvbrowsehelper.h"
     62#include "grideditcutpoints.h"
     63
     64#ifndef FUNCTIONLOGGER
     65#define FUNCTIONLOGGER
     66#define FUNCTIONLOGGER_MARK
     67#define FUNCTIONLOGGER_TIMED
     68#define FUNCTIONLOGGER_TAGGED(s)
     69#define FUNCTIONLOGGER_TMTAG(s)
     70#endif
     71
    6272
    6373#if ! HAVE_ROUND
    6474#define round(x) ((int) ((x) + 0.5))
    EMBEDRETURNVOIDEPG TV::RunProgramGuidePt --- Hunk 2 mythbuild/mythtv/libs/libmythtv/tv_play.cpp 
    152162 */
    153163EMBEDRETURNVOIDFINDER TV::RunProgramFinderPtr = NULL;
    154164
     165/**
     166 * \brief function pointer for RunGridEditCutpoints in grideditcutpoints.cpp
     167 */
     168EMBEDRETURNVOIDGEC TV::RunGridEditCutpointsPtr = NULL;
    155169
    156170/**
    157171 * \brief If any cards are configured, return the number.
    void TV::SetFuncPtr(const char *string, --- Hunk 3 mythbuild/mythtv/libs/libmythtv/tv_play.cpp 
    491505        RunProgramFinderPtr = (EMBEDRETURNVOIDFINDER)lptr;
    492506    else if (name == "scheduleeditor")
    493507        RunScheduleEditorPtr = (EMBEDRETURNVOIDSCHEDIT)lptr;
     508    else if (name == "grideditcutpoints")
     509        RunGridEditCutpointsPtr = (EMBEDRETURNVOIDGEC)lptr;
     510    else
     511        VERBOSE(VB_IMPORTANT, QString("Unknown Function specified: %1").arg(string));
    494512}
    495513
    496514void TV::InitKeys(void)
    void TV::InitKeys(void) --- Hunk 4 mythbuild/mythtv/libs/libmythtv/tv_play.cpp 
    780798            "Jump back 10x the normal amount"), ",,<");
    781799    REG_KEY("TV Editing", "BIGJUMPFWD",  QT_TRANSLATE_NOOP("MythControls",
    782800            "Jump forward 10x the normal amount"), ">,.");
     801    REG_KEY("TV Editing", "EDIT", "Exit out of Edit Mode", "E");
    783802
    784803    /* Teletext keys */
    785804    REG_KEY("Teletext Menu", "NEXTPAGE",    QT_TRANSLATE_NOOP("MythControls",
    void TV::ProcessKeypress(PlayerContext * --- Hunk 5 mythbuild/mythtv/libs/libmythtv/tv_play.cpp 
    35883607
    35893608        if (!handled)
    35903609        {
     3610            if (has_action("EDIT", actions))
     3611            {
     3612                // Should be go to Grid Edit Cutpoints
     3613                ShowEditRecordingGrid();
     3614                handled = true;
     3615            }
    35913616            if (has_action("MENU", actions))
    35923617            {
    3593                 ShowOSDCutpoint(actx, "EDIT_CUT_POINTS");
     3618                // Should be go to Grid Edit Cutpoints
     3619                ShowEditRecordingGrid();
     3620//                ShowOSDCutpoint(actx, "EDIT_CUT_POINTS");
    35943621                handled = true;
    35953622            }
    35963623            if (has_action("ESCAPE", actions))
    vector<bool> TV::DoSetPauseState(PlayerC --- Hunk 6 mythbuild/mythtv/libs/libmythtv/tv_play.cpp 
    77507777    return was_paused;
    77517778}
    77527779
     7780void TV::DoEditRecordingGrid()
     7781{
     7782FUNCTIONLOGGER;
     7783    if (!RunGridEditCutpointsPtr)
     7784        return;
     7785
     7786    PlayerContext *actx = GetPlayerReadLock(-1, __FILE__, __LINE__);
     7787
     7788    actx->LockPlayingInfo(__FILE__, __LINE__);
     7789    if (!actx->playingInfo)
     7790    {
     7791        VERBOSE(VB_IMPORTANT,
     7792                LOC_ERR + "no active ctx playingInfo.");
     7793        actx->UnlockPlayingInfo(__FILE__, __LINE__);
     7794        ReturnPlayerLock(actx);
     7795        return;
     7796    }
     7797    actx->UnlockPlayingInfo(__FILE__, __LINE__);
     7798
     7799    ClearOSD(actx);
     7800
     7801FUNCTIONLOGGER_MARK;
     7802
     7803    // Resize window to the MythTV GUI size
     7804    PlayerContext *mctx = GetPlayer(actx,0);
     7805    mctx->LockDeletePlayer(__FILE__, __LINE__);
     7806    if (mctx->player && mctx->player->getVideoOutput())
     7807        mctx->player->getVideoOutput()->ResizeForGui();
     7808    mctx->UnlockDeletePlayer(__FILE__, __LINE__);
     7809    ReturnPlayerLock(actx);
     7810
     7811    MythMainWindow *mwnd = GetMythMainWindow();
     7812    if (!db_use_gui_size_for_tv || !db_use_fixed_size)
     7813    {
     7814        mwnd->setFixedSize(saved_gui_bounds.size());
     7815        mwnd->setGeometry(saved_gui_bounds.left(), saved_gui_bounds.top(),
     7816                          saved_gui_bounds.width(), saved_gui_bounds.height());
     7817    }
     7818
     7819    // Actually show the pop-up UI
     7820
     7821    RunGridEditCutpointsPtr(this);
     7822    ignoreKeyPresses = true;
     7823
     7824    disableDrawUnusedRects = true;
     7825
     7826    //we are embedding in a mythui window so show the gui paint window again
     7827    if (GetMythMainWindow() && weDisabledGUI)
     7828    {
     7829        GetMythMainWindow()->PopDrawDisabled();
     7830        weDisabledGUI = true;
     7831    }
     7832    GetMythMainWindow()->GetPaintWindow()->show();
     7833
     7834}
     7835
    77537836void TV::DoEditSchedule(int editType)
    77547837{
    77557838    if ((editType == kScheduleProgramGuide  && !RunProgramGuidePtr) ||
    void TV::EditSchedule(const PlayerContex --- Hunk 7 mythbuild/mythtv/libs/libmythtv/tv_play.cpp 
    78887971    qApp->postEvent(this, me);
    78897972}
    78907973
     7974void TV::ShowEditRecordingGrid()
     7975{
     7976FUNCTIONLOGGER;
     7977     // post the request to the main UI thread
     7978     // it will be caught in eventFilter and processed as CustomEvent
     7979     // this will create the program guide window (widget)
     7980     // on the main thread and avoid a deadlock on Win32
     7981
     7982     VERBOSE(VB_GENERAL, "Starting Grid Edit");
     7983     QString message = QString("START_EDIT");
     7984     MythEvent* me = new MythEvent(message);
     7985     qApp->postEvent(GetMythMainWindow(), me);
     7986}
     7987
    78917988void TV::ChangeVolume(PlayerContext *ctx, bool up)
    78927989{
    78937990    ctx->LockDeletePlayer(__FILE__, __LINE__);
    void TV::customEvent(QEvent *e) --- Hunk 8 mythbuild/mythtv/libs/libmythtv/tv_play.cpp 
    85698666    }
    85708667
    85718668    if (message.left(11) == "EPG_EXITING" ||
     8669        message.left(16) == "GRIDEDIT_EXITING" ||
    85728670        message.left(18) == "PROGFINDER_EXITING" ||
    85738671        message.left(21) == "VIEWSCHEDULED_EXITING" ||
    85748672        message.left(19)   == "PLAYBACKBOX_EXITING" ||
    void TV::customEvent(QEvent *e) --- Hunk 9 mythbuild/mythtv/libs/libmythtv/tv_play.cpp 
    86138711            GetMythMainWindow()->PushDrawDisabled();
    86148712            DrawUnusedRects();
    86158713        }
     8714        DrawUnusedRects();
    86168715
    86178716        isEmbedded = false;
    86188717        ignoreKeyPresses = false;
    void TV::customEvent(QEvent *e) --- Hunk 10 mythbuild/mythtv/libs/libmythtv/tv_play.cpp 
    86248723                PrepToSwitchToRecordedProgram(actx, pginfo);
    86258724        }
    86268725
     8726        if (message.left(16) == "GRIDEDIT_EXITING")
     8727        {
     8728            mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
     8729            mctx->LockDeletePlayer(__FILE__, __LINE__);
     8730            if (mctx->player)
     8731                mctx->player->EndEditRecordingGrid();
     8732            mctx->UnlockDeletePlayer(__FILE__, __LINE__);
     8733            ReturnPlayerLock(mctx);
     8734        }
     8735
    86278736        ReturnPlayerLock(actx);
    86288737
    86298738    }
    86308739
     8740    if (message.left(10) == "START_EDIT")
     8741    {
     8742        DoEditRecordingGrid();
     8743    }
     8744
    86318745    if (message.left(14) == "COMMFLAG_START" && (tokens.size() >= 2))
    86328746    {
    86338747        uint evchanid = 0;
    void TV::ShowOSDCutpoint(PlayerContext * --- Hunk 11 mythbuild/mythtv/libs/libmythtv/tv_play.cpp 
    89999113            }
    90009114            else
    90019115            {
     9116                if (ctx->player->IsMarked(frame))
     9117                    osd->DialogAddButton(QObject::tr("Move This Cut Point"),
     9118                                         QString("DIALOG_CUTPOINT_MOVECUT_%1")
     9119                                                 .arg(frame));
     9120
    90029121                osd->DialogAddButton(QObject::tr("Move Start of Cut Here"),
    90039122                                     QString("DIALOG_CUTPOINT_MOVEPREV_%1")
    90049123                                             .arg(frame));
  • mythtv/libs/libmythtv/tv_play.h

    old new typedef void (*EMBEDRETURNVOID) (void *, --- Hunk 1 mythbuild/mythtv/libs/libmythtv/tv_play.h 
    6767typedef void (*EMBEDRETURNVOIDEPG) (uint, const QString &, TV *, bool, bool, int);
    6868typedef void (*EMBEDRETURNVOIDFINDER) (TV *, bool, bool);
    6969typedef void (*EMBEDRETURNVOIDSCHEDIT) (const ProgramInfo *, void *);
     70typedef void (*EMBEDRETURNVOIDGEC) (TV *);
    7071
    7172// Locking order
    7273//
    class MPUBLIC TV : public QObject --- Hunk 2 mythbuild/mythtv/libs/libmythtv/tv_play.h 
    169170    friend class GuideGrid;
    170171    friend class TvPlayWindow;
    171172    friend class TVBrowseHelper;
     173    friend class GridEditCutpoints;
    172174
    173175    Q_OBJECT
    174176  public:
    class MPUBLIC TV : public QObject --- Hunk 3 mythbuild/mythtv/libs/libmythtv/tv_play.h 
    218220    void setInPlayList(bool setting) { inPlaylist = setting; }
    219221    void setUnderNetworkControl(bool setting) { underNetworkControl = setting; }
    220222
     223    void ShowEditRecordingGrid();
    221224    void ShowNoRecorderDialog(const PlayerContext*,
    222225                              NoRecorderMsg msgType = kNoRecorders);
    223226    void FinishRecording(int player_idx); ///< Finishes player's recording
    class MPUBLIC TV : public QObject --- Hunk 4 mythbuild/mythtv/libs/libmythtv/tv_play.h 
    292295    void OSDDialogEvent(int result, QString text, QString action);
    293296
    294297    void DoEditSchedule(int editType = kScheduleProgramGuide);
     298    void DoEditRecordingGrid();
    295299
    296300    void TVEventThreadChecks(void);
    297301
    class MPUBLIC TV : public QObject --- Hunk 5 mythbuild/mythtv/libs/libmythtv/tv_play.h 
    304308    static EMBEDRETURNVOIDEPG RunProgramGuidePtr;
    305309    static EMBEDRETURNVOIDFINDER RunProgramFinderPtr;
    306310    static EMBEDRETURNVOIDSCHEDIT RunScheduleEditorPtr;
     311    static EMBEDRETURNVOIDGEC RunGridEditCutpointsPtr;
    307312
    308313  private:
    309314    void SetActive(PlayerContext *lctx, int index, bool osd_msg);
  • mythtv/libs/libmythui/mythuieditbar.cpp

    old new void MythUIEditBar::ClearRegions(void) --- Hunk 1 mythbuild/mythtv/libs/libmythui/mythuieditbar.cpp 
    6767
    6868void MythUIEditBar::Display(void)
    6969{
    70     QRect keeparea = QRect();
    71     QRect cutarea  = QRect();
     70    QRect keeparea  = QRect();
     71    QRect cutarea   = QRect();
     72    QRect incutarea = QRect();
    7273    MythUIType *position    = GetChild("position");
    7374    MythUIType *keep        = GetChild("keep");
    7475    MythUIType *cut         = GetChild("cut");
     76    MythUIType *incut       = GetChild("incut");
    7577    MythUIType *cuttoleft   = GetChild("cuttoleft");
    7678    MythUIType *cuttoright  = GetChild("cuttoright");
    7779    MythUIType *keeptoleft  = GetChild("keeptoleft");
    void MythUIEditBar::Display(void) --- Hunk 2 mythbuild/mythtv/libs/libmythui/mythuieditbar.cpp 
    9193        cut->SetVisible(false);
    9294        cutarea = cut->GetArea();
    9395    }
     96
     97    if (incut)
     98    {
     99        incut->SetVisible(false);
     100        incutarea = incut->GetArea();
     101    }
    94102    if (cuttoleft)
    95103        cuttoleft->SetVisible(false);
    96104    if (cuttoright)
    void MythUIEditBar::Display(void) --- Hunk 3 mythbuild/mythtv/libs/libmythui/mythuieditbar.cpp 
    117125        return;
    118126    }
    119127
    120     MythUIShape *barshape   = dynamic_cast<MythUIShape*>(cut);
    121     MythUIImage *barimage   = dynamic_cast<MythUIImage*>(cut);
    122     MythUIShape *leftshape  = dynamic_cast<MythUIShape*>(cuttoleft);
    123     MythUIImage *leftimage  = dynamic_cast<MythUIImage*>(cuttoleft);
    124     MythUIShape *rightshape = dynamic_cast<MythUIShape*>(cuttoright);
    125     MythUIImage *rightimage = dynamic_cast<MythUIImage*>(cuttoright);
    126 
    127     QListIterator<QPair<float,float> > regions(m_regions);
    128     while (regions.hasNext() && cutarea.isValid())
    129     {
    130         QPair<float,float> region = regions.next();
    131         int left  = (int)((region.first * cutarea.width()) + 0.5f);
    132         int right = (int)((region.second * cutarea.width()) + 0.5f);
    133         if (left >= right)
    134             right = left + 1;
    135         if (cut)
    136         {
    137             AddBar(barshape, barimage, QRect(left, cutarea.top(), right - left,
    138                                              cutarea.height()));
    139         }
    140 
    141         if (cuttoleft && (region.second < 1.0f))
    142             AddMark(leftshape, leftimage, right, true);
    143 
    144         if (cuttoright && (region.first > 0.0f))
    145             AddMark(rightshape, rightimage, left, false);
    146     }
    147128
    148129    CalcInverseRegions();
    149130
    150     barshape   = dynamic_cast<MythUIShape*>(keep);
    151     barimage   = dynamic_cast<MythUIImage*>(keep);
    152     leftshape  = dynamic_cast<MythUIShape*>(keeptoleft);
    153     leftimage  = dynamic_cast<MythUIImage*>(keeptoleft);
    154     rightshape = dynamic_cast<MythUIShape*>(keeptoright);
    155     rightimage = dynamic_cast<MythUIImage*>(keeptoright);
     131    MythUIShape *barshape   = dynamic_cast<MythUIShape*>(keep);
     132    MythUIImage *barimage   = dynamic_cast<MythUIImage*>(keep);
     133    MythUIShape *leftshape  = dynamic_cast<MythUIShape*>(keeptoleft);
     134    MythUIImage *leftimage  = dynamic_cast<MythUIImage*>(keeptoleft);
     135    MythUIShape *rightshape = dynamic_cast<MythUIShape*>(keeptoright);
     136    MythUIImage *rightimage = dynamic_cast<MythUIImage*>(keeptoright);
    156137
    157138    QListIterator<QPair<float,float> > regions2(m_invregions);
    158139    while (regions2.hasNext() && keeparea.isValid())
    void MythUIEditBar::Display(void) --- Hunk 4 mythbuild/mythtv/libs/libmythui/mythuieditbar.cpp 
    175156            AddMark(rightshape, rightimage, left, false);
    176157    }
    177158
     159    barshape   = dynamic_cast<MythUIShape*>(cut);
     160    barimage   = dynamic_cast<MythUIImage*>(cut);
     161    leftshape  = dynamic_cast<MythUIShape*>(cuttoleft);
     162    leftimage  = dynamic_cast<MythUIImage*>(cuttoleft);
     163    rightshape = dynamic_cast<MythUIShape*>(cuttoright);
     164    rightimage = dynamic_cast<MythUIImage*>(cuttoright);
     165
     166    MythUIShape *inbarshape = dynamic_cast<MythUIShape*>(incut);
     167    MythUIImage *inbarimage = dynamic_cast<MythUIImage*>(incut);
     168
     169    QListIterator<QPair<float,float> > regions(m_regions);
     170    while (regions.hasNext() && cutarea.isValid())
     171    {
     172        QPair<float,float> region = regions.next();
     173        int left  = (int)((region.first * cutarea.width()) + 0.5f);
     174        int right = (int)((region.second * cutarea.width()) + 0.5f);
     175        if (left >= right)
     176            right = left + 1;
     177        if (cut)
     178        {
     179            if (m_position >= region.first && m_position <= region.second &&
     180                (inbarshape || inbarimage))
     181
     182                // Highlight the cutarea if it contains the current position
     183                AddBar(inbarshape, inbarimage, QRect(left, cutarea.top(), right - left,
     184                                                 cutarea.height()));
     185            else
     186                AddBar(barshape, barimage, QRect(left, cutarea.top(), right - left,
     187                                                 cutarea.height()));
     188        }
     189
     190        if (cuttoleft && (region.second < 1.0f))
     191            AddMark(leftshape, leftimage, right, true);
     192
     193        if (cuttoright && (region.first > 0.0f))
     194            AddMark(rightshape, rightimage, left, false);
     195    }
     196
    178197    if (position)
    179198        position->MoveToTop();
    180199}
  • mythtv/libs/libmythui/mythuishape.cpp

    old new using namespace std; --- Hunk 1 mythbuild/mythtv/libs/libmythui/mythuishape.cpp 
    1818#include "mythimage.h"
    1919#include "mythmainwindow.h"
    2020
     21#ifndef FUNCTIONLOGGER
     22#define FUNCTIONLOGGER
     23#endif
     24
    2125MythUIShape::MythUIShape(MythUIType *parent, const QString &name)
    2226          : MythUIType(parent, name)
    2327{
    MythUIShape::MythUIShape(MythUIType *par --- Hunk 2 mythbuild/mythtv/libs/libmythui/mythuishape.cpp 
    2731    m_linePen = QPen(Qt::NoPen);
    2832    m_cornerRadius = 10;
    2933    m_cropRect = MythRect(0,0,0,0);
     34    m_pm = NULL;
    3035}
    3136
    3237MythUIShape::~MythUIShape()
    void MythUIShape::SetLinePen(QPen pen) --- Hunk 3 mythbuild/mythtv/libs/libmythui/mythuishape.cpp 
    7984void MythUIShape::DrawSelf(MythPainter *p, int xoffset, int yoffset,
    8085                          int alphaMod, QRect clipRect)
    8186{
     87//FUNCTIONLOGGER;
     88//    if (m_image)
     89//        VERBOSE(VB_GENERAL, QString("Has Image 1 (null? %1), has pixmap %2").arg(m_image->isNull()).arg(m_pm != NULL));
     90//    else
     91//        VERBOSE(VB_GENERAL, QString("Has Image 0, has pixmap %1").arg(m_pm != NULL));
     92
    8293    QRect area = GetArea();
    8394    area.translate(xoffset, yoffset);
    8495
    void MythUIShape::DrawSelf(MythPainter * --- Hunk 4 mythbuild/mythtv/libs/libmythui/mythuishape.cpp 
    105116    }
    106117}
    107118
     119void MythUIShape::SetPixmap(QPixmap * pm)
     120{
     121//FUNCTIONLOGGER;
     122    m_pm = pm;
     123
     124    if (m_image)
     125    {
     126        m_image->DownRef();
     127        m_image = NULL;
     128    }
     129
     130    m_image = GetMythMainWindow()->GetCurrentPainter()->GetFormatImage();
     131    m_image->UpRef();
     132    if (m_pm)
     133        m_image->Assign(*m_pm);
     134
     135    SetRedraw();
     136}
     137
    108138void MythUIShape::DrawRect(const QRect &area,const QBrush &fillBrush,
    109139                           const QPen &linePen)
    110140{
    void MythUIShape::DrawRect(const QRect & --- Hunk 5 mythbuild/mythtv/libs/libmythui/mythuishape.cpp 
    132162
    133163    m_image = GetPainter()->GetFormatImage();
    134164    m_image->UpRef();
    135     m_image->Assign(image);
     165    if (m_pm) {
     166//        VERBOSE(VB_GENERAL, "m_pm !=  NULL");
     167        m_image->Assign(*m_pm);
     168    } else {
     169//        VERBOSE(VB_GENERAL, "m_pm ==  NULL");
     170        m_image->Assign(image);
     171    }
    136172}
    137173
    138174void MythUIShape::DrawRoundRect(const QRect &area, int radius,
    139175                                const QBrush &fillBrush, const QPen &linePen)
    140176{
     177//FUNCTIONLOGGER;
    141178    if (m_image)
    142179    {
    143180        m_image->DownRef();
    void MythUIShape::DrawEllipse(const QRec --- Hunk 6 mythbuild/mythtv/libs/libmythui/mythuishape.cpp 
    198235
    199236    m_image = GetPainter()->GetFormatImage();
    200237    m_image->UpRef();
    201     m_image->Assign(image);
     238
     239    if (m_pm) {
     240//        VERBOSE(VB_GENERAL, "m_pm !=  NULL");
     241        m_image->Assign(*m_pm);
     242    } else {
     243//        VERBOSE(VB_GENERAL, "m_pm ==  NULL");
     244        m_image->Assign(image);
     245    }
    202246}
    203247
    204248/**
  • mythtv/libs/libmythui/mythuishape.h

    old new class MPUBLIC MythUIShape : public MythU --- Hunk 1 mythbuild/mythtv/libs/libmythui/mythuishape.h 
    3030    void SetFillBrush(QBrush fill);
    3131    void SetLinePen(QPen pen);
    3232
     33    void SetPixmap(QPixmap * pm);
     34
    3335  protected:
    3436    virtual void DrawSelf(MythPainter *p, int xoffset, int yoffset,
    3537                          int alphaMod, QRect clipRect);
    class MPUBLIC MythUIShape : public MythU --- Hunk 2 mythbuild/mythtv/libs/libmythui/mythuishape.h 
    5355    int            m_cornerRadius;
    5456    MythRect       m_cropRect;
    5557
     58    QPixmap        *m_pm;
     59
    5660    friend class MythUIProgressBar;
    5761    friend class MythUIEditBar;
    5862};
  • mythtv/programs/mythfrontend/main.cpp

    old new using namespace std; --- Hunk 1 mythbuild/mythtv/programs/mythfrontend/main.cpp 
    6969#include "mythdb.h"
    7070#include "backendconnectionmanager.h"
    7171
     72#include "grideditcutpoints.h"
     73
    7274static ExitPrompter   *exitPopup = NULL;
    7375static MythThemedMenu *menu;
    7476
    static void InitJumpPoints(void) --- Hunk 2 mythbuild/mythtv/programs/mythfrontend/main.cpp 
    911913    TV::SetFuncPtr("programguide", (void *)GuideGrid::RunProgramGuide);
    912914    TV::SetFuncPtr("programfinder", (void *)RunProgramFinder);
    913915    TV::SetFuncPtr("scheduleeditor", (void *)ScheduleEditor::RunScheduleEditor);
     916    TV::SetFuncPtr("grideditcutpoints", (void *)GridEditCutpoints::RunGridEditCutpoints);
    914917}
    915918
    916919
  • mythtv/themes/default-wide/osd.xml

    old new --- Hunk 1 mythbuild/mythtv/themes/default-wide/osd.xml 
    382382                <type>roundbox</type>
    383383                <cornerradius>6</cornerradius>
    384384            </shape>
     385            <shape name="incut">
     386                <area>0,11,100%,8</area>
     387                <fill color="#FFFF00" />
     388                <type>roundbox</type>
     389                <cornerradius>6</cornerradius>
     390            </shape>
    385391            <shape name="cuttoright">
    386392                <area>0,5,4,20</area>
    387393                <fill color="#FF0000" alpha="255" />
  • mythtv/themes/default-wide/recordings-ui.xml

    old new --- Hunk 1 mythbuild/mythtv/themes/default-wide/recordings-ui.xml 
    444444        </buttonlist>
    445445    </window>
    446446
     447    <window name="grideditcutpoints">
     448        <area>0,0,1280,720</area>
     449
     450        <textarea name="timecap">
     451            <area>0,350,120,40</area>
     452            <font>basesmall</font>
     453            <value>Time:</value>
     454            <align>right</align>
     455        </textarea>
     456
     457        <textarea name="time">
     458            <area>125,350,195,40</area>
     459            <font>basesmal</font>
     460            <align>left</align>
     461        </textarea>
     462
     463        <textarea name="framenumcap">
     464            <area>0,400,120,40</area>
     465            <font>basesmall</font>
     466            <value>Frame:</value>
     467            <align>right</align>
     468        </textarea>
     469
     470        <textarea name="framenum">
     471            <area>125,400,195,40</area>
     472            <font>basesmall</font>
     473            <align>left</align>
     474        </textarea>
     475
     476        <textarea name="cutind">
     477            <area>120,450,195,40</area>
     478            <font>basesmall</font>
     479            <align>left</align>
     480        </textarea>
     481
     482        <textarea name="updatingind">
     483            <area>20,550,210,40</area>
     484            <font>basesmall</font>
     485            <value>Updating</value>
     486            <align>hcenter</align>
     487        </textarea>
     488
     489        <textarea name="jumpstylecap">
     490            <area>0,500,120,40</area>
     491            <font>basesmall</font>
     492            <value>Skip:</value>
     493            <align>right</align>
     494        </textarea>
     495
     496        <textarea name="jumpstyle">
     497            <area>125,500,195,40</area>
     498            <font>basesmall</font>
     499            <align>left</align>
     500        </textarea>
     501
     502        <editbar name="positionbar">
     503            <area>338,554,908,48</area>
     504
     505            <shape name="cut">
     506                <area>0,2,908,44</area>
     507                <fill color="#7F0000"/>
     508            </shape>
     509
     510            <shape name="incut">
     511                <area>0,2,908,44</area>
     512                <fill color="#7F7F00"/>
     513            </shape>
     514
     515            <shape name="keep">
     516                <area>0,2,908,44</area>
     517                <fill color="#202020"/>
     518            </shape>
     519
     520            <shape name="cuttoright">
     521                <area>0,0,2,100%</area>
     522                <fill color="#FFFF00"/>
     523            </shape>
     524
     525            <shape name="cuttoleft">
     526                <area>0,0,2,100%</area>
     527                <fill color="#FFFF00"/>
     528            </shape>
     529
     530            <shape name="position">
     531                <area>0,0,2,100%</area>
     532                <fill color="#FFFFFF"/>
     533            </shape>
     534        </editbar>
     535
     536        <shape name="mainvideoback">
     537            <area>328,24,928,522</area>
     538            <fill color="#7F7F7F" alpha="255" />
     539        </shape>
     540
     541        <shape name="mainvideo">
     542            <area>328,24,928,522</area>
     543        </shape>
     544
     545        <statetype name="videostates">
     546            <area>328,24,928,522</area>
     547            <state name="incut">
     548                <area>0,0,100%,100%</area>
     549                <shape name="cutarea">
     550                    <area>0,0,100%,100%</area>
     551                    <type>box</type>
     552                    <line color="#FF0000" alpha="255" width="2" />
     553                    <fill color="#2F0000" alpha="128" />
     554                </shape>
     555            </state>
     556            <state name="normal">
     557                <area>0,0,100%,100%</area>
     558            </state>
     559            <state name="cutpoint">
     560                <area>0,0,100%,100%</area>
     561                <shape name="cutarea">
     562                    <area>0,0,100%,100%</area>
     563                    <type>box</type>
     564                    <line color="#FFFF00" alpha="255" width="2" />
     565                    <fill color="#2F2F00" alpha="128" />
     566                </shape>
     567            </state>
     568        </statetype>
     569
     570        <statetype name="mainvideostate" from="videostates">
     571            <area>328,24,928,522</area>
     572        </statetype>
     573
     574        <shape name="video0back">
     575            <area>552,614,176,99</area>
     576            <fill color="#7F7F7F" alpha="255" />
     577        </shape>
     578
     579        <shape name="video0" from="mainvideo">
     580            <area>552,614,176,99</area>
     581        </shape>
     582
     583        <shape name="video0frame">
     584            <area>552,614,176,99</area>
     585            <type>box</type>
     586            <line color="#FFFFFF" alpha="255" width="2" />
     587        </shape>
     588
     589        <statetype name="video0state" from="mainvideostate">
     590            <area>552,614,176,99</area>
     591        </statetype>
     592
     593        <shape name="videom3back" from="video0back">
     594            <area>6,614,176,99</area>
     595        </shape>
     596
     597        <shape name="videom3" from="video0">
     598            <area>6,614,176,99</area>
     599        </shape>
     600
     601        <statetype name="videom3state" from="video0state">
     602            <area>6,614,176,99</area>
     603        </statetype>
     604
     605        <shape name="videom2back" from="video0back">
     606            <area>186,614,176,99</area>
     607        </shape>
     608
     609        <shape name="videom2" from="video0">
     610            <area>186,614,176,99</area>
     611        </shape>
     612
     613        <statetype name="videom2state" from="video0state">
     614            <area>188,614,176,99</area>
     615        </statetype>
     616
     617        <shape name="videom1back" from="video0back">
     618            <area>370,614,176,99</area>
     619        </shape>
     620
     621        <shape name="videom1" from="video0">
     622            <area>370,614,176,99</area>
     623        </shape>
     624
     625        <statetype name="videom1state" from="video0state">
     626            <area>370,614,176,99</area>
     627        </statetype>
     628
     629<!--   -->
     630
     631        <shape name="videop1back" from="video0back">
     632            <area>734,614,176,99</area>
     633        </shape>
     634
     635        <shape name="videop1" from="video0">
     636            <area>734,614,176,99</area>
     637        </shape>
     638
     639        <statetype name="videop1state" from="video0state">
     640            <area>734,614,176,99</area>
     641        </statetype>
     642
     643        <shape name="videop2back" from="video0back">
     644            <area>916,614,176,99</area>
     645        </shape>
     646
     647        <shape name="videop2" from="video0">
     648            <area>916,614,176,99</area>
     649        </shape>
     650
     651        <statetype name="videop2state" from="video0state">
     652            <area>916,614,176,99</area>
     653        </statetype>
     654
     655        <shape name="videop3back" from="video0back">
     656            <area>1098,614,176,99</area>
     657        </shape>
     658
     659        <shape name="videop3" from="video0">
     660            <area>1098,614,176,99</area>
     661        </shape>
     662
     663        <statetype name="videop3state" from="video0state">
     664            <area>1098,614,176,99</area>
     665        </statetype>
     666
     667    </window>
     668
    447669</mythuitheme>