<commit_before>/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#pragma once

namespace cuda
{

namespace kernel
{

template <typename T>
struct SharedMemory
{
    // return a pointer to the runtime-sized shared memory array.
    __device__ T* getPointer()
    {
        extern __device__ void Error_UnsupportedType(); // Ensure that we won't compile any un-specialized types
        Error_UnsupportedType();
        return (T*)0;
    }
};

#define SPECIALIZE(T)                           \
    template <>                                 \
    struct SharedMemory <T>                     \
    {                                           \
        __device__ T* getPointer() {            \
            extern __shared__ T ptr_##T##_[];   \
                return ptr_##T##_;              \
        }                                       \
    };

SPECIALIZE(float)
SPECIALIZE(cfloat)
SPECIALIZE(double)
SPECIALIZE(cdouble)
SPECIALIZE(char)
SPECIALIZE(int)
SPECIALIZE(uint)
SPECIALIZE(short)
SPECIALIZE(ushort)
SPECIALIZE(uchar)

#undef SPECIALIZE

}
}
<commit_msg>Fix cuda shared memory instantiation for s64 and u64<commit_after>/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#pragma once

namespace cuda
{

namespace kernel
{

template <typename T>
struct SharedMemory
{
    // return a pointer to the runtime-sized shared memory array.
    __device__ T* getPointer()
    {
        extern __device__ void Error_UnsupportedType(); // Ensure that we won't compile any un-specialized types
        Error_UnsupportedType();
        return (T*)0;
    }
};

#define SPECIALIZE(T)                           \
    template <>                                 \
    struct SharedMemory <T>                     \
    {                                           \
        __device__ T* getPointer() {            \
            extern __shared__ T ptr_##T##_[];   \
                return ptr_##T##_;              \
        }                                       \
    };

SPECIALIZE(float)
SPECIALIZE(cfloat)
SPECIALIZE(double)
SPECIALIZE(cdouble)
SPECIALIZE(char)
SPECIALIZE(int)
SPECIALIZE(uint)
SPECIALIZE(short)
SPECIALIZE(ushort)
SPECIALIZE(uchar)
SPECIALIZE(intl)
SPECIALIZE(uintl)

#undef SPECIALIZE

}
}
<|endoftext|>


<commit_before>#include "core/reactor.hh"
#include "core/app-template.hh"
#include "core/sstring.hh"
#include "message/messaging_service.hh"
#include "gms/gossip_digest_syn.hh"
#include "gms/gossip_digest_ack.hh"
#include "gms/gossip_digest_ack2.hh"
#include "gms/gossip_digest.hh"
#include "core/sleep.hh"
#include "api/api.hh"

using namespace std::chrono_literals;
using namespace net;

struct empty_msg {
    void serialize(bytes::iterator& out) const {
    }
    static empty_msg deserialize(bytes_view& v) {
        return empty_msg();
    }
    size_t serialized_size() const {
        return 0;
    }
    friend inline std::ostream& operator<<(std::ostream& os, const empty_msg& ack) {
        return os << "empty_msg";
    }
};

class tester {
private:
    messaging_service& ms;
    gms::inet_address _server;
    uint32_t _cpuid;
public:
    tester()
       : ms(get_local_messaging_service()) {
    }
    using shard_id = net::messaging_service::shard_id;
    using inet_address = gms::inet_address;
    using endpoint_state = gms::endpoint_state;
    shard_id get_shard_id() {
        return shard_id{_server, _cpuid};
    }
    void set_server_ip(sstring ip) {
        _server = inet_address(ip);
    }
    void set_server_cpuid(uint32_t cpu) {
        _cpuid = cpu;
    }
    future<> stop() {
        return make_ready_future<>();
    }
public:
    void init_handler() {
        ms.register_handler(messaging_verb::GOSSIP_DIGEST_SYN, [] (gms::gossip_digest_syn msg) {
            print("Server got syn msg = %s\n", msg);
            auto ep1 = inet_address("1.1.1.1");
            auto ep2 = inet_address("2.2.2.2");
            int32_t gen = 800;
            int32_t ver = 900;
            std::vector<gms::gossip_digest> digests{
                {ep1, gen++, ver++},
                {ep2, gen++, ver++},
            };
            std::map<inet_address, endpoint_state> eps{
                {ep1, endpoint_state()},
                {ep2, endpoint_state()},
            };
            gms::gossip_digest_ack ack(std::move(digests), std::move(eps));
            return make_ready_future<gms::gossip_digest_ack>(ack);
        });
        ms.register_handler(messaging_verb::GOSSIP_DIGEST_ACK2, [] (gms::gossip_digest_ack2 msg) {
            print("Server got ack2 msg = %s\n", msg);
            return messaging_service::no_wait();
        });
        ms.register_handler(messaging_verb::GOSSIP_SHUTDOWN, [] (empty_msg msg) {
            print("Server got shutdown msg = %s\n", msg);
            return messaging_service::no_wait();
        });
        ms.register_handler(messaging_verb::ECHO, [] (int x, int y) {
            print("Server got echo msg = (%d, %ld) \n", x, y);
            return make_ready_future<int, long>(x*x, y*y);
        });
        ms.register_handler(messaging_verb::UNUSED_1, [] (int x, int y) {
            print("Server got echo msg = (%d, %ld) \n", x, y);
            throw std::runtime_error("I'm throwing runtime_error exception");
            long ret = x + y;
            return make_ready_future<decltype(ret)>(ret);
        });
    }

public:
    future<> test_gossip_digest() {
        print("=== %s ===\n", __func__);
        // Prepare gossip_digest_syn message
        auto id = get_shard_id();
        auto ep1 = inet_address("1.1.1.1");
        auto ep2 = inet_address("2.2.2.2");
        int32_t gen = 100;
        int32_t ver = 900;
        std::vector<gms::gossip_digest> digests{
            {ep1, gen++, ver++},
            {ep2, gen++, ver++},
        };
        gms::gossip_digest_syn syn("my_cluster", "my_partition", digests);
        using RetMsg = gms::gossip_digest_ack;
        return ms.send_message<RetMsg>(messaging_verb::GOSSIP_DIGEST_SYN, std::move(id), std::move(syn)).then([this, id] (RetMsg ack) {
            print("Client sent gossip_digest_syn got gossip_digest_ack reply = %s\n", ack);
            // Prepare gossip_digest_ack2 message
            auto ep1 = inet_address("3.3.3.3");
            std::map<inet_address, endpoint_state> eps{
                {ep1, endpoint_state()},
            };
            gms::gossip_digest_ack2 ack2(std::move(eps));
            return ms.send_message_oneway(messaging_verb::GOSSIP_DIGEST_ACK2, std::move(id), std::move(ack2)).then([] () {
                print("Client sent gossip_digest_ack2 got reply = void\n");
                return make_ready_future<>();
            });
        });
    }

    future<> test_gossip_shutdown() {
        print("=== %s ===\n", __func__);
        auto id = get_shard_id();
        empty_msg msg;
        return ms.send_message_oneway(messaging_verb::GOSSIP_SHUTDOWN, std::move(id), std::move(msg)).then([] () {
            print("Client sent gossip_shutdown got reply = void\n");
            return make_ready_future<>();
        });
    }

    future<> test_echo() {
        print("=== %s ===\n", __func__);
        auto id = get_shard_id();
        using RetMsg = future<int, long>;
        return ms.send_message<RetMsg>(messaging_verb::ECHO, id, 30, 60).then_wrapped([] (future<int, long> f) {
            try {
                auto msg = f.get();
                print("Client sent echo got reply = (%d , %ld)\n", std::get<0>(msg), std::get<1>(msg));
                return sleep(100ms).then([]{
                    return make_ready_future<>();
                });
            } catch (std::runtime_error& e) {
                print("test_echo: %s\n", e.what());
            }
            return make_ready_future<>();
        });
    }

    future<> test_exception() {
        print("=== %s ===\n", __func__);
        auto id = get_shard_id();
        return ms.send_message<long>(messaging_verb::UNUSED_1, id, 3, 6).then_wrapped([] (future<long> f) {
            try {
                auto ret = std::get<0>(f.get());
                print("Client sent UNUSED_1 got reply = %ld\n", ret);
                return make_ready_future<>();
            } catch (std::runtime_error& e) {
                print("Client sent UNUSED_1 got exception: %s\n", e.what());
            }
            return make_ready_future<>();
        });
    }
};

namespace bpo = boost::program_options;

