qt线程----部分代码片段

2012-11-09  来源:本站原创  分类:Qt  人气:5 

一.把视频显示到界面的方法

(1)针对qt4的(视频格式为rgb32)

v4l_grab_movie(&v4l_dev);

unsigned char *pBuffer= v4l_dev.buffer;

QImage image(pBuffer,320,240,QImage::Format_RGB32);

QPixmap pixmap;

pixmap=pixmap.fromImage(image);

label->setPixmap(pixmap);

label->setFixedSize(pixmap.width(),pixmap.height());

(2)针对qt3的

1)格式为rgb32的

QImage *img;

unsigned char *bit=image;

setWFlags(getWFlags() | Qt::WRepaintNoErase);

img=new QImage((uchar *)bit,MAX_WIDTH, MAX_HEIGHT, 32,NULL,0,QImage::IgnoreEndian);

bitBlt(this, 0, 0, img);

2)格式为rgb24的

int x, y;

int i = 0;

#if 0

QLabel *label_time;

QTime time = QTime::currentTime();

label_time = new QLabel(time.toString(),this, "label_time" );

label_time->setGeometry( 5, 250, 160, 31 );

label_time->setAlignment( QLabel::AlignCenter );

#endif

v4l_grab_movie(&v4l_dev);

QString a;

QString d;

QImage img;

unsigned char *bit= v4l_dev.buffer;

QRgb *point;

int r, g, b;

QPainter paint;

//该步很重要,设置标志

//让QWidget在更新窗体时,不擦除原来的窗体

//这样可以避免闪屏

setWFlags(getWFlags() | Qt::WRepaintNoErase);

if(img.create(MAX_WIDTH, MAX_HEIGHT, 32, 0, QImage::IgnoreEndian))

{

for(y=0; y<MAX_HEIGHT; y++)

{

for(x=0; x<MAX_WIDTH; x++)

{

r=(int)bit[i+2];

g=(int)bit[i+1];

b=(int)bit[i];

point= (QRgb *)(img).scanLine(y)+ x;

*point = qRgb(r,g,b);

i+=3;

}

}

}

paint.begin(this);

QDate date=QDate::currentDate();

d=date.toString();

QTime time = QTime::currentTime();

a=time.toString();

paint.drawImage(5, 5, (img));

paint.drawText(20,20,a,-1);

paint.drawText(20,30,d,-1);

paint.end();

二.qt的多线程问题(qt4与qt3有线程是很大不同的)

1)如果不用多线程,一般是通过QApplication的消息循环来处理的

2)QThread本身是继承于QObject的,为线程间的signal-slot机制打下了基础(Qt4),而qt3的线程不是继承于QObject,不能在线程间使用signal-slot机制(如QObject::connect(Thread, SIGNAL(Log(QString)), this, SLOT(Logslots(QString)))不能应用在qt3中,只能应用在qt4中)

3)QObject本身和线程是没关系的,提供signal-slot机制相关信息

三.事件和信号的区别(问题:哪什么时候用事件,什么时候用信号呢?是不是不同的线程间用事件,信号不能用在线程间?但现在的qt4可以在线程间发送信号)

仔细来看,事件与信号其实并无多大差别,从我们对其需求上来说,都只要能注册事件或信号响应函数,在事件或信号产生时能够被通知到即可。但有一项区别在于,事件处理函数的返回值是有意义的,我们要根据这个返回值来确定是否还要继续事件的处理,比如在QT中,事件处理函数如果返回true,则这个事件处理已完成,QApplication会接着处理下一个事件,而如果返回false,那么事件分派函数会继续向上寻找下一个可以处理该事件的注册方法。信号处理函数的返回值对信号分派器来说是无意义的。

另外还有一个需要我们关注的问题是事件和信号处理时的优先级问题。在QT中,事件因为都是与窗口相关的,所以事件回调时都是从当前窗口开始,一级一级向上派发,直到有一个窗口返回true,截断了事件的处理为止。对于信号的处理则比较简单,默认是没有顺序的,如果需要明确的顺序,可以在信号注册时显示地指明槽的位置。

在QT中,事件使用了一个事件队列来维护,如果事件的处理中又产生了新的事件,那么新的事件会加入到队列尾,直到当前事件处理完毕后, QApplication再去队列头取下一个事件来处理。而信号的处理方式有些不同,信号处理是立即回调的,也就是一个信号产生后,他上面所注册的所有槽都会立即被回调。这样就会产生一个递归调用的问题,比如某个信号处理器中又产生了一个信号,会使得信号的处理像一棵树一样的展开。

