Skip to content

Commit

Permalink
Support stereo image streaming using Deflect
Browse files Browse the repository at this point in the history
  • Loading branch information
Stefan Eilemann authored and Stefan Eilemann committed Mar 23, 2017
1 parent d542070 commit 7570cff
Show file tree
Hide file tree
Showing 11 changed files with 154 additions and 97 deletions.
1 change: 1 addition & 0 deletions eq/channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ void Channel::frameStart( const uint128_t&, const uint32_t frameNumber )

void Channel::frameFinish( const uint128_t&, const uint32_t frameNumber )
{
_impl->frameFinish();
releaseFrame( frameNumber );
}

Expand Down
15 changes: 6 additions & 9 deletions eq/deflect/eventHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,20 +165,17 @@ void EventHandler::_processEvents( const Proxy* proxy )

while( _proxy->hasNewEvent( ))
{
::deflect::Event deflectEvent = _proxy->getEvent();

if( deflectEvent.type == ::deflect::Event::EVT_CLOSE )
{
_proxy->stopRunning();
window->getConfig()->sendEvent( EVENT_EXIT );
break;
}

const ::deflect::Event deflectEvent = _proxy->getEvent();
const float x = deflectEvent.mouseX * pvp.w;
const float y = deflectEvent.mouseY * pvp.h;

switch( deflectEvent.type )
{
case ::deflect::Event::EVT_CLOSE:
_proxy->stopRunning();
window->processEvent( EVENT_EXIT );
return;

case ::deflect::Event::EVT_KEY_PRESS:
case ::deflect::Event::EVT_KEY_RELEASE:
{
Expand Down
133 changes: 85 additions & 48 deletions eq/deflect/proxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,13 @@ namespace eq
{
namespace deflect
{

::deflect::Stream::Future make_ready_future( const bool value )
{
std::promise< bool > promise;
promise.set_value( value );
return promise.get_future();
}

class Proxy::Impl : public boost::noncopyable
{
public:
explicit Impl( Channel& channel )
: _channel( channel )
, _sendFuture( make_ready_future( false ))
, _running( false )
explicit Impl( Channel& ch )
: channel( ch )
{
const DrawableConfig& dc = _channel.getDrawableConfig();
const DrawableConfig& dc = channel.getDrawableConfig();
if( dc.colorBits != 8 )
{
LBWARN << "Can only stream 8-bit RGB(A) framebuffers to "
Expand All @@ -64,40 +54,83 @@ class Proxy::Impl : public boost::noncopyable
}

const std::string& deflectHost =
_channel.getView()->getSAttribute( View::SATTR_DEFLECT_HOST );
channel.getView()->getSAttribute( View::SATTR_DEFLECT_HOST );
const std::string& name =
_channel.getView()->getSAttribute( View::SATTR_DEFLECT_ID );
_stream.reset( new ::deflect::Stream( name, deflectHost ));
if( !_stream->isConnected( ))
channel.getView()->getSAttribute( View::SATTR_DEFLECT_ID );
stream.reset( new ::deflect::Stream( name, deflectHost ));
if( !stream->isConnected( ))
{
LBWARN << "Could not connect to Deflect host: " << deflectHost
<< std::endl;
return;
stream.reset();
}

_running = true;
_sendFuture = make_ready_future( true );
}

~Impl()
{
// wait for completion of previous send
_sendFuture.wait();
for( size_t i = 0; i < NUM_EYES; ++i )
if( _sendFuture[i].valid( ))
_sendFuture[i].wait();
if( _finishFuture.valid( ))
_finishFuture.wait();
}

void notifyNewImage( Channel&, const Image& image )
{
switch( channel.getEye( ))
{
case eq::EYE_LEFT:
_send( ::deflect::View::left_eye, EYE_LEFT_BIT, image );
return;

case eq::EYE_RIGHT:
_send( ::deflect::View::right_eye, EYE_RIGHT_BIT, image );
return;

default:
_send( ::deflect::View::mono, EYE_CYCLOP_BIT, image );
return;
}

}

void notifyNewImage( Channel& channel, const Image& image )
void finishFrame()
{
LBASSERT( &channel == &_channel );
if( _finishFuture.valid() && !_finishFuture.get( ))
stream.reset();
if( !stream )
return;

for( size_t i = 0; i < NUM_EYES; ++i )
{
if( _sendFuture[i].valid( ))
{
_finishFuture = stream->finishFrame();
return;
}
}
}

Channel& channel;
std::unique_ptr< ::deflect::Stream > stream;
std::unique_ptr< EventHandler > eventHandler;

// wait for completion of previous send
_running = _sendFuture.get();
private:
void _send( const ::deflect::View view, const Eye eye, const Image& image )
{
if( _sendFuture[eye].valid() && !_sendFuture[eye].get( ))
stream.reset();
if( !stream )
return;

// copy pixels to perform swapYAxis()
const size_t dataSize = image.getPixelDataSize( Frame::Buffer::color );
_buffer.replace( image.getPixelPointer( Frame::Buffer::color ), dataSize);
_buffer[eye].replace( image.getPixelPointer( Frame::Buffer::color ),
dataSize );
const PixelViewport& pvp = image.getPixelViewport();
::deflect::ImageWrapper::swapYAxis( _buffer.getData(), pvp.w, pvp.h,
image.getPixelSize( Frame::Buffer::color ));
::deflect::ImageWrapper::swapYAxis( _buffer[eye].getData(), pvp.w,
pvp.h,
image.getPixelSize( Frame::Buffer::color ));

// determine image offset wrt global view
const Viewport& vp = channel.getViewport();
Expand All @@ -106,20 +139,19 @@ class Proxy::Impl : public boost::noncopyable
const int32_t offsX = vp.x * width;
const int32_t offsY = height - (vp.y * height + vp.h * height);

::deflect::ImageWrapper imageWrapper( _buffer.getData(), pvp.w, pvp.h,
::deflect::BGRA, offsX, offsY );
::deflect::ImageWrapper imageWrapper( _buffer[eye].getData(), pvp.w,
pvp.h, ::deflect::BGRA, offsX,
offsY );
imageWrapper.compressionPolicy = ::deflect::COMPRESSION_ON;
imageWrapper.compressionQuality = 100;
imageWrapper.view = view;

_sendFuture = _stream->asyncSend( imageWrapper );
_sendFuture[eye] = stream->send( imageWrapper );
}

std::unique_ptr< ::deflect::Stream > _stream;
std::unique_ptr< EventHandler > _eventHandler;
Channel& _channel;
lunchbox::Bufferb _buffer;
::deflect::Stream::Future _sendFuture;
bool _running;
lunchbox::Bufferb _buffer[NUM_EYES];
::deflect::Stream::Future _sendFuture[NUM_EYES];
::deflect::Stream::Future _finishFuture;
};

Proxy::Proxy( Channel& channel )
Expand All @@ -131,48 +163,53 @@ Proxy::Proxy( Channel& channel )

Proxy::~Proxy()
{
_impl->_channel.removeResultImageListener( this );
_impl->channel.removeResultImageListener( this );
}

void Proxy::notifyNewImage( Channel& channel, const Image& image )
{
_impl->notifyNewImage( channel, image );

if( !_impl->_eventHandler && _impl->_stream->registerForEvents( true ))
if( !_impl->eventHandler && _impl->stream->registerForEvents( true ))
{
_impl->_eventHandler.reset( new EventHandler( this ));
_impl->eventHandler.reset( new EventHandler( this ));
LBDEBUG << "Installed event handler for Deflect proxy" << std::endl;
}
}

void Proxy::notifyFinishFrame()
{
_impl->finishFrame();
}

Channel& Proxy::getChannel()
{
return _impl->_channel;
return _impl->channel;
}

int Proxy::getSocketDescriptor() const
{
return _impl->_stream->getDescriptor();
return _impl->stream->getDescriptor();
}

bool Proxy::hasNewEvent() const
{
return _impl->_stream->hasEvent();
return _impl->stream->hasEvent();
}

bool Proxy::isRunning() const
{
return _impl->_running;
return _impl->stream != nullptr;
}

void Proxy::stopRunning()
{
_impl->_running = false;
_impl->stream.reset();
}

::deflect::Event Proxy::getEvent() const
{
return _impl->_stream->getEvent();
return _impl->stream->getEvent();
}

}
Expand Down
5 changes: 4 additions & 1 deletion eq/deflect/proxy.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

/* Copyright (c) 2013-2015, Daniel Nachbaur <[email protected]>
/* Copyright (c) 2013-2017, Daniel Nachbaur <[email protected]>
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License version 2.1 as published
Expand Down Expand Up @@ -39,6 +39,9 @@ class Proxy : public ResultImageListener
/** Stream the given image to the Deflect host. */
void notifyNewImage( Channel& channel, const Image& image ) final;

/** Complete stream operations and show image on server. */
void notifyFinishFrame() final;

/** @return the associated destination channel. */
Channel& getChannel();

Expand Down
10 changes: 10 additions & 0 deletions eq/detail/channel.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ public:
downloadFramebuffer( channel, buffers );
for( ResultImageListener* listener : resultImageListeners )
listener->notifyNewImage( channel, framebufferImage );
_finishImageListeners = true;

if( view->getScreenshotBuffers() != eq::Frame::Buffer::none )
{
Expand All @@ -119,6 +120,14 @@ public:
}
}

void frameFinish()
{
if( _finishImageListeners )
for( ResultImageListener* listener : resultImageListeners )
listener->notifyFinishFrame();
_finishImageListeners = false;
}

void downloadFramebuffer( eq::Channel& channel,
const eq::Frame::Buffer buffers )
{
Expand Down Expand Up @@ -190,6 +199,7 @@ public:
FileFrameWriter frameWriter;

bool _updateFrameBuffer;
bool _finishImageListeners = false;
};

}
Expand Down
31 changes: 17 additions & 14 deletions eq/eye.h
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@

/* Copyright (c) 2007-2012, Stefan Eilemann <[email protected]>
* 2010, Cedric Stalder <[email protected]>
/* Copyright (c) 2007-2017, Stefan Eilemann <[email protected]>
* Cedric Stalder <[email protected]>
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License version 2.1 as published
* by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Expand All @@ -23,17 +23,20 @@

namespace eq
{
using fabric::Eye;
using fabric::Eye;

/** @cond IGNORE */
using fabric::EYE_UNDEFINED;
using fabric::EYE_CYCLOP;
using fabric::EYE_LEFT;
using fabric::EYE_RIGHT;
using fabric::EYES_STEREO;
using fabric::EYES_ALL;
using fabric::NUM_EYES;
/** @endcond */
/** @cond IGNORE */
using fabric::EYE_UNDEFINED;
using fabric::EYE_CYCLOP;
using fabric::EYE_LEFT;
using fabric::EYE_RIGHT;
using fabric::EYE_CYCLOP_BIT;
using fabric::EYE_LEFT_BIT;
using fabric::EYE_RIGHT_BIT;
using fabric::EYES_STEREO;
using fabric::EYES_ALL;
using fabric::NUM_EYES;
/** @endcond */
}

#endif // EQ_EYE_H
6 changes: 2 additions & 4 deletions eq/fabric/eventType.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,17 @@ enum EventType // Also update string table in event.cpp
EVENT_MAGELLAN_AXIS = 30, //!< AxisEvent: SpaceMouse touched
EVENT_MAGELLAN_BUTTON, //!< ButtonEvent: SpaceMouse button pressed

// Stateless Events
// Event
EVENT_WINDOW_CLOSE = 40, //!< A window has been closed
EVENT_WINDOW_HIDE, //!< A window is hidden
EVENT_WINDOW_EXPOSE, //!< A window is dirty
EVENT_EXIT, //!< Exit request from application or due to runtime error

EVENT_STATISTIC, //!< Statistic event

/** Window pointer grabbed by system window */
EVENT_WINDOW_POINTER_GRAB,
/** Window pointer to be released by system window */
EVENT_WINDOW_POINTER_UNGRAB,

EVENT_STATISTIC, //!< Statistic event

/**
* Observer moved (head tracking update). Contains observer originator
Expand Down
Loading

0 comments on commit 7570cff

Please sign in to comment.