int main(int ac, char ** av) {
    app_template app;
    app.add_options()
        ("server", bpo::value<std::string>(), "Server ip")
        ("listen-address", bpo::value<std::string>()->default_value("0.0.0.0"), "IP address to listen")
        ("api-port", bpo::value<uint16_t>()->default_value(10000), "Http Rest API port")
        ("stay-alive", bpo::value<bool>()->default_value(false), "Do not kill the test server after the test")
        ("cpuid", bpo::value<uint32_t>()->default_value(0), "Server cpuid");

    distributed<database> db;

    return app.run(ac, av, [&app] {
        auto config = app.configuration();
        uint16_t api_port = config["api-port"].as<uint16_t>();
        bool stay_alive = config["stay-alive"].as<bool>();
        if (config.count("server")) {
            api_port++;
        }
        const gms::inet_address listen = gms::inet_address(config["listen-address"].as<std::string>());
        net::get_messaging_service().start(listen).then([config, api_port, stay_alive] () {
            auto testers = new distributed<tester>;
            testers->start().then([testers]{
                auto& server = net::get_local_messaging_service();
                auto port = server.port();
                std::cout << "Messaging server listening on port " << port << " ...\n";
                return testers->invoke_on_all(&tester::init_handler);
            }).then([testers, config, stay_alive] {
                auto t = &testers->local();
                if (!config.count("server")) {
                    return;
                }
                auto ip = config["server"].as<std::string>();
                auto cpuid = config["cpuid"].as<uint32_t>();
                t->set_server_ip(ip);
                t->set_server_cpuid(cpuid);
                print("=============TEST START===========\n");
                print("Sending to server ....\n");
                t->test_gossip_digest().then([testers, t] {
                    return t->test_gossip_shutdown();
                }).then([testers, t] {
                    return t->test_echo();
                }).then([testers, t] {
                    return t->test_exception();
                }).then([testers, t, stay_alive] {
                    if (stay_alive) {
                        return;
                    }
                    print("=============TEST DONE===========\n");
                    testers->stop().then([testers] {
                        delete testers;
                        net::get_messaging_service().stop().then([]{
                            engine().exit(0);
                        });
                    });
                });
            });
        });
    });
}
<commit_msg>tests: Disable tests/urchin/message.cc for now<commit_after>#if 0
#include "core/reactor.hh"
#include "core/app-template.hh"
#include "core/sstring.hh"
#include "message/messaging_service.hh"
#include "gms/gossip_digest_syn.hh"
#include "gms/gossip_digest_ack.hh"
#include "gms/gossip_digest_ack2.hh"
#include "gms/gossip_digest.hh"
#include "core/sleep.hh"
#include "api/api.hh"

using namespace std::chrono_literals;
using namespace net;

struct empty_msg {
    void serialize(bytes::iterator& out) const {
    }
    static empty_msg deserialize(bytes_view& v) {
        return empty_msg();
    }
    size_t serialized_size() const {
        return 0;
    }
    friend inline std::ostream& operator<<(std::ostream& os, const empty_msg& ack) {
        return os << "empty_msg";
    }
};

class tester {
private:
    messaging_service& ms;
    gms::inet_address _server;
    uint32_t _cpuid;
public:
    tester()
       : ms(get_local_messaging_service()) {
    }
    using shard_id = net::messaging_service::shard_id;
    using inet_address = gms::inet_address;
    using endpoint_state = gms::endpoint_state;
    shard_id get_shard_id() {
        return shard_id{_server, _cpuid};
    }
    void set_server_ip(sstring ip) {
        _server = inet_address(ip);
    }
    void set_server_cpuid(uint32_t cpu) {
        _cpuid = cpu;
    }
    future<> stop() {
        return make_ready_future<>();
    }
public:
    void init_handler() {
        ms.register_handler(messaging_verb::GOSSIP_DIGEST_SYN, [] (gms::gossip_digest_syn msg) {
            print("Server got syn msg = %s\n", msg);
            auto ep1 = inet_address("1.1.1.1");
            auto ep2 = inet_address("2.2.2.2");
            int32_t gen = 800;
            int32_t ver = 900;
            std::vector<gms::gossip_digest> digests{
                {ep1, gen++, ver++},
                {ep2, gen++, ver++},
            };
            std::map<inet_address, endpoint_state> eps{
                {ep1, endpoint_state()},
                {ep2, endpoint_state()},
            };
            gms::gossip_digest_ack ack(std::move(digests), std::move(eps));
            return make_ready_future<gms::gossip_digest_ack>(ack);
        });
        ms.register_handler(messaging_verb::GOSSIP_DIGEST_ACK2, [] (gms::gossip_digest_ack2 msg) {
            print("Server got ack2 msg = %s\n", msg);
            return messaging_service::no_wait();
        });
        ms.register_handler(messaging_verb::GOSSIP_SHUTDOWN, [] (empty_msg msg) {
            print("Server got shutdown msg = %s\n", msg);
            return messaging_service::no_wait();
        });
        ms.register_handler(messaging_verb::ECHO, [] (int x, int y) {
            print("Server got echo msg = (%d, %ld) \n", x, y);
            return make_ready_future<int, long>(x*x, y*y);
        });
        ms.register_handler(messaging_verb::UNUSED_1, [] (int x, int y) {
            print("Server got echo msg = (%d, %ld) \n", x, y);
            throw std::runtime_error("I'm throwing runtime_error exception");
            long ret = x + y;
            return make_ready_future<decltype(ret)>(ret);
        });
    }

public:
    future<> test_gossip_digest() {
        print("=== %s ===\n", __func__);
        // Prepare gossip_digest_syn message
        auto id = get_shard_id();
        auto ep1 = inet_address("1.1.1.1");
        auto ep2 = inet_address("2.2.2.2");
        int32_t gen = 100;
        int32_t ver = 900;
        std::vector<gms::gossip_digest> digests{
            {ep1, gen++, ver++},
            {ep2, gen++, ver++},
        };
        gms::gossip_digest_syn syn("my_cluster", "my_partition", digests);
        using RetMsg = gms::gossip_digest_ack;
        return ms.send_message<RetMsg>(messaging_verb::GOSSIP_DIGEST_SYN, std::move(id), std::move(syn)).then([this, id] (RetMsg ack) {
            print("Client sent gossip_digest_syn got gossip_digest_ack reply = %s\n", ack);
            // Prepare gossip_digest_ack2 message
            auto ep1 = inet_address("3.3.3.3");
            std::map<inet_address, endpoint_state> eps{
                {ep1, endpoint_state()},
            };
            gms::gossip_digest_ack2 ack2(std::move(eps));
            return ms.send_message_oneway(messaging_verb::GOSSIP_DIGEST_ACK2, std::move(id), std::move(ack2)).then([] () {
                print("Client sent gossip_digest_ack2 got reply = void\n");
                return make_ready_future<>();
            });
        });
    }

    future<> test_gossip_shutdown() {
        print("=== %s ===\n", __func__);
        auto id = get_shard_id();
        empty_msg msg;
        return ms.send_message_oneway(messaging_verb::GOSSIP_SHUTDOWN, std::move(id), std::move(msg)).then([] () {
            print("Client sent gossip_shutdown got reply = void\n");
            return make_ready_future<>();
        });
    }

    future<> test_echo() {
        print("=== %s ===\n", __func__);
        auto id = get_shard_id();
        using RetMsg = future<int, long>;
        return ms.send_message<RetMsg>(messaging_verb::ECHO, id, 30, 60).then_wrapped([] (future<int, long> f) {
            try {
                auto msg = f.get();
                print("Client sent echo got reply = (%d , %ld)\n", std::get<0>(msg), std::get<1>(msg));
                return sleep(100ms).then([]{
                    return make_ready_future<>();
                });
            } catch (std::runtime_error& e) {
                print("test_echo: %s\n", e.what());
            }
            return make_ready_future<>();
        });
    }

    future<> test_exception() {
        print("=== %s ===\n", __func__);
        auto id = get_shard_id();
        return ms.send_message<long>(messaging_verb::UNUSED_1, id, 3, 6).then_wrapped([] (future<long> f) {
            try {
                auto ret = std::get<0>(f.get());
                print("Client sent UNUSED_1 got reply = %ld\n", ret);
                return make_ready_future<>();
            } catch (std::runtime_error& e) {
                print("Client sent UNUSED_1 got exception: %s\n", e.what());
            }
            return make_ready_future<>();
        });
    }
};

namespace bpo = boost::program_options;

int main(int ac, char ** av) {
    app_template app;
    app.add_options()
        ("server", bpo::value<std::string>(), "Server ip")
        ("listen-address", bpo::value<std::string>()->default_value("0.0.0.0"), "IP address to listen")
        ("api-port", bpo::value<uint16_t>()->default_value(10000), "Http Rest API port")
        ("stay-alive", bpo::value<bool>()->default_value(false), "Do not kill the test server after the test")
        ("cpuid", bpo::value<uint32_t>()->default_value(0), "Server cpuid");

    distributed<database> db;

    return app.run(ac, av, [&app] {
        auto config = app.configuration();
        uint16_t api_port = config["api-port"].as<uint16_t>();
        bool stay_alive = config["stay-alive"].as<bool>();
        if (config.count("server")) {
            api_port++;
        }
        const gms::inet_address listen = gms::inet_address(config["listen-address"].as<std::string>());
        net::get_messaging_service().start(listen).then([config, api_port, stay_alive] () {
            auto testers = new distributed<tester>;
            testers->start().then([testers]{
                auto& server = net::get_local_messaging_service();
                auto port = server.port();
                std::cout << "Messaging server listening on port " << port << " ...\n";
                return testers->invoke_on_all(&tester::init_handler);
            }).then([testers, config, stay_alive] {
                auto t = &testers->local();
                if (!config.count("server")) {
                    return;
                }
                auto ip = config["server"].as<std::string>();
                auto cpuid = config["cpuid"].as<uint32_t>();
                t->set_server_ip(ip);
                t->set_server_cpuid(cpuid);
                print("=============TEST START===========\n");
                print("Sending to server ....\n");
                t->test_gossip_digest().then([testers, t] {
                    return t->test_gossip_shutdown();
                }).then([testers, t] {
                    return t->test_echo();
                }).then([testers, t] {
                    return t->test_exception();
                }).then([testers, t, stay_alive] {
                    if (stay_alive) {
                        return;
                    }
                    print("=============TEST DONE===========\n");
                    testers->stop().then([testers] {
                        delete testers;
                        net::get_messaging_service().stop().then([]{
                            engine().exit(0);
                        });
                    });
                });
            });
        });
    });
}
#endif
int main(int ac, char ** av) {}
<|endoftext|>


