<commit_before>
/*
    pbrt source code Copyright(c) 1998-2012 Matt Pharr and Greg Humphreys.

    This file is part of pbrt.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are
    met:

    - Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

    - Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

 */

// film/image.cpp*
#include "stdafx.h"
#include "film/image.h"
#include "spectrum.h"
#include "parallel.h"
#include "imageio.h"

// ImageFilm Method Definitions
ImageFilm::ImageFilm(int xres, int yres, Filter *filt, const float crop[4],
                     const string &fn, bool openWindow)
    : Film(xres, yres) {
    filter = filt;
    memcpy(cropWindow, crop, 4 * sizeof(float));
    filename = fn;
    // Compute film image extent
    xPixelStart = Ceil2Int(xResolution * cropWindow[0]);
    xPixelCount = max(1, Ceil2Int(xResolution * cropWindow[1]) - xPixelStart);
    yPixelStart = Ceil2Int(yResolution * cropWindow[2]);
    yPixelCount = max(1, Ceil2Int(yResolution * cropWindow[3]) - yPixelStart);

    // Allocate film image storage
    pixels = new BlockedArray<Pixel>(xPixelCount, yPixelCount);

    // Precompute filter weight table
#define FILTER_TABLE_SIZE 16
    filterTable = new float[FILTER_TABLE_SIZE * FILTER_TABLE_SIZE];
    float *ftp = filterTable;
    for (int y = 0; y < FILTER_TABLE_SIZE; ++y) {
        float fy = ((float)y + .5f) *
                   filter->yWidth / FILTER_TABLE_SIZE;
        for (int x = 0; x < FILTER_TABLE_SIZE; ++x) {
            float fx = ((float)x + .5f) *
                       filter->xWidth / FILTER_TABLE_SIZE;
            *ftp++ = filter->Evaluate(fx, fy);
        }
    }

    // Possibly open window for image display
    if (openWindow || PbrtOptions.openWindow) {
        Warning("Support for opening image display window not available in this build.");
    }
}

void ImageFilm::AddSample(const CameraSample &sample,
                          const Spectrum &L) {
    // Compute sample's raster extent
    float dimageX = sample.imageX - 0.5f;
    float dimageY = sample.imageY - 0.5f;
    int x0 = Ceil2Int (dimageX - filter->xWidth);
    int x1 = Floor2Int(dimageX + filter->xWidth);
    int y0 = Ceil2Int (dimageY - filter->yWidth);
    int y1 = Floor2Int(dimageY + filter->yWidth);
    x0 = max(x0, xPixelStart);
    x1 = min(x1, xPixelStart + xPixelCount - 1);
    y0 = max(y0, yPixelStart);
    y1 = min(y1, yPixelStart + yPixelCount - 1);
    if ((x1-x0) < 0 || (y1-y0) < 0)
    {
        PBRT_SAMPLE_OUTSIDE_IMAGE_EXTENT(const_cast<CameraSample *>(&sample));
        return;
    }

    // Loop over filter support and add sample to pixel arrays
    float xyz[3];
    L.ToXYZ(xyz);

    // Precompute $x$ and $y$ filter table offsets
    int *ifx = ALLOCA(int, x1 - x0 + 1);
    for (int x = x0; x <= x1; ++x) {
        float fx = fabsf((x - dimageX) *
                         filter->invXWidth * FILTER_TABLE_SIZE);
        ifx[x-x0] = min(Floor2Int(fx), FILTER_TABLE_SIZE-1);
    }
    int *ify = ALLOCA(int, y1 - y0 + 1);
    for (int y = y0; y <= y1; ++y) {
        float fy = fabsf((y - dimageY) *
                         filter->invYWidth * FILTER_TABLE_SIZE);
        ify[y-y0] = min(Floor2Int(fy), FILTER_TABLE_SIZE-1);
    }
    bool syncNeeded = (filter->xWidth > 0.5f || filter->yWidth > 0.5f);
    for (int y = y0; y <= y1; ++y) {
        for (int x = x0; x <= x1; ++x) {
            // Evaluate filter value at $(x,y)$ pixel
            int offset = ify[y-y0]*FILTER_TABLE_SIZE + ifx[x-x0];
            float filterWt = filterTable[offset];

            // Update pixel values with filtered sample contribution
            Pixel &pixel = (*pixels)(x - xPixelStart, y - yPixelStart);
            if (!syncNeeded) {
                pixel.Lxyz[0] += filterWt * xyz[0];
                pixel.Lxyz[1] += filterWt * xyz[1];
                pixel.Lxyz[2] += filterWt * xyz[2];
                pixel.weightSum += filterWt;
            }
            else {
                // Safely update _Lxyz_ and _weightSum_ even with concurrency
                AtomicAdd(&pixel.Lxyz[0], filterWt * xyz[0]);
                AtomicAdd(&pixel.Lxyz[1], filterWt * xyz[1]);
                AtomicAdd(&pixel.Lxyz[2], filterWt * xyz[2]);
                AtomicAdd(&pixel.weightSum, filterWt);
            }
        }
    }
}

void ImageFilm::Splat(const CameraSample &sample, const Spectrum &L) {
    if (L.HasNaNs()) {
        Warning("ImageFilm ignoring splatted spectrum with NaN values");
        return;
    }
    float xyz[3];
    L.ToXYZ(xyz);
    int x = Floor2Int(sample.imageX), y = Floor2Int(sample.imageY);
    if (x < xPixelStart || x - xPixelStart >= xPixelCount ||
        y < yPixelStart || y - yPixelStart >= yPixelCount) return;
    Pixel &pixel = (*pixels)(x - xPixelStart, y - yPixelStart);
    AtomicAdd(&pixel.splatXYZ[0], xyz[0]);
    AtomicAdd(&pixel.splatXYZ[1], xyz[1]);
    AtomicAdd(&pixel.splatXYZ[2], xyz[2]);
}

void ImageFilm::GetSampleExtent(int *xstart, int *xend,
                                int *ystart, int *yend) const {
    *xstart = Floor2Int(xPixelStart + 0.5f - filter->xWidth);
    *xend   = Floor2Int(xPixelStart + 0.5f + xPixelCount  +
                        filter->xWidth);

    *ystart = Floor2Int(yPixelStart + 0.5f - filter->yWidth);
    *yend   = Floor2Int(yPixelStart + 0.5f + yPixelCount +
                        filter->yWidth);
}

void ImageFilm::GetPixelExtent(int *xstart, int *xend,
                               int *ystart, int *yend) const {
    *xstart = xPixelStart;
    *xend   = xPixelStart + xPixelCount;
    *ystart = yPixelStart;
    *yend   = yPixelStart + yPixelCount;
}

void ImageFilm::WriteImage(float splatScale) {
    // Convert image to RGB and compute final pixel values
    int nPix = xPixelCount * yPixelCount;
    float *rgb = new float[3*nPix];
    int offset = 0;
    for (int y = 0; y < yPixelCount; ++y) {
        for (int x = 0; x < xPixelCount; ++x) {
            // Convert pixel XYZ color to RGB
            XYZToRGB((*pixels)(x, y).Lxyz, &rgb[3*offset]);

            // Normalize pixel with weight sum
            float weightSum = (*pixels)(x, y).weightSum;
            if (weightSum != 0.f) {
                float invWt = 1.f / weightSum;
                rgb[3*offset  ] = max(0.f, rgb[3*offset  ] * invWt);
                rgb[3*offset+1] = max(0.f, rgb[3*offset+1] * invWt);
                rgb[3*offset+2] = max(0.f, rgb[3*offset+2] * invWt);
            }

            // Add splat value at pixel
            float splatRGB[3];
            XYZToRGB((*pixels)(x, y).splatXYZ, splatRGB);
            rgb[3*offset  ] += splatScale * splatRGB[0];
            rgb[3*offset+1] += splatScale * splatRGB[1];
            rgb[3*offset+2] += splatScale * splatRGB[2];
            ++offset;
        }
    }

    // Write RGB image
    ::WriteImage(filename, rgb, NULL, xPixelCount, yPixelCount,
                 xResolution, yResolution, xPixelStart, yPixelStart);

    // Release temporary image memory
    delete[] rgb;
}

void ImageFilm::UpdateDisplay(int x0, int y0, int x1, int y1,
    float splatScale) {
}

ImageFilm *CreateImageFilm(const ParamSet &params, Filter *filter) {
    string filename = params.FindOneString("filename", "");
    if (PbrtOptions.imageFile != "") {
        if (filename != "") {
            Warning("Output filename supplied on command line, \"%s\", ignored "
                    "due to filename provided in scene description file, \"%s\".",
                    PbrtOptions.imageFile.c_str(), filename.c_str());
        }
        else
            filename = PbrtOptions.imageFile;
    }
    if (filename == "")
#ifdef PBRT_HAS_OPENEXR
        filename = "pbrt.exr";
#else
        filename = "pbrt.tga";
#endif

    int xres = params.FindOneInt("xresolution", 640);
    int yres = params.FindOneInt("yresolution", 480);
    if (PbrtOptions.quickRender) xres = max(1, xres / 4);
    if (PbrtOptions.quickRender) yres = max(1, yres / 4);
    bool openwin = params.FindOneBool("display", false);
    float crop[4] = { 0, 1, 0, 1 };
    int cwi;
    const float *cr = params.FindFloat("cropwindow", &cwi);
    if (cr && cwi == 4) {
        crop[0] = Clamp(min(cr[0], cr[1]), 0., 1.);
        crop[1] = Clamp(max(cr[0], cr[1]), 0., 1.);
        crop[2] = Clamp(min(cr[2], cr[3]), 0., 1.);
        crop[3] = Clamp(max(cr[2], cr[3]), 0., 1.);
    }

    return new ImageFilm(xres, yres, filter, crop, filename, openwin);
}

<commit_msg>Fix bug in ImageFilm::GetSampleExtent() <commit_after>
/*
    pbrt source code Copyright(c) 1998-2012 Matt Pharr and Greg Humphreys.

    This file is part of pbrt.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are
    met:

    - Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

    - Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

 */

// film/image.cpp*
#include "stdafx.h"
#include "film/image.h"
#include "spectrum.h"
#include "parallel.h"
#include "imageio.h"

// ImageFilm Method Definitions
ImageFilm::ImageFilm(int xres, int yres, Filter *filt, const float crop[4],
                     const string &fn, bool openWindow)
    : Film(xres, yres) {
    filter = filt;
    memcpy(cropWindow, crop, 4 * sizeof(float));
    filename = fn;
    // Compute film image extent
    xPixelStart = Ceil2Int(xResolution * cropWindow[0]);
    xPixelCount = max(1, Ceil2Int(xResolution * cropWindow[1]) - xPixelStart);
    yPixelStart = Ceil2Int(yResolution * cropWindow[2]);
    yPixelCount = max(1, Ceil2Int(yResolution * cropWindow[3]) - yPixelStart);

    // Allocate film image storage
    pixels = new BlockedArray<Pixel>(xPixelCount, yPixelCount);

    // Precompute filter weight table
#define FILTER_TABLE_SIZE 16
    filterTable = new float[FILTER_TABLE_SIZE * FILTER_TABLE_SIZE];
    float *ftp = filterTable;
    for (int y = 0; y < FILTER_TABLE_SIZE; ++y) {
        float fy = ((float)y + .5f) *
                   filter->yWidth / FILTER_TABLE_SIZE;
        for (int x = 0; x < FILTER_TABLE_SIZE; ++x) {
            float fx = ((float)x + .5f) *
                       filter->xWidth / FILTER_TABLE_SIZE;
            *ftp++ = filter->Evaluate(fx, fy);
        }
    }

    // Possibly open window for image display
    if (openWindow || PbrtOptions.openWindow) {
        Warning("Support for opening image display window not available in this build.");
    }
}

