<commit_before>/*
* Copyright (C) 2007-2013 German Aerospace Center (DLR/SC)
*
* Created: 2010-08-13 Markus Litz <Markus.Litz@dlr.de>
* Changed: $Id$
*
* Version: $Revision$
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* @brief  Implementation of the TIGL UID manager.
*/

#include "CTiglUIDManager.h"
#include "CTiglError.h"
#include "CTiglLogging.h"
#include "to_string.h"

namespace tigl
{

// Constructor
CTiglUIDManager::CTiglUIDManager()
    : invalidated(true), rootComponent(NULL) {}

void CTiglUIDManager::RegisterObject(const std::string& uid, void* object, const std::type_info& typeInfo)
{
    if (uid.empty()) {
        throw CTiglError("Tried to register an empty uid for type " + std::string(typeInfo.name()));
    }

    // check existence
    const CPACSObjectMap::iterator it = cpacsObjects.find(uid);
    if (it != cpacsObjects.end()) {
        throw CTiglError("Tried to register uid " + uid + " for type " + std::string(typeInfo.name()) + " which is already registered to an instance of " + std::string(it->second.type->name()));
    }

    // insert
    cpacsObjects.insert(it, std::make_pair(uid, TypedPtr(
                                               object,
                                               &typeInfo
                                           )));
}

CTiglUIDManager::TypedPtr CTiglUIDManager::ResolveObject(const std::string& uid, const std::type_info& typeInfo) const
{
    const TypedPtr object = ResolveObject(uid);

    // check type
    if (&typeInfo != object.type) {
        throw CTiglError("Object with uid \"" + uid + "\" is not a " + std::string(typeInfo.name()) + " but a " + std::string(object.type->name()), TIGL_UID_ERROR);
    }

    return object;
}

CTiglUIDManager::TypedPtr CTiglUIDManager::ResolveObject(const std::string& uid) const
{
    // check existence
    const CPACSObjectMap::const_iterator it = cpacsObjects.find(uid);
    if (it == cpacsObjects.end()) {
        throw CTiglError("No object is registered for uid \"" + uid + "\"", TIGL_UID_ERROR);
    }
    return it->second;
}

bool CTiglUIDManager::TryUnregisterObject(const std::string& uid)
{
    const CPACSObjectMap::iterator it = cpacsObjects.find(uid);
    if (it == cpacsObjects.end()) {
        return false;
    }
    cpacsObjects.erase(it);
    return true;
}

void CTiglUIDManager::UnregisterObject(const std::string& uid)
{
    if (!TryUnregisterObject(uid)) {
        throw CTiglError("No object is registered for uid \"" + uid + "\"", TIGL_UID_ERROR);
    }
}

namespace
{
void writeComponent(CTiglRelativelyPositionedComponent* c, int level = 0)
{
    std::string indentation;
    for (int i = 0; i < level; i++) {
        indentation += '\t';
    }
    const auto uid = c->GetDefaultedUID();
    LOG(INFO) << indentation << (uid.empty() ? "<no uid>" : uid) << std::endl;
    const CTiglRelativelyPositionedComponent::ChildContainerType& children = c->GetChildren(false);
    for (CTiglRelativelyPositionedComponent::ChildContainerType::const_iterator it = children.begin(); it != children.end(); ++it) {
        writeComponent(*it, level + 1);
    }
}
}

// Update internal UID manager data.
void CTiglUIDManager::Update()
{
    if (!invalidated) {
        return;
    }

    BuildTree();
    invalidated = false;

    LOG(INFO) << "Relative component trees:" << std::endl;
    for (RelativeComponentContainerType::const_iterator it = rootComponents.begin(); it != rootComponents.end(); ++it) {
        writeComponent(it->second);
    }
}

// Function to add a UID and a geometric component to the uid store.
void CTiglUIDManager::AddGeometricComponent(const std::string& uid, ITiglGeometricComponent* componentPtr)
{
    if (uid.empty()) {
        throw CTiglError("Empty UID in CTiglUIDManager::AddGeometricComponent", TIGL_XML_ERROR);
    }

    if (HasGeometricComponent(uid)) {
        throw CTiglError("Duplicate UID " + uid + " in CPACS file (CTiglUIDManager::AddGeometricComponent)", TIGL_XML_ERROR);
    }

    if (componentPtr == NULL) {
        throw CTiglError("Null pointer for component in CTiglUIDManager::AddGeometricComponent", TIGL_NULL_POINTER);
    }

    CTiglRelativelyPositionedComponent* tmp = dynamic_cast<CTiglRelativelyPositionedComponent*>(componentPtr);
    if (tmp && (componentPtr->GetComponentType() & TIGL_COMPONENT_PHYSICAL) ) {
        relativeComponents[uid] = tmp;
    }
    allShapes[uid] = componentPtr;
    invalidated = true;
}

void CTiglUIDManager::RemoveGeometricComponent(const std::string &uid)
{
    const ShapeContainerType::iterator it = allShapes.find(uid);
    if (it == allShapes.end()) {
        throw CTiglError("No shape is registered for uid \"" + uid + "\"");
    }
    allShapes.erase(it);
}

// Checks if a UID already exists.
bool CTiglUIDManager::HasGeometricComponent(const std::string& uid) const
{
    if (uid.empty()) {
        throw CTiglError("Empty UID in CTiglUIDManager::HasGeometricComponent", TIGL_XML_ERROR);
    }

    return (allShapes.find(uid) != allShapes.end());
}

// Returns a pointer to the geometric component for the given unique id.
ITiglGeometricComponent& CTiglUIDManager::GetGeometricComponent(const std::string& uid) const
{
    if (uid.empty()) {
        throw CTiglError("Empty UID in CTiglUIDManager::GetGeometricComponent", TIGL_UID_ERROR);
    }

    if (!HasGeometricComponent(uid)) {
        throw CTiglError("UID " + std_to_string(uid) + " not found in CTiglUIDManager::GetGeometricComponent", TIGL_UID_ERROR);
    }

    return *allShapes.find(uid)->second;
}

// Returns a pointer to the geometric component for the given unique id.
CTiglRelativelyPositionedComponent& CTiglUIDManager::GetRelativeComponent(const std::string& uid) const
{
    if (uid.empty()) {
        throw CTiglError("Empty UID in CTiglUIDManager::GetGeometricComponent", TIGL_XML_ERROR);
    }

    const RelativeComponentContainerType::const_iterator it = relativeComponents.find(uid);
    if (it == relativeComponents.end()) {
        throw CTiglError("UID '"+uid+"' not found in CTiglUIDManager::GetGeometricComponent", TIGL_XML_ERROR);
    }

    return *it->second;
}

// Clears the uid store
void CTiglUIDManager::Clear()
{
    relativeComponents.clear();
    allShapes.clear();
    rootComponents.clear();
    cpacsObjects.clear();
    invalidated = true;
}

// Returns the parent component for a component or a null pointer
// if there is no parent.
CTiglRelativelyPositionedComponent* CTiglUIDManager::GetParentGeometricComponent(const std::string& uid) const
{
    CTiglRelativelyPositionedComponent& component = GetRelativeComponent(uid);
    const boost::optional<const std::string&> parentUID = component.GetParentUID();
    return parentUID ? NULL : &GetRelativeComponent(*parentUID);
}

// Returns the container with all root components of the geometric topology that have children.
const RelativeComponentContainerType& CTiglUIDManager::GetRootGeometricComponents() const
{
    const_cast<CTiglUIDManager&>(*this).Update(); // TODO(bgruber): hack to keep up logical constness, think about mutable members
    return rootComponents;
}

// Builds the parent child relationships.
void CTiglUIDManager::BuildTree()
{
    // clear all relations
    for (RelativeComponentContainerType::iterator it = relativeComponents.begin(); it != relativeComponents.end(); ++it) {
        it->second->ClearChildren();
    }

    // build relations
    for (RelativeComponentContainerType::iterator it = relativeComponents.begin(); it != relativeComponents.end(); ++it) {
        CTiglRelativelyPositionedComponent& c = *it->second;
        const boost::optional<const std::string&> parentUid = c.GetParentUID();
        if (parentUid) {
            if (parentUid->empty()) {
                throw CTiglError("geometric component with uid " + c.GetDefaultedUID() + " has empty parentUid");
            }

            CTiglRelativelyPositionedComponent& p = GetRelativeComponent(*parentUid);
            p.AddChild(c);
            c.SetParent(p);
        }
    }

    // find all components without a parent uid and find component with most children
    std::size_t count = 0;
    for (RelativeComponentContainerType::iterator it = relativeComponents.begin(); it != relativeComponents.end(); ++it) {
        CTiglRelativelyPositionedComponent* c = it->second;
        if (!c->GetParentUID()) {
            rootComponents[it->first] = c;
        }
        const std::size_t childCount = c->GetChildren(true).size();
        if (childCount > count) {
            count = childCount;
            rootComponent = c;
        }
    }
}

const ShapeContainerType& CTiglUIDManager::GetShapeContainer() const
{
    return allShapes;
}

} // end namespace tigl

<commit_msg>Fixed invalid auto in pre c++11 code<commit_after>/*
* Copyright (C) 2007-2013 German Aerospace Center (DLR/SC)
*
* Created: 2010-08-13 Markus Litz <Markus.Litz@dlr.de>
* Changed: $Id$
*
* Version: $Revision$
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* @brief  Implementation of the TIGL UID manager.
*/

#include "CTiglUIDManager.h"
#include "CTiglError.h"
#include "CTiglLogging.h"
#include "to_string.h"

