512 lines
14 KiB
C
512 lines
14 KiB
C
#include "strm_video_rec.h"
|
||
#include "asm/osd.h"
|
||
#include "app_config.h"
|
||
|
||
|
||
static struct strm_video_hdl fv_rec_handler;
|
||
|
||
#define AUDIO_VOLUME 64
|
||
|
||
#define __this_strm (&fv_rec_handler)
|
||
|
||
#define STRM_USE_NET_VIDEO_BUFF 1 //当使用共用视频buf时:1
|
||
|
||
extern int net_video_rec_get_uvc_id(void);
|
||
extern int net_video_rec_state(void);
|
||
extern void *get_video_rec0_handler(void);
|
||
extern void *get_video_rec1_handler(void);
|
||
static int fv_video_rec_start(void);
|
||
static int fv_video_rec_stop(void);
|
||
static int fv_video_rec_close(char close);
|
||
extern int db_select(const char *name);
|
||
|
||
static const u16 strm_rec_pix_w[] = {1280, 640};
|
||
static const u16 strm_rec_pix_h[] = {720, 480};
|
||
static const unsigned char net_osd_format_buf[] = "yyyy-nn-dd hh:mm:ss";
|
||
|
||
static struct fenice_source_info s_info = {
|
||
.type = STRM_SOURCE_VIDEO0,//摄像头类型
|
||
.width = 640,//分辨率
|
||
.height = 480,
|
||
.fps = STRM_VIDEO_REC_FPS0,//帧率
|
||
.sample_rate = 0,//采样率,默认配置为0
|
||
.channel_num = 1,//通道数
|
||
};
|
||
|
||
/*码率控制,根据具体分辨率设置*/
|
||
static int strm_video_rec_get_abr(u32 width)
|
||
{
|
||
if (width <= 384) {
|
||
return 1000;
|
||
} else if (width <= 640) {
|
||
return 2000;//2000;
|
||
} else if (width <= 1280) {
|
||
return 2500;
|
||
/* return 10000; */
|
||
} else if (width <= 1920) {
|
||
return 3000;
|
||
} else {
|
||
return 3000;
|
||
}
|
||
}
|
||
int strm_video_rec_get_fps(void)
|
||
{
|
||
return 25;
|
||
}
|
||
int strm_video_rec_get_list_vframe(void)
|
||
{
|
||
return __this_strm->fbuf_fcnt;
|
||
}
|
||
void strm_video_rec_pkg_get_video_in_frame(char *fbuf, u32 frame_size)
|
||
{
|
||
__this_strm->fbuf_fcnt++;
|
||
__this_strm->fbuf_ffil += frame_size;
|
||
}
|
||
void strm_video_rec_pkg_get_video_out_frame(char *fbuf, u32 frame_size)
|
||
{
|
||
if (__this_strm->fbuf_fcnt) {
|
||
__this_strm->fbuf_fcnt--;
|
||
}
|
||
if (__this_strm->fbuf_ffil) {
|
||
__this_strm->fbuf_ffil -= frame_size;
|
||
}
|
||
}
|
||
|
||
|
||
static int abs(int a)
|
||
{
|
||
return a < 0 ? -a : a;
|
||
}
|
||
|
||
#include "math.h"
|
||
|
||
static int g_dB = 0;
|
||
int getPcmDB(const unsigned char *pcmdata, size_t size)
|
||
{
|
||
|
||
int db = 0;
|
||
short value = 0;
|
||
unsigned int sum = 0;
|
||
for (int i = 0; i < size; i += 2) {
|
||
memcpy(&value, pcmdata + i, 2); //获取2个字节的大小(值)
|
||
sum += abs(value); //绝对值求和
|
||
}
|
||
sum = sum / (size / 2); //求平均值(2个字节表示一个振幅,所以振幅个数为:size/2个)
|
||
float sum1 = sum / 32768.0;
|
||
|
||
if (sum > 0) {
|
||
db = (int)(20 * log10f(sum1));
|
||
}
|
||
return db;
|
||
}
|
||
|
||
void strm_video_rec_pkg_get_audio_in_frame(char *fbuf, u32 frame_size)
|
||
{
|
||
g_dB = getPcmDB(fbuf, frame_size);
|
||
}
|
||
|
||
int get_dB()
|
||
{
|
||
return g_dB;
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
int strm_video_buff_set_frame_cnt(void)
|
||
{
|
||
#ifdef STRM_VIDEO_BUFF_FRAME_CNT
|
||
return STRM_VIDEO_BUFF_FRAME_CNT;
|
||
#else
|
||
return 0;
|
||
#endif
|
||
}
|
||
int strm_video_rec_get_drop_fp(void)
|
||
{
|
||
#ifdef STRM_VIDEO_REC_DROP_REAl_FP
|
||
return STRM_VIDEO_REC_DROP_REAl_FP;
|
||
#else
|
||
return 0;
|
||
#endif
|
||
}
|
||
int strm_video_rec_get_state(void)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
static int fv_video_rec_open(void)
|
||
{
|
||
int ret;
|
||
int id = 0;
|
||
int buf_size[] = {VREC0_FBUF_SIZE, VREC1_FBUF_SIZE, VREC2_FBUF_SIZE};
|
||
int net_buf_size[] = {NET_VREC0_FBUF_SIZE, NET_VREC1_FBUF_SIZE};
|
||
|
||
if (__this_strm->state == NET_VIDREC_STA_START) {
|
||
printf("video opened \n\n");
|
||
return 0;
|
||
}
|
||
|
||
if (s_info.type == STRM_SOURCE_VIDEO1) {
|
||
#ifdef CONFIG_VIDEO1_ENABLE
|
||
id = 1;
|
||
#endif
|
||
#ifdef CONFIG_VIDEO2_ENABLE
|
||
id = 2;
|
||
#endif
|
||
}
|
||
#if STRM_USE_NET_VIDEO_BUFF
|
||
//当视频buf使用静态buf时,可以打开
|
||
extern u8 net_video_buf[NET_VREC0_FBUF_SIZE];
|
||
extern u8 net_audio_buf[NET_AUDIO_BUF_SIZE] ;
|
||
|
||
__this_strm->video_buf_size = NET_VREC0_FBUF_SIZE;
|
||
__this_strm->video_buf = net_video_buf;
|
||
__this_strm->audio_buf_size = NET_AUDIO_BUF_SIZE;
|
||
__this_strm->audio_buf = net_audio_buf;
|
||
#else
|
||
__this_strm->video_buf_size = net_buf_size[id ? 1 : 0];
|
||
if (!__this_strm->video_buf) {
|
||
__this_strm->video_buf = malloc(__this_strm->video_buf_size);
|
||
if (!__this_strm->video_buf) {
|
||
printf("malloc fv_v0_buf err\n");
|
||
return -1;
|
||
}
|
||
}
|
||
__this_strm->audio_buf_size = NET_AUDIO_BUF_SIZE;
|
||
if (!__this_strm->audio_buf) {
|
||
__this_strm->audio_buf = malloc(__this_strm->audio_buf_size);
|
||
if (!__this_strm->audio_buf) {
|
||
printf("malloc fv_audio_buf err\n");
|
||
free(__this_strm->video_buf);
|
||
return -ENOMEM;
|
||
}
|
||
}
|
||
#endif
|
||
ret = fv_video_rec_start();
|
||
return ret;
|
||
}
|
||
|
||
static void strm_video_rec_server_event_handler(void *priv, int argc, int *argv)
|
||
{
|
||
/*
|
||
*该回调函数会在录像过程中,写卡出错被当前录像APP调用,例如录像过程中突然拔卡
|
||
*/
|
||
switch (argv[0]) {
|
||
case VIDEO_SERVER_PKG_NET_ERR:
|
||
fv_video_rec_close(1);
|
||
break;
|
||
default :
|
||
break;
|
||
}
|
||
}
|
||
static int fv_video_rec_start(void)
|
||
{
|
||
int err = 0;
|
||
char name[32] = {0};
|
||
union video_req req = {0};
|
||
struct video_text_osd text_osd;
|
||
u16 max_one_line_strnum;
|
||
u16 osd_line_num;
|
||
u8 id;
|
||
u8 ch;
|
||
|
||
__this_strm->fbuf_fcnt = 0;
|
||
__this_strm->fbuf_ffil = 0;
|
||
|
||
req.rec.width = s_info.width;
|
||
req.rec.height = s_info.height;
|
||
req.rec.IP_interval = 0;
|
||
req.rec.three_way_type = 0;
|
||
req.rec.camera_type = VIDEO_CAMERA_NORMAL;
|
||
ch = 1;
|
||
|
||
if (s_info.type == STRM_SOURCE_VIDEO0) {
|
||
printf("----ACTION_VIDEO0_OPEN_RT_STREAM-----\n\n");
|
||
puts("start_video_rec0 \n");
|
||
__this_strm->video_id = 0;
|
||
if (!__this_strm->video_rec0) {
|
||
sprintf(name, "video0.%d", 2);
|
||
__this_strm->video_rec0 = server_open("video_server", name);
|
||
if (!__this_strm->video_rec0) {
|
||
return -1;
|
||
}
|
||
server_register_event_handler(__this_strm->video_rec0, NULL, strm_video_rec_server_event_handler);
|
||
}
|
||
} else {
|
||
printf("err unknown video type !!!!!\n\n");
|
||
return -EINVAL;
|
||
}
|
||
|
||
__this_strm->width = req.rec.width;
|
||
__this_strm->height = req.rec.height;
|
||
|
||
#ifdef CONFIG_VIDEO_REC_PPBUF_MODE
|
||
req.rec.bfmode = VIDEO_PPBUF_MODE;
|
||
#endif
|
||
#ifdef CONFIG_VIDEO_SPEC_DOUBLE_REC_MODE
|
||
req.rec.wl80_spec_mode = VIDEO_WL80_SPEC_DOUBLE_REC_MODE;
|
||
#endif
|
||
#if STRM_USE_NET_VIDEO_BUFF
|
||
#define NET_ISC_SBUF_SIZE (CONFIG_VIDEO_IMAGE_W*32*3/2)/*720P内部ISC BUFF采用内部ram*/
|
||
extern u8 net_isc_sbuf[NET_ISC_SBUF_SIZE];
|
||
req.rec.isc_sbuf = net_isc_sbuf;
|
||
req.rec.sbuf_size = NET_ISC_SBUF_SIZE;
|
||
#endif
|
||
|
||
req.rec.state = VIDEO_STATE_START;
|
||
|
||
req.rec.format = STRM_VIDEO_FMT_AVI;
|
||
req.rec.channel = __this_strm->channel = ch;
|
||
req.rec.quality = VIDEO_LOW_Q;
|
||
req.rec.fps = 0;
|
||
req.rec.real_fps = strm_video_rec_get_fps();
|
||
req.rec.audio.sample_rate = s_info.sample_rate;
|
||
req.rec.audio.channel = 1;
|
||
req.rec.audio.volume = AUDIO_VOLUME;
|
||
req.rec.audio.buf = __this_strm->audio_buf;
|
||
req.rec.audio.buf_len = __this_strm->audio_buf_size;
|
||
req.rec.pkg_mute.aud_mute = !db_select("mic");
|
||
req.rec.abr_kbps = strm_video_rec_get_abr(req.rec.width);
|
||
req.rec.roi.roio_xy = (req.rec.height * 5 / 6 / 16) << 24 | (req.rec.height * 3 / 6 / 16) << 16 | (req.rec.width * 5 / 6 / 16) << 8 | (req.rec.width) * 1 / 6 / 16;
|
||
req.rec.roi.roio_ratio = 256 * 70 / 100 ;
|
||
req.rec.roi.roi1_xy = 0;
|
||
req.rec.roi.roi2_xy = 0;
|
||
req.rec.roi.roi3_xy = (1 << 24) | (0 << 16) | ((req.rec.width / 16) << 8) | 0;
|
||
req.rec.roi.roio_ratio1 = 0;
|
||
req.rec.roi.roio_ratio2 = 0;
|
||
req.rec.roi.roio_ratio3 = 256 * 80 / 100;
|
||
|
||
|
||
text_osd.font_w = OSD_DEFAULT_WIDTH;//必须16对齐
|
||
text_osd.font_h = OSD_DEFAULT_HEIGHT;//必须16对齐
|
||
|
||
#if 1
|
||
text_osd.text_format = NULL;//关闭OSD时间水印
|
||
#else
|
||
text_osd.text_format = (char *)net_osd_format_buf;
|
||
#endif
|
||
text_osd.x = (req.rec.width - text_osd.font_w * strlen(net_osd_format_buf) + 15) / 16 * 16;
|
||
text_osd.y = (req.rec.height - text_osd.font_h + 15) / 16 * 16;
|
||
text_osd.osd_yuv = 0xe20095;
|
||
|
||
text_osd.font_matrix_table = NULL;
|
||
text_osd.font_matrix_base = NULL;
|
||
text_osd.font_matrix_len = 0;
|
||
|
||
/* if (db_select("dat")) { */
|
||
/* req.rec.text_osd = &text_osd; */
|
||
/* } */
|
||
|
||
req.rec.slow_motion = 0;
|
||
#ifdef CONFIG_VIDEO1_ENABLE
|
||
req.rec.tlp_time = 0;
|
||
#endif
|
||
#ifdef CONFIG_VIDEO2_ENABLE
|
||
req.rec.tlp_time = 0;//db_select("gap");
|
||
#endif
|
||
|
||
if (req.rec.tlp_time && (req.rec.camera_type != VIDEO_CAMERA_UVC)) {
|
||
req.rec.real_fps = 1000 / req.rec.tlp_time;
|
||
|
||
}
|
||
if (req.rec.slow_motion || req.rec.tlp_time) {
|
||
req.rec.audio.sample_rate = 0;
|
||
req.rec.audio.channel = 0;
|
||
req.rec.audio.volume = 0;
|
||
req.rec.audio.buf = 0;
|
||
req.rec.audio.buf_len = 0;
|
||
}
|
||
|
||
req.rec.buf = __this_strm->video_buf;
|
||
req.rec.buf_len = __this_strm->video_buf_size;
|
||
req.rec.rec_small_pic = 0;
|
||
req.rec.cycle_time = 0;
|
||
|
||
if (s_info.type == STRM_SOURCE_VIDEO0) {
|
||
err = server_request(__this_strm->video_rec0, VIDEO_REQ_REC, &req);
|
||
}
|
||
if (err != 0) {
|
||
puts("\n\n\nstart rec2 err\n\n\n");
|
||
return -EINVAL;
|
||
}
|
||
__this_strm->state = NET_VIDREC_STA_START;
|
||
return 0;
|
||
}
|
||
|
||
static int fv_video_rec_stop(void)
|
||
{
|
||
union video_req req = {0};
|
||
int err;
|
||
|
||
req.rec.channel = __this_strm->channel; /* video0的sd卡录像为:channel0,所以这里不能在占用channel0 */
|
||
req.rec.state = VIDEO_STATE_STOP;
|
||
if (s_info.type == STRM_SOURCE_VIDEO0) {
|
||
if (__this_strm->video_rec0) {
|
||
printf("----ACTION_VIDEO0_CLOSE_RT_STREAM-----\n\n");
|
||
err = server_request(__this_strm->video_rec0, VIDEO_REQ_REC, &req);
|
||
if (err != 0) {
|
||
printf("ERR:stop video rec0 err 0x%x\n", err);
|
||
return -1;
|
||
}
|
||
}
|
||
}
|
||
__this_strm->fbuf_fcnt = 0;
|
||
__this_strm->fbuf_ffil = 0;
|
||
printf("fv_video_rec_stop ok \n");
|
||
return 0;
|
||
}
|
||
|
||
|
||
static int fv_video_rec_close(char close)
|
||
{
|
||
int err;
|
||
|
||
if (__this_strm->state != NET_VIDREC_STA_START) {
|
||
printf("err : __this_strm->state : %d \n", __this_strm->state);
|
||
return 0;
|
||
}
|
||
|
||
__this_strm->video_id = 0;
|
||
err = fv_video_rec_stop();
|
||
if (err) {
|
||
printf("fv_video_rec_stop err !!!\n");
|
||
return -1;
|
||
}
|
||
|
||
if (s_info.type == STRM_SOURCE_VIDEO0) {
|
||
if (__this_strm->video_rec0 && close && __this_strm->state == NET_VIDREC_STA_START) {
|
||
__this_strm->state = NET_VIDREC_STA_STARTING;
|
||
server_close(__this_strm->video_rec0);
|
||
__this_strm->video_rec0 = NULL;
|
||
}
|
||
}
|
||
#if !STRM_USE_NET_VIDEO_BUFF
|
||
//当不使用共用视频buf时,必须关闭
|
||
if (__this_strm->video_buf) {
|
||
free(__this_strm->video_buf);
|
||
__this_strm->video_buf = NULL;
|
||
}
|
||
if (__this_strm->audio_buf) {
|
||
free(__this_strm->audio_buf);
|
||
__this_strm->audio_buf = NULL;
|
||
}
|
||
#endif
|
||
|
||
__this_strm->state = NET_VIDREC_STA_STOP;
|
||
|
||
printf("stream_media close \n\n");
|
||
return 0;
|
||
}
|
||
void fenice_video_rec_open(void)
|
||
{
|
||
int ret;
|
||
|
||
ret = fv_video_rec_open();
|
||
if (ret) {
|
||
printf("fv_video_rec_open err!!!\n");
|
||
}
|
||
}
|
||
void fenice_video_rec_close(void)
|
||
{
|
||
int ret;
|
||
ret = fv_video_rec_close(1);
|
||
if (ret) {
|
||
printf("fv_video_rec_close err!!!\n");
|
||
}
|
||
//RTSP恢复默认
|
||
s_info.type = STRM_SOURCE_VIDEO0;//摄像头类型
|
||
s_info.width = 640;//分辨率
|
||
s_info.height = 480;
|
||
s_info.fps = STRM_VIDEO_REC_FPS0;//帧率
|
||
s_info.sample_rate = 0;//采样率,默认配置为0
|
||
s_info.channel_num = 1;//通道数
|
||
}
|
||
int strm_video_rec_open(void)//主要用于录像控制RTSP
|
||
{
|
||
int ret = 0;
|
||
if (__this_strm->is_open) {
|
||
ret = fv_video_rec_open();
|
||
}
|
||
return ret;
|
||
}
|
||
int strm_video_rec_close(u8 close)//主要用于录像控制RTSP
|
||
{
|
||
int ret = 0;
|
||
if (__this_strm->is_open) {
|
||
ret = fv_video_rec_close(close);
|
||
}
|
||
return ret;
|
||
}
|
||
/* 用于开启实时流时,stream_media_server回调 */
|
||
int fenice_video_rec_setup(void)
|
||
{
|
||
if (!__this_strm->is_open) {//注意:RTSP可能会多次调用open,务必加判断,防止多次open!
|
||
__this_strm->is_open = TRUE;
|
||
fenice_video_rec_open();
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* 用于实时流异常退出时,stream_media_server回调 */
|
||
int fenice_video_rec_exit(void)
|
||
{
|
||
if (__this_strm->is_open) {//注意:RTSP可能会多次调用close,务必加判断,防止多次close!
|
||
__this_strm->is_open = FALSE;
|
||
fenice_video_rec_close();
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
void *get_strm_video_rec_handler(void)
|
||
{
|
||
return (void *)&fv_rec_handler;
|
||
}
|
||
|
||
int fenice_set_media_info(struct fenice_source_info *info)
|
||
{
|
||
s_info.type = info->type == 0 ? STRM_SOURCE_VIDEO0 : STRM_SOURCE_VIDEO1;
|
||
s_info.width = info->width;
|
||
s_info.height = info->height;
|
||
__this_strm->width = s_info.width;
|
||
__this_strm->height = s_info.height;
|
||
printf("strm media info : %s , w : %d , h : %d \n"
|
||
, s_info.type == STRM_SOURCE_VIDEO1 ? "video1/2" : "video0"
|
||
, s_info.width
|
||
, s_info.height);
|
||
return 0;
|
||
}
|
||
|
||
int fenice_get_audio_info(struct fenice_source_info *info)
|
||
{
|
||
s_info.sample_rate = VIDEO_REC_AUDIO_SAMPLE_RATE;
|
||
info->width = s_info.width;
|
||
info->height = s_info.height;
|
||
info->fps = s_info.fps;
|
||
info->sample_rate = s_info.sample_rate;//rtsp选择打开,将采样率设置为8000
|
||
info->channel_num = s_info.channel_num;
|
||
printf("strm audio info : %d , %d\n", info->sample_rate, info->channel_num);
|
||
return 0;
|
||
}
|
||
|
||
int fenice_get_video_info(struct fenice_source_info *info)
|
||
{
|
||
__this_strm->width = s_info.width;
|
||
__this_strm->height = s_info.height;
|
||
info->width = s_info.width;
|
||
info->height = s_info.height;
|
||
info->fps = s_info.fps;
|
||
info->sample_rate = s_info.sample_rate;
|
||
info->channel_num = s_info.channel_num;
|
||
printf("strm video info : %d , %d\n", info->sample_rate, info->channel_num);
|
||
return 0;
|
||
}
|
||
|
||
|