void ImageFilm::AddSample(const CameraSample &sample,
                          const Spectrum &L) {
    // Compute sample's raster extent
    float dimageX = sample.imageX - 0.5f;
    float dimageY = sample.imageY - 0.5f;
    int x0 = Ceil2Int (dimageX - filter->xWidth);
    int x1 = Floor2Int(dimageX + filter->xWidth);
    int y0 = Ceil2Int (dimageY - filter->yWidth);
    int y1 = Floor2Int(dimageY + filter->yWidth);
    x0 = max(x0, xPixelStart);
    x1 = min(x1, xPixelStart + xPixelCount - 1);
    y0 = max(y0, yPixelStart);
    y1 = min(y1, yPixelStart + yPixelCount - 1);
    if ((x1-x0) < 0 || (y1-y0) < 0)
    {
        PBRT_SAMPLE_OUTSIDE_IMAGE_EXTENT(const_cast<CameraSample *>(&sample));
        return;
    }

    // Loop over filter support and add sample to pixel arrays
    float xyz[3];
    L.ToXYZ(xyz);

    // Precompute $x$ and $y$ filter table offsets
    int *ifx = ALLOCA(int, x1 - x0 + 1);
    for (int x = x0; x <= x1; ++x) {
        float fx = fabsf((x - dimageX) *
                         filter->invXWidth * FILTER_TABLE_SIZE);
        ifx[x-x0] = min(Floor2Int(fx), FILTER_TABLE_SIZE-1);
    }
    int *ify = ALLOCA(int, y1 - y0 + 1);
    for (int y = y0; y <= y1; ++y) {
        float fy = fabsf((y - dimageY) *
                         filter->invYWidth * FILTER_TABLE_SIZE);
        ify[y-y0] = min(Floor2Int(fy), FILTER_TABLE_SIZE-1);
    }
    bool syncNeeded = (filter->xWidth > 0.5f || filter->yWidth > 0.5f);
    for (int y = y0; y <= y1; ++y) {
        for (int x = x0; x <= x1; ++x) {
            // Evaluate filter value at $(x,y)$ pixel
            int offset = ify[y-y0]*FILTER_TABLE_SIZE + ifx[x-x0];
            float filterWt = filterTable[offset];

            // Update pixel values with filtered sample contribution
            Pixel &pixel = (*pixels)(x - xPixelStart, y - yPixelStart);
            if (!syncNeeded) {
                pixel.Lxyz[0] += filterWt * xyz[0];
                pixel.Lxyz[1] += filterWt * xyz[1];
                pixel.Lxyz[2] += filterWt * xyz[2];
                pixel.weightSum += filterWt;
            }
            else {
                // Safely update _Lxyz_ and _weightSum_ even with concurrency
                AtomicAdd(&pixel.Lxyz[0], filterWt * xyz[0]);
                AtomicAdd(&pixel.Lxyz[1], filterWt * xyz[1]);
                AtomicAdd(&pixel.Lxyz[2], filterWt * xyz[2]);
                AtomicAdd(&pixel.weightSum, filterWt);
            }
        }
    }
}

void ImageFilm::Splat(const CameraSample &sample, const Spectrum &L) {
    if (L.HasNaNs()) {
        Warning("ImageFilm ignoring splatted spectrum with NaN values");
        return;
    }
    float xyz[3];
    L.ToXYZ(xyz);
    int x = Floor2Int(sample.imageX), y = Floor2Int(sample.imageY);
    if (x < xPixelStart || x - xPixelStart >= xPixelCount ||
        y < yPixelStart || y - yPixelStart >= yPixelCount) return;
    Pixel &pixel = (*pixels)(x - xPixelStart, y - yPixelStart);
    AtomicAdd(&pixel.splatXYZ[0], xyz[0]);
    AtomicAdd(&pixel.splatXYZ[1], xyz[1]);
    AtomicAdd(&pixel.splatXYZ[2], xyz[2]);
}

void ImageFilm::GetSampleExtent(int *xstart, int *xend,
                                int *ystart, int *yend) const {
    *xstart = Floor2Int(xPixelStart + 0.5f - filter->xWidth);
    *xend   = Ceil2Int(xPixelStart + 0.5f + xPixelCount +
                       filter->xWidth);

    *ystart = Floor2Int(yPixelStart + 0.5f - filter->yWidth);
    *yend   = Ceil2Int(yPixelStart + 0.5f + yPixelCount +
                       filter->yWidth);
}

void ImageFilm::GetPixelExtent(int *xstart, int *xend,
                               int *ystart, int *yend) const {
    *xstart = xPixelStart;
    *xend   = xPixelStart + xPixelCount;
    *ystart = yPixelStart;
    *yend   = yPixelStart + yPixelCount;
}

void ImageFilm::WriteImage(float splatScale) {
    // Convert image to RGB and compute final pixel values
    int nPix = xPixelCount * yPixelCount;
    float *rgb = new float[3*nPix];
    int offset = 0;
    for (int y = 0; y < yPixelCount; ++y) {
        for (int x = 0; x < xPixelCount; ++x) {
            // Convert pixel XYZ color to RGB
            XYZToRGB((*pixels)(x, y).Lxyz, &rgb[3*offset]);

            // Normalize pixel with weight sum
            float weightSum = (*pixels)(x, y).weightSum;
            if (weightSum != 0.f) {
                float invWt = 1.f / weightSum;
                rgb[3*offset  ] = max(0.f, rgb[3*offset  ] * invWt);
                rgb[3*offset+1] = max(0.f, rgb[3*offset+1] * invWt);
                rgb[3*offset+2] = max(0.f, rgb[3*offset+2] * invWt);
            }

            // Add splat value at pixel
            float splatRGB[3];
            XYZToRGB((*pixels)(x, y).splatXYZ, splatRGB);
            rgb[3*offset  ] += splatScale * splatRGB[0];
            rgb[3*offset+1] += splatScale * splatRGB[1];
            rgb[3*offset+2] += splatScale * splatRGB[2];
            ++offset;
        }
    }

    // Write RGB image
    ::WriteImage(filename, rgb, NULL, xPixelCount, yPixelCount,
                 xResolution, yResolution, xPixelStart, yPixelStart);

    // Release temporary image memory
    delete[] rgb;
}

void ImageFilm::UpdateDisplay(int x0, int y0, int x1, int y1,
    float splatScale) {
}

ImageFilm *CreateImageFilm(const ParamSet &params, Filter *filter) {
    string filename = params.FindOneString("filename", "");
    if (PbrtOptions.imageFile != "") {
        if (filename != "") {
            Warning("Output filename supplied on command line, \"%s\", ignored "
                    "due to filename provided in scene description file, \"%s\".",
                    PbrtOptions.imageFile.c_str(), filename.c_str());
        }
        else
            filename = PbrtOptions.imageFile;
    }
    if (filename == "")
#ifdef PBRT_HAS_OPENEXR
        filename = "pbrt.exr";
#else
        filename = "pbrt.tga";
#endif

    int xres = params.FindOneInt("xresolution", 640);
    int yres = params.FindOneInt("yresolution", 480);
    if (PbrtOptions.quickRender) xres = max(1, xres / 4);
    if (PbrtOptions.quickRender) yres = max(1, yres / 4);
    bool openwin = params.FindOneBool("display", false);
    float crop[4] = { 0, 1, 0, 1 };
    int cwi;
    const float *cr = params.FindFloat("cropwindow", &cwi);
    if (cr && cwi == 4) {
        crop[0] = Clamp(min(cr[0], cr[1]), 0., 1.);
        crop[1] = Clamp(max(cr[0], cr[1]), 0., 1.);
        crop[2] = Clamp(min(cr[2], cr[3]), 0., 1.);
        crop[3] = Clamp(max(cr[2], cr[3]), 0., 1.);
    }

    return new ImageFilm(xres, yres, filter, crop, filename, openwin);
}

<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qgeotiledmaprouteobjectinfo_p.h"

#include "qgeotiledmapdata.h"
#include "qgeotiledmapdata_p.h"

#include "qgeomaprouteobject.h"

#include "qgeoroutesegment.h"

#include <QPointF>

QTM_BEGIN_NAMESPACE

QGeoTiledMapRouteObjectInfo::QGeoTiledMapRouteObjectInfo(QGeoMapData *mapData, QGeoMapObject *mapObject)
        : QGeoTiledMapObjectInfo(mapData, mapObject)
{
    route = static_cast<QGeoMapRouteObject*>(mapObject);

    connect(route,
            SIGNAL(routeChanged(QGeoRoute)),
            this,
            SLOT(routeChanged(QGeoRoute)));
    connect(route,
            SIGNAL(penChanged(QPen)),
            this,
            SLOT(penChanged(QPen)));
    connect(route,
            SIGNAL(detailLevelChanged(quint32)),
            this,
            SLOT(detailLevelChanged(quint32)));

    pathItem = new QGraphicsPathItem();
    graphicsItem = pathItem;

    penChanged(route->pen());
    routeChanged(route->route());
}

QGeoTiledMapRouteObjectInfo::~QGeoTiledMapRouteObjectInfo() {}

void QGeoTiledMapRouteObjectInfo::routeChanged(const QGeoRoute &route)
{
    QListIterator<QGeoRouteSegment> segIt(this->route->route().routeSegments());

    while (segIt.hasNext()) {
        QListIterator<QGeoCoordinate> coordIt(segIt.next().path());
        while (coordIt.hasNext()) {
            QGeoCoordinate coord = coordIt.next();

            if (!coord.isValid())
                continue;

            points.append(tiledMapData->coordinateToWorldPixel(coord));
        }
    }

    updateData();
}

void QGeoTiledMapRouteObjectInfo::penChanged(const QPen &pen)
{
    pathItem->setPen(route->pen());
    updateItem();
}

void QGeoTiledMapRouteObjectInfo::detailLevelChanged(quint32 detailLevel)
{
    updateData();
}

void QGeoTiledMapRouteObjectInfo::zoomLevelChanged(qreal zoomLevel)
{
    updateData();
}

void QGeoTiledMapRouteObjectInfo::updateData()
{
    distanceFilteredPoints.clear();

    QPointF lastPoint = points.at(0);
    distanceFilteredPoints.append(points.at(0));
    for (int i = 1; i < points.size() - 1; ++i) {
        if ((lastPoint - points.at(i)).manhattanLength() >= route->detailLevel() * tiledMapData->zoomFactor()) {
            distanceFilteredPoints.append(points.at(i));
            lastPoint = points.at(i);
        }
    }

    distanceFilteredPoints.append(points.at(points.size() - 1));

    setValid((distanceFilteredPoints.size() >= 2));

    if (valid())
        updateVisible();
}

void QGeoTiledMapRouteObjectInfo::windowSizeChanged(const QSizeF &windowSize)
{
    if (valid())
        updateVisible();
}

void QGeoTiledMapRouteObjectInfo::centerChanged(const QGeoCoordinate &coordinate)
{
    if (valid())
        updateVisible();
}

void QGeoTiledMapRouteObjectInfo::updateVisible()
{
    QPainterPath painterPath;

    bool offScreen = true;

    for (int i = 0; i < distanceFilteredPoints.size() - 1; ++i) {
        if (!offScreen)
            painterPath.lineTo(distanceFilteredPoints.at(i));

        bool wasOffScreen = offScreen;

        QPointF point1 = distanceFilteredPoints.at(i);
        QPointF point2 = distanceFilteredPoints.at(i + 1);
        QPointF midpoint = (point1 + point2) / 2.0;

        QRect maxZoomScreenRect = tiledMapData->maxZoomScreenRect();

        offScreen = !(maxZoomScreenRect.contains(point1.toPoint())
                      || maxZoomScreenRect.contains(point2.toPoint())
                      || maxZoomScreenRect.contains(midpoint.toPoint()));

        if (wasOffScreen && !offScreen)
            painterPath.moveTo(distanceFilteredPoints.at(i));
    }

    pathItem->setPath(painterPath);
    updateItem();
}

#include "moc_qgeotiledmaprouteobjectinfo_p.cpp"

QTM_END_NAMESPACE

<commit_msg>Fix tiled route object not drawing the last bit of route<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qgeotiledmaprouteobjectinfo_p.h"

#include "qgeotiledmapdata.h"
#include "qgeotiledmapdata_p.h"

#include "qgeomaprouteobject.h"

#include "qgeoroutesegment.h"

#include <QPointF>

QTM_BEGIN_NAMESPACE

QGeoTiledMapRouteObjectInfo::QGeoTiledMapRouteObjectInfo(QGeoMapData *mapData, QGeoMapObject *mapObject)
        : QGeoTiledMapObjectInfo(mapData, mapObject)
{
    route = static_cast<QGeoMapRouteObject*>(mapObject);

    connect(route,
            SIGNAL(routeChanged(QGeoRoute)),
            this,
            SLOT(routeChanged(QGeoRoute)));
    connect(route,
            SIGNAL(penChanged(QPen)),
            this,
            SLOT(penChanged(QPen)));
    connect(route,
            SIGNAL(detailLevelChanged(quint32)),
            this,
            SLOT(detailLevelChanged(quint32)));

    pathItem = new QGraphicsPathItem();
    graphicsItem = pathItem;

    penChanged(route->pen());
    routeChanged(route->route());
}