<commit_before>#include<ros/ros.h>
#include<keyboard/Key.h>

#include<sstream>
#include<string.h>

std::string intToString(int number){
	std::ostringstream oss;
	oss << number;
	return oss.str();
}

void keyupMessageRecieved(const keyboard::Key& msg){
ROS_INFO("%s",intToString(msg.code).c_str());
}
void keydownMessageRecieved(const keyboard::Key& msg){
ROS_INFO("%s",intToString(msg.code).c_str());
}

int main(int argc, char **argv){
ros::init(argc, argv, "little_mapper_teleop_node");
ros::NodeHandle nh;
ros::Subscriber sub_keydown = nh.subscribe("keyboard_node/keydown", 1000, &keyupMessageRecieved);
ros::Subscriber sub_keyup = nh.subscribe("keyboard_node/keyup", 1000, &keydownMessageRecieved);
ros::spin();
}
<commit_msg>little_mapper_teleop_node.cpp refactored<commit_after>#include<ros/ros.h>
#include<keyboard/Key.h>

#include<sstream>
#include<string.h>

std::string intToString(int number){
	std::ostringstream oss;
	oss << number;
	return oss.str();
}

void keyupMessageRecieved(const keyboard::Key& msg){
	ROS_INFO("%s",intToString(msg.code).c_str());
}
void keydownMessageRecieved(const keyboard::Key& msg){
	ROS_INFO("%s",intToString(msg.code).c_str());
}

int main(int argc, char **argv){
	ros::init(argc, argv, "little_mapper_teleop_node");
	ros::NodeHandle nh;
	ros::Subscriber sub_keydown = nh.subscribe("keyboard_node/keydown", 1000, &keyupMessageRecieved);
	ros::Subscriber sub_keyup = nh.subscribe("keyboard_node/keyup", 1000, &keydownMessageRecieved);
	ros::spin();
}
<|endoftext|>


<commit_before>/*******************************************************************************
 * thrill/api/dia_base.cpp
 *
 * Part of Project Thrill - http://project-thrill.org
 *
 * Copyright (C) 2015 Sebastian Lamm <seba.lamm@gmail.com>
 * Copyright (C) 2016 Timo Bingmann <tb@panthema.net>
 *
 * All rights reserved. Published under the BSD-2 license in the LICENSE file.
 ******************************************************************************/

#include <thrill/api/dia_base.hpp>
#include <thrill/common/logger.hpp>
#include <thrill/common/stat_logger.hpp>
#include <thrill/common/stats_timer.hpp>
#include <thrill/mem/allocator.hpp>

#include <algorithm>
#include <chrono>
#include <deque>
#include <functional>
#include <iomanip>
#include <set>
#include <string>
#include <utility>
#include <vector>

namespace thrill {
namespace api {

/******************************************************************************/
// DIABase StageBuilder

static inline
struct tm localtime_from(const time_t& t) {
#if __MINGW32__
    return *localtime(&t); // NOLINT
#else
    struct tm tm;
    memset(&tm, 0, sizeof(tm));
    localtime_r(&t, &tm);
    return tm;
#endif
}

//! format string using time structure
static inline
std::string format_time(const char* format, const struct tm& t) {
    char buffer[256];
    strftime(buffer, sizeof(buffer), format, &t);
    return buffer;
}

//! format string using time in localtime representation
static inline
std::string format_time(const char* format, const time_t& t) {
    return format_time(format, localtime_from(t));
}

class Stage
{
public:
    static const bool debug = false;

    using system_clock = std::chrono::system_clock;

    explicit Stage(const DIABasePtr& node) : node_(node) { }

    //! compute a string to show all target nodes into which this Stage pushes.
    std::string Targets() const {
        std::ostringstream oss;
        std::vector<DIABase*> children = node_->children();
        std::reverse(children.begin(), children.end());

        oss << '[';
        while (children.size())
        {
            DIABase* child = children.back();
            children.pop_back();

            if (child == nullptr) {
                oss << ']';
            }
            else if (child->type() == DIANodeType::COLLAPSE) {
                // push children of Collapse onto stack
                std::vector<DIABase*> sub = child->children();
                children.push_back(nullptr);
                children.insert(children.end(), sub.begin(), sub.end());
                oss << *child << ' ' << '[';
            }
            else {
                oss << *child << ' ';
            }
        }
        oss << ']';
        return oss.str();
    }

    void Execute() {
        common::StatsTimer<true> timer;
        time_t tt = system_clock::to_time_t(system_clock::now());
        sLOG << "START  (EXECUTE) stage" << *node_ << "targets" << Targets()
             << "time:" << format_time("%T", tt);

        timer.Start();
        node_->Execute();
        node_->set_state(DIAState::EXECUTED);
        timer.Stop();

        tt = system_clock::to_time_t(system_clock::now());
        sLOG << "FINISH (EXECUTE) stage" << *node_ << "targets" << Targets()
             << "took" << timer.Milliseconds() << "ms"
             << "time:" << format_time("%T", tt);
    }

    void PushData() {
        if (node_->context().consume() && node_->consume_counter() == 0) {
            sLOG1 << "StageBuilder: attempt to PushData on"
                  << "stage" << *node_
                  << "failed, it was already consumed. Add .Keep()";
            abort();
        }

        common::StatsTimer<true> timer;
        time_t tt = system_clock::to_time_t(system_clock::now());
        sLOG << "START  (PUSHDATA) stage" << *node_ << "targets" << Targets()
             << "time:" << format_time("%T", tt);

        timer.Start();
        node_->RunPushData();
        node_->RemoveAllChildren();
        timer.Stop();

        tt = system_clock::to_time_t(system_clock::now());
        sLOG << "FINISH (PUSHDATA) stage" << *node_ << "targets" << Targets()
             << "took" << timer.Milliseconds() << "ms"
             << "time:" << format_time("%T", tt);
    }

    bool operator < (const Stage& s) const { return node_ < s.node_; }

    //! shared pointer to node
    DIABasePtr node_;

    //! temporary marker for toposort to detect cycles
    mutable bool cycle_mark_ = false;

    //! toposort seen marker
    mutable bool topo_seen_ = false;
};

template <typename T>
using mm_set = std::set<T, std::less<T>, mem::Allocator<T> >;

//! Do a BFS on parents to find all DIANodes (Stages) needed to Execute or
//! PushData to calculate this action node.
static void FindStages(const DIABasePtr& action, mm_set<Stage>& stages) {
    static const bool debug = Stage::debug;

    LOG << "Finding Stages:";

    mem::mm_deque<DIABasePtr> bfs_stack(
        mem::Allocator<DIABasePtr>(action->mem_manager()));

    bfs_stack.push_back(action);
    stages.insert(Stage(action));

    while (!bfs_stack.empty()) {
        DIABasePtr curr = bfs_stack.front();
        bfs_stack.pop_front();

        for (const DIABasePtr& p : curr->parents()) {
            // if parents where not already seen, push onto stages
            if (stages.count(Stage(p))) continue;

            LOG << "  Stage: " << *p;
            stages.insert(Stage(p));

            if (p->CanExecute()) {
                // If parent was not executed push it to the BFS queue and
                // continue upwards. if state is EXECUTED, then we only need to
                // PushData(), which is already indicated by stages.insert().
                if (p->state() == DIAState::NEW)
                    bfs_stack.push_back(p);
            }
            else {
                // If parent cannot be executed (hold data) continue upward.
                bfs_stack.push_back(p);
            }
        }
    }
}

static void TopoSortVisit(
    const Stage& s, mm_set<Stage>& stages, mem::mm_vector<Stage>& result) {
    // check markers
    die_unless(!s.cycle_mark_ && "Cycle in toposort of Stages? Impossible.");
    if (s.topo_seen_) return;

    s.cycle_mark_ = true;
    // iterate over all children of s which are in the to-be-calculate stages
    for (DIABase* child : s.node_->children()) {
        auto it = stages.find(Stage(child->shared_from_this()));

        // child not in stage set
        if (it == stages.end()) continue;

        // depth-first search
        TopoSortVisit(*it, stages, result);
    }

    s.topo_seen_ = true;
    s.cycle_mark_ = false;
    result.push_back(s);
}

static void TopoSortStages(mm_set<Stage>& stages, mem::mm_vector<Stage>& result) {
    // iterate over all stages and visit nodes in DFS search
    for (const Stage& s : stages) {
        if (s.topo_seen_) continue;
        TopoSortVisit(s, stages, result);
    }
}

void DIABase::RunScope() {
    static const bool debug = Stage::debug;

    LOG << "DIABase::Execute() this=" << *this;

    if (!CanExecute())
        die("DIA node " << *this << " cannot be executed.");

    mm_set<Stage> stages {
        mem::Allocator<Stage>(mem_manager())
    };
    FindStages(shared_from_this(), stages);

    mem::mm_vector<Stage> toporder {
        mem::Allocator<Stage>(mem_manager())
    };
    TopoSortStages(stages, toporder);

    LOG << "Topological order";
    for (auto top = toporder.rbegin(); top != toporder.rend(); ++top) {
        LOG << "  " << *top->node_;
    }

    assert(toporder.front().node_.get() == this);

    while (toporder.size())
    {
        Stage& s = toporder.back();

        if (!s.node_->CanExecute()) {
            toporder.pop_back();
            continue;
        }

        if (debug)
            mem::malloc_tracker_print_status();

        if (s.node_->state() == DIAState::NEW) {
            s.Execute();
            if (s.node_.get() != this)
                s.PushData();
        }
        else if (s.node_->state() == DIAState::EXECUTED) {
            if (s.node_.get() != this)
                s.PushData();
        }

        // remove from result stack, this may destroy the last shared_ptr
        // reference to a node.
        toporder.pop_back();
    }
}

/******************************************************************************/
// DIABase

//! make ostream-able.
std::ostream& operator << (std::ostream& os, const DIABase& d) {
    return os << d.label() << '.' << d.id();
}

//! Returns the state of this DIANode as a string. Used by ToString.
const char* DIABase::state_string() {
    switch (state_) {
    case DIAState::NEW:
        return "NEW";
    case DIAState::EXECUTED:
        return "EXECUTED";
    case DIAState::DISPOSED:
        return "DISPOSED";
    default:
        return "UNDEFINED";
    }
}

} // namespace api
} // namespace thrill