四.基于QT4的一个多线程工程实现(网上见到的一个比较好的例子,关于线程任务分配) (网址:http://easons.blogbus.com/logs/14845035.html)

想法:需要模仿ACE异步调用的方法,在一个线程分配任务给工作线程,并等待工作线程完成后返回结果。

定义一个线程类:

头文件:

#ifndef MYTHREAD_H

#define MYTHREAD_H

#include <QThread>

#include <QEvent>

#define METHOD_EVENT QEvent::User + 1028

class MethodEvent : public QEvent

{

public:

MethodEvent() : QEvent(QEvent::Type(METHOD_EVENT))

{

}

~MethodEvent()

{

}

public:

int i;//存储返回值!

};

class MyThread : public QThread

{

Q_OBJECT

public:

MyThread();

~MyThread();

bool StartThread();

bool StopThread();

protected:

void run();

void customEvent(QEvent * e);

};

#endif // MYTHREAD_H

实现文件:

#include "mythread.h"

MyThread::MyThread()

{

}

MyThread::~MyThread()

{

}

bool MyThread::StartThread()

{

start();//线程启动,调用run

return true;

}

bool MyThread::StopThread()

{

exit();

return false;

}

void MyThread::run()

{

exec();//进入本线程的消息循环

}

void MyThread::customEvent(QEvent * e)

{

if(0 == e)

return;

if( METHOD_EVENT != e->type() )

{

return;

}

MethodEvent* methodEvent = static_cast<MethodEvent*>(e);

if(NULL == methodEvent)

return;

for (int i = 0; i < 1000000000; ++i)

{

methodEvent->i = i;

}

}

主函数:

#include <QtCore/QCoreApplication>

#include "mythread.h"

int main(int argc, char *argv[])

{

QCoreApplication a(argc, argv);

MyThread mythread;

mythread.StartThread();//启动辅助线程,

MethodEvent event;//新建一个任务

QCoreApplication::sendEvent(&mythread, &event);//发给工作线程,并阻塞等待

int result = event.i;//得到返回值。

return a.exec();

}

说明:如果不用到返回值,也就是只是简单分配任务的话,可以用postEvent的方法,也就是要new一个event,发给工作线程,工作线程处理完事件后会去删除你new的event,主线程就不管了。换句话说,postEvent马上返回,不管event是否被处理完,两个线程同时在工作。而上面是主线程要等待工作线程完成工作后才可以继续,阻塞在sendEvent上了

五.图像循环队列(摄像头的采集数据放到图像循环队列)

程序通过建立带共享锁的4帧图像循环队列做为图像采集线程和图像发送线程进行数据交换的公共缓冲区(带共享锁的循环队列在这个网址下有介绍:http://www.zaoxue.com/article/tech-55122.htm)

能够在通信中更好的对数据进行读写和存储,在程序编写过程中就把数据队列的方式改为了 循环队列。通过设定数据存储地址的头指针和尾指针,以及对数据存储长度状态值的判断,从而达到 循环队列的目的。当有新的数据到来时,数据的尾指针自动往后移,长度的也做相应的增加。同时判断数据的长度有没有超出BANK的地址范围,如果超出地址范围,则尾指针跳转到头指针之前,继续往后存储数据,形成了 循环队列;同样,当从RAM里取走数据时,数据的头指针自动往后移,长度的也做相应的增减。在队列的出队操作中,还要对数据的长度进行判断,如果达到了最大长度,则丢弃后面所有的数据。直到缓存区能有空间继续作队列为止。

六.视频采集数据缓冲机制的研究

在视频采集系统中,视频数据的采集与发送需要很好的性能,所以需要一个高性能的数据流缓冲机制,在传统的生产者/消费者模型的基础上,提出一种新的数据流缓冲模型(在一份叫做 视频 会议系统中数据缓冲机制的研究.pdf 中有介绍)(一个关于多线程同步的文章 :http://www.vckbase.com/document/viewdoc/?id=1080)

七.GNU/Linux中解决多线程互斥同步问题的分析和说明( http://blog.chinaunix.net/u1/35100/showart.php?id=274716)

当解决多线程互斥同步的问题时, 经常会有如下几个问题:

1. 在一个给定的问题中, 需要多少个Mutex, 多少个Semaphore? 有什么规律?
2. 在对临界区加锁和等待信号量的顺序上有什么要求和规律?
3. 什么样操作适合放在临界区, 什么样的不适合?

下面就生产者和消费者问题来分析一些这几个问题.
下面是一个简单的实现程序:
生产者向数组sharedArray 中写入数据, 而消费者从该数组中读取数据.

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>

#define MAXSIZE 5 /* 共享缓冲区的大小*/

int sharedArray[MAXSIZE]; /*sharedArray 是共享缓冲区*/
int curr=-1; /*curr 是用来指定sharedArray 当前存有数据的最大位置*/
/* 注意,sharedArray curr 都属于共享数据*/

int empty=0;
int full=MAXSIZE;
pthread_mutex_t sharedMutex=PTHREAD_MUTEX_INITIALIZER; /* 锁定临界区的mutex*/
sem_t waitNonEmpty, waitNonFull; /* 等待" 非空资源" 和等待" 非满资源" semaphor*/

void * readData(void * whichone)
{
int data, position;
while (1){
sem_wait(&waitNonEmpty); /* 是否有" 非空资源"*/

pthread_mutex_lock(&sharedMutex); /* 进入临界区*/
data = sharedArray[curr];
position = curr--;
printf ("%s read from the %dth: %d, \n", (char*)whichone, position, data);
sem_post(&waitNonFull); /* 生成一个" 非满资源"*/
pthread_mutex_unlock(&sharedMutex); /* 离开临界区*/

sleep(2); /* 跟同步无关的费时操作*/
}
}

void * writeData(void * whichone)
{
int data, position;
while (1) {
data=(int)(10.0*random()/RAND_MAX); /* 生成一个随机数据, 注意是10.0 而不是10*/
sem_wait(&waitNonFull); /* 是否有" 非满资源"*/

pthread_mutex_lock(&sharedMutex); /* 进入临界区*/
position = ++curr;
sharedArray[curr]=data;
printf ("%s wrote to the %dth: %d, \n", (char*)whichone, position, data);
sem_post(&waitNonEmpty); /* 生成一个" 非空资源"*/
pthread_mutex_unlock(&sharedMutex); /* 离开临界区*/

sleep(1); /* 跟同步无关的费时操作*/

}
}

int main (int argc, char** argv)
{
pthread_t consumer1, consumer2, producer1, producer2; /* 两个生产者和两个消费者*/
sem_init(&waitNonEmpty, 0, empty); /* 初始化信号量*/
sem_init(&waitNonFull, 0, full);
/* 注意, 本问题中的两种semaphore 是有一定关系的, 那就是它们的初始值之和应该等于共享缓冲区大小*/
/* empty+full 等于MAXSIZE*/

pthread_create (&consumer1, NULL, &readData, "consumer1");
pthread_create (&consumer2, NULL, &readData, "consumer2");
pthread_create (&producer1, NULL, &writeData, "producer1");
pthread_create (&producer2, NULL, &writeData, "producer2");
pthread_join (consumer1, NULL);
pthread_join (consumer2, NULL);
pthread_join (producer1, NULL);
pthread_join (producer2, NULL);
sem_destroy(&waitNonEmpty);
sem_destroy(&waitNonFull);

}

分析和说明:

1. 在一个给定的问题中, 需要多少个Mutex, 多少个Semaphore? 有什么规律?

在本问题中, 共需要一个Mutex 和两个Semaphore.
其中,Mutex 是用来锁定临界区的, 以解决对共享数据的互斥访问问题( 无论是对生成者还是对消费者);
我们共需要两个Semaphore, 这是因为在本问题中共有两个稀缺资源.
第一种是" 非空" 这种资源, 是在消费者之间进行竞争的.
第二种是" 非满" 这种资源, 是在生产者之间进行竞争的.
所以, 一般来说, 需要锁定临界区, 就需要Mutex; 有几种稀缺资源就需要几个Semaphore.
对稀缺资源的分析不能想当然. 稀缺资源不一定是指被共享的资源, 很多时候是指线程会被阻塞的条件( 除了要进临界区被阻塞外).
本例中, 消费者会在缓冲区为空时被阻塞, 所以" 非空" 是一种稀缺资源;
生产者会在缓冲区为满时被阻塞, 所以" 非满" 也是一种稀缺资源.

2. 在对临界区加锁和等待信号量的顺序上有什么要求和规律?

这里要说两点:
第一, 不要将等待信号量的语句放在被锁定的临界区内, 这样会造成死锁. 而且这也是很没有必要的.
比如, 消费者在缓冲区没有数据的时候进入临界区, 这样就会把临界区锁上, 由于没有数据, 消费者也会被锁上.
这时, 任何生产者都会由于临界区被锁上而被block , 这样就造成了死锁.
第二, 如果有多个Semaphore 需要等待, 那么每个线程中, 最好对这多个信号量进行等待的顺序一致,
不然的话很容易造成死锁.

3. 什么样操作适合放在临界区, 什么样的不适合?

一般来说, 临界区中只放对共享数据进行访问的语句, 这样会改善程序的性能.
很多时候, 取出共享数据的副本后, 对副本进行费时的各种操作就不需要放在临界区了.
比如, 本例中的sleep 语句就根本不需要放入临界区.

八.教你如何测试循环缓冲区(代码我是参考DivX播放器源代码-playa-0.3.3src.zip这个开源软件的)

这个缓冲区主要包括这两个文件:Queue.h,Queue.cpp( 具体代码请参考程序)

主要函数:

RingBuff::RingBuff()

{

read_pos = 0;

write_pos = 0;

}

void RingBuff::ring_read(unsigned char *data, int size)

{

MutexBuff.lock();

if(write_pos <= read_pos) {

if(read_pos + size < RING_SIZE) {

memcpy(data, ring + read_pos, size);

read_pos += size;

}

else {

if(read_pos + size < RING_SIZE + write_pos) {

unsigned int before, after;

before = (RING_SIZE - 1) - read_pos;

after = size - before;

memcpy(data, ring + read_pos, before);

memcpy(data + before, ring, after);

read_pos = after;

}

else {

}

}

}

else {

if(read_pos + size <= write_pos) {

memcpy(data, ring + read_pos, size);

read_pos += size;

}

else {

}

}

MutexBuff.unlock();

}

void RingBuff::ring_write(unsigned char *data, int size)

{

MutexBuff.lock();

if(write_pos >= read_pos) {

if(write_pos + size < RING_SIZE) {

memcpy(ring + write_pos, data, size);

write_pos += size;

}

else {

if(write_pos + size < RING_SIZE + read_pos) {

unsigned int before, after;

before = (RING_SIZE - 1) - write_pos;

after = size - before;

memcpy(ring + write_pos, data, before);

memcpy(ring, data + before, after);

write_pos = after;

}

}

}

else {

if(write_pos + size <= read_pos) {

memcpy(ring + write_pos, data, size);

write_pos += size;

}

MutexBuff.unlock();

return;

}

MutexBuff.unlock();

}

int RingBuff::ring_full(int size)

{

if(write_pos == read_pos)

return 0;

if(write_pos > read_pos) {

if(write_pos + size < read_pos + RING_SIZE)

return 0;

return 1;

}

else {

if(write_pos + size < read_pos)

return 0;

return 1;

}

}

void RingBuff::CleanUp()

{

if(ring)

delete []ring;

// ring = 0;

write_pos = read_pos = 0;

}

测试自己所建的两个视频采集缓冲区:( 这个是应用在多线程系统中的, 但测试是用于一个线程中全部执行的, 测试是没有问题的,但如果把“从每二个视频缓冲区中取出视频数据--->把从第二个视频缓冲区中取出的视频数据显示出来”这部分放到解压线程中测试时是可以显示图像的,但显示的图像的颜色变了,我想应该是缓冲区的QMutex 问题)

// 第一种测试( 在同一个线程中执行)

void CapThread::run(){

for(;;){

v4l_grab_movie(&v4l_dev);

unsigned char *pBuffer= v4l_dev.buffer;

parent->writeCapBuff(pBuffer,320*240*4);// 将视频数据放入到每一个缓冲区

parent->readCapBuff(testbuffer,320*240*4);// 从每一个缓冲区中取得视频数据

parent->writeEnCodebuff(testbuffer,320*240*4);// 把从第一个缓冲区中取得的视频数据放到第二个视频缓冲区中

parent->readEnCodebuff(testbuffer2,320*240*4);// 从每二个视频缓冲区中取出视频数据

//add--->> 把从第二个视频缓冲区中取出的视频数据显示出来

//QImage image(testbuffer,320,240,QImage::Format_RGB32);

//QImage image(pBuffer,320,240,QImage::Format_RGB32);

QImage image(testbuffer2,320,240,QImage::Format_RGB32);

QPixmap pixmap;

pixmap=pixmap.fromImage(image);

parent->label->setPixmap(pixmap);

parent->label->setFixedSize(pixmap.width(),pixmap.height());

//add

}

}

// 第二种情况( 在两个线程中分别执行)

void CapThread::run(){

for(;;){

v4l_grab_movie(&v4l_dev);

unsigned char *pBuffer= v4l_dev.buffer;

parent->writeCapBuff(pBuffer,320*240*4);// 将视频数据放入到每一个缓冲区

parent->readCapBuff(testbuffer,320*240*4);// 从每一个缓冲区中取得视频数据

parent->writeEnCodebuff(testbuffer,320*240*4);// 把从第一个缓冲区中取得的视频数据放到第二个视频缓冲区中

}

}

void CXvidDec::run()

{for(;;){

parent->readEnCodebuff(getEnCodeBuff,320*240*4);

//Decode(getEnCodeBuff, 320*240*4) ;

//v4l_save_pnm(m_image, 320, 240, 3);

//add_display

//QImage image(m_image,320,240,QImage::Format_RGB32);

QImage image(getEnCodeBuff,320,240,QImage::Format_RGB32);

QPixmap pixmap;

pixmap=pixmap.fromImage(image);

parent->label->setPixmap(pixmap);

parent->label->setFixedSize(pixmap.width(),pixmap.height());

//ddd_display

}

}

我们要测试 ring_read() ring_write() 是否符合我们的要求,本人设计了一种简单的测试方法: 就是用ring_write() 把采集到的视频数据放到缓冲区中,然后用ring_read() 从缓冲区中读取数据,然后将数据保存成一张图片,如果图片是输入的图像就证明了缓冲区的代码是正确的, 由于我使用的队列缓冲区完全是由生产者驱动的,就是说队列的推进的速度等于生产者生产产品的速度, 消费者不一定必必须消费每一个产品,在一定程序上,丢失某些数据是允许的

循环缓冲区由一个固定大小的内存缓冲区构成,进程使用这个内存缓冲区进行日志记录。顾名思义,该缓冲区采用循环的方式进行实现。当该缓冲区填满了数据时,无需为新的数据分配更多的内存,而是从缓冲区开始的位置对其进行写操作,因此将覆盖以前的内容。

1) 对循环缓冲区进行写操作

2 ) 注意事项---在多线程程序中使用循环缓冲区

这个部分介绍了在多线程应用程序中使用循环缓冲区启时需要考虑的一些重要方面。

在访问一个公共的资源时, 同步 始终是多线程程序不可缺少的部分。因为每个线程都试图对全局空间进行写操作,所以必须确保它们同步地写入内存,否则消息就会遭到破坏。通常,每个线程在写入缓冲区之前都持有一个锁,在完成操作时释放该锁。您可以下载一个使用锁对内存进行写操作的循环缓冲区示例。

这种方法具有以下的缺点:如果您的应用程序中包含几个线程,并且每个线程都在进行访问缓冲区,那么该进程的整体性能将会受到影响,因为这些线程将在获得和释放锁上花费了大部分的时间。

通过使得每个线程将数据写入到它自己的内存块,就可以完全避免同步问题。当收到来自用户的转储数据的请求时,每个线程获得一个锁,并将其转储到中心 位置。因为仅在将数据刷新到磁盘时获得锁,所以性能并不会受到很大的影响。

. 每二种缓冲方法 , 先建多个 buffer, 然后将这些 buffer 构成 bufferpool( 本人觉得这种方法比较好 )

class CBuffer

{

BYTE * m_pbBuffer ; // buffer pointer for data

DWORD m_dwBufferLength ; // allocated buffer length

DWORD m_dwPayloadLength ; // actual data length; <= allocated

LONG m_lRef ; // this object's ref; 0 when we're available

CBufferPool * m_pBufferPool ; // back pointer

DWORD_PTR m_dwCompletionContext ; // anything

LIST_ENTRY m_ListEntry ; // list's link

OVERLAPPED m_Overlapped ; // OVERLAPPED struct we use

public :

CBuffer (

IN CBufferPool * pBufferPool, // back pointer

IN DWORD dwBufferLength, // how much to allocator

OUT HRESULT * phr // success/failre of init

) ;

~CBuffer (

) ;

// LIST_ENTRY manipulation

void InsertHead (IN LIST_ENTRY * pListHead) { ASSERT (IsListEmpty (& m_ListEntry)) ; InsertHeadList (pListHead, & m_ListEntry) ; }

void Unhook () { RemoveEntryList (& m_ListEntry) ; InitializeListHead (& m_ListEntry) ; }

// returns a pointer to the object's OVERLAPPED struct

OVERLAPPED * GetOverlapped () { return & m_Overlapped ; }

// given a LIST_ENTRY, recovers the hosting CBuffer object

static CBuffer * RecoverCBuffer (IN LIST_ENTRY * pListEntry) { CBuffer * pBuffer = CONTAINING_RECORD (pListEntry, CBuffer, m_ListEntry) ;

return pBuffer ; }

// buffer manipulation

BYTE * GetBuffer () { return m_pbBuffer ; }

void SetBuffer (BYTE *pBuffer)

{

if(this->m_pbBuffer != NULL)

delete [] m_pbBuffer;

m_pbBuffer = pBuffer;

}

DWORD GetBufferLength () { return m_dwBufferLength ; }

DWORD GetPayloadLength () { return m_dwPayloadLength ; }

void SetPayloadLength (IN DWORD dw) { ASSERT (dw <= m_dwBufferLength) ; m_dwPayloadLength = dw ; }

// async IO completion context; allows us to store information that

// allows us to recover when the IO completes

void SetCompletionContext (IN DWORD_PTR dw) { m_dwCompletionContext = dw ; }

DWORD_PTR GetCompletionContext () { return m_dwCompletionContext ; }

// refcounting

ULONG AddRef () { return InterlockedIncrement (& m_lRef) ; }

ULONG

Release (

) ;

} ;

class CBufferPool

{

// struct is used to request a CBuffer object; the buffer pool maintains a

// pool of these structs to queue buffer requests when none are available.

struct BLOCK_REQUEST {

LIST_ENTRY ListEntry ;

HANDLE hEvent ;

CBuffer * pBuffer ;

} ;

LIST_ENTRY m_Buffers ; // CBuffer list

LIST_ENTRY m_RequestPool ; // BLOCK_REQUEST list; pool

LIST_ENTRY m_Request ; // BLOCK_REQUEST list; outstanding

CRITICAL_SECTION m_crt ; // lock to access the various lists

DWORD m_dwBufferAllocatedLength ; // allocated length of each

void Lock_ () { EnterCriticalSection (& m_crt) ; }

void Unlock_ () { LeaveCriticalSection (& m_crt) ; }

// gets a request object; must hold the pool lock

BLOCK_REQUEST *

GetRequestLocked_ (

)

{

LIST_ENTRY * pListEntry ;

BLOCK_REQUEST * pBlockRequest ;

if (IsListEmpty (& m_RequestPool) == FALSE) {

// list of unused is not empty; grab one

pListEntry = RemoveHeadList (& m_RequestPool) ;

pBlockRequest = CONTAINING_RECORD (pListEntry, BLOCK_REQUEST, ListEntry) ;

}

else {

// list is empty; must allocate

pBlockRequest = new BLOCK_REQUEST ;

}

// initialize correctly if we got 1

if (pBlockRequest) {

pBlockRequest -> hEvent = NULL ;

pBlockRequest -> pBuffer = NULL ;

}

return pBlockRequest ;

}

// recycles the given block request

void

RecycleRequestLocked_ (

IN BLOCK_REQUEST * pBlockRequest

)

{

InsertHeadList (& m_RequestPool, & pBlockRequest -> ListEntry) ;

}

public :

CBufferPool (

IN DWORD dwPoolSize, // number of buffers to allocate

IN DWORD dwBufferLength, // allocated length of each buffer

OUT HRESULT * phr // success/failure

) ;

~CBufferPool (

) ;

DWORD GetBufferAllocatedLength () { return m_dwBufferAllocatedLength ; }

void

Recycle (

CBuffer *

) ;

CBuffer *

GetBuffer (

IN HANDLE hEvent, // manual reset

IN DWORD dwTimeout = INFINITE

) ;

} ;

#endif // __buffpool_h

以上这些代码是我宿舍的成哥所写的,听说是从directshow下的例子所带的,我就参考了这个自己再搞一个qt下的,以下代码是我自己写的

buffer.h文件

#include <QMutex>

#define MAXBUFSIZE 320*240*4

class Buffer

{

public:

Buffer();

virtual ~Buffer();

char *getBuf();

int getSize();

void setSize(int s);

//int getTag();

//void setTag(int stop);

void lockBuf();

void unlockBuf();

int capacity();

int getAvailableSpace();

//unsigned char*buf;

unsigned char *buf;

//char buf[MAXBUFSIZE];

int size;

//synchronization

//#ifdef WIN32

// CCriticalSection mutex;

//#else

// pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

//#endif

// int stopTag; //flag to indicate I/O operation stops or fails on this buffer

public:

//unsigned char* m_pbBuffer;

int m_dwBufferLength ;

int m_dwPayloadLength ;

QMutex BufferMutex;

};

buffer.cpp文件

#include "buffer.h"

#include <string.h>

#include <malloc.h>

Buffer::Buffer():m_dwBufferLength(MAXBUFSIZE)

{

buf = (unsigned char*)malloc(m_dwBufferLength) ;

}

Buffer::~Buffer()

{

delete buf ;

}

char* Buffer::getBuf()

{

//return &buf[0];

}

int Buffer::getSize()

{

return size;

}

void Buffer::setSize(int s)

{

size = s;

}

//int Buffer::getTag()

//

// return stopTag;

//}

//void Buffer::setTag(int stop)

//{

// stopTag = stop;

//}

int Buffer::capacity()

{

return sizeof(buf);

}

int Buffer::getAvailableSpace()

{

return sizeof(buf)-size;

}

void Buffer::lockBuf()

{

BufferMutex.lock();

}

void Buffer::unlockBuf()

{

BufferMutex.unlock();

}

QueueBuffer.h文件

#include <QMutex>

#include <QWaitCondition>

#include "buffer.h"

#define BUFFERNUM 5

class BufferQueue

{

public:

BufferQueue();

virtual ~BufferQueue();

Buffer *getReadBuffer();

void getWriteBuffer(unsigned char *e,int len);

int IsEmpty() const {return readPos == writePos ;}//&& tag == 0; } //if Queue is empty

int IsFull() const {return readPos == (writePos+1)%BUFFERNUM;}//&&tag ==1; //if Queue is full

//bool moveReadBuffer(bool);

//bool moveWriteBuffer(bool);

//void invalidate();

QMutex QueueBufferMutex;

QWaitCondition bufferNotEmpty;//用于信号等待

QWaitCondition bufferNotFull;//用于信号等待

int numUsedBytes;

void lockAccessMutex();

void unLockAccessMutex();

Buffer buffers[BUFFERNUM];

int readPos;//int front;

int writePos;//int rear;

int num;

bool validFlag;

/*Define two events to synchronize between input thread and output thread

**hFullEvent is defined for the circumstance when the buffer queue is full

**and input thread is waiting for output thread to retrieve data from buffer queue

**hEmptyEvent is defined for the circumstance when the buffer queue is empty

**and output thread is waiting for input thread puts data in buffer queue

*/

static int numOfBuffers(){return BUFFERNUM;}

};

QueueBuffer.cpp文件

#include "QueueBuffer.h"

#include <QThread>

BufferQueue::BufferQueue()

{

readPos=writePos=NULL;

numUsedBytes = 0;

}

BufferQueue::~BufferQueue()

{

}

void BufferQueue::lockAccessMutex()

{

QueueBufferMutex.lock();

}

void BufferQueue::unLockAccessMutex()

{

QueueBufferMutex.unlock();

}

/*

* This is used by read thread

*/

Buffer* BufferQueue::getReadBuffer()

{

Buffer *readBuffer;

QueueBufferMutex.lock();

if (numUsedBytes == 0)

bufferNotEmpty.wait(&QueueBufferMutex);

QueueBufferMutex.unlock();

QueueBufferMutex.lock();

readBuffer=&buffers[readPos];

readPos = (readPos+1)%numOfBuffers();

--numUsedBytes;

bufferNotFull.wakeAll();

QueueBufferMutex.unlock();

return readBuffer;

}

void BufferQueue::getWriteBuffer(unsigned char *e,int len)

{

Buffer *writeBuffer = NULL;

QueueBufferMutex.lock();

if (numUsedBytes == numOfBuffers())

bufferNotFull.wait(&QueueBufferMutex);

QueueBufferMutex.unlock();

QueueBufferMutex.lock();

buffers[writePos].buf=e;

buffers[writePos].m_dwPayloadLength=len;

writePos=(writePos+1)%numOfBuffers();

++numUsedBytes;

bufferNotEmpty.wakeAll();

QueueBufferMutex.unlock();

}

. 在qt下如何访问一个共享对象呢?

这是一个我不断思考的问题:有一个共享的视频采集缓冲区(采集线程负责把视频数据放入缓冲区,压缩线程负责从缓冲区中取出视频数据再压缩),到底这个全局的视频采集缓冲区如何可以使采集线程和压缩线程共享呢,开始时我是把这个视频采集缓冲区对象放到采集线程中的,这样采集线程就能访问到这个视频采集缓冲区,但是压缩线程如何共享这个视频采集缓冲区呢?(由于这个压缩线程要读这个视频缓冲区要用到视频缓冲对象的一个读函数,但这个视频缓冲对象是在采集线程中定义的,压缩线程是不能访问采集线程下的子对象(视频采集缓冲区)这成了一个问题),经过两天的思考终于找到了一种办法(由于qt跟vc的编程方法有很大不同,加上网上的资料比较少),我决定把视频缓冲区对象放到主线程(界面对象)中,然后在采集线程和压缩线程中加上一个主线程对像(通过这个对象就能方便地使采集线程和压缩线程访问共享这个视频采集缓冲区).代码如下

MainWindow::MainWindow()//主线程

{

setWindowTitle(tr("No movie loaded"));

setMinimumSize(320,240);

resize(520,420);

label=new QLabel(this);

setCentralWidget(label);

label->setBackgroundRole(QPalette::Dark);

btn_start = new QPushButton("start",this);

btn_start ->setGeometry( QRect(50, 300, 80, 40)) ;

connect(btn_start,SIGNAL(clicked()),this, SLOT(save())) ;

piturebuf = (unsigned char *)malloc(320*240*4);

capbuff=new RingBuff();//新建一个视频采集缓冲区

m_enc = new CXvidEnc(this) ; //新建一个压缩对象(注意this)

m_enc->AttachCaller(320, 240) ;

CXvidEnc::XVID_GLOBAL_INIT() ;

m_enc->Open() ;

m_enc->start();//启动压缩线程

a = new CapThread(this);//新建一个采集对象(注意this)

a->start();//启动采集线程

};

//主线程中对视频采集缓冲区的操作

void MainWindow::readCapBuff(unsigned char *data, int size)

{

//unsigned char*piturebuf = (unsigned char *)malloc(320*240*4) ;

capbuff->ring_read(data,size);

}

void MainWindow::writeCapBuff(unsigned char *data, int size)

{

capbuff->ring_write(data,size);

}

//采集线程

CapThread::CapThread(MainWindow *parent){

this->parent = parent;(与上面的this对应)

v4l_open(DEFAULT_DEVICE, &v4l_dev) ;

v4l_get_capability(&v4l_dev);

v4l_set_picture( &v4l_dev );

v4l_get_picture(&v4l_dev);

v4l_init_mbuf(&v4l_dev);

v4l_get_mbuf(&v4l_dev);

v4l_dev.picture.contrast = 110000;

v4l_set_picture(&v4l_dev);

}

//采集线程执行的任务 (把采集到的数据pBuffer放到视频采集缓冲区中)

void CapThread::run()

{

for(;;){

v4l_grab_movie(&v4l_dev);

unsigned char *pBuffer= v4l_dev.buffer;

parent->writeCapBuff(pBuffer,320*240*3);(这样就可以访问到共享的视频采集缓冲区了)

}

}

//压缩线程

CXvidEnc::CXvidEnc(MainWindow *parent)

{

this->parent = parent;

m_closed = true ;

//m_enc_caller = NULL ;

m_enc_handle = NULL ;

m_key = 0 ;

m_width = 0 ;

m_height = 0 ;

m_bitstream = NULL ;

getCapBuff = (unsigned char *)malloc(320*240*4);

}

//压缩线程要执行的任务(从视频缓冲区中取出数据并压缩)

void CXvidEnc::run()

{

for(;;){

parent->readCapBuff(getCapBuff, 320*240*4);

Encode(getCapBuff);

}

}

.QT多线程入门文章 (转)

Qt 中的多线程(一)

QT通过三种形式提供了对线程的支持。它们分别是,一、平台无关的线程类,二、线程安全的事件投递,三、跨线程的信号-槽连接。这使得开发轻巧的多 线程Qt程序更为容易,并能充分利用多处理器机器的优势。多线程编程也是一个有用的模式,它用于解决执行较长时间的操作而不至于用户界面失去响应。在Qt 的早期版本中,在构建库时有不选择线程支持的选项,从4.0开始,线程总是有效的。

线程类

Qt 包含下面一些线程相关的类:
QThread 提供了开始一个新线程的方法
QThreadStorage 提供逐线程数据存储
QMutex 提供相互排斥的锁,或互斥量
QMutexLocker 是一个便利类,它可以自动对QMutex加锁与解锁
QReadWriterLock 提供了一个可以同时读操作的锁
QReadLocker与QWriteLocker 是便利类,它自动对QReadWriteLock加锁与解锁
QSemaphore 提供了一个整型信号量,是互斥量的泛化
QWaitCondition 提供了一种方法,使得线程可以在被另外线程唤醒之前一直休眠。

创建一个线程

为创建一个线程,子类化QThread并且重写它的run()函数,例如:
class MyThread : public QThread
{
Q_OBJECT protected:
void run();
};
void MyThread::run()
{
...
}
之后,创建这个线程对象的实例,调用QThread::start()。于是,在run()里出现的代码将会在另外线程中被执行。
注意:QCoreApplication::exec()必须总是在主线程(执行main()的那个线程)中被调用,不能从一个QThread中调用。在 GUI程序中,主线程也被称为GUI线程,因为它是唯一一个允许执行GUI相关操作的线程。另外,你必须在创建一个QThread之前创建 QApplication(orQCoreApplication)对象。
线程同步

QMutex, QReadWriteLock, QSemaphore, QWaitCondition 提供了线程同步的手段。使用线程的主要想法是希望它们可以尽可能并发执行,而一些关键点上线程之间需要停止或等待。例如,假如两个线程试图同时访问同一个 全局变量,结果可能不如所愿。
QMutex 提供相互排斥的锁,或互斥量。在一个时刻至多一个线程拥有mutex,假如一个线程试图访问已经被锁定的mutex,那么它将休眠,直到拥有mutex的线程对此mutex解锁。Mutexes常用来保护共享数据访问。
QReadWriterLock 与QMutex相似,除了它对 "read","write"访问进行区别对待。它使得多个读者可以共时访问数据。使用QReadWriteLock而不是QMutex,可以使得多线程程序更具有并发性。

QReadWriteLock lock;
void ReaderThread::run()
{
// ...
lock.lockForRead();
read_file();
lock.unlock();
//...
}
void WriterThread::run()
{
// ...
lock.lockForWrite();
write_file();
lock.unlock();
// ...
}

QSemaphore 是QMutex的一般化,它可以保护一定数量的相同资源,与此相对,一个mutex只保护一个资源。下面例子中,使用QSemaphore来控制对环状缓 冲的访问,此缓冲区被生产者线程和消费者线程共享。生产者不断向缓冲写入数据直到缓冲末端,再从头开始。消费者从缓冲不断读取数据。信号量比互斥量有更好 的并发性,假如我们用互斥量来控制对缓冲的访问,那么生产者,消费者不能同时访问缓冲。然而,我们知道在同一时刻,不同线程访问缓冲的不同部分并没有什么 危害。

const int DataSize = 100000;
const int BufferSize = 8192;
char buffer[BufferSize];
QSemaphore freeBytes(BufferSize);
QSemaphore usedBytes;

class Producer : public QThread
{
public:
void run();
};

void Producer::run()
{
qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
for (int i = 0; i < DataSize; ++i)

{

freeBytes.acquire();

buffer[i % BufferSize] = "ACGT"[(int)qrand() % 4];

usedBytes.release();

}

}

class Consumer : public QThread

{

public: void run();

};

void Consumer::run()

{

for (int i = 0; i < DataSize; ++i)

{

usedBytes.acquire();

fprintf(stderr, "%c", buffer[i % BufferSize]);

freeBytes.release();

}

fprintf(stderr, "\n");

}

int main(int argc, char *argv[])

{

QCoreApplication app(argc, argv);

Producer producer;

Consumer consumer;

producer.start();

consumer.start();

producer.wait();

consumer.wait();

return 0;

}

QWaitCondition 允许线程在某些情况发生时唤醒另外的线程。一个或多个线程可以阻塞等待一QWaitCondition ,用wakeOne()或wakeAll()设置一个条件。wakeOne()随机唤醒一个,wakeAll()唤醒所有。

下面的例子中,生产者首先必须检查缓冲是否已满(numUsedBytes==BufferSize),如果是,线程停下来等待 bufferNotFull条件。如果不是,在缓冲中生产数据,增加numUsedBytes,激活条件bufferNotEmpty。使用mutex来 保护对numUsedBytes的访问。另外,QWaitCondition::wait()接收一个mutex作为参数,这个mutex应该被调用线程 初始化为锁定状态。在线程进入休眠状态之前,mutex会被解锁。而当线程被唤醒时,mutex会处于锁定状态,而且,从锁定状态到等待状态的转换是原子 操作,这阻止了竞争条件的产生。当程序开始运行时,只有生产者可以工作。消费者被阻塞等待bufferNotEmpty条件,一旦生产者在缓冲中放入一个 字节,bufferNotEmpty条件被激发,消费者线程于是被唤醒。

const int DataSize = 100000;

const int BufferSize = 8192;

char buffer[BufferSize];

QWaitCondition bufferNotEmpty;

QWaitCondition bufferNotFull;

QMutex mutex; int numUsedBytes = 0;

class Producer : public QThread

{

public: void run();

};

void Producer::run()

{

qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));

for (int i = 0; i < DataSize; ++i)

{

mutex.lock();

if (numUsedBytes == BufferSize) bufferNotFull.wait(&mutex);

mutex.unlock();

buffer[i % BufferSize] = "ACGT"[(int)qrand() % 4];

mutex.lock();

++numUsedBytes;

bufferNotEmpty.wakeAll();

mutex.unlock();

}

}

