欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

MP4V2实现TF卡录制MP4视频

程序员文章站 2022-07-01 09:40:41
...

     这里移植mp4v2实现mp4的录制,这里已经实现了海思平台3518和君正平台T30的mp4视频录制,总的来说就是交叉编译mp4v2源码,并移植其lib库实现在不同平台,用mp4v2的API将实时H264流封装成MP4视频文件。(前提你要了解海思,君正等相关soc获取实时h264流的流程)。 

1,关键实现MP4的录制代码如下:

(1)3518ev200海思平台

HI_S32 SAMPLE_COMM_VENC_MP4(VENC_STREAM_S *stStream)
{
	static int nRecordFlag = 0x00;
	static int recording = 0x1;
	static int spsflag = 0;
	static int ppsflag = 0;
	static MP4TrackId video = 0;
	static MP4FileHandle hMP4File = NULL;

	static char recordfish = 0x1;
	
	int j = 0;
	int len = 0;
	char *pData = NULL;
	char isSyncSample = 0;
	
	if(recordfish == 0x00){
		return 0;
	}

	if(hMP4File == NULL){
		hMP4File = MP4CreateEx("/usr/mmc/test.mp4",0, 1, 1, 0, 0, 0, 0);			//文件存储到TF挂载的路径
		if (hMP4File == MP4_INVALID_FILE_HANDLE)	{
			printf("open file fialed.\n");
			return -1;
		}
	
		MP4SetTimeScale(hMP4File, 90000);
	}
	
	if(recording && stStream->u32Seq > 30){			//丢弃前30帧,也可以不丢弃
		if(stStream->u32PackCount >= 3){			//从I帧开始编码,保证文件开始就能播放
			nRecordFlag = 1;
		}
	
		if(nRecordFlag){
			for(j = 0;j < stStream->u32PackCount;j++){
				len 	= stStream->pstPack[j].u32Len - stStream->pstPack[j].u32Offset;
				pData	= (stStream->pstPack[j].pu8Addr + stStream->pstPack[j].u32Offset);						
	
				if(stStream->pstPack[j].DataType.enH264EType == H264E_NALU_SPS){
					if(spsflag == 0x00){
						spsflag = 0x1;
						//写sps
						printf("Write sps =================\n");	
	
	
						video = MP4AddH264VideoTrack(hMP4File, 90000, 90000 / 30, 1280, 720,
																pData[4+1], //sps[1] AVCProfileIndication
																pData[4+2], //sps[2] profile_compat
																pData[4+3], //sps[3] AVCLevelIndication
																3); // 4 bytes length before each NAL unit
							MP4SetVideoProfileLevel(hMP4File, 0x7F);
							MP4AddH264SequenceParameterSet(hMP4File, video, pData+4, len-4);										
					}
					
					continue;
				}
				
				if(stStream->pstPack[j].DataType.enH264EType == H264E_NALU_PPS){
					if(ppsflag == 0x00){
						ppsflag = 0x1;
						//写pps										
						printf("Write pps -------------------\n");										
						MP4AddH264PictureParameterSet(hMP4File, video, pData+4, len-4);
					}
					
					continue;
				}
	
				isSyncSample = (stStream->pstPack[j].DataType.enH264EType == H264E_NALU_ISLICE)	?  (1) : (0);
				pData[0] = (len - 4) >> 24;
				pData[1] = (len - 4) >> 16;
				pData[2] = (len - 4) >> 8;
				pData[3] = len - 4; 							
	
				printf("Write date type = %d  isSyncSample = %d\n",stStream->pstPack[j].DataType.enH264EType,isSyncSample);								
	
				MP4WriteSample(hMP4File, video, pData, len , MP4_INVALID_DURATION, 0, isSyncSample);
	
				
			}					
		}
	}
	
	if((recording && stStream->u32Seq > 900)){		//控制文件时长
		recording = 0x00;
		printf("Close mp4 file\n");						
		MP4Close(hMP4File, 0);
		hMP4File = NULL;
		video = 0;
		recordfish = 0x00;
	}

}

