|
|
/**************************************************
|
|
|
*
|
|
|
* 文件名:VideoMgmt.c
|
|
|
* 视频流模块
|
|
|
* 版本:V1.0
|
|
|
* 作用:
|
|
|
* 在视频流完成处理之后
|
|
|
* 1、将视频流数据发送到视频流推送模块
|
|
|
* 2、将视频流数据发送到视频流录制块
|
|
|
* 3、将视频流数据发送到视频流拍照模块
|
|
|
*
|
|
|
* **********************************************************/
|
|
|
#include <stdio.h>
|
|
|
#include <string.h>
|
|
|
#include <stdlib.h>
|
...
|
...
|
@@ -19,241 +31,26 @@ |
|
|
|
|
|
//额外头文件声明
|
|
|
|
|
|
|
|
|
#define DATA_SEND_FROM_VIDEO_STREAM_MAX_LEN 60000
|
|
|
#define VIDEO_FRAME_AUD_LEN 6
|
|
|
|
|
|
static const unsigned char s_frameAudInfo[VIDEO_FRAME_AUD_LEN] = {0x00, 0x00, 0x00, 0x01, 0x09, 0x10};
|
|
|
|
|
|
JZ_VideoStreamUseStatus g_VideoStreamDealStatus = VIDEO_STREAM_IDLE; //视频流的处理状态
|
|
|
|
|
|
/*视频流缓冲区地址说明
|
|
|
留有三对缓冲区,一队中的数据分别为成型数据,以及原始数据
|
|
|
|
|
|
如果设备只有一个摄像头,则使用一号视频流
|
|
|
|
|
|
如果设备为 红外+光学 则红外为1号,光学为2号
|
|
|
|
|
|
*/
|
|
|
void *VideoMgmt_FirstVideo_index = NULL; //一号视频流的缓冲地址
|
|
|
void *VideoMgmt_SecondVideo_index = NULL; //二号视频流的缓冲地址
|
|
|
void *VideoMgmt_ThirdVideo_index = NULL; //三号视频流的缓冲地址
|
|
|
|
|
|
void *VideoMgmt_FirstRaw_index = NULL; //一号原始流的缓冲地址
|
|
|
void *VideoMgmt_SecondRaw_index = NULL; //二号原始流的缓冲地址
|
|
|
void *VideoMgmt_ThirdRaw_index = NULL; //三号原始流的缓冲地址
|
|
|
|
|
|
static int VideoFreezeFlag = JZ_FLAGCODE_OFF; //视频流冻结功能
|
|
|
|
|
|
//视频流缓冲区结构
|
|
|
typedef struct JZsdk_VideoBuffer{
|
|
|
unsigned char *data; //缓冲区数据
|
|
|
unsigned int data_len;
|
|
|
int is_ready; // 标志位,表示数据是否准备好被读取
|
|
|
pthread_mutex_t lock; // 互斥锁,用于线程同步
|
|
|
pthread_cond_t cond; // 条件变量,用于通知读取线程数据已准备好
|
|
|
} JZsdk_VideoBuffer;
|
|
|
|
|
|
// 初始化缓冲区
|
|
|
T_JZsdkReturnCode VideoMgmt_init_buffer(void **index)
|
|
|
{
|
|
|
//从索引值获取对应的缓冲区
|
|
|
//创建一个缓冲区
|
|
|
struct JZsdk_VideoBuffer *VideoBuffer = NULL;
|
|
|
|
|
|
//为编码器参数注册内存
|
|
|
VideoBuffer = (struct JZsdk_VideoBuffer *)malloc(sizeof(struct JZsdk_VideoBuffer));
|
|
|
if (VideoBuffer == NULL) {
|
|
|
JZSDK_LOG_ERROR("视频流缓冲区注册失败");
|
|
|
return JZ_ERROR_SYSTEM_MODULE_CODE_INVALID_PARAMETER;
|
|
|
}
|
|
|
|
|
|
VideoBuffer->data = NULL;
|
|
|
VideoBuffer->data_len = 0;
|
|
|
VideoBuffer->is_ready = 0;
|
|
|
pthread_mutex_init(&VideoBuffer->lock, NULL);
|
|
|
pthread_cond_init(&VideoBuffer->cond, NULL);
|
|
|
|
|
|
if (*index != NULL)
|
|
|
{
|
|
|
free(*index);
|
|
|
}
|
|
|
|
|
|
*index = (void *)VideoBuffer;
|
|
|
|
|
|
return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
|
|
|
}
|
|
|
|
|
|
//缓冲区清理
|
|
|
T_JZsdkReturnCode VideoMgmt_VideoBuffer_Deinit(void **index)
|
|
|
{
|
|
|
if (index == NULL || *index == NULL) {
|
|
|
// 如果索引或缓冲区指针为空,则直接返回
|
|
|
return JZ_ERROR_SYSTEM_MODULE_CODE_INVALID_PARAMETER;
|
|
|
}
|
|
|
|
|
|
//从索引值获取对应的缓冲区
|
|
|
struct JZsdk_VideoBuffer *VideoBuffer = (struct JZsdk_VideoBuffer *)*index;
|
|
|
|
|
|
if (VideoBuffer->data != NULL)
|
|
|
{
|
|
|
free(VideoBuffer->data);
|
|
|
VideoBuffer->data = NULL;
|
|
|
}
|
|
|
|
|
|
VideoBuffer->data_len = 0;
|
|
|
VideoBuffer->is_ready = 0;
|
|
|
pthread_mutex_destroy(&VideoBuffer->lock);
|
|
|
pthread_cond_destroy(&VideoBuffer->cond);
|
|
|
|
|
|
free(VideoBuffer);
|
|
|
index = NULL; // 防止悬挂指针
|
|
|
|
|
|
return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
|
|
|
}
|
|
|
|
|
|
//缓冲区写入
|
|
|
T_JZsdkReturnCode VideoMgmt_write_data(void **index, unsigned char *data, unsigned int data_len)
|
|
|
{
|
|
|
//从索引值获取对应的缓冲区
|
|
|
struct JZsdk_VideoBuffer *VideoBuffer = (struct JZsdk_VideoBuffer *)*index;
|
|
|
|
|
|
pthread_mutex_lock(&VideoBuffer->lock);
|
|
|
|
|
|
// 释放旧数据
|
|
|
if (VideoBuffer->data)
|
|
|
{
|
|
|
free(VideoBuffer->data);
|
|
|
VideoBuffer->data = NULL;
|
|
|
}
|
|
|
|
|
|
// 分配新内存并复制数据
|
|
|
VideoBuffer->data = (unsigned char *)malloc(data_len);
|
|
|
memcpy(VideoBuffer->data, data, data_len);
|
|
|
VideoBuffer->data_len = data_len;
|
|
|
VideoBuffer->is_ready = 1; // 标记数据已准备好
|
|
|
|
|
|
// 通知读取线程数据已准备好
|
|
|
pthread_cond_signal(&VideoBuffer->cond);
|
|
|
|
|
|
pthread_mutex_unlock(&VideoBuffer->lock);
|
|
|
}
|
|
|
|
|
|
//缓冲区读取
|
|
|
//输入的参数,缓冲区索引地址 回复的数据地址 回复的数据长度 帧头帧尾模式 帧头帧尾长度
|
|
|
T_JZsdkReturnCode VideoMgmt_read_data(void **index, unsigned char **data, unsigned int *data_len, unsigned int mode, unsigned int extra_len)
|
|
|
{
|
|
|
//从索引值获取对应的缓冲区
|
|
|
struct JZsdk_VideoBuffer *VideoBuffer = (struct JZsdk_VideoBuffer *)*index;
|
|
|
|
|
|
// 检查缓冲区指针是否有效
|
|
|
if (VideoBuffer == NULL)
|
|
|
{
|
|
|
return JZ_ERROR_SYSTEM_MODULE_CODE_INVALID_PARAMETER; // 假设的错误码,表示参数无效
|
|
|
}
|
|
|
|
|
|
pthread_mutex_lock(&VideoBuffer->lock);
|
|
|
|
|
|
// 等待数据准备好
|
|
|
while (!VideoBuffer->is_ready)
|
|
|
{
|
|
|
pthread_cond_wait(&VideoBuffer->cond, &VideoBuffer->lock);
|
|
|
}
|
|
|
|
|
|
// 检查数据指针是否有效
|
|
|
if (VideoBuffer->data == NULL)
|
|
|
{
|
|
|
pthread_mutex_unlock(&VideoBuffer->lock);
|
|
|
return JZ_ERROR_SYSTEM_MODULE_CODE_INVALID_PARAMETER; // 假设的错误码,表示没有数据可供读取
|
|
|
}
|
|
|
|
|
|
// 返回数据和长度
|
|
|
*data_len = VideoBuffer->data_len;
|
|
|
if (mode == JZ_FLAGCODE_OFF)
|
|
|
{
|
|
|
*data = (unsigned char *)malloc(*data_len);
|
|
|
memcpy(*data, VideoBuffer->data, *data_len);
|
|
|
}
|
|
|
else if (mode == VIDEOMGMT_USE_FRAMEHEAD)
|
|
|
{
|
|
|
*data = (unsigned char *)malloc(*data_len + extra_len);
|
|
|
memcpy(*data+extra_len, VideoBuffer->data, VideoBuffer->data_len);
|
|
|
}
|
|
|
else if (mode == VIDEOMGMT_USE_FRAMEEND)
|
|
|
{
|
|
|
*data = (unsigned char *)malloc(*data_len + extra_len);
|
|
|
memcpy(*data, VideoBuffer->data, VideoBuffer->data_len);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
*data = (unsigned char *)malloc(*data_len);
|
|
|
memcpy(*data, VideoBuffer->data, *data_len);
|
|
|
}
|
|
|
|
|
|
VideoBuffer->is_ready = 0;
|
|
|
pthread_mutex_unlock(&VideoBuffer->lock);
|
|
|
|
|
|
return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
|
|
|
}
|
|
|
|
|
|
/**********
|
|
|
/****************************
|
|
|
*
|
|
|
* 直接返回地址略有风险,暂时不考虑使用这个以下注释的方法
|
|
|
* videoMgmt的初始化
|
|
|
*
|
|
|
*
|
|
|
* ************/
|
|
|
// //缓冲区读取
|
|
|
// T_JZsdkReturnCode VideoMgmt_read_data(void **index, unsigned char **data, unsigned int *data_len)
|
|
|
// {
|
|
|
// //从索引值获取对应的缓冲区
|
|
|
// struct JZsdk_VideoBuffer *VideoBuffer = (struct JZsdk_VideoBuffer *)*index;
|
|
|
|
|
|
// // 检查缓冲区指针是否有效
|
|
|
// if (VideoBuffer == NULL)
|
|
|
// {
|
|
|
// return JZ_ERROR_SYSTEM_MODULE_CODE_INVALID_PARAMETER; // 假设的错误码,表示参数无效
|
|
|
// }
|
|
|
|
|
|
// pthread_mutex_lock(&VideoBuffer->lock);
|
|
|
|
|
|
// // 等待数据准备好
|
|
|
// while (!VideoBuffer->is_ready)
|
|
|
// {
|
|
|
// pthread_cond_wait(&VideoBuffer->cond, &VideoBuffer->lock);
|
|
|
// }
|
|
|
|
|
|
// // 检查数据指针是否有效
|
|
|
// if (VideoBuffer->data == NULL)
|
|
|
// {
|
|
|
// pthread_mutex_unlock(&VideoBuffer->lock);
|
|
|
// return JZ_ERROR_SYSTEM_MODULE_CODE_INVALID_PARAMETER; // 假设的错误码,表示没有数据可供读取
|
|
|
// }
|
|
|
|
|
|
// // 返回数据和长度
|
|
|
// *data = (VideoBuffer->data);
|
|
|
// *data_len = VideoBuffer->data_len;
|
|
|
|
|
|
// return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
|
|
|
// }
|
|
|
|
|
|
// //回复已经读取完成,在read函数,且数据处理完成后调用
|
|
|
// T_JZsdkReturnCode VideoMgmt_ReplyRead(void **index)
|
|
|
// {
|
|
|
// //从索引值获取对应的缓冲区
|
|
|
// struct JZsdk_VideoBuffer *VideoBuffer = (struct JZsdk_VideoBuffer *)*index;
|
|
|
|
|
|
// // 检查缓冲区指针是否有效
|
|
|
// if (VideoBuffer == NULL)
|
|
|
// {
|
|
|
// return JZ_ERROR_SYSTEM_MODULE_CODE_INVALID_PARAMETER; // 假设的错误码,表示参数无效
|
|
|
// }
|
|
|
|
|
|
// VideoBuffer->is_ready = 0;
|
|
|
// pthread_mutex_unlock(&VideoBuffer->lock);
|
|
|
|
|
|
// return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
|
|
|
// }
|
|
|
|
|
|
|
|
|
*
|
|
|
* **************************/
|
|
|
T_JZsdkReturnCode VideoMgmt_Init()
|
|
|
{
|
|
|
//1
|
|
|
VideoMgmt_VideoStreamFlow_Init(int FrameNumber, void **index, int VideoStreamFlowIndex);
|
|
|
}
|
|
|
|
|
|
/*********************************************************************************************************************************************
|
|
|
*
|
...
|
...
|
@@ -375,10 +172,10 @@ T_JZsdkReturnCode VideoStramPhoto_DevelopH264FlowGenerateIDR() |
|
|
/**************
|
|
|
*
|
|
|
* 视频流流转的线程
|
|
|
*
|
|
|
* 视频流处理完成后,可以通过此函数完成拍照记录 录像记录 以及推送
|
|
|
*
|
|
|
* ************/
|
|
|
static T_JZsdkReturnCode VideoStreamToDeal(unsigned char *data, unsigned int data_len)
|
|
|
T_JZsdkReturnCode VideoMgmt_VideoStreamToDeal(unsigned char *data, unsigned int data_len)
|
|
|
{
|
|
|
//拍照数据
|
|
|
VideoStramPhoto_PhotoDataIn(data, data_len);
|
...
|
...
|
@@ -394,6 +191,16 @@ static T_JZsdkReturnCode VideoStreamToDeal(unsigned char *data, unsigned int dat |
|
|
//JZSDK_LOG_INFO("推送一帧%d,数据大小%d\n",VideoPush->VideoStreamFlowIndex,data_len);
|
|
|
}
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
*
|
|
|
* 多线程下的处理
|
|
|
*
|
|
|
*
|
|
|
*
|
|
|
* ***********************************************************/
|
|
|
|
|
|
|
|
|
static void *VideoMgmt_VideoStreamFlow_Thread(void *args)
|
|
|
{
|
|
|
struct VideoMgmt_VideoStreamFlow *VideoPush = (struct VideoMgmt_VideoStreamFlow *)args;
|
...
|
...
|
@@ -442,13 +249,15 @@ static void *VideoMgmt_VideoStreamFlow_Thread(void *args) |
|
|
}
|
|
|
}
|
|
|
|
|
|
//冻结开了就推送冻结画面
|
|
|
if (VideoFreezeFlag == JZ_FLAGCODE_ON && FreezeDataLen != 0)
|
|
|
{
|
|
|
VideoStreamToDeal(FreezeData, FreezeDataLen);
|
|
|
VideoMgmt_VideoStreamToDeal(FreezeData, FreezeDataLen);
|
|
|
}
|
|
|
//否则推送正常画面
|
|
|
else
|
|
|
{
|
|
|
VideoStreamToDeal(data, data_len);
|
|
|
VideoMgmt_VideoStreamToDeal(data, data_len);
|
|
|
}
|
|
|
|
|
|
// 释放数据(如果有必要的话)
|
...
|
...
|
@@ -472,6 +281,7 @@ static void *VideoMgmt_VideoStreamFlow_Thread(void *args) |
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
|
|
|
//视频流流转模块的初始化
|
|
|
T_JZsdkReturnCode VideoMgmt_VideoStreamFlow_Init(int FrameNumber, void **index, int VideoStreamFlowIndex)
|
|
|
{
|
...
|
...
|
|