class Consumer : public QThread

{

public: void run();

};

void Consumer::run()

{

for (int i = 0; i < DataSize; ++i) { mutex.lock(); if (numUsedBytes == 0) bufferNotEmpty.wait(&mutex);

mutex.unlock();

fprintf(stderr, "%c", buffer[i % BufferSize]);

mutex.lock();

--numUsedBytes;

bufferNotFull.wakeAll();

mutex.unlock();

}

fprintf(stderr, "\n");

}

int main(int argc, char *argv[])

{

QCoreApplication app(argc, argv);

Producer producer;

Consumer consumer;

producer.start();

consumer.start();

producer.wait();

consumer.wait();

return 0;

}

Qt 中的多线程(二) 可重入与线程安全 在Qt文档中,术语“可重入”与“线程安全”被用来说明一个函数如何用于多线程程序。假如一个类的任何函数在此类的多个不同的实例上,可以被多个线程同时 调用,那么这个类被称为是“可重入”的。假如不同的线程作用在同一个实例上仍可以正常工作,那么称之为“线程安全”的。 大多数c++类天生就是可重入的,因为它们典型地仅仅引用成员数据。任何线程可以在类的一个实例上调用这样的成员函数,只要没有别的线程在同一个实例上调 用这个成员函数。举例来讲,下面的Counter 类是可重入的:

