Récupérer les images d?une camera ip transmettant un flux mjpeg

5/5 (27 avis)

Snippet vu 36 413 fois - Téléchargée 30 fois

Contenu du snippet

Récupérer les images d?une camera IP ( une DLINK DCS-900) transmettant un flux MJPEG (et non MPEG), transformation en image bitmap puis affichage.
Cette base me sert en robotique mobile (simple vision à distance) et pour différents projet (reconnaissance des formes, d?iris etc..) avec traitement.
Elle utilise la librairie PLIB ( plib.net plib.org) pour le transfert entre la camera (donc facilement migrable sous linux), par contre elle utilise les fonctions windows pour la décompression JPEG ( mais on doit pouvoir facilement utiliser la librairie JPEG de ijg.org )

Source / Exemple :


/******************************************************************

  • recuperation d'un flux Mjpeg venant d'une camera IP (DCS-900) *
  • 320x200 *
  • ouvre une connexion tcp client, envoi une requete http, traite *
  • le flux reçu, extrait les images jpeg, les convertit, et *
  • affiche le resultat *
  • Copyright 2006 Grimal sylvain *
  • utilisation libre pour application non commerciale *
  • linker avec: net ul (plib) libsock32 libgdi32 libuser32 *
  • libole32 liboleaut32 libolepro32 libuuid (.a ou .lib selon *
  • compilateur) *
                                                                                                                                    • /
#include <windows.h> #include <olectl.h> #include "include/netsocket.h" // librarie PLIB voir plib.net ou plib.org #define TCP true #define UDP false #define longMaxJpeg 16384 // longueur maximale d'une image jpeg reçue (suffisant pour du 320x200) unsigned char image[longMaxJpeg]; HWND hWmain; netSocket *sockr; // DC d'affichage HDC hdcSortie; // Bitmap après convertion du jpeg HBITMAP hbmp; /*******************************************************
  • convertion d'une image Jpeg en bitmap *
  • utilisation ole de windows cf msdn *
                                                                                                              • /
HBITMAP convertJpegBmp(LPBYTE pmem, DWORD nSize) { HRESULT hr; CoInitialize(0); HBITMAP hbmp_dst = 0; // copie image jpeg dans global HGLOBAL hgbl =(HGLOBAL)GlobalAlloc(GMEM_FIXED, nSize); memcpy(hgbl, pmem, nSize); // création du stream d'échange IStream* stream = 0; // image jpeg dans global dans stream hr = CreateStreamOnHGlobal(hgbl, TRUE, &stream); if(!SUCCEEDED(hr) || !stream) { // si erreur libération des objets déja crées GlobalFree(hgbl); CoUninitialize(); } else { // création d'une 'picture' IPicture* picture = 0; // conversion stream vers picture hr = OleLoadPicture(stream, nSize, 0, IID_IPicture, (void**)&picture); if(!SUCCEEDED(hr) || !picture) { // si erreur libération des objets déja crées stream->Release(); GlobalFree(hgbl); CoUninitialize(); } else { // recuperation du handle de la 'picture' HBITMAP hbmp_src; picture->get_Handle((OLE_HANDLE *)&hbmp_src); // recuperation du handle du bitmap de la 'picture' BITMAP bmp; GetObject(hbmp_src, sizeof bmp, &bmp); // bmp est le bitmap resultant mais son pointeur vers le contenu pointe vers le contenu de 'picture' // comme on va dechargé la 'picture' on copie dans une autre zone memoire hbmp_dst = (HBITMAP)CopyImage(hbmp_src, IMAGE_BITMAP, 0, 0, 0); picture->Release(); stream->Release(); GlobalFree(hgbl); CoUninitialize(); } } return hbmp_dst; } /****************************************************
  • affiche une image jpeg contenue dans le tableau *
  • image[52 ou 53 à longueur-5] *
                                                                                                        • /
int afficheImage(HWND hwnd, DWORD longueur) { HDC hdc; DWORD debut; // recherche debut variable selon texte indication taille image debut=50; // normalement debut=52 si taille<10Ko et 53 si > while (!((image[debut]==0xFF) & (image[debut+1]==0xD8)) & (debut<54)) { debut ++; } // test entete et fin fichier JPEG if ((image[debut]==0xFF) & (image[debut+1]==0xD8) &(image[longueur-6]==0xFF)&(image[longueur-5]==0xD9)) { // conversion de l'image JPEG en Bitmap (ole Windows) hbmp = convertJpegBmp((LPBYTE) &image[debut], longueur-debut-4); // et affichage (GDI windows) hdc = GetDC(hwnd); SelectObject(hdcSortie, hbmp); BitBlt(hdc, 0, 0, 320, 240, hdcSortie, 0, 0, SRCCOPY); ReleaseDC(hwnd,hdc); // et destruction du bitmap DeleteObject(hbmp); } } /***************************************************************
  • Ouverture d'un socket TCP IP Plib port de sortie *
  • geré automatiquement par plib non contrôlable mais avantage *
  • gestion automatique si lancement de plusieurs applications *
                                                                                                                                • /
netSocket* OpenTcpMjpegParser(char* ip,unsigned int port) { netSocket *sockr; netInit(); sockr= new netSocket(); sockr->open(TCP); sockr->connect(ip,port); return sockr; } /***************************************************************
  • Fermeture du socket TCP IP *
                                                                                                                                • /
int CloseTcpMjpegParser(netSocket *sockr) { sockr->close(); } /****************************************************************
  • routine principale: ouvre une connection TCP/IP entre l'hote *
  • (le client) et la camera (le serveur), envoi la demande http *
  • *
                                                                                                                                  • /
DWORD WINAPI TcpMjpegParser( void *param) { char rbuffer[2048]; char limiteImage[19]="--video boundary--"; // limite entre deux images sur dcs-900 int len; DWORD pointeur=0; DWORD i; DWORD n; bool flag; //dc compatible avec mode d'affichage hdcSortie = CreateCompatibleDC(0); // ouverture du socket et envoi de la demande http GET // mettre l'adresse de la camera sockr=OpenTcpMjpegParser("172.16.186.51",80); // requete http à envoyer à la camera pour recevoir le flux MJPEG à adapter à votre camera // utiliser un sniffer lors d'une connexion avex IE par exemple const char* s = netFormat ("GET /VIDEO.CGI HTTP/1.0\r\nUser-Agent: user\r\nAuthorization: Basic YWRtaW46REVVU1Q=\r\n\r\n") ; sockr->send ( s, strlen(s) ) ; /****************************************************************
  • traitement des informations reçues dans le buffer. Attention *
  • un buffer trop petit entraine la perte de TOUTES les infos *
  • trouve la frontiere entre deux images JPEG *
                                                                                                                                  • /
while(true) // a faire fin du thread { len=sockr->recv(rbuffer,2048,0); // si on a reçue quelque chose if (len>=0) { // traitement un à un des octets reçus for (i=0;i<len;i++) { image[pointeur++]=rbuffer[i]; // on ne fait rien tant que l'on à pas reçu au moins 18 octets if (pointeur>18) { // test limite de l'image dans le flux flag=true; for (n=0;n<18;n++) if (image[pointeur-18+n]==limiteImage[n]) flag=flag&true; else flag=false; if (flag) { afficheImage(hWmain, pointeur-18); // 18 pour suppression de la frontiere Sleep(50) ; pointeur=0; } } } // fin de boucle for lecture du buffer } } CloseTcpMjpegParser(sockr); return 0; } /* Declare Windows procedure */ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT mssg, WPARAM wParam, LPARAM lParam) { switch(mssg) { case WM_DESTROY: DeleteObject(hbmp); DeleteDC(hdcSortie); PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, mssg, wParam, lParam); } /* Make the class name into a global variable */ char szClassName[ ] = "WindowsApp"; int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil) { // classique programmation de gestion windows (generé par dev c++) MSG messages; /* Here messages to the application are saved */ WNDCLASSEX wincl; /* Data structure for the windowclass */ /* The Window structure */ wincl.hInstance = hThisInstance; wincl.lpszClassName = szClassName; wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */ wincl.style = CS_DBLCLKS; /* Catch double-clicks */ wincl.cbSize = sizeof (WNDCLASSEX); /* Use default icon and mouse-pointer */ wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION); wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); wincl.hCursor = LoadCursor (NULL, IDC_ARROW); wincl.lpszMenuName = NULL; /* No menu */ wincl.cbClsExtra = 0; /* No extra bytes after the window class */ wincl.cbWndExtra = 0; /* structure or the window instance */ /* Use Windows's default color as the background of the window */ wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; /* Register the window class, and if it fails quit the program */ if (!RegisterClassEx (&wincl)) return 0; /* The class is registered, let's create the program*/ HWND hWnd; hWnd = CreateWindowEx ( 0, /* Extended possibilites for variation */ szClassName, /* Classname */ "Vision hexapode", /* Title Text */ WS_OVERLAPPEDWINDOW, /* default window */ CW_USEDEFAULT, /* Windows decides the position */ CW_USEDEFAULT, /* where the window ends up on the screen */ 328, /* The programs width */ 270, /* and height in pixels */ HWND_DESKTOP, /* The window is a child-window to desktop */ NULL, /* No menu */ hThisInstance, /* Program Instance handler */ NULL /* No Window Creation data */ ); // pas très propre: handle de la fentre commun à tout le programme hWmain=hWnd; /* Make the window visible on the screen */ ShowWindow (hWmain, nFunsterStil); //création du thread (API Windows) de recuperation et d'affichage DWORD len=0; DWORD total=0; DWORD ThreadId; HANDLE hThread ; DWORD threadID; hThread=CreateThread( NULL, 0, TcpMjpegParser, NULL, NULL , &ThreadId); /* Run the message loop. It will run until GetMessage() returns 0 */ while (GetMessage (&messages, NULL, 0, 0)) { /* Translate virtual-key messages into character messages */ TranslateMessage(&messages); /* Send message to WindowProcedure */ DispatchMessage(&messages); } /* The program return-value is 0 - The value that PostQuitMessage() gave */ return messages.wParam; }

A voir également

Ajouter un commentaire

Commentaires

djmahdouch
Messages postés
3
Date d'inscription
dimanche 11 novembre 2007
Statut
Membre
Dernière intervention
23 février 2012
-
salut
Je me présente, Mahdi , étudiant en troisième année de Informatique, et actuellement en 23ème jour de stage de Projet fin d'étude.

Mon sujet porte sur la gestion d'une caméra IP de surveillance sous Android
Concrètement, je dois réaliser une application Android, permettant à l'utilisateur de pouvoir obtenir l'image sur son Tablet , que reçoit la caméra.
Mon problème actuel : récupérer l'image de la caméra, sur Android , création de la classe client (socket, les méthode de récupération de le flux vidéo )
Or, je me permets donc de vous demander un "petit coup de main", afin de savoir par quelle méthode avez vous pu récupérer l'image de la caméra ?
Si vous pouviez me renseigner, cela me serait d'une grande utilité pour la réalisation de mon projet de stage .
En vous remerciant.

Je vous laisse mes coordonnées si vous souhaitez me contacter :

Mail : mahjoub.mahdi5@gmail.com

MERCI . ......
SebLinck
Messages postés
212
Date d'inscription
mardi 17 mai 2005
Statut
Membre
Dernière intervention
23 juin 2011
-
Salut,

Il faudrait savoir de quel type de mpeg est ton flux d'abord ...
Par exemple certain type de mpeg ne renvois que les pixels qui ont
changé dans l'image par rapport à la précédente ...
Ce qui va engendrer de grosses modifications dans ce code.
Si ta caméra est une TrendNet Tv-IP 300 elle gère le lux MJPEG.
Et si ce n'est pas le cas, il existe du code LGPL chez trend Net:
http://www.trendnet.com/downloads/list_gpl.asp
Avec ça tu devrais pouvoir faire quelque chose de bien !
Bon courage ...
ALICE009
Messages postés
4
Date d'inscription
lundi 27 avril 2009
Statut
Membre
Dernière intervention
21 mai 2009
-
salut SEBLINCK ,
oui mon camera IP possède un serveur web intégré , le probleme que le flux transmit par la camera IP est MPEG et non pas MJPEG ?
pour l'adabtation du code :

const char* s=netFormat("GET /TRENDnet-cgi/mpeg/video.cgi?resolution="512 x 480"&fps="25" HTTP/1.1\r\nUser-Agent: HttpClient\r\nHost:"192.168.0.30"\r\nConnection:Keep-Alive\r\nCache-Control:no-cache\r\n\r\n");

est ce que c'est juste ?
SebLinck
Messages postés
212
Date d'inscription
mardi 17 mai 2005
Statut
Membre
Dernière intervention
23 juin 2011
-
Désolé ZOUZOUAG, je n'avais pas vu ta question.
Pour utiliser un client sur le réseaux local
comme source du flux, il faut soit connaitre
son protocole ( dans notre cas, protocole HTTP)
soit utiliser une API ou SDK fournissant une méthode.
Par exemple pour Axis:
Il faut lier le programme avec la lib de l'API,
puis appeller la méthode GetCurrentImage(...),
avec les paramètres qui vont bien. Et tu retrouves
ton image dans un buffer.Qu'il ne reste plus qu'a
pousser sur l'interface .
SebLinck
Messages postés
212
Date d'inscription
mardi 17 mai 2005
Statut
Membre
Dernière intervention
23 juin 2011
-
Salut,

Si ta caméra IP possède un serveur web intégré sur lequel tu peux te connecter,
pour visualiser le flux live en MJPEG, tu peux très simplement adapter ce code.

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.