//cette fonction est un thread, ne pas l'appeler ! void* video_routine(void* args) { ssize_t pack_size = 0; int nb_img = 0; pthread_mutex_lock(&mutex_stopped); while(!stopped) { pthread_mutex_unlock(&mutex_stopped); //Wait for the drone to send data on the video socket if (select(sock_video+1, &vid_fd_set, NULL, NULL, &video_timeout) < 0) { perror("Error select()"); video_set_stopped(); } else if(FD_ISSET(sock_video, &vid_fd_set)) { /*receive the video data from the drone. Only BASE_SIZE, since TCP_SIZE may be larger on purpose.*/ pack_size = recv(sock_video, tcp_buf, BASE_VIDEO_BUF_SIZE, 0); if(pack_size == 0) { printf("Stream ended by server. Ending the video thread.\n"); video_set_stopped(); } else if(pack_size < 0) perror("Error recv()"); else { //we actually got some data, send it for decoding ! nb_img = video_decode_packet(tcp_buf, pack_size); if(nb_img < 0) { fprintf(stderr, "Error processing frame !\n"); video_set_stopped(); } } } else { printf("Video : data reception has timed out. Ending the video thread now.\n"); video_set_stopped(); } //reset the timeout and the FDSET entry video_timeout.tv_sec = VIDEO_TIMEOUT; FD_ZERO(&vid_fd_set); FD_SET(sock_video, &vid_fd_set); pthread_mutex_lock(&mutex_stopped); } pthread_mutex_unlock(&mutex_stopped); //there's no reason to keep stuff that's needed for our video thread once it's ended, so clean it now. video_clean(); pthread_mutex_lock(&mutex_terminated); terminated = 1; printf("Video thread terminated.\n"); pthread_mutex_unlock(&mutex_terminated); pthread_exit(NULL); }
int jakopter_init_video() { pthread_mutex_lock(&mutex_init); //do not try to initialize the thread if it's already running ! pthread_mutex_lock(&mutex_terminated); if(!terminated) { pthread_mutex_unlock(&mutex_terminated); fprintf(stderr, "Video thread already running.\n"); pthread_mutex_unlock(&mutex_init); return -1; } pthread_mutex_unlock(&mutex_terminated); //make the thread detached so that it can close itself without us having //to join with it in order to free its resources. pthread_attr_t thread_attribs; pthread_attr_init(&thread_attribs); pthread_attr_setdetachstate(&thread_attribs, PTHREAD_CREATE_DETACHED); addr_drone_video.sin_family = AF_INET; addr_drone_video.sin_addr.s_addr = inet_addr(WIFI_ARDRONE_IP); addr_drone_video.sin_port = htons(PORT_VIDEO); //initialiser le fdset FD_ZERO(&vid_fd_set); /* NOT NEEDED NOW //initialize the video buffer's extremity to zero to prevent //possible errors during the decoding process by ffmpeg. //Do not reference FF_INPUT_BUFFER_PADDING_SIZE directly to keep tasks as separated as possible. memset(tcp_buf+BASE_VIDEO_BUF_SIZE, 0, TCP_VIDEO_BUF_SIZE-BASE_VIDEO_BUF_SIZE); */ //initialize the video decoder if(video_init_decoder() < 0) { fprintf(stderr, "Error initializing decoder, aborting.\n"); pthread_attr_destroy(&thread_attribs); pthread_mutex_unlock(&mutex_init); return -1; } sock_video = socket(AF_INET, SOCK_STREAM, 0); if(sock_video < 0) { fprintf(stderr, "Error : couldn't bind TCP socket.\n"); video_stop_decoder(); pthread_attr_destroy(&thread_attribs); pthread_mutex_unlock(&mutex_init); return -1; } //bind du socket client pour le forcer sur le port choisi if(connect(sock_video, (struct sockaddr*)&addr_drone_video, sizeof(addr_drone_video)) < 0) { perror("Error connecting to video stream"); video_clean(); pthread_attr_destroy(&thread_attribs); pthread_mutex_unlock(&mutex_init); return -1; } //ajouter le socket au set pour select FD_SET(sock_video, &vid_fd_set); stopped = 0; terminated = 0; //démarrer la réception des packets vidéo if(pthread_create(&video_thread, &thread_attribs, video_routine, NULL) < 0) { perror("Error creating the main video thread"); stopped = 1; terminated = 1; video_clean(); pthread_attr_destroy(&thread_attribs); pthread_mutex_unlock(&mutex_init); return -1; } pthread_attr_destroy(&thread_attribs); //now that we're done initializing, release the lock. pthread_mutex_unlock(&mutex_init); return 0; }
void* video_routine(void* args) { //TCP segment of encoded video received from the drone static uint8_t tcp_buf[TCP_VIDEO_BUF_SIZE]; //size of this segment in bytes ssize_t pack_size = 0; //set to 1 by the decoding function if a decoded video frame is available int got_frame = 0; //structure that will hold our latest decoded video frame jakopter_video_frame_t decoded_frame; pthread_mutex_lock(&mutex_stopped); while(!stopped) { pthread_mutex_unlock(&mutex_stopped); //Wait for the drone to send data on the video socket if (select(sock_video+1, &vid_fd_set, NULL, NULL, &video_timeout) < 0) { perror("Error select()"); video_set_stopped(); } else if(FD_ISSET(sock_video, &vid_fd_set)) { /*receive the video data from the drone. Only BASE_SIZE, since TCP_SIZE may be larger on purpose.*/ pack_size = recv(sock_video, tcp_buf, BASE_VIDEO_BUF_SIZE, 0); if(pack_size == 0) { printf("Stream ended by server. Ending the video thread.\n"); video_set_stopped(); } else if(pack_size < 0) perror("Error recv()"); else { //we actually got some data, send it for decoding ! got_frame = video_decode_packet(tcp_buf, pack_size, &decoded_frame); if(got_frame < 0) { fprintf(stderr, "Error decoding video !\n"); video_set_stopped(); } //if we have a complete decoded frame, push it onto the queue for decoding else if(got_frame == 1) video_queue_push_frame(&decoded_frame); } } else { printf("Video : data reception has timed out. Ending the video thread now.\n"); video_set_stopped(); } //reset the timeout and the FDSET entry video_timeout.tv_sec = VIDEO_TIMEOUT; FD_ZERO(&vid_fd_set); FD_SET(sock_video, &vid_fd_set); pthread_mutex_lock(&mutex_stopped); } pthread_mutex_unlock(&mutex_stopped); /*push an empty frame on the queue so the processing thread knows it has to stop*/ video_queue_push_frame(&VIDEO_QUEUE_END); pthread_join(processing_thread, NULL); //there's no reason to keep stuff that's needed for our video thread once it's ended, so clean it now. video_clean(); pthread_exit(NULL); }
int jakopter_init_video() { //do not try to initialize the thread if it's already running ! pthread_mutex_lock(&mutex_stopped); if(!stopped) { fprintf(stderr, "Video thread already running.\n"); pthread_mutex_unlock(&mutex_stopped); return -1; } //make sure the thread is terminated video_join_thread(); addr_drone_video.sin_family = AF_INET; addr_drone_video.sin_addr.s_addr = inet_addr(WIFI_ARDRONE_IP); addr_drone_video.sin_port = htons(PORT_VIDEO); //initialize the fdset FD_ZERO(&vid_fd_set); //initialize the video decoder if(video_init_decoder() < 0) { fprintf(stderr, "Error initializing decoder, aborting.\n"); pthread_mutex_unlock(&mutex_stopped); return -1; } sock_video = socket(AF_INET, SOCK_STREAM, 0); if(sock_video < 0) { fprintf(stderr, "Error : couldn't bind TCP socket.\n"); video_stop_decoder(); pthread_mutex_unlock(&mutex_stopped); return -1; } //bind the client socket to force it on the drone's port if(connect(sock_video, (struct sockaddr*)&addr_drone_video, sizeof(addr_drone_video)) < 0) { perror("Error connecting to video stream"); video_clean(); pthread_mutex_unlock(&mutex_stopped); return -1; } //add the socket to the set, for use with select() FD_SET(sock_video, &vid_fd_set); //initialize the queue structure that handles decoding->processing data passing video_queue_init(); //start the threads responsible for video processing and reception if(pthread_create(&processing_thread, NULL, processing_routine, NULL) < 0) { perror("Error creating the video processing thread"); video_clean(); pthread_mutex_unlock(&mutex_stopped); return -1; } //make the reception thread detached so that it can close itself without us having //to join with it in order to free its resources. /*pthread_attr_t thread_attribs; pthread_attr_init(&thread_attribs); pthread_attr_setdetachstate(&thread_attribs, PTHREAD_CREATE_DETACHED);*/ if(pthread_create(&video_thread, NULL, video_routine, NULL) < 0) { perror("Error creating the main video thread"); video_clean(); //pthread_attr_destroy(&thread_attribs); pthread_mutex_unlock(&mutex_stopped); return -1; } //pthread_attr_destroy(&thread_attribs); //Initialization went OK -> set the guard variables so that the threads can start. if(frame_processing_init != NULL) frame_processing_init(); stopped = 0; terminated = 0; pthread_mutex_unlock(&mutex_stopped); return 0; }