Initial commit: TXW82x FPV v2.7.0.7-42229 SDK + project sources

This commit is contained in:
2026-07-06 11:30:13 +08:00
commit e76462eeb7
3451 changed files with 1415300 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <event.h>
#include <log.h>
#include <frame.h>
#include <stream.h>
#include <rtp.h>
void write_access_log( char *path, struct sockaddr *addr, int code, char *req,
int length, char *referer, char *user_agent )
{
/*
char s[128];
time_t now;
int req_len;
if( log_fd < 0 ) return;
for( req_len = 0; req[req_len] && req[req_len] != '\r' &&
req[req_len] != '\n'; ++req_len );
if( ! referer || ! referer[0] ) referer = "-";
if( ! user_agent || ! user_agent[0] ) user_agent = "-";
time( &now );
strcpy( s, inet_ntoa( ((struct sockaddr_in *)addr)->sin_addr ) );
write( log_fd, s, strlen( s ) );
write( log_fd, s,
strftime( s, sizeof( s ), " - - [%d/%b/%Y:%T %z] \"",
localtime( &now ) ) );
write( log_fd, req, req_len );
write( log_fd, s, sprintf( s, "\" %d %d \"", code, length ) );
write( log_fd, referer, strlen( referer ) );
write( log_fd, "\" \"", 3 );
write( log_fd, user_agent, strlen( user_agent ) );
write( log_fd, "\"\n", 2 );
*/
}

View File

@@ -0,0 +1,162 @@
#include "sys_config.h"
#include "tx_platform.h"
#include <csi_kernel.h>
#include "lwip\sockets.h"
#include "lwip\netif.h"
#include "lwip\dns.h"
#include "lwip\api.h"
#include "lwip\tcp.h"
#include "rtsp_common.h"
#include "osal/string.h"
#include "stream_define.h"
#include "video_app/video_app.h"
#include "stream_frame.h"
#include "log.h"
#include "lib/video/dvp/jpeg/jpg.h"
#include "frame.h"
#include "audio_media_ctrl/audio_code_ctrl.h"
#include "audio_msi/audio_adc.h"
#include "jpg_concat_msi.h"
#include "gen420_hardware_msi.h"
extern void spook_send_thread_stream(struct rtsp_priv *r);
extern void err_rtsp_stream(struct rtp_node *node);
static void self_thread(void *d)
{
struct rtsp_priv *r = (struct rtsp_priv*)d;
spook_send_thread_stream(r);
}
static void err_exit_thread(void *d)
{
struct rtp_node *node = (struct rtp_node *)d;
err_rtsp_stream(node);
}
//创建实时预览的的线程
static void self_creat(struct rtsp_source *source,void *priv)
{
const char *path = (const char *)priv;
while((*path) && (*path != '?'))
{
path++;
}
os_printf("match path:%s\n",path);
source->priv = (struct rtsp_priv*)os_zalloc(sizeof(struct rtsp_priv));
struct rtsp_priv *r = (struct rtsp_priv*)source->priv;
if(source->priv && *path == '?')
{
path++;
r->live_node = &source->live_node;
r->video_msi = msi_find(path, 1);
os_printf("video_msi :%s\tmsi:%X\n",path,r->video_msi);
if(r->video_msi)
{
r->v_msi = rtsp_msi_init("custom_rtp",~0,0);
if(r->v_msi)
{
msi_add_output(r->video_msi, NULL, "custom_rtp");
OS_TASK_INIT("live_rtsp_custom", &source->handle, self_thread, r, OS_TASK_PRIORITY_NORMAL + 2, NULL, 1024);
}
}
else
{
os_printf("%s jpg_concat_msi_init_start fail\n", __FUNCTION__);
OS_TASK_INIT("live_rtsp_err", &source->handle, err_exit_thread, &source->live_node, OS_TASK_PRIORITY_NORMAL + 2, NULL, 1024);
return;
}
}
else
{
os_printf("%s not enough space\n",__FUNCTION__);
OS_TASK_INIT("live_rtsp_err", &source->handle, err_exit_thread, &source->live_node, OS_TASK_PRIORITY_NORMAL + 2, NULL, 1024);
}
return;
}
static void self_destory(struct rtsp_source *source)
{
//stop_jpeg();
void *tmp = source->handle.hdl;
struct rtsp_priv *r = source->priv;
if(r)
{
if(r->video_msi)
{
msi_del_output(r->video_msi,NULL,"custom_rtp");
msi_put(r->video_msi);
r->video_msi = NULL;
}
rtsp_msi_deinit((void*)r->v_msi);
os_free(source->priv);
source->priv = NULL;
}
if(tmp)
{
os_task_del(&source->handle);
}
}
static int self_get_sdp( struct session *s, char *dest, int *len,
char *path )
{
struct rtsp_session *ls = (struct rtsp_session *)s->private;
int i = 0;
int t = 0;
char *addr = "IP4 0.0.0.0";
os_printf("%s:%d\tpath:%s\n",__FUNCTION__,__LINE__,path);
if( s->ep[0] && s->ep[0]->trans_type == RTP_TRANS_UDP )
addr = s->ep[0]->trans.udp.sdp_addr;
i = snprintf( dest, *len,"v=0\r\no=- 1 1 IN IP4 127.0.0.1\r\ns=Test\r\na=type:broadcast\r\nt=0 0\r\nc=IN %s\r\n", addr );
for( t = 0; t < MAX_TRACKS && ls->source->track[t].rtp; ++t )
{
int port;
if( s->ep[t] && s->ep[t]->trans_type == RTP_TRANS_UDP )
port = s->ep[t]->trans.udp.sdp_port;
else
port = 0;
if(ls->source->track[t].rtp->type == 0)
{
i += ls->source->track[t].rtp->get_sdp( dest + i, *len - i,96 + t, port,ls->source->track[t].rtp->private );
}
else
{
i += ls->source->track[t].rtp->get_sdp( dest + i, *len - i,96 + t, port,NULL);
}
if( port == 0 ) // XXX What's a better way to do this?
i += sprintf( dest + i, "a=control:track%d\r\n", t );
}
*len = i;
return t;
}
static struct session *self_rtsp_open( char *path, void *d )
{
//默认的,各自模式可以各自去修改
struct session *sess = rtsp_open(path,d);
if(sess)
{
sess->get_sdp = self_get_sdp;
}
return sess;
}
void custom_rtsp_jpeg_init(const rtp_name *rtsp)
{
struct rtsp_source *source;
source = rtsp_start_block();
rtsp_set_path( rtsp->path, source,self_rtsp_open );
set_video_track( (char*)rtsp->video_encode_name, source );
register_live_fn(source,self_creat,self_destory,NULL);
rtsp_end_block(source);
return ;
}

2233
sdk/app/spook/data.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,147 @@
/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <sys/types.h>
#include <stdlib.h>
//#include <stdio.h>
//#include <fcntl.h>
#include <event.h>
#include <log.h>
#include <frame.h>
#include <stream.h>
#include <spook_config.h>
#include <csi_kernel.h>
#include "encoder-audio.h"
//需要修改
static void get_framerate( struct stream *s, int *fincr, int *fbase )
{
/*struct jpeg_encoder *en = (struct jpeg_encoder *)s->private;*/
spook_log( SL_DEBUG, "jpeg get_framerate" );
*fincr = JPEG_FRAMEINC;
*fbase = 25;//JPEG_FRAMERATE-4;
}
static void set_running( struct stream *s, int running )
{
}
/************************ CONFIGURATION DIRECTIVES ************************/
static void *start_block(void)
{
struct audio_encoder *en;
en = (struct audio_encoder *)malloc( sizeof( struct audio_encoder ) );
en->output = NULL;
return en;
}
static void get_back_audio_frame( struct frame *f, void *d )
{
struct audio_encoder *en = (struct audio_encoder *)d;
_os_printf("-");
//exchange_frame( en->ex, new_frame() );
deliver_frame_to_stream( f, en->output );
}
static int end_block( void *d )
{
struct audio_encoder *en = (struct audio_encoder *)d;
//int i;
if( ! en->output )
{
spook_log( SL_ERR, "jpeg: missing output stream name" );
return -1;
}
en->ex = new_exchanger_audio( 0, get_back_audio_frame, en );
exchange_frame( en->ex, new_audio_frame() );
return 0;
}
static int set_output( const char *name, void *d )
{
struct audio_encoder *en = (struct audio_encoder *)d;
spook_log( SL_DEBUG, "audio set_output" );
en->output = new_stream( name, FORMAT_AUDIO, en );
if( ! en->output )
{
spook_log( SL_ERR, "jpeg: unable to create stream \"%s\"", name );
return -1;
}
en->output->get_framerate = get_framerate;
en->output->set_running = set_running;
return 0;
}
void *get_audio_ex(struct audio_encoder *en)
{
return en->ex;
}
void * rtp_audio_init_ret(void)
{
struct audio_encoder *en;
en = start_block();
set_output(AUDIO_ENCODER_NAME, en);
end_block(en);
return en->ex;
}
void * file_audio_init_ret(void)
{
struct audio_encoder *en;
en = start_block();
set_output(FILE_JPEG_ENCODER_NAME, en);
end_block(en);
return en->ex;
}
void *rtsp_audio_encode_init(const char *encode_name)
{
struct audio_encoder *en;
en = start_block();
set_output(encode_name, en);
end_block(en);
return en->ex;
}

View File

@@ -0,0 +1,20 @@
#ifndef __ENCODER_AUDIO_H
#define __ENCODER_AUDIO_H
struct audio_encoder {
struct stream *output;
int format;
struct frame_exchanger *ex;
volatile int running;
};
void * file_audio_init_ret(void);
void * rtp_audio_init_ret(void);
void *get_audio_ex(struct audio_encoder *en);
int rtp_audio_init(void);
#endif

View File