namespace tigl
{

// Constructor
CTiglUIDManager::CTiglUIDManager()
    : invalidated(true), rootComponent(NULL) {}

void CTiglUIDManager::RegisterObject(const std::string& uid, void* object, const std::type_info& typeInfo)
{
    if (uid.empty()) {
        throw CTiglError("Tried to register an empty uid for type " + std::string(typeInfo.name()));
    }

    // check existence
    const CPACSObjectMap::iterator it = cpacsObjects.find(uid);
    if (it != cpacsObjects.end()) {
        throw CTiglError("Tried to register uid " + uid + " for type " + std::string(typeInfo.name()) + " which is already registered to an instance of " + std::string(it->second.type->name()));
    }

    // insert
    cpacsObjects.insert(it, std::make_pair(uid, TypedPtr(
                                               object,
                                               &typeInfo
                                           )));
}

CTiglUIDManager::TypedPtr CTiglUIDManager::ResolveObject(const std::string& uid, const std::type_info& typeInfo) const
{
    const TypedPtr object = ResolveObject(uid);

    // check type
    if (&typeInfo != object.type) {
        throw CTiglError("Object with uid \"" + uid + "\" is not a " + std::string(typeInfo.name()) + " but a " + std::string(object.type->name()), TIGL_UID_ERROR);
    }

    return object;
}

CTiglUIDManager::TypedPtr CTiglUIDManager::ResolveObject(const std::string& uid) const
{
    // check existence
    const CPACSObjectMap::const_iterator it = cpacsObjects.find(uid);
    if (it == cpacsObjects.end()) {
        throw CTiglError("No object is registered for uid \"" + uid + "\"", TIGL_UID_ERROR);
    }
    return it->second;
}

bool CTiglUIDManager::TryUnregisterObject(const std::string& uid)
{
    const CPACSObjectMap::iterator it = cpacsObjects.find(uid);
    if (it == cpacsObjects.end()) {
        return false;
    }
    cpacsObjects.erase(it);
    return true;
}

void CTiglUIDManager::UnregisterObject(const std::string& uid)
{
    if (!TryUnregisterObject(uid)) {
        throw CTiglError("No object is registered for uid \"" + uid + "\"", TIGL_UID_ERROR);
    }
}

namespace
{
void writeComponent(CTiglRelativelyPositionedComponent* c, int level = 0)
{
    std::string indentation;
    for (int i = 0; i < level; i++) {
        indentation += '\t';
    }
    const std::string uid = c->GetDefaultedUID();
    LOG(INFO) << indentation << (uid.empty() ? "<no uid>" : uid) << std::endl;
    const CTiglRelativelyPositionedComponent::ChildContainerType& children = c->GetChildren(false);
    for (CTiglRelativelyPositionedComponent::ChildContainerType::const_iterator it = children.begin(); it != children.end(); ++it) {
        writeComponent(*it, level + 1);
    }
}
}

// Update internal UID manager data.
void CTiglUIDManager::Update()
{
    if (!invalidated) {
        return;
    }

    BuildTree();
    invalidated = false;

    LOG(INFO) << "Relative component trees:" << std::endl;
    for (RelativeComponentContainerType::const_iterator it = rootComponents.begin(); it != rootComponents.end(); ++it) {
        writeComponent(it->second);
    }
}

// Function to add a UID and a geometric component to the uid store.
void CTiglUIDManager::AddGeometricComponent(const std::string& uid, ITiglGeometricComponent* componentPtr)
{
    if (uid.empty()) {
        throw CTiglError("Empty UID in CTiglUIDManager::AddGeometricComponent", TIGL_XML_ERROR);
    }

    if (HasGeometricComponent(uid)) {
        throw CTiglError("Duplicate UID " + uid + " in CPACS file (CTiglUIDManager::AddGeometricComponent)", TIGL_XML_ERROR);
    }

    if (componentPtr == NULL) {
        throw CTiglError("Null pointer for component in CTiglUIDManager::AddGeometricComponent", TIGL_NULL_POINTER);
    }

    CTiglRelativelyPositionedComponent* tmp = dynamic_cast<CTiglRelativelyPositionedComponent*>(componentPtr);
    if (tmp && (componentPtr->GetComponentType() & TIGL_COMPONENT_PHYSICAL) ) {
        relativeComponents[uid] = tmp;
    }
    allShapes[uid] = componentPtr;
    invalidated = true;
}

void CTiglUIDManager::RemoveGeometricComponent(const std::string &uid)
{
    const ShapeContainerType::iterator it = allShapes.find(uid);
    if (it == allShapes.end()) {
        throw CTiglError("No shape is registered for uid \"" + uid + "\"");
    }
    allShapes.erase(it);
}

// Checks if a UID already exists.
bool CTiglUIDManager::HasGeometricComponent(const std::string& uid) const
{
    if (uid.empty()) {
        throw CTiglError("Empty UID in CTiglUIDManager::HasGeometricComponent", TIGL_XML_ERROR);
    }

    return (allShapes.find(uid) != allShapes.end());
}

// Returns a pointer to the geometric component for the given unique id.
ITiglGeometricComponent& CTiglUIDManager::GetGeometricComponent(const std::string& uid) const
{
    if (uid.empty()) {
        throw CTiglError("Empty UID in CTiglUIDManager::GetGeometricComponent", TIGL_UID_ERROR);
    }

    if (!HasGeometricComponent(uid)) {
        throw CTiglError("UID " + std_to_string(uid) + " not found in CTiglUIDManager::GetGeometricComponent", TIGL_UID_ERROR);
    }

    return *allShapes.find(uid)->second;
}

// Returns a pointer to the geometric component for the given unique id.
CTiglRelativelyPositionedComponent& CTiglUIDManager::GetRelativeComponent(const std::string& uid) const
{
    if (uid.empty()) {
        throw CTiglError("Empty UID in CTiglUIDManager::GetGeometricComponent", TIGL_XML_ERROR);
    }

    const RelativeComponentContainerType::const_iterator it = relativeComponents.find(uid);
    if (it == relativeComponents.end()) {
        throw CTiglError("UID '"+uid+"' not found in CTiglUIDManager::GetGeometricComponent", TIGL_XML_ERROR);
    }

    return *it->second;
}

// Clears the uid store
void CTiglUIDManager::Clear()
{
    relativeComponents.clear();
    allShapes.clear();
    rootComponents.clear();
    cpacsObjects.clear();
    invalidated = true;
}

// Returns the parent component for a component or a null pointer
// if there is no parent.
CTiglRelativelyPositionedComponent* CTiglUIDManager::GetParentGeometricComponent(const std::string& uid) const
{
    CTiglRelativelyPositionedComponent& component = GetRelativeComponent(uid);
    const boost::optional<const std::string&> parentUID = component.GetParentUID();
    return parentUID ? NULL : &GetRelativeComponent(*parentUID);
}

// Returns the container with all root components of the geometric topology that have children.
const RelativeComponentContainerType& CTiglUIDManager::GetRootGeometricComponents() const
{
    const_cast<CTiglUIDManager&>(*this).Update(); // TODO(bgruber): hack to keep up logical constness, think about mutable members
    return rootComponents;
}

// Builds the parent child relationships.
void CTiglUIDManager::BuildTree()
{
    // clear all relations
    for (RelativeComponentContainerType::iterator it = relativeComponents.begin(); it != relativeComponents.end(); ++it) {
        it->second->ClearChildren();
    }

    // build relations
    for (RelativeComponentContainerType::iterator it = relativeComponents.begin(); it != relativeComponents.end(); ++it) {
        CTiglRelativelyPositionedComponent& c = *it->second;
        const boost::optional<const std::string&> parentUid = c.GetParentUID();
        if (parentUid) {
            if (parentUid->empty()) {
                throw CTiglError("geometric component with uid " + c.GetDefaultedUID() + " has empty parentUid");
            }

            CTiglRelativelyPositionedComponent& p = GetRelativeComponent(*parentUid);
            p.AddChild(c);
            c.SetParent(p);
        }
    }

    // find all components without a parent uid and find component with most children
    std::size_t count = 0;
    for (RelativeComponentContainerType::iterator it = relativeComponents.begin(); it != relativeComponents.end(); ++it) {
        CTiglRelativelyPositionedComponent* c = it->second;
        if (!c->GetParentUID()) {
            rootComponents[it->first] = c;
        }
        const std::size_t childCount = c->GetChildren(true).size();
        if (childCount > count) {
            count = childCount;
            rootComponent = c;
        }
    }
}

const ShapeContainerType& CTiglUIDManager::GetShapeContainer() const
{
    return allShapes;
}

} // end namespace tigl

<|endoftext|>


<commit_before>/**
 * @file	src/dataLoggers/SaveImageLogger.cpp
 * @date	Jan. 2017
 * @author	PhRG - opticalp.fr
 */

/*
 Copyright (c) 2017 Ph. Renaud-Goud / Opticalp

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 */

#ifdef HAVE_OPENCV

#include "SaveImageLogger.h"
#include "core/DataItem.h"

#include "Poco/NumberFormatter.h"

#include "opencv2/opencv.hpp"

size_t SaveImageLogger::refCount = 0;

SaveImageLogger::SaveImageLogger():
        DataLogger("SaveImageLogger"),
        nextIndex(1), extension(".png"),
        prefix("img_"), digits(2)
{
    setName(refCount);

    setParameterCount(paramCnt);
    addParameter(paramDirectory, "directory", "Directory in which to store the images",
            ParamItem::typeString, "");
    addParameter(paramPrefix, "prefix", "Prefix to be used to build the image file name",
            ParamItem::typeString, "img_");
    addParameter(paramDigits, "digits", "Count of digits to be used to build the image file name. "
            "Those digits will follow the prefix", ParamItem::typeInteger, "2");
    addParameter(paramExtension, "extension", "Image file extension, including the dot. E.g. \".png\"",
            ParamItem::typeString, ".png");
    addParameter(paramNextIndex, "nextIndex", "Next index to be used to generate the image file name",
            ParamItem::typeInteger, "1");

    refCount++;
}

void SaveImageLogger::log()
{
    cv::Mat img = *(getDataSource()->getData<cv::Mat>());

    if (img.data)
    {
        Poco::Path imgPath(directory);

        if (digits)
        {
            std::string fullIndex = Poco::NumberFormatter::format(nextIndex, digits);
            std::string index(fullIndex.end()-digits, fullIndex.end()); // cheap modulo
            imgPath.append(prefix + index + extension);
        }
        else
        {
            imgPath.append(prefix + extension);
        }

        // write image.
        cv::imwrite(imgPath.toString(), img);

        // increment parameters
        nextIndex++;
    }
    else
    {
        throw Poco::RuntimeException(name(),"empty image, nothing to save");
    }
}