/******************************************************************************/
<commit_msg>no localtime_r on windows.<commit_after>/*******************************************************************************
 * thrill/api/dia_base.cpp
 *
 * Part of Project Thrill - http://project-thrill.org
 *
 * Copyright (C) 2015 Sebastian Lamm <seba.lamm@gmail.com>
 * Copyright (C) 2016 Timo Bingmann <tb@panthema.net>
 *
 * All rights reserved. Published under the BSD-2 license in the LICENSE file.
 ******************************************************************************/

#include <thrill/api/dia_base.hpp>
#include <thrill/common/logger.hpp>
#include <thrill/common/stat_logger.hpp>
#include <thrill/common/stats_timer.hpp>
#include <thrill/mem/allocator.hpp>

#include <algorithm>
#include <chrono>
#include <deque>
#include <functional>
#include <iomanip>
#include <set>
#include <string>
#include <utility>
#include <vector>

namespace thrill {
namespace api {

/******************************************************************************/
// DIABase StageBuilder

static inline
struct tm localtime_from(const time_t& t) {
#if __MINGW32__ || defined(_MSC_VER)
    return *localtime(&t); // NOLINT
#else
    struct tm tm;
    memset(&tm, 0, sizeof(tm));
    localtime_r(&t, &tm);
    return tm;
#endif
}

//! format string using time structure
static inline
std::string format_time(const char* format, const struct tm& t) {
    char buffer[256];
    strftime(buffer, sizeof(buffer), format, &t);
    return buffer;
}

//! format string using time in localtime representation
static inline
std::string format_time(const char* format, const time_t& t) {
    return format_time(format, localtime_from(t));
}

class Stage
{
public:
    static const bool debug = false;

    using system_clock = std::chrono::system_clock;

    explicit Stage(const DIABasePtr& node) : node_(node) { }

    //! compute a string to show all target nodes into which this Stage pushes.
    std::string Targets() const {
        std::ostringstream oss;
        std::vector<DIABase*> children = node_->children();
        std::reverse(children.begin(), children.end());

        oss << '[';
        while (children.size())
        {
            DIABase* child = children.back();
            children.pop_back();

            if (child == nullptr) {
                oss << ']';
            }
            else if (child->type() == DIANodeType::COLLAPSE) {
                // push children of Collapse onto stack
                std::vector<DIABase*> sub = child->children();
                children.push_back(nullptr);
                children.insert(children.end(), sub.begin(), sub.end());
                oss << *child << ' ' << '[';
            }
            else {
                oss << *child << ' ';
            }
        }
        oss << ']';
        return oss.str();
    }

    void Execute() {
        common::StatsTimer<true> timer;
        time_t tt = system_clock::to_time_t(system_clock::now());
        sLOG << "START  (EXECUTE) stage" << *node_ << "targets" << Targets()
             << "time:" << format_time("%T", tt);

        timer.Start();
        node_->Execute();
        node_->set_state(DIAState::EXECUTED);
        timer.Stop();

        tt = system_clock::to_time_t(system_clock::now());
        sLOG << "FINISH (EXECUTE) stage" << *node_ << "targets" << Targets()
             << "took" << timer.Milliseconds() << "ms"
             << "time:" << format_time("%T", tt);
    }

    void PushData() {
        if (node_->context().consume() && node_->consume_counter() == 0) {
            sLOG1 << "StageBuilder: attempt to PushData on"
                  << "stage" << *node_
                  << "failed, it was already consumed. Add .Keep()";
            abort();
        }

        common::StatsTimer<true> timer;
        time_t tt = system_clock::to_time_t(system_clock::now());
        sLOG << "START  (PUSHDATA) stage" << *node_ << "targets" << Targets()
             << "time:" << format_time("%T", tt);

        timer.Start();
        node_->RunPushData();
        node_->RemoveAllChildren();
        timer.Stop();

        tt = system_clock::to_time_t(system_clock::now());
        sLOG << "FINISH (PUSHDATA) stage" << *node_ << "targets" << Targets()
             << "took" << timer.Milliseconds() << "ms"
             << "time:" << format_time("%T", tt);
    }

    bool operator < (const Stage& s) const { return node_ < s.node_; }

    //! shared pointer to node
    DIABasePtr node_;

    //! temporary marker for toposort to detect cycles
    mutable bool cycle_mark_ = false;

    //! toposort seen marker
    mutable bool topo_seen_ = false;
};

template <typename T>
using mm_set = std::set<T, std::less<T>, mem::Allocator<T> >;

//! Do a BFS on parents to find all DIANodes (Stages) needed to Execute or
//! PushData to calculate this action node.
static void FindStages(const DIABasePtr& action, mm_set<Stage>& stages) {
    static const bool debug = Stage::debug;

    LOG << "Finding Stages:";

    mem::mm_deque<DIABasePtr> bfs_stack(
        mem::Allocator<DIABasePtr>(action->mem_manager()));

    bfs_stack.push_back(action);
    stages.insert(Stage(action));

    while (!bfs_stack.empty()) {
        DIABasePtr curr = bfs_stack.front();
        bfs_stack.pop_front();

        for (const DIABasePtr& p : curr->parents()) {
            // if parents where not already seen, push onto stages
            if (stages.count(Stage(p))) continue;

            LOG << "  Stage: " << *p;
            stages.insert(Stage(p));

            if (p->CanExecute()) {
                // If parent was not executed push it to the BFS queue and
                // continue upwards. if state is EXECUTED, then we only need to
                // PushData(), which is already indicated by stages.insert().
                if (p->state() == DIAState::NEW)
                    bfs_stack.push_back(p);
            }
            else {
                // If parent cannot be executed (hold data) continue upward.
                bfs_stack.push_back(p);
            }
        }
    }
}

static void TopoSortVisit(
    const Stage& s, mm_set<Stage>& stages, mem::mm_vector<Stage>& result) {
    // check markers
    die_unless(!s.cycle_mark_ && "Cycle in toposort of Stages? Impossible.");
    if (s.topo_seen_) return;

    s.cycle_mark_ = true;
    // iterate over all children of s which are in the to-be-calculate stages
    for (DIABase* child : s.node_->children()) {
        auto it = stages.find(Stage(child->shared_from_this()));

        // child not in stage set
        if (it == stages.end()) continue;

        // depth-first search
        TopoSortVisit(*it, stages, result);
    }

    s.topo_seen_ = true;
    s.cycle_mark_ = false;
    result.push_back(s);
}

static void TopoSortStages(mm_set<Stage>& stages, mem::mm_vector<Stage>& result) {
    // iterate over all stages and visit nodes in DFS search
    for (const Stage& s : stages) {
        if (s.topo_seen_) continue;
        TopoSortVisit(s, stages, result);
    }
}

void DIABase::RunScope() {
    static const bool debug = Stage::debug;

    LOG << "DIABase::Execute() this=" << *this;

    if (!CanExecute())
        die("DIA node " << *this << " cannot be executed.");

    mm_set<Stage> stages {
        mem::Allocator<Stage>(mem_manager())
    };
    FindStages(shared_from_this(), stages);

    mem::mm_vector<Stage> toporder {
        mem::Allocator<Stage>(mem_manager())
    };
    TopoSortStages(stages, toporder);

    LOG << "Topological order";
    for (auto top = toporder.rbegin(); top != toporder.rend(); ++top) {
        LOG << "  " << *top->node_;
    }

    assert(toporder.front().node_.get() == this);

    while (toporder.size())
    {
        Stage& s = toporder.back();

        if (!s.node_->CanExecute()) {
            toporder.pop_back();
            continue;
        }

        if (debug)
            mem::malloc_tracker_print_status();

        if (s.node_->state() == DIAState::NEW) {
            s.Execute();
            if (s.node_.get() != this)
                s.PushData();
        }
        else if (s.node_->state() == DIAState::EXECUTED) {
            if (s.node_.get() != this)
                s.PushData();
        }

        // remove from result stack, this may destroy the last shared_ptr
        // reference to a node.
        toporder.pop_back();
    }
}

/******************************************************************************/
// DIABase

//! make ostream-able.
std::ostream& operator << (std::ostream& os, const DIABase& d) {
    return os << d.label() << '.' << d.id();
}

//! Returns the state of this DIANode as a string. Used by ToString.
const char* DIABase::state_string() {
    switch (state_) {
    case DIAState::NEW:
        return "NEW";
    case DIAState::EXECUTED:
        return "EXECUTED";
    case DIAState::DISPOSED:
        return "DISPOSED";
    default:
        return "UNDEFINED";
    }
}

} // namespace api
} // namespace thrill

