├── LICENSE.md ├── Node.cpp ├── Node.h ├── Peer.cpp ├── Peer.h ├── README.md ├── main.cpp └── makefile /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2016 GitHub Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /Node.cpp: -------------------------------------------------------------------------------- 1 | #include "Node.h" 2 | using namespace std; 3 | 4 | //add new node 5 | void Node::addNewNode(char * ip, int port){ 6 | 7 | bool alreadyExists = false; 8 | 9 | for (int i = 0; (i < qtd_nos) && !(alreadyExists); i++) 10 | if (strcmp(ips[i],ip) == 0) 11 | alreadyExists = true; 12 | 13 | if (!alreadyExists){ 14 | ips[qtd_nos] = ip; 15 | ports[qtd_nos] = port; 16 | qtd_nos++; 17 | } 18 | 19 | } 20 | 21 | //remove node 22 | void Node::removeNode(char * ip){ 23 | 24 | for (int i = 0; i < qtd_nos; i++){ 25 | 26 | if (strcmp(ips[i],ip) == 0){ 27 | 28 | qtd_nos--; 29 | if(i != qtd_nos){ 30 | ips[i] = ips[qtd_nos]; 31 | ports[i] = ports[qtd_nos]; 32 | } 33 | 34 | } 35 | 36 | } 37 | } 38 | 39 | //returns ip 40 | char * Node::getIP(int i){ 41 | 42 | return ips[i]; 43 | 44 | } 45 | 46 | //returns port number 47 | int Node::getPorta(int i){ 48 | 49 | return ports[i]; 50 | 51 | } 52 | 53 | //show friend list 54 | void Node::exibirNos(){ 55 | 56 | for (int i = 0; ih_addr_list[0] == 0) { 30 | cout << "Erro 6" << endl; 31 | return; 32 | } 33 | 34 | memcpy(&addr, host->h_addr_list[0], sizeof(struct in_addr)); 35 | struct sockaddr_in ipt; 36 | 37 | ipt.sin_family = AF_INET; 38 | ipt.sin_port = htons(PORT); 39 | ipt.sin_addr.s_addr = inet_addr(inet_ntoa(addr)); 40 | 41 | char *connected_ip= inet_ntoa(ipt.sin_addr); 42 | string con_ip(connected_ip); 43 | 44 | char *meuIP = inet_ntoa(ip_current.sin_addr); 45 | string my_ip(meuIP); 46 | if ((strcmp(recvBuff, msgAdmissao) == 0) && !(my_ip.compare(con_ip) == 0)) { 47 | 48 | int port = PORT; 49 | char* temp_ip = new char[con_ip.length() + 1]; 50 | strcpy(temp_ip, con_ip.c_str()); 51 | node->addNewNode(temp_ip, port); 52 | cout<<"New peer at network: "<removeNode(temp_ip); 61 | cout<<"Peer leaving: "< sizeof(int)); 112 | 113 | int tamanho_pacote = ((int *)buffer)[0]; 114 | 115 | char * buffer_video = new char[UDP_PACK_SIZE*tamanho_pacote]; 116 | 117 | //get the video 118 | for (int i = 0; i < tamanho_pacote; i++) { 119 | 120 | tamanhoMensagem = recvfrom(socketUdp, buffer, TAMANHO_BUFFER, 0, (sockaddr *)&Video_addr, &len); 121 | 122 | //wrong data, it happens in udp 123 | if (tamanhoMensagem != UDP_PACK_SIZE) continue; 124 | 125 | memcpy(&buffer_video[UDP_PACK_SIZE*i], buffer, UDP_PACK_SIZE); 126 | } 127 | 128 | Mat matVideo = Mat(1, UDP_PACK_SIZE*tamanho_pacote, CV_8UC1, buffer_video); 129 | 130 | Mat frame_video = imdecode(matVideo, CV_LOAD_IMAGE_COLOR); 131 | 132 | //wrong data, it happens in udp 133 | if (frame_video.empty()) continue; 134 | 135 | imshow("Video recebido", frame_video); 136 | 137 | waitKey(1); 138 | 139 | free(buffer_video); 140 | 141 | } 142 | 143 | } 144 | 145 | //connect to peer and send video daata 146 | void Peer::connectPeer(char* ip, int port) { 147 | 148 | findNetwork_Boolean = false; 149 | tellNetwork_Boolean = false; 150 | 151 | ip_destino = ip; 152 | porta_destino = port; 153 | 154 | socketVideo = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 155 | 156 | Recv_addr.sin_family = AF_INET; 157 | Recv_addr.sin_port = htons(port); 158 | Recv_addr.sin_addr.s_addr = INADDR_ANY; 159 | 160 | sockaddr_in Send_addr_video; 161 | Send_addr_video.sin_family = AF_INET; 162 | Send_addr_video.sin_port = htons(port); 163 | Send_addr_video.sin_addr.s_addr = inet_addr(ip); 164 | 165 | //start thread to get the video from other peer 166 | pthread_create( &thread[0], NULL, &Peer::getVideoWrapper, static_cast(this)); 167 | 168 | vector < uchar > encoded; 169 | VideoCapture cap(0); 170 | while(!cap.isOpened()) cout << "Falha ao exibir a web cam"; 171 | 172 | while (1) { 173 | 174 | Mat frame, send; 175 | 176 | cap >> frame; 177 | 178 | if (frame.empty()) continue; 179 | 180 | string servAddress = ip; 181 | 182 | int jpeg = ENCODE_QUALITY; 183 | 184 | resize(frame, send, Size(FRAME_WIDTH, FRAME_HEIGHT), 0, 0, INTER_LINEAR); 185 | 186 | vector parametros_compress; 187 | parametros_compress.push_back(CV_IMWRITE_JPEG_QUALITY); 188 | parametros_compress.push_back(jpeg); 189 | 190 | imencode(".jpg", send, encoded, parametros_compress); 191 | 192 | int total_enviar = 1 + (encoded.size() - 1) / UDP_PACK_SIZE; 193 | int buffer_tamanho[1]; 194 | buffer_tamanho[0] = total_enviar; 195 | 196 | sendto(socketUdp, (char*)buffer_tamanho, sizeof(int), 0, (sockaddr *)&Send_addr_video, sizeof(Send_addr_video)); 197 | 198 | for (int i = 0; i < total_enviar; i++) 199 | sendto(socketUdp, (char*)&encoded[UDP_PACK_SIZE*i], UDP_PACK_SIZE, 0, (sockaddr *)&Send_addr_video, sizeof(Send_addr_video)); 200 | 201 | waitKey(FRAME_INTERVAL); 202 | 203 | } 204 | 205 | } -------------------------------------------------------------------------------- /Peer.h: -------------------------------------------------------------------------------- 1 | #define FRAME_HEIGHT 720 2 | #define FRAME_WIDTH 1280 3 | #define FRAME_INTERVAL (1000/30) 4 | #define UDP_PACK_SIZE 4096 5 | #define ENCODE_QUALITY 80 6 | #define TAMANHO_BUFFER 65540 7 | 8 | #include "Node.h" 9 | 10 | class Peer 11 | { 12 | int socketUdp, socketVideo; 13 | char msgBroadcast[16]; 14 | char msgAdmissao[16]; 15 | char msgSaida[16]; 16 | socklen_t len = sizeof(struct sockaddr_in); 17 | int PORT = 7002; 18 | pthread_t thread[1]; 19 | 20 | public: 21 | 22 | Node * node; 23 | Peer(void){ 24 | 25 | findNetwork_Boolean = true; 26 | tellNetwork_Boolean = true; 27 | std::string mensagemP2p = "GettingInside"; 28 | 29 | strcpy(msgBroadcast, mensagemP2p.c_str()); 30 | strcpy(msgAdmissao, mensagemP2p.c_str()); 31 | 32 | std::string mensagemSaindo = "Leaving"; 33 | strcpy(msgSaida, mensagemSaindo.c_str()); 34 | 35 | node = new Node(); 36 | 37 | socketUdp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 38 | if (socketUdp < 0) 39 | error("ERROR opening socket"); 40 | int broadcastEnable=1; 41 | 42 | if (setsockopt(socketUdp, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable)) < 0) 43 | { 44 | error("Error setting socket to broadcast"); 45 | } 46 | 47 | Recv_addr.sin_family = AF_INET; 48 | Recv_addr.sin_port = htons(PORT); 49 | Recv_addr.sin_addr.s_addr = INADDR_ANY; 50 | Sender_addr.sin_family = AF_INET; 51 | Sender_addr.sin_port = htons(PORT); 52 | Sender_addr.sin_addr.s_addr = inet_addr("255.255.255.255"); 53 | 54 | if (bind(socketUdp, (sockaddr*)&Recv_addr, sizeof(Recv_addr)) < 0) 55 | { 56 | error("Error binding socket"); 57 | } 58 | 59 | char nomePc[80]; 60 | 61 | if (gethostname(nomePc, sizeof(nomePc)) == -1) { 62 | error("Error getting hostname"); 63 | } 64 | std::cout<h_addr_list[0] == 0) { 73 | error("Error"); 74 | } 75 | 76 | struct in_addr addr; 77 | 78 | memcpy(&addr, host->h_addr_list[0], sizeof(struct in_addr)); 79 | 80 | ip_current.sin_family = AF_INET; 81 | ip_current.sin_port = htons(PORT); 82 | ip_current.sin_addr.s_addr = inet_addr(inet_ntoa(addr)); 83 | 84 | std::cout << "Peer created" << std::endl; 85 | } 86 | 87 | static void *getVideoWrapper(void *context) 88 | { 89 | return ((Peer *)context)->getVideo(); 90 | } 91 | 92 | bool findNetwork_Boolean; 93 | bool tellNetwork_Boolean; 94 | void findOtherPeers(); 95 | void tellOtherPeers(); 96 | void leave(); 97 | void *getVideo(); 98 | void connectPeer(char* ip, int port); 99 | struct sockaddr_in Recv_addr; 100 | struct sockaddr_in Sender_addr; 101 | struct sockaddr_in ip_current; 102 | char* ip_destino; 103 | int porta_destino; 104 | 105 | private: 106 | 107 | void error(const char *msg); 108 | 109 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PEER TO PEER (P2P) VIDEO STREAMING USING UDP 2 | (for Linux) 3 | 4 | This is a Peer to Peer application that streams the WebCam video using UDP. 5 | Initially, the system creates a socket where it sends repeatedly , in a separate thread, a specific string message in broadcast mode. On the other side, in another thread, that same socket keeps listening for that same string message coming from another IP address, different from the host where the system is running into. 6 | When that happens, that new IP is added into a kind of list of friends. 7 | That process keeps running until the user desires to stream to one of the peers included into that list. 8 | When both hosts want to comunicate with each other, the stream begins. 9 | 10 | # Build 11 | * Install OpenCV (used for decoding and showing... TODO: Replace OpenCV by FFMpeg and SDL) 12 | * make 13 | 14 | # Run 15 | * ./p2pstreaming -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | //Developed by Raul Lima Alves 2 | //Computer Engineer 3 | 4 | #include "Peer.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | using namespace cv; 14 | 15 | //peer object 16 | Peer * peer; 17 | 18 | //method to show that you are in the network 19 | void *tellYouAreInTheNetwork(void* pParams) { 20 | 21 | while (peer->tellNetwork_Boolean) { 22 | peer->tellOtherPeers(); 23 | } 24 | 25 | } 26 | 27 | //method to find new nodes in network 28 | void *findWhoIsInTheNetwork(void* pParams) { 29 | 30 | while (peer->findNetwork_Boolean) { 31 | peer->findOtherPeers(); 32 | } 33 | 34 | } 35 | 36 | //show main menu 37 | void showMenu() { 38 | 39 | char *connected_ip = inet_ntoa(peer->ip_current.sin_addr); 40 | int port = ntohs(peer->ip_current.sin_port); 41 | cout << endl << "You are connected at " << connected_ip << " : " << port << endl; 42 | cout << "\t\tMENU" << endl; 43 | cout << "1 - List peers" << endl; 44 | cout << "2 - Begin Stream with someone" << endl; 45 | cout << "3 - Exit" << endl; 46 | cout << "Choose your option: "; 47 | 48 | } 49 | 50 | //get user menu option 51 | int getOption() { 52 | 53 | int option; 54 | cin >> option; 55 | return option; 56 | } 57 | 58 | //choses friend in node list to stream 59 | void chooseConnection() { 60 | 61 | system("clear"); 62 | cout << "Which one would you like to stream? " << endl; 63 | peer->node->exibirNos(); 64 | 65 | cout << "Select the Peer`s number: " << endl; 66 | int number; 67 | cin >> number; 68 | char* ip = peer -> node -> getIP(number); 69 | int port = peer -> node -> getPorta(number); 70 | peer->connectPeer(ip, port); 71 | 72 | } 73 | 74 | //main function 75 | int main(int argc, char *argv[]) { 76 | 77 | int option; 78 | int i,j; 79 | peer = new Peer(); 80 | 81 | pthread_t threads[2]; 82 | pthread_create( &threads[0], NULL, tellYouAreInTheNetwork,(void *)i); 83 | pthread_create( &threads[1], NULL, findWhoIsInTheNetwork, (void *)j); 84 | system("clear"); 85 | do { 86 | 87 | 88 | showMenu(); 89 | option = getOption(); 90 | 91 | switch (option) { 92 | 93 | case 1: 94 | peer->node->exibirNos(); 95 | getchar(); 96 | break; 97 | 98 | case 2: 99 | chooseConnection(); 100 | break; 101 | 102 | case 3: 103 | cout << "Saindo da rede..." << endl; 104 | peer->leave(); 105 | delete peer; 106 | exit(0); 107 | 108 | default: 109 | cout << endl << "Opcao incorreta..." << endl; 110 | sleep(2000); 111 | break; 112 | 113 | } 114 | 115 | } while (option != 3); 116 | 117 | delete peer; 118 | return 0; 119 | } -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | CC = g++ -std=c++11 -pthread 2 | CFLAGS = -g -Wall 3 | SRCS = Node.cpp Peer.cpp main.cpp 4 | PROG = p2pstreaming 5 | 6 | OPENCV = `pkg-config opencv --cflags --libs` 7 | LIBS = $(OPENCV) 8 | 9 | $(PROG):$(SRCS) 10 | $(CC) $(CFLAGS) -o $(PROG) $(SRCS) $(LIBS) --------------------------------------------------------------------------------