bool SaveImageLogger::isSupportedInputDataType(int datatype)
{
    return (datatype == (DataItem::typeCvMat | DataItem::contScalar));
}

std::set<int> SaveImageLogger::supportedInputDataType()
{
    std::set<int> ret;
    ret.insert(DataItem::typeCvMat);
    return ret;
}

Poco::Int64 SaveImageLogger::getIntParameterValue(size_t paramIndex)
{
    switch (paramIndex)
    {
    case paramDigits:
        return digits;
    case paramNextIndex:
        return nextIndex;
    default:
        poco_bugcheck_msg("wrong parameter index");
        throw Poco::BugcheckException();
    }
}

std::string SaveImageLogger::getStrParameterValue(size_t paramIndex)
{
    switch (paramIndex)
    {
    case paramDirectory:
        return directory.toString();
    case paramPrefix:
        return prefix;
    case paramExtension:
        return extension;
    default:
        poco_bugcheck_msg("wrong parameter index");
        throw Poco::BugcheckException();
    }
}

void SaveImageLogger::setIntParameterValue(size_t paramIndex, Poco::Int64 value)
{
    switch (paramIndex)
    {
    case paramDigits:
        if (digits < 0)
            throw Poco::RangeException("setParameterValue",
                    "parameter digits has to be positive");
        digits = value;
        break;
    case paramNextIndex:
        nextIndex = value;
        break;
    default:
        poco_bugcheck_msg("wrong parameter index");
        throw Poco::BugcheckException();
    }
}

void SaveImageLogger::setStrParameterValue(size_t paramIndex, std::string value)
{
    switch (paramIndex)
    {
    case paramDirectory:
        directory = value;
        directory.makeAbsolute();
        break;
    case paramPrefix:
        prefix = value;
        break;
    case paramExtension:
        extension = value;
        break;
    default:
        poco_bugcheck_msg("wrong parameter index");
        throw Poco::BugcheckException();
    }
}

#endif /* HAVE_OPENCV */
<commit_msg>Add simple image type conversion while saving<commit_after>/**
 * @file	src/dataLoggers/SaveImageLogger.cpp
 * @date	Jan. 2017
 * @author	PhRG - opticalp.fr
 */

/*
 Copyright (c) 2017 Ph. Renaud-Goud / Opticalp

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 */

#ifdef HAVE_OPENCV

#include "SaveImageLogger.h"
#include "core/DataItem.h"

#include "Poco/NumberFormatter.h"

#include "opencv2/opencv.hpp"

size_t SaveImageLogger::refCount = 0;

SaveImageLogger::SaveImageLogger():
        DataLogger("SaveImageLogger"),
        nextIndex(1), extension(".png"),
        prefix("img_"), digits(2)
{
    setName(refCount);

    setParameterCount(paramCnt);
    addParameter(paramDirectory, "directory", "Directory in which to store the images",
            ParamItem::typeString, "");
    addParameter(paramPrefix, "prefix", "Prefix to be used to build the image file name",
            ParamItem::typeString, "img_");
    addParameter(paramDigits, "digits", "Count of digits to be used to build the image file name. "
            "Those digits will follow the prefix", ParamItem::typeInteger, "2");
    addParameter(paramExtension, "extension", "Image file extension, including the dot. E.g. \".png\"",
            ParamItem::typeString, ".png");
    addParameter(paramNextIndex, "nextIndex", "Next index to be used to generate the image file name",
            ParamItem::typeInteger, "1");

    refCount++;
}

void SaveImageLogger::log()
{
    cv::Mat img = *(getDataSource()->getData<cv::Mat>());

    if (img.data)
    {
        Poco::Path imgPath(directory);

        if (digits)
        {
            std::string fullIndex = Poco::NumberFormatter::format(nextIndex, digits);
            std::string index(fullIndex.end()-digits, fullIndex.end()); // cheap modulo
            imgPath.append(prefix + index + extension);
        }
        else
        {
            imgPath.append(prefix + extension);
        }

        if (img.type()!=CV_8U && img.type()!=CV_16U)
        {
            double min,max;
            cv::minMaxLoc(img,&min,&max);

            cv::Mat tmpImg; // temporary image
            img.convertTo(
                    tmpImg,      // output image
                    CV_8U,       // depth
                    255.0/max ); // scale factor

            // save image
            cv::imwrite(imgPath.toString(), tmpImg);
        }
        else
        {
            cv::imwrite(imgPath.toString(), img);
        }

        // increment parameters
        nextIndex++;
    }
    else
    {
        throw Poco::RuntimeException(name(),"empty image, nothing to save");
    }
}

bool SaveImageLogger::isSupportedInputDataType(int datatype)
{
    return (datatype == (DataItem::typeCvMat | DataItem::contScalar));
}

std::set<int> SaveImageLogger::supportedInputDataType()
{
    std::set<int> ret;
    ret.insert(DataItem::typeCvMat);
    return ret;
}

Poco::Int64 SaveImageLogger::getIntParameterValue(size_t paramIndex)
{
    switch (paramIndex)
    {
    case paramDigits:
        return digits;
    case paramNextIndex:
        return nextIndex;
    default:
        poco_bugcheck_msg("wrong parameter index");
        throw Poco::BugcheckException();
    }
}

std::string SaveImageLogger::getStrParameterValue(size_t paramIndex)
{
    switch (paramIndex)
    {
    case paramDirectory:
        return directory.toString();
    case paramPrefix:
        return prefix;
    case paramExtension:
        return extension;
    default:
        poco_bugcheck_msg("wrong parameter index");
        throw Poco::BugcheckException();
    }
}

void SaveImageLogger::setIntParameterValue(size_t paramIndex, Poco::Int64 value)
{
    switch (paramIndex)
    {
    case paramDigits:
        if (digits < 0)
            throw Poco::RangeException("setParameterValue",
                    "parameter digits has to be positive");
        digits = value;
        break;
    case paramNextIndex:
        nextIndex = value;
        break;
    default:
        poco_bugcheck_msg("wrong parameter index");
        throw Poco::BugcheckException();
    }
}

void SaveImageLogger::setStrParameterValue(size_t paramIndex, std::string value)
{
    switch (paramIndex)
    {
    case paramDirectory:
        directory = value;
        directory.makeAbsolute();
        break;
    case paramPrefix:
        prefix = value;
        break;
    case paramExtension:
        extension = value;
        break;
    default:
        poco_bugcheck_msg("wrong parameter index");
        throw Poco::BugcheckException();
    }
}

#endif /* HAVE_OPENCV */
<|endoftext|>


<commit_before>#include <mesos_sched.hpp>

#include <libgen.h>

#include <cstdlib>
#include <iostream>
#include <sstream>

#include <boost/lexical_cast.hpp>

#include "foreach.hpp"

using namespace std;
using namespace mesos;
using boost::lexical_cast;

class MyScheduler : public Scheduler
{
  string executor;
  int tasksLaunched;
  int tasksFinished;
  int totalTasks;

public:
  MyScheduler(const string& exec)
    : executor(exec), tasksLaunched(0), tasksFinished(0), totalTasks(5) {}

  virtual ~MyScheduler() {}

  virtual string getFrameworkName(SchedulerDriver*) {
    return "C++ Test Framework";
  }

  virtual ExecutorInfo getExecutorInfo(SchedulerDriver*) {
    return ExecutorInfo(executor, "");
  }

  virtual void registered(SchedulerDriver*, FrameworkID fid) {
    cout << "Registered!" << endl;
  }

  virtual void resourceOffer(SchedulerDriver* d,
                             OfferID id,
                             const std::vector<SlaveOffer>& offers) {
    cout << "." << flush;
    vector<TaskDescription> tasks;
    foreach (const SlaveOffer &offer, offers) {
      // This is kind of ugly because operator[] isn't a const function
      int32_t cpus = lexical_cast<int32_t>(offer.params.find("cpus")->second);
      int32_t mem = lexical_cast<int64_t>(offer.params.find("mem")->second);
      if ((tasksLaunched < totalTasks) && (cpus >= 1 && mem >= 32)) {
        TaskID tid = tasksLaunched++;

        cout << endl << "Starting task " << tid << endl;
        string name = "Task " + lexical_cast<string>(tid);
        map<string, string> taskParams;
        taskParams["cpus"] = "1";
        taskParams["mem"] = "32";
        TaskDescription desc(tid, offer.slaveId, name, taskParams, "");
        tasks.push_back(desc);
      }
    }
    map<string, string> params;
    params["timeout"] = "-1";
    d->replyToOffer(id, tasks, params);
  }

  virtual void statusUpdate(SchedulerDriver* d, const TaskStatus& status) {
    cout << endl;
    cout << "Task " << status.taskId << " is in state " << status.state << endl;
    if (status.state == TASK_FINISHED)
      tasksFinished++;
    if (tasksFinished == totalTasks)
      d->stop();
  }
};

int main(int argc, char ** argv) {
  if (argc != 2) {
    cerr << "Usage: " << argv[0] << " <masterPid>" << endl;
    return -1;
  }
  // Find this executable's directory to locate executor
  char buf[4096];
  realpath(dirname(argv[0]), buf);
  string executor = string(buf) + "/test-executor";
  // Run a Mesos scheduler
  MyScheduler sched(executor);
  MesosSchedulerDriver driver(&sched, argv[1]);
  driver.run();
  return 0;
}
<commit_msg>Use the correct executor for the C++ test framework<commit_after>#include <mesos_sched.hpp>

#include <libgen.h>

#include <cstdlib>
#include <iostream>
#include <sstream>

#include <boost/lexical_cast.hpp>

#include "foreach.hpp"

using namespace std;
using namespace mesos;
using boost::lexical_cast;

class MyScheduler : public Scheduler
{
  string executor;
  int tasksLaunched;
  int tasksFinished;
  int totalTasks;

public:
  MyScheduler(const string& exec)
    : executor(exec), tasksLaunched(0), tasksFinished(0), totalTasks(5) {}