@@ -0,0 +1,137 @@
/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <event.h>
#include <log.h>
#include <frame.h>
#include <stream.h>
#include <spook_config.h>
#include <csi_kernel.h>
#include "encoder-jpeg.h"
extern volatile uint8_t framerate_c;
static void get_framerate( struct stream *s, int *fincr, int *fbase )
{
/*struct jpeg_encoder *en = (struct jpeg_encoder *)s->private;*/
spook_log( SL_DEBUG, "h264 get_framerate" );
*fincr = H264_FRAMEINC;
*fbase = 25;//JPEG_FRAMERATE-4;
}
static void set_running( struct stream *s, int running )
{
struct h264_encoder *en = (struct h264_encoder *)s->private;
spook_log( SL_DEBUG, "h264 set_running: %d", running);
en->running = running;
en->ex->scan_ready = running;
}
/************************ CONFIGURATION DIRECTIVES ************************/
static void *start_block(void)
{
struct h264_encoder *en;
en = (struct h264_encoder *)malloc( sizeof( struct h264_encoder ) );
en->output = NULL;
en->running = 0;
return en;
}
static void get_back_frame( struct frame *f, void *d )
{
struct h264_encoder *en = (struct h264_encoder *)d;
//exchange_frame( en->ex, new_frame() );
deliver_frame_to_stream( f, en->output );
}
static int end_block( void *d )
{
struct h264_encoder *en = (struct h264_encoder *)d;
//int i;
if( ! en->output )
{
spook_log( SL_ERR, "h264: missing output stream name" );
return -1;
}
en->ex = new_exchanger( EXCHANGER_SLOT_SIZE, get_back_frame, en );
en->ex->ready = 0;
en->ex->scan_ready = 0;
//for( i = 0; i < EXCHANGER_SLOT_SIZE; ++i )
exchange_frame( en->ex, new_frame() );
return 0;
}
static int set_output( const char *name, void *d )
{
struct h264_encoder *en = (struct h264_encoder *)d;
spook_log( SL_DEBUG, "h264 set_output" );
en->output = new_stream( name, FORMAT_H264, en );
if( ! en->output )
{
spook_log( SL_ERR, "h264: unable to create stream \"%s\"", name );
return -1;
}
en->output->get_framerate = get_framerate;
en->output->set_running = set_running;
return 0;
}
void *get_video_ex_h264(struct h264_encoder *en)
{
return en->ex;
}
void * file_h264_init_ret(void)
{
struct h264_encoder *en;
en = start_block();
set_output(FILE_H264_ENCODER_NAME, en);
end_block(en);
return en->ex;
}
void *h264_encode_init(const char *encode_name)
{
struct h264_encoder *en;
en = start_block();
set_output(encode_name, en);
end_block(en);
return en->ex;
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
//#include <fcntl.h>
//#include <event.h>
#include <log.h>
#include <frame.h>
#include <stream.h>
#include <spook_config.h>
#include <csi_kernel.h>
#include "encoder-jpeg.h"
extern volatile uint8_t framerate_c;
static void get_framerate( struct stream *s, int *fincr, int *fbase )
{
/*struct jpeg_encoder *en = (struct jpeg_encoder *)s->private;*/
spook_log( SL_DEBUG, "jpeg get_framerate" );
*fincr = JPEG_FRAMEINC;
*fbase = 25;//JPEG_FRAMERATE-4;
}
static void set_running( struct stream *s, int running )
{
struct jpeg_encoder *en = (struct jpeg_encoder *)s->private;
spook_log( SL_DEBUG, "jpeg set_running: %d", running);
en->running = running;
en->ex->scan_ready = running;
}
/************************ CONFIGURATION DIRECTIVES ************************/
static void *start_block(void)
{
struct jpeg_encoder *en;
en = (struct jpeg_encoder *)malloc( sizeof( struct jpeg_encoder ) );
en->output = NULL;
en->running = 0;
return en;
}
static void get_back_frame( struct frame *f, void *d )
{
struct jpeg_encoder *en = (struct jpeg_encoder *)d;
//exchange_frame( en->ex, new_frame() );
deliver_frame_to_stream( f, en->output );
}
//extern k_task_handle_t jpeg_scan_handle;
extern k_task_handle_t jpeg_send_handle;
extern k_task_handle_t jpeg_scan_handle;
//void spook_scan_thread(void *d);
void spook_send_thread(void *d);
void spook_scan_thread(void *d);
extern void jpeg_user();
static int end_block( void *d )
{
struct jpeg_encoder *en = (struct jpeg_encoder *)d;
//int i;
if( ! en->output )
{
spook_log( SL_ERR, "jpeg: missing output stream name" );
return -1;
}
en->ex = new_exchanger( EXCHANGER_SLOT_SIZE, get_back_frame, en );
en->ex->ready = 0;
en->ex->scan_ready = 0;
//for( i = 0; i < EXCHANGER_SLOT_SIZE; ++i )
exchange_frame( en->ex, new_frame() );
return 0;
}
static int set_output( const char *name, void *d )
{
struct jpeg_encoder *en = (struct jpeg_encoder *)d;
spook_log( SL_DEBUG, "jpeg set_output" );
en->output = new_stream( name, FORMAT_JPEG, en );
if( ! en->output )
{
spook_log( SL_ERR, "jpeg: unable to create stream \"%s\"", name );
return -1;
}
en->output->get_framerate = get_framerate;
en->output->set_running = set_running;
return 0;
}
void *get_video_ex(struct jpeg_encoder *en)
{
return en->ex;
}
void * file_jpeg_init_ret(void)
{
struct jpeg_encoder *en;
en = start_block();
set_output(FILE_JPEG_ENCODER_NAME, en);
end_block(en);
return en->ex;
}
void *jpeg_encode_init(const char *encode_name)
{
struct jpeg_encoder *en;
en = start_block();
set_output(encode_name, en);
end_block(en);
return en->ex;
}

View File

@@ -0,0 +1,29 @@
#ifndef __ENCODER_JPEG_H
#define __ENCODER_JPEG_H
#include "stream.h"
struct jpeg_encoder {
struct stream *output;
int format;
struct frame_exchanger *ex;
volatile int running;
};
struct h264_encoder {
struct stream *output;
int format;
struct frame_exchanger *ex;
volatile int running;
};
void * file_jpeg_init_ret(void);
void * jpeg_init_ret(void);
void *get_video_ex(struct jpeg_encoder *en);
void * jpeg_init(const rtp_name *jpg_name);
void * file_h264_init_ret(void);
void * h264_init_ret(void);
void *get_video_ex_h264(struct h264_encoder *en);
void * h264_spook_init(const rtp_name *h264_name);
#endif

1192
sdk/app/spook/ephoto.c Normal file

File diff suppressed because it is too large Load Diff

80
sdk/app/spook/event.h Normal file
View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "lwip\sockets.h"
#include "list.h"
#include "lib/net/eloop/eloop.h"
//#include "mutex_os.h"
#ifndef _EVENT_H
#define _EVENT_H
#define EVENT_TIME 1
#define EVENT_FD 2
#define EVENT_ALWAYS 3
#define EVENT_SOFT_QUEUE 4
#define EVENT_F_ENABLED 1
#define EVENT_F_REMOVE 2
#define EVENT_F_ONESHOT 4
#define EVENT_F_RUNNING 8
struct event_info;
typedef void (*callback)( struct event_info *e, void *d );
struct event_info {
struct event *e;
int type;
void *data;
};
int time_diff( eloop_time_ref *tr_start, eloop_time_ref *tr_end );
int time_ago( eloop_time_ref *tr );
void time_now( eloop_time_ref *tr );
void time_add( eloop_time_ref *tr, int msec );
void time_future( eloop_time_ref *tr, int msec );
struct soft_queue *new_soft_queue( int length );
void *get_next_event( struct soft_queue *sq );
int soft_queue_add( struct soft_queue *sq, void *d );
struct event *add_timer_event( int msec, unsigned int flags, callback f, void *d );
struct event *add_alarm_event( eloop_time_ref *t, unsigned int flags, callback f, void *d );
void resched_event( struct event *e, eloop_time_ref *t );
struct event *add_fd_event( int fd, int write, unsigned int flags, callback f, void *d );
struct event *add_always_event( unsigned int flags, callback f, void *d );
struct event *add_softqueue_event( struct soft_queue *sq, unsigned int flags,
callback f, void *d );
void remove_event( struct event *e );
void set_event_interval( struct event *e, int msec );
void set_event_enabled( struct event *e, int enabled );
int get_event_enabled( struct event *e );
void exit_event_loop(void);
void event_loop( int single );
#endif /* EVENT_H */

409
sdk/app/spook/frame.c Normal file
View File

@@ -0,0 +1,409 @@
/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <stdio.h>
//#include <test_util.h>
#include <csi_config.h>
#include <event.h>
#include <log.h>
#include <frame.h>
#include <list.h>
//#include <linux/linux_mutex.h>
#include "spook_config.h"
#include "rtp.h"
#include "lwip/api.h"
#include <csi_kernel.h>
#include "csi_core.h"
#include "list.h"
#include "jpgdef.h"
#include "osal/sleep.h"
#ifdef USB_EN
#include "dev/usb/uvc_host.h"
#endif
#include "osal/string.h"
#include "stream_frame.h"
#include "basic_include.h"
#include "lib/multimedia/msi.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
//data申请空间函数
#define STREAM_MALLOC av_psram_malloc
#define STREAM_FREE av_psram_free
#define STREAM_ZALLOC av_psram_zalloc
//结构体申请空间函数
#define STREAM_LIBC_MALLOC av_malloc
#define STREAM_LIBC_FREE av_free
#define STREAM_LIBC_ZALLOC av_zalloc
#define MAX_RTSP_JPG_RECV 28
struct jpg_rtsp_msi {
struct msi *msi;
uint8_t filter_type; //暂时只是支持某个类型的数据(0xffff是不过滤,只是判断stype)
uint8_t srcID;
//struct os_event evt;
//RBUFFER_DEF(data, struct framebuff *, MAX_RTSP_JPG_RECV);
};
#define MAX_RTSP_AUDIO_RECV 10
struct rtsp_audio_msi {
struct msi *msi;
};
static int32 rtsp_jpg_action(struct msi *msi, uint32 cmd_id, uint32 param1, uint32 param2)
{
struct jpg_rtsp_msi *jpg_rtsp = (struct jpg_rtsp_msi *)msi->priv;
int32_t ret = RET_OK;
//os_printf("cmd_id:%d\n",cmd_id);
switch (cmd_id) {
case MSI_CMD_POST_DESTROY:
{
os_printf("%s:%d\taddr:%X\n",__FUNCTION__,__LINE__,RETURN_ADDR());
STREAM_LIBC_FREE(jpg_rtsp);
}
break;
case MSI_CMD_TRANS_FB:
{
struct framebuff *fb = (struct framebuff *)param1;
//来源要匹配
if(jpg_rtsp->srcID && jpg_rtsp->srcID != fb->srcID)
{
ret = RET_ERR;
break;
}
if(jpg_rtsp->filter_type != (uint8_t)~0)
{
ret = RET_ERR;
if(jpg_rtsp->filter_type == fb->stype)
{
ret = RET_OK;
}
}
}
break;
case MSI_CMD_SET_SPEED: //设置播放倍速,控制数据读取行为
break;
default:
break;
}
return ret;
}
static int32_t rtsp_audio_action(struct msi *msi, uint32_t cmd_id, uint32_t param1, uint32_t param2)
{
struct rtsp_audio_msi *audio_rtsp = (struct rtsp_audio_msi*)msi->priv;
int32_t ret = RET_OK;
switch(cmd_id) {
case MSI_CMD_TRANS_FB:
{
ret = RET_OK;
break;
}
case MSI_CMD_POST_DESTROY:
{
STREAM_LIBC_FREE(audio_rtsp);
ret = RET_OK;
break;
}
default:
break;
}
return ret;
}
struct msi *rtsp_msi_init(const char *name,uint8_t filter_type,uint8_t srcID)
{
struct msi *rtsp_msi = msi_new(name,MAX_RTSP_JPG_RECV,NULL);
struct jpg_rtsp_msi *jpg_rtsp = rtsp_msi->priv;
if(!jpg_rtsp)
{
jpg_rtsp = (struct jpg_rtsp_msi*)STREAM_LIBC_ZALLOC(sizeof(struct jpg_rtsp_msi));
jpg_rtsp->filter_type = filter_type;
jpg_rtsp->srcID = srcID;
rtsp_msi->priv = (void*)jpg_rtsp;
rtsp_msi->action = rtsp_jpg_action;
jpg_rtsp->msi = rtsp_msi;
rtsp_msi->priv = (void*)jpg_rtsp;
}
rtsp_msi->enable = 1;
return rtsp_msi;
}
struct msi *rtsp_audio_msi_init(const char *name)
{
struct msi *rtsp_audio_msi = msi_new(name, MAX_RTSP_AUDIO_RECV,NULL);
struct rtsp_audio_msi *audio_rtsp = rtsp_audio_msi->priv;
if(!audio_rtsp) {
audio_rtsp = (struct rtsp_audio_msi*)STREAM_LIBC_ZALLOC(sizeof(struct rtsp_audio_msi));
rtsp_audio_msi->priv = (void*)audio_rtsp;
rtsp_audio_msi->action = (msi_action)rtsp_audio_action;
audio_rtsp->msi = rtsp_audio_msi;
}
rtsp_audio_msi->enable = 1;
return rtsp_audio_msi;
}
void rtsp_msi_deinit(struct msi *msi)
{
if(msi)
{
msi->enable = 0;
msi_destroy(msi);
}
}
void rtsp_audio_msi_deinit(struct msi *msi)
{
if(msi)
{
msi->enable = 0;
msi_destroy(msi);
}
}
struct frame *new_frame(void)
{
struct frame *f;
//新帧
f = (struct frame*)STREAM_LIBC_MALLOC(sizeof(struct frame));
return f;
}
struct frame *new_audio_frame(void)
{
struct frame *f;
//新帧
f = (struct frame*)STREAM_LIBC_MALLOC(sizeof(struct frame));
return f;
}
struct frame_exchanger *new_exchanger_audio( int slots,
frame_deliver_func func, void *d )
{
struct frame_exchanger *ex;
ex = (struct frame_exchanger *)STREAM_LIBC_MALLOC( sizeof( struct frame_exchanger ) );
ex->f = func;
ex->d = d;
return ex;
}
struct frame_exchanger *new_exchanger( int slots,
frame_deliver_func func, void *d )
{
struct frame_exchanger *ex;
ex = (struct frame_exchanger *)
STREAM_LIBC_MALLOC( sizeof( struct frame_exchanger ) );
ex->f = func;
ex->d = d;
/* read_mutex is used to avoid closing the tcp when frame is sending through sendmsg */
return ex;
}
int exchange_frame( struct frame_exchanger *ex, struct frame *frame )
{
ex->jf= frame;
return 0;
}
void unref_frame( struct frame *f )
{
// int r;
//del_frame
if(!f)
{
return;
}
DEL_JPG_FRAME((struct framebuff *)f->get_f);
}
static int opcode_func(stream *s,void *priv,int opcode)
{
int res = 0;
switch(opcode)
{
case STREAM_OPEN_ENTER:
break;
case STREAM_OPEN_EXIT:
{
enable_stream(s,1);
}
break;
case STREAM_OPEN_FAIL:
break;
case STREAM_RECV_DATA_FINISH:
break;
case STREAM_CLOSE_EXIT:
os_printf("%s:%d close\n",__FUNCTION__,__LINE__);
break;
default:
//默认都返回成功
break;
}
return res;
}
//正常这个就是运行就退出
void err_rtsp_stream(struct rtp_node *node)
{
struct frame_exchanger *ex = node->video_ex;
while(1)
{
ex->f( NULL, ex->d );
os_sleep_ms(1);
}
}
void spook_send_thread_stream(struct rtsp_priv *r)
{
struct rtp_node *node = r->live_node;
struct frame_exchanger *ex = node->video_ex;
struct frame_exchanger *audio_ex = node->audio_ex;
struct jpg_rtsp_msi *jpg_rtsp = r->v_msi?(struct jpg_rtsp_msi *)r->v_msi->priv:NULL;
struct rtsp_audio_msi *audio_rtsp = r->a_msi?(struct rtsp_audio_msi *)r->a_msi->priv:NULL;
struct frame *jpeg;
struct frame *audio;
struct framebuff *fb = NULL;
struct framebuff *audio_fb = NULL;
int count_times = 0;
int get_times_out = 0;
int cnt_num = 0;
uint32_t time_for_count;
uint32_t time = 0;
time_for_count = os_jiffies();
while(1)
{
if(audio_rtsp) {
audio_fb = msi_get_fb(audio_rtsp->msi, 0);
if(audio_fb && audio_fb->mtype != F_AUDIO) {
msi_delete_fb(NULL, audio_fb);
audio_fb = NULL;
}
if(audio_fb) {
audio = audio_ex->jf;
audio->get_f = (void*)audio_fb;
audio->length = audio_fb->len;
audio->timestamp = audio_fb->time;
audio->format = FORMAT_AUDIO;
audio_ex->f(audio,audio_ex->d);
}
}
fb = msi_get_fb(jpg_rtsp->msi, 0);
if(fb && (fb->mtype != F_H264 && fb->mtype != F_JPG))
{
msi_delete_fb(NULL, fb);
fb = NULL;
}
if (fb)
{
jpeg = ex->jf;
jpeg->get_f = (void*)fb;
jpeg->node_len = fb->len;
jpeg->d = (uint8_t*)fb->data;
jpeg->first_length = fb->len;
jpeg->length = fb->len;
jpeg->timestamp = fb->time;
jpeg->format = FORMAT_JPEG;
cnt_num++;
if((os_jiffies() - time_for_count) > 1000){
time_for_count = os_jiffies();
_os_printf(KERN_INFO"cnt_num:%d\r\n",cnt_num);
cnt_num = 0;
}
_os_printf("#");
ex->f( jpeg, ex->d );
}
if(fb)
{
ex->ready = 0;
count_times++;
if(count_times>25)
{
_os_printf("time:%lld\n", os_jiffies() - time);
count_times = 0;
time = os_jiffies();
}
}
if(!fb && !audio_fb)
{
os_sleep_ms(1);
get_times_out++;
if(get_times_out>1000)
{
ex->f( NULL, ex->d );
get_times_out = 0;
}
continue;
}
else
{
get_times_out = 0;
}
fb = NULL;
}
}

159
sdk/app/spook/frame.h Normal file
View File

@@ -0,0 +1,159 @@
/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
#define FORMAT_EMPTY 0
#define FORMAT_RAW_RGB24 1
#define FORMAT_RAW_UYVY 2
#define FORMAT_RAW_BGR24 3
#define FORMAT_PCM 64
#define FORMAT_MPEG4 100
#define FORMAT_JPEG 101
#define FORMAT_MPV 102
#define FORMAT_H263 103
#define FORMAT_MPA 200
#define FORMAT_ALAW 201
*/
#ifndef __FRAME_H
#define __FRAME_H
#include "spook_config.h"
#include "jpgdef.h"
#include "sys_config.h"
#include "stream_frame.h"
#include "basic_include.h"
#include "lib/multimedia/msi.h"
#define FORMAT_JPEG 101
#define FORMAT_H264 96
#define FORMAT_AUDIO 97
enum
{
RECORD_FLAG,
SAVE_PIC_FLAG,
WIFI_FPV_FLAG,
};
struct frame;
typedef int (*frame_destructor)( struct frame *f, void *d );
typedef void (*free_func)(void*node);
struct frame
{
int ref_count;
int size;
int format;
int width;
int height;
int length;
int node_len;
int first_length;
unsigned char *d;//链表第一帧数据
void * get_f;
struct jpeg_fifo *j;
uint32_t timestamp;
free_func free;
};
void init_frame_heap( int size, int count );
int get_max_frame_size(void);
struct frame *new_frame(void);
void ref_frame( struct frame *f );
void unref_frame( struct frame *f );
struct frame_slot {
struct frame_slot *next;
struct frame_slot *prev;
int pending;
struct frame *f;
};
typedef void (*frame_deliver_func)( struct frame *f, void *d );
typedef void (*frame_disconnect_func)( struct frame *f, void *d );
struct frame_exchanger {
int ready;
int scan_ready;
frame_deliver_func f;
struct frame *jf;
void *d;
};
struct rtp_node
{
void *video_ex; //frame_exchanger
void *audio_ex;
void *priv;
};
struct rtsp_priv
{
struct rtp_node *live_node;
//stream *video_s;
//stream *audio_s;
stream *webfile_s;
struct msi *video_msi;
struct msi *audio_msi;
struct msi *v_msi;
struct msi *a_msi;
};
struct frame_exchanger *new_exchanger( int slots,
frame_deliver_func func, void *d );
/* master functions */
int exchange_frame( struct frame_exchanger *ex, struct frame *frame );
/* slave functions */
struct frame *get_next_frame( struct frame_exchanger *ex, int wait );
void deliver_frame( struct frame_exchanger *ex, struct frame *f );
void *spook_register_video(const char *name,const char *action_name,int node_num);
void *spook_register_audio(const char *name,const char *action_name,int node_num,void *afmemt);
void spook_send_thread2(void *d);
int32_t spook_register_del_msg(void *signal);
struct frame_exchanger *new_exchanger_audio( int slots,frame_deliver_func func, void *d );
struct frame *new_audio_frame(void);
struct msi *rtsp_msi_init(const char *name,uint8_t filter_type,uint8_t srcID);
struct msi *rtsp_audio_msi_init(const char *name);
void rtsp_msi_deinit(struct msi *msi);
void rtsp_audio_msi_deinit(struct msi *msi);
#endif

72
sdk/app/spook/log.c Normal file
View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <stdarg.h>
//#include <test_util.h>
#include <csi_config.h>
#include "lwip/api.h"
#if 0
//#include <portmacro.h>
//extern void Uart_PutStr(unsigned char *p_str);
#define LOG_BUFFER_SIZE 1024
static int minlevel;
void spook_log_init( int min )
{
minlevel = min;
}
char string[ LOG_BUFFER_SIZE ];
void spook_debug( int level, char *fmt, ... )
{
#if 1
va_list ap;
//static char string[ LOG_BUFFER_SIZE ];
//OS_CPU_SR cpu_sr = 0u;
if( level < minlevel )
{
va_end( ap );
return;
}
//OS_ENTER_CRITICAL();
//disable_irq();
va_start( ap, fmt );
vsprintf( string , fmt, ap );
va_end( ap );
//Uart_PutStr(string);
_os_printf("%s",string);
//__enable_irq();
#endif
//OS_EXIT_CRITICAL();
}
#endif

33
sdk/app/spook/log.h Normal file
View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#define SL_DEBUG 0
#define SL_VERBOSE 1
#define SL_INFO 2
#define SL_WARN 3
#define SL_ERR 4
#define spook_log(l, s, args...) //spook_debug(l, s"\n", ##args)
#define c99_log(l, s, ...) //spook_debug(l, s"\n", ##__VA_ARGS__)
//void spook_debug( int level, char *fmt, ... );
//void spook_log_init( int min );

411
sdk/app/spook/pmsg.c Normal file
View File

@@ -0,0 +1,411 @@
/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
//#include "lib/common.h"
//#include "sys_config.h"
#include <log.h>
#include <pmsg.h>
#include "typesdef.h"
#include "osal/string.h"
#if 0
int strcasecmp(const char* str1, const char* str2)
{
while (*str1 != '\0' && *str2 != '\0')
{
if (*str1 != *str2)
{
if (((*str1 > 'a' || *str1 < 'z') && (*str1 - 'a' == *str2 - 'A')) ||
((*str1 > 'A' || *str1 < 'Z') && (*str1 - 'A' == *str2 - 'a')))
{
str1++;
str2++;
}
else
{
break;
}
}
else
{
str1++;
str2++;
}
}
return *str1 - *str2;
}
int strncasecmp(const char* str1, const char* str2, size_t n)
{
while (*str1 != '\0' && *str2 != '\0' && n-- > 1)
{
if (*str1 != *str2)
{
if (((*str1 > 'a' || *str1 < 'z') && (*str1 - 'a' == *str2 - 'A')) ||
((*str1 > 'A' || *str1 < 'Z') && (*str1 - 'A' == *str2 - 'a')))
{
str1++;
str2++;
}
else
{
break;
}
}
else
{
str1++;
str2++;
}
}
if (((*str1 > 'a' || *str1 < 'z') && (*str1 - 'a' == *str2 - 'A')) ||
((*str1 > 'A' || *str1 < 'Z') && (*str1 - 'A' == *str2 - 'a')))
{
return 0;
}
else
{
return *str1 - *str2;
}
}
#endif
char *add_pmsg_string( struct pmsg *msg, char *s )
{
int len = strlen( s ) + 1;
char *p;
if( msg->msg_len + len > msg->max_len ) return NULL;
p = (char *)(msg->msg + msg->msg_len);
msg->msg_len += len;
strcpy( p, s );
return p;
}
static int inline delim( char *d, int len, char term1, char term2 )
{
int s;
for( s = 0; s < len; ++s )
if( d[s] == term1 || d[s] == term2 ||
d[s] == '\r' || d[s] == '\n' )
break;
return s;
}
int parse_pmsg( struct pmsg *msg )
{
int i = 0;
unsigned char *d = msg->msg;
int len = msg->msg_len;
msg->header_count = 0;
/* Was it all whitespace? */
if( len - i < 4 ) return -1;
/* Check for a slash in the first word */
for( i = 0; i < len && d[i] != ' ' && d[i] != '/'; ++i );
if( i == len ) return -1;
/* Responses begin with "PROTO/" */
if( d[i] == '/' )
{
msg->type = PMSG_RESP;
/* The first word is the protocol name and version */
msg->proto_id = (char *)d;
i = delim( (char *)d, len, ' ', 0 );
/* Check for a space following the version number */
if( d[i] != ' ' ) return -1;
d[i++] = 0;
while( i < len && d[i] == ' ' ) ++i;
/* The next word is the 3-digit response code, then a space */
if( len - i < 4 || ! isdigit( d[i] ) || ! isdigit( d[i+1] )
|| ! isdigit( d[i+2] ) || d[i+3] != ' ' )
return -1;
msg->sl.stat.code = atoi( (char *)(d + i) );
i += 4;
while( i < len && d[i] == ' ' ) ++i;
/* The rest of the line is the textual response */
msg->sl.stat.reason = (char *)(d + i);
i += delim( (char *)(d + i), len - i, 0, 0 );
d[i++] = 0;
} else
{
msg->type = PMSG_REQ;
/* The first word is the method */
msg->sl.req.method = (char *)d;
i = delim( (char *)d, len, ' ', 0 );
/* Then a space */
if( i >= len || d[i] != ' ' ) return -1;
d[i++] = 0;
while( i < len && d[i] == ' ' ) ++i;
/* The second word is the URI */
msg->sl.req.uri = (char *)(d + i);
i += delim( (char *)(d + i), len - i, ' ', 0 );
/* Then a space */
if( i >= len || d[i] != ' ' ) return -1;
d[i++] = 0;
while( i < len && d[i] == ' ' ) ++i;
/* The last word is the protocol name and version */
msg->proto_id = (char *)(d + i);
i += delim( (char *)(d + i), len - i, 0, 0 );
d[i++] = 0;
#if 0
if(!strcmp(msg->sl.req.method, "SETID") ||
!strcmp(msg->sl.req.method, "GETID") ||
!strcmp(msg->sl.req.method, "RESET")) {
/* The last word is the protocol name and version */
msg->proto_id = (char *)(d + i);
i += delim( (char *)(d + i), len - i, ' ', 0 );
/* Then a space */
if( i >= len || d[i] != ' ' ) return -1;
d[i++] = 0;
while( i < len && d[i] == ' ' ) ++i;
/* The last word is the essid */
msg->essid = (char *)(d + i);
i += delim( (char *)(d + i), len - i, ' ', 0 );
/* Then a space */
if( i >= len || d[i] != ' ' ) return -1;
d[i++] = 0;
while( i < len && d[i] == ' ' ) ++i;
/* The last word is the password */
msg->password = (char *)(d + i);
i += delim( (char *)(d + i), len - i, ' ', 0 );
/* Then a space */
if( i >= len || d[i] != ' ' ) return -1;
d[i++] = 0;
while( i < len && d[i] == ' ' ) ++i;
/* The last word is the fly_id */
msg->fly_id = (char *)(d + i);
i += delim( (char *)(d + i), len - i, 0, 0 );
d[i++] = 0;
} else {
/* The last word is the protocol name and version */
msg->proto_id = (char *)(d + i);
i += delim( (char *)(d + i), len - i, 0, 0 );
d[i++] = 0;
}
#endif
}
/* Skip any trailing space */
while( i < len && d[i] == ' ' ) ++i;
/* Skip the \r if we didn't kill it already */
if( i < len && d[i] == '\r' ) ++i;
/* We should be at the end of the line now */
if( i >= len || d[i++] != '\n' ) return -1;
/* Now, parse all the header lines */
for(;;)
{
/* There may be a \r here if we're at the end of the headers */
if( i < len && d[i] == '\r' ) ++i;
/* If there's no more data, we're done */
if( i == len ) return len;
/* If there's a newline, we're at the end of the headers */
if( d[i] == '\n' ) return i + 1;
/* XXX headers beginning with whitespace are continuations */
if( d[i] == '\t' || d[i] == ' ' ) return -1;
/* The first thing on the line is the header name */
msg->fields[msg->header_count].name = (char *)(d + i);
/* The name ends with optional spaces then a colon */
i += delim( (char *)(d + i), len - i, ' ', ':' );
if( i >= len ) return -1;
/* If the optional spaces are present, skip them */
if( d[i] == ' ' )
{
d[i++] = 0;
while( i < len && d[i] == ' ' ) ++i;
}
/* Make sure the colon is present */
if( i >= len || d[i] != ':' ) return -1;
d[i++] = 0;
/* Skip any whitespace after the colon */
while( i < len && ( d[i] == ' ' || d[i] == '\t' ) ) ++i;
/* Everything else on the line is the header data */
msg->fields[msg->header_count].value = (char *)(d + i);
i += delim( (char *)(d + i), len - i, 0, 0 );
d[i++] = 0;
/* We should be at the end of the line now */
if( i >= len || d[i++] != '\n' ) return -1;
++msg->header_count;
}
}
char *get_header( struct pmsg *msg, char *name )
{
int i;
for( i = 0; i < msg->header_count; ++i )
if( ! os_strcasecmp( msg->fields[i].name, name ) )
return msg->fields[i].value;
return NULL;
}
int add_header( struct pmsg *msg, char *name, char *value )
{
if( msg->header_count == MAX_FIELDS ) return -1;
/* Put the name and value back-to-back at the end of the message */
msg->fields[msg->header_count].name = add_pmsg_string( msg, name );
if( ! msg->fields[msg->header_count].name ) return -1;
msg->fields[msg->header_count].value = add_pmsg_string( msg, value );
if( ! msg->fields[msg->header_count].value ) return -1;
++msg->header_count;
return 0;
}
int add_header_printf( struct pmsg *msg, char *name, char *fmt, ... )
{
va_list ap;
int len;
/* do the vsnprintf first to clean up the stack */
va_start( ap, fmt );
len = vsnprintf( (char *)(msg->msg + msg->msg_len), msg->max_len - msg->msg_len,
fmt, ap );
va_end( ap );
/* check for errors */
if( msg->header_count == MAX_FIELDS ) return -1;
/* vsnprintf will return the length of the formatted string
* regardless of length, although the actual output may be truncated */
if( msg->msg_len + len >= msg->max_len ) return -1;
msg->fields[msg->header_count].value = (char *)(msg->msg + msg->msg_len);
msg->msg_len += len + 1;
/* add the name */
msg->fields[msg->header_count].name = add_pmsg_string( msg, name );
if( ! msg->fields[msg->header_count].name ) return -1;
++msg->header_count;
return 0;
}
int replace_header( struct pmsg *msg, char *name, char *value )
{
int i;
for( i = 0; i < msg->header_count; ++i )
if( ! strcasecmp( msg->fields[i].name, name ) )
{
/* If we can't reuse the space from the original value,
* we have to allocate space for the new value at the
* end of the message */
if( strlen( msg->fields[i].value ) < strlen( value ) )
{
char *p = add_pmsg_string( msg, value );
if( ! p ) return -1;
msg->fields[i].value = p;
} else strcpy( msg->fields[i].value, value );
return 0;
}
/* It doesn't exist, so we'll insert it as new */
return add_header( msg, name, value );
}
int copy_headers( struct pmsg *dest, struct pmsg *src, char *name )
{
int i, count = 0;
for( i = 0; i < src->header_count; ++i )
if( ! strcasecmp( src->fields[i].name, name ) )
{
add_header( dest, src->fields[i].name,
src->fields[i].value );
++count;
}
return count;
}
#if 0
/* get_param() returns 1 for found, 0 for not found, -1 for error */
int get_param( char *value, char *tag, char *dest, int size )
{
int taglen, i;
char *c;
if( ! value ) return -1;
taglen = strlen( tag );
for( c = value; c; c = strchr( c, ';' ) )
{
++c;
if( ! strncasecmp( c, tag, taglen ) )
{
c += taglen;
if( *c == 0 || *c == ';' ) /* Value-less tag */
{
if( dest && size > 0 ) *dest = 0;
return 1;
} else if( *c == '=' ) /* Tag has an associated value */
{
if( ! dest || size <= 0 ) return 1;
++c;
for( i = 0; *c && *c != ';' && i < size;
++i, ++c )
dest[i] = *c;
if( i == size ) return -1;
dest[i] = 0;
return 1;
} /* Otherwise, it's a false hit */
}
}
return 0;
}
#endif
struct pmsg *new_pmsg( int size )
{
struct pmsg *msg;
void *v;
if( ! ( v = malloc( sizeof( struct pmsg ) + size ) ) )
{
spook_log( SL_ERR, "unable to allocate memory for message" );
return NULL;
}
msg = (struct pmsg *)v;
msg->msg = v + sizeof( struct pmsg );
msg->max_len = size;
msg->msg_len = 0;
msg->header_count = 0;
msg->proto_id = NULL;
//_os_printf("%s malloc:%X\n",__FUNCTION__,msg);
return msg;
}
void free_pmsg( struct pmsg *msg )
{
//_os_printf("%s free:%X\n",__FUNCTION__,msg);
free( msg );
}

45
sdk/app/spook/pmsg.h Normal file
View File

@@ -0,0 +1,45 @@
struct hdrf {
char *name;
char *value;
};
#define MAX_FIELDS 32
struct pmsg {
unsigned char *msg;
int max_len;
int msg_len;
struct hdrf fields[MAX_FIELDS];
int header_count;
enum { PMSG_REQ, PMSG_RESP } type;
char *proto_id;
// char *essid;
// char *password;
// char *fly_id;
union {
struct {
char *method;
char *uri;
} req;
struct {
int code;
char *reason;
} stat;
} sl;
};
char *add_pmsg_string( struct pmsg *msg, char *s );
int parse_pmsg( struct pmsg *msg );
char *get_header( struct pmsg *msg, char *name );
int add_header( struct pmsg *msg, char *name, char *value );
int add_header_printf( struct pmsg *msg, char *name, char *fmt, ... );
int replace_header( struct pmsg *msg, char *name, char *value );
int copy_headers( struct pmsg *dest, struct pmsg *src, char *name );
int get_param( char *value, char *tag, char *dest, int size );
struct pmsg *new_pmsg( int size );
void free_pmsg( struct pmsg *msg );
/* http-auth.c */
int check_digest_response( struct pmsg *msg, char *realm,
char *username, char *password );
int add_digest_challenge( struct pmsg *msg, char *realm, int stale );

199
sdk/app/spook/rtp-audio.c Normal file
View File

@@ -0,0 +1,199 @@
/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include "lwip\sockets.h"
#include "lwip\netif.h"
#include "lwip\dns.h"
#include "lwip\api.h"
#include "lwip\tcp.h"
#include <event.h>
#include <log.h>
#include <frame.h>
#include <stream.h>
#include <rtp.h>
#include <rtp_media.h>
#include <spook_config.h>
#include "list.h"
#include "jpgdef.h"
#include "rtp.h"
#include "session.h"
#include "osal/sleep.h"
#include "lib/audio/audio_code/audio_code.h"
#define AUDIO_SAMPLE 8000
struct rtp_audio {
//为了获取到frame,因为使用了链表形式
struct frame *f;
unsigned int timestamp;
};
static int audio_get_sdp( char *dest, int len, int payload, int port, void *d )
{
uint32_t audio_sample_rate = (uint32)d;
_os_printf("audio_sample_rate:%d\n",audio_sample_rate);
if(audio_sample_rate == 0)
{
audio_sample_rate = AUDIO_SAMPLE;//默认采样率
}
return snprintf( dest, len, "m=audio %d RTP/AVP 97\r\na=rtpmap:97 mpeg4-generic/%d/1\r\na=fmtp:97 profile-level-id=1; mode=AAC-hbr; config=1588; sizeLength=13; indexlength=3; indexdeltalength=3\r\n", port,audio_sample_rate);
// return snprintf( dest, len, "m=audio %d RTP/AVP 97\r\na=rtpmap:97 PCMA/%d/1\r\n", port,audio_sample_rate);
// return snprintf( dest, len, "m=audio %d RTP/AVP 97\r\na=rtpmap:97 L16/%d/1\r\n", port,audio_sample_rate);
}
static int audio_process_frame( struct frame *f, void *d )
{
_os_printf("+");
struct rtp_media *rtp = (struct rtp_media *)d;
struct rtp_audio *out = (struct rtp_audio *)rtp->private;
out->f = f;
out->timestamp = f->timestamp*(rtp->sample_rate/(1000));
return 1;
}
static int audio_get_payload( int payload, void *d )
{
_os_printf("%s:%d\n",__FUNCTION__,__LINE__);
return 97;
}
static int audio_send( struct rtp_endpoint *ep, void *d )
{
return 0;
}
static void audio_build_au_header( unsigned char *au_hdr, int au_size )
{
au_hdr[0] = 0x00;
au_hdr[1] = 0x10;
au_hdr[2] = ( au_size & 0x1FE0 ) >> 5;
au_hdr[3] = ( au_size & 0x1F ) << 3;
}
static int audio_send_au_to_endpoint( struct rtp_endpoint *ep, uint32_t timestamp, uint8_t *au_data, uint32_t au_size, int times )
{
struct iovec v[3];
uint8_t au_hdr[4];
int max_payload;
uint32_t max_fragment_size;
uint32_t offset = 0;
uint32_t fragment_len;
if( !ep || !ep->sendEnable || !au_data || au_size <= 0 ) return -1;
if( au_size > 0x1FFF )
{
spook_log( SL_ERR, "AAC AU too large for 13-bit AU-size field: %d", au_size );
ep->sendEnable = 0;
return -1;
}
max_payload = rtp_get_payload_size_limit( ep, RTP_HEADER_SIZE );
if( max_payload <= (int)sizeof( au_hdr ) )
{
ep->sendEnable = 0;
return -1;
}
max_fragment_size = max_payload - sizeof( au_hdr );
audio_build_au_header( au_hdr, au_size );
v[1].iov_base = au_hdr;
v[1].iov_len = sizeof( au_hdr );
while( offset < au_size )
{
fragment_len = au_size - offset;
if( fragment_len > max_fragment_size )
fragment_len = max_fragment_size;
v[2].iov_base = (void *)( au_data + offset );
v[2].iov_len = fragment_len;
if( rtp_sendmsg( ep, v, 3, timestamp, offset + fragment_len >= au_size, times ) < 0 )
{
ep->sendEnable = 0;
return -1;
}
offset += fragment_len;
}
return 0;
}
static int audio_send_more( rtp_loop_search_ep search, void *ls, void *track, void *d )
{
struct rtp_endpoint *ep;
void *head;
uint32_t au_size;
struct rtp_audio *out = (struct rtp_audio *)d;
struct framebuff *fb = (struct framebuff *)out->f->get_f;
if( !fb || fb->len <= 7 )
{
return 0;
}
au_size = fb->len - 7;
head = ls;
while(head)
{
head = search(head,track,(void*)&ep);
if(!ep)
{
continue;
}
if(ep->sendEnable)
{
if( audio_send_au_to_endpoint( ep, out->timestamp, fb->data + 7, au_size, 10 ) < 0 )
{
ep->sendEnable = 0;
}
}
ep->sendEnable = 1;
}
return 0;
}
struct rtp_media *new_rtp_media_audio_stream( struct stream *stream )
{
struct rtp_audio *out;
int fincr, fbase;
struct rtp_media *m;
stream->get_framerate( stream, &fincr, &fbase );
out = (struct rtp_audio *)malloc( sizeof( struct rtp_audio ) );
out->f = NULL;
out->timestamp = 0;
m = new_rtp_rtcp_media( audio_get_sdp, audio_get_payload, audio_process_frame, audio_send, new_rtcp_send, out );
if(m)
{
m->sample_rate = AUDIO_SAMPLE;//默认
m->type = 1; //音频
m->send_more = audio_send_more;
m->per_ms_incr = AUDIO_SAMPLE/(1000);
}
return m;
}

View File

@@ -0,0 +1,6 @@
#ifndef __RTP_AUDIO_H
#define __RTP_AUDIO_H
#include "stream.h"
struct rtp_media *new_rtp_media_audio_stream( struct stream *stream );
#endif

320
sdk/app/spook/rtp-h264.c Normal file
View File

@@ -0,0 +1,320 @@
/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include "lwip\sockets.h"
#include "lwip\netif.h"
#include "lwip\dns.h"
#include "lwip\api.h"
#include "lwip\tcp.h"
#include <event.h>
#include <log.h>
#include <frame.h>
#include <stream.h>
#include <rtp.h>
#include <rtp_media.h>
#include <spook_config.h>
#include "list.h"
#include "jpgdef.h"
#include "rtp.h"
#include "session.h"
#include "osal/sleep.h"
#include "stream_define.h"
#define H264_SAMPLE 90000
struct rtp_h264 {
//为了获取到frame,因为使用了链表形式
unsigned char *d;//链表第一帧数据
struct frame *f;
unsigned int timestamp;
uint8_t first_flag;
uint8_t last_count;
};
static int h264_get_sdp( char *dest, int len, int payload, int port, void *d )
{
uint32_t h264_sample_rate = (uint32)d;
_os_printf("h264_sample_rate:%d\n",h264_sample_rate);
if(h264_sample_rate == 0)
{
h264_sample_rate = H264_SAMPLE;//默认采样率
}
return snprintf( dest, len, "m=video %d RTP/AVP 96\r\na=rtpmap:96 H264/%d\r\na=decode_buf=300\r\n", port,h264_sample_rate);
}
static int h264_process_frame( struct frame *f, void *d )
{
struct rtp_media *rtp = (struct rtp_media *)d;
struct rtp_h264 *out = (struct rtp_h264 *)rtp->private;
_os_printf("+");
out->f = f;
out->d = f->d;
out->timestamp = f->timestamp*(rtp->sample_rate/1000);
return 1;
}
static int h264_get_payload( int payload, void *d )
{
return FORMAT_H264;
}
static int h264_send( struct rtp_endpoint *ep, void *d )
{
return 0;
}
static int h264_send_nalu( struct rtp_endpoint *ep, uint32_t timestamp, uint8_t *nalu, uint32_t nalu_len, uint8_t marker, int times, int max_payload )
{
struct iovec v[3];
uint8_t fu_hdr[2];
uint32_t offset;
uint32_t chunk;
if( !ep || !ep->sendEnable || !nalu || nalu_len <= 0 )
{
return -1;
}
if( nalu_len <= max_payload )
{
// single NALU
v[1].iov_base = (void *)nalu;
v[1].iov_len = nalu_len;
if( rtp_sendmsg( ep, v, 2, timestamp, marker, times ) < 0 )
{
ep->sendEnable = 0;
return -1;
}
return 0;
}
if( nalu_len <= 1 || max_payload <= 2 )
{
ep->sendEnable = 0;
return -1;
}
// FU-A
fu_hdr[0] = ( nalu[0] & 0xE0 ) | 28;
for( offset = 1; offset < nalu_len; offset += chunk )
{
chunk = nalu_len - offset;
if( chunk > max_payload - 2 )
{
chunk = max_payload - 2;
}
fu_hdr[1] = nalu[0] & 0x1F;
if( offset == 1 )
{
fu_hdr[1] |= 0x80;
}
if( offset + chunk >= nalu_len )
{
fu_hdr[1] |= 0x40;
}
v[1].iov_base = fu_hdr;
v[1].iov_len = sizeof( fu_hdr );
v[2].iov_base = (void *)( nalu + offset );
v[2].iov_len = chunk;
if( rtp_sendmsg( ep, v, 3, timestamp, offset + chunk >= nalu_len ? marker : 0, times ) < 0 )
{
ep->sendEnable = 0;
return -1;
}
}
return 0;
}
static void h264_send_nalu_to_endpoint( struct rtp_endpoint *ep, struct rtp_h264 *out, uint8_t *nalu, uint32_t nalu_len, uint8_t marker, int times )
{
int max_payload;
if( !ep || !ep->sendEnable )
{
return;
}
max_payload = rtp_get_payload_size_limit( ep, RTP_HEADER_SIZE );
if( max_payload <= 0 )
{
ep->sendEnable = 0;
return;
}
if( h264_send_nalu( ep, out->timestamp, nalu, nalu_len, marker, times, max_payload ) < 0 )
{
ep->sendEnable = 0;
}
}
static void h264_send_sps_pps( struct rtp_endpoint *ep, struct rtp_h264 *out, struct fb_h264_s *h264, int retries )
{
// stap-a: 1B头 + 2B sps_len + sps + 2B pps_len + pps
struct iovec v[6];
unsigned char stap_hdr;
unsigned char sps_len[2];
unsigned char pps_len[2];
int max_payload;
int stap_payload_len;
if( !ep || !ep->sendEnable || !h264 || !h264->sps || !h264->pps || !h264->sps_len || !h264->pps_len )
{
_os_printf("%s %d\n", __FUNCTION__, __LINE__);
return;
}
max_payload = rtp_get_payload_size_limit( ep, RTP_HEADER_SIZE );
if( max_payload <= 0 )
{
ep->sendEnable = 0;
_os_printf("%s %d\n", __FUNCTION__, __LINE__);
return;
}
stap_payload_len = 1 + 2 + h264->sps_len + 2 + h264->pps_len;
if( stap_payload_len > max_payload )
{
h264_send_nalu_to_endpoint( ep, out, h264->sps, h264->sps_len, 0, retries );
if( ep->sendEnable )
{
h264_send_nalu_to_endpoint( ep, out, h264->pps, h264->pps_len, 0, retries );
}
return;
}
stap_hdr = ( h264->sps[0] & 0xE0 ) | 24;
PUT_16( sps_len, h264->sps_len );
PUT_16( pps_len, h264->pps_len );
v[1].iov_base = &stap_hdr;
v[1].iov_len = 1;
v[2].iov_base = sps_len;
v[2].iov_len = 2;
v[3].iov_base = h264->sps;
v[3].iov_len = h264->sps_len;
v[4].iov_base = pps_len;
v[4].iov_len = 2;
v[5].iov_base = h264->pps;
v[5].iov_len = h264->pps_len;
if( rtp_sendmsg( ep, v, 6, out->timestamp, 0, retries ) < 0 )
{
ep->sendEnable = 0;
}
}
static int h264_send_more( rtp_loop_search_ep search, void *ls, void *track, void *d )
{
struct rtp_h264 *out = (struct rtp_h264 *)d;
struct framebuff *fb = (struct framebuff *)out->f->get_f;
struct fb_h264_s *h264;
uint8_t *nalu;
uint32_t nalu_len;
struct rtp_endpoint *ep;
void *head;
if( !fb || !fb->data || fb->len <= 0 )
{
return -1;
}
h264 = (struct fb_h264_s *)fb->priv;
if( h264 )
{
if( h264->type == 1 )
{
out->first_flag = 1;
}
else if( out->last_count != h264->count )
{
out->first_flag = 0;
os_printf(KERN_NOTICE"drop frame\n");
}
if( !out->first_flag )
{
return -1;
}
nalu = fb->data + h264->start_len;
nalu_len = fb->len - h264->start_len;
if( nalu_len <= 0 )
{
return -1;
}
out->last_count = h264->count + 1;
head = ls;
while( head )
{
head = search( head, track, (void *)&ep );
if( !ep )
{
continue;
}
if( !ep->sendEnable )
{
continue;
}
if( h264->type == 1 )
{
h264_send_sps_pps( ep, out, h264, 30 );
}
if( ep->sendEnable )
{
h264_send_nalu_to_endpoint( ep, out, nalu, nalu_len, 1, 30 );
}
ep->sendEnable = 1;
}
}
return 0;
}
struct rtp_media *new_rtp_media_h264_stream( struct stream *stream )
{
struct rtp_h264 *out;
int fincr, fbase;
struct rtp_media *m;
stream->get_framerate( stream, &fincr, &fbase );
out = (struct rtp_h264 *)malloc( sizeof( struct rtp_h264 ) );
out->f = NULL;
out->timestamp = 0;
//return new_rtp_media( audio_get_sdp, audio_get_payload,audio_process_frame, audio_send, out );
m = new_rtp_rtcp_media( h264_get_sdp, h264_get_payload,h264_process_frame, h264_send,new_rtcp_send, out );
if(m)
{
m->sample_rate = H264_SAMPLE;//默认
m->type = 1; //音频
m->send_more = h264_send_more;
m->per_ms_incr = H264_SAMPLE/(1000);
}
return m;
}

567
sdk/app/spook/rtp-jpeg.c Normal file
View File

@@ -0,0 +1,567 @@
/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include "lwip\sockets.h"
#include "lwip\netif.h"
#include "lwip\dns.h"
#include "lwip\api.h"
#include "lwip\tcp.h"
#include <event.h>
#include <log.h>
#include <frame.h>
#include <stream.h>
#include <rtp.h>
#include <rtp_media.h>
#include <spook_config.h>
#include "list.h"
#include "jpgdef.h"
#include "osal/sleep.h"
#include "session.h"
//#include "common.h"
#include "csi_kernel.h"
#include "osal/string.h"
#include "utlist.h"
#ifdef USB_EN
#include "dev/usb/uvc_host.h"
#endif
#define EXTHDR_LEN 6
#define EXTHDROFF_MAGIC 0
#define EXTHDROFF_VER 1
#define EXTHDROFF_DRI 2
#define EXTHDROFF_HUFF 4
struct rtp_jpeg {
unsigned char *d;//链表第一帧数据
int type;
int q;
int width;
int height;
int luma_table;
int chroma_table;
int quant[16];
int huffoff;
int hufflen;
unsigned char exthdr[EXTHDR_LEN];
unsigned char *scan_data;
int scan_data_len;
int offset;
int init_done;
int ts_incr;
unsigned int timestamp;
int reset_interval;
int dri_num;
unsigned short int dri_len[100];
//为了获取到frame,因为使用了链表形式
struct frame *f;
};
static int parse_DQT( struct rtp_jpeg *out, unsigned char *d, int len )
{
int i;
for( i = 0; i < len; i += 65 )
{
if( ( d[i] & 0xF0 ) != 0 )
{
_os_printf( "Unsupported quant table precision 0x%X!\n",
d[i] & 0xF0 );
return -1;
}
//out->quant[d[i] & 0xF] = d + i + 1;
out->quant[d[i] & 0xF] = d-out->d+i+1;
//out->quant[d[i] & 0xF] = out->scan_data - (d + i + 1);
}
return 0;
}
static int parse_SOF( struct rtp_jpeg *out, unsigned char *d, int len )
{
int c;
out->chroma_table = -1;
if( d[0] != 8 )
{
_os_printf( "Invalid precision %d in SOF0\n", d[0] );
return -1;
}
out->height = GET_16( d + 1 );
out->width = GET_16( d + 3 );
if( ( out->height & 0x7 ) || ( out->width & 0x7 ) )
{
os_printf(KERN_ERR"Width/height not divisible by 8!\n" );
os_printf(KERN_ERR"w:%d\th:%d\n",out->width,out->height);
return -1;
}
out->width >>= 3;
out->height >>= 3;
if( d[5] != 3 )
{
_os_printf( "Number of components is %d, not 3!\n", d[5] );
return -1;
}
/* Loop over the parameters for each component */
for( c = 6; c < 6 + 3 * 3; c += 3 )
{
// if( d[c + 2] >= 16 || ! out->quant[d[c + 2]] )
// {
// _os_printf( "Component %d specified undefined quant table %d!\n", d[c], d[c + 2] );
// return -1;
// }
switch( d[c] ) /* d[c] contains the component ID */
{
case 1: /* Y */
/*
if( d[c + 1] == 0x11 ) out->type = 0;
else if( d[c + 1] == 0x22 ) out->type = 1;
*/
if( d[c + 1] == 0x21 ) out->type = out->type & ~1; //YUV422
else if( d[c + 1] == 0x22 ) out->type = (out->type & ~1)|1; //YUV420
else
{
_os_printf( "Invalid sampling factor 0x%02X in Y component!\n", d[c + 1] );
return -1;
}
out->luma_table = d[c + 2];
break;
case 2: /* Cb */
case 3: /* Cr */
if( d[c + 1] != 0x11 )
{
_os_printf( "Invalid sampling factor 0x%02X in %s component!\n", d[c + 1], d[c] == 2 ? "Cb" : "Cr" );
return -1;
}
if( out->chroma_table < 0 )
out->chroma_table = d[c + 2];
else if( out->chroma_table != d[c + 2] )
{
_os_printf( "Cb and Cr components do not share a quantization table!\n" );
return -1;
}
break;
default:
_os_printf( "Invalid component %d in SOF!\n", d[c] );
return -1;
}
}
return 0;
}
static int parse_DHT( struct rtp_jpeg *out, unsigned char *d, int len )
{
/* We should verify that this coder uses the standard Huffman tables */
/* Kaifan:
* Some USB-Sensor do not use standard Huffman tables.
* So I add Huffman following quant table.
* It's compatible to the old version of App,
* It just looks like some dummy quant tables exist.
* But the dummy size can not be too long, because the old rtpdec-jpeg.c uses hdr[1024]
*/
if(0 == out->hufflen)
{
//out->huffoff = out->scan_data - (d - 4);
out->huffoff = (int)( ( d - 4 ) - out->d );
}
out->hufflen += len + 4;
PUT_16(out->exthdr+EXTHDROFF_HUFF, out->hufflen);
return 0;
}
static void parse_DRI (struct rtp_jpeg *out, unsigned char *d)
{
if (GET_16( d )) {
out->type |= 0x40;
out->reset_interval = GET_16( d );
/* Kaifan:
* Some USB-Sensor's reset-interval is not width/16.
* But the origin room for reset-interval is used by res_len.
* So Save the reset-interval before the Huffman table
*/
PUT_16(out->exthdr+EXTHDROFF_DRI, out->reset_interval);
}
}
extern volatile uint8_t framerate_c;
void clear_init_done(void *d)
{
_os_printf("%s:%d\n",__FUNCTION__,__LINE__);
struct rtp_jpeg *out = (struct rtp_jpeg *)d;
out->init_done = 0;
}
static int jpeg_process_frame( struct frame *f, void *d )
{
struct rtp_media *rtp = (struct rtp_media *)d;
struct rtp_jpeg *out = (struct rtp_jpeg *)rtp->private;
out->f = f;
int i, blen;
uint32_t per_ms_incr = (25 * out->ts_incr)/1000;
//static uint32_t last_time = 0;
//uint32_t sys_time = 0;
out->timestamp = per_ms_incr*f->timestamp;
//out->scan_data = j->scan_data;
//out->scan_data_len = j->scan_data_len;
//out->dri_num = j->dri_num;
//memcpy(out->dri_len, j->dri_len, sizeof(j->dri_len));
/* note by jornny
* just parse once in order to reduce time of processing frame
*/
//uvc 每一次都要扫描
#if USB_EN == 1
out->init_done = 0;
#endif
if(out->init_done == 0 ) {
out->init_done =0;
for( i = 0; i < 16; ++i ) out->quant[i] = 0;
out->type = 0;
out->reset_interval = 0;
/* Kaifan:
* exthdr[0] = 0 let the App knows the extend protocol
* exthdr[1] = 0 extend protocal version 0
*/
out->hufflen = 0;
out->exthdr[EXTHDROFF_MAGIC] = 0;
out->exthdr[EXTHDROFF_VER] = 0;
} else {
return out->init_done;
}
//out->dri_num = 0;
out->d = f->d;
//增加一个前置空数的地方
for( i = 0; i < f->first_length; i += blen + 2 )
{
if( f->d[i] != 0xFF )
{
_os_printf( "Found %02X at %d, expecting FF\n", f->d[i], i );
out->scan_data_len = 0;
return 0;
}
while(f->d[i+1] == 0xFF) ++i;
/* SOI (FF D8) is a bare marker with no length field */
if( f->d[i + 1] == 0xD8 ) blen = 0;
else blen = GET_16( f->d + i + 2 );
switch( f->d[i + 1] )
{
case 0xDB: /* Quantization Table */
if( out->init_done ) break;
if( parse_DQT( out, f->d + i + 4, blen - 2 ) < 0 )
{
out->scan_data_len = 0;
_os_printf( "jpeg_process_frame Quantization Table err!\n" );
return 0;
}
break;
case 0xC0: /* Start of Frame */
if( out->init_done ) break;
if( parse_SOF( out, f->d + i + 4, blen - 2 ) < 0 )
{
out->scan_data_len = 0;
_os_printf( "jpeg_process_frame Start of Frame err!\n" );
return 0;
}
break;
case 0xC4: /* Huffman Table */
// if( out->init_done ) break; /* only parse DHT once */ /* Kaifan: No! Maybe has 4 DHTs! */
if( parse_DHT( out, f->d + i + 4, blen - 2 ) < 0 )
{
out->scan_data_len = 0;
_os_printf( "jpeg_process_frame Huffman Table err!\n" );
return 0;
}
// out->init_done = 1; /* Kaifan: Maybe has 4 DHTs! So can't done here */
break;
case 0xDD: /* DRI */
if( out->init_done ) break;
parse_DRI (out, f->d + i + 4);
break;
case 0xDA: /* Start of Scan */
out->init_done = 1; /* Kaifan: Now can done here */
out->scan_data = f->d + i + 14;
out->scan_data_len = f->length - (out->scan_data - f->d);
out->offset = out->scan_data-f->d;
//_os_printf("scan_data_len:%d\t%d\n",f->length,(out->scan_data - f->d));
return out->init_done;
/*out->scan_data = f->d + i + 2 + blen;
out->scan_data_len = f->length - i - 2 - blen;
out->timestamp += out->ts_incr;
if(scan_DRI(out))
return 0;
else
return out->init_done;*/
}
}
_os_printf( "Found no scan data!\n" );
uint32_t xi=0;
for(xi=0;xi<0x290;xi++)
{
_os_printf(" %02x",f->d[xi]);
}
_os_printf(" \n");
out->scan_data_len = 0;
return 0;
}
static int jpeg_get_sdp( char *dest, int len, int payload, int port, void *d )
{
return snprintf( dest, len, "m=video %d RTP/AVP 26\r\n", port );
}
static int jpeg_get_payload( int payload, void *d )
{
return 26;
}
static int cal_data_len(struct rtp_jpeg *out, int *dri_index, int *res_len, int max_size)
{
/* not by jorrny
* At the beginning, we try to send the packet aligned to dri.
* But we found it inefficient when the dri length is almost a half of the max_size
* So we decide to send the packet with the max_size always to improve efficiency.
* In the same way, we try to send the packet within max_size in order to prevent fragment in ip layer.
*/
int len = 0;
do
{
if(*res_len) {
len = *res_len;
} else {
len += out->dri_len[*dri_index];
}
*res_len = 0;
if(len > max_size) {
*res_len = len - max_size;
len = max_size;
break;
} else if (len == max_size) {
(*dri_index)++;
break;
}
if(++(*dri_index) > out->dri_num)
break;
} while(1);
return len;
}
//版本已经移除
static int jpeg_send( struct rtp_endpoint *ep, void *d )
{
return 0;
}
static void jpeg_send_frame_to_endpoint( struct rtp_endpoint *ep, struct rtp_jpeg *out, struct framebuff *fb )
{
uint8_t *jpeg_buf_addr = (uint8_t *)fb->data;
int i = 0, plen, vcnt, hdr_len;
uint32_t node_offset = out->offset;
struct iovec v[8];
uint8_t vhdr[12], qhdr[4];
int res_len = 1, max_data_size;
uint32_t node_len = out->f->node_len;
if( !ep )
{
return;
}
if( !ep->sendEnable )
{
ep->sendEnable = 1;
return;
}
vhdr[0] = 0;
vhdr[4] = out->type;
vhdr[5] = 255;
vhdr[6] = out->width;
vhdr[7] = out->height;
v[1].iov_base = vhdr;
v[1].iov_len = ( out->type & 0x40 ) ? 12 : 8;
qhdr[0] = 0;
qhdr[1] = 0;
#ifdef USE_EXTHDR
PUT_16( qhdr + 2, 2 * 64 + out->hufflen + EXTHDR_LEN );
#else
PUT_16( qhdr + 2, 2 * 64 );
#endif
v[2].iov_base = qhdr;
v[2].iov_len = 4;
v[3].iov_base = jpeg_buf_addr + out->quant[out->luma_table];
v[3].iov_len = 64;
v[4].iov_base = jpeg_buf_addr + out->quant[out->chroma_table];
v[4].iov_len = 64;
hdr_len = 132 + v[1].iov_len;
#ifdef USE_EXTHDR
vcnt = 7;
v[5].iov_base = out->exthdr;
v[5].iov_len = EXTHDR_LEN;
/* The DHT block stays inside the current JPEG frame, so it can be sent directly. */
v[6].iov_base = jpeg_buf_addr + out->huffoff;
v[6].iov_len = out->hufflen;
hdr_len += v[5].iov_len + v[6].iov_len;
#else
vcnt = 5;
#endif
while( i < out->scan_data_len )
{
if( node_offset >= node_len )
{
node_offset = 0;
}
max_data_size = rtp_get_payload_size_limit( ep, RTP_HEADER_SIZE + hdr_len );
if( max_data_size <= 0 )
{
ep->sendEnable = 0;
break;
}
if( out->type & 0x40 )
{
if( ( out->scan_data_len - i ) > max_data_size )
{
plen = max_data_size;
}
else
{
plen = out->scan_data_len - i;
}
if( res_len )
{
vhdr[8] = out->exthdr[EXTHDROFF_DRI];
vhdr[9] = out->exthdr[EXTHDROFF_DRI + 1];
}
else
{
PUT_16( vhdr + 8, 0x28 );
}
PUT_16( vhdr + 10, 0xffff );
}
else
{
plen = out->scan_data_len - i;
if( plen > max_data_size )
{
plen = max_data_size;
}
}
vhdr[1] = i >> 16;
vhdr[2] = ( i >> 8 ) & 0xff;
vhdr[3] = i & 0xff;
v[vcnt].iov_base = jpeg_buf_addr + node_offset;
if( node_offset + plen >= node_len )
{
plen = node_len - node_offset;
}
else
{
uint32_t align_32 = ( node_offset + plen ) & ( ~0x1F );
plen = align_32 - node_offset;
}
if( i + plen >= out->scan_data_len ) plen = out->scan_data_len - i;
node_offset += plen;
v[vcnt].iov_len = plen;
if( rtp_sendmsg( ep, v, vcnt + 1, out->timestamp, plen + i == out->scan_data_len, 30 ) < 0 )
{
ep->sendEnable = 0;
break;
}
vcnt = 2;
hdr_len = v[1].iov_len;
i += plen;
}
ep->sendEnable = 1;
}
static int jpeg_send_more( rtp_loop_search_ep search,void *ls,void *track, void *d )
{
struct rtp_jpeg *out = (struct rtp_jpeg *)d;
struct framebuff *fb = (struct framebuff *)out->f->get_f;
struct rtp_endpoint *ep;
void *head;
if( !fb )
{
return 0;
}
out->scan_data_len = out->f->length - out->offset;
head = ls;
while( head )
{
head = search( head, track, (void **)&ep );
if( ep )
{
jpeg_send_frame_to_endpoint( ep, out, fb );
}
}
return 0;
}
struct rtp_media *new_rtp_media_jpeg_stream( struct stream *stream )
{
struct rtp_jpeg *out;
int fincr, fbase;
struct rtp_media *m;
stream->get_framerate( stream, &fincr, &fbase );
out = (struct rtp_jpeg *)malloc( sizeof( struct rtp_jpeg ) );
out->init_done = 0;
out->timestamp = 0;
out->scan_data = NULL;
out->scan_data_len = 0;
out->ts_incr = 90000 * fincr / fbase;
m = new_rtp_rtcp_media( jpeg_get_sdp, jpeg_get_payload, jpeg_process_frame, jpeg_send, new_rtcp_send, out );
if(m)
{
m->type = 0;
m->send_more = jpeg_send_more;
m->per_ms_incr = (25 * out->ts_incr)/1000;
}
return m;
}

620
sdk/app/spook/rtp.c Normal file
View File

@@ -0,0 +1,620 @@
/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include "lwip\sockets.h"
#include "lwip\netif.h"
#include "lwip\dns.h"
//#include "lwip\fcntl.h"
#include "lwip\api.h"
#include "lwip\tcp.h"
#include <event.h>
#include <log.h>
#include <frame.h>
#include <rtp.h>
#include "spook_config.h"
//#include <linux/linux_mutex.h>
#include "lwip/api.h"
#include <csi_kernel.h>
#include "rtp_media.h"
#include "lib/net/eloop/eloop.h"
int rtcp_send( struct rtp_endpoint *ep, uint8_t *pbuf,uint16 len);
static int rtp_port_start = 50000, rtp_port_end = 60000;
k_task_handle_t spook_rtcp_handle = NULL;
/*************rtp command to APP***********/
struct rtp_endpoint *new_rtp_endpoint( int payload )
{
struct rtp_endpoint *ep;
if( ! ( ep = (struct rtp_endpoint *)
malloc( sizeof( struct rtp_endpoint ) ) ) )
return NULL;
ep->payload = payload;
ep->max_data_size = MAX_DATA_PACKET_SIZE; /* default maximum */
ep->ssrc = 0;
random_bytes( (unsigned char *)&ep->ssrc, 4 );
ep->start_timestamp = 0;
random_bytes( (unsigned char *)&ep->start_timestamp, 4 );
ep->start_timestamp &= 0xFFFF;
ep->last_timestamp = ep->start_timestamp;
ep->seqnum = 0;
random_bytes( (unsigned char *)&ep->seqnum, 2 );
ep->packet_count = 0;
ep->octet_count = 0;
gettimeofday( &ep->last_rtcp_recv, NULL );
ep->trans_type = 0;
ep->rtcp_send_timestamp = os_jiffies();
ep->sendEnable = 1;
return ep;
}
void close_rtp_socket( void *ei, void *d )
{
struct event* e = (struct event*)ei;
int fd = (int)d;
close( fd);
_os_printf("%s fd:%d\n",__FUNCTION__,fd);
e->flags |= EVENT_F_REMOVE;
}
//socket的关闭会通过eloop内部去关闭,这样就不存在有异步操作的问题了(移除对应事件和关闭socket)
void del_rtp_endpoint( struct rtp_endpoint *ep )
{
switch( ep->trans_type )
{
case RTP_TRANS_UDP:
eloop_remove_event( ep->trans.udp.rtp_event );
//创建socket关闭的事件
eloop_add_alarm(os_jiffies(),EVENT_F_ENABLED,close_rtp_socket,(void*)ep->trans.udp.rtp_fd);
eloop_remove_event( ep->trans.udp.rtcp_event );
eloop_add_alarm(os_jiffies(),EVENT_F_ENABLED,close_rtp_socket,(void*)ep->trans.udp.rtcp_fd);
break;
case RTP_TRANS_INTER:
interleave_disconnect( ep->trans.inter.conn,
ep->trans.inter.rtp_chan );
interleave_disconnect( ep->trans.inter.conn,
ep->trans.inter.rtcp_chan );
break;
}
free( ep );
}
static void udp_rtp_read( void *ei, void *d )
{
struct rtp_endpoint *ep = (struct rtp_endpoint *)d;
unsigned char buf[1024];
int ret;
ret = read( ep->trans.udp.rtp_fd, buf, sizeof( buf ) );
if( ret > 0 )
{
/* some SIP phones don't send RTCP */
gettimeofday( &ep->last_rtcp_recv, NULL );
return;
} else if( ret < 0 )
spook_log( SL_VERBOSE, "error on UDP RTP socket: %s",
strerror( get_errno() ) );
else spook_log( SL_VERBOSE, "UDP RTP socket closed" );
_os_printf("%s:%d\n",__FUNCTION__,__LINE__);
ep->session->select_close(ep->session, ep);
}
static void udp_rtcp_read( void *ei, void *d )
{
#if JPG_EN
static uint8_t rtcp_speed_count = 0x80;
#endif
struct rtp_endpoint *ep = (struct rtp_endpoint *)d;
unsigned char buf[1024];
int ret;
ret = read( ep->trans.udp.rtcp_fd, buf, sizeof( buf ) );
if( ret > 0 )
{
#if JPG_EN
//Wifi_data_receive(buf,ret);
//_os_printf("(%d)rtcp get:%d ===== %x%x\r\n",os_jiffies(),buf[12],buf[0],buf[1]);
if((buf[0] == 0x81)&&(buf[1] == 0xc9)){
if(buf[12] != 0){
rtcp_speed_count++;
if(rtcp_speed_count >= 0x83){
rtcp_speed_count = 0x82;
}
}
if(buf[12] == 0){
rtcp_speed_count--;
if(rtcp_speed_count <= 0x7d){
rtcp_speed_count = 0x7e;
}
}
}
#endif
gettimeofday( &ep->last_rtcp_recv, NULL );
return;
} else if( ret < 0 )
spook_log( SL_VERBOSE, "error on UDP RTCP socket: %s",
strerror( get_errno() ) );
else spook_log( SL_VERBOSE, "UDP RTCP socket closed" );
_os_printf("%s:%d\n",__FUNCTION__,__LINE__);
ep->session->select_close(ep->session, ep);
}
void interleave_recv_rtcp( struct rtp_endpoint *ep, unsigned char *d, int len )
{
spook_log( SL_DEBUG, "received RTCP packet from client INTERLEAVE" );
gettimeofday( &ep->last_rtcp_recv, NULL );
}
int g_timeout = 0;
#define RECORDER_RTCP_NTP 0 // 使用录风者时可以开启,降低延时
int new_rtcp_send( struct rtp_endpoint *ep, void *d )/*RFC3550*/
{
// struct rtp_media *rtp = (struct rtp_media*)d;
if(ep->trans_type == RTP_TRANS_UDP)
{
int res;
unsigned char buf[64];
unsigned int ntp_sec, ntp_usec;
unsigned int rtp_timestamp;
uint16 len_send;
uint16 len = 6; //字符串长度,"taixin"
if(ep == NULL || ep->session == NULL){
_os_printf("send rtcp no session!!\n");
return -1;
}
if(os_jiffies()-ep->rtcp_send_timestamp < 5000)
{
return -1;
}
os_printf("%s:%d\n",__FUNCTION__,__LINE__);
ep->rtcp_send_timestamp = os_jiffies();
rtp_timestamp = ep->last_timestamp;
#if RECORDER_RTCP_NTP
ntp_sec = 0;
ntp_usec = 0;
#else
struct timeval now;
gettimeofday( &now, NULL );
ntp_sec = now.tv_sec + 0x83AA7E80;
ntp_usec = (double)( (double)now.tv_usec * (double)0x4000000 ) / 15625.0;
#endif
buf[0] = 2 << 6; // version
buf[1] = 200; // packet type is Sender Report
PUT_16( buf + 2, 6 ); // length in words minus one
PUT_32( buf + 4, ep->ssrc );
PUT_32( buf + 8, ntp_sec );
PUT_32( buf + 12, ntp_usec );
PUT_32( buf + 16, rtp_timestamp);//ep->rtcp_send_timestamp*per_ms_incr+ep->start_timestamp );
PUT_32( buf + 20, ep->packet_count );
PUT_32( buf + 24, ep->octet_count );
buf[28] = ( 2 << 6 ) | 1; // version; source count = 1
buf[29] = 202; // packet type is Source Description SDES
PUT_16( buf + 30, (4+4+2+len)/4-1 ); // length in words minus one sr = 5word 5-1 = 4 !!!!!!!
PUT_32( buf + 32, ep->ssrc );
buf[36] = 0x01; // field type is CNAME 36/4=9 52/4 = 13
buf[37] = len; // text length
memcpy( buf + 38, "taixin", len );
len_send = (32+4+2+len);
res = send( ep->trans.udp.rtcp_fd, buf, len_send, 0 );
}
return -1;
}
int connect_udp_endpoint( struct rtp_endpoint *ep,
struct in_addr dest_ip, int dest_port, int *our_port )
{
struct sockaddr_in rtpaddr, rtcpaddr;
int port, success = 0, max_tries, rtpfd = -1, rtcpfd = -1;
unsigned int i;
rtpaddr.sin_family = rtcpaddr.sin_family = AF_INET;
rtpaddr.sin_addr.s_addr = rtcpaddr.sin_addr.s_addr = 0;
port = rtp_port_start + rand() % ( rtp_port_end - rtp_port_start );
if( port & 0x1 ) ++port;
max_tries = ( rtp_port_end - rtp_port_start + 1 ) / 2;
for( i = 0; i < max_tries; ++i )
{
if( port + 1 > rtp_port_end ) port = rtp_port_start;
rtpaddr.sin_port = htons( port );
rtcpaddr.sin_port = htons( port + 1 );
if( rtpfd < 0 &&
( rtpfd = socket( PF_INET, SOCK_DGRAM, 0 ) ) < 0 )
{
spook_log( SL_WARN, "unable to create UDP RTP socket: %s",
strerror( get_errno() ) );
return -1;
}
if( rtcpfd < 0 &&
( rtcpfd = socket( PF_INET, SOCK_DGRAM, 0 ) ) < 0 )
{
spook_log( SL_WARN, "unable to create UDP RTCP socket: %s",
strerror( get_errno() ) );
close( rtpfd );
return -1;
}
if( bind( rtpfd, (struct sockaddr *)&rtpaddr,
sizeof( rtpaddr ) ) < 0 )
{
if( get_errno() == EADDRINUSE )
{
port += 2;
continue;
}
spook_log( SL_WARN, "strange error when binding RTP socket: %s",
strerror( get_errno() ) );
close( rtpfd );
close( rtcpfd );
return -1;
}
if( bind( rtcpfd, (struct sockaddr *)&rtcpaddr,
sizeof( rtcpaddr ) ) < 0 )
{
if( get_errno() == EADDRINUSE )
{
close( rtpfd );
rtpfd = -1;
port += 2;
continue;
}
spook_log( SL_WARN, "strange error when binding RTCP socket: %s",
strerror( get_errno() ) );
close( rtpfd );
close( rtcpfd );
return -1;
}
success = 1;
break;
}
if( ! success )
{
spook_log( SL_WARN, "ran out of UDP RTP ports!" );
return -1;
}
rtpaddr.sin_family = rtcpaddr.sin_family = AF_INET;
rtpaddr.sin_addr = rtcpaddr.sin_addr = dest_ip;
rtpaddr.sin_port = htons( dest_port );
rtcpaddr.sin_port = htons( dest_port + 1 );
if( connect( rtpfd, (struct sockaddr *)&rtpaddr,
sizeof( rtpaddr ) ) < 0 )
{
spook_log( SL_WARN, "strange error when connecting RTP socket: %s",
strerror( get_errno() ) );
close( rtpfd );
close( rtcpfd );
return -1;
}
if( connect( rtcpfd, (struct sockaddr *)&rtcpaddr,
sizeof( rtcpaddr ) ) < 0 )
{
spook_log( SL_WARN, "strange error when connecting RTCP socket: %s",
strerror( get_errno() ) );
close( rtpfd );
close( rtcpfd );
return -1;
}
i = sizeof( rtpaddr );
if( getsockname( rtpfd, (struct sockaddr *)&rtpaddr, &i ) < 0 )
{
spook_log( SL_WARN, "strange error from getsockname: %s",
strerror( get_errno() ) );
close( rtpfd );
close( rtcpfd );
return -1;
}
// int tos = 0xe0;
// setsockopt(rtpfd, IPPROTO_IP, IP_TOS, (void *)&tos , sizeof(tos));
// int tos = 0xb8;
// setsockopt(rtpfd, IPPROTO_IP, IP_TOS, (void *)&tos , sizeof(tos));
ep->max_data_size = MAX_DATA_PACKET_SIZE; /* good guess for preventing fragmentation */
ep->trans_type = RTP_TRANS_UDP;
sprintf( ep->trans.udp.sdp_addr, "IP4 %s",
inet_ntoa( rtpaddr.sin_addr ) );
ep->trans.udp.sdp_port = ntohs( rtpaddr.sin_port );
ep->trans.udp.rtp_fd = rtpfd;
ep->trans.udp.rtcp_fd = rtcpfd;
ep->trans.udp.rtp_event = eloop_add_fd( rtpfd, EVENT_READ, EVENT_F_ENABLED, udp_rtp_read, ep );
ep->trans.udp.rtcp_event = eloop_add_fd( rtcpfd, EVENT_READ, EVENT_F_ENABLED, udp_rtcp_read, ep );
spook_log( SL_DEBUG, "connect_udp_endpoint add_fd_event udp_rtp_read udp_rtcp_read");
*our_port = port;
return 0;
}
void connect_interleaved_endpoint( struct rtp_endpoint *ep,
struct conn *conn, int rtp_chan, int rtcp_chan )
{
ep->trans_type = RTP_TRANS_INTER;
ep->trans.inter.conn = conn;
ep->trans.inter.rtp_chan = rtp_chan;
ep->trans.inter.rtcp_chan = rtcp_chan;
ep->trans.inter.running = 1;
}
int rtp_get_packet_size_limit( const struct rtp_endpoint *ep )
{
if( ep && ep->trans_type == RTP_TRANS_INTER )
{
return RTP_TCP_MAX_PACKET_SIZE;
}
if( ep && ep->max_data_size > 0 )
{
return ep->max_data_size;
}
return MAX_DATA_PACKET_SIZE;
}
int rtp_get_payload_size_limit( const struct rtp_endpoint *ep, int packet_overhead )
{
int packet_limit = rtp_get_packet_size_limit( ep );
if( packet_overhead < 0 )
{
return 0;
}
if( packet_limit <= packet_overhead )
{
return 0;
}
return packet_limit - packet_overhead;
}
static void rtp_build_header( struct rtp_endpoint *ep, uint32_t timestamp, uint8_t marker, uint8_t *rtphdr )
{
ep->last_timestamp = ( ep->start_timestamp + timestamp ) & 0xFFFFFFFF;
rtphdr[0] = 2 << 6;
rtphdr[1] = ep->payload;
if( marker )
{
rtphdr[1] |= 0x80;
}
PUT_16( rtphdr + 2, ep->seqnum );
PUT_32( rtphdr + 4, ep->last_timestamp );
PUT_32( rtphdr + 8, ep->ssrc );
}
static uint32_t rtp_get_payload_len( struct iovec *v, int count )
{
uint32_t payload_len = 0;
for( int i = 1; i < count; ++i )
{
payload_len += v[i].iov_len;
}
return payload_len;
}
static void rtp_advance_iov( struct iovec **iov, int *count, int bytes )
{
while( bytes > 0 && *count > 0 )
{
if( bytes >= (int)(*iov)[0].iov_len )
{
bytes -= (*iov)[0].iov_len;
++(*iov);
--(*count);
}
else
{
(*iov)[0].iov_base = (unsigned char *)(*iov)[0].iov_base + bytes;
(*iov)[0].iov_len -= bytes;
bytes = 0;
}
}
}
static int rtp_send_udp( int fd, struct iovec *iov, int count, int retries )
{
struct msghdr mh;
int retry_count = 0;
int total_len = 0;
int ret;
for( int i = 0; i < count; ++i )
{
total_len += iov[i].iov_len;
}
while( retry_count <= retries )
{
memset( &mh, 0, sizeof( mh ) );
mh.msg_iov = iov;
mh.msg_iovlen = count;
ret = sendmsg( fd, &mh, MSG_DONTWAIT );
if( ret == total_len )
{
return 0;
}
if( get_errno() == ENOMEM )
{
return -1;
}
if( ret >= 0 || get_errno() != EAGAIN )
{
_os_printf( "%s %d, err: %d\n", __FUNCTION__, __LINE__, get_errno() );
return -1;
}
++retry_count;
os_sleep_ms( 2 );
}
_os_printf( "%s %d, err: %d\n", __FUNCTION__, __LINE__, get_errno() );
return -1;
}
static int rtp_send_tcp( struct rtp_endpoint *ep, struct iovec *v, int count)
{
struct conn *conn = ep->trans.inter.conn;
struct iovec local_iov[17];
struct iovec *send_iov = local_iov;
uint8_t interleave_hdr[4];
struct msghdr mh;
int payload_len = 0;
int send_count;
uint32_t start_time = os_jiffies();
int ret;
if( !conn || conn->fd <= 0 || !conn->running )
{
return -1;
}
if( count + 1 > (int)( sizeof( local_iov ) / sizeof( local_iov[0] ) ) )
{
_os_printf( "too many interleaved iov entries: %d", count + 1 );
return -1;
}
for( int i = 0; i < count; ++i ) payload_len += v[i].iov_len;
if( payload_len > RTP_TCP_MAX_PACKET_SIZE )
{
_os_printf( "interleaved RTP packet too large: %d", payload_len );
return -1;
}
interleave_hdr[0] = '$';
interleave_hdr[1] = ep->trans.inter.rtp_chan;
PUT_16( interleave_hdr + 2, payload_len );
local_iov[0].iov_base = interleave_hdr;
local_iov[0].iov_len = sizeof( interleave_hdr );
memcpy( &local_iov[1], v, sizeof( v[0] ) * count );
send_count = count + 1;
os_event_wait( &conn->evt, RTSP_TCP_WRITE_MUTEX, NULL, OS_EVENT_WMODE_AND | OS_EVENT_WMODE_CLEAR, -1 );
while( send_count > 0 )
{
memset( &mh, 0, sizeof( mh ) );
mh.msg_iov = send_iov;
mh.msg_iovlen = send_count;
os_event_wait( &conn->evt, RTSP_TCP_READ_MUTEX, NULL, OS_EVENT_WMODE_AND | OS_EVENT_WMODE_CLEAR, -1 );
ret = sendmsg( conn->fd, &mh, MSG_DONTWAIT );
os_event_set( &conn->evt, RTSP_TCP_READ_MUTEX, NULL );
if( ret > 0 )
{
rtp_advance_iov( &send_iov, &send_count, ret );
continue;
}
if( ret == 0 || get_errno() != EAGAIN )
{
ret = -1;
break;
}
if( os_jiffies() - start_time >= 4000 )
{
ret = -1;
break;
}
os_sleep_ms( 1 );
}
os_event_set( &conn->evt, RTSP_TCP_WRITE_MUTEX, NULL );
if( send_count <= 0 )
{
return 0;
}
if( ret < 0 )
{
ep->sendEnable = 0;
if( ep->session && ep->session->closed )
{
ep->session->closed( ep->session, ep );
}
_os_printf( "%s %d, err: %d\n", __FUNCTION__, __LINE__, get_errno() );
}
return ret;
}
int rtp_sendmsg( struct rtp_endpoint *ep, struct iovec *v, int count, uint32_t timestamp, uint8_t marker, int retries )
{
uint8_t rtphdr[12];
uint32_t payload_len;
int ret = -1;
if( !ep || !v || count <= 0 )
{
_os_printf("%s %d\n", __FUNCTION__, __LINE__);
return -1;
}
if( !ep->sendEnable )
{
return -1;
}
rtp_build_header( ep, timestamp, marker, rtphdr );
v[0].iov_base = rtphdr;
v[0].iov_len = sizeof( rtphdr );
payload_len = rtp_get_payload_len( v, count );
switch( ep->trans_type )
{
case RTP_TRANS_UDP:
ret = rtp_send_udp( ep->trans.udp.rtp_fd, v, count, retries > 0 ? retries : 10 );
if( ret < 0 )
{
ep->sendEnable = 0;
}
break;
case RTP_TRANS_INTER:
ret = rtp_send_tcp( ep, v, count );
break;
default:
ret = -1;
break;
}
if( ret < 0 )
{
return -1;
}
ep->octet_count += payload_len;
++ep->packet_count;
ep->seqnum = ( ep->seqnum + 1 ) & 0xFFFF;
return 0;
}

206
sdk/app/spook/rtp.h Normal file
View File

@@ -0,0 +1,206 @@
#ifndef __RTP_H
#define __RTP_H
/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* These should probably be an enum */
#define RTP_TRANS_UDP 1
#define RTP_TRANS_INTER 2
#define MAX_INTERLEAVE_CHANNELS 8
#define RTP_HEADER_SIZE 12
#define RTP_TCP_MAX_PACKET_SIZE (16*1024)
struct rtp_endpoint;
struct conn;
struct session;
struct rtp_endpoint {
struct session *session;
int payload;
int max_data_size;
unsigned int ssrc;
unsigned int start_timestamp;
unsigned int last_timestamp;
unsigned int rtcp_send_timestamp;
int seqnum;
int packet_count;
int octet_count;
struct event *rtcp_send_event;
struct timeval last_rtcp_recv;
int trans_type;
int sendEnable;
union {
struct {
char sdp_addr[48];
int sdp_port;
int rtp_fd;
struct event *rtp_event;
int rtcp_fd;
struct event *rtcp_event;
} udp;
struct {
struct conn *conn;
int rtp_chan;
int rtcp_chan;
int running;
} inter;
} trans;
};
typedef int (*get_sdp_func)( struct session *s, char *dest, int *len,
char *path );
typedef int (*setup_func)( struct session *s, int track );
typedef void (*play_func)( struct session *s, double *start );
typedef void (*pause_func)( struct session *s );
typedef void (*teardown_func)( struct session *s, struct rtp_endpoint *ep );
typedef void (*session_close_func)( struct session *sess );
typedef void (*close_func)( struct session *s, struct rtp_endpoint *ep );
typedef void (*select_func)( struct session *s, struct rtp_endpoint *ep );
#define MAX_TRACKS 4
struct session {
struct session *next;
struct session *prev;
get_sdp_func get_sdp;
setup_func setup;
play_func play;
pause_func pause;
close_func closed;
teardown_func teardown;
select_func select_close;
void *private;
session_close_func control_close;
void *control_private;
struct timeval open_time;
char addr[64];
struct rtp_endpoint *ep[MAX_TRACKS];
struct conn *conn; /* add by jornny */
int connect_type;
};
struct loc_node {
struct loc_node *next;
struct loc_node *prev;
char path[16];
};
typedef struct session *(*open_func)( char *path, void *d );
struct req {
struct conn *conn;
struct pmsg *req;
struct pmsg *resp;
};
struct jpeg_fifo
{
unsigned char *buf;
int len;
unsigned char *scan_data;
int scan_data_len;
unsigned short int dri_len[100];
int dri_num;
unsigned int items;
//struct list_head list;
//boolean *pIsUsing;
};
#define CONN_PROTO_START 0
#define CONN_PROTO_RTSP 1
#define CONN_PROTO_HTTP 2
#define CONN_PROTO_SIP 3
#define CONN_PROTO_APPO 4
#include "osal/event.h"
enum
{
RTSP_TCP_SEND_FINISH = BIT(0), // done的时候报错
RTSP_TCP_READ_MUTEX = BIT(1),
RTSP_TCP_WRITE_MUTEX = BIT(2),
};
struct conn {
struct conn *next;
struct conn *prev;
int fd;
int running;
uint8_t *sendbuf;
int send_buf_len;
struct os_event evt;
struct sockaddr_in client_addr;
struct event *read_event;
struct event *write_event;
int proto;
unsigned char req_buf[512];
int req_len;
struct req *req_list;
unsigned char send_buf[512];
int send_buf_r;
int send_buf_w;
int drop_after;
void *proto_state;
/* add by jornny*/
struct session *sess;
/* Client Hardware Addr of this Conn*/
//unsigned char chaddr[6];
};
/* There's probably a better place to put these... */
#define PUT_16(p,v) ((p)[0]=((v)>>8)&0xff,(p)[1]=(v)&0xff)
#define PUT_32(p,v) ((p)[0]=((v)>>24)&0xff,(p)[1]=((v)>>16)&0xff,(p)[2]=((v)>>8)&0xff,(p)[3]=(v)&0xff)
#define GET_16(p) (((p)[0]<<8)|(p)[1])
#define GET_32(p) (((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|(p)[3])
void random_bytes( unsigned char *dest, int len );
void random_id( unsigned char *dest, int len );
struct rtp_endpoint *new_rtp_endpoint( int payload );
int connect_udp_endpoint( struct rtp_endpoint *ep,
struct in_addr dest_ip, int dest_port, int *our_port );
int avail_send_buf( struct conn *c );
int send_data( struct conn *c, unsigned char *d, int len );
int tcp_send_pmsg( struct conn *c, struct pmsg *msg, int len );
void connect_interleaved_endpoint( struct rtp_endpoint *ep,
struct conn *conn, int rtp_chan, int rtcp_chan );
void rtsp_conn_disconnect( struct conn *c );
void http_conn_disconnect( struct conn *c );
void interleave_disconnect( struct conn *c, int chan );
int interleave_send( struct conn *conn, int chan, struct iovec *v, int count );
int interleave_recv( struct conn *c, int chan, unsigned char *d, int len );
void interleave_recv_rtcp( struct rtp_endpoint *ep, unsigned char *d, int len );
void del_rtp_endpoint( struct rtp_endpoint *ep );
int rtp_get_packet_size_limit( const struct rtp_endpoint *ep );
int rtp_get_payload_size_limit( const struct rtp_endpoint *ep, int packet_overhead );
int rtp_sendmsg( struct rtp_endpoint *ep, struct iovec *v, int count,
unsigned int timestamp, uint8_t marker, int retries );
void new_rtsp_location( const char *path, char *realm, char *username, char *password,
open_func open, void *private );
struct session *new_session(void);
void del_session( struct session *sess );
int print_session_list( char *s, int maxlen );
int http_handle_msg( struct req *req );
int rtsp_handle_msg( struct req *req );
void send_rtcp(uint8_t *data);
int new_rtcp_send( struct rtp_endpoint *ep, void *d );
#endif

54
sdk/app/spook/rtp_media.h Normal file
View File

@@ -0,0 +1,54 @@
#ifndef __RTP_MEDIA_H
#define __RTP_MEDIA_H
#include "frame.h"
#include "stream.h"
/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
typedef int (*rtp_media_get_sdp_func)( char *dest, int len, int payload,
int port, void *d );
typedef int (*rtp_media_get_payload_func)( int payload, void *d );
typedef int (*rtp_media_frame_func)( struct frame *f, void *d );
typedef int (*rtp_media_send_func)( struct rtp_endpoint *ep, void *d );
typedef void* (*rtp_loop_search_ep)( void *head,void *track,void **ep );
typedef int (*rtp_media_send_more_func)( rtp_loop_search_ep search,void *ls, void *track, void *d); //track是live那边的结构体
struct rtp_media {
rtp_media_get_sdp_func get_sdp;
rtp_media_get_payload_func get_payload;
rtp_media_frame_func frame;
rtp_media_send_func send;
rtp_media_send_more_func send_more;
rtp_media_send_func rtcp_send;
void *private;
int per_ms_incr;
uint32_t sample_rate;
uint8_t type;
};
struct rtp_media *new_rtp_media( rtp_media_get_sdp_func get_sdp,
rtp_media_get_payload_func get_payload, rtp_media_frame_func frame,
rtp_media_send_func send, void *private );
struct rtp_media *new_rtp_media_jpeg_stream( struct stream *stream );
struct rtp_media *new_rtp_media_h264_stream( struct stream *stream );
#endif

694
sdk/app/spook/rtsp.c Normal file
View File

@@ -0,0 +1,694 @@
/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include "lwip\sockets.h"
#include "lwip\netif.h"
#include "lwip\dns.h"
#include "lwip\api.h"
#include "lwip\tcp.h"
#include <event.h>
#include <log.h>
#include <frame.h>
#include <stream.h>
#include <pmsg.h>
#include <rtp.h>
//#include "common.h"
#include "osal/string.h"
void write_access_log( char *path, struct sockaddr *addr, int code, char *req,
int length, char *referer, char *user_agent );
struct rtsp_session {
struct rtsp_session *next;
struct rtsp_session *prev;
char id[32];
struct session *sess;
};
struct rtsp_location {
struct loc_node node;
char realm[128];
char username[128];
char password[128];
open_func open;
void *private;
};
struct rtsp_conn {
struct {
struct rtp_endpoint *ep;
int rtcp;
} ichan[MAX_INTERLEAVE_CHANNELS];
};
static struct rtsp_location *rtsp_loc_list = NULL;
static struct rtsp_session *sess_list = NULL;
static char *get_local_path( char *path )
{
char *c;
static char *root = "/";
if( os_strncasecmp( path, "rtsp://", 7 ) ) return NULL;
for( c = path + 7; *c != '/'; ++c ) if( *c == 0 ) return root;
return c;
}
static struct loc_node *node_find_location( struct loc_node *list,
char *path, int len )
{
struct loc_node *loc;
for( loc = list; loc; loc = loc->next )
{
//_os_printf("%s path:%s\tloc:%s\tlen:%d\tres:%d\t%X\t%d\n",__FUNCTION__,path,loc->path,len,loc->path[len],'/',strncmp( path, loc->path, strlen( loc->path ) ));
//if( (! strncmp( path, loc->path, strlen( loc->path ) )) && ( loc->path[len] == '/' || loc->path[len] == 0 ) )
if( ! strncmp( path, loc->path, strlen( loc->path ) ))
{
return loc;
}
}
return NULL;
}
static struct rtsp_location *find_rtsp_location( char *uri, char *base, int *track )
{
char *path, *c, *end;
int len;
if( ! ( path = get_local_path( uri ) ) ) return NULL;
len = strlen( path );
if( track )
{
*track = -1;
if( ( c = strrchr( path, '/' ) ) &&
! strncmp( c, "/track", 6 ) )
{
*track = strtol( c + 6, &end, 10 );
if( ! *end ) len -= strlen( c );
}
}
if( len > 1 && path[len - 1] == '/' ) --len;
if( base )
{
strncpy( base, path, len );
base[len] = 0;
}
return (struct rtsp_location *)node_find_location(
(struct loc_node *)rtsp_loc_list, path, len );
}
static void init_location( struct loc_node *node, const char *path,
struct loc_node **list )
{
node->next = *list;
node->prev = NULL;
if( node->next ) node->next->prev = node;
*list = node;
strcpy( node->path, path );
}
void new_rtsp_location( const char *path, char *realm, char *username, char *password,
open_func open, void *private )
{
struct rtsp_location *loc;
loc = (struct rtsp_location *)malloc( sizeof( struct rtsp_location ) );
init_location( (struct loc_node *)loc, path,
(struct loc_node **)&rtsp_loc_list );
if( realm ) strcpy( loc->realm, realm );
else loc->realm[0] = 0;
if( username ) strcpy( loc->username, username );
else loc->username[0] = 0;
if( password ) strcpy( loc->password, password );
else loc->password[0] = 0;
loc->open = open;
loc->private = private;
}
static void rtsp_session_close( struct session *sess )
{
struct rtsp_session *rs = (struct rtsp_session *)sess->control_private;
spook_log( SL_DEBUG, "freeing session %s", rs->id );
if( rs->next ) rs->next->prev = rs->prev;
if( rs->prev ) rs->prev->next = rs->next;
else sess_list = rs->next;
free( rs );
}
static struct rtsp_session *new_rtsp_session( struct session *sess )
{
struct rtsp_session *rs;
rs = (struct rtsp_session *)malloc( sizeof( struct rtsp_session ) );
rs->next = sess_list;
rs->prev = NULL;
if( rs->next ) rs->next->prev = rs;
sess_list = rs;
random_id( (unsigned char *)rs->id, 30 );
rs->sess = sess;
sess->control_private = rs;
sess->control_close = rtsp_session_close;
return rs;
}
static struct rtsp_session *get_session( char *id )
{
struct rtsp_session *rs;
if( ! id ) return NULL;
for( rs = sess_list; rs; rs = rs->next )
if( ! strcmp( rs->id, id ) ) break;
return rs;
}
void rtsp_conn_disconnect( struct conn *c )
{
struct rtsp_conn *rc = (struct rtsp_conn *)c->proto_state;
int i;
for( i = 0; i < MAX_INTERLEAVE_CHANNELS; ++i )
if( rc->ichan[i].ep && ! rc->ichan[i].rtcp )
rc->ichan[i].ep->session->closed(
rc->ichan[i].ep->session,
rc->ichan[i].ep );
free( rc );
}
void interleave_disconnect( struct conn *c, int chan )
{
struct rtsp_conn *rc = (struct rtsp_conn *)c->proto_state;
rc->ichan[chan].ep = NULL;
}
int interleave_recv( struct conn *c, int chan, unsigned char *d, int len )
{
struct rtsp_conn *rc = (struct rtsp_conn *)c->proto_state;
if( chan >= MAX_INTERLEAVE_CHANNELS || ! rc->ichan[chan].ep ) return -1;
if( rc->ichan[chan].rtcp )
interleave_recv_rtcp( rc->ichan[chan].ep, d, len );
return 0;
}
int interleave_send( struct conn *c, int chan, struct iovec *v, int count )
{
unsigned char head[4];
int len = 0, i;
for( i = 0; i < count; ++i ) len += v[i].iov_len;
if( avail_send_buf( c ) < len + 4 ) return 1;
head[0] = '$';
head[1] = chan;
PUT_16( head + 2, len );
send_data( c, head, 4 );
for( i = 0; i < count; ++i )
send_data( c, v[i].iov_base, v[i].iov_len );
return 0;
}
static void log_request( struct req *req, int code, int length )
{
char *ref, *ua;
ref = get_header( req->req, "referer" );
ua = get_header( req->req, "user-agent" );
write_access_log( NULL, (struct sockaddr *)&req->conn->client_addr,
code, (char *)req->conn->req_buf, length,
ref ? ref : "-", ua ? ua : "-" );
}
static int rtsp_create_reply( struct req *req, int code, char *reason )
{
if( ! ( req->resp = new_pmsg( 512 ) ) ) return -1;
req->resp->type = PMSG_RESP;
req->resp->proto_id = add_pmsg_string( req->resp, "RTSP/1.0" );
req->resp->sl.stat.code = code;
req->resp->sl.stat.reason = add_pmsg_string( req->resp, reason );
copy_headers( req->resp, req->req, "CSeq" );
return 0;
}
static void rtsp_send_error( struct req *req, int code, char *reason )
{
log_request( req, code, 0 );
rtsp_create_reply( req, code, reason );
tcp_send_pmsg( req->conn, req->resp, -1 );
}
/*
static int rtsp_verify_auth( struct req *req, char *realm,
char *username, char *password )
{
int ret = check_digest_response( req->req, realm, username, password );
if( ret > 0 ) return 0;
log_request( req, 401, 0 );
rtsp_create_reply( req, 401, "Unauthorized" );
add_digest_challenge( req->resp, realm, ret == 0 ? 1 : 0 );
tcp_send_pmsg( req->conn, req->resp, -1 );
return -1;
}
*/
static int handle_OPTIONS( struct req *req )
{
rtsp_create_reply( req, 200, "OK" );
add_header( req->resp, "Public",
"DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE" );
log_request( req, 200, 0 );
tcp_send_pmsg( req->conn, req->resp, -1 );
return 0;
}
static int handle_DESCRIBE( struct req *req )
{
char sdp[512+128], path[64], hdr[128];
int sdp_len;
struct rtsp_location *loc;
struct session *sess;
spook_log( SL_DEBUG, "describing streams under '%s'", req->req->sl.req.uri );
//_os_printf("%s:%d url:%s\n",__FUNCTION__,__LINE__,req->req->sl.req.uri);
if( ! ( loc = find_rtsp_location( req->req->sl.req.uri,
path, NULL ) ) ||
! ( sess = loc->open( path, loc->private ) ) )
{
_os_printf("no found uri:%s\tloc:%X\n",req->req->sl.req.uri,(int)loc);
rtsp_send_error( req, 404, "Not Found" );
return 0;
}
/*
if( loc->realm[0] && rtsp_verify_auth( req, loc->realm,
loc->username, loc->password ) < 0 )
return 0;*/
sdp_len = sizeof( sdp ) - 2;
if( sess->get_sdp( sess, sdp, &sdp_len, path ) > 0 )
{
rtsp_create_reply( req, 200, "OK" );
sprintf( hdr, "%s/", req->req->sl.req.uri );
//add_header( req->resp, "Content-Base", hdr );
add_header( req->resp, "Content-Type", "application/sdp" );
add_header( req->resp, "Cache-Control", "no-cache" );
add_header( req->resp, "Server", "Hisilicon RTSP Streaming Media Server/1.0.0" );
log_request( req, 200, sdp_len );
if( tcp_send_pmsg( req->conn, req->resp, sdp_len ) >= 0 )
send_data( req->conn, (unsigned char *)sdp, sdp_len );
} else
{
_os_printf("sdp:%x %x\n",(int)sess->get_sdp,(int)sess->get_sdp( sess, sdp, &sdp_len, path));
rtsp_send_error( req, 404, "Not Found" );
}
sess->select_close(sess, NULL);
return 0;
}
static int rtsp_udp_setup( struct session *s, int track,
struct req *req, char *t )
{
char *p, *end, trans[128];
int cport, server_port;
if( ! ( p = strstr( t, "client_port" ) ) || *(p + 11) != '=' )
return -1;
cport = strtol( p + 12, &end, 10 );
if( end == p + 12 ) return -1;
spook_log( SL_DEBUG, "client requested UDP port %d", cport );
if( connect_udp_endpoint( s->ep[track], req->conn->client_addr.sin_addr,
cport, &server_port ) < 0 )
return -1;
spook_log( SL_VERBOSE, "our port is %d, client port is %d",
server_port, cport );
sprintf( trans, "RTP/AVP;unicast;client_port=%d-%d;server_port=%d-%d",
cport, cport + 1, server_port, server_port + 1 );
add_header( req->resp, "Transport", trans );
return 0;
}
static int rtsp_interleave_setup( struct session *s, int track,
struct req *req, char *t )
{
struct rtsp_conn *rc = (struct rtsp_conn *)req->conn->proto_state;
char *p, *end, trans[128];
int rtp_chan = -1, rtcp_chan = -1, i;
if( ( p = strstr( t, "interleaved" ) ) )
{
if( *(p + 11) != '=' ) return -1;
rtp_chan = strtol( p + 12, &end, 10 );
rtcp_chan = rtp_chan + 1; // XXX make better parser
if( end == p + 12 ) return -1;
if( rtp_chan < 0 || rtcp_chan < 0 ||
rtp_chan >= MAX_INTERLEAVE_CHANNELS ||
rtcp_chan >= MAX_INTERLEAVE_CHANNELS )
return -1;
spook_log( SL_VERBOSE, "requested interleave channels %d-%d",
rtp_chan, rtcp_chan );
if( rc && ( rc->ichan[rtp_chan].ep ||
rc->ichan[rtcp_chan].ep ) )
return -1;
} else
{
spook_log( SL_VERBOSE, "requested any interleave channel" );
if( rc )
{
for( i = 0; i < MAX_INTERLEAVE_CHANNELS; i += 2 )
if( ! rc->ichan[i].ep && ! rc->ichan[i + 1].ep )
break;
if( i >= MAX_INTERLEAVE_CHANNELS ) return -1;
rtp_chan = i;
rtcp_chan = i + 1;
} else
{
rtp_chan = 0;
rtcp_chan = 1;
}
}
if( ! rc )
{
rc = (struct rtsp_conn *)malloc( sizeof( struct rtsp_conn ) );
if( ! rc )
{
spook_log( SL_ERR,
"out of memory on malloc rtsp_conn" );
return -1;
}
for( i = 0; i < MAX_INTERLEAVE_CHANNELS; ++i )
rc->ichan[i].ep = NULL;
req->conn->proto_state = rc;
}
rc->ichan[rtp_chan].ep = s->ep[track];
rc->ichan[rtp_chan].rtcp = 0;
rc->ichan[rtcp_chan].ep = s->ep[track];
rc->ichan[rtcp_chan].rtcp = 1;
connect_interleaved_endpoint( s->ep[track], req->conn,
rtp_chan, rtcp_chan );
sprintf( trans, "RTP/AVP/TCP;unicast;interleaved=%d-%d",
rtp_chan, rtcp_chan );
add_header( req->resp, "Transport", trans );
return 0;
}
static int handle_SETUP( struct req *req )
{
char *t, *sh, path[256];
int track, ret;
struct session *s;
struct rtsp_session *rs = NULL;
struct rtsp_location *loc;
if( ! ( loc = find_rtsp_location( req->req->sl.req.uri,
path, &track ) ) ||
track < 0 || track >= MAX_TRACKS )
{
rtsp_send_error( req, 404, "Not Found" );
return 0;
}
/*
if( loc->realm[0] && rtsp_verify_auth( req, loc->realm,
loc->username, loc->password ) < 0 )
return 0;*/
if( ! ( t = get_header( req->req, "Transport" ) ) )
{
_os_printf("%s %d\r\n",__func__,__LINE__);
// XXX better error reply
rtsp_send_error( req, 461, "Unspecified Transport" );
return 0;
}
if( ! ( sh = get_header( req->req, "Session" ) ) )
{
/*callback: live_open */
if( ! ( s = loc->open( path, loc->private ) ) )
{
rtsp_send_error( req, 404, "Not Found" );
return 0;
}
sprintf( s->addr, "IP4 %s",
inet_ntoa( req->conn->client_addr.sin_addr ) );
} else if( ! ( rs = get_session( sh ) ) )
{
rtsp_send_error( req, 454, "Session Not Found" );
return 0;
} else s = rs->sess;
if( s->ep[track] )
{
_os_printf("%s %d\r\n",__func__,__LINE__);
// XXX better error reply
rtsp_send_error( req, 461, "Unsupported Transport" );
return 0;
}
/* callback: live_setup */
if( s->setup( s, track ) < 0 )
{
rtsp_send_error( req, 404, "Not Found" );
if( ! rs ) s->select_close(s, NULL);
return 0;
}
spook_log( SL_DEBUG, "setting up RTP (%s)", t );
rtsp_create_reply( req, 200, "OK" );
if( ! strncasecmp( t, "RTP/AVP/TCP", 11 ) )
{
// ret = -1;
ret = rtsp_interleave_setup( s, track, req, t );
}
else if( ( ! strncasecmp( t, "RTP/AVP", 7 ) && t[7] != '/' ) ||
! strncasecmp( t, "RTP/AVP/UDP", 11 ) )
ret = rtsp_udp_setup( s, track, req, t );
else ret = -1;
if( ret < 0 )
{
free_pmsg( req->resp );
_os_printf("%s %d\r\n",__func__,__LINE__);
rtsp_send_error( req, 461, "Unsupported Transport" );
s->select_close(s, s->ep[track]);
} else
{
if( ! rs ) rs = new_rtsp_session( s );
add_header( req->resp, "Session", rs->id );
log_request( req, 200, 0 );
tcp_send_pmsg( req->conn, req->resp, -1 );
/* add by jornny */
rs->sess->conn = req->conn;
req->conn->sess = s;
}
return 0;
}
static int handle_PLAY( struct req *req )
{
struct rtsp_session *rs;
double start;
int have_start = 0, i, p, ret;
char *range, hdr[512];
if( ! ( rs = get_session( get_header( req->req, "Session" ) ) ) )
{
rtsp_send_error( req, 454, "Session Not Found" );
return 0;
}
range = get_header( req->req, "Range" );
if( range && sscanf( range, "npt=%lf-", &start ) == 1 )
{
have_start = 1;
spook_log( SL_VERBOSE,
"starting streaming for session %s at position %.4f",
rs->id, start );
} else spook_log( SL_VERBOSE,
"starting streaming for session %s", rs->id );
/* callback:live_play( struct session *s, double *start ) */
rs->sess->play( rs->sess, have_start ? &start : NULL );
rtsp_create_reply( req, 200, "OK" );
add_header( req->resp, "Session", rs->id );
if( have_start && start >= 0 )
{
spook_log( SL_DEBUG, "backend seeked to %.4f", start );
sprintf( hdr, "npt=%.4f-", start );
add_header( req->resp, "Range", hdr );
p = 0;
for( i = 0; i < MAX_TRACKS; ++i )
{
if( ! rs->sess->ep[i] ) continue;
ret = snprintf( hdr + p, sizeof( hdr ) - p,
"url=%s/track%d;seq=%d;rtptime=%u,",
req->req->sl.req.uri, i,
rs->sess->ep[i]->seqnum,
rs->sess->ep[i]->last_timestamp );
if( ret >= sizeof( hdr ) - p )
{
p = -1;
break;
}
p += ret;
}
if( p > 0 )
{
hdr[p - 1] = 0; /* Kill last comma */
add_header( req->resp, "RTP-Info", hdr );
}
}
log_request( req, 200, 0 );
tcp_send_pmsg( req->conn, req->resp, -1 );
#ifdef FLY_CONTROL_RECEIVE
#endif
/* to test audio adc when transporting picture */
// extern void auadc_init(void);
// auadc_init();
return 0;
}
static int handle_PAUSE( struct req *req )
{
struct rtsp_session *rs;
if( ! ( rs = get_session( get_header( req->req, "Session" ) ) ) )
{
rtsp_send_error( req, 454, "Session Not Found" );
return 0;
}
if( ! rs->sess->pause )
{
rtsp_send_error( req, 501, "Not Implemented" );
return 0;
}
spook_log( SL_VERBOSE, "pausing session %s", rs->id );
rs->sess->pause( rs->sess );
rtsp_create_reply( req, 200, "OK" );
add_header( req->resp, "Session", rs->id );
log_request( req, 200, 0 );
tcp_send_pmsg( req->conn, req->resp, -1 );
return 0;
}
static int handle_TEARDOWN( struct req *req )
{
struct rtsp_location *loc;
struct rtsp_session *rs;
int track;
_os_printf("handle_teardown\r\n");
if( ! ( loc = find_rtsp_location( req->req->sl.req.uri,
NULL, &track ) ) ||
track >= MAX_TRACKS )
{
rtsp_send_error( req, 404, "Not Found" );
return 0;
}
if( ! ( rs = get_session( get_header( req->req, "Session" ) ) ) )
{
rtsp_send_error( req, 454, "Session Not Found" );
return 0;
}
spook_log( SL_VERBOSE, "tearing down %s in session %s",
req->req->sl.req.uri, rs->id );
rtsp_create_reply( req, 200, "OK" );
add_header( req->resp, "Session", rs->id );
/* This might destroy the session, so do it after creating the reply
* callback function: live_teardown */
rs->sess->closed( rs->sess, track < 0 ? NULL : rs->sess->ep[track] );
/* add by jornny */
//req->conn->sess = NULL;
log_request( req, 200, 0 );
tcp_send_pmsg( req->conn, req->resp, -1 );
return 0;
}
static int handle_unknown( struct req *req )
{
rtsp_send_error( req, 501, "Not Implemented" );
return 0;
}
uint8 spook_handle_open = 1;
int rtsp_handle_msg( struct req *req )
{
int ret;
_os_printf("===========%s=============\r\n",req->req->sl.req.method);
if(spook_handle_open == 0){
ret = handle_unknown( req );
return ret;
}
if( ! os_strcasecmp( req->req->sl.req.method, "OPTIONS" ) )
ret = handle_OPTIONS( req );
else if( ! os_strcasecmp( req->req->sl.req.method, "DESCRIBE" ) )
ret = handle_DESCRIBE( req );
else if( ! os_strcasecmp( req->req->sl.req.method, "SETUP" ) )
ret = handle_SETUP( req );
else if( ! os_strcasecmp( req->req->sl.req.method, "PLAY" ) )
ret = handle_PLAY( req );
else if( ! os_strcasecmp( req->req->sl.req.method, "PAUSE" ) )
ret = handle_PAUSE( req );
else if( ! os_strcasecmp( req->req->sl.req.method, "TEARDOWN" ) )
ret = handle_TEARDOWN( req );
else ret = handle_unknown( req );
return ret;
}

513
sdk/app/spook/rtsp_common.c Normal file
View File

@@ -0,0 +1,513 @@
#include <stdio.h>
#include "lwip\sockets.h"
#include "lwip\netif.h"
#include "lwip\dns.h"
#include "lwip\api.h"
#include "lwip\tcp.h"
#include "log.h"
#include "sys_config.h"
#include "osal/string.h"
#include "rtsp_common.h"
#include "event.h"
#ifdef send
#undef send
#endif
static int rtsp_get_sdp( struct session *s, char *dest, int *len,
char *path )
{
struct rtsp_session *ls = (struct rtsp_session *)s->private;
int i = 0, t;
char *addr = "IP4 0.0.0.0";
_os_printf("%s:%d\tpath:%s\n",__FUNCTION__,__LINE__,path);
if( s->ep[0] && s->ep[0]->trans_type == RTP_TRANS_UDP )
addr = s->ep[0]->trans.udp.sdp_addr;
i = snprintf( dest, *len,
"v=0\r\no=- 1 1 IN IP4 127.0.0.1\r\ns=Test\r\na=type:broadcast\r\nt=0 0\r\nc=IN %s\r\n", addr );
_os_printf("%s:%d\n",__FUNCTION__,__LINE__);
for( t = 0; t < MAX_TRACKS && ls->source->track[t].rtp; ++t )
{
int port;
//if( ! ls->source->track[t].ready ) return 0;
if( s->ep[t] && s->ep[t]->trans_type == RTP_TRANS_UDP )
port = s->ep[t]->trans.udp.sdp_port;
else
port = 0;
if(ls->source->track[t].rtp->type == 0)
{
i += ls->source->track[t].rtp->get_sdp( dest + i, *len - i,96 + t, port,ls->source->track[t].rtp->private );
}
else
{
i += ls->source->track[t].rtp->get_sdp( dest + i, *len - i,96 + t, port,NULL);
}
if( port == 0 ) // XXX What's a better way to do this?
i += sprintf( dest + i, "a=control:track%d\r\n", t );
}
*len = i;
return t;
}
static int rtsp_setup( struct session *s, int t )
{
struct rtsp_session *ls = (struct rtsp_session *)s->private;
int payload = 96 + t;
//判断source是否已经创建了线程,如果没有创建线程,则在这里创建线程
//线程创建成功后,实际内部不会进行太多操作,主要是读取视频和音频数据
//直到play执行后,对应位被置位后,才会进行发送
//如果teardown后,如果没有ls链表,则将线程删除,释放空间
//删除线程,就要同时考虑将对应视频和音频接入的框架流disable掉,所以是不是应该有一个释放资源的回调函数呢
//所以source是不是应该有一个创建线程和释放线程的回调函数,用的是自身的句柄
//线程传入的参数可以通过source中的track查找,不用管t的值,而是看初始化的时候创建多少个track决定,配合创建线程
//线程创建
if(!ls->source->handle.hdl)
{
if(ls->source->creat)
{
ls->source->creat(ls->source,ls->path);
}
}
else
{
_os_printf("live thread already run:%X\t%X\n",(int)ls->source->handle.hdl,(int)ls->source);
}
if( ! ls->source->track[t].rtp ) return -1;
if( ls->source->track[t].rtp->get_payload )
payload = ls->source->track[t].rtp->get_payload( payload,
ls->source->track[t].rtp->private );
s->ep[t] = new_rtp_endpoint( payload );
s->ep[t]->session = s;
return 0;
}
static void rtsp_play( struct session *s, double *start )
{
struct rtsp_session *ls = (struct rtsp_session *)s->private;
int t;
if( start ) *start = -1;
ls->playing = 1;
for( t = 0; t < MAX_TRACKS && ls->source->track[t].rtp; ++t )
{
//对应位置位,然后就线程会自动发送数据
struct rtsp_track *track = &ls->source->track[t];
track->ready = 1;
//clear_init_done(track->rtp->private);
if( s->ep[t] ) set_waiting( ls->source->track[t].stream, 1 );
}
if(ls->source->play)
{
ls->source->play(ls->source);
}
}
static void track_check_running( struct rtsp_source *source, int t )
{
struct rtsp_session *ls;
for( ls = source->sess_list; ls; ls = ls->next )
if( ls->playing && ls->sess->ep[t] ) return;
set_waiting( source->track[t].stream, 0 );
}
extern void drop_conn( struct conn *c );
void rtsp_release_event(void *ei, void *d)
{
_os_printf("%s:%d\n",__FUNCTION__,__LINE__);
struct session *s = (struct session*)d;
struct rtsp_session *ls = (struct rtsp_session *)s->private;
struct conn *c = s->conn;
if(c)
{
drop_conn( c );
}
os_free( ls );
del_session( s );
}
static void rtsp_teardown( struct session *s, struct rtp_endpoint *ep )
{
_os_printf("%s:%d\n",__FUNCTION__,__LINE__);
struct rtsp_session *ls = (struct rtsp_session *)s->private;
//struct rtsp_source *source = ls->source;
int remaining = 0;
for( int i = 0; i < MAX_TRACKS && ls->source->track[i].rtp; ++i )
{
if( ! s->ep[i] ) continue;
if( ! ep || s->ep[i] == ep )
{
del_rtp_endpoint( s->ep[i] );
s->ep[i] = NULL;
track_check_running( ls->source, i );
} else ++remaining;
}
if( remaining == 0 )
{
//解锁ls链表
if( ls->next ) ls->next->prev = ls->prev;
if( ls->prev ) ls->prev->next = ls->next;
else ls->source->sess_list = ls->next;
//启动event将事件移除
//断开链表后,开启eloop的alarm事件,清除对应的资源
eloop_add_alarm(os_jiffies(),EVENT_F_ENABLED,rtsp_release_event,(void*)s);
}
}
static void rtsp_closed( struct session *s, struct rtp_endpoint *ep )
{
_os_printf("%s:%d\n",__FUNCTION__,__LINE__);
struct rtsp_session *ls = (struct rtsp_session *)s->private;
ls->closed = 1;
}
static void rtsp_select_close( struct session *s, struct rtp_endpoint *ep)
{
struct rtsp_session *ls = (struct rtsp_session *)s->private;
if(ls->source->handle.hdl)
{
_os_printf("%s: %d, set closed\r\n", __FUNCTION__, __LINE__);
s->closed(s, NULL);
}
else
{
_os_printf("%s: %d, set teardown\r\n", __FUNCTION__, __LINE__);
s->teardown(s, NULL);
}
}
struct session *rtsp_open( char *path, void *d )
{
struct rtsp_source *source = (struct rtsp_source *)d;
struct rtsp_session *ls;
ls = (struct rtsp_session *)os_malloc( sizeof( struct rtsp_session ) );
ls->next = source->sess_list;
if( ls->next ) ls->next->prev = ls;
source->sess_list = ls;
ls->prev = NULL;
ls->sess = new_session();
ls->source = source;
ls->playing = 0;
ls->sess->get_sdp = rtsp_get_sdp;
ls->sess->setup = rtsp_setup;
ls->sess->play = rtsp_play;
ls->sess->teardown = rtsp_teardown;
ls->sess->closed = rtsp_closed;
ls->sess->select_close = rtsp_select_close;
ls->sess->private = ls;
ls->closed = 0;
if(strlen(path)<sizeof(ls->path))
{
memcpy(ls->path,path,strlen(path)+1);
}
else
{
_os_printf("%s path too long:%d\n",__FUNCTION__,strlen(path));
}
return ls->sess;
}
static void *loop_search_ep(void *in_head,void *in_track,void **ep)
{
struct rtsp_session *ls;
struct rtsp_session *head = (struct rtsp_session *)in_head;
struct rtsp_track *track = (struct rtsp_track *)in_track;
for( ls = head; ls; ls = ls->next )
{
if( ls->playing && track->ready && ls->sess->ep[track->index] )
{
*ep = ls->sess->ep[track->index];
return ls->next;
}
}
*ep = NULL;
return NULL;
}
static void rtsp_common_send( struct frame *f, void *d )
{
struct rtsp_track *track = (struct rtsp_track *)d;/*d: source->track[t]*/
struct rtsp_session *ls;
if(!f)
{
return;
}
if(!track->ready)
{
return;
}
//dest_status_msg(track,track->ready);
/*struct rtsp_session *next;*/
//这里添加获取jpeg的节点头发送完一帧后再循环到这里看是否有下一帧数据如果有那就继续发送省去多return一次的时间
/*callback: jpeg_process_frame, track->rtp->private: rtp_jpeg *out*/
if( ! track->rtp->frame( f, track->rtp ) ) //这个按理说不用一直运行的,只运行一次则可以
{
return;
}
if(track->rtp->send_more)
{
ls = track->source->sess_list;
if(!ls->closed){
track->rtp->send_more( loop_search_ep,ls, track,track->rtp->private);
}
}
for( ls = track->source->sess_list; ls; ls = ls->next )
{
if( ls->playing && track->ready && ls->sess->ep[track->index] )
{
/*callback: jpeg_send;ls->sess->ep[track->index], track->rtp->private: out*/
//track->rtp->send( ls->sess->ep[track->index], track->rtp->private );
if(track->rtp && track->rtp->rtcp_send)
{
track->rtp->rtcp_send( ls->sess->ep[track->index], track->rtp );
}
}
}
}
static void rtsp_frame_end( struct frame *f, void *d ){
struct rtsp_track *track = (struct rtsp_track *)d;/*d: source->track[t]*/
struct rtsp_session *ls;
struct rtsp_source *source;
for( ls = track->source->sess_list; ls; ls = ls->next )
{
source = ls->source;
if( !f || ls->closed)
{
/*callback: jpeg_send;ls->sess->ep[track->index], track->rtp->private: out*/
//track->rtp->send( ls->sess->ep[track->index], track->rtp->private );
ls->sess->teardown( ls->sess, ls->sess->ep[track->index] );
//如果有teardown后,则需要重新去轮询,因为之前的ls被释放了,虽然效率低,但考虑到设备数不多,这样应该还好
ls = track->source->sess_list;
if(!ls)
{
if(f)
{
//FREE_JPG_NODE(f->get_f);
unref_frame( f );
}
//因为所有的东西被释放,所以就要将线程和资源释放
if(source->release)
{
source->release(source);
}
break;
}
}
}
}
void *rtsp_start_block(void)
{
struct rtsp_source *source;
int i;
spook_log (SL_DEBUG, "live start_block");
source = (struct rtsp_source *)os_malloc( sizeof( struct rtsp_source ) );
//初始化source
memset(source,0,sizeof( struct rtsp_source ));
source->head_len = SPOOK_CACHE_BUF_HEAD_LEN;
//配置默认值
for( i = 0; i < MAX_TRACKS; ++i )
{
source->track[i].index = i;
source->track[i].source = source;
source->track[i].stream = NULL;
source->track[i].ready = 0;
source->track[i].rtp = NULL;
}
return source;
}
int rtsp_end_block( void *d )
{
struct rtsp_source *source = (struct rtsp_source *)d;
spook_log (SL_DEBUG, "live end_block");
if( ! source->track[0].rtp )
{
spook_log( SL_ERR, "live: no media sources specified!" );
return -1;
}
return 0;
}
#include "osal/string.h"
//视频注册
int set_video_track( const char *name, void *d )
{
struct rtsp_source *source = (struct rtsp_source *)d;
int t;
os_printf("%s:%d\n",__FUNCTION__,__LINE__);
spook_log (SL_DEBUG, "live set_track %s", name);
for( t = 0; t < MAX_TRACKS && source->track[t].rtp; ++t );
spook_log (SL_DEBUG, "live set_track %s", name);
if( t == MAX_TRACKS )
{
spook_log( SL_ERR, "live: exceeded maximum number of tracks" );
return -1;
}
spook_log (SL_DEBUG, "live set_track %s", name);
if( ! ( source->track[t].stream = connect_to_stream( name,rtsp_common_send, &source->track[t] ) ) )
{
spook_log( SL_ERR,"live: unable to connect to stream \"%s\"", name );
return -2;
}
spook_log (SL_DEBUG, "live set_track %s", name);
source->live_node.video_ex = get_video_ex(source->track[t].stream->stream->private);
disconnect_stream(source->track[t].stream,rtsp_frame_end);
source->track[t].rtp = new_rtp_media_jpeg_stream(source->track[t].stream->stream );
os_printf("%s source->track[t]:%X\trtp:%X\n",__FUNCTION__,source->track[t],source->track[t].rtp);
if( ! source->track[t].rtp ) return -3;
set_waiting( source->track[t].stream, 0 );
return 0;
}
//视频注册
int set_video_h264_track( const char *name, void *d )
{
struct rtsp_source *source = (struct rtsp_source *)d;
int t;
os_printf("%s:%d\n",__FUNCTION__,__LINE__);
spook_log (SL_DEBUG, "live set_track %s", name);
for( t = 0; t < MAX_TRACKS && source->track[t].rtp; ++t );
spook_log (SL_DEBUG, "live set_track %s", name);
if( t == MAX_TRACKS )
{
spook_log( SL_ERR, "live: exceeded maximum number of tracks" );
return -1;
}
spook_log (SL_DEBUG, "live set_track %s", name);
if( ! ( source->track[t].stream = connect_to_stream( name,rtsp_common_send, &source->track[t] ) ) )
{
spook_log( SL_ERR,"live: unable to connect to stream \"%s\"", name );
return -2;
}
spook_log (SL_DEBUG, "live set_track %s", name);
source->live_node.video_ex = get_video_ex(source->track[t].stream->stream->private);
disconnect_stream(source->track[t].stream,rtsp_frame_end);
source->track[t].rtp = new_rtp_media_h264_stream(source->track[t].stream->stream );
os_printf("%s source->track[t]:%X\trtp:%X\n",__FUNCTION__,source->track[t],source->track[t].rtp);
if( ! source->track[t].rtp ) return -3;
set_waiting( source->track[t].stream, 0 );
return 0;
}
//音频注册
int set_audio_track( char *name, void *d )
{
struct rtsp_source *source = (struct rtsp_source *)d;
int t;
spook_log (SL_DEBUG, "live set_track %s", name);
for( t = 0; t < MAX_TRACKS && source->track[t].rtp; ++t );
if( t == MAX_TRACKS )
{
spook_log( SL_ERR, "live: exceeded maximum number of tracks" );
return -1;
}
if( ! ( source->track[t].stream = connect_to_stream(name,rtsp_common_send, &source->track[t] ) ) )
{
spook_log( SL_ERR,"live: unable to connect to stream \"%s\"", name );
return -1;
}
source->live_node.audio_ex = get_audio_ex(source->track[t].stream->stream->private);
os_printf("live audio_ex:%X\n",source->live_node.audio_ex);
disconnect_stream(source->track[t].stream,rtsp_frame_end);
//要重新新建
source->track[t].rtp = new_rtp_media_audio_stream(source->track[t].stream->stream );
//默认打开
source->track[t].ready = 0;
if( ! source->track[t].rtp ) return -1;
set_waiting( source->track[t].stream, 0 );
return 0;
}
int rtsp_set_path( const char *path, void *d,rtsp_path_register register_fn )
{
spook_log (SL_DEBUG, "live set_path %s", path);
/*if( num_tokens == 2 )*/
{
new_rtsp_location( path, NULL, NULL, NULL,
register_fn, d );
return 0;
}
spook_log( SL_ERR, "rtsp-handler: syntax: Path <path> [<realm> <username> <password>]" );
return -1;
}
void register_live_fn(struct rtsp_source *source,rtsp_creat creat,rtsp_release release,rtsp_play_fn play_fn)
{
source->creat = creat;
source->release = release;
source->play = play_fn;
}

View File

@@ -0,0 +1,66 @@
#ifndef __RTSP_COMMON_H
#define __RTSP_COMMON_H
#include "spook_config.h"
#include "frame.h"
#include "encoder-audio.h"
#include "encoder-jpeg.h"
#include "rtp-audio.h"
#include "rtp.h"
#include "stream.h"
#include "rtp_media.h"
struct rtsp_session;
struct rtsp_track;
struct rtsp_source;
typedef void (*rtsp_creat)(struct rtsp_source *source,void *priv );
typedef void (*rtsp_release)(struct rtsp_source *source );
typedef void (*rtsp_play_fn)(struct rtsp_source *source );
typedef struct session *(*rtsp_path_register)( char *path, void *d );
struct rtsp_session {
struct rtsp_session *next;
struct rtsp_session *prev;
struct session *sess;
struct rtsp_source *source;
char path[64];
int playing;
int closed;
};
struct rtsp_track {
int index;
struct rtsp_source *source;
struct stream_destination *stream;
int ready;
struct rtp_media *rtp;
};
struct rtsp_source {
struct rtsp_session *sess_list;
struct rtsp_track track[MAX_TRACKS];
struct os_task handle;
void *signal;
struct rtp_node live_node;
int head_len; //保留头部的长度
//创建线程以及资源的回调函数,参数就是source
rtsp_creat creat;
//释放线程以及资源的回调函数,参数就是source
rtsp_release release;
rtsp_play_fn play;
void *priv;
};
void *rtsp_start_block(void);
int rtsp_end_block( void *d );
int set_video_track( const char *name, void *d );
int set_video_h264_track( const char *name, void *d );
int set_audio_track( char *name, void *d );
struct session *rtsp_open( char *path, void *d );
void register_live_fn(struct rtsp_source *source,rtsp_creat creat,rtsp_release release,rtsp_play_fn play);
int rtsp_set_path( const char *path, void *d,rtsp_path_register register_fn );
#endif

View File

@@ -0,0 +1,251 @@
#include "sys_config.h"
#include "tx_platform.h"
#include <csi_kernel.h>
#include "lwip\sockets.h"
#include "lwip\netif.h"
#include "lwip\dns.h"
#include "lwip\api.h"
#include "lwip\tcp.h"
#include "rtsp_common.h"
#include "osal/string.h"
#include "stream_define.h"
#include "video_app/video_app.h"
#include "video_app/video_app_h264_msi.h"
#include "stream_frame.h"
#include "log.h"
#include "lib/video/dvp/jpeg/jpg.h"
#include "frame.h"
#include "audio_media_ctrl/audio_code_ctrl.h"
#include "audio_msi/audio_adc.h"
#include "app/video_app/file_thumb.h"
extern struct msi *mp4_demux_msi_init(const char *msi_name, const char *filename);
extern struct msi *rtsp_msi_init(const char *name, uint8_t filter_type,uint8_t srcID);
extern void spook_send_thread_stream(struct rtsp_priv *r);
static void self_thread(void *d)
{
struct rtsp_priv *r = (struct rtsp_priv *) d;
spook_send_thread_stream(r);
}
// 创建实时预览的的线程
static void self_creat(struct rtsp_source *source, void *priv)
{
source->priv = (struct rtsp_priv *) os_zalloc(sizeof(struct rtsp_priv));
struct rtsp_priv *r = (struct rtsp_priv *) source->priv;
uint8_t *path = (uint8_t *) priv;
const char *match_path = (const char *) priv;
uint8_t default_value = 0;
AUENC_INIT auenc_init;
os_printf("path:%s\n", path);
while((*match_path) && (*match_path != '?'))
{
match_path++;
}
if(*match_path == '?')
{
match_path++;
}
os_printf("match_path:%s\n",match_path);
//匹配?的后缀(仅仅特定匹配)
if(*match_path)
{
default_value = *match_path - '0';
if(default_value > 1)
{
default_value = 0;
}
}
os_printf("default_value:%d\n",default_value);
uint8_t mp4_flag = 0;
if (source->priv)
{
r->live_node = &source->live_node;
if (memcmp(path, "/loop/RECA/", strlen("/loop/RECA/")) == 0)
{
uint8_t filepath[64] = {0};
os_sprintf((char *) filepath, REC_PATH "/%s", path + strlen("/loop/RECA/"));
// 尝试打开文件
os_printf("filepath:%s\n", filepath);
mp4_flag = 1;
r->video_msi = mp4_demux_msi_init("demux_mp4", (char *) filepath);
#if AUDIO_EN == 1
if (r->video_msi)
{
r->a_msi = rtsp_audio_msi_init(R_RTP_AUDIO);
msi_add_output(r->video_msi, NULL, R_RTP_AUDIO);
}
#endif
}
else
{
#if AUDIO_EN == 1
r->a_msi = rtsp_audio_msi_init(R_RTP_AUDIO);
auenc_init.destroy_self = 0;
auenc_init.src_msi = get_auadc_msi(AUSYS_AUAD);
r->audio_msi = audio_encode_init(AAC_ENC, audio_adc_get_samplerate(AUSYS_AUAD), &auenc_init);
if (r->audio_msi)
{
audio_code_add_output(r->audio_msi, R_RTP_AUDIO);
}
#endif
r->video_msi = msi_find(AUTO_H264, 1);
}
if (r->video_msi)
{
if (mp4_flag)
{
r->v_msi = rtsp_msi_init(R_RTP_JPEG_H264, FSTYPE_H264_FILE,FRAMEBUFF_SOURCE_NONE);
}
else
{
if(default_value == 0)
{
#ifndef FORCE_SCALE_TO_H264
r->v_msi = rtsp_msi_init(R_RTP_JPEG_H264, FSTYPE_H264_VPP_DATA0,FRAMEBUFF_SOURCE_CAMERA0);
#else
r->v_msi = rtsp_msi_init(R_RTP_JPEG_H264, FSTYPE_H264_SCALER_DATA,FRAMEBUFF_SOURCE_CAMERA0);
#endif
}
else if(default_value == 1)
{
r->v_msi = rtsp_msi_init(R_RTP_JPEG_H264, FSTYPE_H264_GEN420_DATA,FRAMEBUFF_SOURCE_NONE);
}
}
// r->write_test_sd_msi = mp4_encode_msi_init("mp4_write");
if (r->v_msi)
{
msi_add_output(r->video_msi, NULL, R_RTP_JPEG_H264); // 将video_msi的数据输出到R_RTP_JPEG_H264的msi,即v_msi
msi_do_cmd(r->video_msi, MSI_CMD_VIDEO_DEMUX_CTRL, MSI_VIDEO_DEMUX_START, 0);
OS_TASK_INIT("live_rtsp_h264", &source->handle, self_thread, r, OS_TASK_PRIORITY_NORMAL + 2, NULL, 1024);
}
}
// 这里没有增加容错
else
{
os_printf("%s h264 msi fail\n", __FUNCTION__);
return;
}
}
else
{
os_printf("%s not enough space\n", __FUNCTION__);
}
return;
}
static void self_destory(struct rtsp_source *source)
{
// stop_jpeg();
void *tmp = source->handle.hdl;
struct rtsp_priv *r = source->priv;
if (r)
{
if (r->video_msi)
{
msi_del_output(r->video_msi, NULL, R_RTP_JPEG_H264);
msi_put(r->video_msi);
r->video_msi = NULL;
}
rtsp_msi_deinit((void *) r->v_msi);
#if AUDIO_EN == 1
if (r->audio_msi)
{
audio_code_del_output(r->audio_msi, R_RTP_AUDIO);
audio_encode_deinit(r->audio_msi);
}
rtsp_audio_msi_deinit((void *) r->a_msi);
#endif
os_free(source->priv);
source->priv = NULL;
}
if (tmp)
{
os_task_del(&source->handle);
}
}
static void self_play(struct rtsp_source *source)
{
struct rtsp_priv *r = (struct rtsp_priv *) source->priv;
if (r->v_msi)
{
msi_do_cmd(r->video_msi, MSI_CMD_VIDEO_DEMUX_CTRL, MSI_VIDEO_DEMUX_START, 0);
}
}
static int self_get_sdp(struct session *s, char *dest, int *len, char *path)
{
struct rtsp_session *ls = (struct rtsp_session *) s->private;
int i = 0;
int t = 0;
char *addr = "IP4 0.0.0.0";
os_printf("%s:%d\tpath:%s\n", __FUNCTION__, __LINE__, path);
if (s->ep[0] && s->ep[0]->trans_type == RTP_TRANS_UDP)
{
addr = s->ep[0]->trans.udp.sdp_addr;
}
i = snprintf(dest, *len, "v=0\r\no=- 1 1 IN IP4 127.0.0.1\r\ns=Test\r\na=type:broadcast\r\nt=0 0\r\nc=IN %s\r\n", addr);
for (t = 0; t < MAX_TRACKS && ls->source->track[t].rtp; ++t)
{
int port;
if (s->ep[t] && s->ep[t]->trans_type == RTP_TRANS_UDP)
{
port = s->ep[t]->trans.udp.sdp_port;
}
else
{
port = 0;
}
if (ls->source->track[t].rtp->type == 0)
{
i += ls->source->track[t].rtp->get_sdp(dest + i, *len - i, 96 + t, port, ls->source->track[t].rtp->private);
}
else
{
i += ls->source->track[t].rtp->get_sdp(dest + i, *len - i, 96 + t, port, NULL);
}
if (port == 0) // XXX What's a better way to do this?
{
i += sprintf(dest + i, "a=control:track%d\r\n", t);
}
}
*len = i;
return t;
}
static struct session *self_rtsp_open(char *path, void *d)
{
// 默认的,各自模式可以各自去修改
struct session *sess = rtsp_open(path, d);
if (sess)
{
sess->get_sdp = self_get_sdp;
}
return sess;
}
void rtsp_h264_live_init(const rtp_name *rtsp)
{
struct rtsp_source *source;
source = rtsp_start_block();
rtsp_set_path(rtsp->path, source, self_rtsp_open);
set_video_h264_track((char *) rtsp->video_encode_name, source);
#if AUDIO_EN == 1
set_audio_track((char *) rtsp->audio_encode_name, source);
#endif
register_live_fn(source, self_creat, self_destory, self_play);
rtsp_end_block(source);
return;
}

View File

@@ -0,0 +1,168 @@
#include "sys_config.h"
#include "tx_platform.h"
#include <csi_kernel.h>
#include "lwip\sockets.h"
#include "lwip\netif.h"
#include "lwip\dns.h"
#include "lwip\api.h"
#include "lwip\tcp.h"
#include "rtsp_common.h"
#include "osal/string.h"
#include "stream_define.h"
#include "video_app/video_app.h"
#include "stream_frame.h"
#include "log.h"
#include "lib/video/dvp/jpeg/jpg.h"
#include "frame.h"
#include "audio_media_ctrl/audio_code_ctrl.h"
#include "audio_msi/audio_adc.h"
#include "jpg_concat_msi.h"
#include "gen420_hardware_msi.h"
extern void spook_send_thread_stream(struct rtsp_priv *r);
static void self_thread(void *d)
{
struct rtsp_priv *r = (struct rtsp_priv*)d;
spook_send_thread_stream(r);
}
//创建实时预览的的线程
static void self_creat(struct rtsp_source *source,void *priv)
{
source->priv = (struct rtsp_priv*)os_zalloc(sizeof(struct rtsp_priv));
struct rtsp_priv *r = (struct rtsp_priv*)source->priv;
AUENC_INIT auenc_init;
if(source->priv)
{
r->live_node = &source->live_node;
r->video_msi = msi_find(AUTO_JPG, 1); //jpg_concat_msi_init_start(JPGID0,1280, 720, NULL, VPP_DATA0,1);
if(r->video_msi)
{
r->v_msi = rtsp_msi_init(R_RTP_JPEG,~0,0);
#if AUDIO_EN == 1
r->a_msi = rtsp_audio_msi_init(R_RTP_AUDIO2);
auenc_init.destroy_self = 0;
auenc_init.src_msi = get_auadc_msi(AUSYS_AUAD);
r->audio_msi = audio_encode_init(AAC_ENC, audio_adc_get_samplerate(AUSYS_AUAD), &auenc_init);
if(r->audio_msi) {
audio_code_add_output(r->audio_msi, R_RTP_AUDIO2);
}
#endif
//r->write_test_sd_msi = mp4_encode_msi_init("mp4_write");
if(r->v_msi)
{
msi_add_output(r->video_msi, NULL, R_RTP_JPEG);
OS_TASK_INIT("live_rtsp_mjpeg", &source->handle, self_thread, r, OS_TASK_PRIORITY_NORMAL + 2, NULL, 1024);
}
}
//这里没有增加容错
else
{
os_printf("%s jpg_concat_msi_init_start fail\n",__FUNCTION__);
return;
}
}
else
{
os_printf("%s not enough space\n",__FUNCTION__);
}
return;
}
static void self_destory(struct rtsp_source *source)
{
//stop_jpeg();
void *tmp = source->handle.hdl;
struct rtsp_priv *r = source->priv;
if(r)
{
if(r->video_msi)
{
msi_del_output(r->video_msi,NULL,R_RTP_JPEG);
//msi_destroy(r->video_msi);
msi_put(r->video_msi);
r->video_msi = NULL;
}
rtsp_msi_deinit((void*)r->v_msi);
#if AUDIO_EN == 1
if(r->audio_msi) {
audio_code_del_output(r->audio_msi, R_RTP_AUDIO2);
audio_encode_deinit(r->audio_msi);
}
rtsp_audio_msi_deinit((void*)r->a_msi);
#endif
os_free(source->priv);
source->priv = NULL;
}
if(tmp)
{
os_task_del(&source->handle);
}
}
static int self_get_sdp( struct session *s, char *dest, int *len,
char *path )
{
struct rtsp_session *ls = (struct rtsp_session *)s->private;
int i = 0;
int t = 0;
char *addr = "IP4 0.0.0.0";
os_printf("%s:%d\tpath:%s\n",__FUNCTION__,__LINE__,path);
if( s->ep[0] && s->ep[0]->trans_type == RTP_TRANS_UDP )
addr = s->ep[0]->trans.udp.sdp_addr;
i = snprintf( dest, *len,"v=0\r\no=- 1 1 IN IP4 127.0.0.1\r\ns=Test\r\na=type:broadcast\r\nt=0 0\r\nc=IN %s\r\n", addr );
for( t = 0; t < MAX_TRACKS && ls->source->track[t].rtp; ++t )
{
int port;
if( s->ep[t] && s->ep[t]->trans_type == RTP_TRANS_UDP )
port = s->ep[t]->trans.udp.sdp_port;
else
port = 0;
if(ls->source->track[t].rtp->type == 0)
{
i += ls->source->track[t].rtp->get_sdp( dest + i, *len - i,96 + t, port,ls->source->track[t].rtp->private );
}
else
{
i += ls->source->track[t].rtp->get_sdp( dest + i, *len - i,96 + t, port,NULL);
}
if( port == 0 ) // XXX What's a better way to do this?
i += sprintf( dest + i, "a=control:track%d\r\n", t );
}
*len = i;
return t;
}
static struct session *self_rtsp_open( char *path, void *d )
{
//默认的,各自模式可以各自去修改
struct session *sess = rtsp_open(path,d);
if(sess)
{
sess->get_sdp = self_get_sdp;
}
return sess;
}
void rtsp_mjpeg_live_init(const rtp_name *rtsp)
{
struct rtsp_source *source;
source = rtsp_start_block();
rtsp_set_path( rtsp->path, source,self_rtsp_open );
set_video_track( (char*)rtsp->video_encode_name, source );
#if AUDIO_EN == 1
set_audio_track( (char*)rtsp->audio_encode_name, source );
#endif
register_live_fn(source,self_creat,self_destory,NULL);
rtsp_end_block(source);
return ;
}

134
sdk/app/spook/session.c Normal file
View File

@@ -0,0 +1,134 @@
/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
//#include "sys_config.h"
#include "lwip\sockets.h"
#include "lwip\netif.h"
#include "lwip\dns.h"
#include "lwip\api.h"
#include "lwip\tcp.h"
#include <event.h>
#include <log.h>
#include <frame.h>
#include <stream.h>
#include <rtp.h>
#include <rtp_media.h>
static struct session *sess_list = NULL;
struct rtp_media *new_rtp_media( rtp_media_get_sdp_func get_sdp,
rtp_media_get_payload_func get_payload, rtp_media_frame_func frame,
rtp_media_send_func send, void *private )
{
struct rtp_media *m;
if( ! ( m = (struct rtp_media *)malloc( sizeof( *m ) ) ) )
return NULL;
m->get_sdp = get_sdp;
m->get_payload = get_payload;
m->frame = frame;
m->send = send;
m->private = private;
m->rtcp_send = NULL;
return m;
}
struct rtp_media *new_rtp_rtcp_media( rtp_media_get_sdp_func get_sdp,
rtp_media_get_payload_func get_payload, rtp_media_frame_func frame,
rtp_media_send_func send,rtp_media_send_func rtcp_send, void *private )
{
struct rtp_media *m;
if( ! ( m = (struct rtp_media *)malloc( sizeof( *m ) ) ) )
return NULL;
m->get_sdp = get_sdp;
m->get_payload = get_payload;
m->frame = frame;
m->send = send;
m->rtcp_send = rtcp_send;
m->private = private;
return m;
}
void del_session( struct session *sess )
{
if( sess->next ) sess->next->prev = sess->prev;
if( sess->prev ) sess->prev->next = sess->next;
else sess_list = sess->next;
if( sess->control_close ) sess->control_close( sess ); /* callback: rtsp_session_close */
if(sess->conn)
{
//有点绕,判断conn是否正常,正常情况下,两个sess是一样的,则清空,说明这个不是从do_read去关闭,是异常关闭
_os_printf("%s:%d had conn\n",__FUNCTION__,__LINE__);
if(sess->conn->sess == sess)
{
sess->conn->sess = NULL;
}
}
_os_printf("%s session:%X\n",__FUNCTION__,(int)sess);
free( sess );
}
void resetnet_delsession(void)
{
struct session *sess;
for(sess = sess_list; sess != NULL; sess = sess->next) {
sess->conn->sess = NULL;
sess->teardown( sess, NULL );//live_teardown
}
}
struct session *new_session(void)
{
struct session *sess;
int i;
sess = (struct session *)malloc( sizeof( struct session ) );
sess->next = sess_list;
sess->prev = NULL;
if( sess->next ) sess->next->prev = sess;
sess_list = sess;
sess->get_sdp = NULL;
sess->setup = NULL;
sess->play = NULL;
sess->pause = NULL;
sess->private = NULL;
sess->control_private = NULL;
sess->control_close = NULL;
sess->conn = NULL;
gettimeofday( &sess->open_time, NULL );
strcpy( sess->addr, "(unconnected)" );
for( i = 0; i < MAX_TRACKS; ++i ) sess->ep[i] = NULL;
return sess;
}
int print_session_list( char *s, int maxlen )
{
struct session *sess;
int i = 0;
for( sess = sess_list; sess; sess = sess->next )
i += sprintf( s + i, "%s %ld\n",
sess->addr, sess->open_time.tv_sec );
return i;
}

1
sdk/app/spook/session.h Normal file
View File

@@ -0,0 +1 @@
#ifndef __SESSION_H

145
sdk/app/spook/spook.c Normal file
View File

@@ -0,0 +1,145 @@
/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include "lwip\sockets.h"
#include "lwip\netif.h"
#include "lwip\dns.h"
#include "lwip\api.h"
#include "lwip\tcp.h"
#include <event.h>
#include <log.h>
#include <frame.h>
#include <stream.h>
#include <rtp.h>
#include "spook_config.h"
#include "spook.h"
#include "sys_config.h"
#include "encoder-audio.h"
#include "encoder-jpeg.h"
unsigned long random_key;
static int init_random(void)
{
random_key = 0x12345678;
return 0;
}
uint32_t get_random(void)
{
return random_key;
}
void random_bytes( unsigned char *dest, int len )
{
int i;
for( i = 0; i < len; ++i )
dest[i] = (random_key++) & 0xff;
}
void random_id( unsigned char *dest, int len )
{
int i;
for( i = 0; i < len / 2; ++i )
sprintf( (char *)(dest + i * 2), "%02X",
(unsigned int)( (random_key++) & 0xff ) );
dest[len] = 0;
}
void global_init(void)
{
config_port(SPOOK_PORT);
}
extern void spook_send_thread(void *d);
extern int web_init(void);
extern int live_init(const rtp_name *jpg_name);
const rtp_name live_dvp = {
.video_encode_name = JPG_ENCODER_NAME,
.audio_encode_name = AUDIO_AAC_ENCODER_NAME,
.path = "/webcam",
};
const rtp_name live_h264 = {
.video_encode_name = H264_ENCODER_NAME,
.audio_encode_name = AUDIO_AAC_ENCODER_NAME2,
.path = "/h264",
};
const rtp_name live_h264_2 = {
.video_encode_name = H264_ENCODER_NAME,
.audio_encode_name = AUDIO_AAC_ENCODER_NAME,
.path = "/loop/RECA/",
};
const rtp_name live_custom = {
.video_encode_name = JPG_ENCODER_NAME,
.audio_encode_name = AUDIO_AAC_ENCODER_NAME,
.path = "/custom",
};
extern void live_rtsp_init(const rtp_name *rtsp);
extern void live_h264_rtsp_init(const rtp_name *rtsp);
extern void webfile_rtsp_init(const rtp_name *rtsp);
extern void rtsp_mjpeg_live_init(const rtp_name *rtsp);
extern void rtsp_h264_live_init(const rtp_name *rtsp);
void *jpeg_encode_init(const char *encode_name);
void *h264_encode_init(const char *encode_name);
void *rtsp_audio_encode_init(const char *encode_name);
extern void custom_rtsp_jpeg_init(const rtp_name *rtsp);
static void spook_thread(void *d)
{
init_random();
global_init();
jpeg_encode_init(JPG_ENCODER_NAME);
h264_encode_init(H264_ENCODER_NAME);
rtsp_audio_encode_init(AUDIO_AAC_ENCODER_NAME);
rtsp_audio_encode_init(AUDIO_AAC_ENCODER_NAME2);
rtsp_mjpeg_live_init(&live_dvp);
rtsp_h264_live_init(&live_h264);
custom_rtsp_jpeg_init(&live_custom);
rtsp_h264_live_init(&live_h264_2);
//webfile_rtsp_init(&webfile);
}
void spook_init(void)
{
//thread_create(spook_thread, 0, TASK_SPOOK_PRIO, 0, 110*1024, "spook");
spook_thread(0);
}

10
sdk/app/spook/spook.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef __SPOOK_H__
#define __SPOOK_H__
#include "spook_config.h"
int config_port( int port );
int live_init(const rtp_name *jpg_name);
void spook_init(void);
void * jpeg_init(const rtp_name *jpg_name);
#endif

View File

@@ -0,0 +1,73 @@
#ifndef __SPOOK_CONFGIG_H__
#define __SPOOK_CONFGIG_H__
//#include <board_config.h>
#define FRAME_HEAP 20
#define SPOOK_MAX_FRAME_SIZE 0/*352*288*3*/
#define SPOOK_PORT 554//7070//
//#define JPEG_ENCODER_NAME "jpeg_dvp"
//#define JPEG_ENCODER2_NAME "jpeg_usb"
#define FILE_JPEG_ENCODER_NAME "jpeg_file"
#define FILE_H264_ENCODER_NAME "h264_file"
#define JPEG_FRAMEINC 1
#define H264_FRAMEINC 1
#define AUDIO_ENCODER_NAME "audio"
#define FILE_AUDIO_ENCODER_NAME "audio"
#define EXCHANGER_SLOT_SIZE 16
//#define RTSP_LIVE_PATH "/webcam" /* /webcam */
//#define RTSP_LIVE_USB_PATH "/webcam2" /* /webcam */
#define RTSP_WEB_PATH "/file" /* /webcam */
//#define RTSP_LIVE_TRACK "jpeg_dvp"
//#define RTSP_LIVE2_TRACK "jpeg_usb"
#define RTSP_WEBFILE_TRACK "jpeg_file"
#define RTSP_LIVE_AUDIO_TRACK "audio"
#define RTSP_WEBFILE_AUDIO_TRACK "audio_file"
#define HTTP_PATTH "/webcam" /* /webcam */
#define HTTP_INPUT_NAME "jpeg"
#define HTTP_MODE "stream"
#define JPEG_FIFO_SIZE 3
#define SCAN_DATA_OFFSET 0x253//0X265
#define MAX_DATA_PACKET_SIZE 1440
#define SPOOK_CACHE_BUF_LEN 1600
#define SPOOK_CACHE_BUF_HEAD_LEN (4)
typedef struct
{
const char *video_encode_name; //视频编码的名称
const char *audio_encode_name; //音频编码的名称
const char* path;
}rtp_name;
#define H264_ENCODER_NAME "h264_encoder"
#define JPG_ENCODER_NAME "jpg_encoder"
#define AUDIO_AAC_ENCODER_NAME "audio_aac_encoder"
#define AUDIO_AAC_ENCODER_NAME2 "audio_aac_encoder2"
#endif

160
sdk/app/spook/stream.c Normal file
View File

@@ -0,0 +1,160 @@
/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <event.h>
#include <log.h>
#include <frame.h>
#include <stream.h>
struct converter {
struct stream_destination *input;
struct stream *output;
};
static struct stream *stream_list = NULL;
/*
static void get_framerate( struct stream *s, int *fincr, int *fbase )
{
struct stream_destination *dest =
(struct stream_destination *)s->private;
dest->stream->get_framerate( dest->stream, fincr, fbase );
}
static void set_running( struct stream *s, int running )
{
set_waiting( (struct stream_destination *)s->private, running );
}
*/
void deliver_frame_to_stream( struct frame *f, void *d )
{
struct stream *s = (struct stream *)d; /* d: jpeg_encoder->output */
struct stream_destination *dest;
for( dest = s->dest_list; dest; dest = dest->next )
{
/* destination is waitint for frame ?*/
if( ! dest->waiting ) {
if(dest->disconnect_frame){
dest->disconnect_frame( f, dest->d );
}
continue;
}
/*rtsp callback: next_live_frame, dest->d: source->track[t]*/
/*http callback: jpeg_next_frame, dest->d: source->track[t]*/
dest->process_frame( f, dest->d );
if(dest->disconnect_frame){
dest->disconnect_frame( f, dest->d );
}
}
unref_frame( f );
}
static struct stream_destination *new_dest( struct stream *s,
frame_deliver_func process_frame, void *d )
{
struct stream_destination *dest;
dest = (struct stream_destination *)
malloc( sizeof( struct stream_destination ) );
dest->next = s->dest_list;
dest->prev = NULL;
if( dest->next ) dest->next->prev = dest;
s->dest_list = dest;
dest->stream = s;
dest->waiting = 0;
dest->process_frame = process_frame;
dest->disconnect_frame = NULL;
dest->d = d;
return dest;
}
void disconnect_stream(struct stream_destination *dest,frame_disconnect_func disconnect_frame){
dest->disconnect_frame = disconnect_frame;
}
struct stream_destination *connect_to_stream( const char *name,
frame_deliver_func process_frame, void *d )
{
struct stream *s;
int found_one = 0;
for( s = stream_list; s; s = s->next )
if( ! strcmp( s->name, name ) )
return new_dest( s, process_frame, d );
if( found_one )
spook_log( SL_ERR, "unable to convert stream %s", name );
return NULL;
}
void del_stream( struct stream *s )
{
if( s->next ) s->next->prev = s->prev;
if( s->prev ) s->prev->next = s->next;
else stream_list = s->next;
free( s );
}
struct stream *new_stream( const char *name, int format, void *d )
{
struct stream *s;
s = (struct stream *)malloc( sizeof( struct stream ) );
s->next = stream_list;
s->prev = NULL;
if( s->next ) s->next->prev = s;
stream_list = s;
s->name = name;
s->format = format;
s->dest_list = NULL;
s->get_framerate = NULL;
s->set_running = NULL;
s->private = d;
return s;
}
void set_waiting( struct stream_destination *dest, int waiting )
{
struct stream *s = dest->stream;
/* We call set_running every time a destination starts listening,
* or when the last destination stops listening. It is good to know
* when new listeners come so maybe the source can send a keyframe. */
if( dest->waiting )
{
if( waiting ) return; /* no change in status */
dest->waiting = 0;
/* see if anybody else is listening */
for( dest = s->dest_list; dest; dest = dest->next )
waiting |= dest->waiting;
if( waiting ) return; /* others are still listening */
} else
{
if( ! waiting ) return; /* no change in status */
dest->waiting = 1;
}
s->set_running( s, waiting );
}

52
sdk/app/spook/stream.h Normal file
View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __STREAM_H
#define __STREAM_H
#include "frame.h"
struct stream_destination {
struct stream_destination *next;
struct stream_destination *prev;
struct stream *stream;
int waiting;
frame_deliver_func process_frame;
frame_disconnect_func disconnect_frame;
void *d;
};
struct stream {
struct stream *next;
struct stream *prev;
const char *name;
int format;
struct stream_destination *dest_list;
void (*get_framerate)( struct stream *s, int *fincr, int *fbase );
void (*set_running)( struct stream *s, int running );
void *private;
};
struct stream *new_stream( const char *name, int format, void *d );
void deliver_frame_to_stream( struct frame *f, void *d );
struct stream_destination *connect_to_stream( const char *name,
frame_deliver_func process_frame, void *d );
void del_stream( struct stream *s );
void set_waiting( struct stream_destination *dest, int waiting );
void disconnect_stream(struct stream_destination *dest,frame_disconnect_func disconnect_frame);
#endif

722
sdk/app/spook/tcp.c Normal file
View File

@@ -0,0 +1,722 @@
/*
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include "lwip\sockets.h"
#include "lwip\netif.h"
#include "lwip\dns.h"
// #include "lwip\fcntl.h"
#include "lwip\api.h"
#include "typesdef.h"
// #include <linux/linux_mutex.h>
#include <event.h>
#include <log.h>
#include <frame.h>
#include <stream.h>
#include <pmsg.h>
#include <rtp.h>
#include "lwip/api.h"
// #include "leases.h"
// #include "dhcpd.h"
static int base64[] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 00 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 20 */
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1, /* 30 */
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 40 */
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 50 */
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 60 */
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 70 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 90 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A0 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* B0 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* C0 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* D0 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* E0 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* F0 */
};
void write_access_log(char *path, struct sockaddr *addr, int code, char *req, int length, char *referer, char *user_agent);
struct listener
{
int fd;
};
/* all of tcp connetctions loop linked list */
static struct conn *conn_list = NULL;
static void do_read(void *ei, void *d);
void drop_conn(struct conn *c)
{
if (c->read_event)
{
eloop_remove_event(c->read_event);
c->read_event = NULL;
}
if (c->write_event)
{
eloop_remove_event(c->write_event);
c->write_event = NULL;
}
if (c->fd >= 0)
{
close(c->fd);
}
c->fd = -1;
os_event_del(&c->evt);
if (c->next)
{
c->next->prev = c->prev;
}
if (c->prev)
{
c->prev->next = c->next;
}
else
{
conn_list = c->next;
}
if (c->proto_state)
{
free(c->proto_state);
c->proto_state = NULL;
}
free(c);
_os_printf("%s finish\n", __FUNCTION__);
}
static void conn_write(void *ei, void *d)
{
spook_log(SL_DEBUG, "tcp_w");
struct conn *c = (struct conn *) d;
int ret, len;
struct session *sess;
while (c->send_buf_r != c->send_buf_w)
{
if (c->send_buf_w < c->send_buf_r)
{
len = sizeof(c->send_buf) - c->send_buf_r;
}
else
{
len = c->send_buf_w - c->send_buf_r;
}
// 等待1ms,没有完成就退出,等待下一次
int evt_err = os_event_wait(&c->evt, RTSP_TCP_READ_MUTEX|RTSP_TCP_WRITE_MUTEX, NULL, OS_EVENT_WMODE_AND | OS_EVENT_WMODE_CLEAR, 1);
if (!evt_err)
{
ret = write(c->fd, c->send_buf + c->send_buf_r, len);
os_event_set(&c->evt, RTSP_TCP_READ_MUTEX | RTSP_TCP_WRITE_MUTEX, NULL);
}
//没有成功,则直接退出,下次重新尝试发送
else
{
return;
}
if (ret <= 0)
{
if (ret < 0 && get_errno() == EAGAIN)
{
return;
}
// drop_conn( c );
goto conn_write_exit;
}
c->send_buf_r += ret;
if (c->send_buf_r == sizeof(c->send_buf))
{
c->send_buf_r = 0;
}
}
if (c->drop_after)
{
goto conn_write_exit;
}
else
{
eloop_set_event_enabled(c->write_event, 0);
}
// 缓冲buf已经发送完成,所以将读和写重置(这种设置方式,不能存在异步,所以只能全部在event_loop,event_loop相当于单线程)
c->send_buf_r = 0;
c->send_buf_w = 0;
return;
conn_write_exit:
sess = c->sess;
_os_printf("close sess:%x\r\n", (int) sess);
if (sess)
{
// sess->conn = NULL;
_os_printf("close sess->close:%x\r\n", (int) sess->closed);
sess->closed(sess, NULL);
}
// 关闭自己的事件和socket
if (c->read_event)
{
eloop_remove_event(c->read_event);
c->read_event = NULL;
}
if (c->write_event)
{
eloop_remove_event(c->write_event);
c->write_event = NULL;
}
if (c->fd >= 0)
{
close(c->fd);
c->fd = -1;
}
return;
}
int avail_send_buf(struct conn *c)
{
if (c->send_buf_r > c->send_buf_w)
{
return c->send_buf_r - c->send_buf_w - 1;
}
else
{
return sizeof(c->send_buf) - c->send_buf_w + c->send_buf_r - 1;
}
}
int send_data(struct conn *c, unsigned char *d, int len)
{
if (avail_send_buf(c) < len)
{
return 1;
}
while (--len >= 0)
{
c->send_buf[c->send_buf_w++] = *(d++);
if (c->send_buf_w == sizeof(c->send_buf))
{
c->send_buf_w = 0;
}
}
eloop_set_event_enabled(c->write_event, EVENT_F_ENABLED);
return 0;
}
int tcp_send_pmsg(struct conn *c, struct pmsg *msg, int len)
{
char buf[512];
int i, f, totlen;
if (msg->type != PMSG_RESP)
{
return -1;
}
i = sprintf(buf, "%s %d %s\r\n", msg->proto_id, msg->sl.stat.code, msg->sl.stat.reason);
for (f = 0; f < msg->header_count; ++f)
{
i += sprintf(buf + i, "%s: %s\r\n", msg->fields[f].name, msg->fields[f].value);
}
if (len >= 0)
{
i += sprintf(buf + i, "Content-Length: %d\r\n\r\n", len);
totlen = i + len;
}
else
{
i += sprintf(buf + i, "\r\n");
totlen = i;
}
if (avail_send_buf(c) < totlen)
{
return -1;
}
_os_printf("%s\r\n", buf);
send_data(c, (unsigned char *) buf, i);
return 0;
}
static void log_request(struct req *req, int code, int length)
{
char *ref, *ua;
ref = get_header(req->req, "referer");
ua = get_header(req->req, "user-agent");
write_access_log(NULL, (struct sockaddr *) &req->conn->client_addr, code, (char *) req->conn->req_buf, length, ref ? ref : "-", ua ? ua : "-");
}
static int handle_unknown(struct req *req)
{
log_request(req, 501, 0);
req->conn->drop_after = 1;
req->resp = new_pmsg(256);
req->resp->type = PMSG_RESP;
req->resp->proto_id = add_pmsg_string(req->resp, req->req->proto_id);
req->resp->sl.stat.code = 501;
req->resp->sl.stat.reason = add_pmsg_string(req->resp, "Not Implemented");
copy_headers(req->resp, req->req, "CSeq");
tcp_send_pmsg(req->conn, req->resp, -1);
return 0;
}
static int handle_request(struct conn *c)
{
int ret;
struct req *req;
if (c->req_buf[0] == 0)
{
return -1;
}
if ((req = malloc(sizeof(struct req))) == NULL)
{
return -1;
}
req->conn = c;
req->resp = NULL;
req->req = new_pmsg(c->req_len);
req->req->msg_len = c->req_len;
memcpy(req->req->msg, c->req_buf, req->req->msg_len);
if (parse_pmsg(req->req) < 0)
{
free_pmsg(req->req);
free(req);
return -1;
}
spook_log(SL_VERBOSE, "client request: '%s' '%s' '%s'", req->req->sl.req.method, req->req->sl.req.uri, req->req->proto_id);
switch (c->proto)
{
case CONN_PROTO_RTSP:
ret = rtsp_handle_msg(req);
break;
default:
ret = handle_unknown(req);
break;
}
if (ret <= 0)
{
free_pmsg(req->req);
if (req->resp)
{
free_pmsg(req->resp);
}
free(req);
}
return ret < 0 ? -1 : 0;
}
static int parse_client_data(struct conn *c)
{
char *a, *b;
switch (c->proto)
{
case CONN_PROTO_START:
if ((a = strchr((const char *) c->req_buf, '\n')))
{
*a = 0;
if (!(b = strrchr((const char *) c->req_buf, ' ')))
{
return -1;
}
if (!strncmp(b + 1, "HTTP/", 5))
{
c->proto = CONN_PROTO_HTTP;
}
else if (!strncmp(b + 1, "RTSP/", 5))
{
c->proto = CONN_PROTO_RTSP;
}
else if (!strncmp(b + 1, "APPO/", 5))
{
c->proto = CONN_PROTO_APPO;
}
else
{
return -1;
}
*a = '\n';
return 1;
}
break;
case CONN_PROTO_RTSP:
if (c->req_len < 4)
{
return 0;
}
if (c->req_buf[0] == '$')
{
spook_log(SL_DEBUG, "interleave_recv\n");
if (c->req_len < GET_16(c->req_buf + 2) + 4)
{
return 0;
}
#if 0
interleave_recv( c, c->req_buf[1], c->req_buf + 4,
GET_16( c->req_buf + 2 ) );
#else
c->req_len -= (GET_16(c->req_buf + 2) + 4);
#endif
/* should really just delete the packet from the
* buffer, not the entire buffer */
// c->req_len = 0;
}
else
{
if (!strstr((const char *) c->req_buf, (const char *) "\r\n\r\n"))
{
return 0;
}
if (handle_request(c) < 0)
{
return -1;
}
/* should really just delete the request from the
* buffer, not the entire buffer */
c->req_len = 0;
}
break;
}
return 0;
}
static int unbase64(unsigned char *d, int len, int *remain)
{
int src = 0, dest = 0, i;
unsigned char enc[4];
for (;;)
{
for (i = 0; i < 4; ++src)
{
if (src >= len)
{
if (i > 0)
{
memcpy(d + dest, enc, i);
}
*remain = i;
return dest + i;
}
if (base64[d[src]] < 0)
{
continue;
}
enc[i++] = d[src];
}
d[dest] = ((base64[enc[0]] << 2) & 0xFC) | (base64[enc[1]] >> 4);
d[dest + 1] = ((base64[enc[1]] << 4) & 0xF0) | (base64[enc[2]] >> 2);
d[dest + 2] = ((base64[enc[2]] << 6) & 0xC0) | base64[enc[3]];
if (enc[3] == '=')
{
if (enc[2] == '=')
{
dest += 1;
}
else
{
dest += 2;
}
}
else
{
dest += 3;
}
}
}
#if 0
static unsigned char s_ptemp[300] = {"TEARDOWN rtsp://192.168.1.1:7070/webcam/ RTSP/1.0\r\nCSeq: 6\r\nUser-Agent: Lavf56.40.101\r\nSession: 9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9\r\n\r\n4A5A6A7A8A9\r\n\r\n"};
#endif
static void do_read(void *ei, void *d)
{
_os_printf("%s:%d\n", __FUNCTION__, __LINE__);
spook_log(SL_DEBUG, "tcp do_read");
struct conn *c = (struct conn *) d;
int ret;
struct session *sess = NULL;
for (;;)
{
os_event_wait(&c->evt, RTSP_TCP_READ_MUTEX, NULL, OS_EVENT_WMODE_AND | OS_EVENT_WMODE_CLEAR, -1);
ret = read(c->fd, c->req_buf + c->req_len, sizeof(c->req_buf) - c->req_len - 1);
os_event_set(&c->evt, RTSP_TCP_READ_MUTEX, NULL);
if (ret <= 0)
{
if (ret < 0)
{
if (get_errno() == EAGAIN)
{
spook_log(SL_VERBOSE, "get_errno() === %x", get_errno());
return;
}
spook_log(SL_VERBOSE, "get_errno() = %x", get_errno());
spook_log(SL_VERBOSE, "closing TCP connection to client due to read error: %s ret:%d", strerror(get_errno()), ret);
}
else
{
spook_log(SL_VERBOSE, "client closed TCP connection %x c:%X", c->sess, c);
/* add by jornny */
/* should be initialized by NULL */
}
spook_log(SL_DEBUG, "free conn");
// drop_conn( c );
/* add by jornny */
/* drop_conn has free c, so can not use c->sess !!!*/
sess = c->sess;
// 关闭自己的事件和socket
if (c->read_event)
{
eloop_remove_event(c->read_event);
c->read_event = NULL;
}
if (c->write_event)
{
eloop_remove_event(c->write_event);
c->write_event = NULL;
}
c->running = 0;
_os_printf("close sess:%x\r\n", (int) sess);
if (sess)
{
// sess->conn = NULL;
_os_printf("close sess->close:%x\r\n", (int) sess->closed);
sess->closed(sess, NULL);
}
// 没有sess,说明连接还没有正式
else
{
_os_printf("%s:%d\n", __FUNCTION__, __LINE__);
drop_conn(c);
}
return;
}
c->req_len += ret;
if (c->req_len == sizeof(c->req_buf) - 1)
{
spook_log(SL_VERBOSE, "malformed request from client; exceeded maximum size");
return;
}
c->req_buf[c->req_len] = 0;
while ((ret = parse_client_data(c)) > 0)
;
if (ret < 0)
{
_os_printf("%s:%d\n", __FUNCTION__, __LINE__);
// drop_conn( c );
return;
}
}
}
extern int g_timeout;
uint8_t sta_mac[8];
extern uint8_t keep_send;
static void do_accept(void *ei, void *d)
{
spook_log(SL_DEBUG, "tcp do_accept");
struct listener *listener = (struct listener *) d;
int fd;
unsigned int i;
struct sockaddr_in addr;
struct conn *c;
_os_printf("%s %d\n", __func__, __LINE__);
i = sizeof(addr);
if ((fd = accept(listener->fd, (struct sockaddr *) &addr, &i)) < 0)
{
spook_log(SL_WARN, "error accepting TCP connection: %s", strerror(get_errno()));
return;
}
spook_log(SL_VERBOSE, "accepted connection from %s:%d", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
{
spook_log(SL_INFO, "error setting O_NONBLOCK on socket: %s", strerror(get_errno()));
}
i = 0;
if (setsockopt(fd, IPPROTO_TCP /*SOL_SOCKET*/ /*SOL_TCP*/, TCP_NODELAY, &i, sizeof(i)) < 0)
{
spook_log(SL_INFO, "error setting TCP_NODELAY on socket: %s", strerror(get_errno()));
}
// int tos = 0xe0;
// setsockopt(fd, IPPROTO_IP, IP_TOS, (void *)&tos , sizeof(tos));
#if 0
/* Find the dhcp Offered Addr based the IP Addr of this Connection */
p_dhcp_addr = find_lease_by_yiaddr(addr.sin_addr.s_addr);
_os_printf("%s %d\n",__func__,__LINE__);
if (NULL != p_dhcp_addr)
{
for (c = conn_list; c != NULL; c = c->next)
{
ret = memcmp(c->chaddr, p_dhcp_addr->chaddr, 6);
if (0 == ret)
{
/* If the same Connection Client Mac Addr has existed, delete the previous Connection */
if (g_timeout == 0)
{
//parse_client_data(c);
if(c->sess)
c->sess->closed( c->sess, NULL);
}
else
{
g_timeout = 0;
}
drop_conn(c);
break;//只有一个ip是一样的,直接退出,否则drop_conn会更改conn_list链表,导致这里for出错
}
}
}
#endif
int keepalive = 1;
int keepidle = 10;
int keepintvl = 3;
int keepcnt = 3;
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *) &keepalive, sizeof(keepalive));
setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, (void *) &keepidle, sizeof(keepidle));
setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, (void *) &keepintvl, sizeof(keepintvl));
setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, (void *) &keepcnt, sizeof(keepcnt));
c = (struct conn *) malloc(sizeof(struct conn));
_os_printf("%s c:%X\n", __FUNCTION__, (int) c);
c->next = conn_list;
if (c->next)
{
c->next->prev = c;
}
c->prev = NULL;
c->fd = fd;
c->client_addr = addr;
c->proto = CONN_PROTO_START;
c->req_len = 0;
c->req_list = NULL;
c->read_event = eloop_add_fd(fd, EVENT_READ, EVENT_F_ENABLED, do_read, c);
c->write_event = eloop_add_fd(fd, EVENT_WRITE, EVENT_F_DISABLED, conn_write, c);
eloop_set_event_enabled(c->write_event, EVENT_F_DISABLED);
c->send_buf_r = c->send_buf_w = 0;
c->drop_after = 0;
c->proto_state = NULL;
c->sess = NULL; /* should be initialized by NULL */
c->running = 1;
os_event_init(&c->evt);
os_event_set(&c->evt, RTSP_TCP_READ_MUTEX | RTSP_TCP_WRITE_MUTEX, NULL);
conn_list = c;
/* Store the Client MAC Addr */
// memcpy(c->chaddr, p_dhcp_addr->chaddr, 6);
// memcpy(sta_mac, p_dhcp_addr->chaddr, 6);
//_os_printf("STA con[%x %x %x %x %x %x]\n",sta_mac[0],sta_mac[1],sta_mac[2],sta_mac[3],sta_mac[4],sta_mac[5]);
spook_log(SL_DEBUG, "TCP do_accept %d", fd);
}
static int tcp_listen(int port)
{
struct sockaddr_in addr;
struct listener *listener;
int opt, fd;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = 0;
addr.sin_port = htons(port);
if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
spook_log(SL_ERR, "error creating listen socket: %s", strerror(get_errno()));
return -1;
}
opt = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
{
spook_log(SL_WARN, "ignoring error on setsockopt: %s", strerror(get_errno()));
}
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
{
spook_log(SL_ERR, "unable to bind to tcp socket: %s", strerror(get_errno()));
close(fd);
return -1;
}
if (listen(fd, 5) < 0)
{
spook_log(SL_ERR, "error when attempting to listen on tcp socket: %s", strerror(get_errno()));
close(fd);
return -1;
}
listener = (struct listener *) malloc(sizeof(struct listener));
listener->fd = fd;
eloop_add_fd(fd, EVENT_READ, EVENT_F_ENABLED, do_accept, listener);
spook_log(SL_INFO, "listening on tcp port %d", port);
_os_printf("port:%d\tfd:%d\n", port, fd);
return 0;
}
/********************* GLOBAL CONFIGURATION DIRECTIVES ********************/
int config_port(int port)
{
if (port <= 0 || port > 65535)
{
spook_log(SL_ERR, "invalid listen port %d", port);
return -1;
}
return tcp_listen(port); // listen the 7070 port everytime
}