(2)T30君正平台

static int save_stream(int fd, IMPEncoderStream *stream)
{
#if 0
	int ret, i, nr_pack = stream->packCount;

	for (i = 0; i < nr_pack; i++) {
		ret = write(fd, (void *)stream->pack[i].virAddr,
					stream->pack[i].length);
		if (ret != stream->pack[i].length) {
			IMP_LOG_ERR(TAG, "stream write ret(%d) != stream->pack[%d].length(%d) error:%s\n", ret, i, stream->pack[i].length, strerror(errno));
			return -1;
		}
	}
#endif 
	
	static int nRecordFlag = 0x00;
		static int recording = 0x1;
		static int spsflag = 0;
		static int ppsflag = 0;
		static MP4TrackId video = 0;
		static MP4FileHandle hMP4File = NULL;
	
		static char recordfish = 0x1;
		
		int j = 0;
		int len = 0;
		char *pData = NULL;
		char isSyncSample = 0;
		
		if(recordfish == 0x00){
			return 0;
		}
	
		if(hMP4File == NULL){
			hMP4File = MP4CreateEx("./test.mp4",0, 1, 1, 0, 0, 0, 0);			//文件存储到TF卡挂载的路径
			if (hMP4File == MP4_INVALID_FILE_HANDLE)	{
				printf("open file fialed.\n");
				return -1;
			}
		
			MP4SetTimeScale(hMP4File, 90000);
		}
		
		if(recording && stream->seq > 30){ 		//丢弃前30帧,也可以不丢弃
			if(stream->packCount >= 3){			//从I帧开始编码,保证文件开始就能播放
				nRecordFlag = 1;
			}
		
			if(nRecordFlag){
				for(j = 0;j < stream->packCount;j++){
					len 	= stream->pack[j].length;
					pData	= stream->pack[j].virAddr;						
		
					if(stream->pack[j].dataType.h264Type == IMP_H264_NAL_SPS){
						if(spsflag == 0x00){
							spsflag = 0x1;
							//写sps
							printf("Write sps =================\n");	
		
		
							video = MP4AddH264VideoTrack(hMP4File, 90000, 90000 / 30, 1280, 720,
																	pData[4+1], //sps[1] AVCProfileIndication
																	pData[4+2], //sps[2] profile_compat
																	pData[4+3], //sps[3] AVCLevelIndication
																	3); // 4 bytes length before each NAL unit
								MP4SetVideoProfileLevel(hMP4File, 0x7F);
								MP4AddH264SequenceParameterSet(hMP4File, video, pData+4, len-4);										
						}
						
						continue;
					}
					
					if(stream->pack[j].dataType.h264Type == IMP_H264_NAL_PPS){
						if(ppsflag == 0x00){
							ppsflag = 0x1;
							//写pps									
							printf("Write pps -------------------\n");										
							MP4AddH264PictureParameterSet(hMP4File, video, pData+4, len-4);
						}
						
						continue;
					}
		
					isSyncSample = (stream->pack[j].dataType.h264Type == IMP_H264_NAL_SLICE_IDR) ?  (1) : (0);//判断是否是I帧
					pData[0] = (len - 4) >> 24;
					pData[1] = (len - 4) >> 16;
					pData[2] = (len - 4) >> 8;
					pData[3] = len - 4; 							
		
					printf("Write date type = %d  isSyncSample = %d\n",stream->pack[j].dataType.h264Type,isSyncSample); 							
		
					MP4WriteSample(hMP4File, video, pData, len , MP4_INVALID_DURATION, 0, isSyncSample);
		
					
				}					
			}
		}
		
		if((recording && stream->seq > 1000)){		//控制文件时长
			recording = 0x00;
			printf("Close mp4 file\n"); 					
			MP4Close(hMP4File, 0);
			hMP4File = NULL;
			video = 0;
			recordfish = 0x00;
		}
	return 0;
	
}

2,这里给出君正平台下mp4v2的编译移植过程:https://blog.csdn.net/weixin_38251305/article/details/114985672

 

相关标签: RTSP