  virtual ~MyScheduler() {}

  virtual string getFrameworkName(SchedulerDriver*) {
    return "C++ Test Framework";
  }

  virtual ExecutorInfo getExecutorInfo(SchedulerDriver*) {
    return ExecutorInfo(executor, "");
  }

  virtual void registered(SchedulerDriver*, FrameworkID fid) {
    cout << "Registered!" << endl;
  }

  virtual void resourceOffer(SchedulerDriver* d,
                             OfferID id,
                             const std::vector<SlaveOffer>& offers) {
    cout << "." << flush;
    vector<TaskDescription> tasks;
    foreach (const SlaveOffer &offer, offers) {
      // This is kind of ugly because operator[] isn't a const function
      int32_t cpus = lexical_cast<int32_t>(offer.params.find("cpus")->second);
      int32_t mem = lexical_cast<int64_t>(offer.params.find("mem")->second);
      if ((tasksLaunched < totalTasks) && (cpus >= 1 && mem >= 32)) {
        TaskID tid = tasksLaunched++;

        cout << endl << "Starting task " << tid << endl;
        string name = "Task " + lexical_cast<string>(tid);
        map<string, string> taskParams;
        taskParams["cpus"] = "1";
        taskParams["mem"] = "32";
        TaskDescription desc(tid, offer.slaveId, name, taskParams, "");
        tasks.push_back(desc);
      }
    }
    map<string, string> params;
    params["timeout"] = "-1";
    d->replyToOffer(id, tasks, params);
  }

  virtual void statusUpdate(SchedulerDriver* d, const TaskStatus& status) {
    cout << endl;
    cout << "Task " << status.taskId << " is in state " << status.state << endl;
    if (status.state == TASK_FINISHED)
      tasksFinished++;
    if (tasksFinished == totalTasks)
      d->stop();
  }
};

int main(int argc, char ** argv) {
  if (argc != 2) {
    cerr << "Usage: " << argv[0] << " <masterPid>" << endl;
    return -1;
  }
  // Find this executable's directory to locate executor
  char buf[4096];
  realpath(dirname(argv[0]), buf);
  string executor = string(buf) + "/cpp-test-executor";
  // Run a Mesos scheduler
  MyScheduler sched(executor);
  MesosSchedulerDriver driver(&sched, argv[1]);
  driver.run();
  return 0;
}
<|endoftext|>


<commit_before>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/lite/kernels/internal/reference/pooling.h"
#include "arm_nnfunctions.h"
#include "scratch_buffer.h"
#include "tensorflow/lite/c/builtin_op_data.h"
#include "tensorflow/lite/kernels/internal/reference/integer_ops/pooling.h"
#include "tensorflow/lite/kernels/internal/tensor_ctypes.h"
#include "tensorflow/lite/kernels/kernel_util.h"
#include "tensorflow/lite/kernels/padding.h"

namespace tflite {
namespace ops {
namespace micro {
namespace pooling {

namespace {

constexpr int kInputTensor = 0;
constexpr int kOutputTensor = 0;

struct OpData {
  TfLitePaddingValues padding;
};

TfLiteStatus CalculateOpData(const TfLiteContext* context,
                             const TfLitePoolParams* params,
                             const TfLiteTensor* input,
                             const TfLiteTensor* output, OpData* data) {
  // input: batch, height, width, channel
  int height = SizeOfDimension(input, 1);
  int width = SizeOfDimension(input, 2);

  int out_height, out_width;

  data->padding = ComputePaddingHeightWidth(
      params->stride_height, params->stride_width,
      /*dilation_rate_height=*/1,
      /*dilation_rate_width=*/1, height, width, params->filter_height,
      params->filter_width, params->padding, &out_height, &out_width);

  return kTfLiteOk;
}

void AverageEvalFloat(const TfLiteContext* context, const TfLiteNode* node,
                      const TfLitePoolParams* params, const OpData* data,
                      const TfLiteTensor* input, TfLiteTensor* output) {
  float activation_min, activation_max;
  CalculateActivationRange(params->activation, &activation_min,
                           &activation_max);

  PoolParams op_params;
  op_params.stride_height = params->stride_height;
  op_params.stride_width = params->stride_width;
  op_params.filter_height = params->filter_height;
  op_params.filter_width = params->filter_width;
  op_params.padding_values.height = data->padding.height;
  op_params.padding_values.width = data->padding.width;
  op_params.float_activation_min = activation_min;
  op_params.float_activation_max = activation_max;
  reference_ops::AveragePool(
      op_params, GetTensorShape(input), GetTensorData<float>(input),
      GetTensorShape(output), GetTensorData<float>(output));
}

void AverageEvalUint8(const TfLiteContext* context, const TfLiteNode* node,
                      const TfLitePoolParams* params, const OpData* data,
                      const TfLiteTensor* input, TfLiteTensor* output) {
  int32_t activation_min, activation_max;
  CalculateActivationRangeUint8(params->activation, output, &activation_min,
                                &activation_max);

  PoolParams op_params;
  op_params.stride_height = params->stride_height;
  op_params.stride_width = params->stride_width;
  op_params.filter_height = params->filter_height;
  op_params.filter_width = params->filter_width;
  op_params.padding_values.height = data->padding.height;
  op_params.padding_values.width = data->padding.width;
  op_params.quantized_activation_min = activation_min;
  op_params.quantized_activation_max = activation_max;
  reference_ops::AveragePool(
      op_params, GetTensorShape(input), GetTensorData<uint8_t>(input),
      GetTensorShape(output), GetTensorData<uint8_t>(output));
}

TfLiteStatus AverageEvalInt8(const TfLiteContext* context,
                             const TfLiteNode* node,
                             const TfLitePoolParams* params, const OpData* data,
                             const TfLiteTensor* input, TfLiteTensor* output) {
  int32_t activation_min, activation_max;
  CalculateActivationRangeInt8(params->activation, output, &activation_min,
                               &activation_max);

  TFLITE_DCHECK_LE(params->quantized_activation_min,
                   params->quantized_activation_max);

  RuntimeShape input_shape = GetTensorShape(input);
  TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4);

  RuntimeShape output_shape = GetTensorShape(output);
  TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4);

  const int batches = MatchingDim(input_shape, 0, output_shape, 0);
  const int depth = MatchingDim(input_shape, 3, output_shape, 3);
  const int input_height = input_shape.Dims(1);
  const int input_width = input_shape.Dims(2);
  const int output_height = output_shape.Dims(1);
  const int output_width = output_shape.Dims(2);
  const int stride_height = params->stride_height;
  const int stride_width = params->stride_width;

  const int filter_height = params->filter_height;
  const int filter_width = params->filter_width;
  const int padding_height = data->padding.height;
  const int padding_width = data->padding.width;

#if defined(ARM_MATH_DSP) && defined(ARM_MATH_LOOPUNROLL)
  int16_t* scratch_buffer = nullptr;
  const int32_t buffer_size =
      arm_avgpool_s8_get_buffer_size(output_width, depth);

  TF_LITE_ENSURE_OK(
      context, get_cmsis_scratch_buffer(context, &scratch_buffer, buffer_size));

  TF_LITE_ENSURE_EQ(
      context,
      arm_avgpool_s8(input_height, input_width, output_height, output_width,
                     stride_height, stride_width, filter_height, filter_width,
                     padding_height, padding_width, activation_min,
                     activation_max, depth, GetTensorData<int8_t>(input),
                     scratch_buffer, GetTensorData<int8_t>(output)),
      ARM_MATH_SUCCESS);
#else
#error ARM_MATH_DSP and ARM_MATH_LOOPUNROLL must be set
#endif
  return kTfLiteOk;
}

void MaxEvalFloat(TfLiteContext* context, TfLiteNode* node,
                  TfLitePoolParams* params, OpData* data,
                  const TfLiteTensor* input, TfLiteTensor* output) {
  float activation_min, activation_max;
  CalculateActivationRange(params->activation, &activation_min,
                           &activation_max);

  tflite::PoolParams op_params;
  op_params.stride_height = params->stride_height;
  op_params.stride_width = params->stride_width;
  op_params.filter_height = params->filter_height;
  op_params.filter_width = params->filter_width;
  op_params.padding_values.height = data->padding.height;
  op_params.padding_values.width = data->padding.width;
  op_params.float_activation_min = activation_min;
  op_params.float_activation_max = activation_max;
  reference_ops::MaxPool(op_params, GetTensorShape(input),
                         GetTensorData<float>(input), GetTensorShape(output),
                         GetTensorData<float>(output));
}

void MaxEvalQuantizedUInt8(TfLiteContext* context, TfLiteNode* node,
                           TfLitePoolParams* params, OpData* data,
                           const TfLiteTensor* input, TfLiteTensor* output) {
  int32_t activation_min, activation_max;
  CalculateActivationRangeUint8(params->activation, output, &activation_min,
                                &activation_max);

  tflite::PoolParams op_params;
  op_params.stride_height = params->stride_height;
  op_params.stride_width = params->stride_width;
  op_params.filter_height = params->filter_height;
  op_params.filter_width = params->filter_width;
  op_params.padding_values.height = data->padding.height;
  op_params.padding_values.width = data->padding.width;
  op_params.quantized_activation_min = activation_min;
  op_params.quantized_activation_max = activation_max;
  reference_ops::MaxPool(op_params, GetTensorShape(input),
                         GetTensorData<uint8_t>(input), GetTensorShape(output),
                         GetTensorData<uint8_t>(output));
}

}  // namespace

void* Init(TfLiteContext* context, const char* buffer, size_t length) {
  return nullptr;
}

void Free(TfLiteContext* context, void* buffer) {}

TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
  return kTfLiteOk;
}

TfLiteStatus AverageEval(TfLiteContext* context, TfLiteNode* node) {
  auto* params = reinterpret_cast<TfLitePoolParams*>(node->builtin_data);
  OpData data;

  const TfLiteTensor* input = GetInput(context, node, kInputTensor);
  TfLiteTensor* output = GetOutput(context, node, kOutputTensor);

  TF_LITE_ENSURE_STATUS(CalculateOpData(context, params, input, output, &data));

  // Inputs and outputs share the same type, guarenteed by the converter.
  switch (input->type) {
    case kTfLiteFloat32:
      AverageEvalFloat(context, node, params, &data, input, output);
      break;
    case kTfLiteUInt8:
      AverageEvalUint8(context, node, params, &data, input, output);
      break;
    case kTfLiteInt8:
      return AverageEvalInt8(context, node, params, &data, input, output);
      break;
    default:
      context->ReportError(context, "Input type %s is not currently supported",
                           TfLiteTypeGetName(input->type));
      return kTfLiteError;
  }
  return kTfLiteOk;
}

TfLiteStatus MaxEval(TfLiteContext* context, TfLiteNode* node) {
  auto* params = reinterpret_cast<TfLitePoolParams*>(node->builtin_data);
  OpData data;

  const TfLiteTensor* input = GetInput(context, node, kInputTensor);
  TfLiteTensor* output = GetOutput(context, node, kOutputTensor);

  TF_LITE_ENSURE_STATUS(CalculateOpData(context, params, input, output, &data));

  switch (input->type) {
    case kTfLiteFloat32:
      MaxEvalFloat(context, node, params, &data, input, output);
      break;
    case kTfLiteUInt8:
      MaxEvalQuantizedUInt8(context, node, params, &data, input, output);
      break;
    default:
      context->ReportError(context, "Type %s not currently supported.",
                           TfLiteTypeGetName(input->type));
      return kTfLiteError;
  }
  return kTfLiteOk;
}

}  // namespace pooling