/******************************************************************************/
<|endoftext|>


<commit_before>/*============================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.

Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.

============================================================================*/

#include "QmitkVolumeVisualizationView.h"

#include <vtkSmartVolumeMapper.h>

#include <mitkImage.h>

#include <mitkTransferFunction.h>
#include <mitkTransferFunctionInitializer.h>
#include <mitkTransferFunctionProperty.h>

#include <mitkNodePredicateDataType.h>
#include <mitkNodePredicateDimension.h>
#include <mitkNodePredicateAnd.h>
#include <mitkNodePredicateNot.h>
#include <mitkNodePredicateOr.h>
#include <mitkNodePredicateProperty.h>

#include <mitkProperties.h>

const std::string QmitkVolumeVisualizationView::VIEW_ID = "org.mitk.views.volumevisualization";

enum
{
  DEFAULT_RENDERMODE = 0,
  RAYCAST_RENDERMODE = 1,
  GPU_RENDERMODE = 2
};

QmitkVolumeVisualizationView::QmitkVolumeVisualizationView()
  : QmitkAbstractView()
  , m_Controls(nullptr)
{
}

void QmitkVolumeVisualizationView::SetFocus()
{
}

void QmitkVolumeVisualizationView::CreateQtPartControl(QWidget* parent)
{
  m_Controls = new Ui::QmitkVolumeVisualizationViewControls;
  m_Controls->setupUi(parent);

  m_Controls->volumeSelectionWidget->SetDataStorage(GetDataStorage());
  m_Controls->volumeSelectionWidget->SetNodePredicate(mitk::NodePredicateAnd::New(
    mitk::TNodePredicateDataType<mitk::Image>::New(),
    mitk::NodePredicateOr::New(mitk::NodePredicateDimension::New(3), mitk::NodePredicateDimension::New(4)),
    mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))));
  m_Controls->volumeSelectionWidget->SetSelectionIsOptional(true);
  m_Controls->volumeSelectionWidget->SetAutoSelectNewNodes(true);
  m_Controls->volumeSelectionWidget->SetEmptyInfo(QString("Please select a 3D / 4D image volume"));
  m_Controls->volumeSelectionWidget->SetPopUpTitel(QString("Select image volume"));

  // Fill the transfer function presets in the generator widget
  std::vector<std::string> names;
  mitk::TransferFunctionInitializer::GetPresetNames(names);
  for (const auto& name : names)
  {
    m_Controls->transferFunctionGeneratorWidget->AddPreset(QString::fromStdString(name));
  }

  // see enum in vtkSmartVolumeMapper
  m_Controls->renderMode->addItem("Default");
  m_Controls->renderMode->addItem("RayCast");
  m_Controls->renderMode->addItem("GPU");

  // see vtkVolumeMapper::BlendModes
  m_Controls->blendMode->addItem("Comp");
  m_Controls->blendMode->addItem("Max");
  m_Controls->blendMode->addItem("Min");
  m_Controls->blendMode->addItem("Avg");
  m_Controls->blendMode->addItem("Add");

  connect(m_Controls->volumeSelectionWidget, &QmitkSingleNodeSelectionWidget::CurrentSelectionChanged,
    this, &QmitkVolumeVisualizationView::OnCurrentSelectionChanged);
  connect(m_Controls->enableRenderingCB, SIGNAL(toggled(bool)), this, SLOT(OnEnableRendering(bool)));
  connect(m_Controls->renderMode, SIGNAL(activated(int)), this, SLOT(OnRenderMode(int)));
  connect(m_Controls->blendMode, SIGNAL(activated(int)), this, SLOT(OnBlendMode(int)));

  connect(m_Controls->transferFunctionGeneratorWidget, SIGNAL(SignalUpdateCanvas()),
          m_Controls->transferFunctionWidget, SLOT(OnUpdateCanvas()));
  connect(m_Controls->transferFunctionGeneratorWidget, SIGNAL(SignalTransferFunctionModeChanged(int)),
          SLOT(OnMitkInternalPreset(int)));

  m_Controls->enableRenderingCB->setEnabled(false);
  m_Controls->blendMode->setEnabled(false);
  m_Controls->renderMode->setEnabled(false);
  m_Controls->transferFunctionWidget->setEnabled(false);
  m_Controls->transferFunctionGeneratorWidget->setEnabled(false);

  m_Controls->volumeSelectionWidget->SetAutoSelectNewNodes(true);
}

void QmitkVolumeVisualizationView::OnMitkInternalPreset(int mode)
{
  if (m_SelectedNode.IsExpired())
  {
    return;
  }

  auto node = m_SelectedNode.Lock();
  mitk::TransferFunctionProperty::Pointer transferFuncProp;
  if (node->GetProperty(transferFuncProp, "TransferFunction"))
  {
    // first item is only information
    if (--mode == -1)
      return;

    // -- Creat new TransferFunction
    mitk::TransferFunctionInitializer::Pointer tfInit = mitk::TransferFunctionInitializer::New(transferFuncProp->GetValue());
    tfInit->SetTransferFunctionMode(mode);
    RequestRenderWindowUpdate();
    m_Controls->transferFunctionWidget->OnUpdateCanvas();
  }
}

void QmitkVolumeVisualizationView::OnCurrentSelectionChanged(QList<mitk::DataNode::Pointer> nodes)
{
  m_SelectedNode = nullptr;

  if (nodes.empty() || nodes.front().IsNull())
  {
    UpdateInterface();
    return;
  }

  auto selectedNode = nodes.front();
  auto image = dynamic_cast<mitk::Image*>(selectedNode->GetData());
  if (nullptr != image)
  {
    m_SelectedNode = selectedNode;
  }

  UpdateInterface();
}

void QmitkVolumeVisualizationView::OnEnableRendering(bool state)
{
  if (m_SelectedNode.IsExpired())
  {
    return;
  }

  m_SelectedNode.Lock()->SetProperty("volumerendering", mitk::BoolProperty::New(state));
  UpdateInterface();
  RequestRenderWindowUpdate();
}

void QmitkVolumeVisualizationView::OnRenderMode(int mode)
{
  if (m_SelectedNode.IsExpired())
  {
    return;
  }

  auto selectedNode = m_SelectedNode.Lock();

  bool usegpu = false;
  bool useray = false;
  if (DEFAULT_RENDERMODE == mode)
  {
    useray = true;
    usegpu = true;
  }
  else if (GPU_RENDERMODE == mode)
  {
    usegpu = true;
  }
  else if (RAYCAST_RENDERMODE == mode)
  {
    useray = true;
  }

  selectedNode->SetProperty("volumerendering.usegpu", mitk::BoolProperty::New(usegpu));
  selectedNode->SetProperty("volumerendering.useray", mitk::BoolProperty::New(useray));

  RequestRenderWindowUpdate();
}

void QmitkVolumeVisualizationView::OnBlendMode(int mode)
{
  if (m_SelectedNode.IsExpired())
  {
    return;
  }

  auto selectedNode = m_SelectedNode.Lock();

  bool usemip = false;
  if (vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND == mode)
  {
    usemip = true;
  }

  selectedNode->SetProperty("volumerendering.usemip", mitk::BoolProperty::New(usemip));
  selectedNode->SetProperty("volumerendering.blendmode", mitk::IntProperty::New(mode));

  RequestRenderWindowUpdate();
}

void QmitkVolumeVisualizationView::UpdateInterface()
{
  if (m_SelectedNode.IsExpired())
  {
    // turnoff all
    m_Controls->enableRenderingCB->setChecked(false);
    m_Controls->enableRenderingCB->setEnabled(false);

    m_Controls->blendMode->setCurrentIndex(0);
    m_Controls->blendMode->setEnabled(false);

    m_Controls->renderMode->setCurrentIndex(0);
    m_Controls->renderMode->setEnabled(false);

    m_Controls->transferFunctionWidget->SetDataNode(nullptr);
    m_Controls->transferFunctionWidget->setEnabled(false);

    m_Controls->transferFunctionGeneratorWidget->SetDataNode(nullptr);
    m_Controls->transferFunctionGeneratorWidget->setEnabled(false);
    return;
  }

  bool enabled = false;
  auto selectedNode = m_SelectedNode.Lock();

  selectedNode->GetBoolProperty("volumerendering", enabled);
  m_Controls->enableRenderingCB->setEnabled(true);
  m_Controls->enableRenderingCB->setChecked(enabled);

  if (!enabled)
  {
    // turnoff all except volumerendering checkbox
    m_Controls->blendMode->setCurrentIndex(0);
    m_Controls->blendMode->setEnabled(false);

    m_Controls->renderMode->setCurrentIndex(0);
    m_Controls->renderMode->setEnabled(false);

    m_Controls->transferFunctionWidget->SetDataNode(nullptr);
    m_Controls->transferFunctionWidget->setEnabled(false);

    m_Controls->transferFunctionGeneratorWidget->SetDataNode(nullptr);
    m_Controls->transferFunctionGeneratorWidget->setEnabled(false);
    return;
  }

  // otherwise we can activate em all
  m_Controls->blendMode->setEnabled(true);
  m_Controls->renderMode->setEnabled(true);

  // Determine Combo Box mode
  {
    bool usegpu = false;
    bool useray = false;
    bool usemip = false;
    selectedNode->GetBoolProperty("volumerendering.usegpu", usegpu);
    selectedNode->GetBoolProperty("volumerendering.useray", useray);
    selectedNode->GetBoolProperty("volumerendering.usemip", usemip);

    int blendMode;
    if (selectedNode->GetIntProperty("volumerendering.blendmode", blendMode))
      m_Controls->blendMode->setCurrentIndex(blendMode);

    if (usemip)
      m_Controls->blendMode->setCurrentIndex(vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND);

    int mode = DEFAULT_RENDERMODE;

    if (useray)
      mode = RAYCAST_RENDERMODE;
    else if (usegpu)
      mode = GPU_RENDERMODE;

    m_Controls->renderMode->setCurrentIndex(mode);
  }

  m_Controls->transferFunctionWidget->SetDataNode(selectedNode);
  m_Controls->transferFunctionWidget->setEnabled(true);
  m_Controls->transferFunctionGeneratorWidget->SetDataNode(selectedNode);
  m_Controls->transferFunctionGeneratorWidget->setEnabled(true);
}
<commit_msg>remove duplicate SetAutoSelectNewNodes that blocks correct signal connecting<commit_after>/*============================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.

Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.

============================================================================*/