QGeoTiledMapRouteObjectInfo::~QGeoTiledMapRouteObjectInfo() {}

void QGeoTiledMapRouteObjectInfo::routeChanged(const QGeoRoute &route)
{
    QListIterator<QGeoRouteSegment> segIt(this->route->route().routeSegments());

    while (segIt.hasNext()) {
        QListIterator<QGeoCoordinate> coordIt(segIt.next().path());
        while (coordIt.hasNext()) {
            QGeoCoordinate coord = coordIt.next();

            if (!coord.isValid())
                continue;

            points.append(tiledMapData->coordinateToWorldPixel(coord));
        }
    }

    updateData();
}

void QGeoTiledMapRouteObjectInfo::penChanged(const QPen &pen)
{
    pathItem->setPen(route->pen());
    updateItem();
}

void QGeoTiledMapRouteObjectInfo::detailLevelChanged(quint32 detailLevel)
{
    updateData();
}

void QGeoTiledMapRouteObjectInfo::zoomLevelChanged(qreal zoomLevel)
{
    updateData();
}

void QGeoTiledMapRouteObjectInfo::updateData()
{
    distanceFilteredPoints.clear();

    QPointF lastPoint = points.at(0);
    distanceFilteredPoints.append(points.at(0));
    for (int i = 1; i < points.size(); ++i) {
        if ((lastPoint - points.at(i)).manhattanLength() >= route->detailLevel() * tiledMapData->zoomFactor()) {
            distanceFilteredPoints.append(points.at(i));
            lastPoint = points.at(i);
        }
    }

    distanceFilteredPoints.append(points.at(points.size() - 1));

    setValid((distanceFilteredPoints.size() >= 2));

    if (valid())
        updateVisible();
}

void QGeoTiledMapRouteObjectInfo::windowSizeChanged(const QSizeF &windowSize)
{
    if (valid())
        updateVisible();
}

void QGeoTiledMapRouteObjectInfo::centerChanged(const QGeoCoordinate &coordinate)
{
    if (valid())
        updateVisible();
}

void QGeoTiledMapRouteObjectInfo::updateVisible()
{
    QPainterPath painterPath;

    bool offScreen = true;

    for (int i = 0; i < distanceFilteredPoints.size() - 1; ++i) {
        if (!offScreen)
            painterPath.lineTo(distanceFilteredPoints.at(i));

        bool wasOffScreen = offScreen;

        QPointF point1 = distanceFilteredPoints.at(i);
        QPointF point2 = distanceFilteredPoints.at(i + 1);
        QPointF midpoint = (point1 + point2) / 2.0;

        QRect maxZoomScreenRect = tiledMapData->maxZoomScreenRect();

        offScreen = !(maxZoomScreenRect.contains(point1.toPoint())
                      || maxZoomScreenRect.contains(point2.toPoint())
                      || maxZoomScreenRect.contains(midpoint.toPoint()));

        if (wasOffScreen && !offScreen)
            painterPath.moveTo(distanceFilteredPoints.at(i));
    }

    pathItem->setPath(painterPath);
    updateItem();
}

#include "moc_qgeotiledmaprouteobjectinfo_p.cpp"

QTM_END_NAMESPACE

<|endoftext|>


<commit_before><commit_msg>New method: isEmpty() - Checks if a string is empty.<commit_after><|endoftext|>


<commit_before>#include "stdafx.h"
<commit_msg>Remove unused file<commit_after><|endoftext|>


<commit_before><commit_msg>Finished SetPDB atoms.  All that remains is to implement a similar method for UpdateCoords in ExtendedSystem, serialize MolLookup, and finish scraping the old method.<commit_after><|endoftext|>


<commit_before>#ifndef MJOLNIR_CORE_FORCE_FIELD_HPP
#define MJOLNIR_CORE_FORCE_FIELD_HPP
#include <mjolnir/core/LocalForceField.hpp>
#include <mjolnir/core/GlobalForceField.hpp>
#include <mjolnir/core/ExternalForceField.hpp>

namespace mjolnir
{

template<typename traitsT>
class ForceField
{
  public:
    using traits_type              = traitsT;
    using real_type                = typename traits_type::real_type;
    using coordinate_type          = typename traits_type::coordinate_type;
    using system_type              = System<traits_type>;
    using local_forcefield_type    = LocalForceField<traits_type>;
    using global_forcefield_type   = GlobalForceField<traits_type>;
    using external_forcefield_type = ExternalForceField<traits_type>;

  public:

    ForceField(local_forcefield_type&& local, global_forcefield_type&& global)
        : local_(std::move(local)), global_(std::move(global))
    {}

    ForceField(local_forcefield_type&&    local,
               global_forcefield_type&&   global,
               external_forcefield_type&& external)
        : local_(std::move(local)), global_(std::move(global)),
          external_(std::move(external))
    {}

    ForceField()  = default;
    ~ForceField() {}
    ForceField(const ForceField&) = delete;
    ForceField(ForceField&&)      = default;
    ForceField& operator=(const ForceField&) = delete;
    ForceField& operator=(ForceField&&)      = default;

    // this modify system::topology by using local interaction info.
    void initialize(system_type& sys)
    {
        // first, fetch current topology
        local_.write_topology(sys.topology());
        sys.topology().construct_molecules();

        // based on the topology, make exclusion list
        local_   .initialize(sys);
        global_  .initialize(sys);
        external_.initialize(sys);
    }

    // update parameters like temperature, ionic concentration, etc...
    void update(const system_type& sys)
    {
        local_   .update(sys);
        global_  .update(sys);
        external_.update(sys);
    }

    // update margin of neighbor list
    void update_margin(const real_type dmargin, const system_type& sys)
    {
        // TODO:
        // dmargin is a maximum (safe) length to reduce the margin. Since global
        // forcefields calculate forces between particles, the safe length is
        // mostly 2 * (largest displacement in the step). It is dmargin.
        // However, since external forcefields calculate forces between particle
        // and an external field, the safe length can be just the largest
        // displacement in the step. The current implementation overestimate the
        // safe length for the external forcefields (it's correct for global
        // forcefields). In most cases, the most time-consuming part is global
        // forcefields, so I implemented in this way for now. If some idea that
        // works more efficiently is came up, this part would be re-implemented.
        local_   .update_margin(dmargin, sys);
        global_  .update_margin(dmargin, sys);
        external_.update_margin(dmargin, sys);
    }

    void calc_force(system_type& sys) const noexcept
    {
        local_   .calc_force(sys);
        global_  .calc_force(sys);
        external_.calc_force(sys);
    }
    real_type calc_energy(const system_type& sys) const noexcept
    {
        return local_.calc_energy(sys) + global_.calc_energy(sys) +
            external_.calc_energy(sys);
    }

    std::string list_energy_name() const
    {
        return local_.list_energy() + global_.list_energy() +
            external_.list_energy();
    }
    std::string dump_energy(const system_type& sys) const
    {
        return local_.dump_energy(sys) + global_.dump_energy(sys) +
            external_.dump_energy(sys);
    }

    local_forcefield_type    const& local()    const noexcept {return local_;}
    local_forcefield_type    &      local()          noexcept {return local_;}
    global_forcefield_type   const& global()   const noexcept {return global_;}
    global_forcefield_type   &      global()         noexcept {return global_;}
    external_forcefield_type const& external() const noexcept {return external_;}
    external_forcefield_type &      external()       noexcept {return external_;}

  private:

    local_forcefield_type    local_;
    global_forcefield_type   global_;
    external_forcefield_type external_;
};

#ifdef MJOLNIR_SEPARATE_BUILD
extern template class ForceField<SimulatorTraits<double, UnlimitedBoundary>>;
extern template class ForceField<SimulatorTraits<float,  UnlimitedBoundary>>;
extern template class ForceField<SimulatorTraits<double, CuboidalPeriodicBoundary>>;
extern template class ForceField<SimulatorTraits<float,  CuboidalPeriodicBoundary>>;
#endif

} // mjolnir
#endif /* MJOLNIR_FORCE_FIELD */
<commit_msg>feat: remove workaround<commit_after>#ifndef MJOLNIR_CORE_FORCE_FIELD_HPP
#define MJOLNIR_CORE_FORCE_FIELD_HPP
#include <mjolnir/core/LocalForceField.hpp>
#include <mjolnir/core/GlobalForceField.hpp>
#include <mjolnir/core/ExternalForceField.hpp>

namespace mjolnir
{

template<typename traitsT>
class ForceField
{
  public:
    using traits_type              = traitsT;
    using real_type                = typename traits_type::real_type;
    using coordinate_type          = typename traits_type::coordinate_type;
    using system_type              = System<traits_type>;
    using local_forcefield_type    = LocalForceField<traits_type>;
    using global_forcefield_type   = GlobalForceField<traits_type>;
    using external_forcefield_type = ExternalForceField<traits_type>;

  public:

    ForceField(local_forcefield_type&& local, global_forcefield_type&& global)
        : local_(std::move(local)), global_(std::move(global))
    {}

    ForceField(local_forcefield_type&&    local,
               global_forcefield_type&&   global,
               external_forcefield_type&& external)
        : local_(std::move(local)), global_(std::move(global)),
          external_(std::move(external))
    {}

    ForceField()  = default;
    ~ForceField() = default;
    ForceField(const ForceField&) = delete;
    ForceField(ForceField&&)      = default;
    ForceField& operator=(const ForceField&) = delete;
    ForceField& operator=(ForceField&&)      = default;

    // this modify system::topology by using local interaction info.
    void initialize(system_type& sys)
    {
        // first, fetch current topology
        local_.write_topology(sys.topology());
        sys.topology().construct_molecules();

        // based on the topology, make exclusion list
        local_   .initialize(sys);
        global_  .initialize(sys);
        external_.initialize(sys);
    }

    // update parameters like temperature, ionic concentration, etc...
    void update(const system_type& sys)
    {
        local_   .update(sys);
        global_  .update(sys);
        external_.update(sys);
    }

    // update margin of neighbor list
    void update_margin(const real_type dmargin, const system_type& sys)
    {
        // TODO:
        // dmargin is a maximum (safe) length to reduce the margin. Since global
        // forcefields calculate forces between particles, the safe length is
        // mostly 2 * (largest displacement in the step). It is dmargin.
        // However, since external forcefields calculate forces between particle
        // and an external field, the safe length can be just the largest
        // displacement in the step. The current implementation overestimate the
        // safe length for the external forcefields (it's correct for global
        // forcefields). In most cases, the most time-consuming part is global
        // forcefields, so I implemented in this way for now. If some idea that
        // works more efficiently is came up, this part would be re-implemented.
        local_   .update_margin(dmargin, sys);
        global_  .update_margin(dmargin, sys);
        external_.update_margin(dmargin, sys);
    }

    void calc_force(system_type& sys) const noexcept
    {
        local_   .calc_force(sys);
        global_  .calc_force(sys);
        external_.calc_force(sys);
    }
    real_type calc_energy(const system_type& sys) const noexcept
    {
        return local_.calc_energy(sys) + global_.calc_energy(sys) +
            external_.calc_energy(sys);
    }

    std::string list_energy_name() const
    {
        return local_.list_energy() + global_.list_energy() +
            external_.list_energy();
    }
    std::string dump_energy(const system_type& sys) const
    {
        return local_.dump_energy(sys) + global_.dump_energy(sys) +
            external_.dump_energy(sys);
    }

    local_forcefield_type    const& local()    const noexcept {return local_;}
    local_forcefield_type    &      local()          noexcept {return local_;}
    global_forcefield_type   const& global()   const noexcept {return global_;}
    global_forcefield_type   &      global()         noexcept {return global_;}
    external_forcefield_type const& external() const noexcept {return external_;}
    external_forcefield_type &      external()       noexcept {return external_;}

  private:

    local_forcefield_type    local_;
    global_forcefield_type   global_;
    external_forcefield_type external_;
};

#ifdef MJOLNIR_SEPARATE_BUILD
extern template class ForceField<SimulatorTraits<double, UnlimitedBoundary>>;
extern template class ForceField<SimulatorTraits<float,  UnlimitedBoundary>>;
extern template class ForceField<SimulatorTraits<double, CuboidalPeriodicBoundary>>;
extern template class ForceField<SimulatorTraits<float,  CuboidalPeriodicBoundary>>;
#endif

} // mjolnir
#endif /* MJOLNIR_FORCE_FIELD */
<|endoftext|>


<commit_before><commit_msg>Fixing Bug<commit_after><|endoftext|>