TfLiteRegistration* Register_AVERAGE_POOL_2D() {
  static TfLiteRegistration r = {
      pooling::Init,
      pooling::Free,
      pooling::Prepare,
      pooling::AverageEval,
  };
  return &r;
}

TfLiteRegistration* Register_MAX_POOL_2D() {
  static TfLiteRegistration r = {pooling::Init, pooling::Free, pooling::Prepare,
                                 pooling::MaxEval};
  return &r;
}

}  // namespace micro
}  // namespace ops
}  // namespace tflite
<commit_msg>Added reference average pooling kernel fallback<commit_after>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/lite/kernels/internal/reference/pooling.h"
#include "arm_nnfunctions.h"
#include "scratch_buffer.h"
#include "tensorflow/lite/c/builtin_op_data.h"
#include "tensorflow/lite/kernels/internal/reference/integer_ops/pooling.h"
#include "tensorflow/lite/kernels/internal/tensor_ctypes.h"
#include "tensorflow/lite/kernels/kernel_util.h"
#include "tensorflow/lite/kernels/padding.h"

namespace tflite {
namespace ops {
namespace micro {
namespace pooling {

namespace {

constexpr int kInputTensor = 0;
constexpr int kOutputTensor = 0;

struct OpData {
  TfLitePaddingValues padding;
};

TfLiteStatus CalculateOpData(const TfLiteContext* context,
                             const TfLitePoolParams* params,
                             const TfLiteTensor* input,
                             const TfLiteTensor* output, OpData* data) {
  // input: batch, height, width, channel
  int height = SizeOfDimension(input, 1);
  int width = SizeOfDimension(input, 2);

  int out_height, out_width;

  data->padding = ComputePaddingHeightWidth(
      params->stride_height, params->stride_width,
      /*dilation_rate_height=*/1,
      /*dilation_rate_width=*/1, height, width, params->filter_height,
      params->filter_width, params->padding, &out_height, &out_width);

  return kTfLiteOk;
}

void AverageEvalFloat(const TfLiteContext* context, const TfLiteNode* node,
                      const TfLitePoolParams* params, const OpData* data,
                      const TfLiteTensor* input, TfLiteTensor* output) {
  float activation_min, activation_max;
  CalculateActivationRange(params->activation, &activation_min,
                           &activation_max);

  PoolParams op_params;
  op_params.stride_height = params->stride_height;
  op_params.stride_width = params->stride_width;
  op_params.filter_height = params->filter_height;
  op_params.filter_width = params->filter_width;
  op_params.padding_values.height = data->padding.height;
  op_params.padding_values.width = data->padding.width;
  op_params.float_activation_min = activation_min;
  op_params.float_activation_max = activation_max;
  reference_ops::AveragePool(
      op_params, GetTensorShape(input), GetTensorData<float>(input),
      GetTensorShape(output), GetTensorData<float>(output));
}

void AverageEvalUint8(const TfLiteContext* context, const TfLiteNode* node,
                      const TfLitePoolParams* params, const OpData* data,
                      const TfLiteTensor* input, TfLiteTensor* output) {
  int32_t activation_min, activation_max;
  CalculateActivationRangeUint8(params->activation, output, &activation_min,
                                &activation_max);

  PoolParams op_params;
  op_params.stride_height = params->stride_height;
  op_params.stride_width = params->stride_width;
  op_params.filter_height = params->filter_height;
  op_params.filter_width = params->filter_width;
  op_params.padding_values.height = data->padding.height;
  op_params.padding_values.width = data->padding.width;
  op_params.quantized_activation_min = activation_min;
  op_params.quantized_activation_max = activation_max;
  reference_ops::AveragePool(
      op_params, GetTensorShape(input), GetTensorData<uint8_t>(input),
      GetTensorShape(output), GetTensorData<uint8_t>(output));
}

TfLiteStatus AverageEvalInt8(const TfLiteContext* context,
                             const TfLiteNode* node,
                             const TfLitePoolParams* params, const OpData* data,
                             const TfLiteTensor* input, TfLiteTensor* output) {
  int32_t activation_min, activation_max;
  CalculateActivationRangeInt8(params->activation, output, &activation_min,
                               &activation_max);

  TFLITE_DCHECK_LE(params->quantized_activation_min,
                   params->quantized_activation_max);

  RuntimeShape input_shape = GetTensorShape(input);
  TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4);

  RuntimeShape output_shape = GetTensorShape(output);
  TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4);

  const int batches = MatchingDim(input_shape, 0, output_shape, 0);
  const int depth = MatchingDim(input_shape, 3, output_shape, 3);
  const int input_height = input_shape.Dims(1);
  const int input_width = input_shape.Dims(2);
  const int output_height = output_shape.Dims(1);
  const int output_width = output_shape.Dims(2);
  const int stride_height = params->stride_height;
  const int stride_width = params->stride_width;

  const int filter_height = params->filter_height;
  const int filter_width = params->filter_width;
  const int padding_height = data->padding.height;
  const int padding_width = data->padding.width;

#if defined(ARM_MATH_DSP) && defined(ARM_MATH_LOOPUNROLL)
  int16_t* scratch_buffer = nullptr;
  const int32_t buffer_size =
      arm_avgpool_s8_get_buffer_size(output_width, depth);

  TF_LITE_ENSURE_OK(
      context, get_cmsis_scratch_buffer(context, &scratch_buffer, buffer_size));

  TF_LITE_ENSURE_EQ(
      context,
      arm_avgpool_s8(input_height, input_width, output_height, output_width,
                     stride_height, stride_width, filter_height, filter_width,
                     padding_height, padding_width, activation_min,
                     activation_max, depth, GetTensorData<int8_t>(input),
                     scratch_buffer, GetTensorData<int8_t>(output)),
      ARM_MATH_SUCCESS);
#else
  reference_integer_ops::AveragePool(
      op_params, GetTensorShape(input), GetTensorData<int8_t>(input),
      GetTensorShape(output), GetTensorData<int8_t>(output));

#endif
  return kTfLiteOk;
}

void MaxEvalFloat(TfLiteContext* context, TfLiteNode* node,
                  TfLitePoolParams* params, OpData* data,
                  const TfLiteTensor* input, TfLiteTensor* output) {
  float activation_min, activation_max;
  CalculateActivationRange(params->activation, &activation_min,
                           &activation_max);

  tflite::PoolParams op_params;
  op_params.stride_height = params->stride_height;
  op_params.stride_width = params->stride_width;
  op_params.filter_height = params->filter_height;
  op_params.filter_width = params->filter_width;
  op_params.padding_values.height = data->padding.height;
  op_params.padding_values.width = data->padding.width;
  op_params.float_activation_min = activation_min;
  op_params.float_activation_max = activation_max;
  reference_ops::MaxPool(op_params, GetTensorShape(input),
                         GetTensorData<float>(input), GetTensorShape(output),
                         GetTensorData<float>(output));
}

void MaxEvalQuantizedUInt8(TfLiteContext* context, TfLiteNode* node,
                           TfLitePoolParams* params, OpData* data,
                           const TfLiteTensor* input, TfLiteTensor* output) {
  int32_t activation_min, activation_max;
  CalculateActivationRangeUint8(params->activation, output, &activation_min,
                                &activation_max);

  tflite::PoolParams op_params;
  op_params.stride_height = params->stride_height;
  op_params.stride_width = params->stride_width;
  op_params.filter_height = params->filter_height;
  op_params.filter_width = params->filter_width;
  op_params.padding_values.height = data->padding.height;
  op_params.padding_values.width = data->padding.width;
  op_params.quantized_activation_min = activation_min;
  op_params.quantized_activation_max = activation_max;
  reference_ops::MaxPool(op_params, GetTensorShape(input),
                         GetTensorData<uint8_t>(input), GetTensorShape(output),
                         GetTensorData<uint8_t>(output));
}

}  // namespace

void* Init(TfLiteContext* context, const char* buffer, size_t length) {
  return nullptr;
}

void Free(TfLiteContext* context, void* buffer) {}

TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
  return kTfLiteOk;
}

TfLiteStatus AverageEval(TfLiteContext* context, TfLiteNode* node) {
  auto* params = reinterpret_cast<TfLitePoolParams*>(node->builtin_data);
  OpData data;

  const TfLiteTensor* input = GetInput(context, node, kInputTensor);
  TfLiteTensor* output = GetOutput(context, node, kOutputTensor);

  TF_LITE_ENSURE_STATUS(CalculateOpData(context, params, input, output, &data));

  // Inputs and outputs share the same type, guarenteed by the converter.
  switch (input->type) {
    case kTfLiteFloat32:
      AverageEvalFloat(context, node, params, &data, input, output);
      break;
    case kTfLiteUInt8:
      AverageEvalUint8(context, node, params, &data, input, output);
      break;
    case kTfLiteInt8:
      return AverageEvalInt8(context, node, params, &data, input, output);
      break;
    default:
      context->ReportError(context, "Input type %s is not currently supported",
                           TfLiteTypeGetName(input->type));
      return kTfLiteError;
  }
  return kTfLiteOk;
}

TfLiteStatus MaxEval(TfLiteContext* context, TfLiteNode* node) {
  auto* params = reinterpret_cast<TfLitePoolParams*>(node->builtin_data);
  OpData data;

  const TfLiteTensor* input = GetInput(context, node, kInputTensor);
  TfLiteTensor* output = GetOutput(context, node, kOutputTensor);

  TF_LITE_ENSURE_STATUS(CalculateOpData(context, params, input, output, &data));

  switch (input->type) {
    case kTfLiteFloat32:
      MaxEvalFloat(context, node, params, &data, input, output);
      break;
    case kTfLiteUInt8:
      MaxEvalQuantizedUInt8(context, node, params, &data, input, output);
      break;
    default:
      context->ReportError(context, "Type %s not currently supported.",
                           TfLiteTypeGetName(input->type));
      return kTfLiteError;
  }
  return kTfLiteOk;
}

}  // namespace pooling

