当前位置:网站首页>[Fuhan 6630 encodes and stores videos, and uses RTSP server and timestamp synchronization to realize VLC viewing videos]
[Fuhan 6630 encodes and stores videos, and uses RTSP server and timestamp synchronization to realize VLC viewing videos]
2022-07-03 02:46:00 【I&You】
Fuhan 6630 Encode and store video , use rtsp Server and timestamp synchronization vlc Watch the video
- Code logic mainly talks about several important functions
- Encoding threads _thread_venc_data( Save to the video file by frame )
- _dvr_handle_video_frame( Save to the video file by frame )
- read_stream( After the video file is saved )(vlc use url Request playback to start reading video file thread )
- write_stream( Add frame data to rtsp In line )
- RTSP Server logic has been mentioned in previous articles for reference
- Complete code download
Code logic mainly talks about several important functions
Encoding threads _thread_venc_data( Save to the video file by frame )
if(stStream.u32PackCount > 0)
{
s32Ret = FY_MPI_VENC_GetStream(i, &stStream, FY_TRUE);// Get a frame
}
if (FY_SUCCESS != s32Ret)
{
continue;
}
else
{
#if 1
if(i==4){
int len=0,off=0;
memset(&stVideoData, 0, sizeof(stVideoData));
stVideoData.buffer = malloc(200*1024);
// Unpack , Get valid stream data
for (k = 0; k < stStream.u32PackCount; k++)
{
len+=stStream.pstPack[k].u32Len-stStream.pstPack[k].u32Offset;
}
for (k = 0; k < stStream.u32PackCount; k++)
{
memcpy(stVideoData.buffer+off,stStream.pstPack[k].pu8Addr+stStream.pstPack[k].u32Offset,stStream.pstPack[k].u32Len-stStream.pstPack[k].u32Offset);
off+=stStream.pstPack[k].u32Len-stStream.pstPack[k].u32Offset;
}
stVideoData.len =len;
stVideoData.frametype = LXR_FRAME_TYPE_UNKNOWN; // It's useless
stVideoData.timestamp = stStream.pstPack[0].u64PTS*1000; // It's useless , The upper layer gets the assignment again
if(i < s32ChnTotal/2)
streamID = 0; //main stream
else
streamID = 1; //sub stream
conn = i%(s32ChnTotal/2); //conn, Channel number
_dvr_handle_video_frame(conn,streamID,&stVideoData, LXR_VIDEO_TYPE_H264);
}
_dvr_handle_video_frame( Save to the video file by frame )
void _dvr_handle_video_frame(int ch, int streamid, LXRFrame_t* m_frame, LXR_VIDEO_TYPE_E encType)
{
LXRFrame_t frame;
memcpy(&frame, m_frame, sizeof(LXRFrame_t));
// Analytic width and height
//JBOOL bIFrame = JFALSE; // whether I frame
FY_BOOL bNeedCmpareWH = FY_FALSE; // It needs to be wide and high
int frameW = 0, frameH = 0;
LXR_VIDEO_TYPE_E vencType = LXR_VIDEO_TYPE_H264;
unsigned long long timeStap =arch_getSystemStartupMs(); // Must be time stamped , Otherwise, it cannot be played back
frame.timestamp = timeStap;
if(encType == LXR_VIDEO_TYPE_H264)
{
vencType = LXR_VIDEO_TYPE_H264;
unsigned int NaluType = frame.buffer[4]&0x1f;
if((NaluType == 7) || (NaluType == 8) || (NaluType == 5))// Judge whether it is i frame
{
//bIFrame = JTRUE;
frame.frametype = LXR_FRAME_TYPE_I;
}
if(NaluType == 7)
{
// Test execution time .(3535)
// belt __compare_sps: 2us
// No : 7us
//struct timeval tmBegin,tmNow;
//gettimeofday(&tmBegin, 0);
// Check sps Do you need to parse
// analysis sps
#if 0
sps_data_t sps;
h264_parse_sps(frame.buffer+5, frame.len-5, &sps);
frameW = sps.width;
frameH = sps.height;
bNeedCmpareWH = FY_TRUE;
#endif
}
}
static FILE * fp=NULL;
static unsigned char first_iframe = 0;
if(fp==NULL){
fp = fopen("/mnt/h264_stream/lxr_test_record5.h264", "w");
}
if(fp == NULL){
perror("open_recordfile_fail");
}
if(!first_iframe&&frame.frametype==LXR_FRAME_TYPE_I){
first_iframe =1;
}
if(first_iframe){
// The first frame needs to be saved with keys , otherwise vlc It won't play
unsigned char sendBuf[200*1024];
unsigned char *p = (unsigned char*)sendBuf;
int size1,size2,size3,ret;
StramFrame_t grpc_frame={
0};// The frame structure saved to the video file
// assignment
grpc_frame.buffer=frame.buffer;
grpc_frame.ch=ch;
grpc_frame.frametype = frame.frametype;
grpc_frame.len=frame.len;
grpc_frame.stream_id = streamid;
grpc_frame.timestamp = frame.timestamp;
// Copy the data
size1 = sizeof(StramFrame_t);
size2 = grpc_frame.len;
size3 = size1+size2;
*((unsigned int*)p) = size1 + size2 ;
memcpy(p+sizeof(unsigned int), &grpc_frame, size1);
memcpy(p+sizeof(unsigned int)+size1, grpc_frame.buffer, size2);
if(size3>61440){
// Write once 60k, Write several times , You can define a write by yourself 64k Can also be
int i=0;
while(size3>61440){
ret =fwrite(p+i,61440,1,fp);
i+=61440;
size3-=61440;
}
ret =fwrite(p+i,size3,1,fp);
}else{
ret =fwrite(p,sizeof(unsigned int)+size1+size2,1,fp);
}
}
free(frame.buffer);
}
read_stream( After the video file is saved )(vlc use url Request playback to start reading video file thread )
void read_stream(void *arg){
int fd=0,ret;
unsigned char recBuf_init[200*1024];
unsigned char * recBuf=(unsigned char *)recBuf_init;
if(fd==0){
fd = open("/mnt/h264_stream/lxr_test_record5.h264", O_RDONLY);
}
if(fd <0 ){
perror("open_recordfile_fail");
}
while(1)
{
ret = read(fd,recBuf,61440);
if(ret==0){
// Leave after reading
return;
}
unsigned int lenTotal = *((unsigned int*)recBuf)+PACKET_HEAD;
if(ret>lenTotal){
// get entangled with sb.
unsigned int readlen=lenTotal,total=ret;
// Write data
write_stream(recBuf,lenTotal,fd);
unsigned char * recBuf_offset = recBuf;
while (readlen<ret)// Judge whether the unpacking is completed
{
// Offset to the first address of the next packet
recBuf_offset+=lenTotal;
lenTotal = *((unsigned int*)recBuf_offset)+PACKET_HEAD;
// Judge whether it is I Frame subcontracting
if(i_frame_flag(recBuf_offset)){
unsigned int iframe_read=ret-readlen;
while (iframe_read<lenTotal)// Note the package does not contain complete I The frame needs to get the packet
{
ret = read(fd,recBuf_offset+iframe_read,lenTotal-iframe_read);
iframe_read+=ret;
}
write_stream(recBuf_offset,lenTotal,fd);
readlen+=lenTotal;
}else{
//P Packet frame
if((readlen+lenTotal)>ret){
int tmps=lenTotal-(ret-readlen);// Used to store temporary variables
ret = read(fd,recBuf_offset+ret-readlen,tmps);
readlen = tmps;
write_stream(recBuf_offset,lenTotal,fd);
}else{
write_stream(recBuf_offset,lenTotal,fd);
readlen+=lenTotal;
}
}
}
}
else if(i_frame_flag(recBuf)){
// Judge whether it is i Packet frame
unsigned int iframe_read=ret;
while(iframe_read<lenTotal){
//I Frame subcontracting sending
ret = read(fd,recBuf+iframe_read,61440);
iframe_read+=ret;
}
if(lenTotal!=iframe_read){
// Sticky package appears
unsigned int not_readlen = iframe_read-lenTotal;
unsigned int readlen=0;
unsigned char * recBuf_offset=recBuf;
write_stream(recBuf,lenTotal,fd);// First complete I Frame write
while (not_readlen!=readlen)
{
// Offset to next P The first address of the frame
recBuf_offset+=lenTotal;
lenTotal = *((unsigned int*)recBuf_offset)+4;
write_stream(recBuf_offset,lenTotal,fd);
readlen+=lenTotal;
}
}else if(lenTotal==iframe_read){
// Single bag i frame
write_stream(recBuf,lenTotal,fd);
}
}else{
//P Packet frame
write_stream(recBuf,lenTotal,fd);
}
}
}
write_stream( Add frame data to rtsp In line )
void write_stream(unsigned char *recBuf,unsigned int lenTotal,int fd){
// Remove the head
unsigned char *head=(unsigned char *)recBuf+4;
StramFrame_t * recFrm=(StramFrame_t *)head;
if(recFrm)
{
recFrm->buffer = (unsigned char*)recFrm + sizeof(StramFrame_t);
if(lenTotal-4 != recFrm->len + sizeof(StramFrame_t))
{
printf("bad length:chn=%d,lenTotal=%d,frmLen=%d\n", recFrm->ch, lenTotal, recFrm->len);
}
}
// Compare timestamps
FY_BOOL bSendPlay = FY_FALSE; // Do you want to play
static RemoteSync_t syncFrame={
0};
static unsigned char first_comehere=1;
if(first_comehere)
{
first_comehere = 0;
// Synchronization has not been established . Be sure to play
bSendPlay = FY_TRUE;
syncFrame.iFrame = recFrm->frametype;
syncFrame.tsFrame = recFrm->timestamp;
syncFrame.tsPlay = arch_getSystemStartupMs();
//player->tsCurPlay = player->syncFrame.tsPlay;
}
else
{
// Synchronization has been established
// The playback time difference is greater than Frame time difference Just play
unsigned long long tsNow;
do
{
tsNow = arch_getSystemStartupMs();
} while ((tsNow - syncFrame.tsPlay)*1 < recFrm->timestamp - syncFrame.tsFrame);
bSendPlay = FY_TRUE;
}
if(n_1<NMAX&&bSendPlay==FY_TRUE)
{
memcpy(ringfifo_1[iput_1].buffer,recFrm->buffer,recFrm->len);
ringfifo_1[iput_1].size= recFrm->len;
if(recFrm->frametype==LXR_FRAME_TYPE_I)
{
ringfifo_1[iput_1].frame_type = FRAME_TYPE_I;
}
else
ringfifo_1[iput_1].frame_type = FRAME_TYPE_P;
iput_1 = addring(iput_1);
n_1++;
}
}
RTSP Server logic has been mentioned in previous articles for reference
Complete code download
边栏推荐
- SqlServer行转列PIVOT
- SQL Server Query spécifie la structure de la table
- HW initial preparation
- random shuffle注意
- Deep Reinforcement Learning for Intelligent Transportation Systems: A Survey 论文阅读笔记
- Random Shuffle attention
- [principles of multithreading and high concurrency: 1_cpu multi-level cache model]
- What does it mean when lambda is not entered?
- Super easy to use logzero
- Gbase 8C system table PG_ am
猜你喜欢
【Flutter】shared_ Preferences local storage (introduction | install the shared_preferences plug-in | use the shared_preferences process)
Practice of traffic recording and playback in vivo
MATLAB小技巧(24)RBF,GRNN,PNN-神经网络
Deep Reinforcement Learning for Intelligent Transportation Systems: A Survey 论文阅读笔记
SQL statement
What does "where 1=1" mean
HW initial preparation
超好用的日志库 logzero
Pytest (6) -fixture (Firmware)
How to change the panet layer in yolov5 to bifpn
随机推荐
基于can总线的A2L文件解析(2)
[advanced ROS] Lesson 6 recording and playback in ROS (rosbag)
sql server 查詢指定錶的錶結構
C语言初阶-指针详解-庖丁解牛篇
SQL statement
Kubernetes family container housekeeper pod online Q & A?
The Linux server needs to install the agent software EPS (agent) database
Tensorflow to pytorch notes; tf. gather_ Nd (x, y) to pytorch
Simple understanding of SVG
[translation] modern application load balancing with centralized control plane
HTB-Devel
为什么会选择框架?选择什么样的框架
Gbase 8C system table PG_ database
[shutter] banner carousel component (shutter_wiper plug-in | swiper component)
SqlServer行转列PIVOT
Global and Chinese ammonium dimolybdate market in-depth analysis and prospect risk prediction report 2022 Edition
Check log4j problems using stain analysis
JMeter performance test JDBC request (query database to obtain database data) use "suggestions collection"
How to change the panet layer in yolov5 to bifpn
As a leader, how to control the code version and demand development when the epidemic comes| Community essay solicitation