Hi,

I've been trying to capture video from webcam using openCV functions and openGL for rendering.

The code is working fine and I can acquire and display both the cameras.

Now I'm trying to record the captured video's and saving them to a file using openCV createvideowriter object. I can easily save the video into .avi format. However when I try to save/write both the videos from both camera's then the video is saved from first cam properly but not from second. I then started looking for using threads. I haven't used threads before and even after going thru articles I'm unsuccessful running the code.

Getting following error :Error 1 error C2664: 'pthread_create' : cannot convert parameter 3 from 'void *' to 'void *(__cdecl *)(void *)'

The code is like this...

#include <highgui.h>
#include <cv.h>

#include <cstdio>
#include <pthread.h>

#include "Shader.h"

typedef unsigned int uint32;
typedef unsigned char uint8;

uint8 * img0 = 0, * img1 = 0;

uint32 texID[2];

Shader * shader = 0;
uint32 program = 0, locImg0, locImg1;
CvCapture* capture0;
CvCapture* capture1;
IplImage* frame0;
IplImage* frame1;

static CvVideoWriter* writer0;
static CvVideoWriter* writer1;

typedef struct {
	IplImage *image;
} thread_param;

uint32 imageWidth, imageHeight, sizeImg;

int w = 800, h = 600;//Bredde og høyde på vindu

void initOpenGL(); //Setter parametre
int initCameras();
void initWindow();
void setBuffers();

void display(); //Kalles av systemet
void reshape(int bredde, int hoyde); //Kalles av systemet
void keyboard(uint8 key, int x, int y);
void idle(); //Kalles av systemet

void close();

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

	int s = sizeof(void*);
	atexit(close);

	//Disse 5 funksjonene må være tilstede
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);

	initCameras();
	
	//Initialize Writers
	writer0 = cvCreateVideoWriter("video/camera0.avi", CV_FOURCC('X','V','I','D'), 15, cvSize(320,240));
	writer1 = cvCreateVideoWriter("video/camera1.avi", CV_FOURCC('X','V','I','D'), 15, cvSize(320,240));
	
	//create and initialize thread
//	pthread_t thread1, thread2;
//	thread_param *p1 = (thread_param*) malloc(sizeof(thread_param));


	
	initWindow();
	initOpenGL();
	glewInit();

	setBuffers();
	shader = new Shader();
	program = shader->setShader("../Shader/ProcessImages");
	locImg0 = glGetUniformLocation(program, "Image0");
	locImg1 = glGetUniformLocation(program, "Image1");

	glutMainLoop();

	return 0;
}

void initWindow()
{
	glutInitWindowSize(w, h);
	glutInitWindowPosition(100, 150);
	glutCreateWindow("Multi Video");

	//Callback-funksjoner
	glutKeyboardFunc(keyboard);
	glutIdleFunc(idle);
	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
}

int initCameras()
{
	capture0 = cvCaptureFromCAM(0);
	capture1 = cvCaptureFromCAM(0);
	if( !capture0 || !capture1) {
		fprintf( stderr, "ERROR: capture is NULL \n" );
		getchar();
		close();
		return -1;
	}

	frame0 = cvQueryFrame(capture0);
	frame1 = cvQueryFrame(capture1);



	imageWidth = frame0->width;
	imageHeight = frame0->height;
	w = imageWidth;
	h = imageHeight;
	sizeImg = w * h * 3;
	img0 = new unsigned char[sizeImg];
	img1 = new unsigned char[sizeImg];
	memcpy(img0, (uint8 *) frame0->imageData, sizeImg);
	memcpy(img1, (uint8 *) frame1->imageData, sizeImg); 
}

void close()
{
	if (capture0)
	{	cvReleaseCapture(&capture0);
		cvReleaseVideoWriter(&writer0);
	}
	if (capture1)
		cvReleaseCapture(&capture1);
		cvReleaseVideoWriter(&writer1);
	exit(0);
}

void* record1(void *p)
{
	thread_param *param = (thread_param*) p;

	IplImage *image = param->image;
                
    // On écrit la frame dans le fichier vidéo
    cvWriteFrame(writer1, image);

	return NULL;
}

//callback
void display()
{
	if (cvGrabFrame(capture0)) {
		frame0 = cvRetrieveFrame(capture0);	
		//cvWriteFrame(writer0, frame0);	
		memcpy(img0, (uint8 *) frame0->imageData, sizeImg);
	

		// Parameters for thread 1
		pthread_t thread1;
		thread_param *p1 = (thread_param*) malloc(sizeof(thread_param));
		(*p1).image = frame0;
	
		// Start the threads for recording each frame from each camera separately
		//pthread_create(&thread1, NULL, NULL, (void*) p1);
		pthread_create(&thread1, NULL, (void*) cvWriteFrame(writer0, frame0) , NULL);
		
		// Wait the end of the threads
		pthread_join(thread1, NULL);

	}
	if (cvGrabFrame(capture1)) {
		frame1 = cvRetrieveFrame(capture1);
		cvWriteFrame(writer1, frame1);	
		memcpy(img1, (uint8 *) frame1->imageData, sizeImg);
	}

	glBindTexture(GL_TEXTURE_2D, texID[0]);
	glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, imageWidth, imageHeight, 0, GL_BGR, GL_UNSIGNED_BYTE, img0);
	glUniform1i(locImg0, 0);

	glBindTexture(GL_TEXTURE_2D, texID[1]);
	glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, imageWidth, imageHeight, 0, GL_BGR, GL_UNSIGNED_BYTE, img1);
	glUniform1i(locImg1, 1);

	glBegin(GL_QUADS);
	{	
		glTexCoord2f(0, 1); glVertex2f(0, 0);
		glTexCoord2f(1, 1); glVertex2f(1, 0);
		glTexCoord2f(1, 0); glVertex2f(1, 1);
		glTexCoord2f(0, 0); glVertex2f(0, 1);
	}
	glEnd();
	glBindTexture(GL_TEXTURE_2D, 0);

	glutSwapBuffers();
}

void idle()
{
	glutPostRedisplay();
}

void reshape(int bredde, int hoyde) 
{
	glViewport(0, 0, bredde, hoyde);
}

void keyboard(uint8 key, int x, int y)
{
	switch(key) {
		case 27 : close();
	}
}

void initOpenGL()
{
	glClearColor(1.0f, 1.0f, 1.0f, 1.0f);//Hvit bakgrunn

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	gluOrtho2D(0, 1, 0, 1);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}


void setBuffers()
{
    // create texture for display
    glGenTextures(2, texID);

	glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texID[0]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, imageWidth, imageHeight, 0, GL_BGR, GL_UNSIGNED_BYTE, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

	glActiveTexture(GL_TEXTURE0 + 1);
    glBindTexture(GL_TEXTURE_2D, texID[1]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, imageWidth, imageHeight, 0, GL_BGR, GL_UNSIGNED_BYTE, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    glBindTexture(GL_TEXTURE_2D, 0);
}

Anyone of you out there can help me out ?
Thanks

I didn't look through your whole code, but what you do with the thread makes no sense.

You create the thread, and then wait for it to complete. Why is this needed? E.g. why did you chose to use a thread rather than just call the function directly.

Anyway.. to answer your question:

pthread_create(&thread1, NULL, (void*) cvWriteFrame(writer0, frame0) , NULL);	
pthread_join(thread1, NULL);

pthread_create expects a pointer to a function with prototype:
void *(__cdecl *)(void *)

This means it is a function that returns nothing(void) and takes one void* as argument.
So cvWriteFrame is not going to work directly with pthread_create because it takes 2 arguments, not 1. I guess this function comes from a library so you can't change it to only take one argument.

So... think about if you really need the thread, if you think you do... read up pthreads

Thank, I already got it solved.

I didn't look through your whole code, but what you do with the thread makes no sense.

You create the thread, and then wait for it to complete. Why is this needed? E.g. why did you chose to use a thread rather than just call the function directly.

Anyway.. to answer your question:

pthread_create(&thread1, NULL, (void*) cvWriteFrame(writer0, frame0) , NULL);	
pthread_join(thread1, NULL);

pthread_create expects a pointer to a function with prototype:
void *(__cdecl *)(void *)

This means it is a function that returns nothing(void) and takes one void* as argument.
So cvWriteFrame is not going to work directly with pthread_create because it takes 2 arguments, not 1. I guess this function comes from a library so you can't change it to only take one argument.

So... think about if you really need the thread, if you think you do... read up pthreads

This question has already been answered. Start a new discussion instead.