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

#include "SamplingReport.h"

#include <absl/container/flat_hash_set.h>
#include <absl/meta/type_traits.h>
#include <absl/strings/str_format.h>

#include <algorithm>
#include <iterator>
#include <optional>

#include "App.h"
#include "ClientData/CallstackInfo.h"
#include "ClientData/CallstackType.h"
#include "ClientData/PostProcessedSamplingData.h"
#include "ClientProtos/capture_data.pb.h"
#include "OrbitBase/Logging.h"

using orbit_client_data::CallstackCount;
using orbit_client_data::CallstackInfo;
using orbit_client_data::CallstackType;
using orbit_client_data::PostProcessedSamplingData;
using orbit_client_data::ThreadID;
using orbit_client_data::ThreadSampleData;

SamplingReport::SamplingReport(
    OrbitApp* app, const orbit_client_data::CallstackData* callstack_data,
    const orbit_client_data::PostProcessedSamplingData* post_processed_sampling_data,
    orbit_metrics_uploader::MetricsUploader* metrics_uploader, bool has_summary)
    : app_{app},
      metrics_uploader_{metrics_uploader},
      callstack_data_{callstack_data},
      post_processed_sampling_data_{post_processed_sampling_data},
      has_summary_{has_summary} {
  ORBIT_SCOPE_FUNCTION;
  ORBIT_SCOPED_TIMED_LOG("SamplingReport::SamplingReport");
  ORBIT_CHECK(callstack_data_ != nullptr);
  ORBIT_CHECK(post_processed_sampling_data_ != nullptr);
  ORBIT_CHECK(app_ != nullptr);
  FillReport();
}

void SamplingReport::ClearReport() {
  selected_sorted_callstack_report_ = nullptr;
  selected_callstack_index_ = 0;
  if (callstack_data_view_ != nullptr) {
    callstack_data_view_->ClearCallstack();
  }
}

const orbit_client_data::CallstackData& SamplingReport::GetCallstackData() const {
  ORBIT_CHECK(callstack_data_ != nullptr);
  return *callstack_data_;
}

[[nodiscard]] std::optional<absl::flat_hash_set<uint64_t>> SamplingReport::GetSelectedCallstackIds()
    const {
  if (!selected_sorted_callstack_report_) return std::nullopt;

  absl::flat_hash_set<uint64_t> result;
  const std::vector<CallstackCount>& selected_callstacks =
      selected_sorted_callstack_report_->callstack_counts;
  std::transform(std::begin(selected_callstacks), std::end(selected_callstacks),
                 std::inserter(result, result.begin()), [](const CallstackCount& callstack_count) {
                   return callstack_count.callstack_id;
                 });

  return result;
}

void SamplingReport::FillReport() {
  const std::vector<const ThreadSampleData*>& sample_data =
      post_processed_sampling_data_->GetSortedThreadSampleData();

  for (const ThreadSampleData* thread_sample_data : sample_data) {
    orbit_data_views::SamplingReportDataView thread_report{app_, metrics_uploader_};
    thread_report.Init();
    thread_report.SetSampledFunctions(thread_sample_data->sampled_functions);
    thread_report.SetThreadID(thread_sample_data->thread_id);
    thread_report.SetStackEventsCount(thread_sample_data->samples_count);
    thread_report.SetSamplingReport(this);
    thread_data_views_.push_back(std::move(thread_report));
  }
}

void SamplingReport::UpdateDisplayedCallstack() {
  if (selected_addresses_.empty()) {
    ClearReport();
    return;
  }

  selected_sorted_callstack_report_ =
      post_processed_sampling_data_->GetSortedCallstackReportFromFunctionAddresses(
          std::vector<uint64_t>(selected_addresses_.begin(), selected_addresses_.end()),
          selected_thread_id_);
  if (selected_sorted_callstack_report_->callstack_counts.empty()) {
    ClearReport();
  } else {
    OnCallstackIndexChanged(selected_callstack_index_);
  }
}

void SamplingReport::UpdateReport(
    const orbit_client_data::CallstackData* callstack_data,
    const orbit_client_data::PostProcessedSamplingData* post_processed_sampling_data) {
  callstack_data_ = callstack_data;
  post_processed_sampling_data_ = post_processed_sampling_data;

  for (orbit_data_views::SamplingReportDataView& thread_report : thread_data_views_) {
    ThreadID thread_id = thread_report.GetThreadID();
    const ThreadSampleData* thread_sample_data =
        post_processed_sampling_data_->GetThreadSampleDataByThreadId(thread_id);
    if (thread_sample_data != nullptr) {
      thread_report.SetSampledFunctions(thread_sample_data->sampled_functions);
    }
  }

  // Refresh the displayed callstacks as they might not be up to date anymore,
  // for example the number of occurrences or of total callstacks might have
  // changed (OrbitSamplingReport::RefreshCallstackView will do the actual
  // update once OrbitApp::FireRefreshCallbacks is called).
  UpdateDisplayedCallstack();
}

void SamplingReport::OnSelectAddresses(const absl::flat_hash_set<uint64_t>& addresses,
                                       ThreadID thread_id) {
  if (callstack_data_view_ != nullptr) {
    if (selected_addresses_ != addresses || selected_thread_id_ != thread_id) {
      selected_addresses_ = addresses;
      selected_thread_id_ = thread_id;
      UpdateDisplayedCallstack();
    }
  }

  if (ui_refresh_func_) {
    ui_refresh_func_();
  }
}

void SamplingReport::IncrementCallstackIndex() {
  ORBIT_CHECK(HasCallstacks());
  size_t max_index = selected_sorted_callstack_report_->callstack_counts.size() - 1;
  if (++selected_callstack_index_ > max_index) {
    selected_callstack_index_ = 0;
  }

  OnCallstackIndexChanged(selected_callstack_index_);
}

void SamplingReport::DecrementCallstackIndex() {
  ORBIT_CHECK(HasCallstacks());
  size_t max_index = selected_sorted_callstack_report_->callstack_counts.size() - 1;
  if (selected_callstack_index_ == 0) {
    selected_callstack_index_ = max_index;
  } else {
    --selected_callstack_index_;
  }

  OnCallstackIndexChanged(selected_callstack_index_);
}

std::string SamplingReport::GetSelectedCallstackString() const {
  if (selected_sorted_callstack_report_ == nullptr) {
    return "Callstacks";
  }

  int num_occurrences =
      selected_sorted_callstack_report_->callstack_counts[selected_callstack_index_].count;
  int total_callstacks = selected_sorted_callstack_report_->total_callstack_count;

  uint64_t callstack_id =
      selected_sorted_callstack_report_->callstack_counts[selected_callstack_index_].callstack_id;
  const CallstackInfo* callstack = callstack_data_->GetCallstack(callstack_id);
  ORBIT_CHECK(callstack != nullptr);
  CallstackType callstack_type = callstack->type();

  std::string type_string =
      (callstack_type == CallstackType::kComplete)
          ? ""
          : absl::StrFormat(
                "  -  Unwind error (%s)",
                orbit_client_data::CallstackTypeToString(callstack_type));
  return absl::StrFormat(
      "%i of %i unique callstacks  [%i/%i total samples] (%.2f%%)%s", selected_callstack_index_ + 1,
      selected_sorted_callstack_report_->callstack_counts.size(), num_occurrences, total_callstacks,
      100.f * num_occurrences / total_callstacks, type_string);
}

double SamplingReport::ComputeUnwindErrorRatio(uint32_t thread_id) const {
  if (post_processed_sampling_data_ == nullptr) {
    return 0.;
  }
  auto* thread_sampling_data =
      post_processed_sampling_data_->GetThreadSampleDataByThreadId(thread_id);
  if (thread_sampling_data == nullptr) {
    return 0.;
  }
  return static_cast<double>(thread_sampling_data->unwinding_errors_count) /
         thread_sampling_data->samples_count;
}

std::string SamplingReport::GetSelectedCallstackTooltipString() const {
  if (selected_sorted_callstack_report_ == nullptr) {
    return "";
  }

  uint64_t callstack_id =
      selected_sorted_callstack_report_->callstack_counts[selected_callstack_index_].callstack_id;
  const CallstackInfo* callstack = callstack_data_->GetCallstack(callstack_id);
  ORBIT_CHECK(callstack != nullptr);
  CallstackType callstack_type = callstack->type();

  if (callstack_type == CallstackType::kComplete) {
    return "";
  }

  return absl::StrFormat("The callstack could not be unwound successfully.
%s",
                         orbit_client_data::CallstackTypeToDescription(callstack_type));
}