#include "QmitkVolumeVisualizationView.h"

#include <vtkSmartVolumeMapper.h>

#include <mitkImage.h>

#include <mitkTransferFunction.h>
#include <mitkTransferFunctionInitializer.h>
#include <mitkTransferFunctionProperty.h>

#include <mitkNodePredicateDataType.h>
#include <mitkNodePredicateDimension.h>
#include <mitkNodePredicateAnd.h>
#include <mitkNodePredicateNot.h>
#include <mitkNodePredicateOr.h>
#include <mitkNodePredicateProperty.h>

#include <mitkProperties.h>

const std::string QmitkVolumeVisualizationView::VIEW_ID = "org.mitk.views.volumevisualization";

enum
{
  DEFAULT_RENDERMODE = 0,
  RAYCAST_RENDERMODE = 1,
  GPU_RENDERMODE = 2
};

QmitkVolumeVisualizationView::QmitkVolumeVisualizationView()
  : QmitkAbstractView()
  , m_Controls(nullptr)
{
}

void QmitkVolumeVisualizationView::SetFocus()
{
  UpdateInterface();
}

void QmitkVolumeVisualizationView::CreateQtPartControl(QWidget* parent)
{
  m_Controls = new Ui::QmitkVolumeVisualizationViewControls;
  m_Controls->setupUi(parent);

  m_Controls->volumeSelectionWidget->SetDataStorage(GetDataStorage());
  m_Controls->volumeSelectionWidget->SetNodePredicate(mitk::NodePredicateAnd::New(
    mitk::TNodePredicateDataType<mitk::Image>::New(),
    mitk::NodePredicateOr::New(mitk::NodePredicateDimension::New(3), mitk::NodePredicateDimension::New(4)),
    mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))));
  m_Controls->volumeSelectionWidget->SetSelectionIsOptional(true);
  m_Controls->volumeSelectionWidget->SetEmptyInfo(QString("Please select a 3D / 4D image volume"));
  m_Controls->volumeSelectionWidget->SetPopUpTitel(QString("Select image volume"));

  // Fill the transfer function presets in the generator widget
  std::vector<std::string> names;
  mitk::TransferFunctionInitializer::GetPresetNames(names);
  for (const auto& name : names)
  {
    m_Controls->transferFunctionGeneratorWidget->AddPreset(QString::fromStdString(name));
  }

  // see enum in vtkSmartVolumeMapper
  m_Controls->renderMode->addItem("Default");
  m_Controls->renderMode->addItem("RayCast");
  m_Controls->renderMode->addItem("GPU");

  // see vtkVolumeMapper::BlendModes
  m_Controls->blendMode->addItem("Comp");
  m_Controls->blendMode->addItem("Max");
  m_Controls->blendMode->addItem("Min");
  m_Controls->blendMode->addItem("Avg");
  m_Controls->blendMode->addItem("Add");

  connect(m_Controls->volumeSelectionWidget, &QmitkSingleNodeSelectionWidget::CurrentSelectionChanged,
    this, &QmitkVolumeVisualizationView::OnCurrentSelectionChanged);
  connect(m_Controls->enableRenderingCB, SIGNAL(toggled(bool)), this, SLOT(OnEnableRendering(bool)));
  connect(m_Controls->renderMode, SIGNAL(activated(int)), this, SLOT(OnRenderMode(int)));
  connect(m_Controls->blendMode, SIGNAL(activated(int)), this, SLOT(OnBlendMode(int)));

  connect(m_Controls->transferFunctionGeneratorWidget, SIGNAL(SignalUpdateCanvas()),
          m_Controls->transferFunctionWidget, SLOT(OnUpdateCanvas()));
  connect(m_Controls->transferFunctionGeneratorWidget, SIGNAL(SignalTransferFunctionModeChanged(int)),
          SLOT(OnMitkInternalPreset(int)));

  m_Controls->enableRenderingCB->setEnabled(false);
  m_Controls->blendMode->setEnabled(false);
  m_Controls->renderMode->setEnabled(false);
  m_Controls->transferFunctionWidget->setEnabled(false);
  m_Controls->transferFunctionGeneratorWidget->setEnabled(false);

  m_Controls->volumeSelectionWidget->SetAutoSelectNewNodes(true);
}

void QmitkVolumeVisualizationView::OnMitkInternalPreset(int mode)
{
  if (m_SelectedNode.IsExpired())
  {
    return;
  }

  auto node = m_SelectedNode.Lock();
  mitk::TransferFunctionProperty::Pointer transferFuncProp;
  if (node->GetProperty(transferFuncProp, "TransferFunction"))
  {
    // first item is only information
    if (--mode == -1)
      return;

    // -- Creat new TransferFunction
    mitk::TransferFunctionInitializer::Pointer tfInit = mitk::TransferFunctionInitializer::New(transferFuncProp->GetValue());
    tfInit->SetTransferFunctionMode(mode);
    RequestRenderWindowUpdate();
    m_Controls->transferFunctionWidget->OnUpdateCanvas();
  }
}

void QmitkVolumeVisualizationView::OnCurrentSelectionChanged(QList<mitk::DataNode::Pointer> nodes)
{
  m_SelectedNode = nullptr;

  if (nodes.empty() || nodes.front().IsNull())
  {
    UpdateInterface();
    return;
  }

  auto selectedNode = nodes.front();
  auto image = dynamic_cast<mitk::Image*>(selectedNode->GetData());
  if (nullptr != image)
  {
    m_SelectedNode = selectedNode;
  }

  UpdateInterface();
}

void QmitkVolumeVisualizationView::OnEnableRendering(bool state)
{
  if (m_SelectedNode.IsExpired())
  {
    return;
  }

  m_SelectedNode.Lock()->SetProperty("volumerendering", mitk::BoolProperty::New(state));
  UpdateInterface();
  RequestRenderWindowUpdate();
}

void QmitkVolumeVisualizationView::OnRenderMode(int mode)
{
  if (m_SelectedNode.IsExpired())
  {
    return;
  }

  auto selectedNode = m_SelectedNode.Lock();

  bool usegpu = false;
  bool useray = false;
  if (DEFAULT_RENDERMODE == mode)
  {
    useray = true;
    usegpu = true;
  }
  else if (GPU_RENDERMODE == mode)
  {
    usegpu = true;
  }
  else if (RAYCAST_RENDERMODE == mode)
  {
    useray = true;
  }

  selectedNode->SetProperty("volumerendering.usegpu", mitk::BoolProperty::New(usegpu));
  selectedNode->SetProperty("volumerendering.useray", mitk::BoolProperty::New(useray));

  RequestRenderWindowUpdate();
}

void QmitkVolumeVisualizationView::OnBlendMode(int mode)
{
  if (m_SelectedNode.IsExpired())
  {
    return;
  }

  auto selectedNode = m_SelectedNode.Lock();

  bool usemip = false;
  if (vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND == mode)
  {
    usemip = true;
  }

  selectedNode->SetProperty("volumerendering.usemip", mitk::BoolProperty::New(usemip));
  selectedNode->SetProperty("volumerendering.blendmode", mitk::IntProperty::New(mode));

  RequestRenderWindowUpdate();
}