TfLiteRegistration* Register_AVERAGE_POOL_2D() {
  static TfLiteRegistration r = {
      pooling::Init,
      pooling::Free,
      pooling::Prepare,
      pooling::AverageEval,
  };
  return &r;
}

TfLiteRegistration* Register_MAX_POOL_2D() {
  static TfLiteRegistration r = {pooling::Init, pooling::Free, pooling::Prepare,
                                 pooling::MaxEval};
  return &r;
}

}  // namespace micro
}  // namespace ops
}  // namespace tflite
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

bool IsPalindrome(const string& s)
{
	if (s == "")
	{
		return true;
	}

	int n = s.size();
	if (s[0] != s[n-1])
	{
		return false;
	}
	else
	{
		return IsPalindrome(s.substr(1, n-2));
	}
}

bool IsTolerable(const string& s, int p)
{
	char maxChar = p - 1 + 'a';
	for (size_t i = 0; i < s.size(); ++i)
	{
		if (s[i] > maxChar)
		{
			return false;
		}
	}

	int n = s.size();
	for (int k = 2; k <= n; ++k)
	{
		for (int i = 0; i <= n-k; ++i)
		{
			if (IsPalindrome(s.substr(i, k)))
			{
				return false;
			}
		}
	}

	return true;
}

string StrAddOne(const string& s, int p)
{
	char maxChar = p - 1 + 'a';
	string ans(s);
	int n = ans.size();

	ans[n-1] += 1;
	if (ans[n-1] <= maxChar)
	{
		return ans;
	}

	for (int i = n-1; i >= 0; --i)
	{
		if (ans[i] > maxChar)
		{
			ans[i] = 'a';
			if (i-1 >= 0)
			{
				ans[i-1] += 1;
			}
		}
	}
	return ans;
}

int main()
{
	int n, p;
	cin >> n >> p;
	string s;
	cin >> s;

	char maxChar = p - 1 + 'a';
	string maxStr(n, maxChar);

	string ans;
	do
	{
		ans = StrAddOne(s, p);
		if (ans >= maxStr)
		{
			cout << "NO" << endl;
			return 0;
		}

		if (IsTolerable(ans, p))
		{
			cout << ans << endl;
			return 0;
		}

		s = ans;

	}while(true);

	return 0;
}
<commit_msg>A, B, easy good; C, too complicated, TLE<commit_after>#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

bool IsPalindrome(const string& s)
{
	if (s == "")
	{
		return true;
	}

	int n = s.size();
	if (s[0] != s[n-1])
	{
		return false;
	}
	else
	{
		return IsPalindrome(s.substr(1, n-2));
	}
}

bool IsTolerable(const string& s, int p)
{
	char maxChar = p - 1 + 'a';
	for (size_t i = 0; i < s.size(); ++i)
	{
		if (s[i] > maxChar)
		{
			return false;
		}
	}

	int n = s.size();
	for (int k = 2; k <= n; ++k)
	{
		for (int i = 0; i <= n-k; ++i)
		{
			if (IsPalindrome(s.substr(i, k)))
			{
				return false;
			}
		}
	}

	return true;
}

string StrAddOne(const string& s, int p)
{
	char maxChar = p - 1 + 'a';
	string ans(s);
	int n = ans.size();

	ans[n-1] += 1;
	if (ans[n-1] <= maxChar)
	{
		return ans;
	}

	for (int i = n-1; i >= 1; --i)
	{
		if (ans[i] > maxChar)
		{
			ans[i] = 'a';
			ans[i-1] += 1;
		}
	}

	if (ans[0] > maxChar)
	{
		ans[0] = 'a';
		ans = "a" + ans;
	}

	return ans;
}

int main()
{
	int n, p;
	cin >> n >> p;
	string s;
	cin >> s;

	char maxChar = p - 1 + 'a';
	string maxStr(n, maxChar);

	string ans;
	do
	{
		ans = StrAddOne(s, p);
		if (ans.size() > maxStr.size())
		{
			cout << "NO" << endl;
			return 0;
		}

		if (IsTolerable(ans, p))
		{
			cout << ans << endl;
			return 0;
		}

		s = ans;

	}while(true);

	return 0;
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 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 <QtTest/QtTest>
#include <QDebug>

#include <multimedia/qmediaserviceprovider.h>
#include <multimedia/qmediaserviceproviderplugin.h>
#include <multimedia/qmediapluginloader_p.h>
#include <multimedia/qmediaobject.h>
#include <multimedia/qmediaservice.h>
#include <multimedia/qmediaplayer.h>

class MockMediaService : public QMediaService
{
    Q_OBJECT
public:
    MockMediaService(const QString& name, QObject *parent = 0) : QMediaService(parent)
    { setObjectName(name); }
    ~MockMediaService() {}

    QMediaControl* control(const char *) const {return 0;}
};

class MockServicePlugin1 : public QMediaServiceProviderPlugin,
                           public QMediaServiceSupportedFormatsInterface,
                           public QMediaServiceSupportedDevicesInterface
{
    Q_OBJECT
    Q_INTERFACES(QMediaServiceSupportedFormatsInterface)
    Q_INTERFACES(QMediaServiceSupportedDevicesInterface)
public:
    QStringList keys() const
    {
        return QStringList() <<
                QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER) <<
                QLatin1String(Q_MEDIASERVICE_CAMERA);
    }

    QMediaService* create(QString const& key)
    {
        if (keys().contains(key))
            return new MockMediaService("MockServicePlugin1");
        else
            return 0;
    }

    void release(QMediaService *service)
    {
        delete service;
    }

    QtMedia::SupportEstimate hasSupport(const QString &mimeType, const QStringList& codecs) const
    {
        if (codecs.contains(QLatin1String("mpeg4")))
            return QtMedia::NotSupported;

        if (mimeType == "audio/ogg") {
            return QtMedia::ProbablySupported;
        }

        return QtMedia::MaybeSupported;
    }

    QList<QByteArray> devices(const QByteArray &service) const
    {
        QList<QByteArray> res;
        if (service == QByteArray(Q_MEDIASERVICE_CAMERA))
            res << "camera1" << "camera2";
        return res;
    }

    QString deviceDescription(const QByteArray &service, const QByteArray &device)
    {
        if (devices(service).contains(device))
            return QString(device)+" description";
        else
            return QString();
    }
};

class MockServicePlugin2 : public QMediaServiceProviderPlugin,
                            public QMediaServiceSupportedFormatsInterface
{
    Q_OBJECT
    Q_INTERFACES(QMediaServiceSupportedFormatsInterface)
public:
    QStringList keys() const
    {
        return QStringList() << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER);
    }

    QMediaService* create(QString const& key)
    {
        if (keys().contains(key))
            return new MockMediaService("MockServicePlugin2");
        else
            return 0;
    }

    void release(QMediaService *service)
    {
        delete service;
    }

    QtMedia::SupportEstimate hasSupport(const QString &mimeType, const QStringList& codecs) const
    {
        Q_UNUSED(codecs);

        if (mimeType == "audio/wav")
            return QtMedia::PreferedService;

        return QtMedia::NotSupported;
    }
};

class MockServicePlugin3 : public QMediaServiceProviderPlugin,
                            public QMediaServiceSupportedDevicesInterface
{
    Q_OBJECT
    Q_INTERFACES(QMediaServiceSupportedDevicesInterface)
public:
    QStringList keys() const
    {
        return QStringList() <<
               QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER) <<
               QLatin1String(Q_MEDIASERVICE_CAMERA) <<
               QLatin1String(Q_MEDIASERVICE_AUDIOSOURCE);
    }

    QMediaService* create(QString const& key)
    {
        if (keys().contains(key))
            return new MockMediaService("MockServicePlugin3");
        else
            return 0;
    }

    void release(QMediaService *service)
    {
        delete service;
    }

    QList<QByteArray> devices(const QByteArray &service) const
    {
        QList<QByteArray> res;
        if (service == QByteArray(Q_MEDIASERVICE_CAMERA))
            res << "camera3" << "camera4";
        else if (service == QByteArray(Q_MEDIASERVICE_AUDIOSOURCE))
            res << "audiosource1" << "audiosource2";

        return res;
    }

    QString deviceDescription(const QByteArray &service, const QByteArray &device)
    {
        if (devices(service).contains(device))
            return QString(device)+" description";
        else
            return QString();
    }
};

