Ticket #6322: 192-137-editgrid.patch

File 192-137-editgrid.patch, 130.1 KB (added by Bill <billstuff2001@…>, 16 years ago)

Updated against trunk 24132

  • mythtv/libs/libmythtv/NuppelVideoPlayer.cpp

    old new using namespace std;  
    6060#include "mythverbose.h"
    6161#include "myth_imgconvert.h"
    6262
     63#include "grideditcutpoints.h"
     64
    6365extern "C" {
    6466#include "vbitext/vbi.h"
    6567#include "vsync.h"
    static unsigned dbg_ident(const NuppelVi  
    8991#define LOC_WARN QString("NVP(%1), Warning: ").arg(dbg_ident(this),0,36)
    9092#define LOC_ERR  QString("NVP(%1), Error: ").arg(dbg_ident(this),0,36)
    9193
     94#ifndef FUNCTIONLOGGER
     95#define FUNCTIONLOGGER
     96#endif
     97
    9298uint track_type_to_display_mode[kTrackTypeCount+2] =
    9399{
    94100    kDisplayNone,
    NuppelVideoPlayer::NuppelVideoPlayer(boo  
    117123      decoder_thread_alive(true),   killplayer(false),
    118124      killvideo(false),             livetv(false),
    119125      watchingrecording(false),     editmode(false),
     126      hideedits(false),
    120127      resetvideo(false),            using_null_videoout(false),
    121128      no_audio_in(false),           no_audio_out(false),
    122129      transcoding(false),
    NuppelVideoPlayer::NuppelVideoPlayer(boo  
    128135      bookmarkseek(0),
    129136      // Seek
    130137      fftime(0),                    seekamountpos(4),
    131       seekamount(30),               exactseeks(false),
     138      allow_pagesize(false),        half_page(0),
     139      seekamount(30),               seekamounttext("30 Frames"),
     140      exactseeks(false),
    132141      // Playback misc.
    133142      videobuf_retries(0),          framesPlayed(0),
    134143      totalFrames(0),               totalLength(0),
    NuppelVideoPlayer::NuppelVideoPlayer(boo  
    179188      yuv_need_copy(false),         yuv_desired_size(0,0),
    180189      yuv_scaler(NULL),             yuv_frame_scaled(NULL),
    181190      yuv_scaler_in_size(0,0),      yuv_scaler_out_size(0,0),
     191      // Grid Editing
     192      grid_edit_image_scaler(NULL), grid_edit_image_small_scaler(NULL),
     193      grid_edit_image_buffer_yuv(NULL), grid_edit_image_small_buffer_yuv(NULL),
     194      grid_edit_image_buffer_rgb(NULL), grid_edit_image_small_buffer_rgb(NULL),
     195      grid_edit_image_buffer_length(0), grid_edit_image_small_buffer_length(0),
     196      grid_edit_image_in_size(-1, -1),
     197
    182198      // Filters
    183199      videoFiltersForProgram(""),   videoFiltersOverride(""),
    184200      postfilt_width(0),            postfilt_height(0),
    NuppelVideoPlayer::~NuppelVideoPlayer(vo  
    338354        output_jmeter = NULL;
    339355    }
    340356
     357    ClearScreenGrab();
     358
    341359    ShutdownYUVResize();
    342360}
    343361
    VideoFrame *NuppelVideoPlayer::GetCurren  
    15941612    return retval;
    15951613}
    15961614
     1615bool NuppelVideoPlayer::GetScreenGrabsOfCurrentFrame(QImage &normal, QImage &small)
     1616{
     1617    FUNCTIONLOGGER;
     1618    unsigned char *data      = NULL;
     1619    VideoFrame    *frame     = NULL;
     1620    AVPicture      orig;
     1621    AVPicture      scaled_yuv;
     1622    AVPicture      scaled_rgb;
     1623    AVPicture      scaled_yuv_small;
     1624    AVPicture      scaled_rgb_small;
     1625    bzero(&orig,         sizeof(AVPicture));
     1626    bzero(&scaled_yuv,       sizeof(AVPicture));
     1627    bzero(&scaled_rgb,       sizeof(AVPicture));
     1628    bzero(&scaled_yuv_small, sizeof(AVPicture));
     1629    bzero(&scaled_rgb_small, sizeof(AVPicture));
     1630
     1631    int vw, vh;
     1632    if (!(frame = GetCurrentFrame(vw, vh)))
     1633    {
     1634        return false;
     1635    }
     1636
     1637    if (!(data = frame->buf))
     1638    {
     1639        ReleaseCurrentFrame(frame);
     1640        return false;
     1641    }
     1642
     1643    {
     1644        QMutexLocker l(&videofiltersLock);
     1645
     1646        // Check to see if the screen dimensions have changed
     1647        // Probably shouldn't happen in normal use.
     1648        if (grid_edit_image_in_size != video_dim)
     1649            SetupScreenGrab();
     1650
     1651        avpicture_fill(&orig, data, PIX_FMT_YUV420P,
     1652                       video_dim.width(), video_dim.height());
     1653
     1654        avpicture_deinterlace(&orig, &orig, PIX_FMT_YUV420P,
     1655                              video_dim.width(), video_dim.height());
     1656
     1657        // Rescale to the normal size
     1658        avpicture_fill(&scaled_yuv, grid_edit_image_buffer_yuv, PIX_FMT_YUV420P,
     1659                       grid_edit_image_size.width(),
     1660                       grid_edit_image_size.height());
     1661
     1662        avpicture_fill(&scaled_rgb, grid_edit_image_buffer_rgb, PIX_FMT_RGB32,
     1663                       grid_edit_image_size.width(),
     1664                       grid_edit_image_size.height());
     1665
     1666        sws_scale(grid_edit_image_scaler, orig.data, orig.linesize, 0,
     1667                  video_dim.height(),
     1668                  scaled_yuv.data, scaled_yuv.linesize);
     1669
     1670        myth_sws_img_convert(
     1671            &scaled_rgb, PIX_FMT_RGB32, &scaled_yuv, PIX_FMT_YUV420P,
     1672                    grid_edit_image_size.width(), grid_edit_image_size.height());
     1673
     1674
     1675        // Rescale to the small size
     1676        avpicture_fill(&scaled_yuv_small, grid_edit_image_small_buffer_yuv, PIX_FMT_YUV420P,
     1677                       grid_edit_image_small_size.width(),
     1678                       grid_edit_image_small_size.height());
     1679
     1680        avpicture_fill(&scaled_rgb_small, grid_edit_image_small_buffer_rgb, PIX_FMT_RGB32,
     1681                       grid_edit_image_small_size.width(),
     1682                       grid_edit_image_small_size.height());
     1683
     1684        sws_scale(grid_edit_image_small_scaler, orig.data, orig.linesize, 0,
     1685                  video_dim.height(),
     1686                  scaled_yuv_small.data, scaled_yuv_small.linesize);
     1687
     1688        myth_sws_img_convert(
     1689            &scaled_rgb_small, PIX_FMT_RGB32, &scaled_yuv_small, PIX_FMT_YUV420P,
     1690                    grid_edit_image_small_size.width(), grid_edit_image_small_size.height());
     1691
     1692    }
     1693
     1694    // Don't need the current frame anymore so release it
     1695    ReleaseCurrentFrame(frame);
     1696
     1697
     1698#ifdef MMX
     1699#define _RGBSWAP .rgbSwapped()
     1700#endif
     1701
     1702    normal = QImage(grid_edit_image_buffer_rgb,
     1703                    grid_edit_image_size.width(), grid_edit_image_size.height(),
     1704                    QImage::Format_RGB32)_RGBSWAP;
     1705
     1706    small = QImage(grid_edit_image_small_buffer_rgb,
     1707                   grid_edit_image_small_size.width(), grid_edit_image_small_size.height(),
     1708                   QImage::Format_RGB32)_RGBSWAP;
     1709
     1710    return true;
     1711}
     1712
     1713void NuppelVideoPlayer::SetScreenGrabSizes(QSize normal, QSize small)
     1714{
     1715    grid_edit_image_size = normal;
     1716    grid_edit_image_small_size = small;
     1717
     1718    SetupScreenGrab();
     1719    VERBOSE(VB_GENERAL, QString("Main Image = (%1, %2) from (%3, %4)")
     1720                        .arg(grid_edit_image_size.width())
     1721                        .arg(grid_edit_image_size.height())
     1722                        .arg(normal.width()).arg(normal.height()));
     1723    VERBOSE(VB_GENERAL, QString("Small Image = (%1, %2) from (%3, %4)")
     1724                        .arg(grid_edit_image_small_size.width())
     1725                        .arg(grid_edit_image_small_size.height())
     1726                        .arg(small.width()).arg(small.height()));
     1727
     1728}
     1729
     1730void NuppelVideoPlayer::ClearScreenGrab()
     1731{
     1732    if (grid_edit_image_scaler)
     1733    {
     1734        sws_freeContext(grid_edit_image_scaler);
     1735        grid_edit_image_scaler = NULL;
     1736    }
     1737
     1738    if (grid_edit_image_small_scaler)
     1739    {
     1740        sws_freeContext(grid_edit_image_small_scaler);
     1741        grid_edit_image_small_scaler=NULL;
     1742    }
     1743
     1744    if (grid_edit_image_buffer_yuv)
     1745    {
     1746        delete grid_edit_image_buffer_yuv;
     1747        grid_edit_image_buffer_yuv=NULL;
     1748    }
     1749
     1750    if (grid_edit_image_small_buffer_yuv)
     1751    {
     1752        delete grid_edit_image_small_buffer_yuv;
     1753        grid_edit_image_small_buffer_yuv=NULL;
     1754    }
     1755
     1756    if (grid_edit_image_buffer_rgb)
     1757    {
     1758        delete grid_edit_image_buffer_rgb;
     1759        grid_edit_image_buffer_rgb=NULL;
     1760    }
     1761
     1762    if (grid_edit_image_small_buffer_rgb)
     1763    {
     1764        delete grid_edit_image_small_buffer_rgb;
     1765        grid_edit_image_small_buffer_rgb=NULL;
     1766    }
     1767}
     1768
     1769void NuppelVideoPlayer::SetupScreenGrab()
     1770{
     1771    ClearScreenGrab();
     1772    grid_edit_image_in_size = video_dim;
     1773
     1774    // Normalize the output sizes.
     1775    // This is necessary to preserve the aspect ratio
     1776
     1777    QSize tmpsize = grid_edit_image_size;
     1778    grid_edit_image_size =  video_dim;
     1779    grid_edit_image_size.scale(tmpsize, Qt::KeepAspectRatio);
     1780
     1781    tmpsize = grid_edit_image_small_size;
     1782    grid_edit_image_small_size = video_dim;
     1783    grid_edit_image_small_size.scale(tmpsize, Qt::KeepAspectRatio);
     1784
     1785    grid_edit_image_size = QSize(grid_edit_image_size.width() & ~0x7,
     1786                                 grid_edit_image_size.height() & ~0x7);
     1787    grid_edit_image_small_size = QSize(grid_edit_image_small_size.width() & ~0x7,
     1788                                       grid_edit_image_small_size.height() & ~0x7);
     1789
     1790    // Do normal first
     1791    uint sz = grid_edit_image_size.width() * grid_edit_image_size.height();
     1792    grid_edit_image_buffer_yuv = new unsigned char[(sz * 3 / 2) + 128];
     1793    grid_edit_image_buffer_rgb = new unsigned char[sz * 4 + 128];
     1794
     1795    //grid_edit_image_scaler = img_resample_init(
     1796    //            grid_edit_image_size.width(), grid_edit_image_size.height(),
     1797    //            grid_edit_image_in_size.width(),  grid_edit_image_in_size.height());
     1798
     1799    grid_edit_image_scaler = sws_getCachedContext(grid_edit_image_scaler,
     1800                grid_edit_image_in_size.width(), grid_edit_image_in_size.height(),
     1801                PIX_FMT_YUV420P,
     1802                grid_edit_image_size.width(),  grid_edit_image_size.height(),
     1803                PIX_FMT_YUV420P,
     1804                SWS_FAST_BILINEAR, NULL, NULL, NULL);
     1805
     1806    // Then small
     1807    sz = grid_edit_image_small_size.width() * grid_edit_image_small_size.height();
     1808    grid_edit_image_small_buffer_yuv = new unsigned char[(sz * 3 / 2) + 128];
     1809    grid_edit_image_small_buffer_rgb = new unsigned char[sz * 4 + 128];
     1810
     1811    // Resize from normal to small
     1812    //grid_edit_image_small_scaler = img_resample_init(
     1813    //            grid_edit_image_small_size.width(), grid_edit_image_small_size.height(),
     1814    //            grid_edit_image_size.width(),  grid_edit_image_size.height());
     1815
     1816    grid_edit_image_small_scaler = sws_getCachedContext(grid_edit_image_small_scaler,
     1817                grid_edit_image_in_size.width(), grid_edit_image_in_size.height(),
     1818                PIX_FMT_YUV420P,
     1819                grid_edit_image_small_size.width(),  grid_edit_image_small_size.height(),
     1820                PIX_FMT_YUV420P,
     1821                SWS_FAST_BILINEAR, NULL, NULL, NULL);
     1822}
     1823
    15971824void NuppelVideoPlayer::ReleaseCurrentFrame(VideoFrame *frame)
    15981825{
    15991826    if (frame)
    bool NuppelVideoPlayer::EnableEdit(void)  
    48555082
    48565083    dialogname = "";
    48575084
     5085    osd->HideAllExcept("editmode");
     5086
    48585087    InfoMap infoMap;
    48595088    player_ctx->LockPlayingInfo(__FILE__, __LINE__);
    48605089    player_ctx->playingInfo->ToMap(infoMap);
    void NuppelVideoPlayer::DisableEdit(void  
    49195148    player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
    49205149}
    49215150
     5151bool NuppelVideoPlayer::EditSeekToFrame(long long targetFrame)
     5152{
     5153    bool tmpexactseeks = exactseeks;
     5154    GetDecoder()->setExactSeeks(true);
     5155
     5156//    VERBOSE(VB_GENERAL, QString("Before current frame = %1, going to frame %2")
     5157//           .arg(GetFramesPlayed())
     5158//           .arg(targetFrame));
     5159
     5160    if (framesPlayed > targetFrame)
     5161    {
     5162        // seek back
     5163        rewindtime = framesPlayed - targetFrame;
     5164        while (rewindtime != 0)
     5165            usleep(1000);
     5166    }
     5167    else
     5168    {
     5169        // seek forward
     5170        fftime = targetFrame - framesPlayed;
     5171        while (fftime != 0)
     5172            usleep(1000);
     5173
     5174    }
     5175//    VERBOSE(VB_GENERAL, QString("After current frame = %1")
     5176//           .arg(GetFramesPlayed()));
     5177    GetDecoder()->setExactSeeks(tmpexactseeks);
     5178    return (targetFrame == framesPlayed);
     5179}
     5180
     5181void NuppelVideoPlayer::EditHandleClearMap()
     5182{
     5183    QMap<long long, int>::Iterator it;
     5184    for (it = deleteMap.begin(); it != deleteMap.end(); ++it)
     5185        osd->HideEditArrow(it.key(), *it);
     5186
     5187    deleteMap.clear();
     5188    UpdateEditSlider();
     5189}
     5190
     5191void NuppelVideoPlayer::EditHandleInvertMap()
     5192{
     5193    QMap<long long, int>::Iterator it;
     5194    for (it = deleteMap.begin(); it != deleteMap.end(); ++it)
     5195        ReverseMark(it.key());
     5196
     5197    UpdateEditSlider();
     5198    UpdateTimeDisplay();
     5199}
     5200
     5201void NuppelVideoPlayer::EditHandleLoadCommSkip()
     5202{
     5203    if (hascommbreaktable)
     5204    {
     5205        commBreakMapLock.lock();
     5206        QMap<long long, int>::Iterator it;
     5207        for (it = commBreakMap.begin(); it != commBreakMap.end(); ++it)
     5208        {
     5209            if (!deleteMap.contains(it.key()))
     5210            {
     5211                if (*it == MARK_COMM_START)
     5212                    AddMark(it.key(), MARK_CUT_START);
     5213                else
     5214                    AddMark(it.key(), MARK_CUT_END);
     5215            }
     5216        }
     5217        commBreakMapLock.unlock();
     5218        UpdateEditSlider();
     5219        UpdateTimeDisplay();
     5220    }
     5221}
     5222
    49225223bool NuppelVideoPlayer::DoKeypress(QKeyEvent *e)
    49235224{
     5225
    49245226    bool handled = false;
    49255227    QStringList actions;
    49265228    handled = gContext->GetMainWindow()->TranslateKeyPress("TV Editing", e, actions);
    bool NuppelVideoPlayer::DoKeypress(QKeyE  
    50015303            UpdateTimeDisplay();
    50025304        }
    50035305        else if (action == "CLEARMAP")
    5004         {
    5005             QMap<long long, int>::Iterator it;
    5006             for (it = deleteMap.begin(); it != deleteMap.end(); ++it)
    5007                 osd->HideEditArrow(it.key(), *it);
    5008 
    5009             deleteMap.clear();
    5010             UpdateEditSlider();
    5011         }
     5306            EditHandleClearMap();
    50125307        else if (action == "INVERTMAP")
    5013         {
    5014             QMap<long long, int>::Iterator it;
    5015             for (it = deleteMap.begin(); it != deleteMap.end(); ++it)
    5016                 ReverseMark(it.key());
    5017 
    5018             UpdateEditSlider();
    5019             UpdateTimeDisplay();
    5020         }
     5308            EditHandleInvertMap();
    50215309        else if (action == "LOADCOMMSKIP")
    5022         {
    5023             if (hascommbreaktable)
    5024             {
    5025                 commBreakMapLock.lock();
    5026                 QMap<long long, int>::Iterator it;
    5027                 for (it = commBreakMap.begin(); it != commBreakMap.end(); ++it)
    5028                 {
    5029                     if (!deleteMap.contains(it.key()))
    5030                     {
    5031                         if (*it == MARK_COMM_START)
    5032                             AddMark(it.key(), MARK_CUT_START);
    5033                         else
    5034                             AddMark(it.key(), MARK_CUT_END);
    5035                     }
    5036                 }
    5037                 commBreakMapLock.unlock();
    5038                 UpdateEditSlider();
    5039                 UpdateTimeDisplay();
    5040             }
    5041         }
     5310            EditHandleLoadCommSkip();
    50425311        else if (action == "PREVCUT")
    50435312        {
    50445313            int old_seekamount = seekamount;
    bool NuppelVideoPlayer::DoKeypress(QKeyE  
    50845353            UpdateEditSlider();
    50855354            UpdateTimeDisplay();
    50865355        }
    5087         else if (action == "ESCAPE" || action == "MENU" ||
    5088                  action == "EDIT")
     5356        else if (action == "EDIT" || action == "MENU")
     5357        {
     5358            m_tv->ShowEditRecordingGrid();
     5359        }
     5360        else if (action == "ESCAPE")
    50895361        {
    50905362            DisableEdit();
    50915363            retval = false;
    bool NuppelVideoPlayer::DoKeypress(QKeyE  
    50985370    return retval;
    50995371}
    51005372
     5373void NuppelVideoPlayer::StartEditRecordingGrid(void)
     5374{
     5375    {
     5376        QMutexLocker l(&grid_edit_lock);
     5377        if (hideedits)
     5378            return;
     5379
     5380        hideedits = true;
     5381    }
     5382
     5383    // Completely hide the OSD
     5384    osd->HideAll();
     5385}
     5386
     5387void NuppelVideoPlayer::EndEditRecordingGrid(void)
     5388{
     5389
     5390    ClearScreenGrab();
     5391
     5392    allow_pagesize = false;
     5393    {
     5394        QMutexLocker l(&grid_edit_lock);
     5395
     5396        hideedits = false;
     5397
     5398        // Show OSD
     5399
     5400        InfoMap infoMap;
     5401        player_ctx->LockPlayingInfo(__FILE__, __LINE__);
     5402        player_ctx->playingInfo->ToMap(infoMap);
     5403        infoMap.detach();
     5404        player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
     5405
     5406        osd->SetText("editmode", infoMap, -1);
     5407
     5408        UpdateEditSlider();
     5409        UpdateTimeDisplay();
     5410        if (seekamountpos == 3 || seekamountpos == 4)
     5411            UpdateSeekAmount(true);
     5412        else
     5413            UpdateSeekAmountDisplay();
     5414
     5415        QMap<long long, int>::Iterator it;
     5416        for (it = deleteMap.begin(); it != deleteMap.end(); ++it)
     5417             AddMark(it.key(), *it);
     5418    }
     5419}
     5420
    51015421AspectOverrideMode NuppelVideoPlayer::GetAspectOverride(void) const
    51025422{
    51035423    if (videoOutput)
    bool NuppelVideoPlayer::IsEmbedding(void  
    51845504
    51855505void NuppelVideoPlayer::UpdateSeekAmount(bool up)
    51865506{
    5187     if (seekamountpos > 0 && !up)
    5188         seekamountpos--;
    5189     if (seekamountpos < 9 && up)
    5190         seekamountpos++;
     5507    if (up)
     5508    {
     5509        if (seekamountpos < 11)
     5510            seekamountpos++;
     5511        if (allow_pagesize)
     5512        {
     5513            if (seekamountpos == 1)
     5514                seekamountpos = 2;
     5515        }
     5516        else
     5517        {
     5518            if (seekamountpos == 3 || seekamountpos == 4)
     5519                seekamountpos = 5;
     5520        }
     5521    }
     5522    else
     5523    {
     5524        if (seekamountpos > 0)
     5525            seekamountpos--;
     5526        if (allow_pagesize)
     5527        {
     5528            if (seekamountpos == 1)
     5529                seekamountpos =0;
     5530        }
     5531        else
     5532        {
     5533            if (seekamountpos == 3 || seekamountpos == 4)
     5534                seekamountpos = 2;
     5535        }
     5536    }
    51915537
    51925538    QString text = "";
    51935539
    51945540    switch (seekamountpos)
    51955541    {
    5196         case 0: text = QObject::tr("cut point"); seekamount = -2; break;
    5197         case 1: text = QObject::tr("keyframe"); seekamount = -1; break;
    5198         case 2: text = QObject::tr("1 frame"); seekamount = 1; break;
    5199         case 3: text = QObject::tr("0.5 seconds"); seekamount = (int)roundf(video_frame_rate / 2); break;
    5200         case 4: text = QObject::tr("%n second(s)", "", 1); seekamount = (int)roundf(video_frame_rate); break;
    5201         case 5: text = QObject::tr("%n second(s)", "", 5); seekamount = (int)roundf(video_frame_rate * 5); break;
    5202         case 6: text = QObject::tr("%n second(s)", "", 20); seekamount = (int)roundf(video_frame_rate * 20); break;
    5203         case 7: text = QObject::tr("%n minute(s)", "", 1); seekamount = (int)roundf(video_frame_rate * 60); break;
    5204         case 8: text = QObject::tr("%n minute(s)", "", 5); seekamount = (int)roundf(video_frame_rate * 300); break;
    5205         case 9: text = QObject::tr("%n minute(s)", "", 10); seekamount = (int)roundf(video_frame_rate * 600); break;
     5542        case  0: text = QObject::tr("cut point"); seekamount = -2; break;
     5543
     5544        // Only for non-edit grid
     5545        case  1: text = QObject::tr("keyframe"); seekamount = -1; break;
     5546        // Only for non-edit grid
     5547
     5548        case  2: text = QObject::tr("1 frame"); seekamount = 1; break;
     5549
     5550        // Case 3 & 4 are for the edit grid only
     5551        case  3: text = QObject::tr("1/2 Page");    seekamount =  half_page; break;
     5552        case  4: text = QObject::tr("Full Page");   seekamount =  2*half_page; break;
     5553        // Case 3 & 4 are for the edit grid only
     5554
     5555        case  5: text = QObject::tr("0.5 seconds"); seekamount = (int)roundf(video_frame_rate / 2); break;
     5556        case  6: text = QObject::tr("%n second(s)", "", 1); seekamount = (int)roundf(video_frame_rate); break;
     5557        case  7: text = QObject::tr("%n second(s)", "", 5); seekamount = (int)roundf(video_frame_rate * 5); break;
     5558        case  8: text = QObject::tr("%n second(s)", "", 20); seekamount = (int)roundf(video_frame_rate * 20); break;
     5559        case  9: text = QObject::tr("%n minute(s)", "", 1); seekamount = (int)roundf(video_frame_rate * 60); break;
     5560        case 10: text = QObject::tr("%n minute(s)", "", 5); seekamount = (int)roundf(video_frame_rate * 300); break;
     5561        case 11: text = QObject::tr("%n minute(s)", "", 10); seekamount = (int)roundf(video_frame_rate * 600); break;
    52065562        default: text = QObject::tr("error"); seekamount = (int)roundf(video_frame_rate); break;
    52075563    }
    52085564
     5565    seekamounttext = text;
     5566    UpdateSeekAmountDisplay();
     5567}
     5568
     5569void NuppelVideoPlayer::UpdateSeekAmountDisplay(void)
     5570{
    52095571    InfoMap infoMap;
    5210     infoMap["seekamount"] = text;
    5211     osd->SetText("editmode", infoMap, -1);
     5572    infoMap["seekamount"] = seekamounttext;
     5573    if (!hideedits)
     5574        osd->SetText("editmode", infoMap, -1);
    52125575}
    52135576
    52145577void NuppelVideoPlayer::UpdateTimeDisplay(void)
    void NuppelVideoPlayer::UpdateTimeDispla  
    52385601    infoMap["timedisplay"] = timestr;
    52395602    infoMap["framedisplay"] = framestr;
    52405603    infoMap["cutindicator"] = cutmarker;
    5241     osd->SetText("editmode", infoMap, -1);
     5604    if (!hideedits)
     5605        osd->SetText("editmode", infoMap, -1);
    52425606}
    52435607
    5244 void NuppelVideoPlayer::HandleSelect(bool allowSelectNear)
     5608DeletePointInfo NuppelVideoPlayer::GetDeletePointInfo(long long frame, bool allowSelectNear)
    52455609{
    5246     bool deletepoint = false;
    5247     bool cut_after = false;
    5248     int direction = 0;
     5610    DeletePointInfo retval;
    52495611
    52505612    if(!deleteMap.isEmpty())
    52515613    {
    52525614        QMap<long long, int>::ConstIterator iter = deleteMap.begin();
    52535615
    5254         while((iter != deleteMap.end()) && (iter.key() < framesPlayed))
     5616        while((iter != deleteMap.end()) && (iter.key() < frame))
    52555617            ++iter;
    52565618
    52575619        if (iter == deleteMap.end())
    52585620        {
    52595621            --iter;
    5260             cut_after = !(*iter);
     5622            retval.cut_after = !(*iter);
    52615623        }
    5262         else if((iter != deleteMap.begin()) && (iter.key() != framesPlayed))
     5624        else if((iter != deleteMap.begin()) && (iter.key() != frame))
    52635625        {
    52645626            long long value = iter.key();
    5265             if((framesPlayed - (--iter).key()) > (value - framesPlayed))
     5627            if((framesPlayed - (--iter).key()) > (value - frame))
    52665628            {
    5267                 cut_after = !(*iter);
     5629                retval.cut_after = !(*iter);
    52685630                ++iter;
    52695631            }
    52705632            else
    5271                 cut_after = !(*iter);
     5633                retval.cut_after = !(*iter);
    52725634        }
    52735635
    5274         direction = (*iter);
    5275         deleteframe = iter.key();
     5636        retval.direction = (*iter);
     5637        retval.deleteframe = iter.key();
    52765638
    5277         if ((absLongLong(deleteframe - framesPlayed) <
     5639        if ((absLongLong(retval.deleteframe - frame) <
    52785640                   (int)ceil(20 * video_frame_rate)) && !allowSelectNear)
    52795641        {
    5280             deletepoint = true;
     5642            retval.deletepoint = true;
    52815643        }
    52825644    }
     5645    return retval;
     5646}
     5647
     5648void NuppelVideoPlayer::HandleSelect(bool allowSelectNear)
     5649{
     5650    DeletePointInfo dpi = GetDeletePointInfo(framesPlayed, allowSelectNear);
     5651    deleteframe = dpi.deleteframe;
    52835652
    5284     if (deletepoint)
     5653    if (dpi.deletepoint)
    52855654    {
    52865655        QString message = QObject::tr("You are close to an existing cut point. "
    52875656                                      "Would you like to:");
    void NuppelVideoPlayer::HandleSelect(boo  
    52895658        QString option2 = QObject::tr("Move this cut point to the current "
    52905659                                      "position");
    52915660        QString option3 = QObject::tr("Flip directions - delete to the ");
    5292         if (direction == 0)
     5661        if (dpi.direction == 0)
    52935662            option3 += QObject::tr("right");
    52945663        else
    52955664            option3 += QObject::tr("left");
    void NuppelVideoPlayer::HandleSelect(boo  
    53195688        options += option1;
    53205689        options += option2;
    53215690
    5322         osd->NewDialogBox(dialogname, message, options, -1, cut_after);
     5691        osd->NewDialogBox(dialogname, message, options, -1, dpi.cut_after);
    53235692    }
    53245693}
    53255694
    void NuppelVideoPlayer::HandleResponse(v  
    53705739
    53715740void NuppelVideoPlayer::UpdateEditSlider(void)
    53725741{
    5373     osd->DoEditSlider(deleteMap, framesPlayed, totalFrames);
     5742    if (!hideedits)
     5743        osd->DoEditSlider(deleteMap, framesPlayed, totalFrames);
    53745744}
    53755745
    53765746void NuppelVideoPlayer::AddMark(long long frames, int type)
    53775747{
    53785748    deleteMap[frames] = type;
    5379     osd->ShowEditArrow(frames, totalFrames, type);
     5749    if (!hideedits)
     5750        osd->ShowEditArrow(frames, totalFrames, type);
    53805751}
    53815752
    53825753void NuppelVideoPlayer::DeleteMark(long long frames)
    53835754{
    5384     osd->HideEditArrow(frames, deleteMap[frames]);
     5755    if (!hideedits)
     5756        osd->HideEditArrow(frames, deleteMap[frames]);
    53855757    deleteMap.remove(frames);
    53865758}
    53875759
    53885760void NuppelVideoPlayer::ReverseMark(long long frames)
    53895761{
    5390     osd->HideEditArrow(frames, deleteMap[frames]);
     5762    if (!hideedits)
     5763        osd->HideEditArrow(frames, deleteMap[frames]);
    53915764
    53925765    if (deleteMap[frames] == MARK_CUT_END)
    53935766        deleteMap[frames] = MARK_CUT_START;
    53945767    else
    53955768        deleteMap[frames] = MARK_CUT_END;
    53965769
    5397     osd->ShowEditArrow(frames, totalFrames, deleteMap[frames]);
     5770    if (!hideedits)
     5771        osd->ShowEditArrow(frames, totalFrames, deleteMap[frames]);
    53985772}
    53995773
    5400 void NuppelVideoPlayer::HandleArbSeek(bool right)
     5774long long NuppelVideoPlayer::CalcCutPointSeek(long long baseframe, bool right)
    54015775{
    5402     if (seekamount == -2)
     5776    QMap<long long, int>::Iterator i = deleteMap.begin();
     5777    long long framenum = -1;
     5778    long long seekcount = 0;
     5779    if (right)
    54035780    {
    5404         QMap<long long, int>::Iterator i = deleteMap.begin();
    5405         long long framenum = -1;
    5406         if (right)
     5781        for (; i != deleteMap.end(); ++i)
    54075782        {
    5408             for (; i != deleteMap.end(); ++i)
     5783            if (i.key() > baseframe)
    54095784            {
    5410                 if (i.key() > framesPlayed)
    5411                 {
    5412                     framenum = i.key();
    5413                     break;
    5414                 }
     5785                framenum = i.key();
     5786                break;
    54155787            }
    5416             if (framenum == -1)
    5417                 framenum = totalFrames;
     5788        }
     5789        if (framenum == -1)
     5790            framenum = totalFrames;
     5791        seekcount = framenum - baseframe;
     5792    }
     5793    else
     5794    {
     5795        for (; i != deleteMap.end(); ++i)
     5796        {
     5797            if (i.key() >= baseframe)
     5798                break;
     5799            framenum = i.key();
     5800        }
     5801        if (framenum == -1)
     5802            framenum = 0;
     5803        seekcount = baseframe - framenum;
     5804    }
     5805    return seekcount;
     5806}
    54185807
    5419             fftime = framenum - framesPlayed;
     5808void NuppelVideoPlayer::HandleArbSeek(bool right)
     5809{
     5810    if (seekamount == -2)
     5811    {
     5812        long long seekcount = CalcCutPointSeek(framesPlayed, right);
     5813        if (right)
     5814        {
     5815            fftime = seekcount;
    54205816            while (fftime > 0)
    54215817                usleep(1000);
    54225818        }
    54235819        else
    54245820        {
    5425             for (; i != deleteMap.end(); ++i)
    5426             {
    5427                 if (i.key() >= framesPlayed)
    5428                     break;
    5429                 framenum = i.key();
    5430             }
    5431             if (framenum == -1)
    5432                 framenum = 0;
    5433 
    5434             rewindtime = framesPlayed - framenum;
     5821            rewindtime = seekcount;
    54355822            while (rewindtime > 0)
    54365823                usleep(1000);
    54375824        }
    void NuppelVideoPlayer::HandleArbSeek(bo  
    54625849    UpdateEditSlider();
    54635850}
    54645851
     5852int NuppelVideoPlayer::GetCutStatus(long long testframe) const
     5853{
     5854    int retval = 0;
     5855    QMap<long long, int>::const_iterator i;
     5856    i = deleteMap.find(testframe);
     5857    if (i == deleteMap.end()) {
     5858        // testframe is not an explicit cutpoint
     5859        // See if it is in a deleted area
     5860        if (IsInDelete(testframe))
     5861            retval = 1;
     5862    } else {
     5863        int direction = *i;
     5864        if (direction == 0)
     5865            retval = 2;
     5866        else
     5867            retval = 3;
     5868    }
     5869
     5870    return retval;
     5871}
     5872
    54655873bool NuppelVideoPlayer::IsInDelete(long long testframe) const
    54665874{
    54675875    long long startpos = 0;
  • mythtv/libs/libmythtv/NuppelVideoPlayer.h

    old new enum  
    8484    kDisplayTeletextMenu        = 0x40,
    8585};
    8686
     87class DeletePointInfo
     88{
     89    public:
     90        DeletePointInfo() :
     91            deleteframe(0), deletepoint(false), cut_after(false), direction(0) {}
     92
     93        long long deleteframe;
     94        bool deletepoint;
     95        bool cut_after;
     96        int direction;
     97};
     98
    8799class MPUBLIC NuppelVideoPlayer : public CC608Reader, public CC708Reader
    88100{
    89101    friend class PlayerContext;
     102    friend class GridEditCutpoints;
     103    friend class TV;
    90104
    91105  public:
    92106    NuppelVideoPlayer(bool muted = false);
    class MPUBLIC NuppelVideoPlayer : public  
    279293    bool EnableEdit(void);
    280294    bool DoKeypress(QKeyEvent *e);
    281295    bool GetEditMode(void) const { return editmode; }
     296    bool GetHideEdits(void) const { return hideedits; }
    282297
    283298    // Decoder stuff..
    284299    VideoFrame *GetNextVideoFrame(bool allow_unsafe = true);
    class MPUBLIC NuppelVideoPlayer : public  
    298313    void ShutdownYUVResize(void);
    299314    void SaveScreenshot(void);
    300315
     316    // Edit stuff
     317    bool EditSeekToFrame(long long targetFrame);
     318    void SetScreenGrabSizes(QSize normal, QSize small);
     319    bool GetScreenGrabsOfCurrentFrame(QImage & normal, QImage &small); // Get current frame
     320
     321    void       EditHandleClearMap();
     322    void       EditHandleInvertMap();
     323    void       EditHandleLoadCommSkip();
     324
     325    void StartEditRecordingGrid();
     326    void EndEditRecordingGrid();
     327
    301328    // Reinit
    302329    void    ReinitOSD(void);
    303330    void    ReinitVideo(void);
    class MPUBLIC NuppelVideoPlayer : public  
    425452    bool PosMapFromEnc(unsigned long long          start,
    426453                       QMap<long long, long long> &posMap);
    427454
     455    // Stuff for GridEditCutpoints
     456    long long CalcCutPointSeek(long long baseframe, bool right);
     457    // returns
     458    // 0 - no cut
     459    // 1 - is deleted
     460    // 2 - cut left
     461    // 3 - cut right
     462    int  GetCutStatus(long long testframe) const;
     463    long long GetSeekAmount() { return seekamount; }
     464    QString GetSeekAmountText() { return seekamounttext; }
     465
    428466  protected:
    429467    void DisplayPauseFrame(void);
    430468    void DisplayNormalFrame(void);
    class MPUBLIC NuppelVideoPlayer : public  
    510548    void HandleSelect(bool allowSelectNear = false);
    511549    void HandleResponse(void);
    512550
     551    DeletePointInfo GetDeletePointInfo(long long frame, bool allowSelectNear);
     552
     553    void SetupScreenGrab();
     554    void ClearScreenGrab();
     555
    513556    void UpdateTimeDisplay(void);
     557    int  GetSeekAmountPos() { return seekamountpos; }
    514558    void UpdateSeekAmount(bool up);
     559    void SetHalfPageSize(int hp) { allow_pagesize = true; half_page = hp; }
     560    void UpdateSeekAmountDisplay(void);
    515561    void UpdateEditSlider(void);
    516562
    517563    // Private A/V Sync Stuff
    class MPUBLIC NuppelVideoPlayer : public  
    585631    bool     livetv;
    586632    bool     watchingrecording;
    587633    bool     editmode;
     634    bool     hideedits;
    588635    bool     resetvideo;
    589636    bool     using_null_videoout;
    590637    bool     no_audio_in;
    class MPUBLIC NuppelVideoPlayer : public  
    608655    long long fftime;
    609656    /// 1..9 == keyframe..10 minutes. 0 == cut point
    610657    int       seekamountpos;
     658    ///  Used for Grid Edit logic
     659    bool      allow_pagesize;
     660    int       half_page;
    611661    /// Seekable frame increment when not using exact seeks.
    612662    /// Usually equal to keyframedist.
    613663    int      seekamount;
     664    QString  seekamounttext; // OSD seek units
    614665    /// Iff true we ignore seek amount and try to seek to an
    615666    /// exact frame ignoring key frame restrictions.
    616667    bool     exactseeks;
    class MPUBLIC NuppelVideoPlayer : public  
    750801    QMutex              yuv_lock;
    751802    QWaitCondition      yuv_wait;
    752803
     804    // EditGrid still image capture
     805    struct SwsContext  *grid_edit_image_scaler;
     806    struct SwsContext  *grid_edit_image_small_scaler;
     807    unsigned char      *grid_edit_image_buffer_yuv;
     808    unsigned char      *grid_edit_image_small_buffer_yuv;
     809    unsigned char      *grid_edit_image_buffer_rgb;
     810    unsigned char      *grid_edit_image_small_buffer_rgb;
     811    int                 grid_edit_image_buffer_length;
     812    int                 grid_edit_image_small_buffer_length;
     813    QSize               grid_edit_image_in_size;
     814    QSize               grid_edit_image_size;
     815    QSize               grid_edit_image_small_size;
     816    QMutex              grid_edit_lock;
     817
    753818    // Filters
    754819    QMutex   videofiltersLock;
    755820    QString  videoFiltersForProgram;
  • new file 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 "NuppelVideoPlayer.h"
     26#include "mythuicutpointbar.h"
     27#include "mythuicutpointimage.h"
     28#include "mythdialogbox.h"
     29#include "tv_play.h"
     30
     31#ifndef FUNCTIONLOGGER
     32#define FUNCTIONLOGGER
     33#endif
     34
     35void GridEditCutpoints::RunGridEditCutpoints(TV *tv)
     36{
     37    FUNCTIONLOGGER;
     38    MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
     39
     40    GridEditCutpoints *er = new GridEditCutpoints(mainStack, "editrecording", tv);
     41
     42    if (er->Create())
     43    {
     44        mainStack->AddScreen(er);
     45    }
     46    else
     47    {
     48        VERBOSE(VB_GENERAL, "Create failed");
     49        delete er;
     50    }
     51}
     52
     53GridEditCutpoints::GridEditCutpoints(MythScreenStack *parent, QString name, TV *tv)
     54         : MythScreenType(parent, name, true)
     55{
     56    m_tv = tv;
     57
     58    const PlayerContext *mctx =
     59        m_tv->GetPlayerReadLock(0, __FILE__, __LINE__);
     60    mctx->LockDeleteNVP(__FILE__, __LINE__);
     61    m_player = mctx->nvp;
     62    mctx->UnlockDeleteNVP(__FILE__, __LINE__);
     63    tv->ReturnPlayerLock(mctx);
     64
     65    m_images = new GridEditImages(this, m_player);
     66
     67}
     68
     69GridEditCutpoints::~GridEditCutpoints()
     70{
     71    FUNCTIONLOGGER;
     72    gContext->removeListener(this);
     73    if (m_images)
     74    {
     75        delete m_images;
     76        m_images = NULL;
     77    }
     78
     79    if (m_tv)
     80    {
     81        QString message = QString("GRIDEDIT_EXITING");
     82        qApp->postEvent(m_tv, new MythEvent(message));
     83    }
     84
     85}
     86
     87bool GridEditCutpoints::Create()
     88{
     89    FUNCTIONLOGGER
     90
     91    if (!LoadWindowFromXML("recordings-ui.xml", "grideditcutpoints", this))
     92        return false;
     93
     94    int i;
     95    m_gridimagemain = NULL;
     96    for (i = m_gridimages.minIndex(); i < m_gridimages.maxIndex(); i++)
     97    {
     98        m_gridimages[i] = NULL;
     99    }
     100
     101    usedSubVideoCount=0;
     102
     103    QSize videoSizeMain, videoSizeSmall;
     104
     105    m_gridimagemain = dynamic_cast<MythUICutPointImage *> (GetChild("mainvideo"));
     106    if (m_gridimagemain)
     107        videoSizeMain = m_gridimagemain->GetArea().size();
     108    else
     109    {
     110        VERBOSE(VB_IMPORTANT, "FATAL: Couldn't find grideditcutpoints:mainvideo");
     111        return false;
     112    }
     113
     114    // Small version of main frame
     115    m_gridimages[0] = dynamic_cast<MythUICutPointImage *> (GetChild("video0"));
     116
     117    for (i = 1; i < m_gridimages.maxIndex(); i++)
     118    {
     119        QString p = QString("videop%1").arg(i);
     120        QString m = QString("videom%1").arg(i);
     121
     122        // Minus frame i
     123        m_gridimages[-i] = dynamic_cast<MythUICutPointImage *> (GetChild(m));
     124        if (m_gridimages[-i])
     125        {
     126            QSize tmpVideoSizeSmall = m_gridimages[-i]->GetArea().size();
     127            if (videoSizeSmall.isValid() && videoSizeSmall != tmpVideoSizeSmall)
     128                VERBOSE(VB_IMPORTANT,
     129                        QString("Multiple sizes found for edit videos (%1)").arg(m));
     130            else
     131                videoSizeSmall = tmpVideoSizeSmall;
     132            if (i > usedSubVideoCount) usedSubVideoCount=i;
     133        }
     134
     135        m_gridimages[i] = dynamic_cast<MythUICutPointImage *> (GetChild(p));
     136        if (m_gridimages[i])
     137        {
     138            QSize tmpVideoSizeSmall = m_gridimages[i]->GetArea().size();
     139            if (videoSizeSmall.isValid() && videoSizeSmall != tmpVideoSizeSmall)
     140                VERBOSE(VB_IMPORTANT,
     141                        QString("Multiple sizes found for edit videos (%1)").arg(p));
     142            else
     143                videoSizeSmall = tmpVideoSizeSmall;
     144            if (i > usedSubVideoCount) usedSubVideoCount=i;
     145        }
     146    }
     147
     148    imageScreenArea = m_gridimages[-usedSubVideoCount]->GetArea();
     149    for (i = -usedSubVideoCount; i <= usedSubVideoCount; i++)
     150        if (m_gridimages[i])
     151            imageScreenArea = imageScreenArea.unite(m_gridimages[i]->GetArea());
     152
     153    m_slider = dynamic_cast<MythUICutPointBar *> (GetChild("positionbar"));
     154    if (!m_slider)
     155        VERBOSE(VB_GENERAL, "Missing positionbar for GridEditCutpoints");
     156    else
     157        m_slider->InitWidth();
     158
     159    // Get Status boxes
     160    {
     161        m_framenum    = dynamic_cast<MythUIText *> (GetChild("framenum"));
     162        m_time        = dynamic_cast<MythUIText *> (GetChild("time"));
     163        m_cutind      = dynamic_cast<MythUIText *> (GetChild("cutind"));
     164        m_jumpstyle   = dynamic_cast<MythUIText *> (GetChild("jumpstyle"));
     165        m_updatingind = dynamic_cast<MythUIText *> (GetChild("updatingind"));
     166    }
     167
     168    VERBOSE(VB_GENERAL, QString("main = (%1, %2) small = (%3, %4)")
     169                       .arg(videoSizeMain.width()).arg(videoSizeMain.height())
     170                       .arg(videoSizeSmall.width()).arg(videoSizeSmall.height()));
     171
     172    slowMotionDirection = 1; // start off play forward
     173    slowMotionActive = false;
     174    readyForNextFrame = false;
     175    slowMotionTimer = NULL;
     176    slowMotionTimer = new QTimer(this);
     177    QObject::connect(slowMotionTimer, SIGNAL(timeout()),
     178                     this,           SLOT(updateSlowMotion()));
     179
     180    movingCutpoint = false;
     181    // Create blank pixmaps...
     182
     183    m_images->SetVideoInfo(usedSubVideoCount, videoSizeMain, videoSizeSmall);
     184
     185    m_player->StartEditRecordingGrid();
     186
     187    LoadInBackground();
     188    return true;
     189}
     190
     191void GridEditCutpoints::Load()
     192{
     193    FUNCTIONLOGGER;
     194}
     195
     196void GridEditCutpoints::Init()
     197{
     198    FUNCTIONLOGGER;
     199
     200    // Ensure we're not on keyframe seek
     201
     202    m_player->SetHalfPageSize(usedSubVideoCount);
     203
     204    if (m_player->GetSeekAmountPos() == 1)
     205        m_player->UpdateSeekAmount(true);
     206
     207    refreshImages();
     208    refreshCutList();
     209    updateStats();
     210
     211    gContext->addListener(this);
     212}
     213
     214void GridEditCutpoints::Close()
     215{
     216    FUNCTIONLOGGER;
     217
     218    if (slowMotionTimer)
     219        slowMotionTimer->stop();
     220
     221//    unsetCursor();
     222
     223    m_player->EndEditRecordingGrid();
     224    GetScreenStack()->PopScreen(this, false);
     225}
     226
     227void GridEditCutpoints::displayInitialFrame()
     228{
     229    refreshImages();
     230    refreshCutList();
     231    updateStats();
     232}
     233
     234void GridEditCutpoints::updateSlowMotion()
     235{
     236    if (!slowMotionActive)
     237        slowMotionTimer->stop();
     238    else if (readyForNextFrame && slowMotionDirection != 0)
     239    {
     240        readyForNextFrame=false;
     241
     242        if (slowMotionDirection > 0)
     243            EditHandleRight();
     244        else if (slowMotionDirection < 0)
     245            EditHandleLeft();
     246    }
     247}
     248
     249
     250void GridEditCutpoints::setSlowMotionSpeed()
     251{
     252    // slowMotionDirection is max FPS
     253
     254    if (slowMotionDirection != 0)
     255    {
     256        int smd = slowMotionDirection;
     257        if (smd < 0) smd = -smd;
     258        int timeout = 1000 / smd;
     259
     260        slowMotionTimer->start(timeout);
     261    }
     262    SetUpdating(true, QString("%1 FPS max").arg(slowMotionDirection));
     263}
     264
     265
     266bool GridEditCutpoints::keyPressEvent(QKeyEvent *event)
     267{
     268    FUNCTIONLOGGER;
     269
     270    QStringList actions;
     271    bool handled = false;
     272    handled = GetMythMainWindow()->TranslateKeyPress("TV Editing", event, actions);
     273
     274    if (handled)
     275        return true;
     276
     277    bool skipMost=false;
     278
     279    for (unsigned int i = 0; i < actions.size() && !handled; i++)
     280    {
     281        QString action = actions[i];
     282        handled = true;
     283
     284        VERBOSE(VB_GENERAL, QString("key[%1] = '%2'").arg(i).arg(action));
     285
     286        if (action == "SELECT" && !skipMost)
     287        {
     288            if (slowMotionActive)
     289                stopSlowMotion();
     290            else if (movingCutpoint)
     291            {
     292                // Move cutpoint
     293                m_player->DeleteMark(savedCutpoint);
     294                m_player->AddMark(m_images->GetCurrentFrameNumber(), savedCutType);
     295                movingCutpoint = false;
     296                refreshCutList();
     297                refreshImages();
     298            }
     299            else
     300                handleSelect();
     301        }
     302        else if (action == "PAUSE" && !skipMost)
     303            stopSlowMotion();
     304        else if (action == "SLOWMO" && !skipMost)
     305        {
     306            if (movingCutpoint)
     307                ShowOkPopup("Slow Motion Unavailable when moving cutpoint");
     308            else
     309            {
     310                if (slowMotionActive)
     311                    stopSlowMotion();
     312                else
     313                    startSlowMotion();
     314            }
     315        }
     316        else if (action == "LEFT" && !skipMost)
     317        {
     318            if (slowMotionActive)
     319            {
     320                slowMotionDirection--;
     321                setSlowMotionSpeed();
     322            }
     323            else
     324                EditHandleLeft();
     325        }
     326        else if (action == "RIGHT" && !skipMost)
     327        {
     328            if (slowMotionActive)
     329            {
     330                slowMotionDirection++;
     331                setSlowMotionSpeed();
     332            }
     333            else
     334                EditHandleRight();
     335        }
     336        else if (action == "UP" && !skipMost)
     337        {
     338            m_player->UpdateSeekAmount(true);
     339            updateStats();
     340        }
     341        else if (action == "DOWN" && !skipMost)
     342        {
     343            if (slowMotionActive && m_player->GetSeekAmountPos() == 2)
     344                ShowOkPopup("CutPoint skip Unavailable in Slow Motion");
     345            else
     346            {
     347                m_player->UpdateSeekAmount(false);
     348                updateStats();
     349            }
     350        }
     351        else if (action == "CLEARMAP" && !skipMost)
     352        {
     353            if (movingCutpoint)
     354                ShowOkPopup("Clear Cut Map Unavailable when Moving Cutpoint");
     355            else if (slowMotionActive)
     356                ShowOkPopup("Clear Cut Map Unavailable in Slow Motion");
     357            else
     358            {
     359                SetUpdating(true);
     360                m_player->EditHandleClearMap();
     361                refreshCutList();
     362                updateStats();
     363                SetUpdating(false);
     364            }
     365        }
     366        else if (action == "INVERTMAP" && !skipMost)
     367        {
     368            if (movingCutpoint)
     369                ShowOkPopup("Invert Cut Map Unavailable when Moving Cutpoint");
     370            else if (slowMotionActive)
     371                ShowOkPopup("Invert Cut Map Unavailable in Slow Motion");
     372            else
     373            {
     374                SetUpdating(true);
     375                m_player->EditHandleInvertMap();
     376                refreshCutList();
     377                updateStats();
     378                SetUpdating(false);
     379            }
     380        }
     381        else if (action == "LOADCOMMSKIP" && !skipMost)
     382        {
     383            if (movingCutpoint)
     384                ShowOkPopup("Load Comm Skip Map Unavailable when Moving Cutpoint");
     385            else if (slowMotionActive)
     386                ShowOkPopup("Load Comm Skip Map Unavailable in Slow Motion");
     387            else
     388            {
     389                SetUpdating(true);
     390                m_player->EditHandleLoadCommSkip();
     391                refreshCutList();
     392                updateStats();
     393                SetUpdating(false);
     394            }
     395        }
     396        else if (action == "PREVCUT" && !skipMost)
     397        {
     398            if (slowMotionActive)
     399                ShowOkPopup("Prev Cut Unavailable in Slow Motion");
     400            else
     401                EditHandlePrevCut();
     402        }
     403        else if (action == "NEXTCUT" && !skipMost)
     404        {
     405            if (slowMotionActive)
     406                ShowOkPopup("Next Cut Unavailable in Slow Motion");
     407            else
     408                EditHandleNextCut();
     409        }
     410        else if (action == "BIGJUMPREW" && !skipMost)
     411            EditHandleBigJumpRew();
     412        else if (action == "BIGJUMPFWD" && !skipMost)
     413            EditHandleBigJumpFwd();
     414        else if (action == "ESCAPE" && movingCutpoint)
     415        {
     416            movingCutpoint = false;
     417            SetUpdating(false);
     418        }
     419        else if (action == "ESCAPE" && slowMotionActive)
     420            stopSlowMotion();
     421        else if (action == "ESCAPE" || action == "TOGGLEEDIT" ||
     422                 action == "MENU")
     423            Close();
     424        else
     425            handled = false;
     426
     427        if (movingCutpoint)
     428            SetUpdating(true, "Moving Cutpoint");
     429    }
     430
     431    if (!handled && MythScreenType::keyPressEvent(event))
     432        handled = true;
     433
     434    return handled;
     435}
     436
     437void GridEditCutpoints::customEvent(QEvent *event)
     438{
     439FUNCTIONLOGGER;
     440    bool needupdate = false;
     441
     442    VERBOSE(VB_GENERAL, QString("Got Event %1").arg(event->type()));
     443
     444    if (event->type() == DialogCompletionEvent::kEventType)
     445    {
     446        DialogCompletionEvent *dce = (DialogCompletionEvent*)(event);
     447
     448        QString resultid   = dce->GetId();
     449        QString resulttext = dce->GetResultText();
     450        int     buttonnum  = dce->GetResult();
     451
     452        VERBOSE(VB_GENERAL, QString("Got '%1' '%2' %3")
     453                .arg(resultid).arg(resulttext).arg(buttonnum));
     454
     455        if (resultid == "cutpointexists")
     456        {
     457            FrameStats fs = m_images->GetMainFrameStats();
     458            //  menuPopup->AddButton("Delete cutpoint?");
     459            //  menuPopup->AddButton("Move cutpoint?");
     460            //  if (fs.cutInd == 2)
     461            //      menuPopup->AddButton("Flip directions (Cut After)?");
     462            //  else
     463            //      menuPopup->AddButton("Flip directions (Cut Before)?");
     464
     465            if (resulttext == "Delete cutpoint?")
     466            {
     467                m_player->DeleteMark(fs.frameNumber);
     468                needupdate = true;
     469            }
     470            else if (resulttext == "Move cutpoint?")
     471            {
     472                // Move cutpoint
     473                savedCutpoint = fs.frameNumber;
     474                savedCutType = m_player->deleteMap[fs.frameNumber];
     475                movingCutpoint = true;
     476                // Ensure we're at least at 1 frame motion
     477                int i;
     478                for (i = 0; m_player->GetSeekAmountPos() < 2 && i < 10; i++)
     479                    m_player->UpdateSeekAmount(true);
     480                needupdate = true;
     481            }
     482            else if (resulttext == "Flip directions (Cut After)?" ||
     483                     resulttext == "Flip directions (Cut Before)?")
     484            {
     485                m_player->ReverseMark(fs.frameNumber);
     486                needupdate = true;
     487            }
     488        }
     489        else if (resultid == "addcutpoint")
     490        {
     491            FrameStats fs = m_images->GetMainFrameStats();
     492            // menuPopup->AddButton("Delete before this frame");
     493            // menuPopup->AddButton("Delete after this frame");
     494
     495            if (resulttext == "Delete before this frame")
     496            {
     497                // Delete left
     498                m_player->AddMark(fs.frameNumber, MARK_CUT_END);
     499                needupdate = true;
     500            }
     501            else if (resulttext == "Delete after this frame")
     502            {
     503                // Delete Right
     504                m_player->AddMark(fs.frameNumber, MARK_CUT_START);
     505                needupdate = true;
     506            }
     507        }
     508
     509    } else
     510        MythScreenType::customEvent(event);
     511
     512    if (needupdate)
     513    {
     514        refreshCutList();
     515        refreshImages();
     516    }
     517}
     518
     519void GridEditCutpoints::startSlowMotion()
     520{
     521    if (!slowMotionActive)
     522    {
     523        slowMotionActive = true;
     524        readyForNextFrame = true;
     525        slowMotionDirection = 1;
     526
     527        // force to either 1 frame. 1/2 page or full page motion
     528        int i;
     529        // move to 1 frame if on cutpoint
     530        for (i = 0; m_player->GetSeekAmountPos() < 2 && i < 10; i++)
     531            m_player->UpdateSeekAmount(true);
     532
     533        // move to fullpage if higher
     534        for (i = 0; m_player->GetSeekAmountPos() > 4 && i < 10; i++)
     535            m_player->UpdateSeekAmount(false);
     536
     537        setSlowMotionSpeed();
     538    }
     539}
     540
     541void GridEditCutpoints::stopSlowMotion()
     542{
     543    if (slowMotionActive)
     544    {
     545        slowMotionActive = false;
     546        slowMotionTimer->stop();
     547        SetUpdating(false);
     548    }
     549}
     550
     551
     552void GridEditCutpoints::EditHandleLeft(int seektype)
     553{
     554    long long seekamount = m_player->GetSeekAmount();
     555    bool cutpointseek = false;
     556
     557    if (seektype == -2 || seekamount == -2)
     558        cutpointseek = true;
     559    else
     560    {
     561        // seektype == 1 for normal, 10 for bigjump
     562        seekamount *= seektype;
     563    }
     564
     565    if (seekamount < 0) // Invalid -- keyframe
     566        seekamount = 1;
     567
     568    m_images->SeekLeft(seekamount, cutpointseek);
     569
     570    refreshImages();
     571    updateStats();
     572}
     573
     574void GridEditCutpoints::EditHandleRight(int seektype)
     575{
     576    long long seekamount = m_player->GetSeekAmount();
     577    bool cutpointseek=false;
     578
     579    if (seektype == -2 || seekamount == -2)
     580        cutpointseek = true;
     581    else
     582    {
     583        // seektype == 1 for normal, 10 for bigjump
     584        seekamount *= seektype;
     585    }
     586
     587    if (seekamount < 0) // Invalid -- keyframe
     588        seekamount = 1;
     589
     590    m_images->SeekRight(seekamount, cutpointseek);
     591
     592    refreshImages();
     593    updateStats();
     594}
     595
     596void GridEditCutpoints::handleSelect(void)
     597{
     598    bool needupdate = false;
     599    // add / update cutpoint
     600    // -or-
     601    // delete / flip / move cutpoint
     602
     603    // if no cut points on screen
     604    //    "Delete Before"
     605    //    "Delete After"
     606
     607    // if on existing cutpoint
     608    //    "Delete cutpoint"
     609    //    "Flip directions"
     610
     611    // FIXME
     612    // if a cutpoint exists on the screen but not on the current frame
     613    //    "Move to current frame"
     614    //    "Add new"
     615
     616    FrameStats fs = m_images->GetMainFrameStats();
     617    DeletePointInfo dpi = m_player->GetDeletePointInfo(fs.frameNumber, true);
     618
     619    MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
     620
     621    if (fs.cutInd >= 2)
     622    {
     623        MythDialogBox *menuPopup = new MythDialogBox("Cutpoint Exists", popupStack, "menuPopup");
     624        if (menuPopup->Create())
     625        {
     626            menuPopup->SetReturnEvent(this, "cutpointexists");
     627
     628            menuPopup->AddButton("Delete cutpoint?", 0, false, true); // Default
     629            menuPopup->AddButton("Move cutpoint?");
     630            if (fs.cutInd == 2)
     631                menuPopup->AddButton("Flip directions (Cut After)?");
     632            else
     633                menuPopup->AddButton("Flip directions (Cut Before)?");
     634
     635            popupStack->AddScreen(menuPopup);
     636        }
     637        else
     638        {
     639            delete menuPopup;
     640        }
     641    }
     642    else
     643    {
     644        MythDialogBox *menuPopup = new MythDialogBox("Insert New Cutpoint?", popupStack, "menuPopup");
     645        if (menuPopup->Create())
     646        {
     647            menuPopup->SetReturnEvent(this, "addcutpoint");
     648
     649            menuPopup->AddButton("Delete before this frame");
     650            menuPopup->AddButton("Delete after this frame", 0, false, dpi.cut_after); // might be default
     651
     652            popupStack->AddScreen(menuPopup);
     653        }
     654        else
     655        {
     656            delete menuPopup;
     657        }
     658    }
     659}
     660
     661void GridEditCutpoints::refreshImages()
     662{
     663    m_images->refreshImages(m_gridimagemain, m_gridimages, false);
     664//    repaint(m_gridimagemain->GetArea());
     665//    repaint(imageScreenArea);
     666}
     667
     668void GridEditCutpoints::refreshCutList()
     669{
     670    m_images->refreshCutList(m_gridimagemain, m_gridimages);
     671    refreshSlider();
     672}
     673
     674void GridEditCutpoints::refreshSlider()
     675{
     676    if (!m_slider)
     677        return;
     678
     679    m_slider->ClearAll();
     680
     681    const int CUT_LEFT = 0;
     682    const int CUT_RIGHT = 1;
     683
     684    long long startpos = 0;
     685    long long endpos = 0;
     686
     687    int       lastdirection = CUT_LEFT;
     688
     689    QMap<long long, int> & deleteMap = m_player->deleteMap;
     690    QMap<long long, int>::Iterator i = deleteMap.begin();
     691    for (; i != deleteMap.end(); ++i)
     692    {
     693        long long frame = i.key();
     694        int direction = *i;
     695
     696        if (direction == CUT_LEFT)
     697        {
     698            endpos = frame;
     699            m_slider->SetRange(startpos, endpos, m_images->GetMaxFrameNumber());
     700
     701            startpos = frame;
     702            lastdirection = CUT_LEFT;
     703        }
     704        else if (direction == CUT_RIGHT)
     705        {
     706            if (lastdirection == CUT_RIGHT)
     707            {
     708                // continuing within a cutpoint
     709                endpos = frame;
     710                m_slider->SetRange(startpos, endpos, m_images->GetMaxFrameNumber());
     711            }
     712
     713            startpos = frame;
     714            lastdirection = CUT_RIGHT;
     715        }
     716    }
     717
     718    if (lastdirection == CUT_RIGHT)
     719    {
     720        // continuing within a cutpoint
     721        endpos = m_images->GetMaxFrameNumber();
     722        m_slider->SetRange(startpos, endpos, m_images->GetMaxFrameNumber());
     723    }
     724}
     725
     726void GridEditCutpoints::updateStats(bool forcerepaint)
     727{
     728FUNCTIONLOGGER;
     729    int secs, frames, ss, mm, hh;
     730
     731    FrameStats fs = m_images->GetMainFrameStats();
     732
     733    secs = (int)(fs.frameNumber / m_player->GetFrameRate());
     734    frames = fs.frameNumber - (int)(secs * m_player->GetFrameRate());
     735
     736    ss = secs;
     737    mm = ss / 60;
     738    ss %= 60;
     739    hh = mm / 60;
     740    mm %= 60;
     741
     742    char timestr[128];
     743    sprintf(timestr, "%d:%02d:%02d.%02d", hh, mm, ss, frames);
     744
     745    char framestr[128];
     746    sprintf(framestr, "%lld", fs.frameNumber);
     747
     748    if (m_time)
     749    {
     750        m_time->SetText(timestr);
     751//        if (forcerepaint)
     752//            repaint(m_time->getScreenArea());
     753    }
     754    if (m_framenum)
     755    {
     756        m_framenum->SetText(framestr);
     757//        if (forcerepaint)
     758//            repaint(m_framenum->getScreenArea());
     759    }
     760    if (m_cutind)
     761    {
     762        switch (fs.cutInd) {
     763            case 0: m_cutind->SetText("");           break;
     764            case 1: m_cutind->SetText("Cut");        break;
     765            case 2: m_cutind->SetText("Cut Before"); break;
     766            case 3: m_cutind->SetText("Cut After");  break;
     767        }
     768//        if (forcerepaint)
     769//            repaint(m_cutind->getScreenArea());
     770    }
     771
     772    // Don't need to force update this
     773    if (m_jumpstyle)
     774        m_jumpstyle->SetText(m_player->GetSeekAmountText());
     775
     776    if (m_slider)
     777        m_slider->SetCurrentPosition(fs.frameNumber, fs.maxFrameNumber);
     778
     779}
     780
     781void GridEditCutpoints::escape()
     782{
     783    // Make sure we're on the right frame when we go back to
     784    // Normal edit mode
     785//    unsetCursor();
     786//    accept();
     787}
     788
     789void GridEditCutpoints::displayCacheStatus(int level)
     790{
     791    // 0 - onscreen frames
     792    // 1 - precache frames
     793    // 2 - fill-out-the buffer frames
     794
     795    if (!slowMotionActive && !movingCutpoint)
     796        switch (level) {
     797            case 0: SetUpdating(true, "Displaying"); break;
     798            case 1: SetUpdating(true, "Pre-Caching"); break;
     799            case 2: SetUpdating(true, "Caching"); break;
     800            default: SetUpdating(false);
     801        }
     802}
     803
     804void GridEditCutpoints::SetUpdating(bool active, QString text)
     805{
     806
     807    if (m_updatingind)
     808    {
     809        //VERBOSE(VB_GENERAL, QString("Updating to %1").arg(active));
     810        if (active)
     811        {
     812            m_updatingind->Show();
     813            m_updatingind->SetText(text);
     814        }
     815        else
     816            m_updatingind->Hide();
     817//        repaint(m_updatingind->getScreenArea());
     818    }
     819}
     820
     821void GridEditCutpoints::cacheFramesAreReady()
     822{
     823    if (slowMotionActive)
     824    {
     825        readyForNextFrame=true;
     826        if (!slowMotionTimer->isActive())
     827            slowMotionTimer->start(0);
     828    }
     829}
     830
  • new file 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
     14
     15class QTimer;
     16class NuppelVideoPlayer;
     17class GridEditImages;
     18class MythUICutPointBar;
     19class MythUICutPointImage;
     20class MythUIText;
     21class TV;
     22
     23class GridEditCutpoints : public MythScreenType
     24{
     25  Q_OBJECT
     26  public:
     27    // Use this function to instantiate an GridEditCutpoints instance.
     28    static void RunGridEditCutpoints(TV *tv);
     29
     30    void refreshImages();
     31    void cacheFramesAreReady();
     32    bool isValid() { return ((usedSubVideoCount > 0) && (m_gridimagemain != NULL)); };
     33    void displayCacheStatus(int level);
     34
     35    GridEditCutpoints(MythScreenStack *parent, QString name, TV *tv);
     36   ~GridEditCutpoints();
     37
     38    bool Create(void);
     39    virtual void Load(void);
     40    virtual void Init(void);
     41    virtual void Close(void);
     42
     43  protected:
     44    void displayInitialFrame();
     45
     46    void handleSelect();
     47
     48    void updateStats(bool forcerepaint = false);
     49
     50    void startSlowMotion();
     51    void stopSlowMotion();
     52
     53  protected slots:
     54    void escape();
     55    void updateSlowMotion();
     56
     57    void customEvent(QEvent *event);
     58
     59  private:
     60    bool keyPressEvent(QKeyEvent *e);
     61
     62    // seektype == -2 - cutpoint seek
     63    // seektype ==  1 - normal seek
     64    // seektype == 10 - large seek
     65    void EditHandleLeft(int seektype = 1);
     66    void EditHandleRight(int seektype = 1);
     67    void EditHandlePrevCut()    { EditHandleLeft(-2); };
     68    void EditHandleNextCut()    { EditHandleRight(-2); };
     69    void EditHandleBigJumpRew() { EditHandleLeft(10); };
     70    void EditHandleBigJumpFwd() { EditHandleRight(10); };
     71    void setSlowMotionSpeed();
     72    void refreshCutList();
     73    void refreshSlider();
     74
     75    void SetUpdating(bool active, QString text = "Updating");
     76
     77    // Private Data
     78
     79    NuppelVideoPlayer *m_player;
     80    TV *m_tv;
     81    GridEditImages *m_images;
     82
     83    int   usedSubVideoCount;
     84    myArray<MythUICutPointImage*, MAX_SUB_VIDEOS> m_gridimages;
     85    // The main Big image
     86    MythUICutPointImage* m_gridimagemain;
     87
     88    long long savedCutpoint;
     89    int       savedCutType;
     90    bool      movingCutpoint;
     91
     92    MythUIText   *m_framenum;
     93    MythUIText   *m_time;
     94    MythUIText   *m_cutind;
     95    MythUIText   *m_jumpstyle;
     96    MythUIText   *m_updatingind;
     97
     98    MythUICutPointBar     *m_slider;
     99    QTimer                *slowMotionTimer;
     100    int                    slowMotionDirection;
     101    bool                   slowMotionActive;
     102    bool                   readyForNextFrame;
     103
     104    QRect                  imageScreenArea;
     105};
     106
     107#endif
  • new file 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 "NuppelVideoPlayer.h"
     26#include "mythuicutpointimage.h"
     27
     28#define FRAME_DEBUG 0
     29#define CACHE_DEBUG 0
     30
     31#ifndef FUNCTIONLOGGER
     32#define FUNCTIONLOGGER
     33#endif
     34
     35
     36GridEditImages::GridEditImages(GridEditCutpoints *editor, NuppelVideoPlayer *player)
     37{
     38    m_editor = editor;
     39    m_player = player;
     40    usedSubVideoCount = 0;
     41
     42    lastmovewasright= true;
     43
     44    int i;
     45    for (i = stillFrames.minIndex(); i <= stillFrames.maxIndex(); i++)
     46    {
     47        stillFrames[i] = NULL;
     48        stillFramesBig[i] = NULL;
     49        cutFrames[i] = 0;
     50    }
     51
     52    memset(cutFramesCache, 0, sizeof(cutFramesCache));
     53    memset(stillFramesCache, 0, sizeof(stillFramesCache));
     54    memset(stillFramesBigCache, 0, sizeof(stillFramesBigCache));
     55    stillFrameCacheCount = 0;
     56    stillFramesCacheBase = 0;
     57
     58    // Get first frames...
     59    stillMainFrameNumber = m_player->GetFramesPlayed();
     60    if (stillMainFrameNumber <= 0)
     61        stillMainFrameNumber = 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    getImagesTimer = new QTimer(this);
     74    QObject::connect(getImagesTimer, SIGNAL(timeout()),
     75                     this,           SLOT(updateAllFrames()));
     76
     77
     78}
     79
     80GridEditImages::~GridEditImages()
     81{
     82    emptyCache();
     83    clearStillFrames();
     84    m_player->EditSeekToFrame(stillMainFrameNumber);
     85}
     86
     87QPixmap *GridEditImages::makeScaledPixmap(const QImage& qim, QSize sz)
     88{
     89    QPixmap *retval;
     90    if (qim.size() == sz)
     91    {
     92        retval = new QPixmap(sz);
     93        QPainter p(retval);
     94        p.drawImage(0, 0, qim);
     95    }
     96    else
     97    {
     98        retval = new QPixmap(sz);
     99        retval->fill(Qt::black);
     100        QPainter p(retval);
     101
     102        int tl_left = 0;
     103        int tl_top = 0;
     104        if (sz.width() > qim.width())
     105            tl_left += (sz.width() - qim.width()) / 2;
     106
     107        if (sz.height() > qim.height())
     108            tl_top += (sz.height() - qim.height()) / 2;
     109
     110//        VERBOSE(VB_GENERAL, QString("Size mismatch qim(%1, %2) != sz(%3, %4) Shift to (%5, %6)")
     111//             .arg(qim.width()).arg(qim.height())
     112//             .arg(sz.width()).arg(sz.height())
     113//             .arg(tl_left).arg(tl_top));
     114
     115        p.drawImage(tl_left, tl_top, qim);
     116    }
     117    return retval;
     118}
     119
     120void GridEditImages::getMainStillFrame()
     121{
     122    getSpecificFrame(0);
     123}
     124
     125bool GridEditImages::getFrameIndexes(int newlevel)
     126{
     127    // levels:
     128    // 0 - onscreen frames
     129    // 1 - precache frames
     130    // 2 - fill-out-the buffer frames
     131
     132    m_editor->displayCacheStatus(newlevel);
     133    if (newlevel > 2)
     134        return false;
     135
     136    // This gets the upper and lower indexes of the frames we need to get.
     137    // Note these indexes maybe negative
     138    // Negative frames are before the main frame
     139    // Frame #0 is the main frame
     140    // Positive frames are after the main frame
     141
     142    // Basic initialization
     143    // Doesn't go to absolute end because it slows down seeking
     144    // when you go 1 frame left and right
     145    frameIndexLeft       = stillFrames.minIndex() + 4;
     146    frameIndexRight      = stillFrames.maxIndex() - 4;
     147    getFutureFramesFirst = false;
     148
     149    if (newlevel == 0) // Current Display only
     150    {
     151        frameIndexLeft  = -usedSubVideoCount;
     152        frameIndexRight =  usedSubVideoCount;
     153    }
     154    else
     155    {
     156        getFutureFramesFirst = lastmovewasright;
     157
     158        if (newlevel == 1) // PreCache only
     159        {
     160            // preCacheIndexLeft and Right are indexes for the frames to start and end on
     161            frameIndexLeft  = preCacheIndexLeft;
     162            frameIndexRight = preCacheIndexRight;
     163        }
     164    }
     165
     166    // Make sure we don't fall of the front of the file
     167    if (stillMainFrameNumber + frameIndexLeft <= 0)
     168        frameIndexLeft = -(stillMainFrameNumber-1);
     169
     170    // ... or the back of the file
     171    if (frameIndexRight > (maxFrameNumber - stillMainFrameNumber))
     172        frameIndexRight = (maxFrameNumber - stillMainFrameNumber);
     173
     174#if CACHE_DEBUG
     175    VERBOSE(VB_GENERAL, QString("Getting frames from %1 to %2 for level %3")
     176            .arg(frameIndexLeft).arg(frameIndexRight).arg(newlevel));
     177#endif
     178    return true;
     179}
     180
     181bool GridEditImages::getStillFrames(int maxcount)
     182{
     183    // returns true if no more frames to get
     184
     185    // This will fill in all the missing frames in the cache
     186
     187    long long i;
     188    if (getFutureFramesFirst && frameIndexLeft < 0)
     189    {
     190        // If we're filling out the cache and the last move was to the right
     191        // grab future frames first before any past frames
     192        for (i = 1; i <= frameIndexRight; i++)
     193            if (getSpecificFrame(i))
     194                if (--maxcount == 0) return false;
     195    }
     196
     197    // grab all appropriate frames
     198
     199    for (i = frameIndexLeft; i <= frameIndexRight; i++)
     200        if (getSpecificFrame(i))
     201            if (--maxcount == 0) return false;
     202
     203    return true;
     204}
     205
     206bool GridEditImages::getSpecificFrame(long long i)
     207{
     208    // i is the index within the cache of frames
     209
     210    // If we're outside of the normal boundaries of the buffer,
     211    // see if we've precached this frame
     212    if (i < stillFrames.minIndex() || i > stillFrames.maxIndex())
     213    {
     214        // First extra cached frame
     215        if (stillFrameCacheCount == 0)
     216            stillFramesCacheBase = stillMainFrameNumber + i;
     217
     218        int tmpi;
     219        for (tmpi = 0; tmpi < stillFrameCacheCount; tmpi++)
     220        {
     221            long long tmpframe = (stillFramesCacheBase + tmpi);
     222            if (tmpframe == stillMainFrameNumber + i)
     223                return false;
     224        }
     225
     226        // Check for cache overflow
     227        if (stillFrameCacheCount >= MAX_SUB_VIDEOS)
     228        {
     229            VERBOSE(VB_GENERAL, QString("Cached too many videos. Max = %1").arg(MAX_SUB_VIDEOS));
     230            return false;
     231        }
     232
     233        tmpi = stillFrameCacheCount++;
     234
     235#if CACHE_DEBUG
     236        VERBOSE(VB_GENERAL, QString("Caching frame %1, (frm# %2, index %3)")
     237                            .arg(tmpi).arg(stillMainFrameNumber + i)
     238                            .arg(i));
     239#endif
     240
     241        getFrame(i, cutFramesCache[tmpi], stillFramesCache[tmpi], stillFramesBigCache[tmpi]);
     242        return true;
     243    }
     244    else if (!stillFrames[i])
     245    {
     246        getFrame(i, cutFrames[i], stillFrames[i], stillFramesBig[i]);
     247        return true;
     248    }
     249
     250    return false;
     251}
     252
     253void GridEditImages::getFrame(long long i,
     254        int &cutFrame,
     255        QPixmap * &stillFrame,
     256        QPixmap * &stillFrameBig)
     257{
     258    // get this frame
     259    long long targetFrame = stillMainFrameNumber + i;
     260
     261    if (!m_player->EditSeekToFrame(targetFrame))
     262    {
     263        VERBOSE(VB_GENERAL, QString("Error seeking to Frame[%1] (frame # %2)")
     264                            .arg(i).arg(targetFrame));
     265        checkMaxFrameCount();
     266
     267        stillFrameBig = new QPixmap(videoSizeMain);
     268        stillFrameBig->fill(Qt::gray);
     269
     270        stillFrame = new QPixmap(videoSizeSmall);
     271        stillFrame->fill(Qt::gray);
     272    }
     273    else
     274    {
     275        cutFrame = m_player->GetCutStatus(targetFrame);
     276        QImage normal, small;
     277        m_player->GetScreenGrabsOfCurrentFrame(normal, small);
     278
     279        stillFrameBig = makeScaledPixmap(normal, videoSizeMain);
     280        stillFrame    = makeScaledPixmap(small, videoSizeSmall);
     281
     282#if FRAME_DEBUG
     283        VERBOSE(VB_GENERAL, QString("stillFrames[%1] = %2 (%3)")
     284                .arg(i)
     285                .arg(targetFrame)
     286                .arg(cutFrame));
     287#endif
     288    }
     289}
     290
     291void GridEditImages::SetVideoInfo(int vcount, QSize sizeMain, QSize sizeSmall)
     292{
     293    usedSubVideoCount = vcount;
     294    videoSizeMain = sizeMain;
     295    videoSizeSmall = sizeSmall;
     296    SetPreCache(1);
     297
     298    m_player->SetScreenGrabSizes(videoSizeMain, videoSizeSmall);
     299
     300    // start to grab the current images
     301    getMainStillFrame();
     302    startFrameCaching();
     303}
     304
     305void GridEditImages::startFrameCaching()
     306{
     307    frameCacheLevel=0;
     308    getFrameIndexes(frameCacheLevel);
     309
     310    getImagesTimer->start(0);
     311}
     312
     313void GridEditImages::SetPreCache(long long pccount)
     314{
     315    preCacheIndexLeft  = pccount - usedSubVideoCount;
     316    preCacheIndexRight = pccount + usedSubVideoCount;
     317}
     318
     319void GridEditImages::updateAllFrames()
     320{
     321    // getStillFrames() returns 'true' on the next call after it's gotten all requested frames
     322
     323    if (getStillFrames(1))
     324    {
     325        // If we've pre-cached the next screen of frames, tell the editor about it
     326        if (frameCacheLevel == 1)
     327            m_editor->cacheFramesAreReady();
     328
     329        frameCacheLevel++;
     330        if (getFrameIndexes(frameCacheLevel))
     331            getStillFrames(1);
     332        else
     333            stopFrameCaching();
     334    }
     335    m_editor->refreshImages();
     336}
     337
     338void GridEditImages::clearStillFrames()
     339{
     340    int i;
     341    for (i = stillFrames.minIndex(); i <= stillFrames.maxIndex(); i++)
     342    {
     343        if (stillFrames[i])
     344        {
     345            delete stillFrames[i];
     346            stillFrames[i] = NULL;
     347        }
     348        if (stillFramesBig[i])
     349        {
     350            delete stillFramesBig[i];
     351            stillFramesBig[i] = NULL;
     352        }
     353        cutFrames[i] = 0;
     354    }
     355}
     356
     357bool GridEditImages::shiftStillFramesLeft(long long offset)
     358{
     359    if (offset > 2 * stillFrames.maxIndex())
     360    {
     361        // Dump all cached data and re-get it
     362        clearStillFrames();
     363    }
     364    else if (offset < 0)
     365    {
     366        VERBOSE(VB_IMPORTANT, QString("Offset (%1) < 0").arg(offset));
     367        // Dump all cached data and re-get it
     368        clearStillFrames();
     369        offset = 0;
     370    }
     371    else if (offset != 0)
     372    {
     373        // Shift backwards in the stream by offset
     374
     375        // All frames will actually shift to the right.
     376        // frame 'n' will become frame 'n+1'
     377        // frame stillFrameMinus[1] will become mainframe
     378        // frame stillFramePlus[max] will drop off
     379
     380        // shove extra frames into the excess space above usedSubVideos
     381
     382        if (offset >= stillMainFrameNumber)
     383            offset = (stillMainFrameNumber-1);
     384
     385        //    printStillFrameStats("Before SL");
     386        int i,j;
     387        int minIndex = stillFrames.minIndex();
     388        int maxIndex = stillFrames.maxIndex();
     389        for (i = 0; i < offset; i++)
     390        {
     391
     392            if (stillFrames[maxIndex])
     393            {
     394                delete stillFrames[maxIndex];
     395                delete stillFramesBig[maxIndex];
     396            }
     397
     398            for (j = maxIndex; j > minIndex; j--) {
     399                stillFrames[j]    = stillFrames[j-1];
     400                stillFramesBig[j] = stillFramesBig[j-1];
     401                cutFrames[j]      = cutFrames[j-1];
     402            }
     403
     404             stillFrames[minIndex]    = NULL;
     405             stillFramesBig[minIndex] = NULL;
     406             cutFrames[minIndex]      = 0;
     407        }
     408
     409        //   printStillFrameStats("After SL");
     410
     411    }
     412
     413    stillMainFrameNumber -= offset;
     414    if (stillMainFrameNumber < 1)
     415        stillMainFrameNumber = 1;
     416
     417    emptyCache();
     418
     419    return (stillFramesBig[0] != NULL);
     420}
     421
     422bool GridEditImages::shiftStillFramesRight(long long offset)
     423{
     424    //VERBOSE(VB_GENERAL, QString("Offset =  %1").arg(offset));
     425    if (offset > 2 * stillFrames.maxIndex())
     426    {
     427        // Dump all cached data and re-get it
     428        clearStillFrames();
     429    }
     430    else if (offset < 0)
     431    {
     432        VERBOSE(VB_IMPORTANT, QString("Offset (%1) < 0").arg(offset));
     433        // Dump all cached data and re-get it
     434        clearStillFrames();
     435        offset = 0;
     436    }
     437    else if (offset != 0)
     438    {
     439
     440        // Shift forwards in the stream by offset
     441
     442        // All frames will actually shift to the left.
     443        // frame 'n' will become frame 'n-1'
     444        // frame stillFramePlus[1] will become mainframe
     445        // frame stillFrameMinus[max] will drop off
     446
     447        // shove extra frames into the excess space above usedSubVideos
     448
     449        if (stillMainFrameNumber + offset > maxFrameNumber)
     450        {
     451            offset = (maxFrameNumber - stillMainFrameNumber);
     452            VERBOSE(VB_GENERAL, QString("new Offset =  %1").arg(offset));
     453        }
     454        //printStillFrameStats("Before SR");
     455
     456        int i,j;
     457        int minIndex = stillFrames.minIndex();
     458        int maxIndex = stillFrames.maxIndex();
     459
     460        for (i = 0; i < offset; i++)
     461        {
     462            if (stillFrames[minIndex])
     463            {
     464                delete stillFrames[minIndex];
     465                delete stillFramesBig[minIndex];
     466            }
     467
     468            for (j = minIndex; j < maxIndex; j++) {
     469                stillFrames[j]    = stillFrames[j+1];
     470                stillFramesBig[j] = stillFramesBig[j+1];
     471                cutFrames[j]      = cutFrames[j+1];
     472            }
     473
     474             stillFrames[maxIndex]    = NULL;
     475             stillFramesBig[maxIndex] = NULL;
     476             cutFrames[maxIndex]      = 0;
     477        }
     478
     479        //printStillFrameStats("After SR");
     480
     481    }
     482    stillMainFrameNumber += offset;
     483    if (stillMainFrameNumber > maxFrameNumber )
     484        stillMainFrameNumber = maxFrameNumber;
     485
     486    emptyCache();
     487
     488    return (stillFramesBig[0] != NULL);
     489}
     490
     491void GridEditImages::emptyCache()
     492{
     493#if CACHE_DEBUG
     494    if (stillFrameCacheCount > 0)
     495    {
     496        long long minindex = (stillFramesCacheBase - stillMainFrameNumber);
     497        long long maxindex = (stillFramesCacheBase+stillFrameCacheCount-1) - stillMainFrameNumber;
     498        VERBOSE(VB_GENERAL, QString("emptying %1 frames (%2 - %3) into [%4] - [%5] ")
     499                            .arg(stillFrameCacheCount)
     500                            .arg(stillFramesCacheBase)
     501                            .arg(stillFramesCacheBase+(stillFrameCacheCount-1))
     502                            .arg(minindex).arg(maxindex));
     503    }
     504#endif
     505    int i;
     506    for (i = 0; i < stillFrameCacheCount; i++)
     507    {
     508        long long tmpframe = stillFramesCacheBase + i;
     509        long long frameIndex = tmpframe - stillMainFrameNumber;
     510
     511        // frameIndex is the index matching stillFramesCache[i] to stillFrames[frameIndex]
     512        // If frameIndex is within the stillFrames range, then use this frame
     513        // otherwise delete it
     514
     515        if (frameIndex >= stillFrames.minIndex() && frameIndex <= stillFrames.maxIndex())
     516        {
     517            // move cache data into normal arrays.
     518            if (stillFrames[frameIndex])
     519            {
     520                VERBOSE(VB_GENERAL, QString("Frame %1 index %2 already exists")
     521                                    .arg(tmpframe).arg(frameIndex));
     522                // Can't move it -- the destination exists
     523                delete stillFramesCache[i];
     524                delete stillFramesBigCache[i];
     525            }
     526            else
     527            {
     528                cutFrames[frameIndex] = cutFramesCache[i];
     529                stillFrames[frameIndex] = stillFramesCache[i];
     530                stillFramesBig[frameIndex] = stillFramesBigCache[i];
     531            }
     532        }
     533        else
     534        {
     535            delete stillFramesCache[i];
     536            delete stillFramesBigCache[i];
     537        }
     538        cutFramesCache[i]=0;
     539        stillFramesCache[i] = NULL;
     540        stillFramesBigCache[i] = NULL;
     541    }
     542    stillFrameCacheCount = 0;
     543}
     544
     545void GridEditImages::printStillFrameStats(QString caption)
     546{
     547    int i;
     548    // Debug info for frame cache
     549    QString foundframes= caption + " Found Frames: ";
     550
     551    for (i = stillFrames.minIndex(); i <= stillFrames.maxIndex(); i++)
     552        if (stillFrames[i])
     553            foundframes += QString("%1 ").arg(i);
     554
     555    VERBOSE(VB_GENERAL, foundframes);
     556}
     557
     558void GridEditImages::refreshCutList(MythUICutPointImage* gridimagemain,
     559                                    myArray<MythUICutPointImage*, MAX_SUB_VIDEOS> &gridimages)
     560{
     561    int i;
     562    for (i = stillFrames.minIndex(); i <= stillFrames.maxIndex(); i++)
     563    {
     564        if (stillFrames[i])
     565        {
     566            cutFrames[i] = m_player->GetCutStatus(stillMainFrameNumber+i);
     567            if (gridimages[i])
     568                gridimages[i]->setCutStatus(cutFrames[i]);
     569        }
     570    }
     571
     572    gridimagemain->setCutStatus(cutFrames[0]);
     573}
     574
     575bool GridEditImages::refreshImages(MythUICutPointImage* gridimagemain,
     576                                   myArray<MythUICutPointImage*, MAX_SUB_VIDEOS> &gridimages,
     577                                   bool mainFrameOnly)
     578{
     579FUNCTIONLOGGER;
     580//    VERBOSE(VB_GENERAL, "Start");
     581    bool alldone = true;
     582    if (!stillFramesBig[0])
     583        VERBOSE(VB_GENERAL, QString("Null Big Main frame %1").arg(stillMainFrameNumber));
     584    gridimagemain->SetPixmap(stillFramesBig[0],
     585                             stillMainFrameNumber,
     586                             cutFrames[0]);
     587
     588    if (mainFrameOnly && gridimages[0])
     589        gridimages[0]->SetPixmap(stillFrames[0],
     590                                 stillMainFrameNumber,
     591                                 cutFrames[0]);
     592
     593    if (!mainFrameOnly)
     594    {
     595        int i;
     596        for (i = -usedSubVideoCount; i <= usedSubVideoCount; i++)
     597        {
     598            if (stillFrames[i] == NULL)
     599                alldone = false;
     600            if (gridimages[i])
     601                gridimages[i]->SetPixmap(stillFrames[i],
     602                                         (stillMainFrameNumber + i),
     603                                         cutFrames[i]);
     604        }
     605    }
     606
     607//    VERBOSE(VB_GENERAL, "Finish");
     608    return alldone;
     609}
     610
     611
     612// Back up x frames
     613void GridEditImages::SeekLeft(long long seekamount, bool cutpointseek)
     614{
     615    lastmovewasright = false;
     616    stopFrameCaching();
     617    m_editor->displayCacheStatus(0);
     618
     619    if (cutpointseek)
     620        seekamount = m_player->CalcCutPointSeek(stillMainFrameNumber, false);
     621
     622    //VERBOSE(VB_GENERAL, QString("SeekLeft %1, cutpoint = %2").arg(seekamount).arg(cutpointseek));
     623
     624    if (cutpointseek)
     625        SetPreCache(-1);
     626    else
     627        SetPreCache(-seekamount);
     628
     629    if (!shiftStillFramesLeft(seekamount))
     630    {
     631        //VERBOSE(VB_GENERAL, QString("shiftStillFramesLeft(%1) == false")
     632        //                           .arg(seekamount));
     633        // Need to grab the main frame
     634
     635        getMainStillFrame();
     636    }
     637
     638    startFrameCaching();
     639}
     640
     641void GridEditImages::SeekRight(long long seekamount, bool cutpointseek)
     642{
     643    lastmovewasright = true;
     644    stopFrameCaching();
     645    m_editor->displayCacheStatus(0);
     646
     647    if (cutpointseek)
     648        seekamount = m_player->CalcCutPointSeek(stillMainFrameNumber, true);
     649
     650    //VERBOSE(VB_GENERAL, QString("SeekRight %1, cutpoint = %2").arg(seekamount).arg(cutpointseek));
     651
     652    if (cutpointseek)
     653        SetPreCache(1);
     654    else
     655        SetPreCache(seekamount);
     656
     657    if (!shiftStillFramesRight(seekamount))
     658    {
     659        //VERBOSE(VB_GENERAL, QString("shiftStillFramesLeft(%1) == false")
     660        //                           .arg(seekamount));
     661        // Need to grab the main frame
     662
     663        getMainStillFrame();
     664    }
     665
     666    startFrameCaching();
     667}
     668
     669void GridEditImages::checkMaxFrameCount()
     670{
     671    long long tfc = m_player->GetTotalFrameCount();
     672    if (tfc != maxFrameNumberNVP)
     673    {
     674       VERBOSE(VB_GENERAL, QString("Updating: tfc %1, mfn %2, mfnNVP %3")
     675            .arg(tfc).arg(maxFrameNumber).arg(maxFrameNumberNVP));
     676        // Check to see if things changed
     677        maxFrameNumber = tfc;
     678        maxFrameNumberNVP = tfc;
     679    }
     680}
     681
     682FrameStats GridEditImages::GetMainFrameStats()
     683{
     684    FrameStats result;
     685
     686    result.frameNumber = stillMainFrameNumber;
     687    result.cutInd  = cutFrames[0];
     688    result.maxFrameNumber = maxFrameNumber;
     689
     690    return result;
     691}
     692
  • new file mythbuild/mythtv/libs/libmythtv/grideditimages.h

    - +  
     1// -*- Mode: c++ -*-
     2#ifndef GRIDEDITIMAGES_H_
     3#define GRIDEDITIMAGES_H_
     4
     5#include <qstring.h>
     6
     7#include "libmyth/mythwidgets.h"
     8
     9using namespace std;
     10
     11class QTimer;
     12class NuppelVideoPlayer;
     13class GridEditCutpoints;
     14class MythUICutPointImage;
     15
     16#define MAX_SUB_VIDEOS 25
     17
     18// Simple class to allow array indexing from -MAX_SUB_VIDEOS to +MAX_SUB_VIDEOS
     19template<class T, int COUNT> class myArray
     20{
     21    public:
     22        myArray() { memset(_array, 0, sizeof(_array));};
     23
     24        T& operator[](int i) { return _array[COUNT+i]; };
     25        int minIndex() const { return -COUNT; };
     26        int maxIndex() const { return  COUNT; };
     27
     28    private:
     29        T _array[2*COUNT+1];
     30};
     31
     32class FrameStats
     33{
     34    public:
     35        long long frameNumber;
     36        int cutInd;
     37        long long maxFrameNumber;
     38};
     39
     40class MPUBLIC GridEditImages : public QObject
     41{
     42    Q_OBJECT
     43
     44    public:
     45        GridEditImages(GridEditCutpoints *er, NuppelVideoPlayer *player);
     46        ~GridEditImages();
     47
     48        void refreshCutList(MythUICutPointImage* gridimagemain,
     49                            myArray<MythUICutPointImage*, MAX_SUB_VIDEOS> &gridimages);
     50
     51        // return true if anything changed
     52        bool refreshImages(MythUICutPointImage* gridimagemain,
     53                           myArray<MythUICutPointImage*, MAX_SUB_VIDEOS> &gridimages,
     54                           bool mainFrameOnly);
     55
     56        void SeekLeft(long long seekamount, bool cutpointseek = false);
     57        void SeekRight(long long seekamount, bool cutpointseek = false);
     58
     59        FrameStats GetMainFrameStats();
     60        long long GetCurrentFrameNumber() const { return stillMainFrameNumber; }
     61        long long GetMaxFrameNumber() const { return maxFrameNumber; }
     62
     63        void SetVideoInfo(int vcount, QSize sizeMain, QSize sizeSmall);
     64
     65    protected slots:
     66        void updateAllFrames();
     67
     68    private:
     69        // Private functions
     70        void clearStillFrames();
     71        void printStillFrameStats(QString caption);
     72        void checkMaxFrameCount();
     73
     74        // 'newlevel' paramter for getStillFrames():
     75        //  0 = get on screen Frames only
     76        //  1 = get preCache Frames only
     77        //  2 = get any necessary frames
     78        //  3 = done
     79        bool getFrameIndexes(int newlevel);
     80
     81        bool getStillFrames(int maxcount = 1000);
     82        void getMainStillFrame();
     83        bool getSpecificFrame(long long frameindex);
     84        void getFrame(long long i, int &cutFrame, QPixmap* &stillFrame, QPixmap* &stillFrameBig);
     85        void emptyCache();
     86
     87        // return true if anything changed
     88        bool shiftStillFramesLeft(long long offset);
     89        bool shiftStillFramesRight(long long offset);
     90        void startFrameCaching();
     91        void stopFrameCaching() { getImagesTimer->stop(); };
     92
     93        QPixmap *makeScaledPixmap(const QImage& qim, QSize sz);
     94
     95        void SetPreCache(long long pccount);
     96
     97        // Private data
     98        // These frames are in the cutlist
     99        // 0 == not cut
     100        // 1 == cut
     101        // 2 == cutpoint (cut left)
     102        // 3 == cutpoint (cut right)
     103        myArray<int, MAX_SUB_VIDEOS> cutFrames;
     104        myArray<QPixmap *, MAX_SUB_VIDEOS> stillFrames;
     105        myArray<QPixmap *, MAX_SUB_VIDEOS> stillFramesBig;
     106
     107        // pre-caching large seek amounts
     108        // (i.e. while seeking +5 seconds, these are places to store the to-be-displayed data)
     109
     110        int       cutFramesCache[MAX_SUB_VIDEOS];
     111        QPixmap  *stillFramesCache[MAX_SUB_VIDEOS];
     112        QPixmap  *stillFramesBigCache[MAX_SUB_VIDEOS];
     113        int       stillFrameCacheCount;
     114        long long stillFramesCacheBase; // Frame # for index[0]
     115
     116        QSize     videoSizeMain;
     117        QSize     videoSizeSmall;
     118        int       usedSubVideoCount;
     119        long long preCacheIndexLeft;
     120        long long preCacheIndexRight;
     121        long long frameIndexLeft;
     122        long long frameIndexRight;
     123        bool      lastmovewasright;
     124        bool      getFutureFramesFirst;
     125        int       frameCacheLevel;
     126
     127        long long stillMainFrameNumber; // frame number for big still picture
     128        long long currentFrameNumberNVP; // frame number the NVP should be on
     129        long long maxFrameNumber;       // max frame number override for NVP
     130        long long maxFrameNumberNVP;    // Original NVP number
     131
     132        GridEditCutpoints *m_editor;
     133        NuppelVideoPlayer *m_player;
     134
     135        QTimer            *getImagesTimer;
     136
     137};
     138
     139#endif
  • mythtv/libs/libmythtv/libmythtv.pro

    old new using_frontend {  
    336336    SOURCES += ttfont.cpp
    337337    HEADERS += DetectLetterbox.h
    338338    SOURCES += DetectLetterbox.cpp
     339    HEADERS += grideditcutpoints.h      grideditimages.h
     340    SOURCES += grideditcutpoints.cpp    grideditimages.cpp
    339341
    340342    using_mheg {
    341343        # DSMCC stuff
  • mythtv/libs/libmythtv/tv_play.cpp

    old new using namespace std;  
    2828#include "remoteencoder.h"
    2929#include "remoteutil.h"
    3030#include "tvremoteutil.h"
     31#include "grideditcutpoints.h"
    3132#include "NuppelVideoPlayer.h"
    3233#include "DetectLetterbox.h"
    3334#include "programinfo.h"
    using namespace std;  
    7273#define LOC_WARN QString("TV Warning: ")
    7374#define LOC_ERR  QString("TV Error: ")
    7475
     76#ifndef FUNCTIONLOGGER
     77#define FUNCTIONLOGGER
     78#endif
     79
    7580#define GetPlayer(X,Y) GetPlayerHaveLock(X, Y, __FILE__ , __LINE__)
    7681#define GetOSDLock(X) GetOSDL(X, __FILE__, __LINE__)
    7782
    EMBEDRETURNVOIDEPG TV::RunProgramGuidePt  
    135140 */
    136141EMBEDRETURNVOIDFINDER TV::RunProgramFinderPtr = NULL;
    137142
     143/**
     144 * \brief function pointer for RunGridEditCutpoints in grideditcutpoints.cpp
     145 */
     146EMBEDRETURNVOIDGEC TV::RunGridEditCutpointsPtr = NULL;
    138147
    139148/**
    140149 * \brief If any cards are configured, return the number.
    void TV::SetFuncPtr(const char *string,  
    451460        RunProgramFinderPtr = (EMBEDRETURNVOIDFINDER)lptr;
    452461    else if (name == "scheduleeditor")
    453462        RunScheduleEditorPtr = (EMBEDRETURNVOIDSCHEDIT)lptr;
     463    else if (name == "grideditcutpoints")
     464        RunGridEditCutpointsPtr = (EMBEDRETURNVOIDGEC)lptr;
     465    else
     466        VERBOSE(VB_IMPORTANT, QString("Unknown Function specified: %1").arg(string));
    454467}
    455468
    456469void TV::InitKeys(void)
    void TV::InitKeys(void)  
    726739            "Jump back 10x the normal amount"), ",,<");
    727740    REG_KEY("TV Editing", "BIGJUMPFWD",  QT_TRANSLATE_NOOP("MythControls",
    728741            "Jump forward 10x the normal amount"), ">,.");
     742    REG_KEY("TV Editing", "EDIT", "Exit out of Edit Mode", "E");
     743    REG_KEY("TV Editing", "SLOWMO", "Slow Motion Play", "Ctrl+P");
     744    REG_KEY("TV Editing", "PAUSE", "Pause", "P");
    729745
    730746    /* Teletext keys */
    731747    REG_KEY("Teletext Menu", "NEXTPAGE",    QT_TRANSLATE_NOOP("MythControls",
    TV::TV(void)  
    871887      pseudoChangeChanTimerId(0),   speedChangeTimerId(0),
    872888      errorRecoveryTimerId(0),      exitPlayerTimerId(0)
    873889{
    874     VERBOSE(VB_PLAYBACK, LOC + "ctor -- begin");
     890    //VERBOSE(VB_PLAYBACK, LOC + "ctor -- begin");
    875891    ctorTime.start();
    876892
    877893    setObjectName("TV");
    TV::TV(void)  
    9931009    player.push_back(new PlayerContext(kPlayerInUseID));
    9941010    playerActive = 0;
    9951011    playerLock.unlock();
    996     VERBOSE(VB_PLAYBACK, LOC + "ctor -- end");
     1012//    VERBOSE(VB_PLAYBACK, LOC + "ctor -- end");
    9971013}
    9981014
    9991015/** \fn TV::Init(bool)
    void TV::ProcessKeypress(PlayerContext *  
    35633579    if (editmode)
    35643580    {
    35653581        actx->LockDeleteNVP(__FILE__, __LINE__);
     3582        if (actx->nvp && actx->nvp->GetHideEdits())
     3583        {
     3584            actx->UnlockDeleteNVP(__FILE__, __LINE__);
     3585            return;
     3586        }
    35663587        if (actx->nvp && !actx->nvp->DoKeypress(e))
    35673588            editmode = actx->nvp->GetEditMode();
    35683589        actx->UnlockDeleteNVP(__FILE__, __LINE__);
    bool TV::ToggleHandleAction(PlayerContex  
    45414562        if (islivetv)
    45424563            StartChannelEditMode(ctx);
    45434564        else if (!isDVD)
     4565            //DoEditRecordingGrid();
    45444566            StartProgramEditMode(ctx);
    45454567    }
    45464568    else
    void TV::StopEmbedding(PlayerContext *ct  
    80228044
    80238045void TV::DrawUnusedRects(void)
    80248046{
    8025     VERBOSE(VB_PLAYBACK, LOC + "DrawUnusedRects() -- begin");
     8047//    VERBOSE(VB_PLAYBACK, LOC + "DrawUnusedRects() -- begin");
    80268048
    80278049    PlayerContext *mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
    80288050    for (uint i = 0; mctx && (i < player.size()); i++)
    void TV::DrawUnusedRects(void)  
    80358057    }
    80368058    ReturnPlayerLock(mctx);
    80378059
    8038     VERBOSE(VB_PLAYBACK, LOC + "DrawUnusedRects() -- end");
     8060//    VERBOSE(VB_PLAYBACK, LOC + "DrawUnusedRects() -- end");
    80398061}
    80408062
    80418063vector<bool> TV::DoSetPauseState(PlayerContext *lctx, const vector<bool> &pause)
    vector<bool> TV::DoSetPauseState(PlayerC  
    80608082    return was_paused;
    80618083}
    80628084
     8085void TV::DoEditRecordingGrid()
     8086{
     8087FUNCTIONLOGGER;
     8088    PlayerContext *actx = GetPlayerReadLock(-1, __FILE__, __LINE__);
     8089
     8090    actx->LockPlayingInfo(__FILE__, __LINE__);
     8091    if (!actx->playingInfo)
     8092    {
     8093        VERBOSE(VB_IMPORTANT,
     8094                LOC_ERR + "no active ctx playingInfo.");
     8095        actx->UnlockPlayingInfo(__FILE__, __LINE__);
     8096        ReturnPlayerLock(actx);
     8097        return;
     8098    }
     8099    actx->UnlockPlayingInfo(__FILE__, __LINE__);
     8100
     8101    // Resize window to the MythTV GUI size
     8102    PlayerContext *mctx = GetPlayer(actx,0);
     8103    mctx->LockDeleteNVP(__FILE__, __LINE__);
     8104    if (mctx->nvp && mctx->nvp->getVideoOutput())
     8105        mctx->nvp->getVideoOutput()->ResizeForGui();
     8106    mctx->UnlockDeleteNVP(__FILE__, __LINE__);
     8107    ReturnPlayerLock(actx);
     8108
     8109    MythMainWindow *mwnd = gContext->GetMainWindow();
     8110    if (!db_use_gui_size_for_tv || !db_use_fixed_size)
     8111    {
     8112        mwnd->setGeometry(saved_gui_bounds.left(), saved_gui_bounds.top(),
     8113                          saved_gui_bounds.width(), saved_gui_bounds.height());
     8114        mwnd->setFixedSize(saved_gui_bounds.size());
     8115    }
     8116
     8117    // Actually show the pop-up UI
     8118
     8119    RunGridEditCutpointsPtr(this);
     8120    ignoreKeyPresses = true;
     8121
     8122    //we are embedding in a mythui window so show the gui paint window again
     8123    GetMythMainWindow()->SetDrawEnabled(true);
     8124    GetMythMainWindow()->GetPaintWindow()->show();
     8125}
     8126
    80638127void TV::DoEditSchedule(int editType)
    80648128{
    80658129    if ((editType == kScheduleProgramGuide  && !RunProgramGuidePtr) ||
    void TV::EditSchedule(const PlayerContex  
    81918255    qApp->postEvent(gContext->GetMainWindow(), me);
    81928256}
    81938257
     8258void TV::ShowEditRecordingGrid()
     8259{
     8260FUNCTIONLOGGER;
     8261     // post the request to the main UI thread
     8262     // it will be caught in eventFilter and processed as CustomEvent
     8263     // this will create the program guide window (widget)
     8264     // on the main thread and avoid a deadlock on Win32
     8265
     8266     VERBOSE(VB_GENERAL, "Starting Grid Edit");
     8267     QString message = QString("START_EDIT");
     8268     MythEvent* me = new MythEvent(message);
     8269     qApp->postEvent(gContext->GetMainWindow(), me);
     8270}
     8271
    81948272void TV::ChangeVolume(PlayerContext *ctx, bool up)
    81958273{
    81968274    ctx->LockDeleteNVP(__FILE__, __LINE__);
    void TV::customEvent(QEvent *e)  
    88838961    }
    88848962
    88858963    if (message.left(11) == "EPG_EXITING" ||
     8964        message.left(16) == "GRIDEDIT_EXITING" ||
    88868965        message.left(18) == "PROGFINDER_EXITING" ||
    88878966        message.left(21) == "VIEWSCHEDULED_EXITING" ||
    88888967        message.left(19)   == "PLAYBACKBOX_EXITING" ||
    void TV::customEvent(QEvent *e)  
    89399018
    89409019    }
    89419020
     9021    if (message.left(10) == "START_EDIT")
     9022    {
     9023        DoEditRecordingGrid();
     9024    }
     9025
    89429026    if (message.left(14) == "COMMFLAG_START")
    89439027    {
    89449028        QString evchanid = QString::null;
    void TV::TreeMenuSelected(OSDListTreeIte  
    1017210256        }
    1017310257        else if (action == "EDIT")
    1017410258            StartProgramEditMode(actx);
     10259            //DoEditRecordingGrid();
    1017510260        else if (action == "TOGGLEAUTOEXPIRE")
    1017610261            ToggleAutoExpire(actx);
    1017710262        else if (action.left(14) == "TOGGLECOMMSKIP")
  • mythtv/libs/libmythtv/tv_play.h

    old new typedef void (*EMBEDRETURNVOID) (void *,  
    6363typedef void (*EMBEDRETURNVOIDEPG) (uint, const QString &, TV *, bool, bool, int);
    6464typedef void (*EMBEDRETURNVOIDFINDER) (TV *, bool, bool);
    6565typedef void (*EMBEDRETURNVOIDSCHEDIT) (const ProgramInfo *, void *);
     66typedef void (*EMBEDRETURNVOIDGEC) (TV *);
    6667
    6768// Locking order
    6869//
    class MPUBLIC TV : public QThread  
    166167    friend class PlaybackBox;
    167168    friend class GuideGrid;
    168169    friend class TvPlayWindow;
     170    friend class GridEditCutpoints;
    169171
    170172    Q_OBJECT
    171173  public:
    class MPUBLIC TV : public QThread  
    213215    void setInPlayList(bool setting) { inPlaylist = setting; }
    214216    void setUnderNetworkControl(bool setting) { underNetworkControl = setting; }
    215217
     218    void ShowEditRecordingGrid();
    216219    void ShowNoRecorderDialog(const PlayerContext*,
    217220                              NoRecorderMsg msgType = kNoRecorders);
    218221    void FinishRecording(int player_idx); ///< Finishes player's recording
    class MPUBLIC TV : public QThread  
    298301    void TreeMenuSelected(OSDListTreeItemSelectedEvent *e);
    299302
    300303    void DoEditSchedule(int editType = kScheduleProgramGuide);
     304    void DoEditRecordingGrid();
    301305
    302306    virtual void run(void);
    303307    void TVEventThreadChecks(void);
    class MPUBLIC TV : public QThread  
    312316    static EMBEDRETURNVOIDEPG RunProgramGuidePtr;
    313317    static EMBEDRETURNVOIDFINDER RunProgramFinderPtr;
    314318    static EMBEDRETURNVOIDSCHEDIT RunScheduleEditorPtr;
     319    static EMBEDRETURNVOIDGEC RunGridEditCutpointsPtr;
    315320
    316321  private:
    317322    void SetActive(PlayerContext *lctx, int index, bool osd_msg);
  • mythtv/themes/MythCenter-wide/recordings-ui.xml

    old new  
    10851085        </buttonlist>
    10861086    </window>
    10871087
     1088    <window name="grideditcutpoints">
     1089        <font name="white_medium" face="DejaVu Sans">
     1090           <color>#FFFFFF</color>
     1091           <size>20</size>
     1092        </font>
     1093
     1094        <font name="yellow_medium" face="DejaVu Sans">
     1095            <color>#FFFF00</color>
     1096            <size>20</size>
     1097        </font>
     1098
     1099                        <area>0,0,1280,720</area>
     1100
     1101                        <textarea name="timecap" align="right">
     1102                                <area>0,350,120,40</area>
     1103                                <font>white_medium</font>
     1104                                <value>Time:</value>
     1105                        </textarea>
     1106
     1107                        <textarea name="time" align="left">
     1108                                <area>125,350,195,40</area>
     1109                                <font>white_medium</font>
     1110                        </textarea>
     1111
     1112                        <textarea name="framenumcap" align="right">
     1113                                <area>0,400,120,40</area>
     1114                                <font>white_medium</font>
     1115                                <value>Frame:</value>
     1116                        </textarea>
     1117
     1118                        <textarea name="framenum" align="left" >
     1119                                <area>125,400,195,40</area>
     1120                                <font>white_medium</font>
     1121                        </textarea>
     1122
     1123                        <textarea name="cutind" align="left" >
     1124                                <area>120,450,195,40</area>
     1125                                <font>white_medium</font>
     1126                        </textarea>
     1127
     1128                        <textarea name="updatingind" align="center" >
     1129                                <area>20,550,210,40</area>
     1130                                <font>yellow_medium</font>
     1131                                <value>Updating</value>
     1132                        </textarea>
     1133
     1134                        <textarea name="jumpstylecap" align="right" >
     1135                                <area>0,500,120,40</area>
     1136                                <font>white_medium</font>
     1137                                <value>Skip:</value>
     1138                        </textarea>
     1139
     1140                        <textarea name="jumpstyle" align="left" >
     1141                                <area>125,500,195,40</area>
     1142                                <font>white_medium</font>
     1143                        </textarea>
     1144
     1145                        <cutpointbar name="positionbar">
     1146                               <area>338,554,908,48</area>
     1147                               <fillcolor>#202020</fillcolor>
     1148                               <cutcolor>#7f0000</cutcolor>
     1149                               <incutcolor>#7f7f00</incutcolor>
     1150                               <cutpointcolor>#FFFF00</cutpointcolor>
     1151                               <positioncolor>#FFFFFF</positioncolor>
     1152                        </cutpointbar>
     1153
     1154
     1155                        <cutpointimage name="mainvideo">
     1156                                <area>328,24,928,522</area>
     1157                                <outlinecolor>#202020</outlinecolor>
     1158                                <cutcolor>#7f0000</cutcolor>
     1159                                <cutpointcolor>#afaf00</cutpointcolor>
     1160                        </cutpointimage>
     1161
     1162                        <cutpointimage name="videom3" from="mainvideo">
     1163                                <area>6,614,176,99</area>
     1164                        </cutpointimage>
     1165
     1166                        <cutpointimage name="videom2" from="mainvideo">
     1167                                <area>188,614,176,99</area>
     1168                        </cutpointimage>
     1169
     1170                        <cutpointimage name="videom1" from="mainvideo">
     1171                                <area>370,614,176,99</area>
     1172                        </cutpointimage>
     1173
     1174                        <cutpointimage name="video0" from="mainvideo">
     1175                                <area>552,614,176,99</area>
     1176                                <highlightcolor>#ffffff</highlightcolor>
     1177                        </cutpointimage>
     1178
     1179                        <cutpointimage name="videop1" from="mainvideo">
     1180                                <area>734,614,176,99</area>
     1181                        </cutpointimage>
     1182
     1183                        <cutpointimage name="videop2" from="mainvideo">
     1184                                <area>916,614,176,99</area>
     1185                        </cutpointimage>
     1186
     1187                        <cutpointimage name="videop3" from="mainvideo">
     1188                                <area>1098,614,176,99</area>
     1189                        </cutpointimage>
     1190
     1191        </window>
     1192
    10881193</mythuitheme>
  • mythtv/programs/mythfrontend/main.cpp

    old new using namespace std;  
    6969#include "mythdb.h"
    7070#include "backendconnectionmanager.h"
    7171
     72#include "grideditcutpoints.h"
     73
    7274static ExitPrompter   *exitPopup = NULL;
    7375static MythThemedMenu *menu;
    7476static MythThemeBase  *themeBase = NULL;
    void InitJumpPoints(void)  
    965967    TV::SetFuncPtr("programguide", (void *)GuideGrid::RunProgramGuide);
    966968    TV::SetFuncPtr("programfinder", (void *)RunProgramFinder);
    967969    TV::SetFuncPtr("scheduleeditor", (void *)ScheduleEditor::RunScheduleEditor);
     970    TV::SetFuncPtr("grideditcutpoints", (void *)GridEditCutpoints::RunGridEditCutpoints);
    968971}
    969972
    970973
  • mythtv/programs/mythfrontend/guidegrid.cpp

    old new void GuideGrid::RunProgramGuide(uint cha  
    208208        mainStack->AddScreen(gg, (player == NULL));
    209209    else
    210210        delete gg;
     211
     212    QString depth = mainStack->GetLocation(true);
     213
     214    VERBOSE(VB_GENERAL, QString("Screens: %1").arg(depth));
    211215}
    212216
    213217GuideGrid::GuideGrid(MythScreenStack *parent,
  • mythtv/libs/libmythui/mythscreenstack.cpp

    old new  
    44#include "mythpainter.h"
    55#include "mythevent.h"
    66
     7#include "mythverbose.h"
     8
    79#include <cassert>
    810
    911#include <QCoreApplication>
    void MythScreenStack::AddScreen(MythScre  
    7577    screen->aboutToShow();
    7678
    7779    m_topScreen = screen;
     80
     81//    reinterpret_cast<MythMainWindow *>(parent())->ShowAllStacksBut(objectName());
     82//    QString loc = GetLocation(true);
     83//    VERBOSE(VB_GENERAL, QString("Location ('%1') = %2").arg(objectName()).arg(loc));
    7884}
    7985
    8086void MythScreenStack::PopScreen(bool allowFade,
    void MythScreenStack::PopScreen(MythScre  
    8995    if (!screen || screen->IsDeleting())
    9096        return;
    9197
     98    QString popname = screen->objectName();
     99
    92100    screen->aboutToHide();
    93101
    94102    if (m_Children.isEmpty())
    void MythScreenStack::PopScreen(MythScre  
    160168        if (mainscreen)
    161169            mainscreen->SetRedraw();
    162170    }
     171
     172//    QString loc = GetLocation(true);
     173//    VERBOSE(VB_GENERAL, QString("Location ('%1') = %2 popped %3").arg(objectName()).arg(loc).arg(popname));
     174//    reinterpret_cast<MythMainWindow *>(parent())->ShowAllStacksBut(objectName());
    163175}
    164176
    165177MythScreenType *MythScreenStack::GetTopScreen(void) const
  • mythtv/libs/libmythdb/mythobservable.cpp

    old new  
    33#include <QMutex>
    44
    55#include "mythobservable.h"
     6#include "mythverbose.h"
    67
    78/** \class MythObservable
    89 *  \brief Superclass for making an object have a set of listeners
    void MythObservable::addListener(QObject  
    4344{
    4445    if (listener)
    4546    {
     47        VERBOSE(VB_GENERAL, QString("Adding '%1'").arg(listener->objectName()));
    4648        QMutexLocker locker(m_lock);
    4749        m_listeners.insert(listener);
    4850    }
     51//    ShowListeners();
    4952}
    5053
    5154
    void MythObservable::removeListener(QObj  
    6063{
    6164    if (listener)
    6265    {
     66        VERBOSE(VB_GENERAL, QString("Removing '%1'").arg(listener->objectName()));
    6367        QMutexLocker locker(m_lock);
    6468        m_listeners.remove(listener);
    6569        QCoreApplication::removePostedEvents(listener);
    6670    }
     71//    ShowListeners();
     72}
     73
     74void MythObservable::ShowListeners()
     75{
     76    QString output="";
     77    {
     78        QMutexLocker locker(m_lock);
     79
     80        QSet<QObject*>::const_iterator it = m_listeners.begin();
     81        for (; it != m_listeners.end() ; ++it)
     82        {
     83            QString oname = (*it)->objectName();
     84            if (oname != "")
     85                output = output + oname + ", ";
     86            else
     87                output = output + "<none>, ";
     88        }
     89    }
     90    VERBOSE(VB_GENERAL, QString("Listeners = '%1'").arg(output));
    6791}
    6892
    6993/** \brief Dispatch an event to all listeners
    void MythObservable::removeListener(QObj  
    76100 */
    77101void MythObservable::dispatch(const MythEvent &event)
    78102{
     103//    VERBOSE(VB_GENERAL, QString("Dispatching '%1'").arg(event.Message()));
    79104    QMutexLocker locker(m_lock);
    80105
    81106    QSet<QObject*>::const_iterator it = m_listeners.begin();
    void MythObservable::dispatch(const Myth  
    92117 */
    93118void MythObservable::dispatchNow(const MythEvent &event)
    94119{
     120//    VERBOSE(VB_GENERAL, QString("DispatchingNow '%1'").arg(event.Message()));
    95121    QMutexLocker locker(m_lock);
    96122
    97123    QSet<QObject*>::const_iterator it = m_listeners.begin();
  • mythtv/libs/libmythdb/mythobservable.h

    old new class MPUBLIC MythObservable  
    2020    void dispatch(const MythEvent &event);
    2121    void dispatchNow(const MythEvent &event) MDEPRECATED;
    2222
     23    void ShowListeners();
     24
    2325  private:
    2426    QMutex         *m_lock;
    2527    QSet<QObject*>  m_listeners;
  • mythtv/libs/libmythui/mythmainwindow.cpp

    old new MythScreenStack *MythMainWindow::GetStac  
    581581    return NULL;
    582582}
    583583
     584void MythMainWindow::ShowAllStacksBut(QString name)
     585{
     586    QVector<MythScreenStack *>::Iterator it;
     587    for (it = d->stackList.begin(); it != d->stackList.end(); ++it)
     588    {
     589        if ((*it)->objectName() != name)
     590        {
     591            QString loc = (*it)->GetLocation(true);
     592            VERBOSE(VB_GENERAL, QString("Location ('%1' != '%2') = %3").arg((*it)->objectName()).arg(name).arg(loc));
     593        }
     594    }
     595}
     596
    584597void MythMainWindow::RegisterSystemEventHandler(QObject *eventHandler)
    585598{
    586599    d->sysEventHandler = eventHandler;
  • mythtv/libs/libmythui/mythmainwindow.h

    old new class MPUBLIC MythMainWindow : public QW  
    110110    void SetDrawEnabled(bool enable);
    111111    void SetEffectsEnabled(bool enable);
    112112
     113    void ShowAllStacksBut(QString name);
     114
    113115  public slots:
    114116    void mouseTimeout();
    115117
  • mythtv/libs/libmythui/mythuishape.cpp

    old new using namespace std;  
    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  
    2630    m_fillBrush = QBrush(Qt::NoBrush);
    2731    m_linePen = QPen(Qt::NoPen);
    2832    m_cornerRadius = 10;
     33    m_pm = NULL;
    2934}
    3035
    3136MythUIShape::~MythUIShape()
    void MythUIShape::Reset()  
    5156void MythUIShape::DrawSelf(MythPainter *p, int xoffset, int yoffset,
    5257                          int alphaMod, QRect clipRect)
    5358{
     59//FUNCTIONLOGGER;
     60//    if (m_image)
     61//        VERBOSE(VB_GENERAL, QString("Has Image 1 (null? %1), has pixmap %2").arg(m_image->isNull()).arg(m_pm != NULL));
     62//    else
     63//        VERBOSE(VB_GENERAL, QString("Has Image 0, has pixmap %1").arg(m_pm != NULL));
     64
    5465    QRect area = GetArea();
    5566    area.translate(xoffset, yoffset);
    5667
    void MythUIShape::DrawSelf(MythPainter *  
    6273            DrawRoundRect(area, m_cornerRadius, m_fillBrush, m_linePen);
    6374    }
    6475
    65     if (m_image)
     76    if (m_image) {
     77//        VERBOSE(VB_GENERAL, QString("Drawing (%1, %2, xx, %3)").arg(area.x()).arg(area.y()).arg(alphaMod));
    6678        p->DrawImage(area.x(), area.y(), m_image, alphaMod);
     79    }
     80}
     81
     82void MythUIShape::SetPixmap(QPixmap * pm)
     83{
     84//FUNCTIONLOGGER;
     85    m_pm = pm;
     86
     87    if (m_image)
     88    {
     89        m_image->DownRef();
     90        m_image = NULL;
     91    }
     92
     93    m_image = GetMythMainWindow()->GetCurrentPainter()->GetFormatImage();
     94    m_image->UpRef();
     95    if (m_pm)
     96        m_image->Assign(*m_pm);
     97
     98    SetRedraw();
    6799}
    68100
    69101void MythUIShape::DrawRect(const QRect &area,const QBrush &fillBrush,
    70102                           const QPen &linePen)
    71103{
     104//FUNCTIONLOGGER;
    72105    if (m_image)
    73106    {
    74107        m_image->DownRef();
    void MythUIShape::DrawRect(const QRect &  
    93126
    94127    m_image = GetMythMainWindow()->GetCurrentPainter()->GetFormatImage();
    95128    m_image->UpRef();
    96     m_image->Assign(image);
     129    if (m_pm) {
     130//        VERBOSE(VB_GENERAL, "m_pm !=  NULL");
     131        m_image->Assign(*m_pm);
     132    } else {
     133//        VERBOSE(VB_GENERAL, "m_pm ==  NULL");
     134        m_image->Assign(image);
     135    }
    97136}
    98137
    99138void MythUIShape::DrawRoundRect(const QRect &area, int radius,
    100139                                const QBrush &fillBrush, const QPen &linePen)
    101140{
     141//FUNCTIONLOGGER;
    102142    if (m_image)
    103143    {
    104144        m_image->DownRef();
    void MythUIShape::DrawRoundRect(const QR  
    129169
    130170    m_image = GetMythMainWindow()->GetCurrentPainter()->GetFormatImage();
    131171    m_image->UpRef();
    132     m_image->Assign(image);
     172
     173    if (m_pm) {
     174//        VERBOSE(VB_GENERAL, "m_pm !=  NULL");
     175        m_image->Assign(*m_pm);
     176    } else {
     177//        VERBOSE(VB_GENERAL, "m_pm ==  NULL");
     178        m_image->Assign(image);
     179    }
    133180}
    134181
    135182bool MythUIShape::ParseElement(
  • mythtv/libs/libmythui/mythuishape.h

    old new class MPUBLIC MythUIShape : public MythU  
    2020
    2121    void Reset(void);
    2222
     23    void SetPixmap(QPixmap * pm);
     24
    2325  protected:
    2426    virtual void DrawSelf(MythPainter *p, int xoffset, int yoffset,
    2527                          int alphaMod, QRect clipRect);
    class MPUBLIC MythUIShape : public MythU  
    4143    QBrush         m_fillBrush;
    4244    QPen           m_linePen;
    4345    int            m_cornerRadius;
     46
     47    QPixmap        *m_pm;
    4448};
    4549
    4650#endif
  • mythtv/libs/libmythui/libmythui.pro

    old new HEADERS += themeinfo.h mythxdisplay.h Di  
    2828HEADERS += mythgenerictree.h mythuibuttontree.h mythuiutils.h
    2929HEADERS += mythvirtualkeyboard.h mythuishape.h mythuiguidegrid.h
    3030HEADERS += mythrender_base.h mythfontmanager.h
     31HEADERS += mythuicutpointbar.h mythuicutpointimage.h
    3132
    3233SOURCES  = mythmainwindow.cpp mythpainter.cpp mythimage.cpp mythrect.cpp
    3334SOURCES += myththemebase.cpp
    SOURCES += themeinfo.cpp mythxdisplay.cp  
    4445SOURCES += mythgenerictree.cpp mythuibuttontree.cpp mythuiutils.cpp
    4546SOURCES += mythvirtualkeyboard.cpp mythuishape.cpp mythuiguidegrid.cpp
    4647SOURCES += mythfontmanager.cpp
     48SOURCES += mythuicutpointbar.cpp mythuicutpointimage.cpp
    4749
    4850inc.path = $${PREFIX}/include/mythtv/libmythui/
    4951
    inc.files += mythuispinbox.h mythuicheck  
    5860inc.files += mythuiprogressbar.h mythuiwebbrowser.h mythuiutils.h
    5961inc.files += mythsystem.h x11colors.h mythgenerictree.h mythuibuttontree.h
    6062inc.files += mythvirtualkeyboard.h mythuishape.h mythuiguidegrid.h
     63inc.files += mythuicutpointbar.h mythuicutpointimage.h
    6164
    6265INSTALLS += inc
    6366
  • new file mythbuild/mythtv/libs/libmythui/mythuicutpointbar.cpp

    - +  
     1
     2// Own Header
     3#include "mythuicutpointbar.h"
     4
     5// QT
     6#include <QCoreApplication>
     7#include <QDomDocument>
     8
     9// MythDB
     10#include "mythverbose.h"
     11
     12#ifndef FUNCTIONLOGGER
     13#define FUNCTIONLOGGER
     14#endif
     15
     16// MythUI
     17
     18
     19MythUICutPointBar::MythUICutPointBar(MythUIType *parent, const QString &name)
     20                  : MythUIType(parent, name),
     21                    m_layout(LayoutHorizontal), m_effect(EffectReveal),
     22                    m_total(0),                 m_start(0),
     23                    m_current(0)
     24{
     25    m_drawMap = NULL;
     26    m_position=0;
     27}
     28
     29void MythUICutPointBar::InitWidth()
     30{
     31    if (m_drawMap)
     32        delete [] m_drawMap;
     33
     34    m_drawWidth = GetArea().width();
     35    m_drawMap = new unsigned char[m_drawWidth];
     36    for (int i = 0; i < m_drawWidth; i++)
     37        m_drawMap[i] = 0;
     38}
     39
     40void MythUICutPointBar::Reset()
     41{
     42    m_total = m_start = m_current = 0;
     43    CalculatePosition();
     44    MythUIType::Reset();
     45}
     46
     47void MythUICutPointBar::SetRange(
     48        long long fstart, long long fend, long long fcount)
     49{
     50    if (fcount <= 0)
     51    {
     52        VERBOSE(VB_IMPORTANT, QString("Invalid frame count: %1")
     53                .arg(fcount));
     54        return;
     55    }
     56    if (fstart < 0)
     57    {
     58        VERBOSE(VB_IMPORTANT, QString("Invalid starting frame: %1")
     59                .arg(fstart));
     60        return;
     61    }
     62    if (fend < 0)
     63    {
     64        VERBOSE(VB_IMPORTANT, QString("Invalid ending frame: %1")
     65                .arg(fend));
     66        return;
     67    }
     68
     69    if (fstart > fcount) fstart = fcount;
     70    if (fend > fcount) fend = fcount;
     71
     72    int start = (int)((1.0 * fstart * m_drawWidth) / fcount);
     73    int end   = (int)((1.0 * fend   * m_drawWidth) / fcount);
     74
     75    if (start < 0)
     76        start = 0;
     77    if (start >= m_drawWidth)
     78        start = m_drawWidth - 1;
     79    if (end < 0)
     80        end = 0;
     81    if (end >= m_drawWidth)
     82        end = m_drawWidth - 1;
     83
     84    if (end < start)
     85    {
     86        int tmp = start;
     87        start = end;
     88        end = tmp;
     89    }
     90
     91    for (int i = start; i < end; i++)
     92        if (m_drawMap[i] < 1)
     93            m_drawMap[i] = 1;
     94
     95    // Mark endpoints
     96
     97    m_drawMap[start] = 2;
     98    m_drawMap[end]   = 2;
     99
     100    VERBOSE(VB_GENERAL, QString("Range = %1 - %2 (%3 - %4)")
     101            .arg(start).arg(end)
     102            .arg(fstart).arg(fend));
     103    SetRedraw();
     104}
     105
     106void MythUICutPointBar::SetCurrentPosition(
     107        long long fposition, long long fcount)
     108{
     109    if (fcount <= 0)
     110    {
     111        VERBOSE(VB_IMPORTANT, QString("Invalid frame count: %1")
     112                .arg(fcount));
     113        return;
     114    }
     115
     116    if (fposition < 0)
     117    {
     118        VERBOSE(VB_IMPORTANT, QString("Invalid position frame: %1")
     119                .arg(fposition));
     120        return;
     121    }
     122
     123    if (fposition > fcount) fposition = fcount;
     124
     125    int new_position = (int)(1.0 * fposition * m_drawWidth) / fcount;
     126
     127    if (new_position < 0)
     128        new_position = 0;
     129    if (new_position >= m_drawWidth)
     130       new_position = m_drawWidth - 1;
     131
     132    if (new_position != m_position)
     133    {
     134        m_position = new_position;
     135        SetRedraw();
     136    }
     137}
     138
     139
     140
     141bool MythUICutPointBar::ParseElement(
     142    const QString &filename, QDomElement &element, bool showWarnings)
     143{
     144VERBOSE(VB_GENERAL, QString("Got %1").arg(element.tagName()));
     145
     146    if (element.tagName() == "fillcolor")
     147    {
     148        QColor color = getFirstText(element);
     149        setFillColor(color);
     150    }
     151    else if (element.tagName() == "cutcolor")
     152    {
     153        QColor color = getFirstText(element);
     154        setCutColor(color);
     155    }
     156    else if (element.tagName() == "incutcolor")
     157    {
     158        QColor color = getFirstText(element);
     159        setInCutColor(color);
     160    }
     161    else if (element.tagName() == "incutcolor")
     162    {
     163        QColor color = getFirstText(element);
     164        setInCutColor(color);
     165    }
     166    else if (element.tagName() == "cutpointcolor")
     167    {
     168        QColor color = getFirstText(element);
     169        setCutPointColor(color);
     170    }
     171    else if (element.tagName() == "positioncolor")
     172    {
     173        QColor color = getFirstText(element);
     174        setPositionColor(color);
     175    }
     176    else
     177    {
     178        return MythUIType::ParseElement(filename, element, showWarnings);
     179    }
     180
     181    return true;
     182}
     183
     184void MythUICutPointBar::SetStart(int value)
     185{
     186    m_start = value;
     187    CalculatePosition();
     188}
     189
     190void MythUICutPointBar::SetUsed(int value)
     191{
     192    if (value < m_start)
     193        value = m_start;
     194
     195    if (value > m_total)
     196        value = m_total;
     197
     198    m_current = value;
     199    CalculatePosition();
     200}
     201
     202void MythUICutPointBar::SetTotal(int value)
     203{
     204    m_total = value;
     205    CalculatePosition();
     206}
     207
     208void MythUICutPointBar::CalculatePosition(void)
     209{
     210    MythUIImage *progressImage = dynamic_cast<MythUIImage *>
     211                                         (GetChild("progressimage"));
     212
     213    if (!progressImage)
     214    {
     215        VERBOSE(VB_IMPORTANT, "Progress image doesn't exist");
     216        return;
     217    }
     218
     219    progressImage->SetVisible(false);
     220
     221    int total = m_total-m_start;
     222    int current = m_current-m_start;
     223    float percentage = 0.0;
     224
     225    if (total <= 0 || current <= 0 || current > total)
     226        return;
     227
     228    percentage = (float)current / (float)total;
     229    progressImage->SetVisible(true);
     230
     231    QRect fillArea = progressImage->GetArea();
     232
     233    int height = fillArea.height();
     234    int width = fillArea.width();
     235    int x = fillArea.x();
     236    int y = fillArea.y();
     237
     238    switch (m_effect)
     239    {
     240        case EffectReveal :
     241            if (m_layout == LayoutHorizontal)
     242            {
     243                width = (int)((float)fillArea.width() * percentage);
     244            }
     245            else
     246            {
     247                height = (int)((float)fillArea.height() * percentage);
     248            }
     249        break;
     250        case EffectSlide :
     251            if (m_layout == LayoutHorizontal)
     252            {
     253                int newwidth = (int)((float)fillArea.width() * percentage);
     254                x = width - newwidth;
     255                width = newwidth;
     256            }
     257            else
     258            {
     259                int newheight = (int)((float)fillArea.height() * percentage);
     260                y = height - newheight;
     261                height = newheight;
     262            }
     263        break;
     264        case EffectAnimate :
     265            // Not implemented yet
     266        break;
     267    }
     268
     269    if (width <= 0)
     270        width = 1;
     271
     272    if (height <= 0)
     273        height = 1;
     274
     275//    progressImage->SetCropRect(x,y,width,height);
     276    SetRedraw();
     277}
     278
     279void MythUICutPointBar::CopyFrom(MythUIType *base)
     280{
     281    MythUICutPointBar *progressbar = dynamic_cast<MythUICutPointBar *>(base);
     282    if (!progressbar)
     283        return;
     284
     285    m_layout = progressbar->m_layout;
     286    m_effect = progressbar->m_effect;
     287
     288    m_total = progressbar->m_total;
     289    m_start = progressbar->m_start;
     290    m_current = progressbar->m_current;
     291
     292    MythUIType::CopyFrom(base);
     293}
     294
     295void MythUICutPointBar::CreateCopy(MythUIType *parent)
     296{
     297    MythUICutPointBar *progressbar = new MythUICutPointBar(parent, objectName());
     298    progressbar->CopyFrom(this);
     299}
     300
     301void MythUICutPointBar::DrawSelf(MythPainter *p, int xoffset, int yoffset, int alphaMod,
     302              QRect clipRegion)
     303{
     304FUNCTIONLOGGER;
     305    QRect fillArea = GetArea();
     306
     307    int height = fillArea.height();
     308    int width = fillArea.width();
     309    int x = fillArea.x();
     310    int y = fillArea.y();
     311
     312    VERBOSE(VB_GENERAL, QString(" area = (%1, %2, %3, %4)")
     313                .arg(x).arg(y).arg(width).arg(height));
     314
     315    p->DrawRect(fillArea,
     316                true, colorSet[0],
     317                false, 0, colorSet[0]);
     318
     319    if (m_drawMap)
     320    {
     321        int i = 0;
     322
     323        do {
     324            int start = 0;
     325            int end = 0;
     326
     327            while (i < m_drawWidth && m_drawMap[i] == 0) i++;
     328            if (i == m_drawWidth) break;
     329            start = i;
     330
     331            i++;
     332
     333            while (i < m_drawWidth && m_drawMap[i] == 1) i++;
     334            end = i;
     335            if (end == m_drawWidth) end--;
     336
     337            // If the next map value is not a normal internal cutpoint
     338            // increment i so we handle it properly
     339            if (end+1 < m_drawWidth && m_drawMap[end+1] != 1)
     340                i++;
     341
     342            // start == starting point
     343            //   end == endingpoint
     344            {
     345                QRect r = fillArea;
     346                r.setLeft(r.left() + start);
     347                r.setWidth(end - start);
     348
     349//            VERBOSE(VB_GENERAL, QString("Cut from (%1, %2) - (%3, %4)")
     350//                    .arg(r.left()).arg(r.top())
     351//                    .arg(r.right()).arg(r.bottom()));
     352
     353//            VERBOSE(VB_GENERAL, QString("start = %1, m_position = %2, end = %3")
     354//                    .arg(start)
     355//                    .arg(m_position)
     356//                    .arg(end));
     357
     358                if (start <= m_position && m_position <= end)
     359                {
     360                    p->DrawRect(r,
     361                        true, colorSet[4],
     362                        true, 2, colorSet[4]);
     363                }
     364                else
     365                {
     366                    p->DrawRect(r,
     367                        true, colorSet[1],
     368                        true, 2, colorSet[4]);
     369                }
     370
     371                if (m_drawMap[start] == 2)
     372                {
     373                    QRect markArea(r.topLeft(), r.bottomLeft());
     374                    p->DrawRect(markArea,
     375                        true, colorSet[2],
     376                        true, 2, colorSet[2]);
     377                }
     378                if (m_drawMap[end] == 2)
     379                {
     380                    QRect markArea(r.topRight(), r.bottomRight());
     381                    p->DrawRect(markArea,
     382                        true, colorSet[2],
     383                        true, 2, colorSet[2]);
     384                }
     385            }
     386        } while (i < m_drawWidth);
     387    }
     388    // Draw Current Position Mark
     389
     390    QPoint ptop(fillArea.left() + m_position, fillArea.top());
     391    QPoint pbot(fillArea.left() + m_position, fillArea.bottom());
     392
     393    QRect markArea(ptop, pbot);
     394    p->DrawRect(markArea,
     395                true, colorSet[3],
     396                true, 2, colorSet[3]);
     397}
     398
     399void MythUICutPointBar::ClearAll()
     400{
     401    for (int i = 0; i < m_drawWidth; i++)
     402        m_drawMap[i] = 0;
     403    SetRedraw();
     404}
  • new file mythbuild/mythtv/libs/libmythui/mythuicutpointbar.h

    - +  
     1#ifndef MYTHUI_CUTPOINTBAR_H_
     2#define MYTHUI_CUTPOINTBAR_H_
     3
     4#include "mythuitype.h"
     5#include "mythuiimage.h"
     6
     7class MythFontProperties;
     8
     9/** \class MythUIProgressBar
     10 *
     11 *  \brief Progress bar widget.
     12 *
     13 */
     14class MPUBLIC MythUICutPointBar : public MythUIType
     15{
     16  public:
     17    MythUICutPointBar(MythUIType *parent, const QString &name);
     18   ~MythUICutPointBar() { }
     19
     20    void Reset(void);
     21
     22    enum LayoutType { LayoutVertical, LayoutHorizontal };
     23    enum EffectType { EffectReveal, EffectSlide, EffectAnimate };
     24
     25    void SetStart(int);
     26    void SetUsed(int);
     27    void SetTotal(int);
     28
     29    void setFillColor(QColor c)     { colorSet[0] = c; };
     30    void setCutColor(QColor c)      { colorSet[1] = c; };
     31    void setCutPointColor(QColor c) { colorSet[2] = c; };
     32    void setPositionColor(QColor c) { colorSet[3] = c; };
     33    void setInCutColor(QColor c)    { colorSet[4] = c; };
     34
     35    void InitWidth();
     36    void ClearAll();
     37    void SetRange(long long fstart, long long fend, long long fcount);
     38    void SetCurrentPosition(long long fposition, long long fcount);
     39
     40  protected:
     41    virtual void DrawSelf(MythPainter *p, int xoffset, int yoffset,
     42                          int alphaMod, QRect clipRegion);
     43
     44    virtual bool ParseElement(
     45        const QString &filename, QDomElement &element, bool showWarnings);
     46    virtual void CopyFrom(MythUIType *base);
     47    virtual void CreateCopy(MythUIType *parent);
     48
     49    LayoutType m_layout;
     50    EffectType m_effect;
     51
     52    unsigned char *m_drawMap;
     53    int            m_drawWidth;
     54    int            m_position;
     55
     56    QColor         colorSet[5];
     57
     58    int m_total;
     59    int m_start;
     60    int m_current;
     61
     62    void CalculatePosition(void);
     63};
     64
     65#endif
  • mythtv/libs/libmythui/xmlparsebase.cpp

    old new  
    2828#include "mythuispinbox.h"
    2929#include "mythuicheckbox.h"
    3030#include "mythuiprogressbar.h"
     31#include "mythuicutpointbar.h"
     32#include "mythuicutpointimage.h"
    3133#include "mythuigroup.h"
    3234#include "mythuiwebbrowser.h"
    3335#include "mythuiguidegrid.h"
    void XMLParseBase::ParseChildren(const Q  
    246248                     type == "statetype" ||
    247249                     type == "clock" ||
    248250                     type == "progressbar" ||
     251                     type == "cutpointbar" ||
     252                     type == "cutpointimage" ||
    249253                     type == "webbrowser" ||
    250254                     type == "guidegrid" ||
    251255                     type == "shape")
    MythUIType *XMLParseBase::ParseUIType(  
    343347        uitype = new MythUIClock(parent, name);
    344348    else if (type == "progressbar")
    345349        uitype = new MythUIProgressBar(parent, name);
     350    else if (type == "cutpointbar")
     351        uitype = new MythUICutPointBar(parent, name);
     352    else if (type == "cutpointimage")
     353        uitype = new MythUICutPointImage(parent, name);
    346354    else if (type == "webbrowser")
    347355        uitype = new MythUIWebBrowser(parent, name);
    348356    else if (type == "guidegrid")
    MythUIType *XMLParseBase::ParseUIType(  
    432440                     info.tagName() == "statetype" ||
    433441                     info.tagName() == "clock" ||
    434442                     info.tagName() == "progressbar" ||
     443                     info.tagName() == "cutpointbar" ||
     444                     info.tagName() == "cutpointimage" ||
    435445                     info.tagName() == "webbrowser" ||
    436446                     info.tagName() == "guidegrid" ||
    437447                     info.tagName() == "shape")
    bool XMLParseBase::doLoad(const QString  
    617627                         type == "window" ||
    618628                         type == "clock" ||
    619629                         type == "progressbar" ||
     630                         type == "cutpointbar" ||
     631                         type == "cutpointimage" ||
    620632                         type == "webbrowser" ||
    621633                         type == "guidegrid" ||
    622634                         type == "shape")
  • new file mythbuild/mythtv/libs/libmythui/mythuicutpointimage.cpp

    - +  
     1
     2// Own header
     3#include "mythuicutpointimage.h"
     4
     5// C++
     6#include <algorithm>
     7using namespace std;
     8
     9// qt
     10#include <QDomDocument>
     11#include <QPainter>
     12#include <QSize>
     13#include <QColor>
     14
     15// myth
     16#include "mythverbose.h"
     17#include "mythpainter.h"
     18#include "mythimage.h"
     19#include "mythmainwindow.h"
     20
     21#ifndef FUNCTIONLOGGER
     22#define FUNCTIONLOGGER
     23#endif
     24
     25MythUICutPointImage::MythUICutPointImage(MythUIType *parent, const QString &name)
     26          : MythUIType(parent, name)
     27{
     28    m_image = NULL;
     29
     30    m_cutStatus = 0;
     31    m_highlightFrame = false;
     32    m_framenumber = -1;
     33}
     34
     35MythUICutPointImage::~MythUICutPointImage()
     36{
     37    if (m_image)
     38    {
     39        m_image->DownRef();
     40        m_image = NULL;
     41    }
     42}
     43
     44void MythUICutPointImage::Reset()
     45{
     46    if (m_image)
     47    {
     48        m_image->DownRef();
     49        m_image = NULL;
     50    }
     51
     52    MythUIType::Reset();
     53}
     54
     55void MythUICutPointImage::DrawSelf(MythPainter *p, int xoffset, int yoffset,
     56                          int alphaMod, QRect clipRect)
     57{
     58//FUNCTIONLOGGER;
     59//    if (m_image)
     60//        VERBOSE(VB_GENERAL, QString("Has Image 1 (null? %1), has pixmap %2").arg(m_image->isNull()).arg(m_pm != NULL));
     61//    else
     62//        VERBOSE(VB_GENERAL, QString("Has Image 0, has pixmap %1").arg(m_pm != NULL));
     63
     64    QRect area = GetArea();
     65    area.translate(xoffset, yoffset);
     66
     67    if (!m_image || m_image->isNull())
     68        UpdateImage();
     69
     70    if (m_image) {
     71        p->DrawImage(area.x(), area.y(), m_image, alphaMod);
     72    }
     73}
     74
     75void MythUICutPointImage::SetPixmap(QPixmap * new_pmap, long long frame, int new_cutStatus)
     76{
     77//FUNCTIONLOGGER;
     78    if (! new_pmap)
     79    {
     80        clearPixmap();
     81        return;
     82    }
     83
     84    if (frame == m_framenumber)
     85    {
     86        // No change in pixmap (?)
     87        setCutStatus(new_cutStatus);
     88        return;
     89    }
     90
     91    m_pmap = *new_pmap;
     92    m_framenumber = frame;
     93
     94    if (new_cutStatus >= 0 && new_cutStatus <= 3)
     95        m_cutStatus = new_cutStatus;
     96    else
     97        m_cutStatus = 0;
     98
     99    UpdateImage();
     100    SetRedraw();
     101}
     102
     103void MythUICutPointImage::clearPixmap(bool dorefresh)
     104{
     105    if (! m_pmap.isNull())
     106    {
     107        m_pmap = QPixmap();
     108
     109        m_cutStatus = 0;
     110        m_framenumber = -1;
     111        UpdateImage();
     112        if (dorefresh)
     113            SetRedraw();
     114    }
     115}
     116
     117void MythUICutPointImage::setCutStatus(int new_cutStatus)
     118{
     119    if (new_cutStatus == m_cutStatus)
     120        return;
     121
     122    if (new_cutStatus >= 0 && new_cutStatus <= 3)
     123        m_cutStatus = new_cutStatus;
     124    else
     125        m_cutStatus = 0;
     126
     127    UpdateImage();
     128    SetRedraw();
     129}
     130
     131
     132//void MythUICutPointImage::DrawRect(const QRect &area,const QBrush &fillBrush,
     133//                           const QPen &linePen)
     134void MythUICutPointImage::UpdateImage()
     135{
     136    if (m_image)
     137    {
     138        m_image->DownRef();
     139        m_image = NULL;
     140    }
     141    QRect area = GetArea();
     142
     143    QImage image(QSize(area.width(), area.height()), QImage::Format_ARGB32);
     144    QPainter painter(&image);
     145
     146    if (m_pmap.isNull())
     147    {
     148        QRect tmparea(0, 0, area.width(), area.height());
     149        QColor drawcolor = QColor( 0, 0, 0);
     150        painter.setBrush(QBrush(Qt::SolidPattern));
     151        painter.setPen(QPen(drawcolor, 2));
     152        painter.drawRect(tmparea);
     153    }
     154    else
     155    {
     156        QRect m_outer_border(0, 0, area.width(), area.height());
     157        QRect m_inner_border(1, 1, area.width()-2, area.height()-2);
     158        painter.drawPixmap(0, 0, m_pmap);
     159
     160        painter.setRenderHint(QPainter::Antialiasing);
     161
     162        painter.setBrush(QBrush(Qt::NoBrush));
     163        painter.setPen(QPen(m_colorSet[0], 3));
     164        painter.drawRect(m_outer_border);
     165
     166        if (m_cutStatus > 0)
     167        {
     168            painter.setPen(QPen(m_colorSet[m_cutStatus], 3));
     169            painter.drawRect(m_inner_border);
     170            painter.drawLine(m_inner_border.topLeft(), m_inner_border.bottomRight());
     171            painter.drawLine(m_inner_border.bottomLeft(), m_inner_border.topRight());
     172        }
     173        if (m_highlightFrame)
     174        {
     175            // Overlay the image frame with the standard frame color
     176            // This is used to highlight small frame #0
     177            painter.setPen(QPen(m_highlightColor, 3));
     178            painter.drawRect(m_outer_border);
     179        }
     180    }
     181
     182    painter.end();
     183
     184    m_image = GetMythMainWindow()->GetCurrentPainter()->GetFormatImage();
     185    m_image->UpRef();
     186    m_image->Assign(image);
     187}
     188
     189bool MythUICutPointImage::ParseElement(
     190    const QString &filename, QDomElement &element, bool showWarnings)
     191{
     192    if (element.tagName() == "outlinecolor")
     193    {
     194        m_colorSet[0] = QColor(getFirstText(element));
     195    }
     196    else if (element.tagName() == "cutcolor")
     197    {
     198        m_colorSet[1] = QColor(getFirstText(element));
     199    }
     200    else if (element.tagName() == "cutpointcolor")
     201    {
     202        m_colorSet[2] = m_colorSet[3] = QColor(getFirstText(element));
     203    }
     204    else if (element.tagName() == "highlightcolor")
     205    {
     206        m_highlightColor = QColor(getFirstText(element));
     207        m_highlightFrame = true;
     208    }
     209    else
     210    {
     211        return MythUIType::ParseElement(filename, element, showWarnings);
     212    }
     213
     214    return true;
     215}
     216
     217void MythUICutPointImage::CopyFrom(MythUIType *base)
     218{
     219    MythUICutPointImage *shape = dynamic_cast<MythUICutPointImage *>(base);
     220    if (!shape)
     221    {
     222        VERBOSE(VB_IMPORTANT, "ERROR, bad parsing");
     223        return;
     224    }
     225
     226    m_image = shape->m_image;
     227    if (m_image)
     228        m_image->UpRef();
     229
     230    m_pmap = shape->m_pmap ;
     231    m_framenumber = shape->m_framenumber;
     232    m_cutStatus = shape->m_cutStatus;
     233    m_highlightFrame = shape->m_highlightFrame;
     234    m_highlightColor = shape->m_highlightColor;
     235
     236    int i;
     237    for (i = 0; i < 4; i++)
     238        m_colorSet[i] = shape->m_colorSet[i];
     239
     240    MythUIType::CopyFrom(base);
     241}
     242
     243void MythUICutPointImage::CreateCopy(MythUIType *parent)
     244{
     245    MythUICutPointImage *shape = new MythUICutPointImage(parent, objectName());
     246    shape->CopyFrom(this);
     247}
     248
  • new file mythbuild/mythtv/libs/libmythui/mythuicutpointimage.h

    - +  
     1#ifndef MYTHUICUTPOINTIMAGE_H_
     2#define MYTHUICUTPOINTIMAGE_H_
     3
     4// QT headers
     5#include <QColor>
     6#include <QPen>
     7#include <QBrush>
     8#include <QLinearGradient>
     9
     10// Mythui headers
     11#include "mythuitype.h"
     12
     13class MythImage;
     14
     15class MPUBLIC MythUICutPointImage : public MythUIType
     16{
     17  public:
     18    MythUICutPointImage(MythUIType *parent, const QString &name);
     19    ~MythUICutPointImage();
     20
     21    void Reset(void);
     22
     23    void SetPixmap(QPixmap * new_pmap, long long frame, int new_cutStatus);
     24
     25    void clearPixmap(bool dorefresh=true);
     26    void setCutStatus(int new_cutStatus);
     27
     28  protected:
     29    virtual void DrawSelf(MythPainter *p, int xoffset, int yoffset,
     30                          int alphaMod, QRect clipRect);
     31
     32    virtual bool ParseElement(
     33        const QString &filename, QDomElement &element, bool showWarnings);
     34    virtual void CopyFrom(MythUIType *base);
     35    virtual void CreateCopy(MythUIType *parent);
     36
     37    QLinearGradient parseGradient(const QDomElement &element);
     38
     39    void UpdateImage();
     40
     41  private:
     42    MythImage     *m_image;
     43
     44    QPixmap        m_pmap;
     45    long long      m_framenumber; // for consistency checking
     46    int            m_cutStatus;
     47    QColor         m_colorSet[4];
     48    bool           m_highlightFrame;
     49    QColor         m_highlightColor;
     50};
     51
     52#endif