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
上一篇: 怒气冲冲是老师,笑忍不住是小明!
下一篇: 幽默校段儿,离不开学渣
推荐阅读