Skip to content

Commit

Permalink
Added code that use mainthread invoker to transfer control when grabbing
Browse files Browse the repository at this point in the history
images.
  • Loading branch information
cdyk committed Jun 6, 2014
1 parent 83a39cd commit 2f490cc
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 4 deletions.
26 changes: 26 additions & 0 deletions include/tinia/qtcontroller/moc/OpenGLServerGrabber.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,32 @@ class OpenGLServerGrabber : public QObject, public ImageSource

void getImageAsText(QTextStream& os, unsigned int width, unsigned int height, QString key);

/** Mutex that governs exclusive access to this object. */
QMutex*
exclusiveAccessMutex()
{ return &m_mainMutex; }

/** Returns a pointer to the grabbed image.
*
* \note \ref exclusiveAccessMutex must be held before invocation.
*/
const unsigned char*
imageBuffer() const
{ return m_buffer; }

/** Grabs an image of a view
*
* \note Must be invoked in the thread that holds the OpenGL context,
* usually the main/GUI-thread.
* \note \ref exclusiveAccessMutex must be held before invocation.
*/
void
grab(tinia::jobcontroller::OpenGLJob* job,
unsigned int width,
unsigned int height,
const std::string &key );


signals:
void glImageReady();
void getGLImage(unsigned int width, unsigned int height, QString key);
Expand Down
34 changes: 34 additions & 0 deletions src/qtcontroller/OpenGLServerGrabber.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,40 @@ void OpenGLServerGrabber::getImageAsText(QTextStream &os, unsigned int width, un
m_mainMutex.unlock();
}

void
OpenGLServerGrabber::grab( jobcontroller::OpenGLJob *job,
unsigned int width,
unsigned int height,
const std::string& key )
{
if(m_width != width || m_height != height) {
resize(width, height);
}

glBindFramebuffer( GL_FRAMEBUFFER, m_fbo );
glViewport( 0, 0, width, height );
job->renderFrame( "session", key, m_fbo, width, height );

// QImage requires scanline size to be a multiple of 32 bits.
size_t scanline_size = 4*((3*width+3)/4);
glPixelStorei( GL_PACK_ALIGNMENT, 4 );

// make sure that buffer is large enough to hold raw image
size_t req_buffer_size = scanline_size*height*3;
if( (m_buffer == NULL) || (m_buffer_size < req_buffer_size) ) {
if( m_buffer != NULL ) {
delete m_buffer;
}
m_buffer_size = req_buffer_size;
m_buffer = new unsigned char[m_buffer_size];
}

glBindFramebuffer( GL_FRAMEBUFFER, m_fbo );
glReadPixels( 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, m_buffer );
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}


void OpenGLServerGrabber::getImage(unsigned int width, unsigned int height, QString key)
{
tinia::jobcontroller::OpenGLJob* openGLJob = static_cast<tinia::jobcontroller::OpenGLJob*>(m_job);
Expand Down
84 changes: 80 additions & 4 deletions src/qtcontroller/ServerThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <QRegExp>
#include "tinia/renderlist.hpp"
#include <QFile>
#include <QMutexLocker>
#include "tinia/qtcontroller/moc/LongPollHandler.hpp"
#include "tinia/model/ExposedModelLock.hpp"

Expand Down Expand Up @@ -61,6 +62,80 @@ class RenderListFetcher : public QRunnable
};


class SnapshotAsTextFetcher : public QRunnable
{
public:

explicit SnapshotAsTextFetcher( QTextStream& reply,
const QString& request,
tinia::jobcontroller::Job* job,
tinia::qtcontroller::impl::OpenGLServerGrabber* gl_grabber )
: m_reply( reply ),
m_request( request ),
m_job( NULL ),
m_gl_grabber( gl_grabber ),
m_gl_grabber_locker( gl_grabber->exclusiveAccessMutex() )
{
using namespace tinia::qtcontroller::impl;

m_job = dynamic_cast<tinia::jobcontroller::OpenGLJob*>( job );
if( m_job == NULL ) {
throw std::invalid_argument("This is not an OpenGL job!");
}


typedef boost::tuple<unsigned int, unsigned int, std::string> params_t;
params_t arguments = parseGet<params_t >(decodeGetParameters(request),
"width height key" );
m_width = arguments.get<0>();
m_height = arguments.get<1>();
m_key = arguments.get<2>();
}

~SnapshotAsTextFetcher()
{
using namespace tinia::qtcontroller::impl;
QImage img( m_gl_grabber->imageBuffer(),
m_width,
m_height,
QImage::Format_RGB888 );

// This is a temporary fix. The image is reflected through the horizontal
// line y=height ((x, y) |--> (x, h-y) ).
QTransform flipTransformation(1, 0,
0, -1,
0, m_height);
img = img.transformed(flipTransformation);
QBuffer qBuffer;
img.save(&qBuffer, "png");
//m_gl_grabber_locker.unlock();

m_reply << httpHeader(getMimeType("file.txt"));
QString str( QByteArray( qBuffer.data(),
int(qBuffer.size()) ).toBase64() );
m_reply << "\r\n"<<str;
}

void
run()
{
m_gl_grabber->grab( m_job, m_width, m_height, m_key );
}



protected:
QTextStream& m_reply;
const QString& m_request;
tinia::jobcontroller::OpenGLJob* m_job;
tinia::qtcontroller::impl::OpenGLServerGrabber* m_gl_grabber;
QMutexLocker m_gl_grabber_locker;
unsigned int m_width;
unsigned int m_height;
std::string m_key;
};


}


Expand Down Expand Up @@ -155,14 +230,15 @@ bool ServerThread::handleNonStatic(QTextStream &os, const QString& file,
{
try {
if(file == "/snapshot.txt") {

updateState(os, request);
getSnapshotTxt(os, request);
SnapshotAsTextFetcher f( os, request, m_job, &m_grabber );
m_mainthread_invoker->invokeInMainThread( &f, true );
//getSnapshotTxt(os, request);
return true;
}
else if(file == "/getRenderList.xml") {
RenderListFetcher functor( os, request, m_job );
m_mainthread_invoker->invokeInMainThread( &functor, true );
RenderListFetcher f( os, request, m_job );
m_mainthread_invoker->invokeInMainThread( &f, true );
return true;
}
else if(file =="/updateState.xml") {
Expand Down

0 comments on commit 2f490cc

Please sign in to comment.