241
sdk/app/spook/webfile.c Normal file
View File

@@ -0,0 +1,241 @@
#include "sys_config.h"
#include "tx_platform.h"
#include <csi_kernel.h>
#include "lwip\sockets.h"
#include "lwip\netif.h"
#include "lwip\dns.h"
#include "lwip\api.h"
#include "lwip\tcp.h"
#include "rtsp_common.h"
#include "osal/string.h"
#include "stream_define.h"
#include "video_app/video_app.h"
#include "stream_frame.h"
#include "log.h"
#include "avidemux.h"
#define WEBFILE_BASE_PATH "DCIM"
extern void spook_send_thread_stream(struct rtsp_priv *r);
extern uint32_t creat_stream(struct rtsp_priv *r,const char *video_name,const char *audio_name);
extern uint32_t destory_stream(struct rtsp_priv *r);
extern uint32_t stop_play_avi_stream(stream* s);
void rtsp_webfile_thread(void *d)
{
struct rtsp_priv *r = (struct rtsp_priv*)d;
os_printf("%s:%d\n",__FUNCTION__,__LINE__);
spook_send_thread_stream(r);
}
stream* creat_play_avi_stream(const char *name,char *filepath,char *recv_name);
//创建实时预览的的线程
void webfile_rtsp_creat(struct rtsp_source *source,void *priv)
{
char *path = (char*)priv;
//void *fp = NULL;
//struct aviinfo *info = NULL;
char filePath[64] = {0};
if(path)
{
_os_printf("%s path:%s\n",__FUNCTION__,path);
char *base = path;
char *c;
int filePathLen = strlen(base);
if(filePathLen > 1 && path[filePathLen - 1] == '/')
{
--filePathLen;
}
c = strchr (base+1, '/');
filePathLen -= c - base;
filePath[0] = '0';
filePath[1] = ':';
memcpy(filePath+2,WEBFILE_BASE_PATH,strlen(WEBFILE_BASE_PATH));
strncpy (filePath+2+strlen(WEBFILE_BASE_PATH), c, filePathLen);
filePath[2+filePathLen+strlen(WEBFILE_BASE_PATH)] = '\0';
}
else
{
goto webfile_rtsp_creat_end;
}
//先去打开一下文件?然后判断一下?
uint32_t res;
source->priv = (struct rtsp_priv*)os_malloc(sizeof(struct rtsp_priv));
struct rtsp_priv *r = (struct rtsp_priv*)source->priv;
if(source->priv)
{
r->live_node = &source->live_node;
res = creat_stream(r,R_RTP_JPEG,NULL);
if(!res)
{
csi_kernel_task_new((k_task_entry_t)rtsp_webfile_thread, "rtsp", r, 9, 0, NULL, 1024,&source->thread_handle);
//创建播放文件的流
r->webfile_s = creat_play_avi_stream(S_WEBJPEG,filePath,R_RTP_JPEG);
void *webfile_handle;
extern void play_web_avi_thread(void *d);
if(r->webfile_s)
{
_os_printf("webfile_s1:%X\n",(unsigned int)r->webfile_s);
//如果创建任务失败,需要close一次
open_stream_again(r->webfile_s);
//打开对应的文件
csi_kernel_task_new((k_task_entry_t)play_web_avi_thread, "play_avi", r->webfile_s, 9, 0, NULL, 1024,&webfile_handle);
}
}
}
else
{
_os_printf("%s not enough space\n",__FUNCTION__);
}
webfile_rtsp_creat_end:
return;
}
//创建实时预览的的线程
void webfile_rtsp_destory(struct rtsp_source *source)
{
void *tmp = source->thread_handle;
struct rtsp_priv *r = source->priv;
if(r)
{
if(r->webfile_s)
{
stop_avi_stream(r->webfile_s);
}
destory_stream(r);
os_free(source->priv);
source->priv = NULL;
}
source->thread_handle = NULL;
if(tmp)
{
csi_kernel_task_del(tmp);
}
}
static int webfile_get_sdp( struct session *s, char *dest, int *len,
char *path )
{
struct rtsp_session *ls = (struct rtsp_session *)s->private;
int i = 0, t;
char *addr = "IP4 0.0.0.0";
_os_printf("%s:%d\tpath:%s\n",__FUNCTION__,__LINE__,path);
struct avi_msg msg;
char filePath[64] = {0};
uint32_t msk;
if(path)
{
_os_printf("%s path:%s\n",__FUNCTION__,path);
char *base = path;
char *c;
int filePathLen = strlen(base);
if(filePathLen > 1 && path[filePathLen - 1] == '/')
{
--filePathLen;
}
c = strchr (base+1, '/');
filePathLen -= c - base;
filePath[0] = '0';
filePath[1] = ':';
memcpy(filePath+2,WEBFILE_BASE_PATH,strlen(WEBFILE_BASE_PATH));
strncpy (filePath+2+strlen(WEBFILE_BASE_PATH), c, filePathLen);
filePath[2+filePathLen+strlen(WEBFILE_BASE_PATH)] = '\0';
}
_os_printf("filePath:%s\n",filePath);
msk = get_avidemux_parse_stream(filePath,&msg);
if( s->ep[0] && s->ep[0]->trans_type == RTP_TRANS_UDP )
addr = s->ep[0]->trans.udp.sdp_addr;
i = snprintf( dest, *len,"v=0\r\no=- 1 1 IN IP4 127.0.0.1\r\ns=Test\r\na=type:broadcast\r\nt=0 0\r\nc=IN %s\r\n", addr );
for( t = 0; t < MAX_TRACKS && ls->source->track[t].rtp; ++t )
{
int port;
//if( ! ls->source->track[t].ready ) return 0;
if( s->ep[t] && s->ep[t]->trans_type == RTP_TRANS_UDP )
port = s->ep[t]->trans.udp.sdp_port;
else
port = 0;
os_printf("sdp type:%d\n",ls->source->track[t].rtp->type);
if(ls->source->track[t].rtp->type == 0)
{
i += ls->source->track[t].rtp->get_sdp( dest + i, *len - i,96 + t, port,ls->source->track[t].rtp->private );
}
else
{
if(!(msk&BIT(1)))
{
continue;
}
ls->source->track[t].rtp->sample_rate = msg.audio_sample_rate;
i += ls->source->track[t].rtp->get_sdp( dest + i, *len - i,96 + t, port,(void*)msg.audio_sample_rate);
}
if( port == 0 ) // XXX What's a better way to do this?
i += sprintf( dest + i, "a=control:track%d\r\n", t );
}
*len = i;
return t;
}
static struct session *webfile_rtsp_open( char *path, void *d )
{
//默认的,各自模式可以各自去修改
struct session *sess = rtsp_open(path,d);
if(sess)
{
sess->get_sdp = webfile_get_sdp;
}
return sess;
}
static int webfile_set_path( const char *path, void *d )
{
spook_log (SL_DEBUG, "live set_path %s", path);
/*if( num_tokens == 2 )*/
{
new_rtsp_location( path, NULL, NULL, NULL,webfile_rtsp_open, d );
return 0;
}
spook_log( SL_ERR, "rtsp-handler: syntax: Path <path> [<realm> <username> <password>]" );
return -1;
}
void webfile_rtsp_init(const rtp_name *rtsp)
{
struct rtsp_source *source;
source = rtsp_start_block();
webfile_set_path( rtsp->path, source );
set_video_track( (char*)rtsp->jpg_name, source );
//set_audio_track( (char*)rtsp->audio_name, source );
register_live_fn(source,webfile_rtsp_creat,webfile_rtsp_destory);
rtsp_end_block(source);
return ;
}