void QmitkVolumeVisualizationView::UpdateInterface()
{
  if (m_SelectedNode.IsExpired())
  {
    // turnoff all
    m_Controls->enableRenderingCB->setChecked(false);
    m_Controls->enableRenderingCB->setEnabled(false);

    m_Controls->blendMode->setCurrentIndex(0);
    m_Controls->blendMode->setEnabled(false);

    m_Controls->renderMode->setCurrentIndex(0);
    m_Controls->renderMode->setEnabled(false);

    m_Controls->transferFunctionWidget->SetDataNode(nullptr);
    m_Controls->transferFunctionWidget->setEnabled(false);

    m_Controls->transferFunctionGeneratorWidget->SetDataNode(nullptr);
    m_Controls->transferFunctionGeneratorWidget->setEnabled(false);
    return;
  }

  bool enabled = false;
  auto selectedNode = m_SelectedNode.Lock();

  selectedNode->GetBoolProperty("volumerendering", enabled);
  m_Controls->enableRenderingCB->setEnabled(true);
  m_Controls->enableRenderingCB->setChecked(enabled);

  if (!enabled)
  {
    // turnoff all except volumerendering checkbox
    m_Controls->blendMode->setCurrentIndex(0);
    m_Controls->blendMode->setEnabled(false);

    m_Controls->renderMode->setCurrentIndex(0);
    m_Controls->renderMode->setEnabled(false);

    m_Controls->transferFunctionWidget->SetDataNode(nullptr);
    m_Controls->transferFunctionWidget->setEnabled(false);

    m_Controls->transferFunctionGeneratorWidget->SetDataNode(nullptr);
    m_Controls->transferFunctionGeneratorWidget->setEnabled(false);
    return;
  }

  // otherwise we can activate em all
  m_Controls->blendMode->setEnabled(true);
  m_Controls->renderMode->setEnabled(true);

  // Determine Combo Box mode
  {
    bool usegpu = false;
    bool useray = false;
    bool usemip = false;
    selectedNode->GetBoolProperty("volumerendering.usegpu", usegpu);
    selectedNode->GetBoolProperty("volumerendering.useray", useray);
    selectedNode->GetBoolProperty("volumerendering.usemip", usemip);

    int blendMode;
    if (selectedNode->GetIntProperty("volumerendering.blendmode", blendMode))
      m_Controls->blendMode->setCurrentIndex(blendMode);

    if (usemip)
      m_Controls->blendMode->setCurrentIndex(vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND);

    int mode = DEFAULT_RENDERMODE;

    if (useray)
      mode = RAYCAST_RENDERMODE;
    else if (usegpu)
      mode = GPU_RENDERMODE;

    m_Controls->renderMode->setCurrentIndex(mode);
  }

  m_Controls->transferFunctionWidget->SetDataNode(selectedNode);
  m_Controls->transferFunctionWidget->setEnabled(true);
  m_Controls->transferFunctionGeneratorWidget->SetDataNode(selectedNode);
  m_Controls->transferFunctionGeneratorWidget->setEnabled(true);
}
<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2010 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/

#include "FFmpegHeaders.hpp"
#include "FFmpegImageStream.hpp"
#include "FFmpegParameters.hpp"

#include <osgDB/Registry>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>

#if LIBAVCODEC_VERSION_MAJOR >= 53 || \
    (LIBAVCODEC_VERSION_MAJOR==52 && LIBAVCODEC_VERSION_MINOR>=30) || \
    (LIBAVCODEC_VERSION_MAJOR==52 && LIBAVCODEC_VERSION_MINOR==20 && LIBAVCODEC_VERSION_MICRO >= 1)
    #define USE_AV_LOCK_MANAGER
#endif

extern "C" {

static void log_to_osg(void* /*ptr*/, int level, const char *fmt, va_list vl)
{
    char logbuf[256];
    vsnprintf(logbuf, sizeof(logbuf), fmt, vl);
    logbuf[sizeof(logbuf) - 1] = '\0';

    osg::NotifySeverity severity = osg::DEBUG_FP;

    switch (level) {
    case AV_LOG_PANIC:
        severity = osg::ALWAYS;
        break;
    case AV_LOG_FATAL:
        severity = osg::FATAL;
        break;
    case AV_LOG_ERROR:
        severity = osg::WARN;
        break;
    case AV_LOG_WARNING:
        severity = osg::NOTICE;
        break;
    case AV_LOG_INFO:
        severity = osg::INFO;
        break;
    case AV_LOG_VERBOSE:
        severity = osg::DEBUG_INFO;
        break;
    default:
    case AV_LOG_DEBUG:
        severity = osg::DEBUG_FP;
        break;
    }

    // Most av_logs have a trailing newline already
    osg::notify(severity) << logbuf;
}

} // extern "C"

/** Implementation heavily inspired by http://www.dranger.com/ffmpeg/ */

class ReaderWriterFFmpeg : public osgDB::ReaderWriter
{
public:

    ReaderWriterFFmpeg()
    {
        supportsProtocol("http","Read video/audio from http using ffmpeg.");
        supportsProtocol("rtsp","Read video/audio from rtsp using ffmpeg.");
        supportsProtocol("rtp","Read video/audio from rtp using ffmpeg.");
        supportsProtocol("tcp","Read video/audio from tcp using ffmpeg.");

        supportsExtension("ffmpeg", "");
        supportsExtension("avi",    "");
        supportsExtension("flv",    "Flash video");
        supportsExtension("mov",    "Quicktime");
        supportsExtension("ogg",    "Theora movie format");
        supportsExtension("mpg",    "Mpeg movie format");
        supportsExtension("mpv",    "Mpeg movie format");
        supportsExtension("wmv",    "Windows Media Video format");
        supportsExtension("mkv",    "Matroska");
        supportsExtension("mjpeg",  "Motion JPEG");
        supportsExtension("mp4",    "MPEG-4");
        supportsExtension("m4v",    "MPEG-4");
        supportsExtension("sav",    "Unknown");
        supportsExtension("3gp",    "3G multi-media format");
        supportsExtension("sdp",    "Session Description Protocol");
        supportsExtension("m2ts",   "MPEG-2 Transport Stream");
        supportsExtension("ts",     "MPEG-2 Transport Stream");

        supportsOption("format",            "Force setting input format (e.g. vfwcap for Windows webcam)");
        supportsOption("pixel_format",      "Set pixel format");
        supportsOption("frame_size",              "Set frame size (e.g. 320x240)");
        supportsOption("frame_rate",        "Set frame rate (e.g. 25)");
        // WARNING:  This option is kept for backwards compatibility only, use out_sample_rate instead!
        supportsOption("audio_sample_rate", "Set audio sampling rate (e.g. 44100)");
        supportsOption("out_sample_format", "Set the output sample format (e.g. AV_SAMPLE_FMT_S16)");
        supportsOption("out_sample_rate",     "Set the output sample rate or frequency in Hz (e.g. 48000)");
        supportsOption("out_nb_channels",   "Set the output number of channels (e.g. 2 for stereo)");
        supportsOption("context",            "AVIOContext* for custom IO");
        supportsOption("mad",            "Max analyze duration (seconds)");
        supportsOption("rtsp_transport", "RTSP transport (udp, tcp, udp_multicast or http)");

        av_log_set_callback(log_to_osg);

#ifdef USE_AV_LOCK_MANAGER
        // enable thread locking
        av_lockmgr_register(&lockMgr);
#endif
        // Register all FFmpeg formats/codecs
        av_register_all();

        avformat_network_init();
    }

    virtual ~ReaderWriterFFmpeg()
    {
    }

    virtual const char * className() const
    {
        return "ReaderWriterFFmpeg";
    }

    virtual ReadResult readImage(const std::string & filename, const osgDB::ReaderWriter::Options* options) const
    {
        const std::string ext = osgDB::getLowerCaseFileExtension(filename);
        const std::string pro = osgDB::getServerProtocol(filename);
		if (!acceptsExtension(ext) && !acceptsProtocol(pro)) return ReadResult::FILE_NOT_HANDLED;

        if (ext=="ffmpeg") return readImage(osgDB::getNameLessExtension(filename),options);

        osg::ref_ptr<osgFFmpeg::FFmpegParameters> parameters(new osgFFmpeg::FFmpegParameters);
        parseOptions(parameters.get(), options);

        if (filename.compare(0, 5, "/dev/")==0)
        {
            return readImageStream(filename, parameters.get());
        }

#if 1
        // NOTE: The original code checks parameters->isFormatAvailable() which returns
        // false when a format is not explicitly specified.
        // In these cases, the extension is used, which is a problem for videos served
        // from URLs without an extension
        {
            ReadResult rr = readImageStream(filename, parameters.get());
            if ( rr.validImage() )
                return rr;
        }
#else
        if (parameters->isFormatAvailable())
        {
            return readImageStream(filename, parameters.get());
        }
#endif

        if (! acceptsExtension(ext))
            return ReadResult::FILE_NOT_HANDLED;

        const std::string path = osgDB::containsServerAddress(filename) ?
            filename :
            osgDB::findDataFile(filename, options);

        if (path.empty())
            return ReadResult::FILE_NOT_FOUND;

        return readImageStream(path, parameters.get());
    }

    ReadResult readImageStream(const std::string& filename, osgFFmpeg::FFmpegParameters* parameters) const
    {
        OSG_INFO << "ReaderWriterFFmpeg::readImage " << filename << std::endl;

        osg::ref_ptr<osgFFmpeg::FFmpegImageStream> image_stream(new osgFFmpeg::FFmpegImageStream);

        if (! image_stream->open(filename, parameters))
            return ReadResult::FILE_NOT_HANDLED;

        return image_stream.release();
    }

private:

    void parseOptions(osgFFmpeg::FFmpegParameters* parameters, const osgDB::ReaderWriter::Options * options) const
    {
        if (options && options->getNumPluginStringData()>0)
        {
            const FormatDescriptionMap& supportedOptList = supportedOptions();
            for (FormatDescriptionMap::const_iterator itr = supportedOptList.begin();
                 itr != supportedOptList.end(); ++itr)
            {
                const std::string& name = itr->first;
                parameters->parse(name, options->getPluginStringData(name));
            }
        }
        if (options && options->getNumPluginData()>0)
        {
            AVIOContext* context = (AVIOContext*)options->getPluginData("context");
            if (context != NULL)
            {
                parameters->setContext(context);
            }
        }
    }

#ifdef USE_AV_LOCK_MANAGER
    static int lockMgr(void **mutex, enum AVLockOp op)
    {
        // returns are 0 success
        OpenThreads::Mutex **m=(OpenThreads::Mutex**)mutex;
        if (op==AV_LOCK_CREATE)
        {
            *m=new OpenThreads::Mutex;
            return !*m;
        }
        else if (op==AV_LOCK_DESTROY)
        {
            delete *m;
            return 0;
        }
        else if (op==AV_LOCK_OBTAIN)
        {
            (*m)->lock();
            return 0;
        }
        else if (op==AV_LOCK_RELEASE)
        {
            (*m)->unlock();
            return 0;
        }
        else
        {
            return -1;
        }
    }
#endif

};

REGISTER_OSGPLUGIN(ffmpeg, ReaderWriterFFmpeg)
<commit_msg>Fixed indentation, replacing tabs with spaces<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2010 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/

#include "FFmpegHeaders.hpp"
#include "FFmpegImageStream.hpp"
#include "FFmpegParameters.hpp"

#include <osgDB/Registry>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>

#if LIBAVCODEC_VERSION_MAJOR >= 53 || \
    (LIBAVCODEC_VERSION_MAJOR==52 && LIBAVCODEC_VERSION_MINOR>=30) || \
    (LIBAVCODEC_VERSION_MAJOR==52 && LIBAVCODEC_VERSION_MINOR==20 && LIBAVCODEC_VERSION_MICRO >= 1)
    #define USE_AV_LOCK_MANAGER
#endif

extern "C" {

static void log_to_osg(void* /*ptr*/, int level, const char *fmt, va_list vl)
{
    char logbuf[256];
    vsnprintf(logbuf, sizeof(logbuf), fmt, vl);
    logbuf[sizeof(logbuf) - 1] = '\0';

    osg::NotifySeverity severity = osg::DEBUG_FP;

    switch (level) {
    case AV_LOG_PANIC:
        severity = osg::ALWAYS;
        break;
    case AV_LOG_FATAL:
        severity = osg::FATAL;
        break;
    case AV_LOG_ERROR:
        severity = osg::WARN;
        break;
    case AV_LOG_WARNING:
        severity = osg::NOTICE;
        break;
    case AV_LOG_INFO:
        severity = osg::INFO;
        break;
    case AV_LOG_VERBOSE:
        severity = osg::DEBUG_INFO;
        break;
    default:
    case AV_LOG_DEBUG:
        severity = osg::DEBUG_FP;
        break;
    }

    // Most av_logs have a trailing newline already
    osg::notify(severity) << logbuf;
}

} // extern "C"

/** Implementation heavily inspired by http://www.dranger.com/ffmpeg/ */

class ReaderWriterFFmpeg : public osgDB::ReaderWriter
{
public:

    ReaderWriterFFmpeg()
    {
        supportsProtocol("http","Read video/audio from http using ffmpeg.");
        supportsProtocol("rtsp","Read video/audio from rtsp using ffmpeg.");
        supportsProtocol("rtp","Read video/audio from rtp using ffmpeg.");
        supportsProtocol("tcp","Read video/audio from tcp using ffmpeg.");

        supportsExtension("ffmpeg", "");
        supportsExtension("avi",    "");
        supportsExtension("flv",    "Flash video");
        supportsExtension("mov",    "Quicktime");
        supportsExtension("ogg",    "Theora movie format");
        supportsExtension("mpg",    "Mpeg movie format");
        supportsExtension("mpv",    "Mpeg movie format");
        supportsExtension("wmv",    "Windows Media Video format");
        supportsExtension("mkv",    "Matroska");
        supportsExtension("mjpeg",  "Motion JPEG");
        supportsExtension("mp4",    "MPEG-4");
        supportsExtension("m4v",    "MPEG-4");
        supportsExtension("sav",    "Unknown");
        supportsExtension("3gp",    "3G multi-media format");
        supportsExtension("sdp",    "Session Description Protocol");
        supportsExtension("m2ts",   "MPEG-2 Transport Stream");
        supportsExtension("ts",     "MPEG-2 Transport Stream");

        supportsOption("format",            "Force setting input format (e.g. vfwcap for Windows webcam)");
        supportsOption("pixel_format",      "Set pixel format");
        supportsOption("frame_size",              "Set frame size (e.g. 320x240)");
        supportsOption("frame_rate",        "Set frame rate (e.g. 25)");
        // WARNING:  This option is kept for backwards compatibility only, use out_sample_rate instead!
        supportsOption("audio_sample_rate", "Set audio sampling rate (e.g. 44100)");
        supportsOption("out_sample_format", "Set the output sample format (e.g. AV_SAMPLE_FMT_S16)");
        supportsOption("out_sample_rate",     "Set the output sample rate or frequency in Hz (e.g. 48000)");
        supportsOption("out_nb_channels",   "Set the output number of channels (e.g. 2 for stereo)");
        supportsOption("context",            "AVIOContext* for custom IO");
        supportsOption("mad",            "Max analyze duration (seconds)");
        supportsOption("rtsp_transport", "RTSP transport (udp, tcp, udp_multicast or http)");

        av_log_set_callback(log_to_osg);

#ifdef USE_AV_LOCK_MANAGER
        // enable thread locking
        av_lockmgr_register(&lockMgr);
#endif
        // Register all FFmpeg formats/codecs
        av_register_all();

        avformat_network_init();
    }

    virtual ~ReaderWriterFFmpeg()
    {
    }

    virtual const char * className() const
    {
        return "ReaderWriterFFmpeg";
    }

    virtual ReadResult readImage(const std::string & filename, const osgDB::ReaderWriter::Options* options) const
    {
        const std::string ext = osgDB::getLowerCaseFileExtension(filename);
        const std::string pro = osgDB::getServerProtocol(filename);
        if (!acceptsExtension(ext) && !acceptsProtocol(pro)) return ReadResult::FILE_NOT_HANDLED;

        if (ext=="ffmpeg") return readImage(osgDB::getNameLessExtension(filename),options);

        osg::ref_ptr<osgFFmpeg::FFmpegParameters> parameters(new osgFFmpeg::FFmpegParameters);
        parseOptions(parameters.get(), options);

        if (filename.compare(0, 5, "/dev/")==0)
        {
            return readImageStream(filename, parameters.get());
        }

#if 1
        // NOTE: The original code checks parameters->isFormatAvailable() which returns
        // false when a format is not explicitly specified.
        // In these cases, the extension is used, which is a problem for videos served
        // from URLs without an extension
        {
            ReadResult rr = readImageStream(filename, parameters.get());
            if ( rr.validImage() )
                return rr;
        }
#else
        if (parameters->isFormatAvailable())
        {
            return readImageStream(filename, parameters.get());
        }
#endif

        if (! acceptsExtension(ext))
            return ReadResult::FILE_NOT_HANDLED;

        const std::string path = osgDB::containsServerAddress(filename) ?
            filename :
            osgDB::findDataFile(filename, options);

        if (path.empty())
            return ReadResult::FILE_NOT_FOUND;

        return readImageStream(path, parameters.get());
    }

    ReadResult readImageStream(const std::string& filename, osgFFmpeg::FFmpegParameters* parameters) const
    {
        OSG_INFO << "ReaderWriterFFmpeg::readImage " << filename << std::endl;

        osg::ref_ptr<osgFFmpeg::FFmpegImageStream> image_stream(new osgFFmpeg::FFmpegImageStream);

        if (! image_stream->open(filename, parameters))
            return ReadResult::FILE_NOT_HANDLED;

        return image_stream.release();
    }

private:

    void parseOptions(osgFFmpeg::FFmpegParameters* parameters, const osgDB::ReaderWriter::Options * options) const
    {
        if (options && options->getNumPluginStringData()>0)
        {
            const FormatDescriptionMap& supportedOptList = supportedOptions();
            for (FormatDescriptionMap::const_iterator itr = supportedOptList.begin();
                 itr != supportedOptList.end(); ++itr)
            {
                const std::string& name = itr->first;
                parameters->parse(name, options->getPluginStringData(name));
            }
        }
        if (options && options->getNumPluginData()>0)
        {
            AVIOContext* context = (AVIOContext*)options->getPluginData("context");
            if (context != NULL)
            {
                parameters->setContext(context);
            }
        }
    }

#ifdef USE_AV_LOCK_MANAGER
    static int lockMgr(void **mutex, enum AVLockOp op)
    {
        // returns are 0 success
        OpenThreads::Mutex **m=(OpenThreads::Mutex**)mutex;
        if (op==AV_LOCK_CREATE)
        {
            *m=new OpenThreads::Mutex;
            return !*m;
        }
        else if (op==AV_LOCK_DESTROY)
        {
            delete *m;
            return 0;
        }
        else if (op==AV_LOCK_OBTAIN)
        {
            (*m)->lock();
            return 0;
        }
        else if (op==AV_LOCK_RELEASE)
        {
            (*m)->unlock();
            return 0;
        }
        else
        {
            return -1;
        }
    }
#endif

};

REGISTER_OSGPLUGIN(ffmpeg, ReaderWriterFFmpeg)
<|endoftext|>