<commit_before>/*
 OneMsTaskTimer.cpp - Leveraging tasks using a timer with 1ms resolution

 History:
 got inspired by Arduino MsTimer2 by Javier Valencia <javiervalencia80@gmail.com>
 11/Nov/14 - Made more flexible for MSP430 variants
             set to 1ms overflow time -> change to OneMsTaskTimer
			 by Stefan Sch
 17/Nov/14 - restructured code to support mulitple tasks
             added suppport for CC3200
			 by Stefan Sch

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

/*
 MSP430 Notes:
 This timer currently uses Timer1 available on chips like the MSP430G2553
 It uses CCR0 in interrupt mode with the same period as PWM so PWM is
 still available for Timer1 which means pwm , analogWrite() is still available
 on the Timer1 associated pins.  We could have hacked into the watchdog timer
 which is used for millis() but that would have been a core change.

 The MSP430/Energia Servo library uses Timer0 so this library should be able to
 run concurrently with Servo.

 It will not run at the same time as the interrupt driven software serial library
 because that uses both timer interrupt vectors
*/

#include "Energia.h"
#include "OneMsTaskTimer.h"

volatile int8_t overflowing;
OneMsTaskTimer_t * p_initial_OneMsTaskTimer = 0;

#if defined(__MSP430__)

#define DEFAULT_TIMER 1
uint32_t timer_index_ = DEFAULT_TIMER;

//#if defined(__MSP430_HAS_T1A2__) || defined(__MSP430_HAS_T1A3__) || defined(__MSP430_HAS_T1A5__) || defined(__MSP430_HAS_T1A7__)
	#if DEFAULT_TIMER == 0
	#define TAxCCTL0 TA0CCTL0
	#define TAxCCR0 TA0CCR0
	#define TAxCTL TA0CTL
	#define TIMERx_A0_VECTOR TIMER0_A0_VECTOR
	#endif
	#if DEFAULT_TIMER == 1
	#define TAxCCTL0 TA1CCTL0
	#define TAxCCR0 TA1CCR0
	#define TAxCTL TA1CTL
	#define TIMERx_A0_VECTOR TIMER1_A0_VECTOR
	#endif
	#if DEFAULT_TIMER == 2
	#define TAxCCTL0 TA2CCTL0
	#define TAxCCR0 TA2CCR0
	#define TAxCTL TA2CTL
	#define TIMERx_A0_VECTOR TIMER2_A0_VECTOR
	#endif
	#if DEFAULT_TIMER == 3
	#define TAxCCTL0 TA3CCTL0
	#define TAxCCR0 TA3CCR0
	#define TAxCTL TA3CTL
	#define TIMERx_A0_VECTOR TIMER3_A0_VECTOR
	#endif
	#if DEFAULT_TIMER == 4
	#define TAxCCTL0 TA4CCTL0
	#define TAxCCR0 TA4CCR0
	#define TAxCTL TA4CTL
	#define TIMERx_A0_VECTOR TIMER4_A0_VECTOR
	#endif
	#if DEFAULT_TIMER == 10
	#define TAxCCTL0 TB0CCTL0
	#define TAxCCR0 TB0CCR0
	#define TAxCTL TB0CTL
	#define TIMERx_A0_VECTOR TIMER0_B0_VECTOR
	#endif
//#else
//#error Board not supported
//#endif

// lifted from wiring_analog.c so that the do not step on each other
// there should probably be a processor check here but that also exists in MsTimer.h
#define PWM_DIV ID__8
#define PWM_PERIOD F_CPU/1000/8

#ifndef MC__UP
#define MC__UP MC_1
#endif
#ifndef ID__8
#define ID__8 ID_3
#endif

void OneMsTaskTimer::start(uint32_t timer_index) {
  //// !!!! count = 0;
  overflowing = 0;
  // identical to the wiring_analog.c pwm setup so is compatible
  TAxCCR0 = PWM_PERIOD;           // PWM Period
  TAxCTL = TACLR | TASSEL_2 | MC__UP | PWM_DIV;            // SMCLK, up mode
  TAxCCTL0 |= CCIE;                             // CCR0 interrupt enabled
}

// turn off the interrupts but don't turn of the timer because may
// be in use for pwm.
void OneMsTaskTimer::stop() {
  // disable interrupt
  TAxCCTL0 &= ~CCIE;
  TAxCTL = 0;
}

// Timer interrupt service routine
__attribute__((interrupt(TIMERx_A0_VECTOR)))
void OneMsTaskTimer_int(void)
{
  OneMsTaskTimer::_ticHandler();
}

#endif //if defined(__MSP430__)

#if defined(__CC3200R1M1RGC__)

#include <driverlib/prcm.h>
#include <driverlib/rom_map.h>
#include <driverlib/pin.h>
#include <driverlib/timer.h>
#include <inc/hw_memmap.h>
#include <inc/hw_gprcm.h>
#include "inc/hw_timer.h"

#define DEFAULT_TIMER 1
uint32_t timer_index_ = DEFAULT_TIMER;

static volatile uint32_t g_ulBase;
void OneMsTaskTimer_int(void);

// lifted from wiring_analog.c so that the do not step on each other
// there should probably be a processor check here but that also exists in MsTimer.h
#define PWM_DIV 0
#define PWM_PERIOD F_CPU/1000

void OneMsTaskTimer::start(uint32_t timer_index) {
  uint32_t load = (F_CPU / 1000);
  //// !!!! count = 0;
  overflowing = 0;
  // Base address for first timer
  g_ulBase = TIMERA0_BASE + (timer_index <<12);
  // Configuring the timers
  MAP_PRCMPeripheralClkEnable(PRCM_TIMERA0 + timer_index, PRCM_RUN_MODE_CLK);
  MAP_PRCMPeripheralReset(PRCM_TIMERA0 + timer_index);
  MAP_TimerConfigure(g_ulBase,TIMER_CFG_PERIODIC);
  MAP_TimerPrescaleSet(g_ulBase,TIMER_A,0);
  // Setup the interrupts for the timer timeouts.
  MAP_TimerIntRegister(g_ulBase, TIMER_A, OneMsTaskTimer_int);
  MAP_TimerIntEnable(g_ulBase, TIMER_TIMA_TIMEOUT);
  // Turn on the timers
  MAP_TimerLoadSet(g_ulBase,TIMER_A, load);
  // Enable the GPT
  MAP_TimerEnable(g_ulBase,TIMER_A);
}

// turn off the interrupts but don't turn of the timer because may
// be in use for pwm.
void OneMsTaskTimer::stop() {
  // disable interrupt
  MAP_TimerIntDisable(g_ulBase, TIMER_TIMA_TIMEOUT);
  MAP_TimerDisable(g_ulBase, TIMER_A);
}

// Timer interrupt service routine
void OneMsTaskTimer_int(void)
{
  // Clear the timer interrupt.
  MAP_TimerIntClear(g_ulBase, MAP_TimerIntStatus(g_ulBase, true));
  OneMsTaskTimer::_ticHandler();
}

#endif //if defined(__CC3200R1M1RGC__)

#if defined(__TM4C123GH6PM__)

#include "wiring_private.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/timer.h"
#include <inc/hw_memmap.h>
#include "inc/hw_timer.h"
#include "driverlib/rom.h"

#define DEFAULT_TIMER 0
uint32_t timer_index_ = DEFAULT_TIMER;

static volatile uint32_t g_ulBase;
static volatile uint32_t timerAB;
void OneMsTaskTimer_int(void);

// lifted from wiring_analog.c so that the do not step on each other
// there should probably be a processor check here but that also exists in MsTimer.h
#define PWM_DIV 0
#define PWM_PERIOD F_CPU/1000

void OneMsTaskTimer::start(uint32_t timer_index) {
  uint32_t load = (F_CPU / 1000);
  //// !!!! count = 0;
  overflowing = 0;
  // Base address for first timer
  g_ulBase = getTimerBase(timerToOffset(timer_index));
  timerAB = TIMER_A << timerToAB(timer_index);
  //Setup interrupts for duration, interrupting at 1kHz
  ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0+ timer_index);
  ROM_IntMasterEnable();
  ROM_TimerConfigure(g_ulBase, TIMER_CFG_PERIODIC);
  ROM_TimerLoadSet(g_ulBase, TIMER_A, F_CPU/1000);

  // Setup the interrupts for the timer timeouts.
  TimerIntRegister(g_ulBase, TIMER_A, OneMsTaskTimer_int);
  ROM_IntEnable(INT_TIMER0A+timer_index);
  ROM_TimerIntEnable(g_ulBase, TIMER_TIMA_TIMEOUT);
  ROM_TimerEnable(g_ulBase, TIMER_A);

}

// turn off the interrupts but don't turn of the timer because may
// be in use for pwm.
void OneMsTaskTimer::stop() {
  // disable interrupt
  ROM_TimerIntDisable(g_ulBase, TIMER_A);
  ROM_TimerIntClear(g_ulBase, TIMER_A);
  ROM_TimerDisable(g_ulBase, timerAB);
}

// Timer interrupt service routine
void OneMsTaskTimer_int(void)
{
  // Clear the timer interrupt.
  ROM_TimerIntClear(g_ulBase, TIMER_A);
  OneMsTaskTimer::_ticHandler();
}
#endif //#if defined(__TM4C123GH6PM__)

#if defined(ti_sysbios_BIOS___VERS)
#include <xdc/runtime/Error.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Clock.h>
#include <xdc/runtime/Error.h>
#include <xdc/runtime/Types.h>

#define DEFAULT_TIMER 1
uint32_t timer_index_ = DEFAULT_TIMER;
static volatile uint32_t g_ulBase;
Clock_Handle myClock = NULL;
void OneMsTaskTimer_int(UArg arg);

void OneMsTaskTimer::start(uint32_t timer_index) {
    Clock_Params clockParams;
    Error_Block eb;
    Error_init(&eb);

    Clock_Params_init(&clockParams);
    clockParams.period = 1;
    clockParams.startFlag = TRUE;
    clockParams.arg = (UArg)0x5555;
    if (myClock == NULL){
		myClock = Clock_create(OneMsTaskTimer_int, 1, &clockParams, &eb);
	}
    Clock_start(myClock);
}

void OneMsTaskTimer::stop() {
    Clock_stop(myClock);
}
void OneMsTaskTimer_int(UArg arg)
{
  OneMsTaskTimer::_ticHandler();
}

#endif //#if defined(ti_sysbios_BIOS___VERS)
// ---------------------------------------------------------------------
// Common Functions
// ---------------------------------------------------------------------

void OneMsTaskTimer::set_timer_index(uint32_t timer_index) {
	timer_index_ = timer_index;
}

// configure the registers
void OneMsTaskTimer::start() {
  OneMsTaskTimer::start(timer_index_);
}

// add an additional task into the handler
void OneMsTaskTimer::add(OneMsTaskTimer_t * task) {
  OneMsTaskTimer_t * p_task = p_initial_OneMsTaskTimer;
  if (p_task == 0){
	  p_initial_OneMsTaskTimer = task;
  }else{
	while (p_task->nextTask != 0){
	  p_task = p_task->nextTask;
	}
	p_task->nextTask = task;
  }
  p_task = task;

  // ensure save initialisation
  if (task->msecs == 0)
  	task->msecs = 1;
  task->count = 0;
  task->nextTask = 0;
}

// removes an task from the handler
void OneMsTaskTimer::remove(OneMsTaskTimer_t * task) {
  OneMsTaskTimer_t * p_task;
  OneMsTaskTimer_t * p_nexttask;
  p_nexttask = (OneMsTaskTimer_t *)p_initial_OneMsTaskTimer;
  p_task = p_nexttask;

  while (p_nexttask != task && p_nexttask != 0){
    p_task = p_nexttask;
    p_nexttask = p_task->nextTask;
  }
  if (p_nexttask != 0){
    if (p_nexttask == p_initial_OneMsTaskTimer){
      if (p_nexttask != 0){
        p_initial_OneMsTaskTimer = p_nexttask->nextTask;
      }else{
        p_initial_OneMsTaskTimer = 0;
      }
    }else{
      p_task->nextTask = p_nexttask->nextTask;
    }
  }
}

