Skip to content

Commit

Permalink
Merge pull request #234 from OSVR/wip_imaging_merge
Browse files Browse the repository at this point in the history
imaging merge (in-process memory image message and jni bridge code)
  • Loading branch information
JeroMiya committed Oct 13, 2015
2 parents d9e05ed + ca21719 commit 4c48e60
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 1 deletion.
28 changes: 28 additions & 0 deletions inc/osvr/Common/ImagingComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <osvr/Util/ChannelCountC.h>
#include <osvr/Util/ImagingReportTypesC.h>
#include <osvr/Common/IPCRingBuffer.h>
#include <osvr/Common/ImagingComponentConfig.h>

// Library/third-party includes
#include <vrpn_BaseClass.h>
Expand All @@ -54,6 +55,14 @@ namespace common {

static const char *identifier();
};
#ifdef OSVR_COMMON_IN_PROCESS_IMAGING
class ImagePlacedInProcessMemory
: public MessageRegistration<ImagePlacedInProcessMemory> {
public:
class MessageSerialization;
static const char *identifier();
};
#endif
class ImagePlacedInSharedMemory
: public MessageRegistration<ImagePlacedInSharedMemory> {
public:
Expand All @@ -79,6 +88,12 @@ namespace common {
/// shared memory ring buffer.
messages::ImagePlacedInSharedMemory imagePlacedInSharedMemory;

#ifdef OSVR_COMMON_IN_PROCESS_IMAGING
/// @brief Message from server to client, notifying of image data in process
/// memory (assumes joint client kit)
messages::ImagePlacedInProcessMemory imagePlacedInProcessMemory;
#endif

OSVR_COMMON_EXPORT void sendImageData(
OSVR_ImagingMetadata metadata, OSVR_ImageBufferElement *imageData,
OSVR_ChannelCount sensor, OSVR_TimeValue const &timestamp);
Expand All @@ -103,12 +118,25 @@ namespace common {
OSVR_ChannelCount sensor,
OSVR_TimeValue const &timestamp);

#ifdef OSVR_COMMON_IN_PROCESS_IMAGING
/// @return true if we could send it.
bool m_sendImageDataViaInProcessMemory(OSVR_ImagingMetadata metadata,
OSVR_ImageBufferElement *imageData,
OSVR_ChannelCount sensor,
OSVR_TimeValue const &timestamp);
#endif

static int VRPN_CALLBACK
m_handleImageRegion(void *userdata, vrpn_HANDLERPARAM p);

static int VRPN_CALLBACK
m_handleImagePlacedInSharedMemory(void *userdata, vrpn_HANDLERPARAM p);

#ifdef OSVR_COMMON_IN_PROCESS_IMAGING
static int VRPN_CALLBACK
m_handleImagePlacedInProcessMemory(void *userdata, vrpn_HANDLERPARAM p);
#endif

void m_checkFirst(OSVR_ImagingMetadata const &metadata);
void m_growShmVecIfRequired(OSVR_ChannelCount sensor);

Expand Down
6 changes: 6 additions & 0 deletions src/osvr/Common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,13 @@ if(BUILD_WITH_TRACING)
endif()
endif()

option(OSVR_COMMON_IN_PROCESS_IMAGING "Option to switch from shared-memory imaging messages to use only in-process memory messages. Requires single-process client/server." OFF)

mark_as_advanced(OSVR_COMMON_IN_PROCESS_IMAGING)

configure_file(TracingConfig.h.cmake_in "${CMAKE_CURRENT_BINARY_DIR}/TracingConfig.h")

configure_file(ImagingComponentConfig.h.cmake_in "${CMAKE_CURRENT_BINARY_DIR}/ImagingComponentConfig.h")

set(API
"${HEADER_LOCATION}/AddDevice.h"
Expand Down Expand Up @@ -58,6 +63,7 @@ set(API
"${HEADER_LOCATION}/GeneralizedTransform.h"
"${HEADER_LOCATION}/GetEnvironmentVariable.h"
"${HEADER_LOCATION}/ImagingComponent.h"
"${CMAKE_CURRENT_BINARY_DIR}/ImagingComponentConfig.h"
"${HEADER_LOCATION}/IntegerByteSwap.h"
"${HEADER_LOCATION}/InterfaceCallbacks.h"
"${HEADER_LOCATION}/InterfaceList.h"
Expand Down
101 changes: 101 additions & 0 deletions src/osvr/Common/ImagingComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,47 @@ namespace common {
return "com.osvr.imaging.imageregion";
}

#ifdef OSVR_COMMON_IN_PROCESS_IMAGING
namespace {
struct InProcessMemoryMessage {
OSVR_ImagingMetadata metadata;
OSVR_ChannelCount sensor;
int buffer;
};
template <typename T>
void process(InProcessMemoryMessage &ipmmMsg, T &p) {
process(ipmmMsg.metadata, p);
p(ipmmMsg.sensor);
p(ipmmMsg.buffer);
}
} // namespace

const char *ImagePlacedInProcessMemory::identifier() {
return "com.osvr.imaging.imageplacedinprocessmemory";
}

class ImagePlacedInProcessMemory::MessageSerialization {
public:
MessageSerialization() {}
explicit MessageSerialization(InProcessMemoryMessage &&msg)
: m_msgData(std::move(msg)) {}

#if defined(_MSC_VER) && defined(_PREFAST_)
// @todo workaround for apparent bug in VS2013 /analyze
explicit MessageSerialization(InProcessMemoryMessage const &msg)
: m_msgData(msg) { }
#endif
template <typename T> void processMessage(T &p) {
process(m_msgData, p);
}

InProcessMemoryMessage const &getMessage() { return m_msgData; }

private:
InProcessMemoryMessage m_msgData;
};
#endif

namespace {
struct SharedMemoryMessage {
OSVR_ImagingMetadata metadata;
Expand Down Expand Up @@ -169,15 +210,42 @@ namespace common {
OSVR_TimeValue const &timestamp) {

util::Flag dataSent;

#ifdef OSVR_COMMON_IN_PROCESS_IMAGING
dataSent +=
m_sendImageDataViaInProcessMemory(metadata, imageData, sensor, timestamp);
#else
dataSent += m_sendImageDataViaSharedMemory(metadata, imageData, sensor,
timestamp);
#endif
dataSent +=
m_sendImageDataOnTheWire(metadata, imageData, sensor, timestamp);
if (dataSent) {
m_checkFirst(metadata);
}
}

#ifdef OSVR_COMMON_IN_PROCESS_IMAGING
bool ImagingComponent::m_sendImageDataViaInProcessMemory(
OSVR_ImagingMetadata metadata, OSVR_ImageBufferElement *imageData,
OSVR_ChannelCount sensor, OSVR_TimeValue const &timestamp) {

auto imageBufferSize = getBufferSize(metadata);
auto imageBufferCopy = reinterpret_cast<OSVR_ImageBufferElement*>(cv::fastMalloc(imageBufferSize));
memcpy(imageBufferCopy, imageData, imageBufferSize);

Buffer<> buf;
messages::ImagePlacedInProcessMemory::MessageSerialization serialization(
messages::InProcessMemoryMessage{ metadata, sensor, reinterpret_cast<int>(imageBufferCopy) });

serialize(buf, serialization);
m_getParent().packMessage(
buf, imagePlacedInProcessMemory.getMessageType(), timestamp);

return true;
}
#endif

bool ImagingComponent::m_sendImageDataViaSharedMemory(
OSVR_ImagingMetadata metadata, OSVR_ImageBufferElement *imageData,
OSVR_ChannelCount sensor, OSVR_TimeValue const &timestamp) {
Expand Down Expand Up @@ -259,6 +327,30 @@ namespace common {
return 0;
}

#ifdef OSVR_COMMON_IN_PROCESS_IMAGING
int VRPN_CALLBACK
ImagingComponent::m_handleImagePlacedInProcessMemory(void *userdata,
vrpn_HANDLERPARAM p) {
auto self = static_cast<ImagingComponent *>(userdata);
auto bufReader = readExternalBuffer(p.buffer, p.payload_len);

messages::ImagePlacedInProcessMemory::MessageSerialization msgSerialize;
deserialize(bufReader, msgSerialize);
auto msg = msgSerialize.getMessage();
ImageData data;
data.sensor = msg.sensor;
data.metadata = msg.metadata;
data.buffer.reset(reinterpret_cast<OSVR_ImageBufferElement*>(msg.buffer), &cv::fastFree);
auto timestamp = util::time::fromStructTimeval(p.msg_time);

self->m_checkFirst(msg.metadata);
for (auto const &cb : self->m_cb) {
cb(data, timestamp);
}
return 0;
}
#endif

int VRPN_CALLBACK
ImagingComponent::m_handleImagePlacedInSharedMemory(void *userdata,
vrpn_HANDLERPARAM p) {
Expand Down Expand Up @@ -317,12 +409,21 @@ namespace common {
m_registerHandler(
&ImagingComponent::m_handleImagePlacedInSharedMemory, this,
imagePlacedInSharedMemory.getMessageType());

#ifdef OSVR_COMMON_IN_PROCESS_IMAGING
m_registerHandler(
&ImagingComponent::m_handleImagePlacedInProcessMemory, this,
imagePlacedInProcessMemory.getMessageType());
#endif
}
m_cb.push_back(handler);
}
void ImagingComponent::m_parentSet() {
m_getParent().registerMessageType(imageRegion);
m_getParent().registerMessageType(imagePlacedInSharedMemory);
#ifdef OSVR_COMMON_IN_PROCESS_IMAGING
m_getParent().registerMessageType(imagePlacedInProcessMemory);
#endif
}

void ImagingComponent::m_checkFirst(OSVR_ImagingMetadata const &metadata) {
Expand Down
30 changes: 30 additions & 0 deletions src/osvr/Common/ImagingComponentConfig.h.cmake_in
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/** @file
@brief Generated header describing imaging component config

@date 2015

@author
Sensics, Inc.
<http://sensics.com/osvr>
*/

// Copyright 2015 Sensics, Inc.
//
// 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.

#ifndef INCLUDED_ImagingComponentConfig_h_GUID_093B7AF1_DCAB_4307_ACBB_F9DA4282E3BB
#define INCLUDED_ImagingComponentConfig_h_GUID_093B7AF1_DCAB_4307_ACBB_F9DA4282E3BB

#cmakedefine OSVR_COMMON_IN_PROCESS_IMAGING 1

#endif // INCLUDED_ImagingComponentConfig_h_GUID_093B7AF1_DCAB_4307_ACBB_F9DA4282E3BB
1 change: 0 additions & 1 deletion src/osvr/PluginKit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ add_library(osvr::${LIBNAME_INTERFACE} ALIAS ${LIBNAME_INTERFACE})
###
osvr_add_interface_library(Imaging)


# In an installed version, we search and add the dependency in the
# osvrConfigInstalledOpenCV.cmake script since we don't need the same version in
# the same place. Thus, here we only add it to the interface if using a build tree.
Expand Down
36 changes: 36 additions & 0 deletions src/osvr/PluginKit/ImagingInterfaceC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,42 @@
// Standard includes
// - none

// @todo This is a hack. expect this to be moved to a separate osvrJniBridge
// library and encapsulated behind a proper API.

#if defined(__ANDROID__)
#include <jni.h>
OSVR_ImageBufferElement *gLastFrame = NULL;
OSVR_ImageBufferElement *gLastFrameBuffer = NULL;
OSVR_ImagingMetadata gLastFrameMetadata;

extern "C" {
JNIEXPORT void JNICALL Java_com_osvr_android_jni_JNIBridge_reportFrame(JNIEnv * env, jclass clazz,
jbyteArray data, jlong width, jlong height);
}

JNIEXPORT void JNICALL Java_com_osvr_android_jni_JNIBridge_reportFrame(JNIEnv * env, jclass clazz,
jbyteArray data, jlong width, jlong height) {

gLastFrameMetadata.height = (OSVR_ImageDimension)height;
gLastFrameMetadata.width = (OSVR_ImageDimension)width;
gLastFrameMetadata.channels = (OSVR_ImageChannels)4;
gLastFrameMetadata.depth = (OSVR_ImageDepth)1;

// @todo determine whether the current metadata matches the last metadata,
// and if so, reuse the last frame buffer instead of deleting and recreating.
// better yet, use a ring buffer so that image reports aren't lost if update
// isn't called frequently enough.
int size = env->GetArrayLength(data);

if(gLastFrameBuffer == NULL) {
gLastFrameBuffer = new OSVR_ImageBufferElement[size];
}
gLastFrame = gLastFrameBuffer;
env->GetByteArrayRegion(data, 0, size, reinterpret_cast<jbyte*>(gLastFrameBuffer));
}
#endif

struct OSVR_ImagingDeviceInterfaceObject
: public osvr::connection::DeviceInterfaceBase {
osvr::common::ImagingComponent *imaging;
Expand Down

0 comments on commit 4c48e60

Please sign in to comment.