PDA

View Full Version : Create video widget using byte array



Elv13
13th June 2012, 19:15
Hi,

I have access to a framebuffer using SHM on Linux. I can get access to the data and I am quite sure they are valid. However, it only work at small resolution and somehow I get overscroll video. I try to use QImage and tried many combinaisons. Most wont work above 160x120. This one work with 340x240, but not above. The CPU does not seem to be the problem, my app use little. I can't use OpenGL (not supported on device)..

What is the best way to make a video from a frame buffer?

This is the current code:

VideoWidget::VideoWidget(QWidget* parent) : QWidget(parent),m_Image(NULL) {
setMinimumSize(200,200);
connect(VideoModel::getInstance(),SIGNAL(frameUpda ted()),this,SLOT(repaint2()));
}

void VideoWidget::update() {
QPainter painter(this);
painter.drawImage(QRect(0,0,width(),height()),*(m_ Image));
painter.end();
}

void VideoWidget::paintEvent(QPaintEvent* event)
{
Q_UNUSED(event)
if (VideoModel::getInstance()->isPreviewing()) {
update();
}
}

void VideoWidget::repaint2()
{
QSize size(VideoModel::getInstance()->getActiveResolution().width, VideoModel::getInstance()->getActiveResolution().height);
if (size != minimumSize())
setMinimumSize(size);
//if (m_Image)
// delete m_Image;
m_Image = new QImage(size,QImage::Format_ARGB32);
m_Image->loadFromData(VideoModel::getInstance()->getCurrentFrame(),"BMP");
repaint();
}



/************************************************** **********************************
* Copyright (C) 2012 by Savoir-Faire Linux *
* Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* 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 *
************************************************** *********************************/
#include "VideoModel.h"
#include "video_interface_singleton.h"
#include <QSharedMemory>
#include <QDBusPendingReply>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <unistd.h>

VideoModel* VideoModel::m_spInstance = NULL;

///@namespace ShmManager Low level function to access shared memory
namespace ShmManager {
static int getShm(unsigned numBytes, int shmKey)
{
key_t key = shmKey;
int shm_id = shmget(key, numBytes, 0644);

if (shm_id == -1)
qDebug() << ("shmget");

return shm_id;
}


static void * attachShm(int shm_id)
{
void *data = shmat(shm_id, (void *)0, 0);
if (data == (char *)(-1)) {
qDebug() << ("shmat");
data = NULL;
}

return data;
}


static void detachShm(char *data)
{
/* detach from the segment: */
if (shmdt(data) == -1)
qDebug() << ("shmdt");
}

#if _SEM_SEMUN_UNDEFINED
union semun
{
int val ; /* value for SETVAL */
struct semid_ds* buf ; /* buffer for IPC_STAT & IPC_SET */
unsigned short int* array; /* array for GETALL & SETALL */
struct seminfo* __buf; /* buffer for IPC_INFO */
};
#endif

static int get_sem_set(int semKey)
{
int sem_set_id;
key_t key = semKey;

union semun sem_val;

sem_set_id = semget(key, 1, 0600);
if (sem_set_id == -1) {
qDebug() << ("semget");
return sem_set_id;
}
sem_val.val = 0;
semctl(sem_set_id, 0, SETVAL, sem_val);
return sem_set_id;
}

static int sem_wait(int sem_set_id)
{
/* structure for semaphore operations. */
struct sembuf sem_op;

/* wait on the semaphore, unless it's value is non-negative. */
sem_op.sem_num = 0;
sem_op.sem_op = -1;
sem_op.sem_flg = IPC_NOWAIT;
return semop(sem_set_id, &sem_op, 1);
}
};

///Constructor
VideoModel::VideoModel():m_BufferSize(0),m_ShmKey( 0),m_SemKey(0),m_Res(0,0),m_pTimer(0),m_PreviewSta te(false),
m_Attached(false)
{
VideoInterface& interface = VideoInterfaceSingleton::getInstance();
connect( &interface , SIGNAL(receivingEvent(int,int,int,int,int) ), this, SLOT( receivingEvent(int,int,int,int,int) ));
connect( &interface , SIGNAL(deviceEvent() ), this, SLOT( deviceEvent() ));
connect( &interface , SIGNAL(stoppedReceivingEvent(int,int) ), this, SLOT( stoppedReceivingEvent(int,int) ));
}

///Singleton
VideoModel* VideoModel::getInstance()
{
if (!m_spInstance) {
m_spInstance = new VideoModel();
}
return m_spInstance;
}

///Stop video preview
void VideoModel::stopPreview()
{
VideoInterface& interface = VideoInterfaceSingleton::getInstance();
interface.stopPreview();
m_PreviewState = false;
if (m_pTimer)
m_pTimer->stop();
if (m_Attached) {
ShmManager::detachShm((char*)m_pBuffer);
m_Attached = false;
}
}

///Start video preview
void VideoModel::startPreview()
{
if (m_PreviewState) return;
VideoInterface& interface = VideoInterfaceSingleton::getInstance();
QDBusPendingReply<int,int,int,int,int> reply = interface.startPreview();
reply.waitForFinished();
if (!reply.isError()) {
m_Res.width = reply.argumentAt(0).toInt();
m_Res.height = reply.argumentAt(1).toInt();
m_ShmKey = reply.argumentAt(2).toInt();
m_SemKey = reply.argumentAt(3).toInt();
m_BufferSize = reply.argumentAt(4).toInt();
if (!m_pTimer) {
m_pTimer = new QTimer(this);
connect(m_pTimer,SIGNAL(timeout()),this,SLOT(timed Events()));
}
m_pTimer->setInterval(42);
m_pTimer->start();
m_PreviewState = true;
}
}

bool VideoModel::isPreviewing()
{
return m_PreviewState;
}

///@todo Set the video buffer size
void VideoModel::setBufferSize(uint size)
{
m_BufferSize = size;
}

///Event callback
void VideoModel::receivingEvent(int shmKey, int semKey, int videoBufferSize, int destWidth, int destHeight)
{
m_ShmKey = (uint)shmKey;
m_ShmKey = (uint)semKey;
m_BufferSize = videoBufferSize;
m_Res.width = destWidth;
m_Res.height = destHeight;


}

///Callback when video is stopped
void VideoModel::stoppedReceivingEvent(int shmKey, int semKey)
{
m_ShmKey = (uint)shmKey;
m_ShmKey = (uint)semKey;
}

///Event callback
void VideoModel::deviceEvent()
{

}

///Update the buffer
void VideoModel::timedEvents()
{
if ( !m_Attached ) {
int shm_id = ShmManager::getShm(m_BufferSize, m_ShmKey);
m_pBuffer = ShmManager::attachShm(shm_id);
m_Attached = true;
m_SetSetId = ShmManager::get_sem_set(m_SemKey);
}

int ret = ShmManager::sem_wait(m_SetSetId);
if (ret != -1) {
qDebug() << "Updating frame" << m_pBuffer << m_Res.width << m_Res.height << m_BufferSize;;
QByteArray array((char*)m_pBuffer,m_BufferSize);
m_Frame.resize(0);
m_Frame = array;
emit frameUpdated();
}
else {
qDebug() << "Skipping" << ret;
usleep(rand()%100000); //Be sure it can come back in sync
}
qDebug() << "Ret" << ret;
}

///Return the current framerate
QByteArray VideoModel::getCurrentFrame()
{
return m_Frame;
}

///Return the current resolution
Resolution VideoModel::getActiveResolution()
{
return m_Res;
}

high_flyer
27th June 2012, 12:13
What is the original size of your frame?