class MockMediaServiceProvider : public QMediaServiceProvider
{
    QMediaService* requestService(const QByteArray &type, const QMediaServiceProviderHint &)
    {
        Q_UNUSED(type);
        return 0;
    }

    void releaseService(QMediaService *service)
    {
        Q_UNUSED(service);
    }
};

class tst_QMediaServiceProvider : public QObject
{
    Q_OBJECT

public slots:
    void initTestCase();

private slots:
    void testDefaultProviderAvailable();
    void testObtainService();
    void testHasSupport();
    void testDevices();
    void testProviderHints();

private:
    QObjectList plugins;
};

void tst_QMediaServiceProvider::initTestCase()
{
    plugins << new MockServicePlugin1;
    plugins << new MockServicePlugin2;
    plugins << new MockServicePlugin3;

    QMediaPluginLoader::setStaticPlugins(QLatin1String("/mediaservice"), plugins);
}

void tst_QMediaServiceProvider::testDefaultProviderAvailable()
{
    // Must always be a default provider available
    QVERIFY(QMediaServiceProvider::defaultServiceProvider() != 0);
}

void tst_QMediaServiceProvider::testObtainService()
{
    QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider();

    if (provider == 0)
        QSKIP("No default provider", SkipSingle);

    QMediaService *service = 0;

    QTest::ignoreMessage(QtWarningMsg, "Load static plugins for \"/mediaservice/\" ");
    // Player
    service = provider->requestService(Q_MEDIASERVICE_MEDIAPLAYER);
    QVERIFY(service != 0);
    provider->releaseService(service);
}

void tst_QMediaServiceProvider::testHasSupport()
{
    MockMediaServiceProvider mockProvider;
    QCOMPARE(mockProvider.hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), "video/ogv", QStringList()),
             QtMedia::MaybeSupported);

    QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider();

    if (provider == 0)
        QSKIP("No default provider", SkipSingle);

    QCOMPARE(provider->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), "video/ogv", QStringList()),
             QtMedia::MaybeSupported);

    QCOMPARE(provider->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), "audio/ogg", QStringList()),
             QtMedia::ProbablySupported);

    //while the service returns PreferredService, provider should return ProbablySupported
    QCOMPARE(provider->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), "audio/wav", QStringList()),
             QtMedia::ProbablySupported);

    //even while all the plugins with "hasSupport" returned NotSupported,
    //MockServicePlugin3 has no "hasSupport" interface, so MaybeSupported
    QCOMPARE(provider->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), "video/avi",
                                  QStringList() << "mpeg4"),
             QtMedia::MaybeSupported);

    QCOMPARE(provider->hasSupport(QByteArray("non existing service"), "video/ogv", QStringList()),
             QtMedia::NotSupported);

    QCOMPARE(QMediaPlayer::hasSupport("video/ogv"), QtMedia::MaybeSupported);
    QCOMPARE(QMediaPlayer::hasSupport("audio/ogg"), QtMedia::ProbablySupported);
    QCOMPARE(QMediaPlayer::hasSupport("audio/wav"), QtMedia::ProbablySupported);
}

void tst_QMediaServiceProvider::testDevices()
{
    MockMediaServiceProvider mockProvider;
    QVERIFY(mockProvider.devices(QByteArray(Q_MEDIASERVICE_CAMERA)).isEmpty());
    QVERIFY(mockProvider.deviceDescription(QByteArray(Q_MEDIASERVICE_CAMERA),
                                           QByteArray()).isEmpty());

    QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider();

    QVERIFY(!provider->devices(QByteArray(Q_MEDIASERVICE_CAMERA)).isEmpty());

    QVERIFY(provider->devices(QByteArray("non existing service")).isEmpty());
}

void tst_QMediaServiceProvider::testProviderHints()
{
    {
        QMediaServiceProviderHint hint;
        QVERIFY(hint.isNull());
        QCOMPARE(hint.type(), QMediaServiceProviderHint::Null);
        QVERIFY(hint.device().isEmpty());
        QVERIFY(hint.mimeType().isEmpty());
        QVERIFY(hint.codecs().isEmpty());
        QCOMPARE(hint.features(), 0);
    }

    {
        QByteArray deviceName(QByteArray("testDevice"));
        QMediaServiceProviderHint hint(deviceName);
        QVERIFY(!hint.isNull());
        QCOMPARE(hint.type(), QMediaServiceProviderHint::Device);
        QCOMPARE(hint.device(), deviceName);
        QVERIFY(hint.mimeType().isEmpty());
        QVERIFY(hint.codecs().isEmpty());
        QCOMPARE(hint.features(), 0);
    }

    {
        QMediaServiceProviderHint hint(QMediaServiceProviderHint::LowLatencyPlayback);
        QVERIFY(!hint.isNull());
        QCOMPARE(hint.type(), QMediaServiceProviderHint::SupportedFeatures);
        QVERIFY(hint.device().isEmpty());
        QVERIFY(hint.mimeType().isEmpty());
        QVERIFY(hint.codecs().isEmpty());
        QCOMPARE(hint.features(), QMediaServiceProviderHint::LowLatencyPlayback);
    }

    {
        QString mimeType(QLatin1String("video/ogg"));
        QStringList codecs;
        codecs << "theora" << "vorbis";

        QMediaServiceProviderHint hint(mimeType,codecs);
        QVERIFY(!hint.isNull());
        QCOMPARE(hint.type(), QMediaServiceProviderHint::ContentType);
        QVERIFY(hint.device().isEmpty());
        QCOMPARE(hint.mimeType(), mimeType);
        QCOMPARE(hint.codecs(), codecs);

        QMediaServiceProviderHint hint2(hint);

        QVERIFY(!hint2.isNull());
        QCOMPARE(hint2.type(), QMediaServiceProviderHint::ContentType);
        QVERIFY(hint2.device().isEmpty());
        QCOMPARE(hint2.mimeType(), mimeType);
        QCOMPARE(hint2.codecs(), codecs);

        QMediaServiceProviderHint hint3;
        QVERIFY(hint3.isNull());
        hint3 = hint;
        QVERIFY(!hint3.isNull());
        QCOMPARE(hint3.type(), QMediaServiceProviderHint::ContentType);
        QVERIFY(hint3.device().isEmpty());
        QCOMPARE(hint3.mimeType(), mimeType);
        QCOMPARE(hint3.codecs(), codecs);

        QCOMPARE(hint, hint2);
        QCOMPARE(hint3, hint2);

        QMediaServiceProviderHint hint4(mimeType,codecs);
        QCOMPARE(hint, hint4);

        QMediaServiceProviderHint hint5(mimeType,QStringList());
        QVERIFY(hint != hint5);
    }
}

QTEST_MAIN(tst_QMediaServiceProvider)

