예제 #1
0
MythUIType::MythUIType(QObject *parent, const QString &name)
    : QObject(parent)
{
    setObjectName(name);

    m_Visible = true;
    m_Enabled = true;
    m_CanHaveFocus = m_HasFocus = false;
    m_Area = MythRect(0, 0, 0, 0);
    m_MinArea = MythRect(0, 0, 0, 0);
    m_NeedsRedraw = false;
    m_Alpha = 255;
    m_AlphaChangeMode = m_AlphaChange = m_AlphaMin = 0;
    m_AlphaMax = 255;
    m_Moving = false;
    m_XYDestination = QPoint(0, 0);
    m_XYSpeed = QPoint(0, 0);
    m_deferload = false;

    m_Parent = NULL;
    if (parent)
    {
        m_Parent = dynamic_cast<MythUIType *>(parent);
        if (m_Parent)
            m_Parent->AddChild(this);
    }

    m_DirtyRegion = QRegion(QRect(0, 0, 0, 0));

    m_Fonts = new FontMap();
    m_focusOrder = 0;
    m_Painter = NULL;
}
예제 #2
0
void TeletextScreen::OptimiseDisplayedArea(void)
{
    VideoOutput *vo = m_player->GetVideoOutput();
    if (!vo)
        return;
    MythPainter *osd_painter = vo->GetOSDPainter();
    if (!osd_painter)
        return;

    QHashIterator<int, QImage*> it(m_rowImages);
    while (it.hasNext())
    {
        it.next();
        MythImage* image = osd_painter->GetFormatImage();
        if (!image || !it.value())
            continue;

        int row = it.key();
        image->Assign(*(it.value()));
        MythUIImage *uiimage = new MythUIImage(this, QString("ttrow%1")
                                                        .arg(row));
        if (uiimage)
        {
            uiimage->SetImage(image);
            uiimage->SetArea(MythRect(0, row * m_rowHeight,
                                      m_safeArea.width(), m_rowHeight * 2));
        }
    }

    QRegion visible;
    QListIterator<MythUIType *> i(m_ChildrenList);
    while (i.hasNext())
    {
        MythUIType *img = i.next();
        visible = visible.united(img->GetArea());
    }

    if (visible.isEmpty())
        return;

    QRect bounding  = visible.boundingRect();
    bounding = bounding.translated(m_safeArea.topLeft());
    bounding = m_safeArea.intersected(bounding);
    int left = m_safeArea.left() - bounding.left();
    int top  = m_safeArea.top()  - bounding.top();
    SetArea(MythRect(bounding));

    i.toFront();;
    while (i.hasNext())
    {
        MythUIType *img = i.next();
        img->SetArea(img->GetArea().translated(left, top));
    }
}
예제 #3
0
void SubtitleScreen::OptimiseDisplayedArea(void)
{
    if (!m_refreshArea)
        return;

    QRegion visible;
    QListIterator<MythUIType *> i(m_ChildrenList);
    while (i.hasNext())
    {
        MythUIType *img = i.next();
        visible = visible.united(img->GetArea());
    }

    if (visible.isEmpty())
        return;

    QRect bounding  = visible.boundingRect();
    bounding = bounding.translated(m_safeArea.topLeft());
    bounding = m_safeArea.intersected(bounding);
    int left = m_safeArea.left() - bounding.left();
    int top  = m_safeArea.top()  - bounding.top();
    SetArea(MythRect(bounding));

    i.toFront();;
    while (i.hasNext())
    {
        MythUIType *img = i.next();
        img->SetArea(img->GetArea().translated(left, top));
    }
}
예제 #4
0
파일: mhi.cpp 프로젝트: Olti/mythtv
// Called by the video player to redraw the image.
void MHIContext::UpdateOSD(InteractiveScreen *osdWindow,
                           MythPainter *osdPainter)
{
    if (!osdWindow || !osdPainter)
        return;

    QMutexLocker locker(&m_display_lock);
    m_updated = false;
    osdWindow->DeleteAllChildren();
    // Copy all the display items into the display.
    list<MHIImageData*>::iterator it = m_display.begin();
    for (int count = 0; it != m_display.end(); ++it, count++)
    {
        MHIImageData *data = *it;
        MythImage* image = osdPainter->GetFormatImage();
        if (!image)
            continue;

        image->Assign(data->m_image);
        MythUIImage *uiimage = new MythUIImage(osdWindow, QString("itv%1")
                                               .arg(count));
        if (uiimage)
        {
            uiimage->SetImage(image);
            uiimage->SetArea(MythRect(data->m_x, data->m_y,
                             data->m_image.width(), data->m_image.height()));
        }
        image->DecrRef();
    }
    osdWindow->OptimiseDisplayedArea();
    // N.B. bypasses OSD class hence no expiry set
    osdWindow->SetVisible(true);
}
예제 #5
0
/**
 *  \brief Initialises the class
 */
