mirror of
https://github.com/paparazzi/paparazzi.git
synced 2026-06-04 13:55:40 +08:00
[vision] add computer vision library in standard modules + 2 modules
- video RTP stream - image download for ARDrone2
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2013
|
||||
*
|
||||
* This file is part of Paparazzi.
|
||||
*
|
||||
* Paparazzi is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* Paparazzi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Paparazzi; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include "image.h"
|
||||
|
||||
inline void grayscale_uyvy(struct img_struct* input, struct img_struct* output);
|
||||
inline void grayscale_uyvy(struct img_struct* input, struct img_struct* output)
|
||||
{
|
||||
uint8_t *source = input->buf;
|
||||
uint8_t *dest = output->buf;
|
||||
source++;
|
||||
|
||||
for (int y=0;y<output->h;y++)
|
||||
{
|
||||
for (int x=0;x<output->w;x++)
|
||||
{
|
||||
// UYVY
|
||||
*dest++ = 127; // U
|
||||
*dest++ = *source; // Y
|
||||
source+=2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline int colorfilt_uyvy(struct img_struct* input, struct img_struct* output, uint8_t y_m, uint8_t y_M, uint8_t u_m, uint8_t u_M, uint8_t v_m, uint8_t v_M);
|
||||
inline int colorfilt_uyvy(struct img_struct* input, struct img_struct* output, uint8_t y_m, uint8_t y_M, uint8_t u_m, uint8_t u_M, uint8_t v_m, uint8_t v_M)
|
||||
{
|
||||
int cnt = 0;
|
||||
uint8_t *source = input->buf;
|
||||
uint8_t *dest = output->buf;
|
||||
|
||||
for (int y=0;y<output->h;y++)
|
||||
{
|
||||
for (int x=0;x<output->w;x+=2)
|
||||
{
|
||||
// Color Check:
|
||||
if (
|
||||
// Light
|
||||
(dest[1] >= y_m)
|
||||
&& (dest[1] <= y_M)
|
||||
&& (dest[0] >= u_m)
|
||||
&& (dest[0] <= u_M)
|
||||
&& (dest[2] >= v_m)
|
||||
&& (dest[2] <= v_M)
|
||||
)// && (dest[2] > 128))
|
||||
{
|
||||
cnt ++;
|
||||
// UYVY
|
||||
dest[0] = 64; // U
|
||||
dest[1] = source[1]; // Y
|
||||
dest[2] = 255; // V
|
||||
dest[3] = source[3]; // Y
|
||||
}
|
||||
else
|
||||
{
|
||||
// UYVY
|
||||
char u = source[0]-127;
|
||||
u/=4;
|
||||
dest[0] = 127; // U
|
||||
dest[1] = source[1]; // Y
|
||||
u = source[2]-127;
|
||||
u/=4;
|
||||
dest[2] = 127; // V
|
||||
dest[3] = source[3]; // Y
|
||||
}
|
||||
|
||||
dest+=4;
|
||||
source+=4;
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,45 @@
|
||||
|
||||
#ifndef __MY_JPEG_HEADER__
|
||||
#define __MY_JPEG_HEADER__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define FOUR_ZERO_ZERO 0
|
||||
#define FOUR_TWO_ZERO 1
|
||||
#define FOUR_TWO_TWO 2
|
||||
#define FOUR_FOUR_FOUR 3
|
||||
#define RGB 4
|
||||
|
||||
unsigned char *encode_image (
|
||||
uint8_t* in,
|
||||
uint8_t* out,
|
||||
uint32_t q, // image quality 1-8
|
||||
uint32_t fmt, // image format code
|
||||
uint32_t width, // image width
|
||||
uint32_t height, // image height
|
||||
uint8_t add_dri_header // data only or full jpeg file
|
||||
);
|
||||
|
||||
unsigned char *encode_image_rtp (
|
||||
uint8_t* in,
|
||||
uint8_t* out,
|
||||
uint32_t q, // image quality 1-8
|
||||
uint32_t fmt, // image format code
|
||||
uint32_t width, // image width
|
||||
uint32_t height, // image height
|
||||
uint8_t add_dri_header // data only or full jpeg file
|
||||
);
|
||||
|
||||
unsigned char *encode_image_std_qt (
|
||||
uint8_t* in,
|
||||
uint8_t* out,
|
||||
uint32_t q, // image quality 0 to 99
|
||||
uint32_t fmt, // image format code
|
||||
uint32_t width, // image width
|
||||
uint32_t height, // image height
|
||||
uint8_t add_dri_header // data only or full jpeg file
|
||||
);
|
||||
|
||||
int create_svs_jpeg_header(unsigned char* buf, int32_t size, int w);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,196 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "udp/socket.h"
|
||||
|
||||
#include "rtp.h"
|
||||
|
||||
void send_rtp_packet(struct UdpSocket *sock, uint8_t* Jpeg, int JpegLen, uint32_t m_SequenceNumber, uint32_t m_Timestamp, uint32_t m_offset, uint8_t marker_bit, int w, int h, uint8_t format_code, uint8_t quality_code, uint8_t has_dri_header);
|
||||
|
||||
// http://www.ietf.org/rfc/rfc3550.txt
|
||||
|
||||
#define KJpegCh1ScanDataLen 32
|
||||
#define KJpegCh2ScanDataLen 56
|
||||
|
||||
// RGB JPEG images as RTP payload - 64x48 pixel
|
||||
uint8_t JpegScanDataCh2A[KJpegCh2ScanDataLen] =
|
||||
{
|
||||
0xf8, 0xbe, 0x8a, 0x28, 0xaf, 0xe5, 0x33, 0xfd,
|
||||
0xfc, 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0x28, 0xa2,
|
||||
0x80, 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0x28, 0xa2,
|
||||
0x80, 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0x28, 0xa2,
|
||||
0x80, 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0x28, 0xa2,
|
||||
0x80, 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0x28, 0xa2,
|
||||
0x80, 0x0a, 0x28, 0xa2, 0x80, 0x3f, 0xff, 0xd9
|
||||
};
|
||||
uint8_t JpegScanDataCh2B[KJpegCh2ScanDataLen] =
|
||||
{
|
||||
0xf5, 0x8a, 0x28, 0xa2, 0xbf, 0xca, 0xf3, 0xfc,
|
||||
0x53, 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0x28, 0xa2,
|
||||
0x80, 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0x28, 0xa2,
|
||||
0x80, 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0x28, 0xa2,
|
||||
0x80, 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0x28, 0xa2,
|
||||
0x80, 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0x28, 0xa2,
|
||||
0x80, 0x0a, 0x28, 0xa2, 0x80, 0x3f, 0xff, 0xd9
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void test_rtp_frame(struct UdpSocket *sock)
|
||||
{
|
||||
static uint32_t framecounter = 0;
|
||||
static uint32_t timecounter = 0;
|
||||
static uint8_t toggle = 0;
|
||||
toggle = ! toggle;
|
||||
|
||||
uint8_t format_code = 0x01;
|
||||
uint8_t quality_code = 0x54;
|
||||
|
||||
if (toggle)
|
||||
{
|
||||
send_rtp_packet(sock, JpegScanDataCh2A,KJpegCh2ScanDataLen,framecounter, timecounter, 0, 1, 64, 48, format_code, quality_code, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
send_rtp_packet(sock, JpegScanDataCh2B,KJpegCh2ScanDataLen,framecounter, timecounter, 0, 1, 64, 48, format_code, quality_code, 0);
|
||||
}
|
||||
framecounter++;
|
||||
timecounter+=3600;
|
||||
}
|
||||
|
||||
|
||||
void send_rtp_frame(struct UdpSocket *sock, uint8_t * Jpeg, uint32_t JpegLen, int w, int h, uint8_t format_code, uint8_t quality_code, uint8_t has_dri_header, uint32_t delta_t)
|
||||
{
|
||||
static uint32_t packetcounter = 0;
|
||||
static uint32_t timecounter = 0;
|
||||
uint32_t offset = 0;
|
||||
|
||||
#define MAX_PACKET_SIZE 1400
|
||||
|
||||
if (delta_t <= 0)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, 0);
|
||||
uint32_t t = (tv.tv_sec % (256*256)) * 90000 + tv.tv_usec * 9 / 100;
|
||||
timecounter = t;
|
||||
}
|
||||
|
||||
// Split frame into packets
|
||||
for (;JpegLen > 0;)
|
||||
{
|
||||
uint32_t len = MAX_PACKET_SIZE;
|
||||
uint8_t lastpacket = 0;
|
||||
|
||||
if (JpegLen <= len)
|
||||
{
|
||||
lastpacket = 1;
|
||||
len = JpegLen;
|
||||
}
|
||||
|
||||
send_rtp_packet(sock, Jpeg,len,packetcounter, timecounter, offset, lastpacket, w, h, format_code, quality_code, has_dri_header);
|
||||
|
||||
JpegLen -= len;
|
||||
Jpeg += len;
|
||||
offset += len;
|
||||
packetcounter++;
|
||||
}
|
||||
|
||||
|
||||
if (delta_t > 0)
|
||||
{
|
||||
// timestamp = 1 / 90 000 seconds
|
||||
timecounter+=delta_t;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The RTP timestamp is in units of 90000Hz. The same timestamp MUST
|
||||
appear in each fragment of a given frame. The RTP marker bit MUST be
|
||||
set in the last packet of a frame.
|
||||
*
|
||||
*/
|
||||
|
||||
void send_rtp_packet(
|
||||
struct UdpSocket *sock,
|
||||
uint8_t * Jpeg, int JpegLen,
|
||||
uint32_t m_SequenceNumber, uint32_t m_Timestamp,
|
||||
uint32_t m_offset, uint8_t marker_bit,
|
||||
int w, int h,
|
||||
uint8_t format_code, uint8_t quality_code,
|
||||
uint8_t has_dri_header)
|
||||
{
|
||||
|
||||
#define KRtpHeaderSize 12 // size of the RTP header
|
||||
#define KJpegHeaderSize 8 // size of the special JPEG payload header
|
||||
|
||||
uint8_t RtpBuf[2048];
|
||||
int RtpPacketSize = JpegLen + KRtpHeaderSize + KJpegHeaderSize;
|
||||
|
||||
memset(RtpBuf,0x00,sizeof(RtpBuf));
|
||||
|
||||
/*
|
||||
The RTP header has the following format:
|
||||
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|V=2|P|X| CC |M| PT | sequence number |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| timestamp |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| synchronization source (SSRC) identifier |
|
||||
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
| contributing source (CSRC) identifiers |
|
||||
| .... |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* */
|
||||
|
||||
// Prepare the 12 byte RTP header
|
||||
RtpBuf[0] = 0x80; // RTP version
|
||||
RtpBuf[1] = 0x1a + (marker_bit<<7); // JPEG payload (26) and marker bit
|
||||
RtpBuf[2] = m_SequenceNumber >> 8;
|
||||
RtpBuf[3] = m_SequenceNumber & 0x0FF; // each packet is counted with a sequence counter
|
||||
RtpBuf[4] = (m_Timestamp & 0xFF000000) >> 24; // each image gets a timestamp
|
||||
RtpBuf[5] = (m_Timestamp & 0x00FF0000) >> 16;
|
||||
RtpBuf[6] = (m_Timestamp & 0x0000FF00) >> 8;
|
||||
RtpBuf[7] = (m_Timestamp & 0x000000FF);
|
||||
RtpBuf[8] = 0x13; // 4 byte SSRC (sychronization source identifier)
|
||||
RtpBuf[9] = 0xf9; // we just an arbitrary number here to keep it simple
|
||||
RtpBuf[10] = 0x7e;
|
||||
RtpBuf[11] = 0x67;
|
||||
|
||||
/* JPEG header", are as follows:
|
||||
*
|
||||
* http://tools.ietf.org/html/rfc2435
|
||||
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type-specific | Fragment Offset |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type | Q | Width | Height |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
|
||||
// Prepare the 8 byte payload JPEG header
|
||||
RtpBuf[12] = 0x00; // type specific
|
||||
RtpBuf[13] = (m_offset & 0x00FF0000) >> 16; // 3 byte fragmentation offset for fragmented images
|
||||
RtpBuf[14] = (m_offset & 0x0000FF00) >> 8;
|
||||
RtpBuf[15] = (m_offset & 0x000000FF);
|
||||
RtpBuf[16] = 0x00; // type: 0 422 or 1 421
|
||||
RtpBuf[17] = 60; // quality scale factor
|
||||
RtpBuf[16] = format_code; // type: 0 422 or 1 421
|
||||
if (has_dri_header)
|
||||
RtpBuf[16] |= 0x40; // DRI flag
|
||||
RtpBuf[17] = quality_code; // quality scale factor
|
||||
RtpBuf[18] = w/8; // width / 8 -> 48 pixel
|
||||
RtpBuf[19] = h/8; // height / 8 -> 32 pixel
|
||||
// append the JPEG scan data to the RTP buffer
|
||||
memcpy(&RtpBuf[20],Jpeg,JpegLen);
|
||||
|
||||
udp_write(sock,RtpBuf,RtpPacketSize);
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include "udp/socket.h"
|
||||
|
||||
void send_rtp_frame(
|
||||
struct UdpSocket *sock, // socket
|
||||
uint8_t * Jpeg, uint32_t JpegLen, // jpeg data
|
||||
int w, int h, // width and height
|
||||
uint8_t format_code, // 0=422, 1=421
|
||||
uint8_t quality_code, // 0-99 of 128 for custom (include
|
||||
uint8_t has_dri_header, // Does Jpeg data include Header Info?
|
||||
uint32_t delta_t // time step 90kHz
|
||||
);
|
||||
|
||||
void test_rtp_frame(struct UdpSocket *sock);
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2013
|
||||
*
|
||||
* This file is part of Paparazzi.
|
||||
*
|
||||
* Paparazzi is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* Paparazzi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Paparazzi; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _MY_IMAGE_HEADER_
|
||||
#define _MY_IMAGE_HEADER_
|
||||
|
||||
|
||||
struct img_struct {
|
||||
int seq;
|
||||
double timestamp;
|
||||
unsigned char *buf;
|
||||
int w;
|
||||
int h;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2013
|
||||
*
|
||||
* This file is part of Paparazzi.
|
||||
*
|
||||
* Paparazzi is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* Paparazzi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Paparazzi; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include "image.h"
|
||||
|
||||
inline void resize_uyuv(struct img_struct* input, struct img_struct* output, int downsample);
|
||||
inline void resize_uyuv(struct img_struct* input, struct img_struct* output, int downsample)
|
||||
{
|
||||
uint8_t *source = input->buf;
|
||||
uint8_t *dest = output->buf;
|
||||
|
||||
int pixelskip = downsample-1;
|
||||
for (int y=0;y<output->h;y++)
|
||||
{
|
||||
for (int x=0;x<output->w;x+=2)
|
||||
{
|
||||
// YUYV
|
||||
*dest++ = *source++; // U
|
||||
*dest++ = *source++; // Y
|
||||
// now skip 3 pixels
|
||||
if (pixelskip) source+=(pixelskip+1)*2;
|
||||
*dest++ = *source++; // U
|
||||
*dest++ = *source++; // V
|
||||
if (pixelskip) source+=(pixelskip-1)*2;
|
||||
}
|
||||
// skip 3 rows
|
||||
if (pixelskip) source += pixelskip * input->w * 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Gautier Hattenberger <gautier.hattenberger@enac.fr>
|
||||
*
|
||||
* This file is part of Paparazzi.
|
||||
*
|
||||
* Paparazzi is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* Paparazzi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with paparazzi; see the file COPYING. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file modules/computer_vision/image_nc_send.c
|
||||
*
|
||||
* Capture an image on an ARDrone2 and send it to the ground with netcat (nc)
|
||||
*/
|
||||
|
||||
// Own header
|
||||
#include "modules/computer_vision/image_nc_send.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
// Video
|
||||
#include "modules/computer_vision/lib/v4l/video.h"
|
||||
#include "modules/computer_vision/cv/resize.h"
|
||||
#include "modules/computer_vision/cv/encoding/jpeg.h"
|
||||
|
||||
// Threaded computer vision
|
||||
#include <pthread.h>
|
||||
|
||||
// Default netcat server IP (destination)
|
||||
#ifndef IMAGE_SERVER_IP
|
||||
#define IMAGE_SERVER_IP "192.168.1.2"
|
||||
#endif
|
||||
|
||||
// Default netcat port
|
||||
#ifndef IMAGE_SERVER_PORT
|
||||
#define IMAGE_SERVER_PORT 4900
|
||||
#endif
|
||||
|
||||
// Default downsize factor
|
||||
#ifndef IMAGE_DOWNSIZE_FACTOR
|
||||
#define IMAGE_DOWNSIZE_FACTOR 1
|
||||
#endif
|
||||
|
||||
// JPEG compression quality factor from 0 to 99 (99=high)
|
||||
#ifndef IMAGE_QUALITY_FACTOR
|
||||
#define IMAGE_QUALITY_FACTOR 99
|
||||
#endif
|
||||
|
||||
// Frame Per Second
|
||||
#ifndef IMAGE_FPS
|
||||
#define IMAGE_FPS (1./6.)
|
||||
#endif
|
||||
|
||||
// Save images by default
|
||||
#ifndef IMAGE_SAVE
|
||||
#define IMAGE_SAVE 1
|
||||
#endif
|
||||
|
||||
void image_nc_send_run(void) {}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// COMPUTER VISION THREAD
|
||||
|
||||
pthread_t computervision_thread;
|
||||
volatile uint8_t computervision_thread_status = 0;
|
||||
volatile uint8_t computer_vision_thread_command = 0;
|
||||
void *computervision_thread_main(void* data);
|
||||
void *computervision_thread_main(void* data)
|
||||
{
|
||||
// Video Input
|
||||
struct vid_struct vid;
|
||||
vid.device = (char*)"/dev/video1";
|
||||
vid.w=1280;
|
||||
vid.h=720;
|
||||
vid.n_buffers = 4;
|
||||
if (video_init(&vid)<0) {
|
||||
printf("Error initialising video\n");
|
||||
computervision_thread_status = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Frame Grabbing
|
||||
struct img_struct* img_new = video_create_image(&vid);
|
||||
|
||||
// Frame Resizing
|
||||
uint8_t quality_factor = IMAGE_QUALITY_FACTOR;
|
||||
uint8_t dri_jpeg_header = 1;
|
||||
|
||||
struct img_struct small;
|
||||
small.w = vid.w / IMAGE_DOWNSIZE_FACTOR;
|
||||
small.h = vid.h / IMAGE_DOWNSIZE_FACTOR;
|
||||
small.buf = (uint8_t*)malloc(small.w*small.h*2);
|
||||
|
||||
// Commpressed image buffer
|
||||
uint8_t* jpegbuf = (uint8_t*)malloc(vid.h*vid.w*2);
|
||||
|
||||
// file index (search from 0)
|
||||
int file_index = 0;
|
||||
|
||||
int microsleep = (int)(1000000. / IMAGE_FPS);
|
||||
|
||||
while (computer_vision_thread_command > 0)
|
||||
{
|
||||
usleep(microsleep);
|
||||
video_grab_image(&vid, img_new);
|
||||
|
||||
// Resize
|
||||
resize_uyuv(img_new, &small, IMAGE_DOWNSIZE_FACTOR);
|
||||
|
||||
// JPEG encode the image:
|
||||
uint32_t image_format = FOUR_TWO_TWO; // format (in jpeg.h)
|
||||
uint8_t* end = encode_image (small.buf, jpegbuf, quality_factor, image_format, small.w, small.h, dri_jpeg_header);
|
||||
uint32_t size = end-(jpegbuf);
|
||||
|
||||
#if IMAGE_SAVE
|
||||
FILE* save;
|
||||
char save_name[128];
|
||||
if (system("mkdir -p /data/video/images") == 0) {
|
||||
// search available index (max is 99)
|
||||
for ( ; file_index < 99; file_index++) {
|
||||
printf("search %d\n",file_index);
|
||||
sprintf(save_name,"/data/video/images/img_%02d.jpg",file_index);
|
||||
// test if file exists or not
|
||||
if (access(save_name, F_OK) == -1) {
|
||||
printf("access\n");
|
||||
save = fopen(save_name, "w");
|
||||
if (save != NULL) {
|
||||
fwrite(jpegbuf, sizeof(uint8_t), size, save);
|
||||
fclose(save);
|
||||
}
|
||||
else {
|
||||
printf("Error when opening file %s\n", save_name);
|
||||
}
|
||||
// leave for loop
|
||||
break;
|
||||
}
|
||||
else {printf("file exists\n");}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Fork process
|
||||
int status;
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid == 0) {
|
||||
// Open process to send using netcat in child process
|
||||
char nc_cmd[64];
|
||||
sprintf(nc_cmd, "nc %s %d", IMAGE_SERVER_IP, IMAGE_SERVER_PORT);
|
||||
FILE* netcat;
|
||||
netcat = popen(nc_cmd, "w");
|
||||
if (netcat != NULL) {
|
||||
fwrite(jpegbuf, sizeof(uint8_t), size, netcat);
|
||||
if (pclose(netcat) == 0) {
|
||||
printf("Sending image succesfully\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("Fail sending image\n");
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
else if (pid < 0) {
|
||||
printf("Fork failed\n");
|
||||
}
|
||||
else {
|
||||
// Parent is waiting for child to terminate
|
||||
wait(&status);
|
||||
}
|
||||
|
||||
}
|
||||
printf("Thread Closed\n");
|
||||
video_close(&vid);
|
||||
computervision_thread_status = -100;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void image_nc_send_start(void)
|
||||
{
|
||||
computer_vision_thread_command = 1;
|
||||
int rc = pthread_create(&computervision_thread, NULL, computervision_thread_main, NULL);
|
||||
if(rc) {
|
||||
printf("ctl_Init: Return code from pthread_create(mot_thread) is %d\n", rc);
|
||||
}
|
||||
}
|
||||
|
||||
void image_nc_send_stop(void)
|
||||
{
|
||||
computer_vision_thread_command = 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Gautier Hattenberger <gautier.hattenberger@enac.fr>
|
||||
*
|
||||
* This file is part of Paparazzi.
|
||||
*
|
||||
* Paparazzi is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* Paparazzi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with paparazzi; see the file COPYING. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file modules/computer_vision/image_nc_send.h
|
||||
*
|
||||
* Capture an image on an ARDrone2 and send it to the ground with netcat (nc)
|
||||
*/
|
||||
|
||||
#ifndef IMAGE_NC_SEND_H
|
||||
#define IMAGE_NC_SEND_H
|
||||
|
||||
// Module functions
|
||||
extern void image_nc_send_run(void);
|
||||
extern void image_nc_send_start(void);
|
||||
extern void image_nc_send_stop(void);
|
||||
|
||||
#endif /* IMAGE_NC_SEND_H */
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Gautier Hattenberger
|
||||
*
|
||||
* This file is part of Paparazzi.
|
||||
*
|
||||
* Paparazzi is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* Paparazzi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Paparazzi; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
// Own header
|
||||
#include "image_capture.h"
|
||||
|
||||
void image_capture_run(void) {}
|
||||
|
||||
void image_capture_start(void) {}
|
||||
|
||||
void image_capture_stop(void) {}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
#include "socket.h"
|
||||
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
# define ADDR_SIZE_TYPE socklen_t
|
||||
# define SOCKET_ERROR -1
|
||||
# define IO_SOCKET ioctl
|
||||
|
||||
struct UdpSocket* udp_socket(const char* str_ip_out, const int port_out, const int port_in, const int broadcast)
|
||||
{
|
||||
|
||||
struct UdpSocket* me = malloc(sizeof(struct UdpSocket));
|
||||
|
||||
int so_reuseaddr = 1;
|
||||
me->socket_out = socket( AF_INET, SOCK_DGRAM, 0);
|
||||
setsockopt(me->socket_out, SOL_SOCKET, SO_REUSEADDR,
|
||||
&so_reuseaddr, sizeof(so_reuseaddr));
|
||||
|
||||
/* only set broadcast option if explicitly enabled */
|
||||
if (broadcast)
|
||||
setsockopt(me->socket_out, SOL_SOCKET, SO_BROADCAST,
|
||||
&broadcast, sizeof(broadcast));
|
||||
|
||||
me->addr_out.sin_family = AF_INET;
|
||||
me->addr_out.sin_port = htons(port_out);
|
||||
me->addr_out.sin_addr.s_addr = inet_addr(str_ip_out);
|
||||
|
||||
me->socket_in = socket( AF_INET, SOCK_DGRAM, 0);
|
||||
setsockopt(me->socket_in, SOL_SOCKET, SO_REUSEADDR,
|
||||
&so_reuseaddr, sizeof(so_reuseaddr));
|
||||
|
||||
me->addr_in.sin_family = AF_INET;
|
||||
me->addr_in.sin_port = htons(port_in);
|
||||
me->addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
bind(me->socket_in, (struct sockaddr *)&me->addr_in, sizeof(me->addr_in));
|
||||
|
||||
return me;
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
//#define UDP_MODE MSG_DONTWAIT
|
||||
#define UDP_MODE 0
|
||||
|
||||
int udp_write(struct UdpSocket* me, unsigned char* buf, int len) {
|
||||
sendto(me->socket_out, buf, len, UDP_MODE,
|
||||
(struct sockaddr*)&me->addr_out, sizeof(me->addr_out));
|
||||
//printf("sendto ret=%d\n",ret);
|
||||
return len;
|
||||
}
|
||||
|
||||
unsigned long MIN(unsigned long a, unsigned long b);
|
||||
unsigned long MIN(unsigned long a, unsigned long b)
|
||||
{
|
||||
if (a<b) return a;
|
||||
return b;
|
||||
}
|
||||
|
||||
int udp_read(struct UdpSocket* me, unsigned char* buf, int len)
|
||||
{
|
||||
unsigned long toread = 0;
|
||||
int btr = 1; // set to >0 in order to start the reading loop
|
||||
int newbytes = 0;
|
||||
|
||||
int status;
|
||||
|
||||
// if socket is connected
|
||||
for (;btr>0;)
|
||||
{
|
||||
// Check Status
|
||||
status = IO_SOCKET(me->socket_in, FIONREAD, &toread);
|
||||
if(status == SOCKET_ERROR) {
|
||||
printf("problem receiving from socket\n");
|
||||
break;
|
||||
}
|
||||
|
||||
//printf("UDP has %d bytes\n", toread);
|
||||
if (toread <= 0)
|
||||
break;
|
||||
|
||||
// If status: ok and new data: read it
|
||||
btr = MIN(toread,(unsigned long)len);
|
||||
recvfrom(me->socket_in, buf, btr, 0, (struct sockaddr*)&me->addr_in, (socklen_t *) sizeof(me->addr_in) );
|
||||
newbytes += btr;
|
||||
}
|
||||
return newbytes;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef SOCKET_H
|
||||
#define SOCKET_H
|
||||
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define FMS_UNICAST 0
|
||||
#define FMS_BROADCAST 1
|
||||
|
||||
struct UdpSocket {
|
||||
int socket_in;
|
||||
int socket_out;
|
||||
struct sockaddr_in addr_in;
|
||||
struct sockaddr_in addr_out;
|
||||
};
|
||||
|
||||
|
||||
extern struct UdpSocket* udp_socket(const char* str_ip_out, const int port_out, const int port_in, const int broadcast);
|
||||
extern int udp_write(struct UdpSocket* me, unsigned char* buf, int len);
|
||||
extern int udp_read(struct UdpSocket* me, unsigned char* buf, int len);
|
||||
|
||||
|
||||
#endif /* SOCKET_H */
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
video.c - video driver
|
||||
|
||||
Copyright (C) 2011 Hugo Perquin - http://blog.perquin.com
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <getopt.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <asm/types.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "video.h"
|
||||
|
||||
#define CLEAR(x) memset (&(x), 0, sizeof (x))
|
||||
|
||||
|
||||
pthread_t video_thread;
|
||||
void *video_thread_main(void* data);
|
||||
void *video_thread_main(void* data)
|
||||
{
|
||||
struct vid_struct* vid = (struct vid_struct*)data;
|
||||
printf("video_thread_main started\n");
|
||||
while (1) {
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
int r;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(vid->fd, &fds);
|
||||
|
||||
tv.tv_sec = 2;
|
||||
tv.tv_usec = 0;
|
||||
r = select(vid->fd + 1, &fds, NULL, NULL, &tv);
|
||||
|
||||
if (-1 == r) {
|
||||
if (EINTR == errno) continue;
|
||||
printf("select err\n");
|
||||
}
|
||||
|
||||
if (0 == r) {
|
||||
fprintf(stderr, "select timeout\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct v4l2_buffer buf;
|
||||
|
||||
CLEAR(buf);
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
if (ioctl(vid->fd, VIDIOC_DQBUF, &buf) < 0) {
|
||||
printf("ioctl() VIDIOC_DQBUF failed.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
assert(buf.index < vid->n_buffers);
|
||||
|
||||
vid->seq++;
|
||||
|
||||
if(vid->trigger) {
|
||||
|
||||
// todo add timestamp again
|
||||
//vid->img->timestamp = util_timestamp();
|
||||
vid->img->seq = vid->seq;
|
||||
memcpy(vid->img->buf, vid->buffers[buf.index].buf, vid->w*vid->h*2);
|
||||
vid->trigger=0;
|
||||
}
|
||||
|
||||
if (ioctl(vid->fd, VIDIOC_QBUF, &buf) < 0) {
|
||||
printf("ioctl() VIDIOC_QBUF failed.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int video_init(struct vid_struct *vid)
|
||||
{
|
||||
struct v4l2_capability cap;
|
||||
struct v4l2_format fmt;
|
||||
unsigned int i;
|
||||
enum v4l2_buf_type type;
|
||||
|
||||
vid->seq=0;
|
||||
vid->trigger=0;
|
||||
if(vid->n_buffers==0) vid->n_buffers=4;
|
||||
|
||||
vid->fd = open(vid->device, O_RDWR | O_NONBLOCK, 0);
|
||||
|
||||
if (ioctl(vid->fd, VIDIOC_QUERYCAP, &cap) < 0) {
|
||||
printf("ioctl() VIDIOC_QUERYCAP failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//printf("2 driver = %s, card = %s, version = %d, capabilities = 0x%x\n", cap.driver, cap.card, cap.version, cap.capabilities);
|
||||
|
||||
CLEAR(fmt);
|
||||
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
fmt.fmt.pix.width = vid->w;
|
||||
fmt.fmt.pix.height = vid->h;
|
||||
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
|
||||
|
||||
if (ioctl(vid->fd, VIDIOC_S_FMT, &fmt) < 0) {
|
||||
printf("ioctl() VIDIOC_S_FMT failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//image_size = fmt.fmt.pix.width * fmt.fmt.pix.height *3/2;
|
||||
|
||||
struct v4l2_requestbuffers req;
|
||||
|
||||
CLEAR(req);
|
||||
req.count = vid->n_buffers;
|
||||
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
req.memory = V4L2_MEMORY_MMAP;
|
||||
|
||||
if (ioctl(vid->fd, VIDIOC_REQBUFS, &req) < 0) {
|
||||
printf("ioctl() VIDIOC_REQBUFS failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Buffer count = %d\n", vid->n_buffers);
|
||||
|
||||
vid->buffers = (struct buffer_struct*)calloc(vid->n_buffers, sizeof(struct buffer_struct));
|
||||
|
||||
for (i = 0; i < vid->n_buffers; ++i) {
|
||||
struct v4l2_buffer buf;
|
||||
|
||||
CLEAR(buf);
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
buf.index = i;
|
||||
|
||||
if (ioctl(vid->fd, VIDIOC_QUERYBUF, &buf) < 0) {
|
||||
printf("ioctl() VIDIOC_QUERYBUF failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
vid->buffers[i].length = buf.length;
|
||||
printf("buffer%d.length=%d\n",i,buf.length);
|
||||
vid->buffers[i].buf = mmap(NULL, buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, vid->fd, buf.m.offset);
|
||||
|
||||
if (MAP_FAILED == vid->buffers[i].buf) {
|
||||
printf ("mmap() failed.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < vid->n_buffers; ++i) {
|
||||
struct v4l2_buffer buf;
|
||||
|
||||
CLEAR(buf);
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
buf.index = i;
|
||||
|
||||
if (ioctl(vid->fd, VIDIOC_QBUF, &buf) < 0) {
|
||||
printf("ioctl() VIDIOC_QBUF failed.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (ioctl(vid->fd, VIDIOC_STREAMON, &type)< 0) {
|
||||
printf("ioctl() VIDIOC_STREAMON failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//start video thread
|
||||
int rc = pthread_create(&video_thread, NULL, video_thread_main, vid);
|
||||
if(rc) {
|
||||
printf("ctl_Init: Return code from pthread_create(mot_thread) is %d\n", rc);
|
||||
return 202;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void video_close(struct vid_struct *vid)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < (int)vid->n_buffers; ++i) {
|
||||
if (-1 == munmap(vid->buffers[i].buf, vid->buffers[i].length)) printf("munmap() failed.\n");
|
||||
}
|
||||
close(vid->fd);
|
||||
}
|
||||
|
||||
struct img_struct *video_create_image(struct vid_struct *vid)
|
||||
{
|
||||
struct img_struct* img = (struct img_struct*)malloc(sizeof(struct img_struct));
|
||||
img->w=vid->w;
|
||||
img->h=vid->h;
|
||||
img->buf = (unsigned char*)malloc(vid->h*vid->w*2);
|
||||
return img;
|
||||
}
|
||||
|
||||
pthread_mutex_t video_grab_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
void video_grab_image(struct vid_struct *vid, struct img_struct *img) {
|
||||
pthread_mutex_lock(&video_grab_mutex);
|
||||
vid->img = img;
|
||||
vid->trigger=1;
|
||||
// while(vid->trigger) pthread_yield();
|
||||
while(vid->trigger) usleep(1);
|
||||
pthread_mutex_unlock(&video_grab_mutex);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
video.h - video driver
|
||||
|
||||
Copyright (C) 2011 Hugo Perquin - http://blog.perquin.com
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _VIDEO_H
|
||||
#define _VIDEO_H
|
||||
|
||||
#include "../../cv/image.h"
|
||||
|
||||
struct buffer_struct {
|
||||
void * buf;
|
||||
size_t length;
|
||||
};
|
||||
|
||||
struct vid_struct {
|
||||
char *device;
|
||||
int w;
|
||||
int h;
|
||||
int seq;
|
||||
unsigned int n_buffers;
|
||||
|
||||
//private members
|
||||
int trigger;
|
||||
struct img_struct *img;
|
||||
struct buffer_struct * buffers;
|
||||
int fd;
|
||||
};
|
||||
|
||||
|
||||
int video_init(struct vid_struct *vid);
|
||||
struct img_struct *video_create_image(struct vid_struct *vid);
|
||||
|
||||
void video_grab_image(struct vid_struct *vid, struct img_struct *img);
|
||||
void video_close(struct vid_struct *vid);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2014 The Paparazzi Community
|
||||
*
|
||||
* This file is part of Paparazzi.
|
||||
*
|
||||
* Paparazzi is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* Paparazzi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with paparazzi; see the file COPYING. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file modules/computer_vision/viewvideo.c
|
||||
*
|
||||
* Get live images from a RTP/UDP stream
|
||||
* and save pictures on internal memory
|
||||
*
|
||||
* Works on Linux platforms
|
||||
*/
|
||||
|
||||
// Own header
|
||||
#include "modules/computer_vision/viewvideo.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
// UDP RTP Images
|
||||
#include "modules/computer_vision/lib/udp/socket.h"
|
||||
// Video
|
||||
#include "modules/computer_vision/lib/v4l/video.h"
|
||||
#include "modules/computer_vision/cv/resize.h"
|
||||
#include "modules/computer_vision/cv/encoding/jpeg.h"
|
||||
#include "modules/computer_vision/cv/encoding/rtp.h"
|
||||
|
||||
// Threaded computer vision
|
||||
#include <pthread.h>
|
||||
|
||||
// Default broadcast IP
|
||||
#ifndef VIDEO_SOCK_IP
|
||||
#define VIDEO_SOCK_IP "192.168.1.255"
|
||||
#endif
|
||||
|
||||
// Output socket can be defined from an offset
|
||||
#ifdef VIDEO_SOCK_OUT_OFFSET
|
||||
#define VIDEO_SOCK_OUT (5000+VIDEO_SOCK_OUT_OFFSET)
|
||||
#endif
|
||||
|
||||
#ifndef VIDEO_SOCK_OUT
|
||||
#define VIDEO_SOCK_OUT 5000
|
||||
#endif
|
||||
|
||||
#ifndef VIDEO_SOCK_IN
|
||||
#define VIDEO_SOCK_IN 4999
|
||||
#endif
|
||||
|
||||
// Downsize factor for video stream
|
||||
#ifndef VIDEO_DOWNSIZE_FACTOR
|
||||
#define VIDEO_DOWNSIZE_FACTOR 4
|
||||
#endif
|
||||
|
||||
// From 0 to 99 (99=high)
|
||||
#ifndef VIDEO_QUALITY_FACTOR
|
||||
#define VIDEO_QUALITY_FACTOR 50
|
||||
#endif
|
||||
|
||||
// Frame Per Seconds
|
||||
#ifndef VIDEO_FPS
|
||||
#define VIDEO_FPS 4.
|
||||
#endif
|
||||
|
||||
void viewvideo_run(void) {}
|
||||
|
||||
// take shot flag
|
||||
int viewvideo_shot = 0;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// COMPUTER VISION THREAD
|
||||
|
||||
pthread_t computervision_thread;
|
||||
volatile uint8_t computervision_thread_status = 0;
|
||||
volatile uint8_t computer_vision_thread_command = 0;
|
||||
void *computervision_thread_main(void* data);
|
||||
void *computervision_thread_main(void* data)
|
||||
{
|
||||
// Video Input
|
||||
struct vid_struct vid;
|
||||
vid.device = (char*)"/dev/video1";
|
||||
vid.w=1280;
|
||||
vid.h=720;
|
||||
vid.n_buffers = 4;
|
||||
if (video_init(&vid)<0) {
|
||||
printf("Error initialising video\n");
|
||||
computervision_thread_status = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Video Grabbing
|
||||
struct img_struct* img_new = video_create_image(&vid);
|
||||
|
||||
// Video Resizing
|
||||
uint8_t quality_factor = VIDEO_QUALITY_FACTOR;
|
||||
uint8_t dri_jpeg_header = 0;
|
||||
int microsleep = (int)(1000000. / VIDEO_FPS);
|
||||
|
||||
struct img_struct small;
|
||||
small.w = vid.w / VIDEO_DOWNSIZE_FACTOR;
|
||||
small.h = vid.h / VIDEO_DOWNSIZE_FACTOR;
|
||||
small.buf = (uint8_t*)malloc(small.w*small.h*2);
|
||||
|
||||
// Video Compression
|
||||
uint8_t* jpegbuf = (uint8_t*)malloc(vid.h*vid.w*2);
|
||||
|
||||
// Network Transmit
|
||||
struct UdpSocket* vsock;
|
||||
vsock = udp_socket(VIDEO_SOCK_IP, VIDEO_SOCK_OUT, VIDEO_SOCK_IN, FMS_BROADCAST);
|
||||
|
||||
// Create SPD file and make folder if necessary
|
||||
FILE* sdp;
|
||||
if (system("mkdir -p /data/video/sdp") == 0) {
|
||||
sdp = fopen("/data/video/sdp/x86_config-mjpeg.sdp","w");
|
||||
if (sdp != NULL) {
|
||||
fprintf(sdp, "v=0\n");
|
||||
fprintf(sdp, "m=video %d RTP/AVP 26\n", (int)(VIDEO_SOCK_OUT));
|
||||
fprintf(sdp, "c=IN IP4 0.0.0.0");
|
||||
fclose(sdp);
|
||||
}
|
||||
}
|
||||
|
||||
// file index (search from 0)
|
||||
int file_index = 0;
|
||||
|
||||
// time
|
||||
struct timeval last_time;
|
||||
gettimeofday(&last_time, NULL);
|
||||
|
||||
while (computer_vision_thread_command > 0)
|
||||
{
|
||||
// compute usleep to have a more stable frame rate
|
||||
struct timeval time;
|
||||
gettimeofday(&time, NULL);
|
||||
int dt = (int)(time.tv_sec - last_time.tv_sec)*1000000 + (int)(time.tv_usec - last_time.tv_usec);
|
||||
if (dt < microsleep) usleep(microsleep - dt);
|
||||
last_time = time;
|
||||
|
||||
// Grab new frame
|
||||
video_grab_image(&vid, img_new);
|
||||
|
||||
// Save picture on disk
|
||||
if (computer_vision_thread_command == 2)
|
||||
{
|
||||
uint8_t* end = encode_image (img_new->buf, jpegbuf, 99, FOUR_TWO_TWO, vid.w, vid.h, 1);
|
||||
uint32_t size = end-(jpegbuf);
|
||||
FILE* save;
|
||||
char save_name[128];
|
||||
if (system("mkdir -p /data/video/images") == 0) {
|
||||
// search available index (max is 99)
|
||||
for ( ; file_index < 99; file_index++) {
|
||||
printf("search %d\n",file_index);
|
||||
sprintf(save_name,"/data/video/images/img_%02d.jpg",file_index);
|
||||
// test if file exists or not
|
||||
if (access(save_name, F_OK) == -1) {
|
||||
printf("access\n");
|
||||
save = fopen(save_name, "w");
|
||||
if (save != NULL) {
|
||||
fwrite(jpegbuf, sizeof(uint8_t), size, save);
|
||||
fclose(save);
|
||||
}
|
||||
else {
|
||||
printf("Error when opening file %s\n", save_name);
|
||||
}
|
||||
// leave for loop
|
||||
break;
|
||||
} else {
|
||||
printf("file exists\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
computer_vision_thread_command = 1;
|
||||
viewvideo_shot = 0;
|
||||
}
|
||||
|
||||
// Resize
|
||||
resize_uyuv(img_new, &small, VIDEO_DOWNSIZE_FACTOR);
|
||||
|
||||
// JPEG encode the image:
|
||||
uint32_t image_format = FOUR_TWO_TWO; // format (in jpeg.h)
|
||||
uint8_t* end = encode_image (small.buf, jpegbuf, quality_factor, image_format, small.w, small.h, dri_jpeg_header);
|
||||
uint32_t size = end - (jpegbuf);
|
||||
|
||||
// Send image with RTP
|
||||
printf("Sending an image ...%u\n",size);
|
||||
send_rtp_frame(
|
||||
vsock, // UDP
|
||||
jpegbuf,size, // JPEG
|
||||
small.w, small.h, // Img Size
|
||||
0, // Format 422
|
||||
quality_factor, // Jpeg-Quality
|
||||
dri_jpeg_header, // DRI Header
|
||||
1 // 90kHz time increment
|
||||
);
|
||||
// Extra note: when the time increment is set to 0,
|
||||
// it is automaticaly calculated by the send_rtp_frame function
|
||||
// based on gettimeofday value. This seems to introduce some lag or jitter.
|
||||
// An other way is to compute the time increment and set the correct value.
|
||||
// It seems that a lower value is also working (when the frame is received
|
||||
// the timestamp is always "late" so the frame is displayed immediately).
|
||||
// Here, we set the time increment to the lowest possible value
|
||||
// (1 = 1/90000 s) which is probably stupid but is actually working.
|
||||
}
|
||||
printf("Thread Closed\n");
|
||||
video_close(&vid);
|
||||
computervision_thread_status = -100;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void viewvideo_start(void)
|
||||
{
|
||||
computer_vision_thread_command = 1;
|
||||
int rc = pthread_create(&computervision_thread, NULL, computervision_thread_main, NULL);
|
||||
if(rc) {
|
||||
printf("ctl_Init: Return code from pthread_create(mot_thread) is %d\n", rc);
|
||||
}
|
||||
}
|
||||
|
||||
void viewvideo_stop(void)
|
||||
{
|
||||
computer_vision_thread_command = 0;
|
||||
}
|
||||
|
||||
int viewvideo_save_shot(void)
|
||||
{
|
||||
if (computer_vision_thread_command > 0) {
|
||||
computer_vision_thread_command = 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2014 The Paparazzi Community
|
||||
*
|
||||
* This file is part of Paparazzi.
|
||||
*
|
||||
* Paparazzi is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* Paparazzi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with paparazzi; see the file COPYING. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file modules/computer_vision/viewvideo.h
|
||||
*
|
||||
* Get live images from a RTP/UDP stream
|
||||
* and save pictures on internal memory
|
||||
*
|
||||
* Works on Linux platforms
|
||||
*/
|
||||
|
||||
#ifndef VIEW_VIDEO_H
|
||||
#define VIEW_VIDEO_H
|
||||
|
||||
// Module functions
|
||||
extern void viewvideo_run(void);
|
||||
extern void viewvideo_start(void);
|
||||
extern void viewvideo_stop(void);
|
||||
|
||||
// Save picture on disk at full resolution
|
||||
// can be called from flight plan
|
||||
extern int viewvideo_save_shot(void);
|
||||
|
||||
extern int viewvideo_shot;
|
||||
#define viewvideo_SaveShot(_v) { \
|
||||
viewvideo_shot = 1; \
|
||||
viewvideo_save_shot(); \
|
||||
}
|
||||
|
||||
#endif /* VIEW_VIDEO_H */
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2013
|
||||
*
|
||||
* This file is part of Paparazzi.
|
||||
*
|
||||
* Paparazzi is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* Paparazzi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Paparazzi; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/** Dummy C implementation for simulation
|
||||
*/
|
||||
|
||||
// Own header
|
||||
#include "viewvideo.h"
|
||||
|
||||
int viewvideo_shot = 0;
|
||||
|
||||
void viewvideo_run(void) {}
|
||||
void viewvideo_start(void) {}
|
||||
void viewvideo_stop(void) {}
|
||||
|
||||
int viewvideo_save_shot(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
# base address for ARDrone2
|
||||
ADDR_BASE=192.168.1.
|
||||
|
||||
# tmp folder for images files (relative path by default)
|
||||
IMAGES_DIR=${PAPARAZZI_HOME=../../../..}/var/images_tmp
|
||||
|
||||
# test if a complete IP address is passed as first argument or just the last digit
|
||||
if [ `grep -c '\.' <<< $1` == 1 ]
|
||||
then
|
||||
ADDR=$1
|
||||
else
|
||||
ADDR=$ADDR_BASE$1
|
||||
fi
|
||||
|
||||
# download images folder from ARDrone
|
||||
mkdir -p $IMAGES_DIR/$ADDR
|
||||
../ardrone2.py --host=$ADDR download_dir $IMAGES_DIR/$ADDR images
|
||||
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
# base address for ARDrone2
|
||||
ADDR_BASE=192.168.1.
|
||||
|
||||
# test if a complete IP address is passed as first argument or just the last digit
|
||||
if [ `grep -c '\.' <<< $1` == 1 ]
|
||||
then
|
||||
ADDR=$1
|
||||
PORT=$2
|
||||
else
|
||||
ADDR=$ADDR_BASE$1
|
||||
PORT=$((5000+$1))
|
||||
fi
|
||||
|
||||
pid=0
|
||||
|
||||
echo "Start video for $ADDR on port $PORT"
|
||||
/usr/bin/avplay -loglevel quiet -max_delay 50 -fflags nobuffer rtp://$ADDR:$PORT
|
||||
|
||||
Executable
+50
@@ -0,0 +1,50 @@
|
||||
#!/bin/bash
|
||||
|
||||
# base address for ARDrone2
|
||||
ADDR_BASE=192.168.1.
|
||||
|
||||
# tmp folder for sdp files (relative path by default)
|
||||
SDP_DIR=${PAPARAZZI_HOME=../../../..}/var/sdp_tmp
|
||||
|
||||
# test if a complete IP address is passed as first argument or just the last digit
|
||||
if [ `grep -c '\.' <<< $1` == 1 ]
|
||||
then
|
||||
ADDR=$1
|
||||
else
|
||||
ADDR=$ADDR_BASE$1
|
||||
fi
|
||||
|
||||
pid=0
|
||||
|
||||
function quit {
|
||||
echo "Stop video"
|
||||
if [ $pid > 0 ]
|
||||
then
|
||||
kill -9 $pid
|
||||
fi
|
||||
exit 0
|
||||
}
|
||||
|
||||
# trap control+c to stop mplayer
|
||||
trap quit SIGINT
|
||||
|
||||
# fetch sdp file on the ARDrone
|
||||
mkdir -p $SDP_DIR/$ADDR
|
||||
../ardrone2.py --host=$ADDR download_file $SDP_DIR/$ADDR/x86_config-mjpeg.sdp sdp
|
||||
|
||||
if [ ! -f $SDP_DIR/$ADDR/x86_config-mjpeg.sdp ];
|
||||
then
|
||||
echo "Unable to download sdp file from $ADDR"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# start mplayer and respawn if needed
|
||||
echo "Start video"
|
||||
while [ 1 ]
|
||||
do
|
||||
/usr/bin/mplayer -really-quiet $SDP_DIR/$ADDR/x86_config-mjpeg.sdp&
|
||||
pid=$!
|
||||
wait $pid
|
||||
echo "Restart video"
|
||||
done
|
||||
|
||||
Reference in New Issue
Block a user