#include "tst_qmediaserviceprovider.moc"
<commit_msg>Added tests for camera service selection by device name and player by supported low latency playback feature.<commit_after>/****************************************************************************
**
** Copyright (C) 2009 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 <QtTest/QtTest>
#include <QDebug>

#include <multimedia/qmediaserviceprovider.h>
#include <multimedia/qmediaserviceproviderplugin.h>
#include <multimedia/qmediapluginloader_p.h>
#include <multimedia/qmediaobject.h>
#include <multimedia/qmediaservice.h>
#include <multimedia/qmediaplayer.h>
#include <multimedia/experimental/qcamera.h>
#include <multimedia/qaudiocapturesource.h>

class MockMediaService : public QMediaService
{
    Q_OBJECT
public:
    MockMediaService(const QString& name, QObject *parent = 0) : QMediaService(parent)
    { setObjectName(name); }
    ~MockMediaService() {}

    QMediaControl* control(const char *) const {return 0;}
};

class MockServicePlugin1 : public QMediaServiceProviderPlugin,
                           public QMediaServiceSupportedFormatsInterface,
                           public QMediaServiceSupportedDevicesInterface
{
    Q_OBJECT
    Q_INTERFACES(QMediaServiceSupportedFormatsInterface)
    Q_INTERFACES(QMediaServiceSupportedDevicesInterface)
public:
    QStringList keys() const
    {
        return QStringList() <<
                QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER) <<
                QLatin1String(Q_MEDIASERVICE_CAMERA);
    }

    QMediaService* create(QString const& key)
    {
        if (keys().contains(key))
            return new MockMediaService("MockServicePlugin1");
        else
            return 0;
    }

    void release(QMediaService *service)
    {
        delete service;
    }

    QtMedia::SupportEstimate hasSupport(const QString &mimeType, const QStringList& codecs) const
    {
        if (codecs.contains(QLatin1String("mpeg4")))
            return QtMedia::NotSupported;

        if (mimeType == "audio/ogg") {
            return QtMedia::ProbablySupported;
        }

        return QtMedia::MaybeSupported;
    }

    QList<QByteArray> devices(const QByteArray &service) const
    {
        QList<QByteArray> res;
        if (service == QByteArray(Q_MEDIASERVICE_CAMERA))
            res << "camera1" << "camera2";
        return res;
    }

    QString deviceDescription(const QByteArray &service, const QByteArray &device)
    {
        if (devices(service).contains(device))
            return QString(device)+" description";
        else
            return QString();
    }
};

class MockServicePlugin2 : public QMediaServiceProviderPlugin,
                            public QMediaServiceSupportedFormatsInterface,
                            public QMediaServiceFeaturesInterface
{
    Q_OBJECT
    Q_INTERFACES(QMediaServiceSupportedFormatsInterface)
    Q_INTERFACES(QMediaServiceFeaturesInterface)
public:
    QStringList keys() const
    {
        return QStringList() << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER);
    }

    QMediaService* create(QString const& key)
    {
        if (keys().contains(key))
            return new MockMediaService("MockServicePlugin2");
        else
            return 0;
    }

    void release(QMediaService *service)
    {
        delete service;
    }

    QtMedia::SupportEstimate hasSupport(const QString &mimeType, const QStringList& codecs) const
    {
        Q_UNUSED(codecs);

        if (mimeType == "audio/wav")
            return QtMedia::PreferedService;

        return QtMedia::NotSupported;
    }

    QMediaServiceProviderHint::Features supportedFeatures(const QByteArray &service) const
    {
        if (service == QByteArray(Q_MEDIASERVICE_MEDIAPLAYER))
            return QMediaServiceProviderHint::LowLatencyPlayback;
        else
            return 0;
    }
};

class MockServicePlugin3 : public QMediaServiceProviderPlugin,
                            public QMediaServiceSupportedDevicesInterface
{
    Q_OBJECT
    Q_INTERFACES(QMediaServiceSupportedDevicesInterface)
public:
    QStringList keys() const
    {
        return QStringList() <<
               QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER) <<
               QLatin1String(Q_MEDIASERVICE_CAMERA) <<
               QLatin1String(Q_MEDIASERVICE_AUDIOSOURCE);
    }

    QMediaService* create(QString const& key)
    {
        if (keys().contains(key))
            return new MockMediaService("MockServicePlugin3");
        else
            return 0;
    }

    void release(QMediaService *service)
    {
        delete service;
    }

    QList<QByteArray> devices(const QByteArray &service) const
    {
        QList<QByteArray> res;
        if (service == QByteArray(Q_MEDIASERVICE_CAMERA))
            res << "camera3" << "camera4";
        else if (service == QByteArray(Q_MEDIASERVICE_AUDIOSOURCE))
            res << "audiosource1" << "audiosource2";

        return res;
    }

    QString deviceDescription(const QByteArray &service, const QByteArray &device)
    {
        if (devices(service).contains(device))
            return QString(device)+" description";
        else
            return QString();
    }
};

class MockMediaServiceProvider : public QMediaServiceProvider
{
    QMediaService* requestService(const QByteArray &type, const QMediaServiceProviderHint &)
    {
        Q_UNUSED(type);
        return 0;
    }

    void releaseService(QMediaService *service)
    {
        Q_UNUSED(service);
    }
};

class tst_QMediaServiceProvider : public QObject
{
    Q_OBJECT

public slots:
    void initTestCase();

private slots:
    void testDefaultProviderAvailable();
    void testObtainService();
    void testHasSupport();
    void testDevices();
    void testProviderHints();

private:
    QObjectList plugins;
};

void tst_QMediaServiceProvider::initTestCase()
{
    plugins << new MockServicePlugin1;
    plugins << new MockServicePlugin2;
    plugins << new MockServicePlugin3;

    QMediaPluginLoader::setStaticPlugins(QLatin1String("/mediaservice"), plugins);
}

void tst_QMediaServiceProvider::testDefaultProviderAvailable()
{
    // Must always be a default provider available
    QVERIFY(QMediaServiceProvider::defaultServiceProvider() != 0);
}

void tst_QMediaServiceProvider::testObtainService()
{
    QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider();

    if (provider == 0)
        QSKIP("No default provider", SkipSingle);

    QMediaService *service = 0;

    QTest::ignoreMessage(QtWarningMsg, "Load static plugins for \"/mediaservice/\" ");
    // Player
    service = provider->requestService(Q_MEDIASERVICE_MEDIAPLAYER);
    QVERIFY(service != 0);
    provider->releaseService(service);
}

void tst_QMediaServiceProvider::testHasSupport()
{
    MockMediaServiceProvider mockProvider;
    QCOMPARE(mockProvider.hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), "video/ogv", QStringList()),
             QtMedia::MaybeSupported);

    QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider();

    if (provider == 0)
        QSKIP("No default provider", SkipSingle);

    QCOMPARE(provider->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), "video/ogv", QStringList()),
             QtMedia::MaybeSupported);

    QCOMPARE(provider->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), "audio/ogg", QStringList()),
             QtMedia::ProbablySupported);

    //while the service returns PreferredService, provider should return ProbablySupported
    QCOMPARE(provider->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), "audio/wav", QStringList()),
             QtMedia::ProbablySupported);

    //even while all the plugins with "hasSupport" returned NotSupported,
    //MockServicePlugin3 has no "hasSupport" interface, so MaybeSupported
    QCOMPARE(provider->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), "video/avi",
                                  QStringList() << "mpeg4"),
             QtMedia::MaybeSupported);

    QCOMPARE(provider->hasSupport(QByteArray("non existing service"), "video/ogv", QStringList()),
             QtMedia::NotSupported);

    QCOMPARE(QMediaPlayer::hasSupport("video/ogv"), QtMedia::MaybeSupported);
    QCOMPARE(QMediaPlayer::hasSupport("audio/ogg"), QtMedia::ProbablySupported);
    QCOMPARE(QMediaPlayer::hasSupport("audio/wav"), QtMedia::ProbablySupported);

    //ensure the correct media player plugin is choosen for mime type
    QMediaPlayer simplePlayer(0, QMediaPlayer::LowLatency);
    QCOMPARE(simplePlayer.service()->objectName(), QLatin1String("MockServicePlugin2"));

    QMediaPlayer mediaPlayer;
    QVERIFY(mediaPlayer.service()->objectName() != QLatin1String("MockServicePlugin2"));
}

void tst_QMediaServiceProvider::testDevices()
{
    MockMediaServiceProvider mockProvider;
    QVERIFY(mockProvider.devices(QByteArray(Q_MEDIASERVICE_CAMERA)).isEmpty());
    QVERIFY(mockProvider.deviceDescription(QByteArray(Q_MEDIASERVICE_CAMERA),
                                           QByteArray()).isEmpty());

    QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider();

    QList<QByteArray> cameraDevices = provider->devices(QByteArray(Q_MEDIASERVICE_CAMERA));
    QCOMPARE(cameraDevices.count(), 4);
    QVERIFY(cameraDevices.contains(QByteArray("camera1")));
    QVERIFY(cameraDevices.contains(QByteArray("camera2")));
    QVERIFY(cameraDevices.contains(QByteArray("camera3")));
    QVERIFY(cameraDevices.contains(QByteArray("camera4")));

    //ensure the right plugin is choosen for a device
    QCamera camera1(QByteArray("camera1"));
    QCOMPARE( camera1.service()->objectName(), QLatin1String("MockServicePlugin1") );
    QCamera camera2(QByteArray("camera2"));
    QCOMPARE( camera2.service()->objectName(), QLatin1String("MockServicePlugin1") );
    QCamera camera3(QByteArray("camera3"));
    QCOMPARE( camera3.service()->objectName(), QLatin1String("MockServicePlugin3") );
    QCamera camera4(QByteArray("camera4"));
    QCOMPARE( camera4.service()->objectName(), QLatin1String("MockServicePlugin3") );

    QList<QByteArray> audioSourceDevices = provider->devices(QByteArray(Q_MEDIASERVICE_AUDIOSOURCE));
    QCOMPARE(audioSourceDevices.count(), 2);
    QVERIFY(audioSourceDevices.contains(QByteArray("audiosource1")));
    QVERIFY(audioSourceDevices.contains(QByteArray("audiosource2")));

    QVERIFY(provider->devices(QByteArray("non existing service")).isEmpty());
}

void tst_QMediaServiceProvider::testProviderHints()
{
    {
        QMediaServiceProviderHint hint;
        QVERIFY(hint.isNull());
        QCOMPARE(hint.type(), QMediaServiceProviderHint::Null);
        QVERIFY(hint.device().isEmpty());
        QVERIFY(hint.mimeType().isEmpty());
        QVERIFY(hint.codecs().isEmpty());
        QCOMPARE(hint.features(), 0);
    }

    {
        QByteArray deviceName(QByteArray("testDevice"));
        QMediaServiceProviderHint hint(deviceName);
        QVERIFY(!hint.isNull());
        QCOMPARE(hint.type(), QMediaServiceProviderHint::Device);
        QCOMPARE(hint.device(), deviceName);
        QVERIFY(hint.mimeType().isEmpty());
        QVERIFY(hint.codecs().isEmpty());
        QCOMPARE(hint.features(), 0);
    }

    {
        QMediaServiceProviderHint hint(QMediaServiceProviderHint::LowLatencyPlayback);
        QVERIFY(!hint.isNull());
        QCOMPARE(hint.type(), QMediaServiceProviderHint::SupportedFeatures);
        QVERIFY(hint.device().isEmpty());
        QVERIFY(hint.mimeType().isEmpty());
        QVERIFY(hint.codecs().isEmpty());
        QCOMPARE(hint.features(), QMediaServiceProviderHint::LowLatencyPlayback);
    }

    {
        QString mimeType(QLatin1String("video/ogg"));
        QStringList codecs;
        codecs << "theora" << "vorbis";

        QMediaServiceProviderHint hint(mimeType,codecs);
        QVERIFY(!hint.isNull());
        QCOMPARE(hint.type(), QMediaServiceProviderHint::ContentType);
        QVERIFY(hint.device().isEmpty());
        QCOMPARE(hint.mimeType(), mimeType);
        QCOMPARE(hint.codecs(), codecs);

        QMediaServiceProviderHint hint2(hint);

        QVERIFY(!hint2.isNull());
        QCOMPARE(hint2.type(), QMediaServiceProviderHint::ContentType);
        QVERIFY(hint2.device().isEmpty());
        QCOMPARE(hint2.mimeType(), mimeType);
        QCOMPARE(hint2.codecs(), codecs);

        QMediaServiceProviderHint hint3;
        QVERIFY(hint3.isNull());
        hint3 = hint;
        QVERIFY(!hint3.isNull());
        QCOMPARE(hint3.type(), QMediaServiceProviderHint::ContentType);
        QVERIFY(hint3.device().isEmpty());
        QCOMPARE(hint3.mimeType(), mimeType);
        QCOMPARE(hint3.codecs(), codecs);

        QCOMPARE(hint, hint2);
        QCOMPARE(hint3, hint2);

        QMediaServiceProviderHint hint4(mimeType,codecs);
        QCOMPARE(hint, hint4);

        QMediaServiceProviderHint hint5(mimeType,QStringList());
        QVERIFY(hint != hint5);
    }
}

QTEST_MAIN(tst_QMediaServiceProvider)

#include "tst_qmediaserviceprovider.moc"
<|endoftext|>