Beispiel #1
0
int preview_helper(const QString &chanid, const QString &starttime,
                   long long previewFrameNumber, long long previewSeconds,
                   const QSize &previewSize,
                   const QString &infile, const QString &outfile)
{
    // Lower scheduling priority, to avoid problems with recordings.
    if (setpriority(PRIO_PROCESS, 0, 9))
        VERBOSE(VB_GENERAL, "Setting priority failed." + ENO);

    ProgramInfo *pginfo = NULL;
    if (!chanid.isEmpty() && !starttime.isEmpty())
    {
        pginfo = ProgramInfo::GetProgramFromRecorded(chanid, starttime);
        if (!pginfo)
        {
            VERBOSE(VB_IMPORTANT, QString(
                        "Can not locate recording made on '%1' at '%2'")
                    .arg(chanid).arg(starttime));
            return GENERIC_EXIT_NOT_OK;
        }
    }
    else if (!infile.isEmpty())
    {
        pginfo = ProgramInfo::GetProgramFromBasename(infile);
        if (!pginfo)
        {
            VERBOSE(VB_IMPORTANT, QString(
                        "Can not locate recording '%1'").arg(infile));
            return GENERIC_EXIT_NOT_OK;
        }
    }
    else
    {
        VERBOSE(VB_IMPORTANT, "Can not locate recording for preview");
        return GENERIC_EXIT_NOT_OK;
    }

    PreviewGenerator *previewgen = new PreviewGenerator(pginfo, true);

    if (previewFrameNumber >= 0)
        previewgen->SetPreviewTimeAsFrameNumber(previewFrameNumber);

    if (previewSeconds >= 0)
        previewgen->SetPreviewTimeAsSeconds(previewSeconds);

    previewgen->SetOutputSize(previewSize);
    previewgen->SetOutputFilename(outfile);
    previewgen->RunReal();
    previewgen->deleteLater();

    delete pginfo;

    return GENERIC_EXIT_OK;
}
Beispiel #2
0
QFileInfo Content::GetPreviewImage(        int        nChanId,
                                     const QDateTime &recstarttsRaw,
                                           int        nWidth,
                                           int        nHeight,
                                           int        nSecsIn )
{
    if (!recstarttsRaw.isValid())
    {
        QString sMsg = QString("GetPreviewImage: bad start time '%1'")
            .arg(MythDate::toString(recstarttsRaw, MythDate::ISODate));

        LOG(VB_GENERAL, LOG_ERR, sMsg);

        throw sMsg;
    }

    QDateTime recstartts = recstarttsRaw.toUTC();

    // ----------------------------------------------------------------------
    // Read Recording From Database
    // ----------------------------------------------------------------------

    ProgramInfo pginfo( (uint)nChanId, recstartts);

    if (!pginfo.GetChanID())
    {
        LOG(VB_GENERAL, LOG_ERR,
            QString("GetPreviewImage: No recording for '%1'")
            .arg(ProgramInfo::MakeUniqueKey(nChanId, recstartts)));
        return QFileInfo();
    }

    if (pginfo.GetHostname().toLower() != gCoreContext->GetHostName().toLower())
    {
        QString sMsg =
            QString("GetPreviewImage: Wrong Host '%1' request from '%2'")
                          .arg( gCoreContext->GetHostName())
                          .arg( pginfo.GetHostname() );

        LOG(VB_UPNP, LOG_ERR, sMsg);

        throw HttpRedirectException( pginfo.GetHostname() );
    }

    QString sFileName = GetPlaybackURL(&pginfo);

    // ----------------------------------------------------------------------
    // check to see if default preview image is already created.
    // ----------------------------------------------------------------------

    QString sPreviewFileName;

    if (nSecsIn <= 0)
    {
        nSecsIn = -1;
        sPreviewFileName = sFileName + ".png";
    }
    else
    {
        sPreviewFileName = QString("%1.%2.png").arg(sFileName).arg(nSecsIn);
    }

    if (!QFile::exists( sPreviewFileName ))
    {
        // ------------------------------------------------------------------
        // Must generate Preview Image, Generate Image and save.
        // ------------------------------------------------------------------
        if (!pginfo.IsLocal() && sFileName.startsWith("/"))
            pginfo.SetPathname(sFileName);

        if (!pginfo.IsLocal())
            return QFileInfo();

        PreviewGenerator *previewgen = new PreviewGenerator( &pginfo, 
                                                             QString(), 
                                                             PreviewGenerator::kLocal);
        previewgen->SetPreviewTimeAsSeconds( nSecsIn          );
        previewgen->SetOutputFilename      ( sPreviewFileName );

        bool ok = previewgen->Run();

        previewgen->deleteLater();

        if (!ok)
            return QFileInfo();
    }

    float fAspect = 0.0;

    QImage *pImage = new QImage(sPreviewFileName);

    if (!pImage)
        return QFileInfo();

    if (fAspect <= 0)
        fAspect = (float)(pImage->width()) / pImage->height();

    if (fAspect == 0)
    {
        delete pImage;
        return QFileInfo();
    }

    bool bDefaultPixmap = (nWidth == 0) && (nHeight == 0);

    if ( nWidth == 0 )
        nWidth = (int)rint(nHeight * fAspect);

    if ( nHeight == 0 )
        nHeight = (int)rint(nWidth / fAspect);

    QString sNewFileName;

    if (bDefaultPixmap)
        sNewFileName = sPreviewFileName;
    else
        sNewFileName = QString( "%1.%2.%3x%4.png" )
                          .arg( sFileName )
                          .arg( nSecsIn   )
                          .arg( nWidth    )
                          .arg( nHeight   );

    // ----------------------------------------------------------------------
    // check to see if scaled preview image is already created.
    // ----------------------------------------------------------------------

    if (QFile::exists( sNewFileName ))
    {
        delete pImage;
        return QFileInfo( sNewFileName );
    }

    PreviewGenerator *previewgen = new PreviewGenerator( &pginfo,
                                                         QString(),
                                                         PreviewGenerator::kLocal);
    previewgen->SetPreviewTimeAsSeconds( nSecsIn             );
    previewgen->SetOutputFilename      ( sNewFileName        );
    previewgen->SetOutputSize          (QSize(nWidth,nHeight));

    bool ok = previewgen->Run();

    previewgen->deleteLater();

    if (!ok)
        return QFileInfo();

    delete pImage;

    return QFileInfo( sNewFileName );
}
Beispiel #3
0
int preview_helper(uint chanid, QDateTime starttime,
                   long long previewFrameNumber, long long previewSeconds,
                   const QSize &previewSize,
                   const QString &infile, const QString &outfile)
{
    // Lower scheduling priority, to avoid problems with recordings.
    if (setpriority(PRIO_PROCESS, 0, 9))
        LOG(VB_GENERAL, LOG_ERR, "Setting priority failed." + ENO);

    if (!chanid || !starttime.isValid())
        ProgramInfo::QueryKeyFromPathname(infile, chanid, starttime);

    ProgramInfo *pginfo = NULL;
    if (chanid && starttime.isValid())
    {
        pginfo = new ProgramInfo(chanid, starttime);
        if (!pginfo->GetChanID())
        {
            LOG(VB_GENERAL, LOG_ERR,
                QString("Cannot locate recording made on '%1' at '%2'")
                .arg(chanid).arg(starttime.toString(Qt::ISODate)));
            delete pginfo;
            return GENERIC_EXIT_NOT_OK;
        }
        pginfo->SetPathname(pginfo->GetPlaybackURL(false, true));
    }
    else if (!infile.isEmpty())
    {
        if (!QFileInfo(infile).isReadable())
        {
            LOG(VB_GENERAL, LOG_ERR,
                QString("Cannot read this file '%1'").arg(infile));
            return GENERIC_EXIT_NOT_OK;
        }
        pginfo = new ProgramInfo(
            infile, ""/*plot*/, ""/*title*/, ""/*subtitle*/, ""/*director*/,
            0/*season*/, 0/*episode*/, ""/*inetref*/, 120/*length_in_minutes*/,
            1895/*year*/, ""/*id*/);
    }
    else
    {
        LOG(VB_GENERAL, LOG_ERR, "Cannot locate recording to preview");
        return GENERIC_EXIT_NOT_OK;
    }

    PreviewGenerator *previewgen = new PreviewGenerator(
        pginfo, QString(), PreviewGenerator::kLocal);

    if (previewFrameNumber >= 0)
        previewgen->SetPreviewTimeAsFrameNumber(previewFrameNumber);

    if (previewSeconds >= 0)
        previewgen->SetPreviewTimeAsSeconds(previewSeconds);

    previewgen->SetOutputSize(previewSize);
    previewgen->SetOutputFilename(outfile);
    bool ok = previewgen->RunReal();
    previewgen->deleteLater();

    delete pginfo;

    return (ok) ? GENERIC_EXIT_OK : GENERIC_EXIT_NOT_OK;
}
Beispiel #4
0
QString PreviewGeneratorQueue::GeneratePreviewImage(
    ProgramInfo &pginfo,
    const QSize &size,
    const QString &outputfile,
    long long time, bool in_seconds,
    QString token)
{
    QString key = QString("%1_%2x%3_%4%5")
        .arg(pginfo.GetBasename()).arg(size.width()).arg(size.height())
        .arg(time).arg(in_seconds?"s":"f");

    if (pginfo.GetAvailableStatus() == asPendingDelete)
    {
        SendEvent(pginfo, "PREVIEW_FAILED", key, token,
                  "Pending Delete", QDateTime());
        return QString();
    }

    QString filename = (outputfile.isEmpty()) ?
        pginfo.GetPathname() + ".png" : outputfile;
    QString ret_file = filename;
    QString ret;

    bool is_special = !outputfile.isEmpty() || time >= 0 ||
        size.width() || size.height();

    bool needs_gen = true;
    if (!is_special)
    {
        QDateTime previewLastModified;
        bool streaming = filename.left(1) != "/";
        bool locally_accessible = false;
        bool bookmark_updated = false;

        QDateTime bookmark_ts = pginfo.QueryBookmarkTimeStamp();
        QDateTime cmp_ts;
        if (bookmark_ts.isValid())
            cmp_ts = bookmark_ts;
        else if (MythDate::current() >= pginfo.GetRecordingEndTime())
            cmp_ts = pginfo.GetLastModifiedTime();
        else
            cmp_ts = pginfo.GetRecordingStartTime();

        if (streaming)
        {
            ret_file = QString("%1/remotecache/%2")
                .arg(GetConfDir()).arg(filename.section('/', -1));

            QFileInfo finfo(ret_file);
            if (finfo.isReadable() && finfo.lastModified() >= cmp_ts)
            {
                // This is just an optimization to avoid
                // hitting the backend if our cached copy
                // is newer than the bookmark, or if we have
                // a preview and do not update it when the
                // bookmark changes.
                previewLastModified = finfo.lastModified();
            }
            else if (!IsGeneratingPreview(key))
            {
                previewLastModified =
                    RemoteGetPreviewIfModified(pginfo, ret_file);
            }
        }
        else
        {
            QFileInfo fi(filename);
            if ((locally_accessible = fi.isReadable()))
                previewLastModified = fi.lastModified();
        }

        bookmark_updated =
            (!previewLastModified.isValid() || (previewLastModified <= cmp_ts));

        if (bookmark_updated && bookmark_ts.isValid() &&
            previewLastModified.isValid())
        {
            ClearPreviewGeneratorAttempts(key);
        }

        bool preview_exists = previewLastModified.isValid();

        if (0)
        {
            QString alttext = (bookmark_ts.isValid()) ? QString() :
                QString("\n\t\t\tcmp_ts:               %1")
                .arg(cmp_ts.toString(Qt::ISODate));
            LOG(VB_GENERAL, LOG_INFO,
                QString("previewLastModified:  %1\n\t\t\t"
                        "bookmark_ts:          %2%3\n\t\t\t"
                        "pginfo.lastmodified:  %4")
                    .arg(previewLastModified.toString(Qt::ISODate))
                    .arg(bookmark_ts.toString(Qt::ISODate))
                    .arg(alttext)
                    .arg(pginfo.GetLastModifiedTime(MythDate::ISODate)) +
                QString("Title: %1\n\t\t\t")
                    .arg(pginfo.toString(ProgramInfo::kTitleSubtitle)) +
                QString("File  '%1' \n\t\t\tCache '%2'")
                    .arg(filename).arg(ret_file) +
                QString("\n\t\t\tPreview Exists: %1, Bookmark Updated: %2, "
                        "Need Preview: %3")
                    .arg(preview_exists).arg(bookmark_updated)
                    .arg((bookmark_updated || !preview_exists)));
        }

        needs_gen = bookmark_updated || !preview_exists;

        if (!needs_gen)
        {
            if (locally_accessible)
                ret = filename;
            else if (preview_exists && QFileInfo(ret_file).isReadable())
                ret = ret_file;
        }
    }

    if (needs_gen && !IsGeneratingPreview(key))
    {
        uint attempts = IncPreviewGeneratorAttempts(key);
        if (attempts < m_maxAttempts)
        {
            LOG(VB_PLAYBACK, LOG_INFO, LOC +
                QString("Requesting preview for '%1'") .arg(key));
            PreviewGenerator *pg = new PreviewGenerator(&pginfo, token, m_mode);
            if (!outputfile.isEmpty() || time >= 0 ||
                size.width() || size.height())
            {
                pg->SetPreviewTime(time, in_seconds);
                pg->SetOutputFilename(outputfile);
                pg->SetOutputSize(size);
            }

            SetPreviewGenerator(key, pg);

            LOG(VB_PLAYBACK, LOG_INFO, LOC +
                QString("Requested preview for '%1'").arg(key));
        }
        else if (attempts >= m_maxAttempts)
        {
            LOG(VB_GENERAL, LOG_ERR, LOC +
                QString("Attempted to generate preview for '%1' "
                        "%2 times; >= max(%3)")
                    .arg(key).arg(attempts).arg(m_maxAttempts));
        }
    }
    else if (needs_gen)
    {
        LOG(VB_PLAYBACK, LOG_INFO, LOC +
            QString("Not requesting preview for %1,"
                    "as it is already being generated")
                .arg(pginfo.toString(ProgramInfo::kTitleSubtitle)));
        IncPreviewGeneratorPriority(key, token);
    }

    UpdatePreviewGeneratorThreads();

    if (!ret.isEmpty())
    {
        QString msg = "On Disk";
        QDateTime dt = QFileInfo(ret).lastModified();
        SendEvent(pginfo, "PREVIEW_SUCCESS", ret, token, msg, dt);
    }
    else
    {
        uint queue_depth, token_cnt;
        GetInfo(key, queue_depth, token_cnt);
        QString msg = QString("Queue depth %1, our tokens %2")
            .arg(queue_depth).arg(token_cnt);
        SendEvent(pginfo, "PREVIEW_QUEUED", ret, token, msg, QDateTime());
    }

    return ret;
}
Beispiel #5
0
int preview_helper(const QString &_chanid, const QString &starttime,
                   long long previewFrameNumber, long long previewSeconds,
                   const QSize &previewSize,
                   const QString &infile, const QString &outfile)
{
    // Lower scheduling priority, to avoid problems with recordings.
    if (setpriority(PRIO_PROCESS, 0, 9))
        VERBOSE(VB_GENERAL, "Setting priority failed." + ENO);

    uint chanid = _chanid.toUInt();
    QDateTime recstartts = myth_dt_from_string(starttime);
    if (!chanid || !recstartts.isValid())
        ProgramInfo::ExtractKeyFromPathname(infile, chanid, recstartts);

    ProgramInfo *pginfo = NULL;
    if (chanid && recstartts.isValid())
    {
        pginfo = new ProgramInfo(chanid, recstartts);
        if (!pginfo->GetChanID())
        {
            VERBOSE(VB_IMPORTANT, QString(
                        "Cannot locate recording made on '%1' at '%2'")
                    .arg(chanid).arg(starttime));
            delete pginfo;
            return PREVIEWGEN_EXIT_NOT_OK;
        }
        pginfo->SetPathname(pginfo->GetPlaybackURL(false, true));
    }
    else if (!infile.isEmpty())
    {
        if (!QFileInfo(infile).isReadable())
        {
            VERBOSE(VB_IMPORTANT, QString(
                        "Cannot read this file '%1'").arg(infile));
            return PREVIEWGEN_EXIT_NOT_OK;
        }
        pginfo = new ProgramInfo(
            infile, ""/*plot*/, ""/*title*/, ""/*subtitle*/, ""/*director*/,
            0/*season*/, 0/*episode*/, 120/*length_in_minutes*/,
            1895/*year*/);
    }
    else
    {
        VERBOSE(VB_IMPORTANT, "Cannot locate recording to preview");
        return PREVIEWGEN_EXIT_NOT_OK;
    }

    PreviewGenerator *previewgen = new PreviewGenerator(
        pginfo, QString(), PreviewGenerator::kLocal);

    if (previewFrameNumber >= 0)
        previewgen->SetPreviewTimeAsFrameNumber(previewFrameNumber);

    if (previewSeconds >= 0)
        previewgen->SetPreviewTimeAsSeconds(previewSeconds);

    previewgen->SetOutputSize(previewSize);
    previewgen->SetOutputFilename(outfile);
    bool ok = previewgen->RunReal();
    previewgen->deleteLater();

    delete pginfo;

    return (ok) ? PREVIEWGEN_EXIT_OK : PREVIEWGEN_EXIT_NOT_OK;
}
Beispiel #6
0
QFileInfo Content::GetPreviewImage(        int        nRecordedId,
                                           int        nChanId,
                                     const QDateTime &recstarttsRaw,
                                           int        nWidth,
                                           int        nHeight,
                                           int        nSecsIn,
                                     const QString   &sFormat )
{
    if ((nRecordedId <= 0) &&
        (nChanId <= 0 || !recstarttsRaw.isValid()))
        throw QString("Recorded ID or Channel ID and StartTime appears invalid.");

    if (!sFormat.isEmpty()
        && !QImageWriter::supportedImageFormats().contains(sFormat.toLower().toLocal8Bit()))
    {
        throw "GetPreviewImage: Specified 'Format' is not supported.";
    }

    // ----------------------------------------------------------------------
    // Read Recording From Database
    // ----------------------------------------------------------------------

    // TODO Should use RecordingInfo
    ProgramInfo pginfo;
    if (nRecordedId > 0)
        pginfo = ProgramInfo(nRecordedId);
    else
        pginfo = ProgramInfo(nChanId, recstarttsRaw.toUTC());

    if (!pginfo.GetChanID())
    {
        LOG(VB_GENERAL, LOG_ERR,
            QString("GetPreviewImage: No recording for '%1'")
            .arg(nRecordedId));
        return QFileInfo();
    }

    if (pginfo.GetHostname().toLower() != gCoreContext->GetHostName().toLower())
    {
        QString sMsg =
            QString("GetPreviewImage: Wrong Host '%1' request from '%2'")
                          .arg( gCoreContext->GetHostName())
                          .arg( pginfo.GetHostname() );

        LOG(VB_UPNP, LOG_ERR, sMsg);

        throw HttpRedirectException( pginfo.GetHostname() );
    }

    QString sImageFormat = sFormat;
    if (sImageFormat.isEmpty())
        sImageFormat = "PNG";

    QString sFileName = GetPlaybackURL(&pginfo);

    // ----------------------------------------------------------------------
    // check to see if default preview image is already created.
    // ----------------------------------------------------------------------

    QString sPreviewFileName;

    if (nSecsIn <= 0)
    {
        nSecsIn = -1;
        sPreviewFileName = QString("%1.png").arg(sFileName);
    }
    else
    {
        sPreviewFileName = QString("%1.%2.png").arg(sFileName).arg(nSecsIn);
    }

    if (!QFile::exists( sPreviewFileName ))
    {
        // ------------------------------------------------------------------
        // Must generate Preview Image, Generate Image and save.
        // ------------------------------------------------------------------
        if (!pginfo.IsLocal() && sFileName.startsWith("/"))
            pginfo.SetPathname(sFileName);

        if (!pginfo.IsLocal())
            return QFileInfo();

        PreviewGenerator *previewgen = new PreviewGenerator( &pginfo, 
                                                             QString(), 
                                                             PreviewGenerator::kLocal);
        previewgen->SetPreviewTimeAsSeconds( nSecsIn          );
        previewgen->SetOutputFilename      ( sPreviewFileName );

        bool ok = previewgen->Run();

        previewgen->deleteLater();

        if (!ok)
            return QFileInfo();
    }

    bool bDefaultPixmap = (nWidth == 0) && (nHeight == 0);

    QString sNewFileName;

    if (bDefaultPixmap)
        sNewFileName = sPreviewFileName;
    else
    {
        sNewFileName = QString( "%1.%2.%3x%4.%5" )
                          .arg( sFileName )
                          .arg( nSecsIn   )
                          .arg( nWidth == 0 ? -1 : nWidth )
                          .arg( nHeight == 0 ? -1 : nHeight )
                          .arg( sImageFormat.toLower() );

        // ----------------------------------------------------------------------
        // check to see if scaled preview image is already created and isn't
        // out of date
        // ----------------------------------------------------------------------
        if (QFile::exists( sNewFileName ))
        {
            if (QFileInfo(sPreviewFileName).lastModified() <=
                QFileInfo(sNewFileName).lastModified())
                return QFileInfo( sNewFileName );
        }

        QImage image = QImage(sPreviewFileName);

        if (image.isNull())
            return QFileInfo();

        // We can just re-scale the default (full-size version) to avoid
        // a preview generator run
        if ( nWidth <= 0 )
            image = image.scaledToHeight(nHeight, Qt::SmoothTransformation);
        else if ( nHeight <= 0 )
            image = image.scaledToWidth(nWidth, Qt::SmoothTransformation);
        else
            image = image.scaled(nWidth, nHeight, Qt::IgnoreAspectRatio,
                                        Qt::SmoothTransformation);

        image.save(sNewFileName, sImageFormat.toUpper().toLocal8Bit());

        // Let anybody update it
        bool ret = makeFileAccessible(sNewFileName.toLocal8Bit().constData());
        if (!ret)
        {
            LOG(VB_GENERAL, LOG_ERR, "Unable to change permissions on "
                                     "preview image. Backends and frontends "
                                     "running under different users will be "
                                     "unable to access it");
        }
    }

    if (QFile::exists( sNewFileName ))
        return QFileInfo( sNewFileName );

    PreviewGenerator *previewgen = new PreviewGenerator( &pginfo,
                                                         QString(),
                                                         PreviewGenerator::kLocal);
    previewgen->SetPreviewTimeAsSeconds( nSecsIn             );
    previewgen->SetOutputFilename      ( sNewFileName        );
    previewgen->SetOutputSize          (QSize(nWidth,nHeight));

    bool ok = previewgen->Run();

    previewgen->deleteLater();

    if (!ok)
        return QFileInfo();

    return QFileInfo( sNewFileName );
}