// called by the ISR every time we get an interrupt
void OneMsTaskTimer::_ticHandler() {
  OneMsTaskTimer_t * p_task = p_initial_OneMsTaskTimer;

  while (p_task != 0){
    // It is a 1000hz interrupt so each interrupt is 1msec
    p_task->count += 1;
    if (p_task->count >= p_task->msecs && !overflowing) {
      overflowing = 1;
      // subtract ms to catch missed overflows. set to 0 if you don't want this.
      // do this before running supplied function so don't take into account handler time
      p_task->count = p_task->count - p_task->msecs;
      // call the program supplied function
      (*p_task->func)();
      overflowing = 0;
    }
    p_task = (OneMsTaskTimer_t *)p_task->nextTask;
  }
}
<commit_msg>Fix for when Clock.tickPeriod is NOT set to 1000us<commit_after>/*
 OneMsTaskTimer.cpp - Leveraging tasks using a timer with 1ms resolution

 History:
 got inspired by Arduino MsTimer2 by Javier Valencia <javiervalencia80@gmail.com>
 11/Nov/14 - Made more flexible for MSP430 variants
             set to 1ms overflow time -> change to OneMsTaskTimer
			 by Stefan Sch
 17/Nov/14 - restructured code to support mulitple tasks
             added suppport for CC3200
			 by Stefan Sch

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

/*
 MSP430 Notes:
 This timer currently uses Timer1 available on chips like the MSP430G2553
 It uses CCR0 in interrupt mode with the same period as PWM so PWM is
 still available for Timer1 which means pwm , analogWrite() is still available
 on the Timer1 associated pins.  We could have hacked into the watchdog timer
 which is used for millis() but that would have been a core change.

 The MSP430/Energia Servo library uses Timer0 so this library should be able to
 run concurrently with Servo.

 It will not run at the same time as the interrupt driven software serial library
 because that uses both timer interrupt vectors
*/

#include "Energia.h"
#include "OneMsTaskTimer.h"

volatile int8_t overflowing;
OneMsTaskTimer_t * p_initial_OneMsTaskTimer = 0;

#if defined(__MSP430__)

#define DEFAULT_TIMER 1
uint32_t timer_index_ = DEFAULT_TIMER;

//#if defined(__MSP430_HAS_T1A2__) || defined(__MSP430_HAS_T1A3__) || defined(__MSP430_HAS_T1A5__) || defined(__MSP430_HAS_T1A7__)
	#if DEFAULT_TIMER == 0
	#define TAxCCTL0 TA0CCTL0
	#define TAxCCR0 TA0CCR0
	#define TAxCTL TA0CTL
	#define TIMERx_A0_VECTOR TIMER0_A0_VECTOR
	#endif
	#if DEFAULT_TIMER == 1
	#define TAxCCTL0 TA1CCTL0
	#define TAxCCR0 TA1CCR0
	#define TAxCTL TA1CTL
	#define TIMERx_A0_VECTOR TIMER1_A0_VECTOR
	#endif
	#if DEFAULT_TIMER == 2
	#define TAxCCTL0 TA2CCTL0
	#define TAxCCR0 TA2CCR0
	#define TAxCTL TA2CTL
	#define TIMERx_A0_VECTOR TIMER2_A0_VECTOR
	#endif
	#if DEFAULT_TIMER == 3
	#define TAxCCTL0 TA3CCTL0
	#define TAxCCR0 TA3CCR0
	#define TAxCTL TA3CTL
	#define TIMERx_A0_VECTOR TIMER3_A0_VECTOR
	#endif
	#if DEFAULT_TIMER == 4
	#define TAxCCTL0 TA4CCTL0
	#define TAxCCR0 TA4CCR0
	#define TAxCTL TA4CTL
	#define TIMERx_A0_VECTOR TIMER4_A0_VECTOR
	#endif
	#if DEFAULT_TIMER == 10
	#define TAxCCTL0 TB0CCTL0
	#define TAxCCR0 TB0CCR0
	#define TAxCTL TB0CTL
	#define TIMERx_A0_VECTOR TIMER0_B0_VECTOR
	#endif
//#else
//#error Board not supported
//#endif

// lifted from wiring_analog.c so that the do not step on each other
// there should probably be a processor check here but that also exists in MsTimer.h
#define PWM_DIV ID__8
#define PWM_PERIOD F_CPU/1000/8

#ifndef MC__UP
#define MC__UP MC_1
#endif
#ifndef ID__8
#define ID__8 ID_3
#endif

void OneMsTaskTimer::start(uint32_t timer_index) {
  //// !!!! count = 0;
  overflowing = 0;
  // identical to the wiring_analog.c pwm setup so is compatible
  TAxCCR0 = PWM_PERIOD;           // PWM Period
  TAxCTL = TACLR | TASSEL_2 | MC__UP | PWM_DIV;            // SMCLK, up mode
  TAxCCTL0 |= CCIE;                             // CCR0 interrupt enabled
}

// turn off the interrupts but don't turn of the timer because may
// be in use for pwm.
void OneMsTaskTimer::stop() {
  // disable interrupt
  TAxCCTL0 &= ~CCIE;
  TAxCTL = 0;
}

// Timer interrupt service routine
__attribute__((interrupt(TIMERx_A0_VECTOR)))
void OneMsTaskTimer_int(void)
{
  OneMsTaskTimer::_ticHandler();
}

#endif //if defined(__MSP430__)

#if defined(__CC3200R1M1RGC__)

#include <driverlib/prcm.h>
#include <driverlib/rom_map.h>
#include <driverlib/pin.h>
#include <driverlib/timer.h>
#include <inc/hw_memmap.h>
#include <inc/hw_gprcm.h>
#include "inc/hw_timer.h"

#define DEFAULT_TIMER 1
uint32_t timer_index_ = DEFAULT_TIMER;

static volatile uint32_t g_ulBase;
void OneMsTaskTimer_int(void);

// lifted from wiring_analog.c so that the do not step on each other
// there should probably be a processor check here but that also exists in MsTimer.h
#define PWM_DIV 0
#define PWM_PERIOD F_CPU/1000

void OneMsTaskTimer::start(uint32_t timer_index) {
  uint32_t load = (F_CPU / 1000);
  //// !!!! count = 0;
  overflowing = 0;
  // Base address for first timer
  g_ulBase = TIMERA0_BASE + (timer_index <<12);
  // Configuring the timers
  MAP_PRCMPeripheralClkEnable(PRCM_TIMERA0 + timer_index, PRCM_RUN_MODE_CLK);
  MAP_PRCMPeripheralReset(PRCM_TIMERA0 + timer_index);
  MAP_TimerConfigure(g_ulBase,TIMER_CFG_PERIODIC);
  MAP_TimerPrescaleSet(g_ulBase,TIMER_A,0);
  // Setup the interrupts for the timer timeouts.
  MAP_TimerIntRegister(g_ulBase, TIMER_A, OneMsTaskTimer_int);
  MAP_TimerIntEnable(g_ulBase, TIMER_TIMA_TIMEOUT);
  // Turn on the timers
  MAP_TimerLoadSet(g_ulBase,TIMER_A, load);
  // Enable the GPT
  MAP_TimerEnable(g_ulBase,TIMER_A);
}

// turn off the interrupts but don't turn of the timer because may
// be in use for pwm.
void OneMsTaskTimer::stop() {
  // disable interrupt
  MAP_TimerIntDisable(g_ulBase, TIMER_TIMA_TIMEOUT);
  MAP_TimerDisable(g_ulBase, TIMER_A);
}

// Timer interrupt service routine
void OneMsTaskTimer_int(void)
{
  // Clear the timer interrupt.
  MAP_TimerIntClear(g_ulBase, MAP_TimerIntStatus(g_ulBase, true));
  OneMsTaskTimer::_ticHandler();
}

#endif //if defined(__CC3200R1M1RGC__)

#if defined(__TM4C123GH6PM__)

#include "wiring_private.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/timer.h"
#include <inc/hw_memmap.h>
#include "inc/hw_timer.h"
#include "driverlib/rom.h"

#define DEFAULT_TIMER 0
uint32_t timer_index_ = DEFAULT_TIMER;

static volatile uint32_t g_ulBase;
static volatile uint32_t timerAB;
void OneMsTaskTimer_int(void);

// lifted from wiring_analog.c so that the do not step on each other
// there should probably be a processor check here but that also exists in MsTimer.h
#define PWM_DIV 0
#define PWM_PERIOD F_CPU/1000

void OneMsTaskTimer::start(uint32_t timer_index) {
  uint32_t load = (F_CPU / 1000);
  //// !!!! count = 0;
  overflowing = 0;
  // Base address for first timer
  g_ulBase = getTimerBase(timerToOffset(timer_index));
  timerAB = TIMER_A << timerToAB(timer_index);
  //Setup interrupts for duration, interrupting at 1kHz
  ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0+ timer_index);
  ROM_IntMasterEnable();
  ROM_TimerConfigure(g_ulBase, TIMER_CFG_PERIODIC);
  ROM_TimerLoadSet(g_ulBase, TIMER_A, F_CPU/1000);

  // Setup the interrupts for the timer timeouts.
  TimerIntRegister(g_ulBase, TIMER_A, OneMsTaskTimer_int);
  ROM_IntEnable(INT_TIMER0A+timer_index);
  ROM_TimerIntEnable(g_ulBase, TIMER_TIMA_TIMEOUT);
  ROM_TimerEnable(g_ulBase, TIMER_A);

}

// turn off the interrupts but don't turn of the timer because may
// be in use for pwm.
void OneMsTaskTimer::stop() {
  // disable interrupt
  ROM_TimerIntDisable(g_ulBase, TIMER_A);
  ROM_TimerIntClear(g_ulBase, TIMER_A);
  ROM_TimerDisable(g_ulBase, timerAB);
}

// Timer interrupt service routine
void OneMsTaskTimer_int(void)
{
  // Clear the timer interrupt.
  ROM_TimerIntClear(g_ulBase, TIMER_A);
  OneMsTaskTimer::_ticHandler();
}
#endif //#if defined(__TM4C123GH6PM__)

#if defined(ti_sysbios_BIOS___VERS)
#include <xdc/runtime/Error.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Clock.h>
#include <xdc/runtime/Error.h>
#include <xdc/runtime/Types.h>

#define DEFAULT_TIMER 1
uint32_t timer_index_ = DEFAULT_TIMER;
static volatile uint32_t g_ulBase;
Clock_Handle myClock = NULL;
void OneMsTaskTimer_int(UArg arg);

void OneMsTaskTimer::start(uint32_t timer_index) {
    Clock_Params clockParams;
    Error_Block eb;
    Error_init(&eb);

    if (myClock == NULL){
        Clock_Params_init(&clockParams);
        clockParams.period = (uint32_t)1000 / (uint64_t)Clock_tickPeriod;
        clockParams.startFlag = FALSE;
        clockParams.arg = (UArg)0x5555;

		myClock = Clock_create(OneMsTaskTimer_int, clockParams.period, &clockParams, &eb);
	}
    Clock_start(myClock);
}

void OneMsTaskTimer::stop() {
    Clock_stop(myClock);
}
void OneMsTaskTimer_int(UArg arg)
{
  OneMsTaskTimer::_ticHandler();
}

#endif //#if defined(ti_sysbios_BIOS___VERS)
// ---------------------------------------------------------------------
// Common Functions
// ---------------------------------------------------------------------

void OneMsTaskTimer::set_timer_index(uint32_t timer_index) {
	timer_index_ = timer_index;
}

// configure the registers
void OneMsTaskTimer::start() {
  OneMsTaskTimer::start(timer_index_);
}

// add an additional task into the handler
void OneMsTaskTimer::add(OneMsTaskTimer_t * task) {
  OneMsTaskTimer_t * p_task = p_initial_OneMsTaskTimer;
  if (p_task == 0){
	  p_initial_OneMsTaskTimer = task;
  }else{
	while (p_task->nextTask != 0){
	  p_task = p_task->nextTask;
	}
	p_task->nextTask = task;
  }
  p_task = task;

  // ensure save initialisation
  if (task->msecs == 0)
  	task->msecs = 1;
  task->count = 0;
  task->nextTask = 0;
}

// removes an task from the handler
void OneMsTaskTimer::remove(OneMsTaskTimer_t * task) {
  OneMsTaskTimer_t * p_task;
  OneMsTaskTimer_t * p_nexttask;
  p_nexttask = (OneMsTaskTimer_t *)p_initial_OneMsTaskTimer;
  p_task = p_nexttask;

  while (p_nexttask != task && p_nexttask != 0){
    p_task = p_nexttask;
    p_nexttask = p_task->nextTask;
  }
  if (p_nexttask != 0){
    if (p_nexttask == p_initial_OneMsTaskTimer){
      if (p_nexttask != 0){
        p_initial_OneMsTaskTimer = p_nexttask->nextTask;
      }else{
        p_initial_OneMsTaskTimer = 0;
      }
    }else{
      p_task->nextTask = p_nexttask->nextTask;
    }
  }
}

