Commit be058841 authored by Mikhail Karpenko's avatar Mikhail Karpenko

Add unmodified sources from elphel353 project

parents
html/*
attic/*
/.project
/.cproject
/.pydevproject
/.externalToolBuilders
/.settings
.directory
generated*
sysroots
bitbake-logs
/temp/
*.o
*.cgi
bitbake-logs
.depend
/image
This diff is collapsed.
# Runs 'make', 'make install', and 'make clean' in specified subdirectories
SUBDIRS := src
INSTALLDIRS = $(SUBDIRS:%=install-%)
CLEANDIRS = $(SUBDIRS:%=clean-%)
#TARGETDIR=$(DESTDIR)/www/pages
all: $(SUBDIRS)
@echo "make all top"
$(SUBDIRS):
$(MAKE) -C $@
install: $(INSTALLDIRS)
@echo "make install top"
$(INSTALLDIRS):
$(MAKE) -C $(@:install-%=%) install
clean: $(CLEANDIRS)
@echo "make clean top"
$(CLEANDIRS):
$(MAKE) -C $(@:clean-%=%) clean
.PHONY: all install clean $(SUBDIRS) $(INSTALLDIRS) $(CLEANDIRS)
# elphel-apps-astreamer
#!/bin/bash
args="$@"
while (( "$#" )); do
shift
done
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
echo "Launching bitbake $args"
cd $DIR/../../poky
. ./oe-init-build-env
bitbake $args | sed -u 's@| @@'
exit 0
AXIS_USABLE_LIBS = UCLIBC GLIBC
AXIS_AUTO_DEPEND = yes
-include $(AXIS_TOP_DIR)/tools/build/Rules.axis
INSTALL ?= install_elinux
INSTALL_PATH = $(prefix)/usr/local
INCDIR = $(AXIS_KERNEL_DIR)/include
LDFLAGS = -Wl -s -L$(prefix)/lib -lpthread -lasound
CXXFLAGS = -Wall -O2 -I$(INCDIR)
STREAMER_OBJS = main.o streamer.o audio.o video.o socket.o rtsp.o rtp_stream.o helpers.o parameters.o
SRCS = main.cpp streamer.cpp audio.cpp video.cpp socket.cpp rtsp.cpp rtp_stream.cpp helpers.cpp parameters.cpp
PROG = str
all: dependency $(PROG)
clean:
rm -f *.o *.ver *.mp *~ core* $(PROG)
$(PROG): $(STREAMER_OBJS)
$(CXX) $(LDFLAGS) -o $@ $(STREAMER_OBJS) -lpthread -asound
%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
#install: $(PROG)
install: clean $(PROG)
$(INSTALL) $(PROG) $(INSTALL_PATH)/bin/$(PROG)
configsubs:
This diff is collapsed.
#ifndef _AUDIO__H_
#define _AUDIO__H_
#include <string>
#define __cplusplus 1
#include <alsa/asoundlib.h>
#include <pthread.h>
#include "rtp_stream.h"
using namespace std;
#define SAMPLE_RATE 44100
#define SAMPLE_CHANNELS 2
class Audio : public RTP_Stream {
public:
Audio(bool enable, int sample_rate = SAMPLE_RATE, int channels = SAMPLE_CHANNELS);
virtual ~Audio(void);
long sample_rate(void) { return _sample_rate; };
long channels(void) { return _channels; };
bool present(void) { return _present; };
long volume(void) { return _volume; };
void set_volume(long volume) { set_capture_volume(volume); }
void Start(string ip, long port, int ttl = -1);
void Stop(void);
protected:
int fd;
snd_pcm_t *capture_handle;
short *sbuffer;
long sbuffer_len;
bool _present;
long _sample_rate;
long _channels;
long _volume;
long capture(void);
long process(void);
long process_send(long sample_len);
void set_capture_volume(int volume);
uint64_t timestamp_rtcp;
long delta_fpga_sys; // A/V clocks delta for RTCP
bool is_first;
bool is_first2;
};
//extern Audio *audio;
#endif // _AUDIO__H_
#ifndef __H_HELPER__
#define __H_HELPER__
#include <sys/time.h>
inline long time_delta_us(const struct timeval &tv_1, const struct timeval &tv_2) {
long tu = tv_1.tv_usec;
if(tv_1.tv_sec != tv_2.tv_sec)
tu += (tv_1.tv_sec - tv_2.tv_sec) * 1000000;
tu -= tv_2.tv_usec;
return tu;
}
inline struct timeval time_plus(struct timeval tv_1, const struct timeval &tv_2) {
tv_1.tv_sec += tv_2.tv_sec;
tv_1.tv_usec += tv_2.tv_usec;
if(tv_1.tv_usec >= 1000000) {
tv_1.tv_sec++;
tv_1.tv_usec -= 1000000;
}
return tv_1;
}
inline struct timeval time_minus(struct timeval tv_1, const struct timeval &tv_2) {
tv_1.tv_sec -= tv_2.tv_sec;
tv_1.tv_usec += 1000000;
tv_1.tv_usec -= tv_2.tv_usec;
if(tv_1.tv_usec >= 1000000) {
tv_1.tv_usec -= 1000000;
} else {
tv_1.tv_sec--;
}
return tv_1;
}
#endif
#include "helpers.h"
#include <iostream>
using namespace std;
bool String::split(const string &str, char delimiter, string &left, string &right) {
left = "";
right = "";
int i = str.find(delimiter);
//cerr << "_______" << endl;
//cerr << "delimiter == |" << delimiter << "|, i == " << i << endl;
if(i > 0 && i < (int)str.length()) {
const char *c = str.c_str();
//cerr <<
left.insert(0, c, i);
right.insert(0, &c[i + 1], str.length() - i - 1);
return true;
} else
left = str;
return false;
}
list<string> String::split_to_list(string str, char delimiter) {
list<string> l;
if((str.c_str())[str.length() - 1] != delimiter)
str += delimiter;
const char *c = str.c_str();
int j = 0;
for(int i = 0; c[i]; i++) {
if(c[i] == delimiter) {
string a;
a.insert(0, &c[j], i - j);
j = i + 1;
l.push_back(a);
}
}
return l;
}
map<string, string> String::split_list_to_map(const list<string> &l, char delimiter) {
map<string, string> m;
for(list<string>::const_iterator it = l.begin(); it != l.end(); it++) {
int i = (*it).find(delimiter);
if(i > 0 && i < (int)(*it).length()) {
const char *c = (*it).c_str();
string n, v;
n.insert(0, c, i);
v.insert(0, &c[i + 1], (*it).length() - i - 1);
m[n] = v;
}
}
return m;
}
#ifndef _HELPERS__H_
#define _HELPERS__H_
#include <string>
#include <list>
#include <map>
using namespace std;
class String {
public:
static bool split(const string &str, char delimiter, string &left, string &right);
static list<string> split_to_list(string str, char delimiter);
static map<string, string> split_list_to_map(const list<string> &l, char delimiter);
};
#endif // _HELPERS__H_
#include <iostream>
#include <string>
#include <map>
#include "streamer.h"
using namespace std;
#include <unistd.h>
#include <linux/sysctl.h>
int main(int argc, char *argv[]) {
string opt;
map<string, string> args;
for(int i = 1; i < argc; i++) {
if(argv[i][0] == '-' && argv[i][1] != '\0') {
if(opt != "")
args[opt] = "";
opt = &argv[i][1];
continue;
} else {
if(opt != "") {
args[opt] = argv[i];
opt = "";
}
}
}
if(opt != "")
args[opt] = "";
for(map<string, string>::iterator it = args.begin(); it != args.end(); it++) {
cerr << "|" << (*it).first << "| == |" << (*it).second << "|" << endl;
}
Streamer *streamer = new Streamer(args);
streamer->Main();
return 0;
}
#include "parameters.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <asm/elphel/c313a.h>
#include <iostream>
#include "streamer.h"
using namespace std;
#undef PARAMETERS_DEBUG
//#define PARAMETERS_DEBUG
#ifdef PARAMETERS_DEBUG
#define D(a) a
#else
#define D(a)
#endif
Parameters *Parameters::_parameters = NULL;
Parameters::Parameters(void) {
fd_fparmsall = open("/dev/frameparsall", O_RDWR);
if(fd_fparmsall < 0)
throw("can't open /dev/frameparsall");
//! now try to mmap
frameParsAll = (struct framepars_all_t *) mmap(0, sizeof (struct framepars_all_t) , PROT_READ | PROT_WRITE , MAP_SHARED, fd_fparmsall, 0);
if((int)frameParsAll == -1)
throw("Error in mmap /dev/frameparsall");
framePars = frameParsAll->framePars;
globalPars = frameParsAll->globalPars;
}
Parameters::~Parameters(void) {
if(fd_fparmsall > 0)
close(fd_fparmsall);
}
/**
* @brief Read either G_* parameter (these are 'regular' values defined by number) or P_* parameter
* (it can be read for up to 6 frames ahead, but current interface only allows to read last/current value)
* @param GPNumber parameter number (as defined in c313a.h), G_* parameters have numbers above FRAMEPAR_GLOBALS, P_* - below)
* @return parameter value
*/
unsigned long Parameters::getGPValue(unsigned long GPNumber) {
return (GPNumber >= FRAMEPAR_GLOBALS) ? GLOBALPARS(GPNumber) : framePars[GLOBALPARS(G_THIS_FRAME) & PARS_FRAMES_MASK].pars[GPNumber];
}
/**
* @brief Set value of the specified global (G_*) parameter
* @param GNumber - parameter number (as defined in c313a.h)
* @param value - value to set
*/
void Parameters::setGValue(unsigned long GNumber, unsigned long value) {
GLOBALPARS(GNumber) = value;
}
unsigned long Parameters::getFrameValue(unsigned long FPNumber) {
return framePars[GLOBALPARS(G_THIS_FRAME) & PARS_FRAMES_MASK].pars[FPNumber];
}
bool Parameters::daemon_enabled(void) {
return((getFrameValue(P_DAEMON_EN) & (1 << DAEMON_BIT_STREAMER)) != 0);
}
void Parameters::setPValue(unsigned long *val_array, int count) {
/*
long target_frame = params->getGPValue(G_THIS_FRAME) + FRAMES_AHEAD_FPS;
write_data[0] = FRAMEPARS_SETFRAME;
write_data[1] = target_frame; /// wait then for that frame to be available on the output plus 2 frames for fps to be stable
write_data[2] = P_FP1000SLIM;
write_data[3] = (unsigned long)fps * 1000;
write_data[4] = P_FPSFLAGS;
write_data[5] = 3;
*/
// long rslt = write(fd_fparmsall, write_data, sizeof(write_data));
this->write(val_array, sizeof(unsigned long) * count);
}
//------------------------------------------------------------------------------
#ifndef _PARS__H_
#define _PARS__H_
#include <sys/types.h>
#include <unistd.h>
#include <string>
using namespace std;
#include <asm/elphel/c313a.h>
//#define FRAMES_AHEAD_FPS 3 /// number of video frames ahead of current to frite FPS limit
//#define FRAMES_SKIP_FPS 3 /// number of video frames to wait after target so circbuf will have at least 2 frames with new fps for calculation
class Parameters {
public:
/*
enum vevent {
VEVENT0,
DAEMON_DISABLED,
FPS_CHANGE,
SIZE_CHANGE
};
*/
inline static Parameters *instance(void) {
if(_parameters == NULL)
_parameters = new Parameters();
return _parameters;
}
~Parameters(void);
// unsigned long get
/// interface to global camera parameters
unsigned long getGPValue(unsigned long GPNumber);
void setGValue(unsigned long GNumber, unsigned long value);
unsigned long getFrameValue(unsigned long FPNumber);
int write(unsigned long *data, int length) { return ::write(fd_fparmsall, (void *)data, length); }
off_t lseek(off_t offset, int whence) { return ::lseek(fd_fparmsall, offset, whence); }
bool daemon_enabled(void);
void setPValue(unsigned long *val_array, int count);
protected:
static Parameters *_parameters;
Parameters(void);
struct framepars_all_t *frameParsAll;
struct framepars_t *framePars;
unsigned long *globalPars;
int fd_fparmsall;
};
//extern Video *video;
#endif // _VIDEO__H_
#include <arpa/inet.h>
#include <iostream>
#include "rtp_stream.h"
#include "helper.h"
using namespace std;
#define CNAME "elphel353"
#undef RTP_DEBUG
//#define RTP_DEBUG
#ifdef RTP_DEBUG
#define D(a) a
#else
#define D(a)
#endif
RTP_Stream::RTP_Stream(void) {
_play = false;
pthread_mutex_init(&pthm_flow, NULL);
stream_name = "unknown";
rtp_socket = NULL;
rtcp_socket = NULL;
sem_init(&sem_play, 0, 0);
pth_id = -1;
}
RTP_Stream::~RTP_Stream() {
//cerr << "RTP_Stream::~RTP_Stream() for stream " << stream_name << endl;
if(pth_id >= 0)
pthread_cancel(pth);
if(rtp_socket != NULL)
delete rtp_socket;
if(rtcp_socket != NULL)
delete rtcp_socket;
sem_destroy(&sem_play);
pthread_mutex_destroy(&pthm_flow);
}
void RTP_Stream::init_pthread(void *__this) {
pthread_attr_t tattr;
pthread_attr_init(&tattr);
pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
pth_id = pthread_create(&pth, &tattr, RTP_Stream::pthread_f, (void *)__this);
}
void *RTP_Stream::pthread_f(void *_this) {
RTP_Stream *__this = (RTP_Stream *)_this;
return __this->thread();
}
void RTP_Stream::Start(string ip, int port, int ttl) {
D( cerr << " new " << stream_name << " UDP socket at port: " << port << endl;)
pthread_mutex_lock(&pthm_flow);
if(!_play) {
rtp_socket = new Socket(ip, port, Socket::TYPE_UDP, ttl);
rtcp_socket = new Socket(ip, port + 1, Socket::TYPE_UDP, ttl);
rtp_packets = 0;
rtp_octets = 0;
rtcp_tv.tv_sec = 0;
rtcp_tv.tv_usec = 0;
// rtcp_delay = 2500000; // in usec
// rtcp_delay = 1250000; // in usec
rtcp_delay = 2000000; // in usec
_play = true;
/// unlock semaphore - 'play' event
sem_post(&sem_play);
}
pthread_mutex_unlock(&pthm_flow);
}
void RTP_Stream::Stop(void) {
D( cerr << __FILE__<< ":"<< __FUNCTION__ << ":" <<__LINE__ <<endl;)
//cerr << "RTP_Stream::Stop() for stream " << stream_name << " - begin" << endl;
pthread_mutex_lock(&pthm_flow);
if(_play) {
//cerr << "RTP_Stream::Stop() for stream " << stream_name << " - in progress" << endl;
/// reset semaphore
sem_init(&sem_play, 0, 0);
_play = false;
// delete rtcp_socket;
if(rtp_socket != NULL) {
delete rtp_socket;
rtp_socket = NULL;
}
if(rtcp_socket != NULL) {
delete rtcp_socket;
rtcp_socket = NULL;
}
}
pthread_mutex_unlock(&pthm_flow);
//cerr << "RTP_Stream::Stop() for stream " << stream_name << " - end" << endl;
}
/**
* @brief Thread that invokes the video (and audio too) frame acquisition/ transmission
* In the current implementation video process() is blocking, but may be made
* non-blocking again later (through poll()). In addition to bool result
* (false if no frames are available, there are now long process(), with
* additional <0 result for the video frame change/stream shut down detected
* in Video class.
* @return never
*/
void *RTP_Stream::thread(void) {
D( cerr << "RTP_Stream::thread(void)" <<endl;)
for(;;) {
pthread_mutex_lock(&pthm_flow);
if(_play) {
long f = process();
if(f > 0)
rtcp();
// process() and rtcp() use sockets
pthread_mutex_unlock(&pthm_flow);
if(f < 0) {
D( cerr << __FILE__<< ":"<< __FUNCTION__ << ":" <<__LINE__<< "process exception detected: " << f << endl;)
// cerr << "Stop() from thread for stream " << stream_name << endl;
Stop();
}
} else { /// wait for 'play' event semaphore
pthread_mutex_unlock(&pthm_flow);
sem_wait(&sem_play);
}
}
return NULL;
}
void RTP_Stream::rtcp(void) {
// check time for next one RTCP...
if(f_tv.tv_sec == 0 && f_tv.tv_usec == 0)
return;
long td = time_delta_us(f_tv, rtcp_tv);
if(td < 0) {
rtcp_tv = f_tv;
return;
}
if(td < rtcp_delay)
return;
rtcp_tv = f_tv;
rtcp_send_sdes();
rtcp_send_sr();
}
void RTP_Stream::rtcp_send_sr(void) {
char packet[8 + 20]; // by RTP RFC 3550, for SR RTCP packet needed 8 + 20 bytes
int packet_len = sizeof(packet);
uint16_t us;
uint32_t ul;
// RTCP header
packet[0] = 0x81;
packet[1] = 200; // SR
us = htons(((packet_len) / 4) - 1);
memcpy((void *)&packet[2], (void *)&us, 2);
memcpy((void *)&packet[4], (void *)&SSRC, 4);
// NTP timestamp is a fixed point 32.32 format time
ul = htonl(f_tv.tv_sec);
memcpy((void *)&packet[8], (void *)&ul, 4);
double d = f_tv.tv_usec;
d /= 1000000.0;
d *= 65536.0;
d *= 4096.0;
uint32_t f = (uint32_t)d;
if(f > 0x0FFFFFFF)
f = 0x0FFFFFFF;
f <<= 4;
ul = htonl(f);
memcpy((void *)&packet[12], (void *)&ul, 4);
ul = htonl(timestamp);
memcpy((void *)&packet[16], (void *)&ul, 4);
ul = htonl(rtp_packets);
memcpy((void *)&packet[20], (void *)&ul, 4);
ul = htonl(rtp_octets);
memcpy((void *)&packet[24], (void *)&ul, 4);
rtcp_socket->send(packet, packet_len);
}
void RTP_Stream::rtcp_send_sdes(void) {
char packet[8 + 4 + 128]; // by RTP RFC 3550, for SDES RTCP packet needed 8 + 4 + ... bytes,
// so get additional 128 bytes for 126 CNAME field
int packet_len = 0;
int padding=0;
uint16_t us;
const char *cname = CNAME;
int cname_len = strlen(cname);
bzero((void *)packet, 140); //8+4+128
// RTCP header
packet[0] = 0x81;
packet[1] = 202;
memcpy((void *)&packet[4], (void *)&SSRC, 4);
packet_len += 8;
// SDES fields
packet[8] = 0x01;
memcpy((void *)&packet[10], (void *)cname, cname_len);
packet_len += 2; // + cname_len;
// calculate common length SDES
padding=(cname_len+2)%4;
if(padding)
cname_len += (4-padding);
packet[9] = cname_len;
// each chunk MUST be terminated by one or more null octets(RFC3350)
packet_len += (cname_len+4);
us = htons((packet_len / 4) - 1);
memcpy((void *)&packet[2], (void *)&us, 2);
rtcp_socket->send(packet, packet_len);
}
#ifndef __H_RTP_STREAM__
#define __H_RTP_STREAM__
#include <sys/time.h>
#include <string>
#include <pthread.h>
#include <semaphore.h>
#include "socket.h"
#include <stdint.h>
using namespace std;
extern int fd_stream;
class RTP_Stream {
public:
RTP_Stream(void);
virtual ~RTP_Stream();
int ptype(void) { return _ptype; };
virtual void Start(string ip, int port, int ttl = -1);
virtual void Stop(void);
protected:
void init_pthread(void *__this);
pthread_t pth;
int pth_id;
static void *pthread_f(void *_this);
void *thread(void);
pthread_mutex_t pthm_flow;
// virtual bool process(void) = 0;
virtual long process(void) = 0;
int _ptype;
bool _play;
/// semaphore to wait 'play' event
sem_t sem_play;
Socket *rtp_socket;
Socket *rtcp_socket;
unsigned short packet_num;
unsigned long SSRC;
struct timeval f_tv;
struct timeval rtcp_tv; // time of last SR
long rtcp_delay;
unsigned long timestamp;
unsigned long rtp_packets;
unsigned long rtp_octets;
void rtcp(void);
void rtcp_send_sr(void);
void rtcp_send_sdes(void);
string stream_name;
};
#endif //__H_RTP_STREAM__
This diff is collapsed.
#ifndef _RTSP_H_
#define _RTSP_H_
//#include "types.h"
#include "session.h"
#include "socket.h"
#include <map>
#include <list>
#include <string>
#include <iostream>
using namespace std;
class _Request {
public:
_Request(const string &req);
inline const string &get_method(void) {
return method;
}
inline const string &get_uri(void) {
return uri;
}
inline map<string, string> &get_fields(void) {
return fields;
}
protected:
string method;
string uri;
map<string, string> fields;
};
class _Responce {
public:
enum status {STATUS_EMPTY, STATUS_BUSY, STATUS_OK};
_Responce():_status(STATUS_EMPTY) {};
inline void set_status(status st) {
_status = st;
}
void add_field(const string &name, const string &value);
void add_include(const string &include);
string serialize(void);
protected:
status _status;
map<string, string> fields;
string include;
};
class RTSP_Server {
public:
enum event {
EMPTY,
DESCRIBE,
PLAY,
PAUSE,
TEARDOWN,
PARAMS_WAS_CHANGED,
RESET
// IS_DAEMON_ENABLED
};
// if transport == NULL - wait for set_transport(), when client connected and ask DESCRIBE
RTSP_Server(int (*h)(void *, RTSP_Server *, RTSP_Server::event), void *handler_data, Session *_session = NULL);
~RTSP_Server();
// deprecated
void main(void);
protected:
bool process(Socket *s);
string make_sdp(string uri);
string make_transport(string req);
Session *session;
// socket to accept requests
// Socket *socket_main;
int (*handler_f)(void *, RTSP_Server *, RTSP_Server::event);
void *handler_data;
int handler(RTSP_Server::event event) {
return handler_f(handler_data, this, event);
}
// keep Sockets of clients to identify them and block second client in unicast mode
list<Socket *> active_sockets;
bool process_teardown(Socket *s);
bool process_play(Socket *s, bool add = true); // if secons argument is false - just check what server not busy
// void *_busy; // pointer to Socket of client, what use current unicast stream
string part_of_request;
// thread...
// RTP *rtp;
Socket *socket_main_1;
Socket *socket_main_2;
// Socket *socket_main_3;
};
#endif // _RTSP_H_
#ifndef _SESSION__H_
#define _SESSION__H_
#include <string>
using namespace std;
#define VIDEO_MJPEG "MJPG"
struct transport_t {
string ip;
bool ip_custom; // true, if user set IP by himself, otherwise false
unsigned long ip_cached; // cashed IP to check parameter
// string port;
int port_video;
int port_audio;
bool process_audio;
bool multicast;
string ttl;
};
struct video_t {
int type; // == "", if not present
double fps; // == 0, if unspecified
int width;
int height;
int fps_scale; // 0,1 - no scale, 2 - scale 2x etc...
};
struct audio_t {
int type;
int sample_rate;
int channels;
int volume; // for inner use only - from 0 to 65535 - current audio capture volume
};
class Session {
public:
string id;
struct transport_t rtp_in;
struct transport_t rtp_out;
struct video_t video;
struct audio_t audio;
bool process_audio;
};
#endif // _SESSION__H_
#include <string>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/poll.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <net/if.h>
#include <sys/ioctl.h>
using namespace std;
#include "socket.h"
#include "helpers.h"
#undef RTSP_DEBUG
#undef RTSP_DEBUG_2
#ifdef RTSP_DEBUG
#define D(a) a
#else
#define D(a)
#endif
#ifdef RTSP_DEBUG_2
#define D2(a) a
#else
#define D2(a)
#endif
#define BUF_SIZE 2048
TCP_Client::TCP_Client(bool enable_exception) {
ex = enable_exception;
fd = -1;
}
TCP_Client::~TCP_Client() {
disconnect();
}
void TCP_Client::connect(string ip, string port) {
if((fd = ::socket(PF_INET, SOCK_STREAM, 0)) == -1) {
cerr << "fail socket()" << endl;
throw(false);
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(::atol(port.c_str()));
addr.sin_addr.s_addr = ::inet_addr(ip.c_str());
if(::connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
cerr << "fail connect() to " << ip << ":" << port << endl;
throw(false);
}
// TODO: we must use size as MTU for interface... and also - checking for not single frames...
buf = (char *)malloc(1500);
}
void TCP_Client::disconnect(void) {
if(fd > 0) {
::close(fd);
free(buf);
buf = NULL;
}
fd = -1;
}
void TCP_Client::send(const string *data, int opt) {
if(::send(fd, data->c_str(), data->length(), opt) < 0) {
cerr << "fail to send(const string *)" << endl;
throw(false);
}
}
void TCP_Client::send(const string data, int opt) {
int er;
if(::send(fd, data.c_str(), data.length(), opt) < 0) {
er = errno;
cerr << "fail to send(const string): " << strerror(er) << endl;
throw(false);
}
}
void TCP_Client::send(void *data, int len, int opt) {
if(::send(fd, data, len, opt) < 0) {
cerr << "fail to send(void *, len)" << endl;
throw(false);
}
}
void TCP_Client::recv(string &r, int opt) {
int l, er;
if((l = ::recv(fd, buf, BUF_SIZE - 1, opt)) > 0) {
buf[l] = '\0';
r = buf;
} else {
er = errno;
cerr << "fail to recv(string &): " << strerror(er) << endl;
throw (false);
}
}
/*
* Socket class...
*/
unsigned long Socket::ip_to_number(string ip) {
string left;
string right;
unsigned long rez = 0;
while(String::split(ip, '.', left, right)) {
rez += atol(left.c_str());
rez <<= 8;
ip = right;
}
return rez;
}
bool Socket::_is_multicast(string ip) {
bool rez = true;
unsigned long a_min = ip_to_number("224.0.0.0");
unsigned long a_max = ip_to_number("239.255.255.255");
if(a_min > a_max) {
unsigned long a = a_min;
a_min = a_max;
a_max = a;
}
unsigned long a_ip = ip_to_number(ip.c_str());
if(a_ip > a_max)
rez = false;
if(a_ip < a_min)
rez = false;
return rez;
}
struct in_addr Socket::mcast_from_local(void) {
int _fd;
int reuse = 1;
_fd = socket(AF_INET, SOCK_DGRAM, 0);
setsockopt(_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse, sizeof(reuse));
struct ifreq ifr;
struct sockaddr_in *sin;
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, "eth0");
struct ifconf ifc;
ifc.ifc_len = 1;
ifc.ifc_req = &ifr;
ioctl(_fd, SIOCGIFADDR, &ifr);
close(_fd);
sin = (struct sockaddr_in *)(ifr.ifr_addr.sa_data - 2);
sin->sin_addr.s_addr &= (0xFFFFFF0F);
sin->sin_addr.s_addr |= (0x000000E0);
return sin->sin_addr;
}
/// use ttl parameter only with UDP sockets
Socket::Socket(string _ip, int _port, stype _type, int ttl) {
ip = _ip;
port = _port;
is_multicast = false;
D(cerr << "new socket..." << endl;)
_state = STATE_EMPTY;
int t = 0;
type = _type;
struct sockaddr_in addr;
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = PF_INET;
addr.sin_port = htons(port);
switch(type) {
case TYPE_TCP: {
fd = socket(PF_INET, SOCK_STREAM, 0);
int flag = 1;
setsockopt(fd, IPPROTO_IP, SO_REUSEADDR, &flag, sizeof(flag));
if(ip != "")
addr.sin_addr.s_addr = inet_addr(ip.c_str());
else
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if(ttl>0)
setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
t = bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr));
D( int er = errno;)
D( cerr << "TCP ::bind() == " << t; if(t != 0) cerr << "; errno == " << strerror(er); cerr << endl;)
break;
}
case TYPE_UDP: {
fd = socket(PF_INET, SOCK_DGRAM, 0);
struct sockaddr_in saddr;
memset(&saddr, 0, sizeof(struct sockaddr_in));
saddr.sin_family = PF_INET;
saddr.sin_port = htons(0);
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
::bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in));
addr.sin_addr.s_addr = inet_addr(ip.c_str());
t = ::connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr));
D( cerr << "::connect() == " << t << endl;)
if((is_multicast = _is_multicast(ip)) == true) {
struct ip_mreqn multiaddr;
multiaddr.imr_multiaddr.s_addr = inet_addr(ip.c_str());
multiaddr.imr_address.s_addr = htonl(INADDR_ANY);
multiaddr.imr_ifindex = 0;
setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &multiaddr, sizeof(struct sockaddr_in));
}
// check TTL
if(ttl > 0) {
//cerr << "try to set TTL to value == " << ttl << endl;
setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
}
break;
}
default:
break;
}
}
Socket::Socket(int _fd, string _ip, int _port, stype _t) {
_state = STATE_EMPTY;
fd =_fd;
ip = _ip;
port = _port;
type = _t;
D( cerr << "socket: ip == " << ip << "; port == " << port << endl;)
}
Socket::~Socket() {
close(fd);
}
int Socket::poll(list<Socket *> &s, int timeout) {
struct pollfd *pfd;
ssize_t s_size = s.size();
D2(cerr << "Socket::poll()..." << endl;)
pfd = (struct pollfd *)malloc(sizeof(struct pollfd) * s_size);
memset(pfd, 0, sizeof(struct pollfd) * s_size);
int i = 0;
D2(cerr << "socket.fd == ";)
for(list<Socket *>::iterator it = s.begin(); it != s.end(); it++, i++) {
pfd[i].fd = (*it)->fd;
D2(cerr << pfd[i].fd << "; ";)
// pfd[i].events = 0xFFFF;
pfd[i].events = POLLIN;
pfd[i].revents = 0x00;
}
D2(cerr << endl;)
int p = ::poll(pfd, s_size, timeout);
i = 0;
for(list<Socket *>::iterator it = s.begin(); it != s.end(); it++, i++) {
(*it)->_state = STATE_EMPTY;
D2(cerr << "revents == " << pfd[i].revents << "; POLLIN == " << POLLIN << endl;)
if(pfd[i].revents & POLLIN) {
(*it)->_state = STATE_IN;
D2(cerr << "STATE_IN; fd == " << (*it)->fd << "; revents == " << pfd[i].revents << endl;)
}
if(pfd[i].revents & POLLHUP) {
// if(pfd[i].revents & POLLHUP || pfd[i].revents & POLLERR) {
(*it)->_state = STATE_DISCONNECT;
//D2(cerr << "STATE_DISCONNECT; fd == " << (*it)->fd << "; revents == " << pfd[i].revents << endl;)
cerr << "STATE_DISCONNECT; fd == " << (*it)->fd << "; revents == " << pfd[i].revents << endl;
}
}
free((void *)pfd);
return p;
}
void Socket::listen(int in) {
long sock_flags;
sock_flags = fcntl(fd, F_GETFL);
sock_flags |= O_NONBLOCK;
fcntl(fd, F_SETFL, sock_flags);
int l = ::listen(fd, in);
D(cerr << "listen() == " << l << endl;)
l++;
}
Socket *Socket::accept(void) {
int _fd;
struct sockaddr_in addr;
socklen_t addr_len = 0;
long sock_flags;
Socket *s;
memset(&addr, 0, sizeof(struct sockaddr_in));
addr_len = sizeof(struct sockaddr_in);
_fd = ::accept(fd, (struct sockaddr *)&addr, &addr_len);
if(_fd < 0)
return NULL;
sock_flags = fcntl(_fd, F_GETFL);
sock_flags |= O_NONBLOCK;
fcntl(_fd, F_SETFL, sock_flags);
D(cerr << "accept == " << _fd << "; addr_len == " << addr_len << endl;)
s = new Socket(_fd, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), type);
return s;
}
void Socket::set_so_keepalive(int val) {
int keepalive = val;
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
::setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive));
::setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
::setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
}
bool Socket::recv(string &rez) {
rez = "???";
char buf[1501];
int l = 0;
buf[0] = '\0';
if((l = ::recv(fd, buf, 1500, MSG_NOSIGNAL | MSG_DONTWAIT)) > 0) {
buf[l] = '\0';
rez = buf;
D(cerr << "read - ok!"<< endl;)
return true;
} else {
if(l == 0) {
rez = "";
return true;
}
}
rez = "";
return false;
}
bool Socket::send(void *data, int len) {
return (::send(fd, data, len, MSG_NOSIGNAL | MSG_DONTWAIT) > 0);
}
bool Socket::send(const string *data) {
if(::send(fd, data->c_str(), data->length(), 0) > 0)
return true;
return false;
}
bool Socket::send(const string data) {
if(::send(fd, data.c_str(), data.length(), MSG_NOSIGNAL | MSG_DONTWAIT) > 0)
return true;
return false;
}
uint16_t in_chksum(const uint16_t *addr, register uint32_t len) {
int32_t nleft = len;
const uint16_t *w = addr;
uint16_t answer;
int32_t sum = 0;
while(nleft > 1) {
sum += *w++;
nleft -= 2;
}
if(nleft == 1)
sum += htons(*(uint8_t *)w << 8);
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return answer;
}
bool Socket::send2v(void **v_ptr, int *v_len) {
struct iovec iov[2];
int iovcnt = sizeof(iov) / sizeof(struct iovec);
iov[0].iov_base = v_ptr[0];
iov[0].iov_len = v_len[0];
iov[1].iov_base = v_ptr[1];
iov[1].iov_len = v_len[1];
if(::writev(fd, iov, iovcnt))
return true;
return false;
}
bool Socket::send3v(void **v_ptr, int *v_len) {
struct iovec iov[3];
int iovcnt = sizeof(iov) / sizeof(struct iovec);
iov[0].iov_base = v_ptr[0];
iov[0].iov_len = v_len[0];
iov[1].iov_base = v_ptr[1];
iov[1].iov_len = v_len[1];
iov[2].iov_base = v_ptr[2];
iov[2].iov_len = v_len[2];
if(::writev(fd, iov, iovcnt))
return true;
return false;
}
#ifndef _SOCKETS_H_
#define _SOCKETS_H_
#include <string>
#include <list>
#include <sys/socket.h>
using namespace std;
class TCP_Client {
public:
TCP_Client(bool enable_exception);
~TCP_Client();
void connect(string ip, string port);
void disconnect(void);
void send(const string *data, int opt = 0);
void send(const string data, int opt = 0);
void send(void *data, int len, int opt = 0);
void recv(string &r, int opt = 0);
protected:
bool ex;
int fd;
char *buf;
};
class Socket {
public:
enum stype {TYPE_TCP, TYPE_UDP};
enum state {STATE_EMPTY, STATE_IN, STATE_DISCONNECT};
Socket(string ip, int port, stype _t = TYPE_TCP, int ttl = 64);
~Socket();
bool recv(string &rez);
bool send(void *data, int len);
bool send(const string *data);
bool send(const string data);
bool send2v(void **v_ptr, int *v_len);
bool send3v(void **v_ptr, int *v_len);
static int poll(list<Socket *> &s, int timeout = -1);
void listen(int in);
Socket *accept(void);
// bool connect(void);
void set_so_keepalive(int val = 1);
inline state state_refresh(void) {
state st = _state;
_state = STATE_EMPTY;
return st;
}
int get_fd(void) { return fd;};
int fd;
string source_ip(void) {
return ip;
}
static struct in_addr mcast_from_local(void);
protected:
Socket(int _fd, string _ip, int _port, stype _t);
string ip;
int port;
stype type;
// int fd;
state _state;
int ttl;
unsigned short ip_id;
bool _is_multicast(string ip);
unsigned long ip_to_number(string ip);
bool is_multicast;
/*
struct sockaddr_ll s_ll;
struct msghdr msg;
struct udphdr udp_hdr;
struct iphdr ip_hdr;
*/
};
#endif
This diff is collapsed.
#ifndef __H_STREAMER__
#define __H_STREAMER__
#include <string>
#include <map>
#include "video.h"
#include "audio.h"
#include "rtsp.h"
using namespace std;
class Streamer {
public:
Streamer(const map<string, string> &args);
~Streamer();
void Main(void);
bool opt_present(string name) {
if(args.find(name) != args.end())
return true;
return false;
}
static Streamer *instance(void) {
return _streamer;
}
protected:
static Streamer *_streamer;
static int f_handler(void *ptr, RTSP_Server *rtsp_server, RTSP_Server::event event);
int handler(RTSP_Server *rtsp_server, RTSP_Server::event event);
int update_settings(bool apply = false);
map<string, string> args;
RTSP_Server *rtsp_server;
Session *session;
Audio *audio;
Video *video;
bool running;
int connected_count;
void audio_init(void);
};
#endif // __H_STREAMER__
This diff is collapsed.
#ifndef _VIDEO__H_
#define _VIDEO__H_
#include <string>
#include "rtp_stream.h"
#include "parameters.h"
using namespace std;
#include <asm/elphel/c313a.h>
#define FRAMES_AHEAD_FPS 3 /// number of frames ahead of current to frite FPS limit
#define FRAMES_SKIP_FPS 3 /// number of frames to wait after target so circbuf will have at least 2 frames with new fps for calculation
/// structure to store current video description
struct video_desc_t {
bool valid;
int width;
int height;
int quality;
float fps;
};
class Video : public RTP_Stream {
public:
enum vevent {
VEVENT0,
DAEMON_DISABLED,
FPS_CHANGE,
SIZE_CHANGE
};
Video(void);
virtual ~Video(void);
/// return description of the current frame - i.e. current video parameters
struct video_desc_t get_current_desc(bool with_fps = true);
void fps(float);
void Start(string ip, long port, int fps_scale, int ttl = -1);
void Stop(void);
Parameters *params;
/// Using Video class to interface global camera parameters
bool waitDaemonEnabled(int daemonBit); // <0 - use default
bool isDaemonEnabled(int daemonBit); // <0 - use default
protected:
long getFramePars(struct interframe_params_t * frame_pars, long before, long ptr_before = 0);
unsigned long prev_jpeg_wp;
// frame params
int f_width;
int f_height;
int f_quality;
bool qtables_include;
unsigned char qtable[128];
// struct timeval f_tv;
long buffer_length;
unsigned long *buffer_ptr;
unsigned long *buffer_ptr_s; /// Second copy of the circbuf just after the end of the first to prevent rollovers
void *frame_ptr;
long capture(void);
// bool process(void);
long process(void);
// for statistic
long v_t_sec;
long v_t_usec;
int v_frames;
unsigned long used_width; ///frame width reported by Video::width(), used as the stream width
unsigned long used_height; /// similar to above
float used_fps; /// similar to above
int fps_scale;
int fps_scale_c; // counter for fps_scale
};
//extern Video *video;
#endif // _VIDEO__H_
#!/usr/bin/env python
# encoding: utf-8
from __future__ import division
from __future__ import print_function
"""
# @file used_files.py
# @brief Extract file access data after build, modify CDT project configuration
# (.cproject) accordingly
# @copyright Copyright (C) 2016, Elphel.inc.
# @param <b>License</b>
# 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 3 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, see <http:#www.gnu.org/licenses/>.
@author: Andrey Filippov
@license: GPLv3.0+
@contact: andrey@elphel.coml
@deffield updated: Updated
"""
__author__ = "Andrey Filippov"
__copyright__ = "Copyright 2016, Elphel, Inc."
__license__ = "GPL"
__version__ = "3.0+"
__maintainer__ = "Andrey Filippov"
__email__ = "andrey@elphel.com"
__status__ = "Development"
import sys
import os
import time
import xml.etree.ElementTree as ET
'''
TODO:Automate, find out why separate touch commands are needed
Run this program twice:
1-st run ./used_files.py linux -1
and save shown timestamp
Then run (some mystery here)
touch src/drivers/ata/ahci_elphel.c
touch src/drivers/elphel/sensor_common.c
Wait 5 seconds and run (in a different console with appropriate sourcing)
bitbake linux-xlnx -c compile -f
Then again
./used_files.py linux <timestamp_from_the_first_run>
If somethong went wrong you will need to resore .cproject from eclipse_project_setup directory
For php:
bitbake php -c cleansstate
bitbake php -c unpack -f
bitbake php -c configure -f
./used_files.py php -1
bitbake php -c compile -f
./used_files.py php 1471044836.8
Doing:
bitbake php -c compile -f
./used_files.py php -1
bitbake php -c compile -f
./used_files.py php 1471044836.8
Corrupts make process
'''
def file_tree(flist): # Each file in list is a file, no directories
ftree={}
for p in flist:
node = ftree
seg_list=p.split(os.sep)
last_i=len(seg_list)-1
for i,segm in enumerate(seg_list):
if not segm in node:
if i == last_i:
node[segm] = None
else:
node[segm] = {}
node=node[segm]
return ftree
def exclude_list(ftree, flist):
mark = "*" # no file/dir name can be "*"
def list_tree_recursive(root):
rslt = []
if not mark in root:
return [[""]] # convert to trailing "/" for directories
for n in root:
if not n == mark:
if root[n] is None:
rslt.append([n])
else:
for l in list_tree_recursive(root[n]):
rslt.append([n]+l)
return rslt
ftree[mark]=None # mark top level dir
for p in flist:
node = ftree
for segm in p.split(os.sep)[:-1]:
node=node[segm]
node[mark]=None # [mark] means used in flist
del node[p.split(os.sep)[-1]]
#print (ftree)
# for k in ftree:
# print(k)
#Now prune unused directories
#prune_recursive(ftree) # (assuming root is used)
# now create list
files_list_list = list_tree_recursive(ftree)
# print (files_list_list)
#converrt to file paths
pl = []
for l in files_list_list:
pl.append(os.path.join(*(l[1:])))
pl = sorted (pl)
return pl
def proc_tree():
DEBUG = True
extensions = [".h",".c",".cpp"]
exclude_start = ["linux"+os.sep+"scripts"+os.sep,"linux"+os.sep+"source"+os.sep+"scripts"+os.sep]
delta_t = 3 # seconds
try:
root_path = sys.argv[1]
except:
print ("Calling %s <root directory path> [timestamp]"%(os.path.basename(sys.argv[0])))
try:
start_time = float(sys.argv[2])
except:
start_time = 0.0
touch_files= start_time < 0.0
print ("root_path = %s"%(root_path))
# root_path = "/home/eyesis/git/poky/linux-elphel/linux/"
lstFiles = []
# Append files to a list
for path, _, files in os.walk(root_path, followlinks = True):
for f in files:
for ext in extensions:
if f.endswith(ext):
lstFiles.append(os.path.join(path, f))
break
all_tree= file_tree(sorted(lstFiles))
include_lst=[]
lst_a = []
latest_at=0
for p in lstFiles:
if touch_files:
if os.path.islink(p):
try:
os.utime(os.path.realpath(p), None)
except:
print("missing linked file: %s"%(os.path.realpath(p)))
else:
os.utime(p, None)
else:
# at = time.ctime(os.stat(p).st_atime)
try:
at = os.stat(p).st_atime
l = None
except:
at = 0
if os.path.islink(p):
try:
l = os.path.realpath(p)
at = os.stat(l).st_atime
except:
at = 0 # missing file
latest_at = max((latest_at,at))
if at > (start_time + delta_t):
#Scripts/lexers result in problems
exclude=False
for exStr in exclude_start:
if p.startswith(exStr):
exclude=True
break
if exclude:
break
#exclude_start
lst_a.append([p,at,l])
include_lst.append(p)
if touch_files:
print (len(lstFiles), "last time = ", time.time())
return
excluding = exclude_list(all_tree, include_lst)
# print (all_tree)
# print (sorted(include_lst))
# print ("|".join(excluding))
if DEBUG:
with open("all_sources.lst","w" ) as f:
for p in sorted(lstFiles):
try:
at = os.stat(p).st_atime
except:
at = 0
lnk=""
if os.path.islink(p):
try:
at = os.stat(os.path.realpath(p)).st_atime
except:
at = 0
lnk = os.path.realpath(p)
print (p,at,lnk, file=f)
with open("excluding.lst","w" ) as f:
for p in excluding:
print (p, file=f)
with open("including.lst","w" ) as f:
for p in include_lst:
print (p, file=f)
# include_tree= file_tree(sorted(include_lst))
# print(include_tree)
root_dir=include_lst[0].split(os.sep)[0]
print ("root_dir=",root_dir)
xml= ET.parse(".cproject")
root=xml.getroot()
# for child in root:
# print(child.tag, child.attrib)
for child in root.iter('sourceEntries'):
for gchild in child:
print(gchild.tag)
for child in root.iter('sourceEntries'):
for gchild in child:
if gchild.tag == 'entry':
attr = gchild.attrib
try:
if (attr['kind'] == 'sourcePath') and (attr['name'] == root_dir):
child.remove (gchild)
print ("Removed existing entry ",gchild.tag)
break
except:
print ("error matching attributes for ",gchild.tag)
pass
break #after first 'sourceEntries' - should be just one?
ET.SubElement(child, 'entry', {"flags":"VALUE_WORKSPACE_PATH", "kind":"sourcePath", "name":root_dir, "excluding":"|".join(excluding)})
for child in root.iter('sourceEntries'):
for gchild in child:
print(gchild.tag)
oneliner= ET.tostring(root)
#overwrites original .cproject, may change to somethong different
with open(".cproject", "wr") as f:
f.write("""<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?fileVersion 4.0.0?>""")
f.write(oneliner)
print (len(lstFiles), len(lst_a), "last access time = ",latest_at)
if __name__ == '__main__':
proc_tree()
"""
make clean # otherwise compiled files are preserved
bitbake apps-autoexposure -c cleansstate
bitbake apps-autoexposure -c unpack -f
bitbake apps-autoexposure -c configure -f
./used_files.py sysroots -1
bitbake apps-autoexposure -c compile -f
./used_files.py sysroots 1473297567.42
eyesis@eyesis-SH87R:~/git/elphel393/rootfs-elphel/elphel-apps-autoexposure$ ./used_files.py sysroots/elphel393/usr -1
root_path = sysroots/elphel393/usr
5615 last time = 1473300068.01
eyesis@eyesis-SH87R:~/git/elphel393/rootfs-elphel/elphel-apps-autoexposure$ ./used_files.py sysroots/elphel393/usr 1473300068.01
root_path = sysroots/elphel393/usr
root_dir= sysroots
entry
entry
entry
entry
entry
5615 84 last access time = 1473300080.1
"""
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment