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

Dani AI

Generated

— the crash/compile error in the thread was caused by two related mistakes: passing the result of cvWriteFrame(...) (i.e. calling the function) to pthread_create instead of a function pointer, and spawning+joining a thread for every single frame (which removes any concurrency benefit and is expensive). spotted the prototype mismatch; the next practical steps are architectural.

Recommended pattern (robust and thread‑safe)

  • Do not create a thread per frame. Create one persistent writer thread per output (or a small writer pool) and push frames into a queue for that thread to consume. Thread creation + join per frame causes huge overhead and race/lifetime problems.
  • Never pass the IplImage pointer returned by cvRetrieveFrame directly to a worker that runs asynchronously — that pointer refers to an internal buffer that will be reused. Clone/copy the frame (or convert to cv::Mat and clone()) before enqueueing.
  • Prefer modern threading primitives (C++11 std::thread, std::mutex, std::condition_variable) on Visual Studio when available. If stuck with pthreads on Windows, use a stable pthreads port and the same queue design.

Small illustrative sketch (C++11 + OpenCV)

// producer: capture thread / main loop
cv::Mat f;
cap >> f;
{
  std::lock_guard<std::mutex> lk(m);
  q.push(f.clone());           // clone before enqueue
}
cv.notify_one();

// consumer: writer thread
while (!stop) {
  std::unique_lock<std::mutex> lk(m);
  cv.wait(lk, []{ return !q.empty() || stop; });
  if (!q.empty()) {
    cv::Mat frame = std::move(q.front()); q.pop();
    lk.unlock();
    writer.write(frame);       // single thread writes to this writer
  }
}

Quick checklist before concluding

  • Use separate VideoWriter instances (one per file) and check they opened OK.
  • Ensure capture indices are correct (0, 1 for two webcams).
  • Protect a single VideoWriter with a mutex or give each writer its own thread so writes are never concurrent on the same writer.
  • Release/flush writers on exit.

This approach fixes the pthread_create misuse, avoids lifetime bugs from internal capture buffers, and scales reliably when recording multiple streams.

Recommended Answers

All 2 Replies

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

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.