// called by the ISR every time we get an interrupt
void OneMsTaskTimer::_ticHandler() {
  OneMsTaskTimer_t * p_task = p_initial_OneMsTaskTimer;

  while (p_task != 0){
    // It is a 1000hz interrupt so each interrupt is 1msec
    p_task->count += 1;
    if (p_task->count >= p_task->msecs && !overflowing) {
      overflowing = 1;
      // subtract ms to catch missed overflows. set to 0 if you don't want this.
      // do this before running supplied function so don't take into account handler time
      p_task->count = p_task->count - p_task->msecs;
      // call the program supplied function
      (*p_task->func)();
      overflowing = 0;
    }
    p_task = (OneMsTaskTimer_t *)p_task->nextTask;
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012 The Native Client Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include <assert.h>
#include <stdio.h>
#include <string.h>

#include <ppapi/c/ppb_file_io.h>

#include "HTTP2OpenJob.h"
#include "../util/DebugPrint.h"

HTTP2OpenJob::HTTP2OpenJob() : factory_(NULL), loader_(NULL), ref_(NULL),
                               parent_ref_(NULL), io_(NULL) {
}

HTTP2OpenJob::~HTTP2OpenJob() {
}

void HTTP2OpenJob::Run(MainThreadRunner::JobEntry *e) {
  job_entry_ = e;

  dbgprintf("open %s\n", fs_path_.c_str());
  ref_ = new pp::FileRef(*fs_, fs_path_.c_str());
  pp::Instance *instance = MainThreadRunner::ExtractPepperInstance(job_entry_);
  io_ = new pp::FileIO(instance);

  factory_ = new pp::CompletionCallbackFactory<HTTP2OpenJob>(this);

  pp::CompletionCallback cc =
    factory_->NewCallback(&HTTP2OpenJob::FileOpenCallback);

  int32_t rv = io_->Open(*ref_, PP_FILEOPENFLAG_READ, cc);

  if (rv != PP_OK_COMPLETIONPENDING)
    cc.Run(rv);
}

pp::URLRequestInfo HTTP2OpenJob::MakeRequest(std::string url) {
  pp::Instance *instance = MainThreadRunner::ExtractPepperInstance(job_entry_);
  pp::URLRequestInfo request(instance);
  request.SetURL(url);
  request.SetMethod("GET");
  request.SetFollowRedirects(true);
  request.SetStreamToFile(false);
  request.SetAllowCredentials(true);
  request.SetAllowCrossOriginRequests(true);
  return request;
}

void HTTP2OpenJob::FileOpenCallback(int32_t result) {
  if (result == PP_OK) {
    // Open for reading succeded. Check that the file size is correct.
    if (expected_size_ == -1) {
      *file_io_ = io_;
      io_ = NULL;
      Finish(result);
    } else {
      pp::CompletionCallback cc =
        factory_->NewCallback(&HTTP2OpenJob::FileQueryCallback);

      int32_t rv = io_->Query(&query_buf_, cc);
      if (rv != PP_OK_COMPLETIONPENDING)
        cc.Run(rv);
    }
  } else {
    // Open for reading failed. Create a new file.
    DownloadFile();
  }
}

void HTTP2OpenJob::FileQueryCallback(int32_t result) {
  if (result != PP_OK) {
    dbgprintf("Query failed, %d\n", result);
    Finish(result);
    return;
  }

  if (query_buf_.size < expected_size_) {
    // Bad/truncated file. Re-download.
    // TODO(eugenis): resume download if the file is shorter than expected
    io_->Close();
    DownloadFile();
  } else {
    // success
    *file_io_ = io_;
    io_ = NULL;
    Finish(result);
  }
}

void HTTP2OpenJob::DownloadFile() {
  dbgprintf("fetch %s\n", url_.c_str());

  // First, create a directory for the new file.
  pp::CompletionCallback cc =
    factory_->NewCallback(&HTTP2OpenJob::DirCreateCallback);

  parent_ref_ = new pp::FileRef(ref_->GetParent());

  if (parent_ref_->GetPath().AsString() == "/") {
    cc.Run(PP_ERROR_FILEEXISTS);
  } else {
    int32_t rv = parent_ref_->MakeDirectoryIncludingAncestors(cc);
    if (rv != PP_OK_COMPLETIONPENDING)
      cc.Run(rv);
  }
}

void HTTP2OpenJob::DirCreateCallback(int32_t result) {
  if (result != PP_OK && result != PP_ERROR_FILEEXISTS) {
    dbgprintf("Could not create a directory in the local fs: %s, %d\n",
        parent_ref_->GetPath().AsString().c_str(), result);
    Finish(result);
    return;
  }

  if (result == PP_ERROR_FILEEXISTS) {
    dbgprintf("Dir already exists. That's fine.\n");
  }

  pp::CompletionCallback cc =
    factory_->NewCallback(&HTTP2OpenJob::FileCreateCallback);

  int32_t rv = io_->Open(*ref_,
      PP_FILEOPENFLAG_CREATE | PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_WRITE,
      cc);

  if (rv != PP_OK_COMPLETIONPENDING)
    cc.Run(rv);
}

void HTTP2OpenJob::FileCreateCallback(int32_t result) {
  if (result != PP_OK) {
    dbgprintf("file creation failed: %d\n", result);
    Finish(result);
    return;
  }

  offset_ = 0;
  write_in_flight_ = false;
  read_done_ = false;

  loader_ =
    new pp::URLLoader(MainThreadRunner::ExtractPepperInstance(job_entry_));
  pp::CompletionCallback cc =
    factory_->NewCallback(&HTTP2OpenJob::UrlOpenCallback);

  int32_t rv = loader_->Open(MakeRequest(url_), cc);
  if (rv != PP_OK_COMPLETIONPENDING)
    cc.Run(rv);
}

void HTTP2OpenJob::UrlOpenCallback(int32_t result) {
  if (result != PP_OK) {
    dbgprintf("Open failed, %d\n", result);
    Finish(result);
    return;
  }

  const pp::URLResponseInfo& response_info = loader_->GetResponseInfo();
  int status_code = response_info.GetStatusCode();
  if (status_code != 200) {
    dbgprintf("bad status code %d\n", status_code);
    Finish(-status_code);
    return;
  }

  ReadMore();
}

void HTTP2OpenJob::ReadMore() {
  pp::CompletionCallback cc =
    factory_->NewCallback(&HTTP2OpenJob::UrlReadCallback);
  int32_t rv = loader_->ReadResponseBody(read_buf_, sizeof(read_buf_), cc);
  if (rv != PP_OK_COMPLETIONPENDING) {
    cc.Run(rv);
  }
}

void HTTP2OpenJob::UrlReadCallback(int32_t result) {
  if (result < 0) {
    dbgprintf("Read failed, %d\n", result);
    Finish(result);
    return;
  }

  if (result == 0) {
    read_done_ = true;
    MaybeDone();
  }

  if (result > 0) {
    // append data to the write buffer
    size_t pos = write_buf_.size();
    write_buf_.resize(pos + result);
    memcpy(&write_buf_[pos], read_buf_, result);

    MaybeWrite();

    // continue reading
    ReadMore();
  }
}

void HTTP2OpenJob::MaybeWrite() {
  if (write_in_flight_)
    return;
  if (write_buf_.empty()) {
    MaybeDone();
  } else {
    pp::CompletionCallback cc =
      factory_->NewCallback(&HTTP2OpenJob::FileWriteCallback);
    int32_t rv =
      io_->Write(offset_, &write_buf_.front(), write_buf_.size(), cc);
    write_in_flight_ = true;
    if (rv != PP_OK_COMPLETIONPENDING) {
      cc.Run(rv);
    }
  }
}

void HTTP2OpenJob::MaybeDone() {
  if (!write_in_flight_ && write_buf_.empty() && read_done_) {
    *file_io_ = io_;
    io_ = NULL;
    Finish(0);
    return;
  }
}

void HTTP2OpenJob::ReportProgress() {
  if (progress_handler_)
    progress_handler_->HandleProgress(path_, offset_, expected_size_);
}

void HTTP2OpenJob::FileWriteCallback(int32_t result) {
  write_in_flight_ = false;
  if (result <= 0) {
    dbgprintf("Write failed\n");
    Finish(result);
    return;
  }

  // result > 0
  offset_ += result;
  write_buf_.erase(write_buf_.begin(), write_buf_.begin() + result);

  ReportProgress();

  MaybeWrite();
}

void HTTP2OpenJob::Finish(int32_t result) {
  delete factory_;
  delete loader_;
  delete ref_;
  delete parent_ref_;
  delete io_;
  MainThreadRunner::ResultCompletion(job_entry_, result);
}
<commit_msg>Don't reuse pp::FileIO when redownloading a file in HTTP2Mount <commit_after>/*
 * Copyright (c) 2012 The Native Client Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include <assert.h>
#include <stdio.h>
#include <string.h>

#include <ppapi/c/ppb_file_io.h>

#include "HTTP2OpenJob.h"
#include "../util/DebugPrint.h"

HTTP2OpenJob::HTTP2OpenJob() : factory_(NULL), loader_(NULL), ref_(NULL),
                               parent_ref_(NULL), io_(NULL) {
}

HTTP2OpenJob::~HTTP2OpenJob() {
}

void HTTP2OpenJob::Run(MainThreadRunner::JobEntry *e) {
  job_entry_ = e;

  dbgprintf("open %s\n", fs_path_.c_str());
  ref_ = new pp::FileRef(*fs_, fs_path_.c_str());
  io_ = new pp::FileIO(MainThreadRunner::ExtractPepperInstance(job_entry_));

  factory_ = new pp::CompletionCallbackFactory<HTTP2OpenJob>(this);

  pp::CompletionCallback cc =
    factory_->NewCallback(&HTTP2OpenJob::FileOpenCallback);

  int32_t rv = io_->Open(*ref_, PP_FILEOPENFLAG_READ, cc);

  if (rv != PP_OK_COMPLETIONPENDING)
    cc.Run(rv);
}

pp::URLRequestInfo HTTP2OpenJob::MakeRequest(std::string url) {
  pp::Instance *instance = MainThreadRunner::ExtractPepperInstance(job_entry_);
  pp::URLRequestInfo request(instance);
  request.SetURL(url);
  request.SetMethod("GET");
  request.SetFollowRedirects(true);
  request.SetStreamToFile(false);
  request.SetAllowCredentials(true);
  request.SetAllowCrossOriginRequests(true);
  return request;
}

void HTTP2OpenJob::FileOpenCallback(int32_t result) {
  if (result == PP_OK) {
    // Open for reading succeded. Check that the file size is correct.
    if (expected_size_ == -1) {
      *file_io_ = io_;
      io_ = NULL;
      Finish(result);
    } else {
      pp::CompletionCallback cc =
        factory_->NewCallback(&HTTP2OpenJob::FileQueryCallback);

      int32_t rv = io_->Query(&query_buf_, cc);
      if (rv != PP_OK_COMPLETIONPENDING)
        cc.Run(rv);
    }
  } else {
    // Open for reading failed. Create a new file.
    DownloadFile();
  }
}

void HTTP2OpenJob::FileQueryCallback(int32_t result) {
  if (result != PP_OK) {
    dbgprintf("Query failed, %d\n", result);
    Finish(result);
    return;
  }

  if (query_buf_.size < expected_size_) {
    // Bad/truncated file. Re-download.
    // TODO(eugenis): resume download if the file is shorter than expected
    io_->Close();
    delete io_;
    io_ = new pp::FileIO(MainThreadRunner::ExtractPepperInstance(job_entry_));
    DownloadFile();
  } else {
    // success
    *file_io_ = io_;
    io_ = NULL;
    Finish(result);
  }
}

void HTTP2OpenJob::DownloadFile() {
  dbgprintf("fetch %s\n", url_.c_str());

  // First, create a directory for the new file.
  pp::CompletionCallback cc =
    factory_->NewCallback(&HTTP2OpenJob::DirCreateCallback);

  parent_ref_ = new pp::FileRef(ref_->GetParent());

  if (parent_ref_->GetPath().AsString() == "/") {
    cc.Run(PP_ERROR_FILEEXISTS);
  } else {
    int32_t rv = parent_ref_->MakeDirectoryIncludingAncestors(cc);
    if (rv != PP_OK_COMPLETIONPENDING)
      cc.Run(rv);
  }
}

void HTTP2OpenJob::DirCreateCallback(int32_t result) {
  if (result != PP_OK && result != PP_ERROR_FILEEXISTS) {
    dbgprintf("Could not create a directory in the local fs: %s, %d\n",
        parent_ref_->GetPath().AsString().c_str(), result);
    Finish(result);
    return;
  }

  if (result == PP_ERROR_FILEEXISTS) {
    dbgprintf("Dir already exists. That's fine.\n");
  }

  pp::CompletionCallback cc =
    factory_->NewCallback(&HTTP2OpenJob::FileCreateCallback);

  int32_t rv = io_->Open(*ref_,
      PP_FILEOPENFLAG_CREATE | PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_WRITE,
      cc);

  if (rv != PP_OK_COMPLETIONPENDING)
    cc.Run(rv);
}

void HTTP2OpenJob::FileCreateCallback(int32_t result) {
  if (result != PP_OK) {
    dbgprintf("file creation failed: %d\n", result);
    Finish(result);
    return;
  }

  offset_ = 0;
  write_in_flight_ = false;
  read_done_ = false;

  loader_ =
    new pp::URLLoader(MainThreadRunner::ExtractPepperInstance(job_entry_));
  pp::CompletionCallback cc =
    factory_->NewCallback(&HTTP2OpenJob::UrlOpenCallback);

  int32_t rv = loader_->Open(MakeRequest(url_), cc);
  if (rv != PP_OK_COMPLETIONPENDING)
    cc.Run(rv);
}

void HTTP2OpenJob::UrlOpenCallback(int32_t result) {
  if (result != PP_OK) {
    dbgprintf("Open failed, %d\n", result);
    Finish(result);
    return;
  }

  const pp::URLResponseInfo& response_info = loader_->GetResponseInfo();
  int status_code = response_info.GetStatusCode();
  if (status_code != 200) {
    dbgprintf("bad status code %d\n", status_code);
    Finish(-status_code);
    return;
  }

  ReadMore();
}

void HTTP2OpenJob::ReadMore() {
  pp::CompletionCallback cc =
    factory_->NewCallback(&HTTP2OpenJob::UrlReadCallback);
  int32_t rv = loader_->ReadResponseBody(read_buf_, sizeof(read_buf_), cc);
  if (rv != PP_OK_COMPLETIONPENDING) {
    cc.Run(rv);
  }
}

void HTTP2OpenJob::UrlReadCallback(int32_t result) {
  if (result < 0) {
    dbgprintf("Read failed, %d\n", result);
    Finish(result);
    return;
  }

  if (result == 0) {
    read_done_ = true;
    MaybeDone();
  }

  if (result > 0) {
    // append data to the write buffer
    size_t pos = write_buf_.size();
    write_buf_.resize(pos + result);
    memcpy(&write_buf_[pos], read_buf_, result);

    MaybeWrite();

    // continue reading
    ReadMore();
  }
}

void HTTP2OpenJob::MaybeWrite() {
  if (write_in_flight_)
    return;
  if (write_buf_.empty()) {
    MaybeDone();
  } else {
    pp::CompletionCallback cc =
      factory_->NewCallback(&HTTP2OpenJob::FileWriteCallback);
    int32_t rv =
      io_->Write(offset_, &write_buf_.front(), write_buf_.size(), cc);
    write_in_flight_ = true;
    if (rv != PP_OK_COMPLETIONPENDING) {
      cc.Run(rv);
    }
  }
}

void HTTP2OpenJob::MaybeDone() {
  if (!write_in_flight_ && write_buf_.empty() && read_done_) {
    *file_io_ = io_;
    io_ = NULL;
    Finish(0);
    return;
  }
}

void HTTP2OpenJob::ReportProgress() {
  if (progress_handler_)
    progress_handler_->HandleProgress(path_, offset_, expected_size_);
}

void HTTP2OpenJob::FileWriteCallback(int32_t result) {
  write_in_flight_ = false;
  if (result <= 0) {
    dbgprintf("Write failed\n");
    Finish(result);
    return;
  }

  // result > 0
  offset_ += result;
  write_buf_.erase(write_buf_.begin(), write_buf_.begin() + result);

  ReportProgress();

  MaybeWrite();
}

void HTTP2OpenJob::Finish(int32_t result) {
  delete factory_;
  delete loader_;
  delete ref_;
  delete parent_ref_;
  delete io_;
  MainThreadRunner::ResultCompletion(job_entry_, result);
}
<|endoftext|>


<commit_before>/*************************************************
* Unix EntropySource Source File                 *
* (C) 1999-2007 The Botan Project                *
*************************************************/

#include <botan/es_unix.h>
#include <botan/unix_cmd.h>
#include <botan/parsing.h>
#include <botan/config.h>
#include <algorithm>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>

namespace Botan {

namespace {

/*************************************************
* Sort ordering by priority                      *
*************************************************/
bool Unix_Program_Cmp(const Unix_Program& a, const Unix_Program& b)
   { return (a.priority < b.priority); }

}

/*************************************************
* Unix_EntropySource Constructor                 *
*************************************************/
Unix_EntropySource::Unix_EntropySource()
   {
   add_default_sources(sources);
   }

/*************************************************
* Add sources to the list                        *
*************************************************/
void Unix_EntropySource::add_sources(const Unix_Program srcs[], u32bit count)
   {
   sources.insert(sources.end(), srcs, srcs + count);
   std::sort(sources.begin(), sources.end(), Unix_Program_Cmp);
   }

/*************************************************
* Unix Fast Poll                                 *
*************************************************/
void Unix_EntropySource::do_fast_poll()
   {
   add_bytes(getpid());
   add_bytes(getppid());

   add_bytes(getuid());
   add_bytes(getgid());
   add_bytes(geteuid());
   add_bytes(getegid());

   add_bytes(getpgrp());
   add_bytes(getsid(0));

   struct rusage usage;

   clear_mem(&usage, 1);
   getrusage(RUSAGE_SELF, &usage);
   add_bytes(&usage, sizeof(usage));

   getrusage(RUSAGE_CHILDREN, &usage);
   add_bytes(&usage, sizeof(usage));
   }

/*************************************************
* Unix Slow Poll                                 *
*************************************************/
void Unix_EntropySource::do_slow_poll()
   {
   const u32bit TRY_TO_GET = 16 * 1024;
   const u32bit MINIMAL_WORKING = 32;

   const std::string BASE_PATH = "/bin:/sbin:/usr/bin:/usr/sbin";
   const std::string EXTRA_PATH = global_config().option("rng/unix_path");

   std::string PATH = BASE_PATH;
   if(EXTRA_PATH != "")
      PATH += ':' + EXTRA_PATH;

   u32bit got = 0;
   for(u32bit j = 0; j != sources.size(); j++)
      {
      add_timestamp();

      DataSource_Command pipe(sources[j].name_and_args, PATH);
      SecureVector<byte> buffer(DEFAULT_BUFFERSIZE);

      uint32_t got_from_src = 0;

      while(!pipe.end_of_data())
         {
         u32bit this_loop = pipe.read(buffer, buffer.size());
         add_bytes(buffer, this_loop);
         got_from_src += this_loop;
         }

      sources[j].working = (got_from_src >= MINIMAL_WORKING) ? true : false;
      got += got_from_src;

      if(got >= TRY_TO_GET)
         break;
      }
   }

}
<commit_msg>Add stats of '/', '/tmp', '.', and '..' to the es_unix fast poll.<commit_after>/*************************************************
* Unix EntropySource Source File                 *
* (C) 1999-2007 The Botan Project                *
*************************************************/

#include <botan/es_unix.h>
#include <botan/unix_cmd.h>
#include <botan/parsing.h>
#include <botan/config.h>
#include <algorithm>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <unistd.h>

namespace Botan {

namespace {

/*************************************************
* Sort ordering by priority                      *
*************************************************/
bool Unix_Program_Cmp(const Unix_Program& a, const Unix_Program& b)
   { return (a.priority < b.priority); }

}

/*************************************************
* Unix_EntropySource Constructor                 *
*************************************************/
Unix_EntropySource::Unix_EntropySource()
   {
   add_default_sources(sources);
   }

/*************************************************
* Add sources to the list                        *
*************************************************/
void Unix_EntropySource::add_sources(const Unix_Program srcs[], u32bit count)
   {
   sources.insert(sources.end(), srcs, srcs + count);
   std::sort(sources.begin(), sources.end(), Unix_Program_Cmp);
   }

/*************************************************
* Unix Fast Poll                                 *
*************************************************/
void Unix_EntropySource::do_fast_poll()
   {
   const char* STAT_TARGETS[] = { "/", "/tmp", ".", "..", 0 };

   for(u32bit j = 0; STAT_TARGETS[j]; j++)
      {
      struct stat statbuf;
      clear_mem(&statbuf, 1);
      stat(STAT_TARGETS[j], &statbuf);
      add_bytes(&statbuf, sizeof(statbuf));
      }

   add_bytes(getpid());
   add_bytes(getppid());

   add_bytes(getuid());
   add_bytes(getgid());
   add_bytes(geteuid());
   add_bytes(getegid());

   add_bytes(getpgrp());
   add_bytes(getsid(0));

   struct rusage usage;

   clear_mem(&usage, 1);
   getrusage(RUSAGE_SELF, &usage);
   add_bytes(&usage, sizeof(usage));

   getrusage(RUSAGE_CHILDREN, &usage);
   add_bytes(&usage, sizeof(usage));
   }

/*************************************************
* Unix Slow Poll                                 *
*************************************************/
void Unix_EntropySource::do_slow_poll()
   {
   const u32bit TRY_TO_GET = 16 * 1024;
   const u32bit MINIMAL_WORKING = 32;

   const std::string BASE_PATH = "/bin:/sbin:/usr/bin:/usr/sbin";
   const std::string EXTRA_PATH = global_config().option("rng/unix_path");

   std::string PATH = BASE_PATH;
   if(EXTRA_PATH != "")
      PATH += ':' + EXTRA_PATH;

   u32bit got = 0;
   for(u32bit j = 0; j != sources.size(); j++)
      {
      add_timestamp();

      DataSource_Command pipe(sources[j].name_and_args, PATH);
      SecureVector<byte> buffer(DEFAULT_BUFFERSIZE);

      u32bit got_from_src = 0;

      while(!pipe.end_of_data())
         {
         u32bit this_loop = pipe.read(buffer, buffer.size());
         add_bytes(buffer, this_loop);
         got_from_src += this_loop;
         }

      sources[j].working = (got_from_src >= MINIMAL_WORKING) ? true : false;
      got += got_from_src;

      if(got >= TRY_TO_GET)
         break;
      }
   }

}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/filters/ffmpeg_video_decode_engine.h"

#include "base/task.h"
#include "media/base/buffers.h"
#include "media/base/callback.h"
#include "media/base/limits.h"
#include "media/ffmpeg/ffmpeg_common.h"
#include "media/ffmpeg/ffmpeg_util.h"
#include "media/filters/ffmpeg_demuxer.h"

namespace media {

FFmpegVideoDecodeEngine::FFmpegVideoDecodeEngine()
    : codec_context_(NULL),
      state_(kCreated) {
}

FFmpegVideoDecodeEngine::~FFmpegVideoDecodeEngine() {
}

void FFmpegVideoDecodeEngine::Initialize(AVStream* stream, Task* done_cb) {
  AutoTaskRunner done_runner(done_cb);

  // Always try to use two threads for video decoding.  There is little reason
  // not to since current day CPUs tend to be multi-core and we measured
  // performance benefits on older machines such as P4s with hyperthreading.
  //
  // Handling decoding on separate threads also frees up the pipeline thread to
  // continue processing. Although it'd be nice to have the option of a single
  // decoding thread, FFmpeg treats having one thread the same as having zero
  // threads (i.e., avcodec_decode_video() will execute on the calling thread).
  // Yet another reason for having two threads :)
  static const int kDecodeThreads = 2;

  CHECK(state_ == kCreated);

  codec_context_ = stream->codec;
  codec_context_->flags2 |= CODEC_FLAG2_FAST;  // Enable faster H264 decode.
  // Enable motion vector search (potentially slow), strong deblocking filter
  // for damaged macroblocks, and set our error detection sensitivity.
  codec_context_->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK;
  codec_context_->error_recognition = FF_ER_CAREFUL;

  AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id);

  // TODO(fbarchard): On next ffmpeg roll, retest Theora multi-threading.
  int decode_threads = (codec_context_->codec_id == CODEC_ID_THEORA)
      ? 1 : kDecodeThreads;

  // We don't allocate AVFrame on the stack since different versions of FFmpeg
  // may change the size of AVFrame, causing stack corruption.  The solution is
  // to let FFmpeg allocate the structure via avcodec_alloc_frame().
  av_frame_.reset(avcodec_alloc_frame());

  if (codec &&
      avcodec_thread_init(codec_context_, decode_threads) >= 0 &&
      avcodec_open(codec_context_, codec) >= 0 &&
      av_frame_.get()) {
    state_ = kNormal;
  } else {
    state_ = kError;
  }
}

static void CopyPlane(size_t plane,
                      scoped_refptr<VideoFrame> video_frame,
                      const AVFrame* frame) {
  DCHECK(video_frame->width() % 2 == 0);
  const uint8* source = frame->data[plane];
  const size_t source_stride = frame->linesize[plane];
  uint8* dest = video_frame->data(plane);
  const size_t dest_stride = video_frame->stride(plane);
  size_t bytes_per_line = video_frame->width();
  size_t copy_lines = video_frame->height();
  if (plane != VideoFrame::kYPlane) {
    bytes_per_line /= 2;
    if (video_frame->format() == VideoFrame::YV12) {
      copy_lines = (copy_lines + 1) / 2;
    }
  }
  DCHECK(bytes_per_line <= source_stride && bytes_per_line <= dest_stride);
  for (size_t i = 0; i < copy_lines; ++i) {
    memcpy(dest, source, bytes_per_line);
    source += source_stride;
    dest += dest_stride;
  }
}

// Decodes one frame of video with the given buffer.
void FFmpegVideoDecodeEngine::DecodeFrame(
    Buffer* buffer,
    scoped_refptr<VideoFrame>* video_frame,
    bool* got_frame,
    Task* done_cb) {
  AutoTaskRunner done_runner(done_cb);
  *got_frame = false;
  *video_frame = NULL;

  // Create a packet for input data.
  // Due to FFmpeg API changes we no longer have const read-only pointers.
  AVPacket packet;
  av_init_packet(&packet);
  packet.data = const_cast<uint8*>(buffer->GetData());
  packet.size = buffer->GetDataSize();

  int frame_decoded = 0;
  int result = avcodec_decode_video2(codec_context_,
                                     av_frame_.get(),
                                     &frame_decoded,
                                     &packet);

  // Log the problem if we can't decode a video frame and exit early.
  if (result < 0) {
    LOG(INFO) << "Error decoding a video frame with timestamp: "
              << buffer->GetTimestamp().InMicroseconds() << " us"
              << " , duration: "
              << buffer->GetDuration().InMicroseconds() << " us"
              << " , packet size: "
              << buffer->GetDataSize() << " bytes";
    *got_frame = false;
  } else {
    // If frame_decoded == 0, then no frame was produced.
    *got_frame = frame_decoded != 0;

     if (*got_frame) {
       // TODO(fbarchard): Work around for FFmpeg http://crbug.com/27675
       // The decoder is in a bad state and not decoding correctly.
       // Checking for NULL avoids a crash in CopyPlane().
       if (!av_frame_->data[VideoFrame::kYPlane] ||
           !av_frame_->data[VideoFrame::kUPlane] ||
           !av_frame_->data[VideoFrame::kVPlane]) {
         // TODO(jiesun): this is also an error case handled as normal.
         *got_frame = false;
         return;
       }

       VideoFrame::CreateFrame(GetSurfaceFormat(),
                               codec_context_->width,
                               codec_context_->height,
                               StreamSample::kInvalidTimestamp,
                               StreamSample::kInvalidTimestamp,
                               video_frame);
       if (!video_frame->get()) {
         // TODO(jiesun): this is also an error case handled as normal.
         *got_frame = false;
         return;
       }

       // Copy the frame data since FFmpeg reuses internal buffers for AVFrame
       // output, meaning the data is only valid until the next
       // avcodec_decode_video() call.
       // TODO(scherkus): figure out pre-allocation/buffer cycling scheme.
       // TODO(scherkus): is there a cleaner way to figure out the # of planes?
       CopyPlane(VideoFrame::kYPlane, video_frame->get(), av_frame_.get());
       CopyPlane(VideoFrame::kUPlane, video_frame->get(), av_frame_.get());
       CopyPlane(VideoFrame::kVPlane, video_frame->get(), av_frame_.get());

       DCHECK_LE(av_frame_->repeat_pict, 2);  // Sanity check.
       (*video_frame)->SetRepeatCount(av_frame_->repeat_pict);
     }
  }
}

void FFmpegVideoDecodeEngine::Flush(Task* done_cb) {
  AutoTaskRunner done_runner(done_cb);

  avcodec_flush_buffers(codec_context_);
}

VideoFrame::Format FFmpegVideoDecodeEngine::GetSurfaceFormat() const {
  // J (Motion JPEG) versions of YUV are full range 0..255.
  // Regular (MPEG) YUV is 16..240.
  // For now we will ignore the distinction and treat them the same.
  switch (codec_context_->pix_fmt) {
    case PIX_FMT_YUV420P:
    case PIX_FMT_YUVJ420P:
      return VideoFrame::YV12;
      break;
    case PIX_FMT_YUV422P:
    case PIX_FMT_YUVJ422P:
      return VideoFrame::YV16;
      break;
    default:
      // TODO(scherkus): More formats here?
      return VideoFrame::INVALID;
  }
}

}  // namespace media
<commit_msg>Fix nested ifs and incorrect indentation in ffmpeg_video_decode_engine.cc.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/filters/ffmpeg_video_decode_engine.h"

#include "base/task.h"
#include "media/base/buffers.h"
#include "media/base/callback.h"
#include "media/base/limits.h"
#include "media/ffmpeg/ffmpeg_common.h"
#include "media/ffmpeg/ffmpeg_util.h"
#include "media/filters/ffmpeg_demuxer.h"

namespace media {

FFmpegVideoDecodeEngine::FFmpegVideoDecodeEngine()
    : codec_context_(NULL),
      state_(kCreated) {
}

FFmpegVideoDecodeEngine::~FFmpegVideoDecodeEngine() {
}

void FFmpegVideoDecodeEngine::Initialize(AVStream* stream, Task* done_cb) {
  AutoTaskRunner done_runner(done_cb);

  // Always try to use two threads for video decoding.  There is little reason
  // not to since current day CPUs tend to be multi-core and we measured
  // performance benefits on older machines such as P4s with hyperthreading.
  //
  // Handling decoding on separate threads also frees up the pipeline thread to
  // continue processing. Although it'd be nice to have the option of a single
  // decoding thread, FFmpeg treats having one thread the same as having zero
  // threads (i.e., avcodec_decode_video() will execute on the calling thread).
  // Yet another reason for having two threads :)
  static const int kDecodeThreads = 2;

  CHECK(state_ == kCreated);

  codec_context_ = stream->codec;
  codec_context_->flags2 |= CODEC_FLAG2_FAST;  // Enable faster H264 decode.
  // Enable motion vector search (potentially slow), strong deblocking filter
  // for damaged macroblocks, and set our error detection sensitivity.
  codec_context_->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK;
  codec_context_->error_recognition = FF_ER_CAREFUL;

  AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id);

  // TODO(fbarchard): On next ffmpeg roll, retest Theora multi-threading.
  int decode_threads = (codec_context_->codec_id == CODEC_ID_THEORA)
      ? 1 : kDecodeThreads;

  // We don't allocate AVFrame on the stack since different versions of FFmpeg
  // may change the size of AVFrame, causing stack corruption.  The solution is
  // to let FFmpeg allocate the structure via avcodec_alloc_frame().
  av_frame_.reset(avcodec_alloc_frame());

  if (codec &&
      avcodec_thread_init(codec_context_, decode_threads) >= 0 &&
      avcodec_open(codec_context_, codec) >= 0 &&
      av_frame_.get()) {
    state_ = kNormal;
  } else {
    state_ = kError;
  }
}

static void CopyPlane(size_t plane,
                      scoped_refptr<VideoFrame> video_frame,
                      const AVFrame* frame) {
  DCHECK(video_frame->width() % 2 == 0);
  const uint8* source = frame->data[plane];
  const size_t source_stride = frame->linesize[plane];
  uint8* dest = video_frame->data(plane);
  const size_t dest_stride = video_frame->stride(plane);
  size_t bytes_per_line = video_frame->width();
  size_t copy_lines = video_frame->height();
  if (plane != VideoFrame::kYPlane) {
    bytes_per_line /= 2;
    if (video_frame->format() == VideoFrame::YV12) {
      copy_lines = (copy_lines + 1) / 2;
    }
  }
  DCHECK(bytes_per_line <= source_stride && bytes_per_line <= dest_stride);
  for (size_t i = 0; i < copy_lines; ++i) {
    memcpy(dest, source, bytes_per_line);
    source += source_stride;
    dest += dest_stride;
  }
}

// Decodes one frame of video with the given buffer.
void FFmpegVideoDecodeEngine::DecodeFrame(
    Buffer* buffer,
    scoped_refptr<VideoFrame>* video_frame,
    bool* got_frame,
    Task* done_cb) {
  AutoTaskRunner done_runner(done_cb);
  *got_frame = false;
  *video_frame = NULL;

  // Create a packet for input data.
  // Due to FFmpeg API changes we no longer have const read-only pointers.
  AVPacket packet;
  av_init_packet(&packet);
  packet.data = const_cast<uint8*>(buffer->GetData());
  packet.size = buffer->GetDataSize();

  int frame_decoded = 0;
  int result = avcodec_decode_video2(codec_context_,
                                     av_frame_.get(),
                                     &frame_decoded,
                                     &packet);

  // Log the problem if we can't decode a video frame and exit early.
  if (result < 0) {
    LOG(INFO) << "Error decoding a video frame with timestamp: "
              << buffer->GetTimestamp().InMicroseconds() << " us"
              << " , duration: "
              << buffer->GetDuration().InMicroseconds() << " us"
              << " , packet size: "
              << buffer->GetDataSize() << " bytes";
    *got_frame = false;
    return;
  }

  // If frame_decoded == 0, then no frame was produced.
  *got_frame = frame_decoded != 0;
  if (!*got_frame) {
    return;
  }

  // TODO(fbarchard): Work around for FFmpeg http://crbug.com/27675
  // The decoder is in a bad state and not decoding correctly.
  // Checking for NULL avoids a crash in CopyPlane().
  if (!av_frame_->data[VideoFrame::kYPlane] ||
      !av_frame_->data[VideoFrame::kUPlane] ||
      !av_frame_->data[VideoFrame::kVPlane]) {
    // TODO(jiesun): this is also an error case handled as normal.
    *got_frame = false;
    return;
  }

  VideoFrame::CreateFrame(GetSurfaceFormat(),
                          codec_context_->width,
                          codec_context_->height,
                          StreamSample::kInvalidTimestamp,
                          StreamSample::kInvalidTimestamp,
                          video_frame);
  if (!video_frame->get()) {
    // TODO(jiesun): this is also an error case handled as normal.
    *got_frame = false;
    return;
  }

  // Copy the frame data since FFmpeg reuses internal buffers for AVFrame
  // output, meaning the data is only valid until the next
  // avcodec_decode_video() call.
  // TODO(scherkus): figure out pre-allocation/buffer cycling scheme.
  // TODO(scherkus): is there a cleaner way to figure out the # of planes?
  CopyPlane(VideoFrame::kYPlane, video_frame->get(), av_frame_.get());
  CopyPlane(VideoFrame::kUPlane, video_frame->get(), av_frame_.get());
  CopyPlane(VideoFrame::kVPlane, video_frame->get(), av_frame_.get());

  DCHECK_LE(av_frame_->repeat_pict, 2);  // Sanity check.
  (*video_frame)->SetRepeatCount(av_frame_->repeat_pict);
}

void FFmpegVideoDecodeEngine::Flush(Task* done_cb) {
  AutoTaskRunner done_runner(done_cb);

  avcodec_flush_buffers(codec_context_);
}

VideoFrame::Format FFmpegVideoDecodeEngine::GetSurfaceFormat() const {
  // J (Motion JPEG) versions of YUV are full range 0..255.
  // Regular (MPEG) YUV is 16..240.
  // For now we will ignore the distinction and treat them the same.
  switch (codec_context_->pix_fmt) {
    case PIX_FMT_YUV420P:
    case PIX_FMT_YUVJ420P:
      return VideoFrame::YV12;
      break;
    case PIX_FMT_YUV422P:
    case PIX_FMT_YUVJ422P:
      return VideoFrame::YV16;
      break;
    default:
      // TODO(scherkus): More formats here?
      return VideoFrame::INVALID;
  }
}

}  // namespace media
<|endoftext|>