Ticket #10072: 0001-freemheg-Support-bitmap-backgrounds-used-by-BBC-Free.patch

File 0001-freemheg-Support-bitmap-backgrounds-used-by-BBC-Free.patch, 13.2 KB (added by Lawrence Rust <lvr@…>, 14 years ago)
  • mythtv/libs/libmythfreemheg/Bitmap.cpp

    From 8618a0f10820562793417c0a546f91ea02194f75 Mon Sep 17 00:00:00 2001
    From: Lawrence Rust <lvr@softsystem.co.uk>
    Date: Sun, 2 Oct 2011 14:36:50 +0200
    Subject: [PATCH] freemheg: Support bitmap backgrounds used by BBC/Freesat
    
    Add support for bitmaps with a content hook type of 5 which are
    transmitted by the BBC on FreesSat & FreeView.
    
    Type 5 bitmaps are identical to type 2, an MPEG I-frame, but are intended
    to be used as a background onto which the MHEG content and video is rendered.
    
    Signed-off-by: Lawrence Rust <lvr@softsystem.co.uk>
    ---
     mythtv/libs/libmythfreemheg/Bitmap.cpp |   26 ++++----
     mythtv/libs/libmythfreemheg/freemheg.h |    2 +-
     mythtv/libs/libmythtv/mhi.cpp          |  113 ++++++++++++++++++++-----------
     mythtv/libs/libmythtv/mhi.h            |    9 ++-
     4 files changed, 91 insertions(+), 59 deletions(-)
    
    diff --git a/mythtv/libs/libmythfreemheg/Bitmap.cpp b/mythtv/libs/libmythfreemheg/Bitmap.cpp
    index 42c9df1..1c4ffae 100644
    a b void MHBitmap::ContentArrived(const unsigned char *data, int length, MHEngine *e  
    150150        nCHook = engine->GetDefaultBitmapCHook();
    151151    }
    152152
    153     // TODO: What if we can't convert it?
    154     if (nCHook == 4)   // PNG.
     153    switch (nCHook)
    155154    {
     155    case 4: // PNG.
    156156        m_pContent->CreateFromPNG(data, length);
    157     }
    158     // CHook 5 seems to be used by the BBC on Freesat for an MPEG I-frame for the
    159     // background but enabling it here results in it overlaying the video.
    160     // Presumably it is not simply the same as CHook 2.
    161     else if (nCHook == 2 /* ||nCHook == 5 */)   // MPEG I-frame.
    162     {
     157        break;
     158    case 2: // MPEG I-frame.
     159    case 5: // BBC/Freesat MPEG I-frame background
    163160        m_pContent->CreateFromMPEG(data, length);
    164     }
    165 
    166     else
    167     {
     161        break;
     162    case 6: // JPEG ISO/IEC 10918-1, JFIF file
     163    default: // 1,3,5,8 are reserved. 7= H.264 Intra Frame
    168164        MHERROR(QString("Unknown bitmap content hook %1").arg(nCHook));
    169165    }
    170166
    void MHBitmap::Display(MHEngine *)  
    229225    }
    230226
    231227    m_pContent->Draw(m_nPosX + m_nXDecodeOffset, m_nPosY + m_nYDecodeOffset,
    232                      QRect(m_nPosX, m_nPosY, m_nBoxWidth, m_nBoxHeight), m_fTiling);
     228            QRect(m_nPosX, m_nPosY, m_nBoxWidth, m_nBoxHeight), m_fTiling,
     229            m_nContentHook == 5); // 'under video' if BBC MPEG I-frame background
    233230}
    234231
    235232// Return the region drawn by the bitmap.
    QRegion MHBitmap::GetVisibleArea()  
    253250QRegion MHBitmap::GetOpaqueArea()
    254251{
    255252    // The area is empty unless the bitmap is opaque.
    256     if (! m_fRunning || m_pContent == NULL || ! m_pContent->IsOpaque())
     253    // and it's not a BBC MPEG I-frame background
     254    if (! m_fRunning || m_nContentHook == 5 || m_pContent == NULL || ! m_pContent->IsOpaque())
    257255    {
    258256        return QRegion();
    259257    }
  • mythtv/libs/libmythfreemheg/freemheg.h

    diff --git a/mythtv/libs/libmythfreemheg/freemheg.h b/mythtv/libs/libmythfreemheg/freemheg.h
    index 0b61f65..42ad883 100644
    a b class MHBitmapDisplay  
    187187    // Draw the completed drawing onto the display.  x and y give the position of the image
    188188    // relative to the screen.  rect gives the bounding box for the image, again relative to
    189189    // the screen.
    190     virtual void Draw(int x, int y, QRect rect, bool tiled) = 0;
     190    virtual void Draw(int x, int y, QRect rect, bool tiled, bool bUnder) = 0;
    191191    // Creation functions
    192192    virtual void CreateFromPNG(const unsigned char *data, int length) = 0;
    193193    virtual void CreateFromMPEG(const unsigned char *data, int length) = 0;
  • mythtv/libs/libmythtv/mhi.cpp

    diff --git a/mythtv/libs/libmythtv/mhi.cpp b/mythtv/libs/libmythtv/mhi.cpp
    index 1631495..6694efc 100644
    a b class MHIImageData  
    4444    QImage m_image;
    4545    int    m_x;
    4646    int    m_y;
     47    bool   m_bUnder;
    4748};
    4849
    4950// Special value for the NetworkBootInfo version.  Real values are a byte.
    MHIContext::MHIContext(InteractiveTV *parent)  
    6061      m_audioTag(-1),       m_videoTag(-1),
    6162      m_lastNbiVersion(NBI_VERSION_UNSET),
    6263      m_videoRect(0, 0, StdDisplayWidth, StdDisplayHeight),
     64      m_videoDisplayRect(0, 0, StdDisplayWidth, StdDisplayHeight),
    6365      m_displayRect(0, 0, StdDisplayWidth, StdDisplayHeight)
    6466{
    6567    m_xScale = (float)m_displayWidth / (float)MHIContext::StdDisplayWidth;
    void MHIContext::UpdateOSD(InteractiveScreen *osdWindow,  
    505507        return;
    506508
    507509    QMutexLocker locker(&m_display_lock);
     510
     511    // In MHEG the video is just another item in the display stack
     512    // but when we create the OSD we overlay everything over the video.
     513    // We need to cut out anything belowthe video on the display stack
     514    // to leave the video area clear.
     515    list<MHIImageData*>::iterator it = m_display.begin();
     516    for (; it != m_display.end(); ++it)
     517    {
     518        MHIImageData *data = *it;
     519        if (!data->m_bUnder)
     520            continue;
     521
     522        QRect imageRect(data->m_x, data->m_y,
     523                        data->m_image.width(), data->m_image.height());
     524        if (!m_videoDisplayRect.intersects(imageRect))
     525            continue;
     526
     527        // Replace this item with a set of cut-outs.
     528        it = m_display.erase(it);
     529
     530        QVector<QRect> rects =
     531            (QRegion(imageRect) - QRegion(m_videoDisplayRect)).rects();
     532        for (uint j = 0; j < (uint)rects.size(); j++)
     533        {
     534            QRect &rect = rects[j];
     535            QImage image =
     536                data->m_image.copy(rect.x()-data->m_x, rect.y()-data->m_y,
     537                                   rect.width(), rect.height());
     538            MHIImageData *newData = new MHIImageData;
     539            newData->m_image = image;
     540            newData->m_x = rect.x();
     541            newData->m_y = rect.y();
     542            newData->m_bUnder = true;
     543            m_display.insert(it, newData);
     544            ++it;
     545        }
     546        delete data;
     547    }
     548
    508549    m_updated = false;
    509550    osdWindow->DeleteAllChildren();
    510551    // Copy all the display items into the display.
    511     list<MHIImageData*>::iterator it = m_display.begin();
     552    it = m_display.begin();
    512553    for (int count = 0; it != m_display.end(); ++it, count++)
    513554    {
    514555        MHIImageData *data = *it;
    void MHIContext::RequireRedraw(const QRegion &)  
    551592    m_updated = true;
    552593}
    553594
    554 void MHIContext::AddToDisplay(const QImage &image, int x, int y)
     595void MHIContext::AddToDisplay(const QImage &image, int x, int y, bool bUnder /*=false*/)
    555596{
    556597    MHIImageData *data = new MHIImageData;
    557598    int dispx = x + m_displayRect.left();
    void MHIContext::AddToDisplay(const QImage &image, int x, int y)  
    560601    data->m_image = image;
    561602    data->m_x = dispx;
    562603    data->m_y = dispy;
     604    data->m_bUnder = bUnder;
    563605    QMutexLocker locker(&m_display_lock);
    564     m_display.push_back(data);
     606    if (!bUnder)
     607        m_display.push_back(data);
     608    else
     609    {
     610        // Replace any existing items under the video with this
     611        list<MHIImageData*>::iterator it = m_display.begin();
     612        while (it != m_display.end())
     613        {
     614            MHIImageData *old = *it;
     615            if (!old->m_bUnder)
     616                ++it;
     617            else
     618            {
     619                it = m_display.erase(it);
     620                delete old;
     621            }
     622        }
     623        m_display.push_front(data);
     624    }
    565625}
    566626
    567 // In MHEG the video is just another item in the display stack
    568 // but when we create the OSD we overlay everything over the video.
    569 // We need to cut out anything belowthe video on the display stack
    570 // to leave the video area clear.
    571627// The videoRect gives the size and position to which the video must be scaled.
    572628// The displayRect gives the rectangle reserved for the video.
    573629// e.g. part of the video may be clipped within the displayRect.
    void MHIContext::DrawVideo(const QRect &videoRect, const QRect &dispRect)  
    587643        }
    588644    }
    589645
    590     QMutexLocker locker(&m_display_lock);
    591     QRect displayRect(SCALED_X(dispRect.x()),
     646    m_videoDisplayRect = QRect(SCALED_X(dispRect.x()),
    592647                      SCALED_Y(dispRect.y()),
    593648                      SCALED_X(dispRect.width()),
    594649                      SCALED_Y(dispRect.height()));
    595650
     651    // Mark all existing items in the display stack as under the video
     652    QMutexLocker locker(&m_display_lock);
    596653    list<MHIImageData*>::iterator it = m_display.begin();
    597654    for (; it != m_display.end(); ++it)
    598655    {
    599         MHIImageData *data = *it;
    600         QRect imageRect(data->m_x, data->m_y,
    601                         data->m_image.width(), data->m_image.height());
    602         if (displayRect.intersects(imageRect))
    603         {
    604             // Replace this item with a set of cut-outs.
    605             it = m_display.erase(it);
    606 
    607             QVector<QRect> rects =
    608                 (QRegion(imageRect) - QRegion(displayRect)).rects();
    609             for (uint j = 0; j < (uint)rects.size(); j++)
    610             {
    611                 QRect &rect = rects[j];
    612                 QImage image =
    613                     data->m_image.copy(rect.x()-data->m_x, rect.y()-data->m_y,
    614                                        rect.width(), rect.height());
    615                 MHIImageData *newData = new MHIImageData;
    616                 newData->m_image = image;
    617                 newData->m_x = rect.x();
    618                 newData->m_y = rect.y();
    619                 m_display.insert(it, newData);
    620                 ++it;
    621             }
    622             delete data;
    623         }
     656        (*it)->m_bUnder = true;
    624657    }
    625658}
    626659
    void MHIContext::DrawRect(int xPos, int yPos, int width, int height,  
    866899// and usually that will be the same as the origin of the bounding
    867900// box (clipRect).
    868901void MHIContext::DrawImage(int x, int y, const QRect &clipRect,
    869                            const QImage &qImage)
     902                           const QImage &qImage, bool bUnder)
    870903{
    871904    if (qImage.isNull())
    872905        return;
    void MHIContext::DrawImage(int x, int y, const QRect &clipRect,  
    884917                Qt::IgnoreAspectRatio,
    885918                Qt::SmoothTransformation);
    886919        AddToDisplay(q_scaled.convertToFormat(QImage::Format_ARGB32),
    887                      SCALED_X(x), SCALED_Y(y));
     920                     SCALED_X(x), SCALED_Y(y), bUnder);
    888921    }
    889922    else if (!displayRect.isEmpty())
    890923    { // We must clip the image.
    void MHIContext::DrawImage(int x, int y, const QRect &clipRect,  
    899932                Qt::SmoothTransformation);
    900933        AddToDisplay(q_scaled,
    901934                     SCALED_X(displayRect.x()),
    902                      SCALED_Y(displayRect.y()));
     935                     SCALED_Y(displayRect.y()), bUnder);
    903936    }
    904937    // Otherwise draw nothing.
    905938}
    void MHIDLA::DrawPoly(bool isFilled, int nPoints, const int *xArray, const int *  
    14521485}
    14531486
    14541487
    1455 void MHIBitmap::Draw(int x, int y, QRect rect, bool tiled)
     1488void MHIBitmap::Draw(int x, int y, QRect rect, bool tiled, bool bUnder)
    14561489{
    14571490    if (tiled)
    14581491    {
    void MHIBitmap::Draw(int x, int y, QRect rect, bool tiled)  
    14701503                tiledImage.setPixel(i, j, m_image.pixel(i % m_image.width(), j % m_image.height()));
    14711504            }
    14721505        }
    1473         m_parent->DrawImage(rect.x(), rect.y(), rect, tiledImage);
     1506        m_parent->DrawImage(rect.x(), rect.y(), rect, tiledImage, bUnder);
    14741507    }
    14751508    else
    14761509    {
    1477         m_parent->DrawImage(x, y, rect, m_image);
     1510        m_parent->DrawImage(x, y, rect, m_image, bUnder);
    14781511    }
    14791512}
    14801513
  • mythtv/libs/libmythtv/mhi.h

    diff --git a/mythtv/libs/libmythtv/mhi.h b/mythtv/libs/libmythtv/mhi.h
    index 2b10c8b..c7339fe 100644
    a b class MHIContext : public MHContext, public QRunnable  
    9999    virtual void DrawBackground(const QRegion &reg);
    100100    virtual void DrawVideo(const QRect &videoRect, const QRect &displayRect);
    101101
    102     void DrawImage(int x, int y, const QRect &rect, const QImage &image);
     102    void DrawImage(int x, int y, const QRect &rect, const QImage &image,
     103        bool bUnder = false);
    103104
    104105    virtual int GetChannelIndex(const QString &str);
    105106    /// Get netId etc from the channel index.
    class MHIContext : public MHContext, public QRunnable  
    125126
    126127    // Operations used by the display classes
    127128    // Add an item to the display vector
    128     void AddToDisplay(const QImage &image, int x, int y);
     129    void AddToDisplay(const QImage &image, int x, int y, bool bUnder = false);
    129130
    130131    FT_Face GetFontFace(void) { return m_face; }
    131132    bool IsFaceLoaded(void) { return m_face_loaded; }
    class MHIContext : public MHContext, public QRunnable  
    185186    uint             m_lastNbiVersion;
    186187    vector<unsigned char> m_nbiData;
    187188
    188     QRect            m_videoRect;
     189    QRect            m_videoRect, m_videoDisplayRect;
    189190    QRect            m_displayRect;
    190191};
    191192
    class MHIBitmap : public MHBitmapDisplay  
    238239     *  \param y     Vertical position of the image relative to the screen.
    239240     *  \param rect  Bounding box for the image relative to the screen.
    240241     */
    241     virtual void Draw(int x, int y, QRect rect, bool tiled);
     242    virtual void Draw(int x, int y, QRect rect, bool tiled, bool bUnder);
    242243
    243244    /// Scale the bitmap.  Only used for image derived from MPEG I-frames.
    244245    virtual void ScaleImage(int newWidth, int newHeight);