void MythUIImage::Init(void)
{
    m_cropRect = MythRect(0,0,0,0);
    m_ForceSize = QSize(0,0);

    m_CurPos = 0;
    m_LastDisplay = QTime::currentTime();

    m_NeedLoad = false;

    m_isReflected = false;
    m_reflectShear = 0;
    m_reflectScale = m_reflectLength = 100;
    m_reflectAxis = ReflectVertical;
    m_reflectSpacing = 0;

    m_isMasked = false;
    m_maskImage = NULL;

    m_isGreyscale = false;

    m_preserveAspect = false;

    m_animationCycle = kCycleStart;
    m_animationReverse = false;
    m_animatedImage = false;
}
예제 #6
0
void SubtitleScreen::AddScaledImage(QImage &img, QRect &pos)
{
    VideoOutput *vo = m_player->GetVideoOutput();
    if (!vo)
        return;

    QRect scaled = vo->GetImageRect(pos);
    if (scaled.size() != pos.size())
    {
        img = img.scaled(scaled.width(), scaled.height(),
                         Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
    }

    MythPainter *osd_painter = vo->GetOSDPainter();
    MythImage* image = NULL;
    if (osd_painter)
         image = osd_painter->GetFormatImage();

    if (image)
    {
        image->Assign(img);
        MythUIImage *uiimage = new MythUIImage(this, "dvd_button");
        if (uiimage)
        {
            m_refreshArea = true;
            uiimage->SetImage(image);
            uiimage->SetArea(MythRect(scaled));
        }
    }
}
예제 #7
0
/**
 *  \brief Reset the image back to the default defined in the theme
 */
void MythUIImage::Reset(void)
{
    d->m_UpdateLock.lockForWrite();

    SetMinArea(MythRect());

    if (m_imageProperties.filename != m_OrigFilename)
    {
        m_imageProperties.isThemeImage = true;
        m_imageProperties.filename = m_OrigFilename;

        if (m_animatedImage)
        {
            m_LowNum = 0;
            m_HighNum = 0;
            m_animatedImage = false;
        }
        emit DependChanged(true);

        d->m_UpdateLock.unlock();
        Load();
    }
    else
        d->m_UpdateLock.unlock();

    MythUIType::Reset();
}
예제 #8
0
void SubtitleScreen::DisableForcedSubtitles(void)
{
    if (kDisplayNone != m_subtitleType)
        return;
    ClearAllSubtitles();
    SetVisible(false);
    SetArea(MythRect());
}
예제 #9
0
void MythUITextEdit::SetInitialStates()
{
    if (m_initialized)
        return;

    m_initialized = true;

    m_Text        = dynamic_cast<MythUIText*>(GetChild("text"));
    m_cursorImage = dynamic_cast<MythUIImage*>(GetChild("cursor"));
    m_backgroundState =
        dynamic_cast<MythUIStateType*>(GetChild("background"));

    if (!m_Text)
        VERBOSE(VB_IMPORTANT, LOC_ERR + "Missing text element.");
    if (!m_cursorImage)
        VERBOSE(VB_IMPORTANT, LOC_ERR + "Missing cursor element.");
    if (!m_backgroundState)
        VERBOSE(VB_IMPORTANT, LOC_WARN + "Missing background element.");

    if (!m_Text || !m_cursorImage)
    {
        m_Text = NULL;
        m_cursorImage = NULL;
        m_backgroundState = NULL;
        return;
    }

    if (m_backgroundState && !m_backgroundState->DisplayState("active"))
        VERBOSE(VB_IMPORTANT, "MythUITextEdit: active state doesn't exist");

    QFontMetrics fm(m_Text->GetFontProperties()->face());
    int height = fm.height();
    if (height > 0)
    {
        MythRect imageArea = m_cursorImage->GetArea();
        int width = int(((float)height / (float)imageArea.height())
                        * (float)imageArea.width());
        if (width <= 0)
            width = 1;
        m_cursorImage->ForceSize(QSize(width,height));
    }

    MythRect textrect = m_Text->GetArea();

    if (textrect.isNull())
        textrect = MythRect(5,5,m_Area.width()-10,m_Area.height()-10);

    textrect.setWidth(textrect.width() - m_cursorImage->GetArea().width());

    if (textrect.isValid())
        m_Text->SetArea(textrect);

    m_Text->SetCutDown(false);

    m_cursorImage->SetPosition(textrect.x(),textrect.y());
}
예제 #10
0
MythUIType::MythUIType(QObject *parent, const QString &name)
    : QObject(parent)
{
    setObjectName(name);

    m_Visible = true;
    m_Enabled = true;
    m_EnableInitiator = false;
    m_Initiator = false;
    m_Vanish = false;
    m_Vanished = false;
    m_CanHaveFocus = m_HasFocus = false;
    m_Area = MythRect(0, 0, 0, 0);
    m_MinArea = MythRect(0, 0, 0, 0);
    m_NeedsRedraw = false;
    m_AlphaChangeMode = m_AlphaChange = m_AlphaMin = 0;
    m_AlphaMax = 255;
    m_Moving = false;
    m_XYDestination = QPoint(0, 0);
    m_XYSpeed = QPoint(0, 0);
    m_deferload = false;
    m_IsDependDefault = false;

    m_Parent = nullptr;

    if (parent)
    {
        m_Parent = dynamic_cast<MythUIType *>(parent);

        if (m_Parent)
            m_Parent->AddChild(this);
    }

    m_DirtyRegion = QRegion(QRect(0, 0, 0, 0));

    m_Fonts = new FontMap();
    m_focusOrder = 0;
    m_Painter = nullptr;

    m_BorderColor = QColor(random() % 255, random()  % 255, random()  % 255);
}
예제 #11
0
MythRect XMLParseBase::parseRect(const QString &text, bool normalize)
{
    MythRect retval;
    QStringList values = text.split(',', QString::SkipEmptyParts);
    if (values.size() == 4)
        retval = MythRect(values[0], values[1], values[2], values[3]);

     if (normalize)
         retval.NormRect();

    return retval;
}
예제 #12
0
void InteractiveScreen::UpdateArea(void)
{
    if (m_ChildrenList.isEmpty())
    {
        m_safeArea = QRect();
    }
    else if (m_player && m_player->getVideoOutput())
    {
        float tmp = 0.0;
        QRect dummy;
        m_player->getVideoOutput()->GetOSDBounds(dummy, m_safeArea, tmp, tmp, tmp);
    }
    SetArea(MythRect(m_safeArea));
}
예제 #13
0
void SubtitleScreen::EnableSubtitles(int type, bool forced_only)
{
    if (forced_only)
    {
        SetVisible(true);
        SetArea(MythRect());
        return;
    }

    m_subtitleType = type;
    if (m_subreader)
    {
        m_subreader->EnableAVSubtitles(kDisplayAVSubtitle == m_subtitleType);
        m_subreader->EnableTextSubtitles(kDisplayTextSubtitle == m_subtitleType);
        m_subreader->EnableRawTextSubtitles(kDisplayRawTextSubtitle == m_subtitleType);
    }
    if (m_608reader)
        m_608reader->SetEnabled(kDisplayCC608 == m_subtitleType);
    if (m_708reader)
        m_708reader->SetEnabled(kDisplayCC708 == m_subtitleType);
    ClearAllSubtitles();
    SetVisible(m_subtitleType != kDisplayNone);
    SetArea(MythRect());
}
예제 #14
0
void ImageProperties::Init()
{
    filename = QString();
    cropRect = MythRect(0, 0, 0, 0);
    forceSize = QSize(0, 0);
    preserveAspect = false;
    isGreyscale = false;
    isReflected = false;
    isMasked = false;
    isOriented = false;
    reflectAxis = ReflectVertical;
    reflectScale = 100;
    reflectLength = 100;
    reflectShear = 0;
    reflectSpacing = 0;
    orientation = 1;
    isThemeImage = false;
    maskImage = NULL;
}
예제 #15
0
void SubtitleScreen::DrawTextSubtitles(QStringList &wrappedsubs,
                                       uint64_t start, uint64_t duration)
{
    QFontMetrics font(*(gTextSubFont->GetFace()));
    int height = font.height() * (1 + PAD_HEIGHT);
    int pad_width = font.maxWidth() * PAD_WIDTH;
    int y = m_safeArea.height() - (height * wrappedsubs.size());
    int centre = m_safeArea.width() / 2;
    QBrush bgfill = QBrush(QColor(0, 0, 0), Qt::SolidPattern);
    foreach (QString subtitle, wrappedsubs)
    {
        if (subtitle.isEmpty())
            continue;
        int width = font.width(subtitle) + pad_width * 2;
        int x = centre - (width / 2) - pad_width;
        QRect rect(x, y, width, height);

        if (m_useBackground)
        {
            MythUIShape *shape = new MythUIShape(this,
                QString("tsubbg%1%2").arg(x).arg(y));
            shape->SetFillBrush(bgfill);
            shape->SetArea(MythRect(rect));
            if (duration > 0)
                m_expireTimes.insert(shape, start + duration);
        }
        MythUISimpleText* text = new MythUISimpleText
                                 (subtitle, *gTextSubFont, rect,
                                  Qt::AlignCenter, this,
                                  QString("tsub%1%2").arg(x).arg(y));
        y += height;
        LOG(VB_PLAYBACK, LOG_INFO, LOC + subtitle);
        m_refreshArea = true;

        if (duration > 0)
        {
            m_expireTimes.insert(text, start + duration);
            LOG(VB_PLAYBACK, LOG_INFO, LOC +
                QString("Display text subtitle for %1 ms").arg(duration));
        }
    }
}
예제 #16
0
/*!
 * \brief Initialise the tree having loaded the formatting options from the
 *        theme
 */
void MythUIButtonTree::Init()
{
    if (!m_listTemplate)
        m_listTemplate = dynamic_cast<MythUIButtonList *>
                         (GetChild("listtemplate"));

    if (!m_listTemplate)
    {
        LOG(VB_GENERAL, LOG_ERR, QString("(%1) MythUIButtonList listtemplate "
                                         "is required in mythuibuttonlist: %2")
            .arg(GetXMLLocation().arg(objectName())));
        return;
    }

    m_listTemplate->SetVisible(false);

    int width = (m_Area.width() - (m_listSpacing * (m_numLists - 1))) / m_numLists;
    int height = m_Area.height();

    int i = 0;

    while (i < (int)m_numLists)
    {
        QString listname = QString("buttontree list %1").arg(i);
        MythUIButtonList *list = new MythUIButtonList(this, listname);
        list->CopyFrom(m_listTemplate);
        list->SetVisible(false);
        list->SetActive(false);
        list->SetCanTakeFocus(false);
        int x = i * (width + m_listSpacing);
        MythRect listArea = MythRect(x, 0, width, height);
        list->SetArea(listArea);
        m_buttonlists.append(list);
        i++;
    }

    m_initialized = true;
}
예제 #17
0
void BDOverlayScreen::DisplayBDOverlay(BDOverlay *overlay)
{
    if (!overlay || !m_player)
        return;

    if (!overlay->m_data)
    {
        m_overlayArea = overlay->m_position;
        SetArea(MythRect(m_overlayArea));
        DeleteAllChildren();
        m_overlayMap.clear();
        SetRedraw();
        LOG(VB_PLAYBACK, LOG_INFO, LOC +
            QString("Initialised Size: %1x%2 (%3+%4) Plane: %5 Pts: %6")
                .arg(overlay->m_position.width())
                .arg(overlay->m_position.height())
                .arg(overlay->m_position.left())
                .arg(overlay->m_position.top())
                .arg(overlay->m_plane)
                .arg(overlay->m_pts));
        BDOverlay::DeleteOverlay(overlay);
        return;
    }

    if (!m_overlayArea.isValid())
    {
        LOG(VB_GENERAL, LOG_ERR, LOC +
            "Error: Overlay image submitted before initialisation.");
    }

    VideoOutput *vo = m_player->GetVideoOutput();
    if (!vo)
        return;

    QRect   rect = overlay->m_position;
    QString hash = QString("%1+%2+%3x%4")
                    .arg(rect.left()).arg(rect.top())
                    .arg(rect.width()).arg(rect.height());

    // remove if we already have this overlay
    if (m_overlayMap.contains(hash))
    {
        LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("Removing %1 (%2 left)")
            .arg(hash).arg(m_overlayMap.size()));
        MythUIImage *old = m_overlayMap.take(hash);
        DeleteChild(old);
    }

    // convert the overlay palette to ARGB
    uint32_t *origpalette = (uint32_t *)(overlay->m_palette);
    QVector<unsigned int> palette;
    for (int i = 0; i < 256; i++)
    {
        int y  = (origpalette[i] >> 0) & 0xff;
        int cr = (origpalette[i] >> 8) & 0xff;
        int cb = (origpalette[i] >> 16) & 0xff;
        int a  = (origpalette[i] >> 24) & 0xff;
        int r  = int(y + 1.4022 * (cr - 128));
        int b  = int(y + 1.7710 * (cb - 128));
        int g  = int(1.7047 * y - (0.1952 * b) - (0.5647 * r));
        if (r < 0) r = 0;
        if (g < 0) g = 0;
        if (b < 0) b = 0;
        if (r > 0xff) r = 0xff;
        if (g > 0xff) g = 0xff;
        if (b > 0xff) b = 0xff;
        palette.push_back((a << 24) | (r << 16) | (g << 8) | b);
    }

    // convert the image to QImage
    QImage img(rect.size(), QImage::Format_Indexed8);
    memcpy(img.bits(), overlay->m_data, rect.width() * rect.height());
    img.setColorTable(palette);
    img.convertToFormat(QImage::Format_ARGB32);

    // add to screen
    QRect scaled = vo->GetImageRect(rect);
    if (scaled.size() != rect.size())
    {
        img = img.scaled(scaled.width(), scaled.height(),
                         Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
    }

    MythPainter *osd_painter = vo->GetOSDPainter();
    MythImage* image = NULL;
    if (osd_painter)
         image = osd_painter->GetFormatImage();

    if (image)
    {
        image->Assign(img);
        MythUIImage *uiimage = new MythUIImage(this, "bdoverlay");
        if (uiimage)
        {
            uiimage->SetImage(image);
            uiimage->SetArea(MythRect(scaled));
            m_overlayMap.insert(hash, uiimage);
            LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("Added %1 (%2 tot)")
                .arg(hash).arg(m_overlayMap.size()));
        }
    }

    SetRedraw();
    BDOverlay::DeleteOverlay(overlay);
}
예제 #18
0
/**
 *  \brief Load the image(s), wraps ImageLoader::LoadImage()
 */