void SamplingReport::OnCallstackIndexChanged(size_t index) {
  if (index < selected_sorted_callstack_report_->callstack_counts.size()) {
    const CallstackCount& callstack_count =
        selected_sorted_callstack_report_->callstack_counts[index];
    selected_callstack_index_ = index;
    const CallstackInfo* callstack = callstack_data_->GetCallstack(callstack_count.callstack_id);
    ORBIT_CHECK(callstack != nullptr);
    callstack_data_view_->SetCallstack(*callstack);
    callstack_data_view_->SetFunctionsToHighlight(selected_addresses_);
  } else {
    selected_callstack_index_ = 0;
  }
}
<commit_msg>Update the callstack index when changing the functions (#3693)<commit_after>// Copyright (c) 2020 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "SamplingReport.h"

#include <absl/container/flat_hash_set.h>
#include <absl/meta/type_traits.h>
#include <absl/strings/str_format.h>

#include <algorithm>
#include <iterator>
#include <optional>

#include "App.h"
#include "ClientData/CallstackInfo.h"
#include "ClientData/CallstackType.h"
#include "ClientData/PostProcessedSamplingData.h"
#include "ClientProtos/capture_data.pb.h"
#include "OrbitBase/Logging.h"

using orbit_client_data::CallstackCount;
using orbit_client_data::CallstackInfo;
using orbit_client_data::CallstackType;
using orbit_client_data::PostProcessedSamplingData;
using orbit_client_data::ThreadID;
using orbit_client_data::ThreadSampleData;

SamplingReport::SamplingReport(
    OrbitApp* app, const orbit_client_data::CallstackData* callstack_data,
    const orbit_client_data::PostProcessedSamplingData* post_processed_sampling_data,
    orbit_metrics_uploader::MetricsUploader* metrics_uploader, bool has_summary)
    : app_{app},
      metrics_uploader_{metrics_uploader},
      callstack_data_{callstack_data},
      post_processed_sampling_data_{post_processed_sampling_data},
      has_summary_{has_summary} {
  ORBIT_SCOPE_FUNCTION;
  ORBIT_SCOPED_TIMED_LOG("SamplingReport::SamplingReport");
  ORBIT_CHECK(callstack_data_ != nullptr);
  ORBIT_CHECK(post_processed_sampling_data_ != nullptr);
  ORBIT_CHECK(app_ != nullptr);
  FillReport();
}

void SamplingReport::ClearReport() {
  selected_sorted_callstack_report_ = nullptr;
  selected_callstack_index_ = 0;
  if (callstack_data_view_ != nullptr) {
    callstack_data_view_->ClearCallstack();
  }
}

const orbit_client_data::CallstackData& SamplingReport::GetCallstackData() const {
  ORBIT_CHECK(callstack_data_ != nullptr);
  return *callstack_data_;
}

[[nodiscard]] std::optional<absl::flat_hash_set<uint64_t>> SamplingReport::GetSelectedCallstackIds()
    const {
  if (!selected_sorted_callstack_report_) return std::nullopt;

  absl::flat_hash_set<uint64_t> result;
  const std::vector<CallstackCount>& selected_callstacks =
      selected_sorted_callstack_report_->callstack_counts;
  std::transform(std::begin(selected_callstacks), std::end(selected_callstacks),
                 std::inserter(result, result.begin()), [](const CallstackCount& callstack_count) {
                   return callstack_count.callstack_id;
                 });

  return result;
}

void SamplingReport::FillReport() {
  const std::vector<const ThreadSampleData*>& sample_data =
      post_processed_sampling_data_->GetSortedThreadSampleData();

  for (const ThreadSampleData* thread_sample_data : sample_data) {
    orbit_data_views::SamplingReportDataView thread_report{app_, metrics_uploader_};
    thread_report.Init();
    thread_report.SetSampledFunctions(thread_sample_data->sampled_functions);
    thread_report.SetThreadID(thread_sample_data->thread_id);
    thread_report.SetStackEventsCount(thread_sample_data->samples_count);
    thread_report.SetSamplingReport(this);
    thread_data_views_.push_back(std::move(thread_report));
  }
}

void SamplingReport::UpdateDisplayedCallstack() {
  if (selected_addresses_.empty()) {
    ClearReport();
    return;
  }

  selected_sorted_callstack_report_ =
      post_processed_sampling_data_->GetSortedCallstackReportFromFunctionAddresses(
          std::vector<uint64_t>(selected_addresses_.begin(), selected_addresses_.end()),
          selected_thread_id_);
  if (selected_sorted_callstack_report_->callstack_counts.empty()) {
    ClearReport();
  } else {
    OnCallstackIndexChanged(selected_callstack_index_);
  }
}

void SamplingReport::UpdateReport(
    const orbit_client_data::CallstackData* callstack_data,
    const orbit_client_data::PostProcessedSamplingData* post_processed_sampling_data) {
  callstack_data_ = callstack_data;
  post_processed_sampling_data_ = post_processed_sampling_data;

  for (orbit_data_views::SamplingReportDataView& thread_report : thread_data_views_) {
    ThreadID thread_id = thread_report.GetThreadID();
    const ThreadSampleData* thread_sample_data =
        post_processed_sampling_data_->GetThreadSampleDataByThreadId(thread_id);
    if (thread_sample_data != nullptr) {
      thread_report.SetSampledFunctions(thread_sample_data->sampled_functions);
    }
  }

  // Refresh the displayed callstacks as they might not be up to date anymore,
  // for example the number of occurrences or of total callstacks might have
  // changed (OrbitSamplingReport::RefreshCallstackView will do the actual
  // update once OrbitApp::FireRefreshCallbacks is called).
  UpdateDisplayedCallstack();
}

void SamplingReport::OnSelectAddresses(const absl::flat_hash_set<uint64_t>& addresses,
                                       ThreadID thread_id) {
  if (callstack_data_view_ != nullptr) {
    if (selected_addresses_ != addresses || selected_thread_id_ != thread_id) {
      selected_addresses_ = addresses;
      selected_thread_id_ = thread_id;
      selected_callstack_index_ = 0;
      UpdateDisplayedCallstack();
    }
  }

  if (ui_refresh_func_) {
    ui_refresh_func_();
  }
}

void SamplingReport::IncrementCallstackIndex() {
  ORBIT_CHECK(HasCallstacks());
  size_t max_index = selected_sorted_callstack_report_->callstack_counts.size() - 1;
  if (++selected_callstack_index_ > max_index) {
    selected_callstack_index_ = 0;
  }

  OnCallstackIndexChanged(selected_callstack_index_);
}

void SamplingReport::DecrementCallstackIndex() {
  ORBIT_CHECK(HasCallstacks());
  size_t max_index = selected_sorted_callstack_report_->callstack_counts.size() - 1;
  if (selected_callstack_index_ == 0) {
    selected_callstack_index_ = max_index;
  } else {
    --selected_callstack_index_;
  }

  OnCallstackIndexChanged(selected_callstack_index_);
}

std::string SamplingReport::GetSelectedCallstackString() const {
  if (selected_sorted_callstack_report_ == nullptr) {
    return "Callstacks";
  }

  int num_occurrences =
      selected_sorted_callstack_report_->callstack_counts[selected_callstack_index_].count;
  int total_callstacks = selected_sorted_callstack_report_->total_callstack_count;

  uint64_t callstack_id =
      selected_sorted_callstack_report_->callstack_counts[selected_callstack_index_].callstack_id;
  const CallstackInfo* callstack = callstack_data_->GetCallstack(callstack_id);
  ORBIT_CHECK(callstack != nullptr);
  CallstackType callstack_type = callstack->type();

  std::string type_string =
      (callstack_type == CallstackType::kComplete)
          ? ""
          : absl::StrFormat(
                "  -  Unwind error (%s)",
                orbit_client_data::CallstackTypeToString(callstack_type));
  return absl::StrFormat(
      "%i of %i unique callstacks  [%i/%i total samples] (%.2f%%)%s", selected_callstack_index_ + 1,
      selected_sorted_callstack_report_->callstack_counts.size(), num_occurrences, total_callstacks,
      100.f * num_occurrences / total_callstacks, type_string);
}

double SamplingReport::ComputeUnwindErrorRatio(uint32_t thread_id) const {
  if (post_processed_sampling_data_ == nullptr) {
    return 0.;
  }
  auto* thread_sampling_data =
      post_processed_sampling_data_->GetThreadSampleDataByThreadId(thread_id);
  if (thread_sampling_data == nullptr) {
    return 0.;
  }
  return static_cast<double>(thread_sampling_data->unwinding_errors_count) /
         thread_sampling_data->samples_count;
}

std::string SamplingReport::GetSelectedCallstackTooltipString() const {
  if (selected_sorted_callstack_report_ == nullptr) {
    return "";
  }

  uint64_t callstack_id =
      selected_sorted_callstack_report_->callstack_counts[selected_callstack_index_].callstack_id;
  const CallstackInfo* callstack = callstack_data_->GetCallstack(callstack_id);
  ORBIT_CHECK(callstack != nullptr);
  CallstackType callstack_type = callstack->type();

  if (callstack_type == CallstackType::kComplete) {
    return "";
  }

  return absl::StrFormat("The callstack could not be unwound successfully.
%s",
                         orbit_client_data::CallstackTypeToDescription(callstack_type));
}

void SamplingReport::OnCallstackIndexChanged(size_t index) {
  if (index < selected_sorted_callstack_report_->callstack_counts.size()) {
    const CallstackCount& callstack_count =
        selected_sorted_callstack_report_->callstack_counts[index];
    selected_callstack_index_ = index;
    const CallstackInfo* callstack = callstack_data_->GetCallstack(callstack_count.callstack_id);
    ORBIT_CHECK(callstack != nullptr);
    callstack_data_view_->SetCallstack(*callstack);
    callstack_data_view_->SetFunctionsToHighlight(selected_addresses_);
  } else {
    selected_callstack_index_ = 0;
  }
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 Elviss Strazdins
// This file is part of the Ouzel engine.

#include <rapidjson/rapidjson.h>
#include <rapidjson/filereadstream.h>
#include <rapidjson/document.h>
#include "Sprite.h"
#include "CompileConfig.h"
#include "Engine.h"
#include "Renderer.h"
#include "Texture.h"
#include "Shader.h"
#include "Utils.h"
#include "Camera.h"
#include "SceneManager.h"
#include "FileSystem.h"
#include "File.h"
#include "Layer.h"
#include "Cache.h"

namespace ouzel
{
    std::shared_ptr<Sprite> Sprite::createFromFile(const std::string& filename)
    {
        std::shared_ptr<Sprite> result = std::make_shared<Sprite>();

        if (!result->initFromFile(filename))
        {
            result.reset();
        }

        return result;
    }

    Sprite::Sprite()
    {
    }

    Sprite::~Sprite()
    {

    }

    bool Sprite::initFromFile(const std::string& filename)
    {
        _frameCount = 0;
        _frameVertices.clear();
        _frameMeshBuffers.clear();

        std::string extension = Engine::getInstance()->getFileSystem()->getExtension(filename);

        if (extension == "json")
        {
            if (!loadSpriteSheet(filename))
            {
                return false;
            }
        }
        else
        {
            _texture = Engine::getInstance()->getCache()->getTexture(filename);

            if (!_texture)
            {
                return false;
            }

            _size = _texture->getSize();

            Rectangle rectangle(0, 0, _size.width, _size.height);

            addFrame(rectangle, _size, false, _size, Vector2(), Vector2(0.5f, 0.5f));
        }

        _boundingBox.set(Vector2(-_size.width / 2.0f, -_size.height / 2.0f),
                         Vector2(_size.width / 2.0f, _size.height / 2.0f));
        _boundingRadius = Vector2(_size.width / 2.0f, _size.height / 2.0f).length();

        _shader = Engine::getInstance()->getCache()->getShader(SHADER_TEXTURE);

        if (!_shader)
        {
            return false;
        }

#ifdef OUZEL_PLATFORM_WINDOWS
        _uniModelViewProj = 0;
#else
        _uniModelViewProj = _shader->getVertexShaderConstantId("modelViewProj");
#endif

        return true;
    }

    bool Sprite::loadSpriteSheet(const std::string& filename)
    {
        File file(filename, File::Mode::READ, false);

        if (file)
        {
            rapidjson::FileReadStream is(file.getFile().get(), TEMP_BUFFER, sizeof(TEMP_BUFFER));

            rapidjson::Document document;
            document.ParseStream<0>(is);

            if (document.HasParseError())
            {
                return false;
            }

            const rapidjson::Value& metaObject = document["meta"];
            const rapidjson::Value& sizeObject = metaObject["size"];

            Size2 textureSize(static_cast<float>(sizeObject["w"].GetInt()),
                              static_cast<float>(sizeObject["h"].GetInt()));

            _texture = Engine::getInstance()->getCache()->getTexture(metaObject["image"].GetString());

            const rapidjson::Value& framesArray = document["frames"];

            _frameVertices.reserve(framesArray.Size());
            _frameMeshBuffers.reserve(framesArray.Size());

            for (uint32_t index = 0; index < static_cast<uint32_t>(framesArray.Size()); ++index)
            {
                const rapidjson::Value& frameObject = framesArray[index];

                const rapidjson::Value& rectangleObject = frameObject["frame"];

                Rectangle rectangle(static_cast<float>(rectangleObject["x"].GetInt()),
                                    static_cast<float>(rectangleObject["y"].GetInt()),
                                    static_cast<float>(rectangleObject["w"].GetInt()),
                                    static_cast<float>(rectangleObject["h"].GetInt()));

                bool rotated = frameObject["rotated"].GetBool();

                const rapidjson::Value& sourceSizeObject = frameObject["sourceSize"];

                Size2 sourceSize(static_cast<float>(sourceSizeObject["w"].GetInt()),
                                 static_cast<float>(sourceSizeObject["h"].GetInt()));

                if (sourceSize.width > _size.width) _size.width = sourceSize.width;
                if (sourceSize.height > _size.height) _size.height = sourceSize.height;

                const rapidjson::Value& spriteSourceSizeObject = frameObject["spriteSourceSize"];

                Vector2 offset(static_cast<float>(spriteSourceSizeObject["x"].GetInt()),
                               static_cast<float>(spriteSourceSizeObject["y"].GetInt()));

                const rapidjson::Value& pivotObject = frameObject["pivot"];

                Vector2 pivot(static_cast<float>(pivotObject["x"].GetDouble()),
                              static_cast<float>(pivotObject["y"].GetDouble()));

                addFrame(rectangle, textureSize, rotated, sourceSize, offset, pivot);
            }
        }
        else
        {
            return false;
        }

        return true;
    }

    void Sprite::addFrame(const Rectangle& rectangle, const Size2& textureSize, bool rotated, const Size2& sourceSize, const Vector2& offset, const Vector2& pivot)
    {
        std::vector<uint16_t> indices = {0, 1, 2, 1, 3, 2};

        Vector2 textCoords[4];
        Vector2 realOffset(-sourceSize.width * pivot.x + offset.x,
                           -sourceSize.height * pivot.y + (sourceSize.height - rectangle.height - offset.y));

        if (!rotated)
        {
            Vector2 leftTop(rectangle.x / textureSize.width,
                            rectangle.y / textureSize.height);

            Vector2 rightBottom((rectangle.x + rectangle.width) / textureSize.width,
                                (rectangle.y + rectangle.height) / textureSize.height);

            textCoords[0] = Vector2(leftTop.x, rightBottom.y);
            textCoords[1] = Vector2(rightBottom.x, rightBottom.y);
            textCoords[2] = Vector2(leftTop.x, leftTop.y);
            textCoords[3] = Vector2(rightBottom.x, leftTop.y);
        }
        else
        {
            Vector2 leftTop = Vector2(rectangle.x / textureSize.width,
                                      rectangle.y / textureSize.height);

            Vector2 rightBottom = Vector2((rectangle.x + rectangle.height) / textureSize.width,
                                          (rectangle.y + rectangle.width) / textureSize.height);

            textCoords[0] = Vector2(leftTop.x, leftTop.y);
            textCoords[1] = Vector2(leftTop.x, rightBottom.y);
            textCoords[2] = Vector2(rightBottom.x, leftTop.y);
            textCoords[3] = Vector2(rightBottom.x, rightBottom.y);
        }

        std::vector<VertexPCT> vertices = {
            VertexPCT(Vector3(realOffset.x, realOffset.y, 0.0f), _color, textCoords[0]),
            VertexPCT(Vector3(realOffset.x + rectangle.width, realOffset.y, 0.0f), _color, textCoords[1]),
            VertexPCT(Vector3(realOffset.x, realOffset.y + rectangle.height, 0.0f),  _color, textCoords[2]),
            VertexPCT(Vector3(realOffset.x + rectangle.width, realOffset.y + rectangle.height, 0.0f),  _color, textCoords[3])
        };

        _frameVertices.push_back(vertices);

        _frameMeshBuffers.push_back(Engine::getInstance()->getRenderer()->createMeshBuffer(indices.data(), sizeof(uint16_t),
                                                                                static_cast<uint32_t>(indices.size()), false,
                                                                                vertices.data(), sizeof(VertexPCT),
                                                                                static_cast<uint32_t>(vertices.size()), true,
                                                                                VertexPCT::ATTRIBUTES));

        _frameCount++;
    }

    void Sprite::update(float delta)
    {
        Node::update(delta);

        if (_playing)
        {
            _timeSinceLastFrame += delta;

            while (_timeSinceLastFrame > _frameInterval)
            {
                _timeSinceLastFrame -= _frameInterval;
                _currentFrame++;

                if (_currentFrame >= _frameCount)
                {
                    _currentFrame = 0;

                    if (!_repeat)
                    {
                        _playing = false;
                    }
                }
            }
        }
    }

    void Sprite::draw()
    {
        Node::draw();

        LayerPtr layer = _layer.lock();

        if (_shader && _texture && layer)
        {
            Engine::getInstance()->getRenderer()->activateTexture(_texture, 0);
            Engine::getInstance()->getRenderer()->activateShader(_shader);

            Matrix4 modelViewProj = layer->getProjection() * layer->getCamera()->getTransform() * _transform;

            _shader->setVertexShaderConstant(_uniModelViewProj, { modelViewProj });

            if (_currentFrame < _frameCount)
            {
                MeshBufferPtr meshBuffer = _frameMeshBuffers[_currentFrame];

                Engine::getInstance()->getRenderer()->drawMeshBuffer(meshBuffer);
            }
        }
    }

    void Sprite::setOpacity(float opacity)
    {
        Node::setOpacity(opacity);

        updateVertexColor();
    }

    void Sprite::setTexture(const TexturePtr& texture)
    {
        _texture = texture;
    }

    void Sprite::setShader(const ShaderPtr& shader)
    {
        _shader = shader;
    }

    void Sprite::setColor(const Color& color)
    {
        _color = color;

        updateVertexColor();
    }

    void Sprite::updateVertexColor()
    {
        for (uint32_t i = 0; i < _frameMeshBuffers.size(); ++i)
        {
            for (VertexPCT& vertex : _frameVertices[i])
            {
                vertex.color.r = _color.r;
                vertex.color.g = _color.g;
                vertex.color.b = _color.b;
                vertex.color.a = static_cast<uint8_t>(_opacity * _color.a);
            }

            MeshBufferPtr meshBuffer = _frameMeshBuffers[i];
            meshBuffer->uploadVertices(_frameVertices[i].data(), static_cast<uint32_t>(_frameVertices[i].size()));
        }
    }

    void Sprite::play(bool repeat, float frameInterval)
    {
        _repeat = repeat;
        _frameInterval = frameInterval;
        _playing = true;
    }

    void Sprite::stop(bool resetAnimation)
    {
        _playing = false;

        if (resetAnimation)
        {
            reset();
        }
    }

    void Sprite::reset()
    {
        _currentFrame = 0;
        _timeSinceLastFrame = 0.0f;
    }
}
<commit_msg>Don't reset Sprite's frame if it is not repeating<commit_after>// Copyright (C) 2015 Elviss Strazdins
// This file is part of the Ouzel engine.

#include <rapidjson/rapidjson.h>
#include <rapidjson/filereadstream.h>
#include <rapidjson/document.h>
#include "Sprite.h"
#include "CompileConfig.h"
#include "Engine.h"
#include "Renderer.h"
#include "Texture.h"
#include "Shader.h"
#include "Utils.h"
#include "Camera.h"
#include "SceneManager.h"
#include "FileSystem.h"
#include "File.h"
#include "Layer.h"
#include "Cache.h"

namespace ouzel
{
    std::shared_ptr<Sprite> Sprite::createFromFile(const std::string& filename)
    {
        std::shared_ptr<Sprite> result = std::make_shared<Sprite>();

        if (!result->initFromFile(filename))
        {
            result.reset();
        }

        return result;
    }

    Sprite::Sprite()
    {
    }

    Sprite::~Sprite()
    {

    }

    bool Sprite::initFromFile(const std::string& filename)
    {
        _frameCount = 0;
        _frameVertices.clear();
        _frameMeshBuffers.clear();

        std::string extension = Engine::getInstance()->getFileSystem()->getExtension(filename);

        if (extension == "json")
        {
            if (!loadSpriteSheet(filename))
            {
                return false;
            }
        }
        else
        {
            _texture = Engine::getInstance()->getCache()->getTexture(filename);

            if (!_texture)
            {
                return false;
            }

            _size = _texture->getSize();

            Rectangle rectangle(0, 0, _size.width, _size.height);

            addFrame(rectangle, _size, false, _size, Vector2(), Vector2(0.5f, 0.5f));
        }

        _boundingBox.set(Vector2(-_size.width / 2.0f, -_size.height / 2.0f),
                         Vector2(_size.width / 2.0f, _size.height / 2.0f));
        _boundingRadius = Vector2(_size.width / 2.0f, _size.height / 2.0f).length();

        _shader = Engine::getInstance()->getCache()->getShader(SHADER_TEXTURE);

        if (!_shader)
        {
            return false;
        }

#ifdef OUZEL_PLATFORM_WINDOWS
        _uniModelViewProj = 0;
#else
        _uniModelViewProj = _shader->getVertexShaderConstantId("modelViewProj");
#endif

        return true;
    }

    bool Sprite::loadSpriteSheet(const std::string& filename)
    {
        File file(filename, File::Mode::READ, false);

        if (file)
        {
            rapidjson::FileReadStream is(file.getFile().get(), TEMP_BUFFER, sizeof(TEMP_BUFFER));

            rapidjson::Document document;
            document.ParseStream<0>(is);

            if (document.HasParseError())
            {
                return false;
            }

            const rapidjson::Value& metaObject = document["meta"];
            const rapidjson::Value& sizeObject = metaObject["size"];

            Size2 textureSize(static_cast<float>(sizeObject["w"].GetInt()),
                              static_cast<float>(sizeObject["h"].GetInt()));

            _texture = Engine::getInstance()->getCache()->getTexture(metaObject["image"].GetString());

            const rapidjson::Value& framesArray = document["frames"];

            _frameVertices.reserve(framesArray.Size());
            _frameMeshBuffers.reserve(framesArray.Size());

            for (uint32_t index = 0; index < static_cast<uint32_t>(framesArray.Size()); ++index)
            {
                const rapidjson::Value& frameObject = framesArray[index];

                const rapidjson::Value& rectangleObject = frameObject["frame"];

                Rectangle rectangle(static_cast<float>(rectangleObject["x"].GetInt()),
                                    static_cast<float>(rectangleObject["y"].GetInt()),
                                    static_cast<float>(rectangleObject["w"].GetInt()),
                                    static_cast<float>(rectangleObject["h"].GetInt()));

                bool rotated = frameObject["rotated"].GetBool();

                const rapidjson::Value& sourceSizeObject = frameObject["sourceSize"];

                Size2 sourceSize(static_cast<float>(sourceSizeObject["w"].GetInt()),
                                 static_cast<float>(sourceSizeObject["h"].GetInt()));

                if (sourceSize.width > _size.width) _size.width = sourceSize.width;
                if (sourceSize.height > _size.height) _size.height = sourceSize.height;

                const rapidjson::Value& spriteSourceSizeObject = frameObject["spriteSourceSize"];

                Vector2 offset(static_cast<float>(spriteSourceSizeObject["x"].GetInt()),
                               static_cast<float>(spriteSourceSizeObject["y"].GetInt()));

                const rapidjson::Value& pivotObject = frameObject["pivot"];

                Vector2 pivot(static_cast<float>(pivotObject["x"].GetDouble()),
                              static_cast<float>(pivotObject["y"].GetDouble()));

                addFrame(rectangle, textureSize, rotated, sourceSize, offset, pivot);
            }
        }
        else
        {
            return false;
        }

        return true;
    }

    void Sprite::addFrame(const Rectangle& rectangle, const Size2& textureSize, bool rotated, const Size2& sourceSize, const Vector2& offset, const Vector2& pivot)
    {
        std::vector<uint16_t> indices = {0, 1, 2, 1, 3, 2};

        Vector2 textCoords[4];
        Vector2 realOffset(-sourceSize.width * pivot.x + offset.x,
                           -sourceSize.height * pivot.y + (sourceSize.height - rectangle.height - offset.y));

        if (!rotated)
        {
            Vector2 leftTop(rectangle.x / textureSize.width,
                            rectangle.y / textureSize.height);

            Vector2 rightBottom((rectangle.x + rectangle.width) / textureSize.width,
                                (rectangle.y + rectangle.height) / textureSize.height);

            textCoords[0] = Vector2(leftTop.x, rightBottom.y);
            textCoords[1] = Vector2(rightBottom.x, rightBottom.y);
            textCoords[2] = Vector2(leftTop.x, leftTop.y);
            textCoords[3] = Vector2(rightBottom.x, leftTop.y);
        }
        else
        {
            Vector2 leftTop = Vector2(rectangle.x / textureSize.width,
                                      rectangle.y / textureSize.height);

            Vector2 rightBottom = Vector2((rectangle.x + rectangle.height) / textureSize.width,
                                          (rectangle.y + rectangle.width) / textureSize.height);

            textCoords[0] = Vector2(leftTop.x, leftTop.y);
            textCoords[1] = Vector2(leftTop.x, rightBottom.y);
            textCoords[2] = Vector2(rightBottom.x, leftTop.y);
            textCoords[3] = Vector2(rightBottom.x, rightBottom.y);
        }

        std::vector<VertexPCT> vertices = {
            VertexPCT(Vector3(realOffset.x, realOffset.y, 0.0f), _color, textCoords[0]),
            VertexPCT(Vector3(realOffset.x + rectangle.width, realOffset.y, 0.0f), _color, textCoords[1]),
            VertexPCT(Vector3(realOffset.x, realOffset.y + rectangle.height, 0.0f),  _color, textCoords[2]),
            VertexPCT(Vector3(realOffset.x + rectangle.width, realOffset.y + rectangle.height, 0.0f),  _color, textCoords[3])
        };

        _frameVertices.push_back(vertices);

        _frameMeshBuffers.push_back(Engine::getInstance()->getRenderer()->createMeshBuffer(indices.data(), sizeof(uint16_t),
                                                                                static_cast<uint32_t>(indices.size()), false,
                                                                                vertices.data(), sizeof(VertexPCT),
                                                                                static_cast<uint32_t>(vertices.size()), true,
                                                                                VertexPCT::ATTRIBUTES));

        _frameCount++;
    }

    void Sprite::update(float delta)
    {
        Node::update(delta);

        if (_playing)
        {
            _timeSinceLastFrame += delta;

            while (_timeSinceLastFrame > _frameInterval)
            {
                _timeSinceLastFrame -= _frameInterval;
                _currentFrame++;

                if (_currentFrame >= _frameCount)
                {
                    if (_repeat)
                    {
                        _currentFrame = 0;
                    }
                    else
                    {
                        _playing = false;
                    }
                }
            }
        }
    }

    void Sprite::draw()
    {
        Node::draw();

        LayerPtr layer = _layer.lock();

        if (_shader && _texture && layer)
        {
            Engine::getInstance()->getRenderer()->activateTexture(_texture, 0);
            Engine::getInstance()->getRenderer()->activateShader(_shader);

            Matrix4 modelViewProj = layer->getProjection() * layer->getCamera()->getTransform() * _transform;

            _shader->setVertexShaderConstant(_uniModelViewProj, { modelViewProj });

            if (_currentFrame < _frameCount)
            {
                MeshBufferPtr meshBuffer = _frameMeshBuffers[_currentFrame];

                Engine::getInstance()->getRenderer()->drawMeshBuffer(meshBuffer);
            }
        }
    }

    void Sprite::setOpacity(float opacity)
    {
        Node::setOpacity(opacity);

        updateVertexColor();
    }

    void Sprite::setTexture(const TexturePtr& texture)
    {
        _texture = texture;
    }

    void Sprite::setShader(const ShaderPtr& shader)
    {
        _shader = shader;
    }

    void Sprite::setColor(const Color& color)
    {
        _color = color;

        updateVertexColor();
    }

    void Sprite::updateVertexColor()
    {
        for (uint32_t i = 0; i < _frameMeshBuffers.size(); ++i)
        {
            for (VertexPCT& vertex : _frameVertices[i])
            {
                vertex.color.r = _color.r;
                vertex.color.g = _color.g;
                vertex.color.b = _color.b;
                vertex.color.a = static_cast<uint8_t>(_opacity * _color.a);
            }

            MeshBufferPtr meshBuffer = _frameMeshBuffers[i];
            meshBuffer->uploadVertices(_frameVertices[i].data(), static_cast<uint32_t>(_frameVertices[i].size()));
        }
    }

    void Sprite::play(bool repeat, float frameInterval)
    {
        _repeat = repeat;
        _frameInterval = frameInterval;
        _playing = true;
    }

    void Sprite::stop(bool resetAnimation)
    {
        _playing = false;

        if (resetAnimation)
        {
            reset();
        }
    }

    void Sprite::reset()
    {
        _currentFrame = 0;
        _timeSinceLastFrame = 0.0f;
    }
}
<|endoftext|>


<commit_before>// This file is part of the AliceVision project.
// Copyright (c) 2016 AliceVision contributors.
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

#pragma once

#include <aliceVision/config.hpp>
#include <aliceVision/system/Logger.hpp>

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

#if ALICEVISION_IS_DEFINED(ALICEVISION_HAVE_CUDA)
#include <cuda_runtime.h>
#endif

namespace aliceVision {
namespace system {

/**
 * @brief Check if the system support CUDA with the given parameters
 * @param[in] minComputeCapabilityMajor The minimum compute capability major
 * @param[in] minComputeCapabilityMinor The minimum compute capability minor
 * @param[in] minTotalDeviceMemory The minimum device total memory in MB
 * @return True if system support CUDA with the given parameters
 */
inline bool gpuSupportCUDA(int minComputeCapabilityMajor,
                    int minComputeCapabilityMinor,
                    int minTotalDeviceMemory = 0)
{
#if ALICEVISION_IS_DEFINED(ALICEVISION_HAVE_CUDA)
  int nbDevices = 0;
  cudaGetDeviceCount(&nbDevices);

  if(nbDevices > 0)
  {
    for(int i = 0; i < nbDevices; ++i)
    {
      std::unique_ptr<cudaDeviceProp> deviceProperties(new cudaDeviceProp);
      if(cudaGetDeviceProperties(deviceProperties.get(), i) != cudaSuccess)
        throw std::runtime_error("Cannot get properties for CUDA gpu device " + std::to_string(i));

      if((deviceProperties->major > minComputeCapabilityMajor ||
         (deviceProperties->major == minComputeCapabilityMajor &&
          deviceProperties->minor >= minComputeCapabilityMinor)) &&
         deviceProperties->totalGlobalMem >= (minTotalDeviceMemory*1024*1024))
      {
        ALICEVISION_LOG_INFO("Supported CUDA-Enabled GPU detected.");
        return true;
      }
    }
    ALICEVISION_LOG_INFO("CUDA-Enabled GPU not supported.");
  }
  else
  {
    ALICEVISION_LOG_DEBUG("Can't find CUDA-Enabled GPU.");
  }
#endif
  return false;
}

/**
 * @brief gpuInformationCUDA
 * @return string with all CUDA device(s) information
 */
inline std::string gpuInformationCUDA()
{
  std::string information;
#if ALICEVISION_IS_DEFINED(ALICEVISION_HAVE_CUDA)
  int nbDevices = 0;
  cudaGetDeviceCount(&nbDevices);

  if(nbDevices > 0)
  {
    information = "CUDA-Enabled GPU.\n";
    for(int i = 0; i < nbDevices; ++i)
    {
      std::unique_ptr<cudaDeviceProp> deviceProperties(new cudaDeviceProp);
      if(cudaGetDeviceProperties(deviceProperties.get(), i) != cudaSuccess)
        throw std::runtime_error("Cannot get properties for CUDA gpu device " + std::to_string(i));

      std::stringstream deviceSS;

      deviceSS << "Device information:" << std::endl
               << "\t- id:                      " << i << std::endl
               << "\t- name:                    " << deviceProperties->name << std::endl
               << "\t- compute capability:      " << deviceProperties->major << "." << deviceProperties->minor << std::endl
               << "\t- total device memory:     " << deviceProperties->totalGlobalMem / (1024 * 1024) << " MB " << std::endl
               << "\t- per-block shared memory: " << deviceProperties->sharedMemPerBlock << std::endl
               << "\t- warp size:               " << deviceProperties->warpSize << std::endl
               << "\t- max threads per block:   " << deviceProperties->maxThreadsPerBlock << std::endl
               << "\t- max threads per SM(X):   " << deviceProperties->maxThreadsPerMultiProcessor << std::endl
               << "\t- max block sizes:         "
               << "{" << deviceProperties->maxThreadsDim[0]
               << "," << deviceProperties->maxThreadsDim[1]
               << "," << deviceProperties->maxThreadsDim[2] << "}" << std::endl
               << "\t- max grid sizes:          "
               << "{" << deviceProperties->maxGridSize[0]
               << "," << deviceProperties->maxGridSize[1]
               << "," << deviceProperties->maxGridSize[2] << "}" << std::endl
               << "\t- number of SM(x)s:        " << deviceProperties->multiProcessorCount << std::endl
               << "\t- registers per SM(x):     " << deviceProperties->regsPerMultiprocessor << std::endl
               << "\t- registers per block:     " << deviceProperties->regsPerBlock << std::endl
               << "\t- concurrent kernels:      " << (deviceProperties->concurrentKernels ? "yes":"no") << std::endl
               << "\t- mapping host memory:     " << (deviceProperties->canMapHostMemory ? "yes":"no") << std::endl
               << "\t- unified addressing:      " << (deviceProperties->unifiedAddressing ? "yes":"no") << std::endl
               << "\t- texture alignment:       " << deviceProperties->textureAlignment << " byte" << std::endl
               << "\t- pitch alignment:         " << deviceProperties->texturePitchAlignment << " byte" << std::endl;

      information += deviceSS.str();
    }
  }
#else
  information = "No CUDA-Enabled GPU.";
#endif
  return information;
}

} // namespace system
} // namespace aliceVision
<commit_msg>[system] improve CUDA device property reading<commit_after>// This file is part of the AliceVision project.
// Copyright (c) 2016 AliceVision contributors.
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

#pragma once

#include <aliceVision/config.hpp>
#include <aliceVision/system/Logger.hpp>

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

#if ALICEVISION_IS_DEFINED(ALICEVISION_HAVE_CUDA)
#include <cuda_runtime.h>
#endif

namespace aliceVision {
namespace system {

/**
 * @brief Check if the system support CUDA with the given parameters
 * @param[in] minComputeCapabilityMajor The minimum compute capability major
 * @param[in] minComputeCapabilityMinor The minimum compute capability minor
 * @param[in] minTotalDeviceMemory The minimum device total memory in MB
 * @return True if system support CUDA with the given parameters
 */
inline bool gpuSupportCUDA(int minComputeCapabilityMajor,
                    int minComputeCapabilityMinor,
                    int minTotalDeviceMemory = 0)
{
#if ALICEVISION_IS_DEFINED(ALICEVISION_HAVE_CUDA)
  int nbDevices = 0;
  cudaError_t success;
  success = cudaGetDeviceCount(&nbDevices);
  if( success != cudaSuccess )
  {
    ALICEVISION_LOG_ERROR("cudaGetDeviceCount failed: " << cudaGetErrorString(success));
  }

  if(nbDevices > 0)
  {
    for(int i = 0; i < nbDevices; ++i)
    {
      cudaDeviceProp deviceProperties;

      if(cudaGetDeviceProperties(&deviceProperties, i) != cudaSuccess)
        throw std::runtime_error("Cannot get properties for CUDA gpu device " + std::to_string(i));

      if((deviceProperties.major > minComputeCapabilityMajor ||
         (deviceProperties.major == minComputeCapabilityMajor &&
          deviceProperties.minor >= minComputeCapabilityMinor)) &&
          deviceProperties.totalGlobalMem >= (minTotalDeviceMemory*1024*1024))
      {
        ALICEVISION_LOG_INFO("Supported CUDA-Enabled GPU detected.");
        return true;
      }
      else
      {
        ALICEVISION_LOG_ERROR("CUDA-Enabled GPU detected, but the compute capabilities is not enough.\n"
          << " - Device " << i << ": " << deviceProperties.major << "." << deviceProperties.minor << ", global memory: " << int(deviceProperties.totalGlobalMem / (1024*1024)) << "MB\n"
          << " - Requirements: " << minComputeCapabilityMajor << "." << minComputeCapabilityMinor << ", global memory: " << minTotalDeviceMemory << "MB\n"
          );
      }
    }
    ALICEVISION_LOG_INFO("CUDA-Enabled GPU not supported.");
  }
  else
  {
    ALICEVISION_LOG_INFO("Can't find CUDA-Enabled GPU.");
  }
#endif
  return false;
}

/**
 * @brief gpuInformationCUDA
 * @return string with all CUDA device(s) information
 */
inline std::string gpuInformationCUDA()
{
  std::string information;
#if ALICEVISION_IS_DEFINED(ALICEVISION_HAVE_CUDA)
  int nbDevices = 0;
  if( cudaGetDeviceCount(&nbDevices) != cudaSuccess )
  {
    ALICEVISION_LOG_WARNING( "Could not determine number of CUDA cards in this system" );
    nbDevices = 0;
  }

  if(nbDevices > 0)
  {
    information = "CUDA-Enabled GPU.\n";
    for(int i = 0; i < nbDevices; ++i)
    {
      cudaDeviceProp deviceProperties;
      if(cudaGetDeviceProperties( &deviceProperties, i) != cudaSuccess )
        throw std::runtime_error("Cannot get properties for CUDA gpu device " + std::to_string(i));

      if( cudaSetDevice( i ) != cudaSuccess )
      {
        ALICEVISION_LOG_WARNING( "Device with number " << i << " does not exist" );
        continue;
      }

      std::size_t avail;
      std::size_t total;
      if(cudaMemGetInfo(&avail, &total) != cudaSuccess)
      {
          // if the card does not provide this information.
          avail = 0;
          total = 0;
          ALICEVISION_LOG_WARNING("Cannot get available memory information for CUDA gpu device " << i << ".");
      }
      std::stringstream deviceSS;

      deviceSS << "Device information:" << std::endl
               << "\t- id:                      " << i << std::endl
               << "\t- name:                    " << deviceProperties.name << std::endl
               << "\t- compute capability:      " << deviceProperties.major << "." << deviceProperties.minor << std::endl
               << "\t- total device memory:     " << deviceProperties.totalGlobalMem / (1024 * 1024) << " MB " << std::endl
               << "\t- device memory available: " << avail / (1024 * 1024) << " MB " << std::endl
               << "\t- per-block shared memory: " << deviceProperties.sharedMemPerBlock << std::endl
               << "\t- warp size:               " << deviceProperties.warpSize << std::endl
               << "\t- max threads per block:   " << deviceProperties.maxThreadsPerBlock << std::endl
               << "\t- max threads per SM(X):   " << deviceProperties.maxThreadsPerMultiProcessor << std::endl
               << "\t- max block sizes:         "
               << "{" << deviceProperties.maxThreadsDim[0]
               << "," << deviceProperties.maxThreadsDim[1]
               << "," << deviceProperties.maxThreadsDim[2] << "}" << std::endl
               << "\t- max grid sizes:          "
               << "{" << deviceProperties.maxGridSize[0]
               << "," << deviceProperties.maxGridSize[1]
               << "," << deviceProperties.maxGridSize[2] << "}" << std::endl
               << "\t- max 2D array texture:    "
               << "{" << deviceProperties.maxTexture2D[0]
               << "," << deviceProperties.maxTexture2D[1] << "}" << std::endl
               << "\t- max 3D array texture:    "
               << "{" << deviceProperties.maxTexture3D[0]
               << "," << deviceProperties.maxTexture3D[1]
               << "," << deviceProperties.maxTexture3D[2] << "}" << std::endl
               << "\t- max 2D linear texture:   "
               << "{" << deviceProperties.maxTexture2DLinear[0]
               << "," << deviceProperties.maxTexture2DLinear[1]
               << "," << deviceProperties.maxTexture2DLinear[2] << "}" << std::endl
               << "\t- max 2D layered texture:  "
               << "{" << deviceProperties.maxTexture2DLayered[0]
               << "," << deviceProperties.maxTexture2DLayered[1]
               << "," << deviceProperties.maxTexture2DLayered[2] << "}" << std::endl
               << "\t- number of SM(x)s:        " << deviceProperties.multiProcessorCount << std::endl
               << "\t- registers per SM(x):     " << deviceProperties.regsPerMultiprocessor << std::endl
               << "\t- registers per block:     " << deviceProperties.regsPerBlock << std::endl
               << "\t- concurrent kernels:      " << (deviceProperties.concurrentKernels ? "yes":"no") << std::endl
               << "\t- mapping host memory:     " << (deviceProperties.canMapHostMemory ? "yes":"no") << std::endl
               << "\t- unified addressing:      " << (deviceProperties.unifiedAddressing ? "yes":"no") << std::endl
               << "\t- texture alignment:       " << deviceProperties.textureAlignment << " byte" << std::endl
               << "\t- pitch alignment:         " << deviceProperties.texturePitchAlignment << " byte" << std::endl;

      information += deviceSS.str();
    }
  }
#else
  information = "No CUDA-Enabled GPU.";
#endif
  return information;
}

} // namespace system
} // namespace aliceVision
<|endoftext|>


<commit_before>/*------------------------------------------------------------------------------

    Copyright (c) 2004 Media Development Loan Fund

    This file is part of the LiveSupport project.
    http://livesupport.campware.org/
    To report bugs, send an e-mail to bugs@campware.org

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

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

    You should have received a copy of the GNU General Public License
    along with LiveSupport; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Author   : $Author: fgerlits $
    Version  : $Revision: 1.7 $
    Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/playlistExecutor/src/GstreamerPlayer.cxx,v $

------------------------------------------------------------------------------*/

/* ============================================================ include files */

#ifdef HAVE_CONFIG_H
#include "configure.h"
#endif

#include "LiveSupport/Core/TimeConversion.h"
#include "LiveSupport/GstreamerElements/autoplug.h"
#include "GstreamerPlayer.h"

using namespace boost::posix_time;
using namespace LiveSupport::Core;
using namespace LiveSupport::PlaylistExecutor;

/* ===================================================  local data structures */

/* ================================================  local constants & macros */

/**
 *  The name of the config element for this class
 */
const std::string GstreamerPlayer::configElementNameStr = "gstreamerPlayer";

/**
 *  The name of the audio device attribute.
 */
static const std::string    audioDeviceName = "audioDevice";

/* ===============================================  local function prototypes */

/* =============================================================  module code */

/*------------------------------------------------------------------------------
 *  Configure the Audio Player.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: configure(const xmlpp::Element   &  element)
                                                throw (std::invalid_argument,
                                                       std::logic_error)
{
    if (element.get_name() != configElementNameStr) {
        std::string eMsg = "Bad configuration element ";
        eMsg += element.get_name();
        throw std::invalid_argument(eMsg);
    }

    const xmlpp::Attribute    * attribute;

    if ((attribute = element.get_attribute(audioDeviceName))) {
        audioDevice = attribute->get_value();
    }
}

/*------------------------------------------------------------------------------
 *  Initialize the Audio Player
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: initialize(void)                 throw (std::exception)
{
    if (initialized) {
        return;
    }

    // initialize the gstreamer library
    if (!gst_init_check(0, 0)) {
        throw std::runtime_error("couldn't initialize the gstreamer library");
    }

    // initialize the pipeline
    pipeline   = gst_thread_new("audio-player");
    // take ownership of the pipeline object
    gst_object_ref(GST_OBJECT(pipeline));
    gst_object_sink(GST_OBJECT(pipeline));

    g_signal_connect(pipeline, "error", G_CALLBACK(errorHandler), this);

    setAudioDevice(audioDevice);

    // set up other variables
    initialized = true;
}

/*------------------------------------------------------------------------------
 *  Handler for gstreamer errors.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: errorHandler(GstElement   * pipeline,
                                GstElement   * source,
                                GError       * error,
                                gchar        * debug,
                                gpointer       self)
                                                                throw ()
{
    // TODO: handle error
    std::cerr << "gstreamer error: " << error->message << std::endl;
}

/*------------------------------------------------------------------------------
 *  De-initialize the Gstreamer Player
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: deInitialize(void)                       throw ()
{
    if (initialized) {
        gst_element_set_state(pipeline, GST_STATE_NULL);
        gst_bin_sync_children_state(GST_BIN(pipeline));

        if (!gst_element_get_parent(audiosink)) {
            // delete manually, if audiosink wasn't added to the pipeline
            // for some reason
            gst_object_unref(GST_OBJECT(audiosink));
        }
        gst_object_unref(GST_OBJECT(pipeline));

        initialized = false;
    }
}

/*------------------------------------------------------------------------------
 *  Attach an event listener.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: attachListener(AudioPlayerEventListener*     eventListener)
                                                                    throw ()
{
    listeners.push_back(eventListener);
}

/*------------------------------------------------------------------------------
 *  Detach an event listener.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: detachListener(AudioPlayerEventListener*     eventListener)
                                                throw (std::invalid_argument)
{
    ListenerVector::iterator    it  = listeners.begin();
    ListenerVector::iterator    end = listeners.end();

    while (it != end) {
        if (*it == eventListener) {
            listeners.erase(it);
            return;
        }
        ++it;
    }

    throw std::invalid_argument("supplied event listener not found");
}

/*------------------------------------------------------------------------------
 *  Send the onStop event to all attached listeners.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: fireOnStopEvent(void)                        throw ()
{
    ListenerVector::iterator    it  = listeners.begin();
    ListenerVector::iterator    end = listeners.end();

    while (it != end) {
        (*it)->onStop();
        ++it;
    }
}

/*------------------------------------------------------------------------------
 *  An EOS event handler, that will put the pipeline to EOS as well.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: eosEventHandler(GstElement    * element,
                                   gpointer        self)
                                                                throw ()
{
    GstreamerPlayer   * player = (GstreamerPlayer*) self;

    gst_element_set_eos(player->pipeline);
    player->fireOnStopEvent();
}

/*------------------------------------------------------------------------------
 *  Specify which file to play
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: open(const std::string   fileUrl)
                                                throw (std::invalid_argument)
{
    std::string     filePath;
    GstElement    * pipe;
    GstElement    * fakesink;
    gint64          position;

    if (isOpened()) {
        close();
    }

    if (fileUrl.find("file:") == 0) {
        filePath = fileUrl.substr(5, fileUrl.size());
    } else if (fileUrl.find("file://") == 0) {
        filePath = fileUrl.substr(7, fileUrl.size());
    } else {
        throw std::invalid_argument("badly formed URL or unsupported protocol");
    }

    g_object_ref(G_OBJECT(audiosink));
    gst_bin_remove(GST_BIN(pipeline), audiosink);

    filesrc    = gst_element_factory_make("filesrc", "file-source");
    g_object_set(G_OBJECT(filesrc), "location", filePath.c_str(), NULL);

    decoder = ls_gst_autoplug_plug_source(filesrc, "decoder");

    if (!decoder) {
        throw std::invalid_argument(std::string("can't open URL ") + fileUrl);
    }

    // connect the decoder unto a fakesink, and iterate on it until the
    // first bytes come out. this is to make sure that _really_ all
    // initialiation is done at opening
    pipe     = gst_pipeline_new("pipe");
    fakesink = gst_element_factory_make("fakesink", "fakesink");
    g_object_ref(G_OBJECT(filesrc));
    g_object_ref(G_OBJECT(decoder));
    gst_element_link_many(decoder, fakesink, NULL);
    gst_bin_add_many(GST_BIN(pipe), filesrc, decoder, fakesink, NULL);

    gst_element_set_state(pipe, GST_STATE_PAUSED);
    gst_element_set_state(pipe, GST_STATE_PLAYING);

    position = 0LL;
//    while (position == 0LL && gst_bin_iterate(GST_BIN(pipe))) {
    while (position == 0LL) {
        bool ok;
        try {
//            std::cerr << "before\n";
            ok = gst_bin_iterate(GST_BIN(pipe));
//            std::cerr << "after: " << ok << "\n";
        } catch (...) {
            std::cerr << "exception thrown by gst_bin_iterate()\n";
            std::exit(1);
        }
        if (!ok) {
            break;
        }
        GstFormat   format = GST_FORMAT_DEFAULT;
        gst_element_query(fakesink, GST_QUERY_POSITION, &format, &position);
    }

    gst_element_set_state(pipe, GST_STATE_PAUSED);
    gst_bin_remove_many(GST_BIN(pipe), filesrc, decoder, NULL);
    gst_element_unlink(decoder, fakesink);
    gst_object_unref(GST_OBJECT(pipe));

    // connect the decoder to the real audio sink
    gst_element_link(decoder, audiosink);
    gst_bin_add_many(GST_BIN(pipeline), filesrc, decoder, audiosink, NULL);
    // connect the eos signal handler
    g_signal_connect(decoder, "eos", G_CALLBACK(eosEventHandler), this);

    gst_element_set_state(pipeline, GST_STATE_PAUSED);
    gst_bin_sync_children_state(GST_BIN(pipeline));
}

/*------------------------------------------------------------------------------
 *  Tell if we've been opened.
 *----------------------------------------------------------------------------*/
bool
GstreamerPlayer :: isOpened(void)                               throw ()
{
    return decoder != 0;
}

/*------------------------------------------------------------------------------
 *  Get the length of the current audio clip.
 *----------------------------------------------------------------------------*/
Ptr<time_duration>::Ref
GstreamerPlayer :: getPlaylength(void)                      throw ()
{
    Ptr<time_duration>::Ref   length;
    gint64                    ns;
    GstFormat                 format = GST_FORMAT_TIME;

    if (decoder
     && gst_element_query(decoder, GST_QUERY_TOTAL, &format, &ns)
     && format == GST_FORMAT_TIME) {

        // use microsec, as nanosec() is not found by the compiler (?)
        length.reset(new time_duration(microsec(ns / 1000LL)));
    }

    return length;
}

/*------------------------------------------------------------------------------
 *  Start playing
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: start(void)                      throw (std::logic_error)
{
    if (!isOpened()) {
        throw std::logic_error("GstreamerPlayer not opened yet");
    }

    if (!isPlaying()) {
        gst_element_set_state(audiosink, GST_STATE_PAUSED);
        gst_element_set_state(pipeline, GST_STATE_PLAYING);
    }
}

/*------------------------------------------------------------------------------
 *  Pause the player
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: pause(void)                      throw (std::logic_error)
{
    if (isPlaying()) {
        gst_element_set_state(pipeline, GST_STATE_PAUSED);
    }
}

/*------------------------------------------------------------------------------
 *  Tell if we're playing
 *----------------------------------------------------------------------------*/
bool
GstreamerPlayer :: isPlaying(void)                  throw ()
{
    return gst_element_get_state(pipeline) == GST_STATE_PLAYING;
}

/*------------------------------------------------------------------------------
 *  Stop playing
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: stop(void)                       throw (std::logic_error)
{
    if (!isOpened()) {
        throw std::logic_error("GstreamerPlayer not opened yet");
    }

    if (isPlaying()) {
        gst_element_set_state(pipeline, GST_STATE_READY);
    }
}

/*------------------------------------------------------------------------------
 *  Close the currently opened audio file.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: close(void)                       throw ()
{
    if (isPlaying()) {
        stop();
    }

    gst_element_set_state(pipeline, GST_STATE_NULL);
    gst_element_unlink(filesrc, decoder);
    gst_element_unlink(decoder, audiosink);
    gst_bin_remove(GST_BIN(pipeline), decoder);
    gst_bin_remove(GST_BIN(pipeline), filesrc);
    filesrc = 0;
    decoder = 0;
}

/*------------------------------------------------------------------------------
 *  Get the volume of the player.
 *----------------------------------------------------------------------------*/
unsigned int
GstreamerPlayer :: getVolume(void)                                  throw ()
{
    return 0;
}

/*------------------------------------------------------------------------------
 *  Set the volume of the player.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: setVolume(unsigned int   volume)                 throw ()
{
}

/*------------------------------------------------------------------------------
 *  Set the audio device.
 *----------------------------------------------------------------------------*/
bool
GstreamerPlayer :: setAudioDevice(const std::string &deviceName)
                                                                throw ()
{
    bool    oss    = deviceName.find("/dev") == 0;
    bool    relink = false;

    if (deviceName.size() == 0) {
        return false;
    }

    if (audiosink) {
        bool    oldOss = g_strrstr(gst_element_get_name(audiosink), "osssink");
        relink = oss && !oldOss;
    }

    if (relink && audiosink) {
        if (decoder) {
            gst_element_unlink(decoder, audiosink);
        }
        gst_bin_remove(GST_BIN(pipeline), audiosink);
        // FIXME: why unref here? remove should unref already
        g_object_unref(G_OBJECT(audiosink));
        audiosink = 0;
    }

    if (!audiosink) {
        audiosink = oss
                  ? gst_element_factory_make("osssink", "osssink")
                  : gst_element_factory_make("alsasink", "alsasink");
        relink = true;
    }
    if (!audiosink) {
        return false;
    }

    // it's the same property, "device" for both alsasink and osssink
    g_object_set(G_OBJECT(audiosink), "device", deviceName.c_str(), NULL);

    if (relink) {
        if (decoder) {
            gst_element_link(decoder, audiosink);
        }
        gst_bin_add(GST_BIN(pipeline), audiosink);
    }

    return true;
}

<commit_msg>fixed issue of initializing the GstreamerPlayer after de-Initializing it causing a segfault<commit_after>/*------------------------------------------------------------------------------

    Copyright (c) 2004 Media Development Loan Fund

    This file is part of the LiveSupport project.
    http://livesupport.campware.org/
    To report bugs, send an e-mail to bugs@campware.org

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

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

    You should have received a copy of the GNU General Public License
    along with LiveSupport; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Author   : $Author: maroy $
    Version  : $Revision: 1.8 $
    Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/playlistExecutor/src/GstreamerPlayer.cxx,v $

------------------------------------------------------------------------------*/

/* ============================================================ include files */

#ifdef HAVE_CONFIG_H
#include "configure.h"
#endif

#include "LiveSupport/Core/TimeConversion.h"
#include "LiveSupport/GstreamerElements/autoplug.h"
#include "GstreamerPlayer.h"

using namespace boost::posix_time;
using namespace LiveSupport::Core;
using namespace LiveSupport::PlaylistExecutor;

/* ===================================================  local data structures */

/* ================================================  local constants & macros */

/**
 *  The name of the config element for this class
 */
const std::string GstreamerPlayer::configElementNameStr = "gstreamerPlayer";

/**
 *  The name of the audio device attribute.
 */
static const std::string    audioDeviceName = "audioDevice";

/* ===============================================  local function prototypes */

/* =============================================================  module code */

/*------------------------------------------------------------------------------
 *  Configure the Audio Player.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: configure(const xmlpp::Element   &  element)
                                                throw (std::invalid_argument,
                                                       std::logic_error)
{
    if (element.get_name() != configElementNameStr) {
        std::string eMsg = "Bad configuration element ";
        eMsg += element.get_name();
        throw std::invalid_argument(eMsg);
    }

    const xmlpp::Attribute    * attribute;

    if ((attribute = element.get_attribute(audioDeviceName))) {
        audioDevice = attribute->get_value();
    }
}

/*------------------------------------------------------------------------------
 *  Initialize the Audio Player
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: initialize(void)                 throw (std::exception)
{
    if (initialized) {
        return;
    }

    // initialize the gstreamer library
    if (!gst_init_check(0, 0)) {
        throw std::runtime_error("couldn't initialize the gstreamer library");
    }

    // initialize the pipeline
    pipeline   = gst_thread_new("audio-player");
    // take ownership of the pipeline object
    gst_object_ref(GST_OBJECT(pipeline));
    gst_object_sink(GST_OBJECT(pipeline));

    g_signal_connect(pipeline, "error", G_CALLBACK(errorHandler), this);

    setAudioDevice(audioDevice);

    // set up other variables
    initialized = true;
}

/*------------------------------------------------------------------------------
 *  Handler for gstreamer errors.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: errorHandler(GstElement   * pipeline,
                                GstElement   * source,
                                GError       * error,
                                gchar        * debug,
                                gpointer       self)
                                                                throw ()
{
    // TODO: handle error
    std::cerr << "gstreamer error: " << error->message << std::endl;
}

/*------------------------------------------------------------------------------
 *  De-initialize the Gstreamer Player
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: deInitialize(void)                       throw ()
{
    if (initialized) {
        gst_element_set_state(pipeline, GST_STATE_NULL);
        gst_bin_sync_children_state(GST_BIN(pipeline));

        if (!gst_element_get_parent(audiosink)) {
            // delete manually, if audiosink wasn't added to the pipeline
            // for some reason
            gst_object_unref(GST_OBJECT(audiosink));
        }
        gst_object_unref(GST_OBJECT(pipeline));

        audiosink   = 0;
        initialized = false;
    }
}

/*------------------------------------------------------------------------------
 *  Attach an event listener.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: attachListener(AudioPlayerEventListener*     eventListener)
                                                                    throw ()
{
    listeners.push_back(eventListener);
}

/*------------------------------------------------------------------------------
 *  Detach an event listener.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: detachListener(AudioPlayerEventListener*     eventListener)
                                                throw (std::invalid_argument)
{
    ListenerVector::iterator    it  = listeners.begin();
    ListenerVector::iterator    end = listeners.end();

    while (it != end) {
        if (*it == eventListener) {
            listeners.erase(it);
            return;
        }
        ++it;
    }

    throw std::invalid_argument("supplied event listener not found");
}

/*------------------------------------------------------------------------------
 *  Send the onStop event to all attached listeners.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: fireOnStopEvent(void)                        throw ()
{
    ListenerVector::iterator    it  = listeners.begin();
    ListenerVector::iterator    end = listeners.end();

    while (it != end) {
        (*it)->onStop();
        ++it;
    }
}

/*------------------------------------------------------------------------------
 *  An EOS event handler, that will put the pipeline to EOS as well.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: eosEventHandler(GstElement    * element,
                                   gpointer        self)
                                                                throw ()
{
    GstreamerPlayer   * player = (GstreamerPlayer*) self;

    gst_element_set_eos(player->pipeline);
    player->fireOnStopEvent();
}

/*------------------------------------------------------------------------------
 *  Specify which file to play
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: open(const std::string   fileUrl)
                                                throw (std::invalid_argument)
{
    std::string     filePath;
    GstElement    * pipe;
    GstElement    * fakesink;
    gint64          position;

    if (isOpened()) {
        close();
    }

    if (fileUrl.find("file:") == 0) {
        filePath = fileUrl.substr(5, fileUrl.size());
    } else if (fileUrl.find("file://") == 0) {
        filePath = fileUrl.substr(7, fileUrl.size());
    } else {
        throw std::invalid_argument("badly formed URL or unsupported protocol");
    }

    g_object_ref(G_OBJECT(audiosink));
    gst_bin_remove(GST_BIN(pipeline), audiosink);

    filesrc    = gst_element_factory_make("filesrc", "file-source");
    g_object_set(G_OBJECT(filesrc), "location", filePath.c_str(), NULL);

    decoder = ls_gst_autoplug_plug_source(filesrc, "decoder");

    if (!decoder) {
        throw std::invalid_argument(std::string("can't open URL ") + fileUrl);
    }

    // connect the decoder unto a fakesink, and iterate on it until the
    // first bytes come out. this is to make sure that _really_ all
    // initialiation is done at opening
    pipe     = gst_pipeline_new("pipe");
    fakesink = gst_element_factory_make("fakesink", "fakesink");
    g_object_ref(G_OBJECT(filesrc));
    g_object_ref(G_OBJECT(decoder));
    gst_element_link_many(decoder, fakesink, NULL);
    gst_bin_add_many(GST_BIN(pipe), filesrc, decoder, fakesink, NULL);

    gst_element_set_state(pipe, GST_STATE_PAUSED);
    gst_element_set_state(pipe, GST_STATE_PLAYING);

    position = 0LL;
//    while (position == 0LL && gst_bin_iterate(GST_BIN(pipe))) {
    while (position == 0LL) {
        bool ok;
        try {
//            std::cerr << "before\n";
            ok = gst_bin_iterate(GST_BIN(pipe));
//            std::cerr << "after: " << ok << "\n";
        } catch (...) {
            std::cerr << "exception thrown by gst_bin_iterate()\n";
            std::exit(1);
        }
        if (!ok) {
            break;
        }
        GstFormat   format = GST_FORMAT_DEFAULT;
        gst_element_query(fakesink, GST_QUERY_POSITION, &format, &position);
    }

    gst_element_set_state(pipe, GST_STATE_PAUSED);
    gst_bin_remove_many(GST_BIN(pipe), filesrc, decoder, NULL);
    gst_element_unlink(decoder, fakesink);
    gst_object_unref(GST_OBJECT(pipe));

    // connect the decoder to the real audio sink
    gst_element_link(decoder, audiosink);
    gst_bin_add_many(GST_BIN(pipeline), filesrc, decoder, audiosink, NULL);
    // connect the eos signal handler
    g_signal_connect(decoder, "eos", G_CALLBACK(eosEventHandler), this);

    gst_element_set_state(pipeline, GST_STATE_PAUSED);
    gst_bin_sync_children_state(GST_BIN(pipeline));
}

/*------------------------------------------------------------------------------
 *  Tell if we've been opened.
 *----------------------------------------------------------------------------*/
bool
GstreamerPlayer :: isOpened(void)                               throw ()
{
    return decoder != 0;
}

/*------------------------------------------------------------------------------
 *  Get the length of the current audio clip.
 *----------------------------------------------------------------------------*/
Ptr<time_duration>::Ref
GstreamerPlayer :: getPlaylength(void)                      throw ()
{
    Ptr<time_duration>::Ref   length;
    gint64                    ns;
    GstFormat                 format = GST_FORMAT_TIME;

    if (decoder
     && gst_element_query(decoder, GST_QUERY_TOTAL, &format, &ns)
     && format == GST_FORMAT_TIME) {

        // use microsec, as nanosec() is not found by the compiler (?)
        length.reset(new time_duration(microsec(ns / 1000LL)));
    }

    return length;
}

/*------------------------------------------------------------------------------
 *  Start playing
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: start(void)                      throw (std::logic_error)
{
    if (!isOpened()) {
        throw std::logic_error("GstreamerPlayer not opened yet");
    }

    if (!isPlaying()) {
        gst_element_set_state(audiosink, GST_STATE_PAUSED);
        gst_element_set_state(pipeline, GST_STATE_PLAYING);
    }
}

/*------------------------------------------------------------------------------
 *  Pause the player
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: pause(void)                      throw (std::logic_error)
{
    if (isPlaying()) {
        gst_element_set_state(pipeline, GST_STATE_PAUSED);
    }
}

/*------------------------------------------------------------------------------
 *  Tell if we're playing
 *----------------------------------------------------------------------------*/
bool
GstreamerPlayer :: isPlaying(void)                  throw ()
{
    return gst_element_get_state(pipeline) == GST_STATE_PLAYING;
}

/*------------------------------------------------------------------------------
 *  Stop playing
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: stop(void)                       throw (std::logic_error)
{
    if (!isOpened()) {
        throw std::logic_error("GstreamerPlayer not opened yet");
    }

    if (isPlaying()) {
        gst_element_set_state(pipeline, GST_STATE_READY);
    }
}

/*------------------------------------------------------------------------------
 *  Close the currently opened audio file.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: close(void)                       throw ()
{
    if (isPlaying()) {
        stop();
    }

    gst_element_set_state(pipeline, GST_STATE_NULL);
    gst_element_unlink(filesrc, decoder);
    gst_element_unlink(decoder, audiosink);
    gst_bin_remove(GST_BIN(pipeline), decoder);
    gst_bin_remove(GST_BIN(pipeline), filesrc);
    filesrc = 0;
    decoder = 0;
}

/*------------------------------------------------------------------------------
 *  Get the volume of the player.
 *----------------------------------------------------------------------------*/
unsigned int
GstreamerPlayer :: getVolume(void)                                  throw ()
{
    return 0;
}

/*------------------------------------------------------------------------------
 *  Set the volume of the player.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: setVolume(unsigned int   volume)                 throw ()
{
}

/*------------------------------------------------------------------------------
 *  Set the audio device.
 *----------------------------------------------------------------------------*/
bool
GstreamerPlayer :: setAudioDevice(const std::string &deviceName)
                                                                throw ()
{
    bool    oss    = deviceName.find("/dev") == 0;
    bool    relink = false;

    if (deviceName.size() == 0) {
        return false;
    }

    if (audiosink) {
        bool    oldOss = g_strrstr(gst_element_get_name(audiosink), "osssink");
        relink = oss && !oldOss;
    }

    if (relink && audiosink) {
        if (decoder) {
            gst_element_unlink(decoder, audiosink);
        }
        gst_bin_remove(GST_BIN(pipeline), audiosink);
        // FIXME: why unref here? remove should unref already
        g_object_unref(G_OBJECT(audiosink));
        audiosink = 0;
    }

    if (!audiosink) {
        audiosink = oss
                  ? gst_element_factory_make("osssink", "osssink")
                  : gst_element_factory_make("alsasink", "alsasink");
        relink = true;
    }
    if (!audiosink) {
        return false;
    }

    // it's the same property, "device" for both alsasink and osssink
    g_object_set(G_OBJECT(audiosink), "device", deviceName.c_str(), NULL);

    if (relink) {
        if (decoder) {
            gst_element_link(decoder, audiosink);
        }
        gst_bin_add(GST_BIN(pipeline), audiosink);
    }

    return true;
}

<|endoftext|>


<commit_before>//----------------------------  petsc_01.cc  ---------------------------
//    petsc_01.cc,v 1.4 2003/07/03 10:31:46 guido Exp
//    Version:
//
//    Copyright (C) 2004 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  petsc_01.cc  ---------------------------

// check setting elements in a petsc matrix using
// petsc_wrappers::SparseMatrix::set()

#include "../tests.h"
#include <lac/petsc_sparse_matrix.h>
#include <fstream>
#include <iostream>

void test (petsc_wrappers::SparseMatrix &m)
{
                                   // first set a few entries
  for (unsigned int i=0; i<m.m(); ++i)
    for (unsigned int j=0; j<m.m(); ++j)
      if ((i+2*j+1) % 3 == 0)
        m.set (i,j, i*j*.5+.5);

  m.compress ();

                                   // then make sure we retrieve the same ones
  for (unsigned int i=0; i<m.m(); ++i)
    for (unsigned int j=0; j<m.m(); ++j)
      if ((i+2*j+1) % 3 == 0)
        {
          Assert (m(i,j) == i*j*.5+.5, ExcInternalError());
          Assert (m.el(i,j) == i*j*.5+.5, ExcInternalError());
        }
      else
        {
          Assert (m(i,j) == 0, ExcInternalError());
          Assert (m.el(i,j) == 0, ExcInternalError());
        }

  deallog << "OK" << std::endl;
}

int main (int argc,char **argv)
{
  std::ofstream logfile("petsc_01.output");
  deallog.attach(logfile);
  deallog.depth_console(0);

  try
    {
      PetscInitialize(&argc,&argv,0,0);
      {
        petsc_wrappers::SparseMatrix m (5,5,3);
        test (m);
      }
      PetscFinalize();
    }
  catch (std::exception &exc)
    {
      std::cerr << std::endl << std::endl
		<< "----------------------------------------------------"
		<< std::endl;
      std::cerr << "Exception on processing: " << std::endl
		<< exc.what() << std::endl
		<< "Aborting!" << std::endl
		<< "----------------------------------------------------"
		<< std::endl;

      return 1;
    }
  catch (...)
    {
      std::cerr << std::endl << std::endl
		<< "----------------------------------------------------"
		<< std::endl;
      std::cerr << "Unknown exception!" << std::endl
		<< "Aborting!" << std::endl
		<< "----------------------------------------------------"
		<< std::endl;
      return 1;
    };
}
<commit_msg>Fix cvs tag<commit_after>//----------------------------  petsc_01.cc  ---------------------------
//    $Id$
//    Version:
//
//    Copyright (C) 2004 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  petsc_01.cc  ---------------------------

// check setting elements in a petsc matrix using
// petsc_wrappers::SparseMatrix::set()

#include "../tests.h"
#include <lac/petsc_sparse_matrix.h>
#include <fstream>
#include <iostream>

void test (petsc_wrappers::SparseMatrix &m)
{
                                   // first set a few entries
  for (unsigned int i=0; i<m.m(); ++i)
    for (unsigned int j=0; j<m.m(); ++j)
      if ((i+2*j+1) % 3 == 0)
        m.set (i,j, i*j*.5+.5);

  m.compress ();

                                   // then make sure we retrieve the same ones
  for (unsigned int i=0; i<m.m(); ++i)
    for (unsigned int j=0; j<m.m(); ++j)
      if ((i+2*j+1) % 3 == 0)
        {
          Assert (m(i,j) == i*j*.5+.5, ExcInternalError());
          Assert (m.el(i,j) == i*j*.5+.5, ExcInternalError());
        }
      else
        {
          Assert (m(i,j) == 0, ExcInternalError());
          Assert (m.el(i,j) == 0, ExcInternalError());
        }

  deallog << "OK" << std::endl;
}

int main (int argc,char **argv)
{
  std::ofstream logfile("petsc_01.output");
  deallog.attach(logfile);
  deallog.depth_console(0);

  try
    {
      PetscInitialize(&argc,&argv,0,0);
      {
        petsc_wrappers::SparseMatrix m (5,5,3);
        test (m);
      }
      PetscFinalize();
    }
  catch (std::exception &exc)
    {
      std::cerr << std::endl << std::endl
		<< "----------------------------------------------------"
		<< std::endl;
      std::cerr << "Exception on processing: " << std::endl
		<< exc.what() << std::endl
		<< "Aborting!" << std::endl
		<< "----------------------------------------------------"
		<< std::endl;

      return 1;
    }
  catch (...)
    {
      std::cerr << std::endl << std::endl
		<< "----------------------------------------------------"
		<< std::endl;
      std::cerr << "Unknown exception!" << std::endl
		<< "Aborting!" << std::endl
		<< "----------------------------------------------------"
		<< std::endl;
      return 1;
    };
}
<|endoftext|>