class Counter

{

public:

Counter() {n=0;}

void increment() {++n;}

void decrement() {--n;}

int value() const {return n;}

private:

int n;

};

这个类不是线程安全的,因为假如多个线程都试图修改数据成员 n,结果未定义。这是因为c++中的++和--操作符不是原子操作。实际上,它们会被扩展为三个机器指令: 1,把变量值装入寄存器 2,增加或减少寄存器中的值 3,把寄存器中的值写回内存 假如线程A与B同时装载变量的旧值,在寄存器中增值,回写。他们写操作重叠了,导致变量值仅增加了一次。很明显,访问应该串行化:A执行123步骤时不应 被打断。使这个类成为线程安全的最简单方法是使用QMutex来保护数据成员:

class Counter {

public:

Counter() { n = 0; }

void increment()

{

QMutexLocker locker(&mutex);

++n;

}

void decrement() {

QMutexLocker locker(&mutex); --n;

}

int value() const

{

QMutexLocker locker(&mutex);

return n;

}

private:

mutable QMutex mutex;

int n;

};

QMutexLocker类在构造函数中自动对mutex进行加锁,在析构函数中进行解锁。随便一提的是,mutex使用了mutable关键字来修饰, 因为我们在value()函数中对mutex进行加锁与解锁操作,而value()是一个const函数。 大多数Qt类是可重入,非线程安全的。有一些类与函数是线程安全的,它们主要是线程相关的类,如QMutex,QCoreApplication:: postEvent()。 线程与QObjects QThread 继承自QObject,它发射信号以指示线程执行开始与结束,而且也提供了许多slots。更有趣的是,QObjects可以用于多线程,这是因为每个线 程被允许有它自己的事件循环。 QObject 可重入性 QObject是可重入的。它的大多数非GUI子类,像QTimer,QTcpSocket,QUdpSocket,QHttp,QFtp, QProcess也是可重入的,在多个线程中同时使用这些类是可能的。需要注意的是,这些类被设计成在一个单线程中创建与使用,因此,在一个线程中创建一 个对象,而在另外的线程中调用它的函数,这样的行为不能保证工作良好。有三种约束需要注意: 1,QObject的孩子总是应该在它父亲被创建的那个线程中创建。这意味着,你绝不应该传递QThread对象作为另一个对象的父亲(因为 QThread对象本身会在另一个线程中被创建) 2,事件驱动对象仅仅在单线程中使用。明确地说,这个规则适用于"定时器机制“与”网格模块“,举例来讲,你不应该在一个线程中开始一个定时器或是连接一 个套接字,当这个线程不是这些对象所在的线程。 3,你必须保证在线程中创建的所有对象在你删除QThread前被删除。这很容易做到:你可以run()函数运行的栈上创建对象。 尽管QObject是可重入的,但GUI类,特别是QWidget与它的所有子类都是不可重入的。它们仅用于主线程。正如前面提到过的, QCoreApplication::exec()也必须从那个线程中被调用。实践上,不会在别的线程中使用GUI类,它们工作在主线程上,把一些耗时的 操作放入独立的工作线程中,当工作线程运行完成,把结果在主线程所拥有的屏幕上显示。 逐线程事件循环 每个线程可以有它的事件循环,初始线程开始它的事件循环需使用QCoreApplication::exec(),别的线程开始它的事件循环需要用 QThread::exec().像QCoreApplication一样,QThreadr提供了exit(int)函数,一个quit() slot。 线程中的事件循环,使得线程可以使用那些需要事件循环的非GUI 类(如,QTimer,QTcpSocket,QProcess)。也可以把任何线程的signals连接到特定线程的slots,也就是说信号-槽机制 是可以跨线程使用的。对于在QApplication之前创建的对象,QObject::thread()返回0,这意味着主线程仅为这些对象处理投递事 件,不会为没有所属线程的对象处理另外的事件。可以用QObject::moveToThread()来改变它和它孩子们的线程亲缘关系,假如对象有父 亲,它不能移动这种关系。在另一个线程(而不是创建它的那个线程)中delete QObject对象是不安全的。除非你可以保证在同一时刻对象不在处理事件。可以用QObject::deleteLater(),它会投递一个 DeferredDelete事件,这会被对象线程的事件循环最终选取到。 假如没有事件循环运行,事件不会分发给对象。举例来说,假如你在一个线程中创建了一个QTimer对象,但从没有调用过exec(),那么QTimer就 不会发射它的timeout()信号.对deleteLater()也不会工作。(这同样适用于主线程)。你可以手工使用线程安全的函数 QCoreApplication::postEvent(),在任何时候,给任何线程中的任何对象投递一个事件,事件会在那个创建了对象的线程中通过事 件循环派发。事件过滤器在所有线程中也被支持,不过它限定被监视对象与监视对象生存在同一线程中。类似地,QCoreApplication:: sendEvent(不是postEvent()),仅用于在调用此函数的线程中向目标对象投递事件。 从别的线程中访问QObject子类 QObject和所有它的子类是非线程安全的。这包括整个的事件投递系统。需要牢记的是,当你正从别的线程中访问对象时,事件循环可以向你的 QObject子类投递事件。假如你调用一个不生存在当前线程中的QObject子类的函数时,你必须用mutex来保护QObject子类的内部数据, 否则会遭遇灾难或非预期结果。像其它的对象一样,QThread对象生存在创建它的那个线程中---不是当QThread::run()被调用时创建的那 个线程。一般来讲,在你的QThread子类中提供slots是不安全的,除非你用mutex保护了你的成员变量。 另一方面,你可以安全的从QThread::run()的实现中发射信号,因为信号发射是线程安全的。 跨线程的信号-槽 Qt支持三种类型的信号-槽连接: 1,直接连接,当signal发射时,slot立即调用。此slot在发射signal的那个线程中被执行(不一定是接收对象生存的那个线程) 2,队列连接,当控制权回到对象属于的那个线程的事件循环时,slot被调用。此slot在接收对象生存的那个线程中被执行 3,自动连接(缺省),假如信号发射与接收者在同一个线程中,其行为如直接连接,否则,其行为如队列连接。 连接类型可能通过以向connect()传递参数来指定。注意的是,当发送者与接收者生存在不同的线程中,而事件循环正运行于接收者的线程中,使用直接连 接是不安全的。同样的道理,调用生存在不同的线程中的对象的函数也是不是安全的。QObject::connect()本身是线程安全的。 多线程与隐含共享 Qt为它的许多值类型使用了所谓的隐含共享(implicitsharing)来优化性能。原理比较简单,共享类包含一个指向共享数据块的指针,这个数据 块中包含了真正原数据与一个引用计数。把深拷贝转化为一个浅拷贝,从而提高了性能。这种机制在幕后发生作用,程序员不需要关心它。如果深入点看,假如对象 需要对数据进行修改,而引用计数大于1,那么它应该先detach()。以使得它修改不会对别的共享者产生影响,既然修改后的数据与原来的那份数据不同 了,因此不可能再共享了,于是它先执行深拷贝,把数据取回来,再在这份数据上进行修改。例如: void QPen::setStyle(Qt::PenStyle style) { detach(); // detach From common data d->style = style; // set the style member
}
void QPen::detach()
{
if (d->ref != 1) {
... // perform a deep copy
}
}
一般认为,隐含共享与多线程不太和谐,因为有引用计数的存在。对引用计数进行保护的方法之一是使用mutex,但它很慢,Qt早期版本没有提供一个满意的 解决方案。从4.0开始,隐含共享类可以安全地跨线程拷贝,如同别的值类型一样。它们是完全可重入的。隐含共享真的是"implicit"。它使用汇编语 言实现了原子性引用计数操作,这比用mutex快多了。
假如你在多个线程中同进访问相同对象,你也需要用mutex来串行化访问顺序,就如同其他可重入对象那样。总的来讲,隐含共享真的给”隐含“掉了,在多线程程序中,你可以把它们看成是一般的,非共享的,可重入的类型,这种做法是安全的。