bool MythUIImage::Load(bool allowLoadInBackground, bool forceStat)
{
    d->m_UpdateLock.lockForRead();

    m_Initiator = m_EnableInitiator;

    QString bFilename = m_imageProperties.filename;
    bFilename.detach();

    d->m_UpdateLock.unlock();

    QString filename = bFilename;

    if (bFilename.isEmpty())
    {
        Clear();
        SetMinArea(MythRect());
        SetRedraw();

        return false;
    }

    if (getenv("DISABLETHREADEDMYTHUIIMAGE"))
        allowLoadInBackground = false;

    // Don't clear the widget before we need to, otherwise it causes
    // unsightly flashing. We exclude animations for now since that requires a
    // deeper fix
    bool isAnimation = (m_HighNum != m_LowNum) || m_animatedImage;

    if (isAnimation)
        Clear();

    QString imagelabel;

    int j = 0;

    for (int i = m_LowNum; i <= m_HighNum && !m_animatedImage; i++)
    {
        if (!m_animatedImage && m_HighNum != m_LowNum &&
            bFilename.contains("%1"))
            filename = bFilename.arg(i);

        ImageProperties imProps = m_imageProperties;
        imProps.filename = filename;
        imagelabel = ImageLoader::GenImageLabel(imProps);

        // Only load in the background if allowed and the image is
        // not already in our mem cache
        int cacheMode = kCacheIgnoreDisk;

        if (forceStat)
            cacheMode |= (int)kCacheForceStat;

        int cacheMode2 = kCacheNormal;

        if (forceStat)
            cacheMode2 |= (int)kCacheForceStat;

        bool do_background_load = false;
        if (allowLoadInBackground)
        {
            MythImage *img = GetMythUI()->LoadCacheImage(
                filename, imagelabel, GetPainter(),
                static_cast<ImageCacheMode>(cacheMode));
            if (img)
                img->DecrRef();
            else
                do_background_load = true;
        }

        if (do_background_load)
        {
            SetMinArea(MythRect());
            LOG(VB_GUI | VB_FILE, LOG_DEBUG, LOC +
                QString("Load(), spawning thread to load '%1'").arg(filename));

            m_runningThreads++;
            ImageLoadThread *bImgThread;
            bImgThread = new ImageLoadThread(this, GetPainter(),
                                             imProps,
                                             bFilename, i,
                                             static_cast<ImageCacheMode>(cacheMode2));
            GetMythUI()->GetImageThreadPool()->start(bImgThread, "ImageLoad");
        }
        else
        {
            if (!isAnimation && !GetMythUI()->IsImageInCache(imagelabel))
                Clear();

            // Perform a blocking load
            LOG(VB_GUI | VB_FILE, LOG_DEBUG, LOC +
                QString("Load(), loading '%1' in foreground").arg(filename));
            bool aborted = false;

            if (ImageLoader::SupportsAnimation(filename))
            {
                AnimationFrames *myFrames;

                myFrames = ImageLoader::LoadAnimatedImage(GetPainter(), imProps,
                                        static_cast<ImageCacheMode>(cacheMode2),
                                        this, aborted);

                // TODO We might want to handle an abort here more gracefully
                if (aborted)
                    LOG(VB_GUI, LOG_DEBUG, QString("Aborted loading animated"
                                                   "image %1 in foreground")
                                                                .arg(filename));

                SetAnimationFrames(*myFrames);

                delete myFrames;
            }
            else
            {
                MythImage *image = NULL;

                image = ImageLoader::LoadImage(GetPainter(),
                                               imProps,
                                               static_cast<ImageCacheMode>(cacheMode2),
                                               this, aborted);

                // TODO We might want to handle an abort here more gracefully
                if (aborted)
                    LOG(VB_GUI, LOG_DEBUG, QString("Aborted loading animated"
                                                   "image %1 in foreground")
                                                                .arg(filename));

                if (image)
                {
                    if (m_imageProperties.forceSize.isNull())
                        SetSize(image->size());

                    MythRect rect(GetFullArea());
                    rect.setSize(image->size());
                    SetMinArea(rect);

                    m_ImagesLock.lock();
                    m_Images[j] = image;
                    m_ImagesLock.unlock();

                    SetRedraw();
                    d->m_UpdateLock.lockForWrite();
                    m_LastDisplay = QTime::currentTime();
                    d->m_UpdateLock.unlock();
                }
                else
                {
                    Reset();

                    m_ImagesLock.lock();
                    m_Images[j] = NULL;
                    m_ImagesLock.unlock();
                }
            }
        }

        ++j;
    }

    return true;
}
예제 #19
0
void SubtitleScreen::DisplayAVSubtitles(void)
{
    if (!m_player || !m_subreader)
        return;

    AVSubtitles* subs = m_subreader->GetAVSubtitles();
    QMutexLocker lock(&(subs->lock));
    if (subs->buffers.empty() && (kDisplayAVSubtitle != m_subtitleType))
        return;

    VideoOutput    *videoOut = m_player->GetVideoOutput();
    VideoFrame *currentFrame = videoOut ? videoOut->GetLastShownFrame() : NULL;

    if (!currentFrame || !videoOut)
        return;

    float tmp = 0.0;
    QRect dummy;
    videoOut->GetOSDBounds(dummy, m_safeArea, tmp, tmp, tmp);

    while (!subs->buffers.empty())
    {
        const AVSubtitle subtitle = subs->buffers.front();
        if (subtitle.start_display_time > currentFrame->timecode)
            break;

        ClearDisplayedSubtitles();
        subs->buffers.pop_front();
        for (std::size_t i = 0; i < subtitle.num_rects; ++i)
        {
            AVSubtitleRect* rect = subtitle.rects[i];

            bool displaysub = true;
            if (subs->buffers.size() > 0 &&
                subs->buffers.front().end_display_time <
                currentFrame->timecode)
            {
                displaysub = false;
            }

            if (displaysub && rect->type == SUBTITLE_BITMAP)
            {
                // AVSubtitleRect's image data's not guaranteed to be 4 byte
                // aligned.

                QSize img_size(rect->w, rect->h);
                QRect img_rect(rect->x, rect->y, rect->w, rect->h);
                QRect display(rect->display_x, rect->display_y,
                              rect->display_w, rect->display_h);

                // XSUB and some DVD/DVB subs are based on the original video
                // size before the video was converted. We need to guess the
                // original size and allow for the difference

                int right  = rect->x + rect->w;
                int bottom = rect->y + rect->h;
                if (subs->fixPosition || (currentFrame->height < bottom) ||
                   (currentFrame->width  < right))
                {
                    int sd_height = 576;
                    if ((m_player->GetFrameRate() > 26.0f) && bottom <= 480)
                        sd_height = 480;
                    int height = ((currentFrame->height <= sd_height) &&
                                  (bottom <= sd_height)) ? sd_height :
                                 ((currentFrame->height <= 720) && bottom <= 720)
                                   ? 720 : 1080;
                    int width  = ((currentFrame->width  <= 720) &&
                                  (right <= 720)) ? 720 :
                                 ((currentFrame->width  <= 1280) &&
                                  (right <= 1280)) ? 1280 : 1920;
                    display = QRect(0, 0, width, height);
                }

                QRect scaled = videoOut->GetImageRect(img_rect, &display);
                QImage qImage(img_size, QImage::Format_ARGB32);
                for (int y = 0; y < rect->h; ++y)
                {
                    for (int x = 0; x < rect->w; ++x)
                    {
                        const uint8_t color = rect->pict.data[0][y*rect->pict.linesize[0] + x];
                        const uint32_t pixel = *((uint32_t*)rect->pict.data[1]+color);
                        qImage.setPixel(x, y, pixel);
                    }
                }

                if (scaled.size() != img_size)
                {
                    qImage = qImage.scaled(scaled.width(), scaled.height(),
                             Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
                }

                MythPainter *osd_painter = videoOut->GetOSDPainter();
                MythImage* image = NULL;
                if (osd_painter)
                   image = osd_painter->GetFormatImage();

                long long displayfor = subtitle.end_display_time -
                                       subtitle.start_display_time;
                if (displayfor == 0)
                    displayfor = 60000;
                displayfor = (displayfor < 50) ? 50 : displayfor;
                long long late = currentFrame->timecode -
                                 subtitle.start_display_time;
                MythUIImage *uiimage = NULL;
                if (image)
                {
                    image->Assign(qImage);
                    QString name = QString("avsub%1").arg(i);
                    uiimage = new MythUIImage(this, name);
                    if (uiimage)
                    {
                        m_refreshArea = true;
                        uiimage->SetImage(image);
                        uiimage->SetArea(MythRect(scaled));
                        m_expireTimes.insert(uiimage,
                                     currentFrame->timecode + displayfor);
                    }
                }
                if (uiimage)
                {
                    LOG(VB_PLAYBACK, LOG_INFO, LOC +
                        QString("Display %1AV subtitle for %2ms")
                        .arg(subtitle.forced ? "FORCED " : "")
                        .arg(displayfor));
                    if (late > 50)
                        LOG(VB_PLAYBACK, LOG_INFO, LOC +
                            QString("AV Sub was %1ms late").arg(late));
                }
            }
#ifdef USING_LIBASS
            else if (displaysub && rect->type == SUBTITLE_ASS)
            {
                InitialiseAssTrack(m_player->GetDecoder()->GetTrack(kTrackTypeSubtitle));
                AddAssEvent(rect->ass);
            }
#endif
        }
        m_subreader->FreeAVSubtitle(subtitle);
    }
#ifdef USING_LIBASS
    RenderAssTrack(currentFrame->timecode);
#endif
}
예제 #20
0
void SubtitleScreen::Display708Strings(const CC708Window &win, int num,
                                       float aspect, vector<CC708String*> &list)
{
    LOG(VB_VBI, LOG_INFO,LOC +
        QString("Display Win %1, Anchor_id %2, x_anch %3, y_anch %4, "
                "relative %5")
            .arg(num).arg(win.anchor_point).arg(win.anchor_horizontal)
            .arg(win.anchor_vertical).arg(win.relative_pos));

    bool display = false;
    MythFontProperties *mythfont;
    uint max_row_width = 0;
    uint total_height = 0;
    uint i = 0;
    for (uint row = 0; (row < win.true_row_count) && (i < list.size()); row++)
    {
        uint row_width = 0, max_row_height = 0;
        for (; (i < list.size()) && list[i] && (list[i]->y <= row); i++)
        {
            if (list[i]->y < row)
                continue;

            mythfont = Get708Font(list[i]->attr);
            if (!mythfont)
                continue;

            QString text = list[i]->str.trimmed();
            if (!text.isEmpty())
                display = true;

            QFontMetrics font(*(mythfont->GetFace()));
            uint height = (uint)font.height() * (1 + PAD_HEIGHT);

            row_width += font.width(list[i]->str) +
                         (font.maxWidth() * PAD_WIDTH * 2);
            max_row_height = max(max_row_height, height);
        }

        max_row_width = max(max_row_width, row_width);
        total_height += max_row_height;
    }

    if (!display)
        return;

    float xrange  = win.relative_pos ? 100.0f :
                    (aspect > 1.4f) ? 210.0f : 160.0f;
    float yrange  = win.relative_pos ? 100.0f : 75.0f;
    float xmult   = (float)m_safeArea.width() / xrange;
    float ymult   = (float)m_safeArea.height() / yrange;
    uint anchor_x = (uint)(xmult * (float)win.anchor_horizontal);
    uint anchor_y = (uint)(ymult * (float)win.anchor_vertical);

    if (win.anchor_point % 3 == 1)
        anchor_x -= (((int)max_row_width) / 2);
    if (win.anchor_point % 3 == 2)
        anchor_x -= (int)max_row_width;
    if (win.anchor_point / 3 == 1)
        anchor_y -= (((int)total_height) / 2);
    if (win.anchor_point / 3 == 2)
        anchor_y -= (int)total_height;

    if (win.GetFillAlpha()) // TODO border?
    {
        QRect bg(anchor_x, anchor_y, max_row_width, total_height);
        QBrush fill(win.GetFillColor(), Qt::SolidPattern);
        MythUIShape *shape = new MythUIShape(this,
                QString("cc708bg%1").arg(num));
        shape->SetFillBrush(fill);
        shape->SetArea(MythRect(bg));
        m_708imageCache[num].append(shape);
        m_refreshArea = true;
    }

    i = 0;
    int y = anchor_y;
    for (uint row = 0; (row < win.true_row_count) && (i < list.size()); row++)
    {
        uint maxheight = 0;
        int  x = anchor_x;
        bool first = true;
        for (; (i < list.size()) && list[i] && (list[i]->y <= row); i++)
        {
            bool last = ((i + 1) == list.size());
            if (!last)
                last = (list[i + 1]->y > row);

            QString rawstring = list[i]->str;
            mythfont = Get708Font(list[i]->attr);

            if ((list[i]->y < row) || !mythfont || rawstring.isEmpty())
                continue;

            QString trimmed = rawstring.trimmed();
            if (!trimmed.size() && last)
                continue;

            QFontMetrics font(*(mythfont->GetFace()));
            uint height = (uint)font.height() * (1 + PAD_HEIGHT);
            maxheight   = max(maxheight, height);
            uint spacewidth = font.width(QString(" "));
            uint textwidth  = font.width(trimmed);

            int leading  = 0;
            int trailing = 0;
            if (trimmed.size() != rawstring.size())
            {
                if (trimmed.size())
                {
                    leading  = rawstring.indexOf(trimmed.at(0));
                    trailing = rawstring.size() - trimmed.size() - leading;
                }
                else
                {
                    leading = rawstring.size();
                }
                leading  *= spacewidth;
                trailing *= spacewidth;
            }

            if (!leading)
                textwidth += spacewidth * PAD_WIDTH;
            if (!trailing)
                textwidth += spacewidth * PAD_WIDTH;

            bool background = list[i]->attr.GetBGAlpha();
            QBrush bgfill = QBrush((list[i]->attr.GetBGColor(), Qt::SolidPattern));

            if (leading && background && !first)
            {
                // draw background for leading space
                QRect space(x, y, leading, height);
                MythUIShape *shape = new MythUIShape(this,
                        QString("cc708shape%1x%2lead").arg(row).arg(i));
                shape->SetFillBrush(bgfill);
                shape->SetArea(MythRect(space));
                m_708imageCache[num].append(shape);
                m_refreshArea = true;
            }

            x += leading;
            QRect rect(x, y, textwidth, height);

            if (trimmed.size() && textwidth && background)
            {
                MythUIShape *shape = new MythUIShape(this,
                        QString("cc708shape%1x%2main").arg(row).arg(i));
                shape->SetFillBrush(bgfill);
                shape->SetArea(MythRect(rect));
                m_708imageCache[num].append(shape);
                m_refreshArea = true;
            }

            if (trimmed.size() && textwidth)
            {
                MythUIText *text = new MythUIText(list[i]->str, *mythfont,
                                                  rect, rect,
                                                  (MythUIType*)this,
                                                  QString("cc708text%1x%2").arg(row).arg(i));
                m_708imageCache[num].append(text);
                if (text)
                    text->SetJustification(Qt::AlignCenter);
                m_refreshArea = true;
            }

            x += textwidth;

            if (trailing && background && !last)
            {
                // draw background for trailing space
                QRect space(x, y, trailing, height);
                MythUIShape *shape = new MythUIShape(this,
                        QString("cc708shape%1x%2trail").arg(row).arg(i));
                shape->SetFillBrush(bgfill);
                shape->SetArea(MythRect(space));
                m_708imageCache[num].append(shape);
                m_refreshArea = true;
            }

            x += trailing;
            first = false;
            LOG(VB_VBI, LOG_INFO, QString("Win %1 row %2 String '%3'")
                .arg(num).arg(row).arg(list[i]->str));
        }
        y += maxheight;
    }
}
예제 #21
0
/**
 *  \brief Crop the image using the given rectangle, useful for removing
 *         unsightly edges from imported images or zoom effects
 */
void MythUIImage::SetCropRect(int x, int y, int width, int height)
{
    SetCropRect(MythRect(x, y, width, height));
}
예제 #22
0
void SubtitleScreen::DisplayCC608Subtitles(void)
{
    static const QColor clr[8] =
    {
        Qt::white,   Qt::red,     Qt::green, Qt::yellow,
        Qt::blue,    Qt::magenta, Qt::cyan,  Qt::white,
    };

    if (!InitialiseFont(m_fontStretch) || !m_608reader)
        return;

    bool changed = false;

    if (m_player && m_player->GetVideoOutput())
    {
        QRect oldsafe = m_safeArea;
        m_safeArea = m_player->GetVideoOutput()->GetSafeRect();
        if (oldsafe != m_safeArea)
            changed = true;
    }
    else
    {
        return;
    }

    CC608Buffer* textlist = m_608reader->GetOutputText(changed);
    if (!changed)
        return;
    if (textlist)
        textlist->lock.lock();
    DeleteAllChildren();
    if (!textlist)
        return;
    if (textlist && textlist->buffers.empty())
    {
        SetRedraw();
        textlist->lock.unlock();
        return;
    }

    vector<CC608Text*>::iterator i = textlist->buffers.begin();
    bool teletextmode = (*i)->teletextmode;
    int xscale = teletextmode ? 40 : 36;
    int yscale = teletextmode ? 25 : 17;
    gTextSubFont->GetFace()->setPixelSize(m_safeArea.height() / (yscale * 1.2));
    QFontMetrics font(*(gTextSubFont->GetFace()));
    QBrush bgfill = QBrush(QColor(0, 0, 0), Qt::SolidPattern);
    int height = font.height() * (1 + PAD_HEIGHT);
    int pad_width = font.maxWidth() * PAD_WIDTH;

    for (; i != textlist->buffers.end(); i++)
    {
        CC608Text *cc = (*i);

        if (cc && (cc->text != QString::null))
        {
            int width  = font.width(cc->text) + pad_width;
            int x = teletextmode ? cc->y : (cc->x + 3);
            int y = teletextmode ? cc->x : cc->y;
            x = (int)(((float)x / (float)xscale) * (float)m_safeArea.width());
            y = (int)(((float)y / (float)yscale) * (float)m_safeArea.height());
            QRect rect(x, y, width, height);

            if (!teletextmode && m_useBackground)
            {
                MythUIShape *shape = new MythUIShape(this,
                    QString("cc608bg%1%2%3").arg(cc->x).arg(cc->y).arg(width));
                shape->SetFillBrush(bgfill);
                QRect bgrect(x - pad_width, y, width + pad_width, height);
                shape->SetArea(MythRect(bgrect));
            }

            gTextSubFont->SetColor(clr[min(max(0, cc->color), 7)]);
            MythUIText *text = new MythUIText(
                   cc->text, *gTextSubFont, rect, rect, (MythUIType*)this,
                   QString("cc608txt%1%2%3").arg(cc->x).arg(cc->y).arg(width));
            if (text)
                text->SetJustification(Qt::AlignLeft);
            m_refreshArea = true;
            LOG(VB_VBI, LOG_INFO, QString("x %1 y %2 String: '%3'")
                                .arg(cc->x).arg(cc->y).arg(cc->text));
        }
    }
    textlist->lock.unlock();
}