MYNT-EYE-S-SDK/src/mynteye/device/streams.cc

233 lines
7.5 KiB
C++
Raw Normal View History

2018-05-10 09:46:34 +03:00
// Copyright 2018 Slightech Co., Ltd. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2018-10-27 16:24:04 +03:00
#include "mynteye/device/streams.h"
2018-04-08 07:23:33 +03:00
#include <algorithm>
2018-04-08 17:35:49 +03:00
#include <chrono>
2018-04-11 12:08:24 +03:00
#include <stdexcept>
2018-04-08 20:20:00 +03:00
2018-11-16 10:30:13 +02:00
#include "mynteye/logger.h"
2018-10-27 16:24:04 +03:00
#include "mynteye/device/types.h"
2018-04-08 07:23:33 +03:00
MYNTEYE_BEGIN_NAMESPACE
Streams::Streams(const std::shared_ptr<StreamsAdapter> &adapter)
: key_streams_(std::move(adapter->GetKeyStreams())),
stream_capabilities_(std::move(adapter->GetStreamCapabilities())),
unpack_img_data_map_(std::move(adapter->GetUnpackImgDataMap())),
unpack_img_pixels_map_(std::move(adapter->GetUnpackImgPixelsMap())) {
2018-04-08 07:23:33 +03:00
VLOG(2) << __func__;
}
Streams::~Streams() {
VLOG(2) << __func__;
}
void Streams::ConfigStream(
const Capabilities &capability, const StreamRequest &request) {
if (!IsStreamCapability(capability)) {
2018-05-30 07:31:54 +03:00
LOG(ERROR) << "Cannot config stream without stream capability";
return;
2018-04-08 07:23:33 +03:00
}
2018-04-08 17:35:49 +03:00
VLOG(2) << "Config stream request of " << capability << ", " << request;
2018-04-08 07:23:33 +03:00
stream_config_requests_[capability] = request;
}
2018-05-31 05:20:48 +03:00
bool Streams::PushStream(const Capabilities &capability, const void *data) {
2018-04-08 07:23:33 +03:00
if (!HasStreamConfigRequest(capability)) {
LOG(FATAL) << "Cannot push stream without stream config request";
}
2018-04-08 17:35:49 +03:00
std::unique_lock<std::mutex> lock(mtx_);
auto &&request = GetStreamConfigRequest(capability);
2018-05-31 05:20:48 +03:00
bool pushed = false;
2018-04-08 17:35:49 +03:00
switch (capability) {
case Capabilities::STEREO:
case Capabilities::STEREO_COLOR: {
2018-04-11 12:08:24 +03:00
// alloc left
AllocStreamData(capability, Stream::LEFT, request);
2018-04-08 17:35:49 +03:00
auto &&left_data = stream_datas_map_[Stream::LEFT].back();
// unpack img data
2018-04-10 11:19:28 +03:00
if (unpack_img_data_map_[Stream::LEFT](
data, request, left_data.img.get())) {
2018-10-26 10:39:34 +03:00
left_data.frame_id = left_data.img->frame_id;
2018-04-11 12:08:24 +03:00
// alloc right
AllocStreamData(capability, Stream::RIGHT, request);
2018-04-11 12:08:24 +03:00
auto &&right_data = stream_datas_map_[Stream::RIGHT].back();
*right_data.img = *left_data.img;
2018-10-26 10:39:34 +03:00
right_data.frame_id = left_data.img->frame_id;
2018-04-11 12:08:24 +03:00
// unpack frame
unpack_img_pixels_map_[Stream::LEFT](
data, request, left_data.frame.get());
unpack_img_pixels_map_[Stream::RIGHT](
data, request, right_data.frame.get());
2018-05-31 05:20:48 +03:00
pushed = true;
2018-04-09 04:24:08 +03:00
} else {
2018-04-11 12:08:24 +03:00
// discard left
DiscardStreamData(Stream::LEFT);
VLOG(2) << "Image packet is unaccepted, frame dropped";
2018-05-31 05:20:48 +03:00
pushed = false;
2018-04-09 04:24:08 +03:00
}
2018-04-08 17:35:49 +03:00
} break;
default:
LOG(FATAL) << "Not supported " << capability << " now";
}
if (HasKeyStreamDatas())
cv_.notify_one();
2018-05-31 05:20:48 +03:00
return pushed;
2018-04-08 17:35:49 +03:00
}
void Streams::WaitForStreams() {
std::unique_lock<std::mutex> lock(mtx_);
auto ready = std::bind(&Streams::HasKeyStreamDatas, this);
if (!ready() && !cv_.wait_for(lock, std::chrono::seconds(2), ready)) {
2018-05-30 07:31:54 +03:00
LOG(FATAL) << "Timeout waiting for key frames. Please use USB 3.0, and not "
"in virtual machine.";
2018-04-08 17:35:49 +03:00
}
}
2018-04-12 04:54:54 +03:00
void Streams::ConfigStreamLimits(
const Stream &stream, std::size_t max_data_size) {
CHECK_GT(max_data_size, 0);
stream_limits_map_[stream] = max_data_size;
}
std::size_t Streams::GetStreamDataMaxSize(const Stream &stream) const {
try {
return stream_limits_map_.at(stream);
} catch (const std::out_of_range &e) {
return 4; // default stream data max size
}
}
2018-04-08 17:35:49 +03:00
Streams::stream_datas_t Streams::GetStreamDatas(const Stream &stream) {
2018-04-08 20:20:00 +03:00
std::unique_lock<std::mutex> lock(mtx_);
2018-05-31 18:41:32 +03:00
if (!HasStreamDatas(stream)) {
2018-05-30 17:15:50 +03:00
LOG(WARNING) << "There are no stream datas of " << stream
<< ". Did you call WaitForStreams() before this?";
2018-04-08 17:35:49 +03:00
return {};
}
2018-05-31 18:41:32 +03:00
auto datas = stream_datas_map_.at(stream);
2018-04-08 17:35:49 +03:00
stream_datas_map_[stream].clear();
return datas;
}
Streams::stream_data_t Streams::GetLatestStreamData(const Stream &stream) {
2018-05-31 05:20:48 +03:00
std::unique_lock<std::mutex> lock(mtx_);
2018-05-31 18:41:32 +03:00
if (!HasStreamDatas(stream)) {
2018-05-31 05:20:48 +03:00
LOG(WARNING) << "There are no stream datas of " << stream
<< ". Did you call WaitForStreams() before this?";
return {};
}
2018-05-31 18:41:32 +03:00
auto data = stream_datas_map_.at(stream).back();
2018-05-31 05:20:48 +03:00
stream_datas_map_[stream].clear();
2018-05-31 18:41:32 +03:00
return data;
2018-04-08 17:35:49 +03:00
}
2018-04-11 12:08:24 +03:00
const Streams::stream_datas_t &Streams::stream_datas(const Stream &stream) {
2018-05-31 05:20:48 +03:00
std::unique_lock<std::mutex> lock(mtx_);
2018-04-11 12:08:24 +03:00
try {
return stream_datas_map_.at(stream);
} catch (const std::out_of_range &e) {
// Add empty vector of this stream key
stream_datas_map_[stream] = {};
return stream_datas_map_.at(stream);
}
2018-04-08 07:23:33 +03:00
}
bool Streams::IsStreamCapability(const Capabilities &capability) const {
return std::find(
stream_capabilities_.begin(), stream_capabilities_.end(),
capability) != stream_capabilities_.end();
}
bool Streams::HasStreamConfigRequest(const Capabilities &capability) const {
return stream_config_requests_.find(capability) !=
stream_config_requests_.end();
}
const StreamRequest &Streams::GetStreamConfigRequest(
const Capabilities &capability) const {
return stream_config_requests_.at(capability);
}
bool Streams::HasStreamDatas(const Stream &stream) const {
2018-05-31 18:41:32 +03:00
return stream_datas_map_.find(stream) != stream_datas_map_.end() &&
!stream_datas_map_.at(stream).empty();
2018-04-08 07:23:33 +03:00
}
void Streams::AllocStreamData(const Capabilities &capability,
2018-04-08 17:35:49 +03:00
const Stream &stream, const StreamRequest &request) {
auto format = request.format;
if (capability == Capabilities::STEREO) {
format = Format::GREY;
}
AllocStreamData(capability, stream, request, format);
2018-04-08 17:35:49 +03:00
}
void Streams::AllocStreamData(const Capabilities &capability,
2018-04-08 17:35:49 +03:00
const Stream &stream, const StreamRequest &request, const Format &format) {
stream_data_t data;
2018-06-01 10:09:03 +03:00
2018-05-31 18:41:32 +03:00
if (HasStreamDatas(stream)) {
// If cached equal to limits_max, drop the oldest one.
if (stream_datas_map_.at(stream).size() == GetStreamDataMaxSize(stream)) {
auto &&datas = stream_datas_map_[stream];
2018-06-01 10:09:03 +03:00
// reuse the dropped data
data.img = datas.front().img;
data.frame = datas.front().frame;
2018-10-26 10:39:34 +03:00
data.frame_id = 0;
2018-05-31 18:41:32 +03:00
datas.erase(datas.begin());
VLOG(2) << "Stream data of " << stream << " is dropped as out of limits";
}
}
2018-06-01 10:09:03 +03:00
if (stream == Stream::LEFT || stream == Stream::RIGHT) {
if (!data.img) {
2018-06-01 10:09:03 +03:00
data.img = std::make_shared<ImgData>();
}
} else {
data.img = nullptr;
}
2018-05-31 18:41:32 +03:00
if (!data.frame) {
auto width = request.width;
if (capability == Capabilities::STEREO_COLOR) {
width /= 2; // split to half
}
2018-08-05 21:23:27 +03:00
data.frame =
std::make_shared<frame_t>(width, request.height, format, nullptr);
2018-04-08 17:35:49 +03:00
}
2018-10-26 10:39:34 +03:00
data.frame_id = 0;
2018-05-31 18:41:32 +03:00
stream_datas_map_[stream].push_back(data);
2018-04-08 17:35:49 +03:00
}
2018-04-11 12:08:24 +03:00
void Streams::DiscardStreamData(const Stream &stream) {
// Must discard after alloc, otherwise at will out of range when no this key.
if (stream_datas_map_.at(stream).size() > 0) {
auto &&datas = stream_datas_map_[stream];
2018-05-31 18:41:32 +03:00
datas.pop_back();
2018-04-11 12:08:24 +03:00
} else {
VLOG(2) << "Stream data of " << stream << " is empty, could not discard";
}
}
2018-04-08 17:35:49 +03:00
bool Streams::HasKeyStreamDatas() const {
for (auto &&s : key_streams_) {
if (!HasStreamDatas(s))
return false;
}
return true;
2018-04-08 07:23:33 +03:00
}
MYNTEYE_END_NAMESPACE