Bonjour,

Aujourd'hui j'ai voulu réaliser une application C++ visant à modifier en temps réel le flux vidéo de ma webcam.

Pour ça j'utilise une méthode callback visant à récupérer le buffer de la frame précédente avant que celle-ci ne remplace la frame courante (si j'ai bien lu la doc).

Voici l'aperçu de cette fonction.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
LRESULT CALLBACK capVideoStreamCallback(HWND hWnd, LPVIDEOHDR lpVHdr)
Donc comme paramètre je récupère une structure VIDEOHDR (Aperçu ci-dessous).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
 
typedef struct videohdr_tag {
  LPBYTE    lpData;
  DWORD     dwBufferLength;
  DWORD     dwBytesUsed;
  DWORD     dwTimeCaptured;
  DWORD_PTR dwUser;
  DWORD     dwFlags;
  DWORD_PTR dwReserved[4];
} VIDEOHDR, *PVIDEOHDR, *LPVIDEOHDR;
Je récupère donc le pointer lpData qui contient les données de la frame.

Mais le problème vient du faite que ces données sont déjà compressée au format supporté par les drivers de la webcam (ici j'ai 2 format supporté: YUY2 et MJPG)

Donc en théorie je devrais m'adapter par rapport au format ou passer sur un format RGB pour traiter les données plus les renvoyé dans le bon format.

En faite, c'est à cette partie là que je coince. Le mieux serait que je puisse passer au format RGB peut importe le format de base. Il y avait une
solution qui consistait entre la réception de message(PeekMessage) de créer un bitmap à partir du contexte d'affichage (code ci-dessous).

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 
void captureFrame()
{
	HDC hdcWin = GetDC(hWindow); // Contexte d'affichage de la fenêtre
	HDC hdc = GetDC(hWebcam); // Contexte d'affichage de la webcam
	HDC hdcMem = CreateCompatibleDC(hdc);	// Contexte de données
 
	// Donne les infos sur le bitmap
	BITMAPINFO bmpinfo;
	bmpinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmpinfo.bmiHeader.biWidth = 320;
	bmpinfo.bmiHeader.biHeight = 240;
	bmpinfo.bmiHeader.biPlanes = 1;
	bmpinfo.bmiHeader.biBitCount = 32;
	bmpinfo.bmiHeader.biCompression = BI_RGB;
	bmpinfo.bmiHeader.biSizeImage = 0;
	bmpinfo.bmiHeader.biXPelsPerMeter = 0;
	bmpinfo.bmiHeader.biYPelsPerMeter = 0;
	bmpinfo.bmiHeader.biClrUsed = 0;
	bmpinfo.bmiHeader.biClrImportant = 0;
 
	// Création du bitmap
	void *pBits;
	HBITMAP hbmp = CreateDIBSection(hdc, &bmpinfo, DIB_PAL_COLORS, &pBits, NULL, 0);
 
	// Sélection du bitmap
	SelectObject(hdcMem, hbmp);
 
	// Copie l'image
	BitBlt(hdcMem, 0, 0, 320, 240, hdc, 0, 0, SRCCOPY);
 
	// Initialisation du tableau de pixels
	int len = 320 * 240 * 4;
	BYTE *pixels = new BYTE[len];
 
	// Récupère les pixels
	GetDIBits(hdcMem, hbmp, 0, 240, pixels, &bmpinfo, DIB_RGB_COLORS);
 
	// Traitement sur les pixels
	for (int i = 0; i < len; i++)
		pixels[i] = 255 - pixels[i];
 
	// Afficher l'image
	SetDIBitsToDevice(hdcWin, 320, 0, 320, 240, 0, 0, 0, 240, pixels, &bmpinfo, DIB_RGB_COLORS);
 
	// Vidage mémoire
	delete[] pixels;
	DeleteDC(hdcMem);
	DeleteDC(hdc);
}
Je sais pas si il est fonctionnel mais c'était pour vous faire une idée. Cette méthode fonctionne mais après le problème est que je n'arrive pas à afficher seulement le rendu final de la capture. Je suis obliger de la laisser la preview de la webcam donc je me retrouve constamment avec rendu.

Y a-t-il un moyen d'avoir que le rendu final après le traitement de l'image (en modifiant directement le buffer ?) ou d'utiliser la technique décrite ci-dessus mais en affichant que le rendu final ?

Voici le code de mon application !

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
 
#include <Windows.h>
#include <Vfw.h>
 
const int widthCapture = 640;
const int heightCapture = 480;
 
HWND hWebcam;
 
LRESULT CALLBACK capVideoStreamCallback(HWND hWnd, LPVIDEOHDR lpVHdr)
{
	// C'est ici que je récupère le buffer de la frame avant que celle-ci ne s'affiche
	return 0;
}
 
LRESULT CALLBACK winProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg)
	{
		case WM_CREATE:
		{
			hWebcam = capCreateCaptureWindow("Webcam capture", WS_CHILD | WS_VISIBLE, 0, 0, widthCapture, heightCapture, hwnd, 0);
 
			if (SendMessage(hWebcam, WM_CAP_DRIVER_CONNECT, 0, 0))
			{
				//SendMessage(hWebcam, WM_CAP_DLG_VIDEOFORMAT, 0, 0);
				SendMessage(hWebcam, WM_CAP_SET_CALLBACK_FRAME, 0, (LPARAM)&capVideoStreamCallback);
				SendMessage(hWebcam, WM_CAP_SET_PREVIEWRATE, 33, 0);
				SendMessage(hWebcam, WM_CAP_SET_PREVIEW, true, 0);
			}
			else SendMessage(hwnd, WM_DESTROY, 0, 0);
			break;
		}
 
		case WM_DESTROY:
		{
			SendMessage(hWebcam, WM_CAP_SET_PREVIEW, false, 0);
			SendMessage(hWebcam, WM_CAP_SET_CALLBACK_FRAME, 0, NULL);
			SendMessage(hWebcam, WM_CAP_DRIVER_DISCONNECT, 0, 0);
 
			PostQuitMessage(0);
			break;
		}
 
		default:
			return DefWindowProc(hwnd, uMsg, wParam, lParam);
	}
 
	return 0;
}
 
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	WNDCLASS wc;
	memset(&wc, 0, sizeof(WNDCLASS));
 
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = winProc;
	wc.hInstance = hInstance;
	wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
	wc.lpszClassName = "classOfWindow";
 
	RegisterClass(&wc);
 
	HWND hWindow = CreateWindow(wc.lpszClassName, "Rectangle reconizer", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, widthCapture + 20, heightCapture + 40, NULL, NULL, NULL, NULL);
 
	ShowWindow(hWindow, SW_SHOW);
	UpdateWindow(hWindow);
 
	MSG msg;
 
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
 
	DestroyWindow(hWindow);
 
	return msg.wParam;
}
Je ne sais pas jusqu'où je peux aller pour avoir quelque chose qui puissent être rapide et qui ne surcharge pas trop la machine.

Merci d'avance pour vos réponses !

Cordialement,

firepolo