十二 . 服务端

服务端还使用了两个socket,一个用于和服务端口绑定后侦听是否有服务请求,另外一个用于发送图像数据

十三 . 摄像头采集到的数据的格式可以为下面格式(include/linux/videodev.h),本程序使用的是VIDEO_PALETTE_RGB32(在v4l_set_picture( v4l_device *vd )中定义)

#define VIDEO_PALETTE_GREY 1 /* Linear greyscale */

#define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */

#define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */

#define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */

#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */

#define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */

#define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */

#define VIDEO_PALETTE_YUYV 8

#define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */

#define VIDEO_PALETTE_YUV420 10

#define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */

#define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */

#define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */

#define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */

#define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */

#define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */

#define VIDEO_PALETTE_PLANAR 13 /* start of planar entries */

#define VIDEO_PALETTE_COMPONENT 7 /* start of component entries */

int v4l_set_picture( v4l_device *vd )

{

//vd->picture.palette=VIDEO_PALETTE_YUV420P;

vd->picture.palette=VIDEO_PALETTE_RGB32;

if( ioctl( vd->fd, VIDIOCSPICT, &( vd->picture ) ) < 0 )

{

return -1;

}

return 0;

}

相关文章
  • qt线程----部分代码片段 2012-11-09

    一.把视频显示到界面的方法 (1)针对qt4的(视频格式为rgb32) v4l_grab_movie(&v4l_dev); unsigned char *pBuffer= v4l_dev.buffer; QImage image(pBuffer,320,240,QImage::Format_RGB32); QPixmap pixmap; pixmap=pixmap.fromImage(image); label->setPixmap(pixmap); label->setFixedSi

  • Qt线程基础(这个比较完整) 2012-11-09

    线程基础 保谓线程? 线程与并行处理任务息息相关,就像进程一样.那么,线程与进程有什么区别呢?当你在电子表格上进行数据结算的时候,在相同的桌面上可能有一个播放器正在播放你最喜欢的歌曲.这是一个两个进程并行工作的例子:一个进程运行电子表格程序;另一个进程运行一个媒体播放器.这种情况最适合用多任务这个词来描述.进一步观察媒体播放器,你会发现在这个进程内,又存在并行的工作.当媒体播放器向音频驱动发送音乐数据的时候,用户界面上与之相关的信息不断地进行更新.这就是单个进程内的并行线程. 那么,线程的并行性

  • Android实现Back功能代码片段总结 2015-03-09

    今天把在公司实现某功能所用到的Back键功能模块代码片段做一个整理.方便以后直接拿出来使用 实现Back键功能方法有: 一:重写onBackPressed方法 @Override public void onBackPressed() { // do something what you want super.onBackPressed(); } 二:使用测试框架Instrumentation,模拟任意键按下动作,注意的是该方法不能在主线程中使用,只能开启新线程,带来的问题就是反应速度较慢,项目

  • Qt 线程基础(QThread.QtConcurrent.QThreadPool等) 2012-11-08

    使用线程 基本上有种使用线程的场合: 通过利用处理器的多个核使处理速度更快. 为保持GUI线程或其他高实时性线程的响应,将耗时的操作或阻塞的调用移到其他线程. 何时使用其他技术替代线程 开发人员使用线程时需要非常小心.启动线程是很容易的,但确保所有共享数据保持一致很难.遇到问题往往很难解决,这是由于在一段时间内它可能只出现一次或只在特定的硬件配置下出现.在创建线程来解决某些问题之前,应该考虑一些替代的技术 : 替代技术 注解 QEventLoop::processEvents() 在一个耗时的计

  • Qt 线程基础(QThread.QtConcurrent等) 2012-11-10

    昨晚看Qt的Manual,突然发现下一个版本的Qt中(Qt4.7.4.Qt4.8等)增加了一个特赞的介绍多线程的文章 : Thread Basics 注意: 该链接以后会失效,但是 到时候你直接看Qt自带Manual就行了 本文不是严格的翻译 dbzhang800 2011.06.18 使用线程 基本上有种使用线程的场合: 通过利用处理器的多个核使处理速度更快. 为保持GUI线程或其他高实时性线程的响应,将耗时的操作或阻塞的调用移到其他线程. 何时使用其他技术替代线程 开发人员使用线程时需要非常

  • QT线程与定时器[二] 2014-08-14

    下面转一个相关说明吧 实例代码1: class MThread :public QThread { public: MThread(); ~MThread(); virtual void run(); void foo(); ... }; POINT 1:QThread类的实例与普通类的实例没什么不同,只是运行着的run()函数会不同 实例代码2: class MDialog :public QDialog { ... MThread *mythread; }; MDialog::MDialog

  • JS/CSS代码片段测试 JS Bin 2012-04-19

    JS Bin 网站 : https://github.com/jsbin/jsbin JSBin 是一个 Web 应用,主要用于帮助测试 JavaScript 和 CSS 的代码片段.功能与 jsFiddle 网站一致. 在线演示:http://jsbin.com/ 授权协议: MIT 开发语言: JavaScript 操作系统: 跨平台

  • 9个实用的PHP代码片段分享 2013-10-04

    这篇文章主要介绍了9个实用的PHP代码片段分享,本文讲解了查看邮件是否已被阅读.从网页中提取关键词.查找页面上的所有链接.自动转换URL为可点击超链接等内容,需要的朋友可以参考下 一.查看邮件是否已被阅读 当你发送邮件时,你肯定很想知道你的邮件是否已被对方查看.下面的代码就能实现记录阅读你邮件的IP地址,还有实际的阅读日期和时间. error_reporting(0); Header("Content-Type: image/jpeg"); //Get IP if (!empty($_

  • 分享8个最佳的代码片段在线测试网站 2013-10-22

    有时候,我们需要测试一些代码片段,而电脑中没有安装针对该语言的运行环境,没关系,你可以在线测试它们 有时候,我们需要测试一些代码片段,而电脑中没有安装针对该语言的运行环境,没关系,你可以在线测试它们. 本文为你带来 8 款非常好用的代码片段在线工具,帮助你快速.方便地测试.编辑代码片段. 1. ideone ideone 是一个在线代码编辑.调试工具,允许开发者在线编译.运行代码,支持超过 40 种编程语言. 2. Codepad Codepad 是一个在线编译/解释器,还是一个简单的协作工具.

  • 基于C++实现的线程休眠代码 2013-12-29

    这篇文章主要介绍了基于C++实现的线程休眠代码,包括了Linux平台及基于boost库的两种实现方法,有不错的参考借鉴价值,需要的朋友可以参考下 本文实例讲述了基于C++实现的线程休眠代码,分享给大家供大家参考.具体方法如下: linux平台示例如下: /* File : thread1.c Author : Mike E-Mail : [email protected] */ #include <stdio.h> #include <pthread.h> #include <

  • 19个超实用的PHP代码片段 2014-04-23

    每位程序员和开发者都喜欢讨论他们最爱的代码片段,尤其是当PHP开发者花费数个小时为网页编码或创建应用时,他们更知道这些代码的重要性.为了节约编码时间,小编收集了一些较为实用的代码片段,帮助开发者提高工作效率 1) Whois query using PHP --利用PHP获取Whois请求 利用这段代码,在特定的域名里可获得whois信息.把域名名称作为参数,并显示所有域名的相关信息. function whois_query($domain) { // fix the domain name:

  • Lua操作字符串的5个代码片段分享 2014-05-20

    这篇文章主要介绍了Lua操作字符串的5个代码片段分享,本文讲解了匹配字符串中的数字.字母和下划线.替换字符串中的指定字符.判断字符串中是否有目标字串.从文件的绝对路径中获取到文件名等内容,需要的朋友可以参考下 1.匹配字符串中的数字.字母和下划线 str = "hello_+asdf2312+887441a+asdf" table = {} string.gsub(str, "([%w_]+)", function(w) table.insert(table,w)

  • Android实用的代码片段 常用代码总结 2014-05-25

    这篇文章主要介绍了Android实用的代码片段 常用代码总结,需要的朋友可以参考下 1:查看是否有存储卡插入 String status=Environment.getExternalStorageState(); if(status.equals(Enviroment.MEDIA_MOUNTED)) { 说明有SD卡插入 } 2:让某个Activity透明 OnCreate中不设Layout this.setTheme(R.style.Theme_Transparent); 以下是Theme_

  • 10个不可忽视的CSS代码片段 2014-06-03

    概述:本文介绍10个非常有用的CSS代码片段,绝对不容忽视.包括在整个容器中垂直对齐.元素拉伸为全屏高度.跨浏览器图像灰度.动画背景等,使用平率高,经常无法完全达到想要效果.现在有了这10个CSS代码片段,我们可以将这些效果做得更好. 1.垂直对齐 将文本或元素垂直对齐.现在使用CSS3 Transforms,我们可以更有效解决这问题,如下: 1 2 3 4 5 6 7 .verticalcenter{ position:relative; top:50%; -webkit-transform:

  • 10个实用的PHP代码片段推荐 2014-06-30

    当我们使用PHP的时候,如果你自己有些非常有用的方法或者代码片段,那么将会给你带来极大的便利.今天我们将介绍10个超级好用的PHP代码片段,希望大家能够喜欢! 使用textmagic API来发送消息 可能有的时候,你需要发送一些短信到你客户手机上,你绝对应该看看textMagic.他们提供非常简单的API来实现这个功能.但是不是免费的哦. // Include the TextMagic PHP librequire('textmagic-sms-api-php/TextMagicAPI.ph

  • JavaScript的漂亮的代码片段 2014-07-28

    记录我看到之后,不得不赞的代码片段.本贴板内容将不断更新,欢迎关注 动态构建正则表达式 new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ) 来自sizzle,动态构建正则时,这样做避免了字符转义. 更灵活和巧妙的数字补零 复制代码 代码如下: function prefixInteger(num, length) { return (num / Math.pow(10, length)).to

  • 9个经典的PHP代码片段分享 2014-10-12

    这篇文章主要给大家分享了9个经典的PHP代码片段,都是非常实用,也是经常能够用到的功能,推荐给大家. 一.查看邮件是否已被阅读 当你在发送邮件时,你或许很想知道该邮件是否被对方已阅读.这里有段非常有趣的代码片段能够显示对方IP地址记录阅读的实际日期和时间. <? error_reporting(0); Header("Content-Type: image/jpeg"); //Get IP if (!empty($_SERVER['HTTP_CLIENT_IP'])) { $ip

  • 10个超级有用值得收藏的PHP代码片段 2014-12-16

    这篇文章主要介绍了10个超级有用值得收藏的PHP代码片段,本文讲解了黑名单过滤.随机颜色生成器.从网络下载文件.强制下载文件.通过Email显示用户的Gravatar头像等内容,需要的朋友可以参考下 尽管PHP经常被人诟病,被人贬低,被人当玩笑开,事实证明,PHP是全世界网站开发中使用率最高的编程语言.PHP最大的缺点是太简单,语法不严谨,框架体系很弱,但这也是它最大的优点,一个有点编程背景的普通人,只需要学习PHP半天时间,就可以上手开始开发web应用了. 网上有人总结几种编程语言的特点,我觉

  • 一些实用的jQuery代码片段收集 2015-01-01

    今天总结一下学习jQuery时中遇到的一些常用的jQuery代码,这些代码片段可能在我们急需的时候能起到帮助. 下边这些jQuery片段只是很少的一部分,如果您在学习过程中也遇到过一些常用的jQuery代码,欢迎分享.下边就让我们看看这些有代码片段. 1.jQuery得到用户IP: $.getJSON("http://jsonip.appspot.com?callback=?", function (data) { alert("Your ip: " + data.

  • EmEditor代码片段插件介绍 2015-02-10

    在双周分享会上分享了一下EmEditor的使用技巧.PPT经过删减和编辑一些不适合web展示的内容后,只剩下代码片段的部分介绍,下面是幻灯片. EmEditor Snippet View more presentations from chandleryu.