53
- 收藏
- 点赞
- 分享
- 举报
求助!hi3518dv500使用ffmpeg封装音视频为mp4格式中间的时间戳计算问题
使用ffmpeg封装海思的音视频,想法是调海思的函数,在venc里面拿到视频流,在音频的aenc里拿到aac音频,目前已经封装出了mp4文件,但是由于小弟第一次做这块领域,不明白海思的时间戳如何计算,如何能保证音视频同步,现在我封装出来mp4里面音频是要比视频慢一些。而且视频有点卡顿,不知道有没有大佬知道海思时间戳要如何计算呢。
下面附上计算代码
td_s32 nd_HI_PDT_WriteVideo(ot_venc_chn VeChn, ot_venc_stream *pstStream, nd_FfmpegConf *fc)
{
unsigned int i = 0;
unsigned char *pPackVirtAddr = NULL; // 码流首地址
unsigned int u32PackLen = 0; // 码流长度
int ret = 0;
AVStream *Vpst = NULL; // 视频流指针
AVPacket pkt; // 音视频包结构体,这个包不是海思的包,填充之后,用于最终写入数据
uint8_t sps_buf[32];
uint8_t pps_buf[32];
uint8_t sps_pps_buf[64];
td_s32 small_increment = 1;
unsigned int pps_len = 0;
unsigned int sps_len = 0;
if (NULL == pstStream) // 裸码流有效判断
{
return TD_SUCCESS;
}
// u32PackCount是海思中记录此码流结构体中码流包数量,一般含I帧的是4个包,P帧1个
for (i = 0; i < pstStream->pack_cnt; i++)
{
// 从海思码流包中获取数据地址,长度
pPackVirtAddr = pstStream->pack[i].addr + pstStream->pack[i].offset;
u32PackLen = pstStream->pack[i].len - pstStream->pack[i].offset;
// 最重要的数据要给AVpack包
av_init_packet(&pkt); // 初始化AVpack包
pkt.flags = AV_PKT_FLAG_KEY; // 默认是关键帧,关不关键好像都没问题
switch (pstStream->pack[i].data_type.h264_type)
{
case OT_VENC_H264_NALU_SPS: // 如果这个包是SPS
pkt.flags = 0; // 不是关键帧
if (fc->b_First_IDR_Find[VeChn] == 2) // 如果不是第一个SPS帧
{
continue; // 不处理,丢弃
// 我只要新建文件之后的第一个SPS PPS信息,后面都是一样的,只要第一个即可
}
else // 如果是第一个SPS帧
{
sps_len = u32PackLen;
memcpy(sps_buf, pPackVirtAddr, sps_len);
if (fc->b_First_IDR_Find[VeChn] == 1) // 如果PPS帧已经收到
{
memcpy(sps_pps_buf, sps_buf, sps_len); // 复制sps
memcpy(sps_pps_buf + sps_len, pps_buf, pps_len); // 加上pps
// 去添加视频流,和SPS PPS信息,这步之后才开始写入视频帧
ret = nd_HI_ADD_SPS_PPS(VeChn, sps_pps_buf, sps_len + pps_len, fc);
if (ret < 0)
return TD_FAILURE;
}
fc->b_First_IDR_Find[VeChn]++;
}
continue; // 继续
case OT_VENC_H264_NALU_PPS:
pkt.flags = 0; // 不是关键帧
if (fc->b_First_IDR_Find[VeChn] == 2) // 如果不是第一个PPS帧
{
continue;
}
else // 是第一个PPS帧
{
pps_len = u32PackLen;
memcpy(pps_buf, pPackVirtAddr, pps_len); // 复制
if (fc->b_First_IDR_Find[VeChn] == 1) // 如果SPS帧已经收到
{
memcpy(sps_pps_buf, sps_buf, sps_len);
memcpy(sps_pps_buf + sps_len, pps_buf, pps_len);
// 这里和SPS那里互斥,只有一个会执行,主要是看SPS和PPS包谁排在后面
ret = nd_HI_ADD_SPS_PPS(VeChn, sps_pps_buf, sps_len + pps_len, fc);
if (ret < 0)
return TD_FAILURE;
}
fc->b_First_IDR_Find[VeChn]++;
}
continue;
case OT_VENC_H264_NALU_SEI: // 增强帧,不含图像数据信息,只是对图像数据信息和视频流的补充
continue; // 不稀罕这个帧
case OT_VENC_H264_NALU_P_SLICE: // P帧
case OT_VENC_H264_NALU_I_SLICE: // I帧
if (fc->b_First_IDR_Find[VeChn] != 2) // 如果这个文件还没有收到过sps和pps帧
{
continue; // 跳过,不处理这帧
}
break;
default:
break;
}
if (fc->vi[VeChn] < 0) // 流索引号,如果g_OutFmt_Ctx里面还没有新建视频流,也就是说还没收到I帧
{
printf("vi less than 0 \n");
return TD_SUCCESS;
}
if (fc->Vfirst[VeChn] == 0)
{
fc->Vfirst[VeChn] = 1;
// fc->Video_PTS[VeChn] = pstStream->seq; // 记录初始序号
fc->Video_PTS[VeChn] = pstStream->pack[i].pts;
// printf("Computed pstStream->seq: %lld\n", pstStream->seq);
}
Vpst = fc->g_OutFmt_Ctx[VeChn]->streams[fc->vi[VeChn]];
pkt.stream_index = Vpst->index;
pkt.data = pPackVirtAddr;
pkt.size = u32PackLen;
// pkt.pts = av_rescale_q_rnd(pstStream->pack[i].pts - fc->Video_PTS[VeChn], (AVRational){1, STREAM_FRAME_RATE}, Vpst->time_base, (enum AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
pkt.pts = av_rescale_q_rnd(fc->Video_PTS[VeChn]++, (AVRational){1, STREAM_FRAME_RATE}, Vpst->time_base, (enum AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
pkt.dts = pkt.pts; // 只有I、P帧,相等就行了
pkt.duration = av_rescale_q(40, Vpst->time_base, Vpst->time_base);
pkt.pos = -1;
// printf("Computed SEQ: %lld\n", pstStream->seq);
// printf("Computed pstStream->seq - fc->Video_PTS[VeChn]: %lld\n", pstStream->seq - fc->Video_PTS[VeChn]);
ret = av_interleaved_write_frame(fc->g_OutFmt_Ctx[VeChn], &pkt);
if (ret < 0)
{
printf("cannot write video frame\n");
return TD_FAILURE;
}
printf(" write video frame\n");
}
return TD_SUCCESS;
}
td_s32 nd_HI_PDT_WriteAudio(ot_aenc_chn AeChn, ot_audio_stream *pstStream, nd_FfmpegConf *fc)
{
unsigned char *pPackVirtAddr = NULL; // 码流数据首地址
unsigned int u32PackLen = 0; // 码流数据长度
int ret = 0;
AVStream *Apst = NULL; // 用于指向音频流
AVPacket pkt; // 定义一个包
pkt.data = NULL;
if (NULL == pstStream)
{
return TD_SUCCESS;
}
if (fc->ai[AeChn] < 0)
{ // 如果文件里面没有音频流
#ifdef DEBUG
printf("ai[%d] less than 0 \n", AeChn);
#endif
return TD_SUCCESS;
}
// 获取音频码流信息
pPackVirtAddr = pstStream->stream; // 带7字节ADTS头
u32PackLen = pstStream->len;
av_init_packet(&pkt); // 初始化AVpack包
Apst = fc->g_OutFmt_Ctx[AeChn]->streams[fc->ai[AeChn]]; // ai[AeChn]代表音频流索引号
if (fc->Afirst[AeChn] == 0) // 如果是第一个音频帧
{
fc->Afirst[AeChn] = 1;
// fc->Audio_PTS[AeChn] = pstStream->seq; // 记录下初始序列号
fc->Audio_PTS[AeChn] = pstStream->time_stamp; // 记录下开始时间戳
// fc->Audio_PTS[AeChn] = pstStream->time_stamp; // 记录下开始时间戳
}
// pkt.pts = pkt.dts = av_rescale_q_rnd(pstStream->seq - fc->Audio_PTS[AeChn],
// (AVRational){1000, 15625}, // 16000/1024*1000=15625
// Apst->time_base,
// (enum AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
pkt.pts = pkt.dts = (pstStream->time_stamp - fc->Audio_PTS[AeChn]) / (1000000 / AUDIO_RATE); // 时间基转换
// pkt.pts = pkt.dts = (fc->Audio_PTS[AeChn]++) / (1000000 / AUDIO_RATE); // 时间基转换
pkt.duration = 40; // 64ms
pkt.duration = av_rescale_q(pkt.duration, Apst->time_base, Apst->time_base); // 转换
pkt.pos = -1;
pkt.stream_index = Apst->index; // 音频流的索引号 赋给 包里面流索引号,表示这个包属于音频流
pkt.data = pPackVirtAddr; // 接受音频数据
pkt.size = u32PackLen; // 音频数据长度
// 写入一帧
ret = av_interleaved_write_frame(fc->g_OutFmt_Ctx[AeChn], &pkt);
if (ret < 0)
{
printf("Muxing: cannot write audio frame\n");
return TD_FAILURE;
}
printf("write audio frame\n");
return TD_SUCCESS;
}
我来回答
回答5个
时间排序
认可量排序
认可0
或将文件直接拖到这里
悬赏:
E币
网盘
* 网盘链接:
* 提取码:
悬赏:
E币
Markdown 语法
- 加粗**内容**
- 斜体*内容*
- 删除线~~内容~~
- 引用> 引用内容
- 代码`代码`
- 代码块```编程语言↵代码```
- 链接[链接标题](url)
- 无序列表- 内容
- 有序列表1. 内容
- 缩进内容
- 图片![alt](url)
相关问答
-
2016-12-26 21:18:32
-
2016-07-08 14:26:05
-
2020-01-10 20:21:25
-
2018-10-23 19:23:15
-
2016-04-08 09:16:39
-
2017-03-09 17:54:01
-
2020-10-30 11:11:35
-
12021-06-18 10:42:16
-
2020-09-09 10:20:33
-
2017-08-24 16:41:46
-
2015-10-18 16:55:24
-
2016-06-30 10:39:32
-
2015-08-12 15:22:22
-
2016-06-24 17:32:36
-
2021-01-19 16:45:02
-
2017-10-10 16:08:22
-
2018-06-15 16:16:41
-
2017-03-28 17:27:32
-
2022-05-30 18:08:10
无更多相似问答 去提问
点击登录
-- 积分
-- E币
提问
—
收益
—
被采纳
—
我要提问
切换马甲
上一页
下一页
举报反馈
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明
提醒
你的问题还没有最佳答案,是否结题,结题后将扣除20%的悬赏金
取消
确认
提醒
你的问题还没有最佳答案,是否结题,结题后将根据回答情况扣除相应悬赏金(1回答=1E币)
取消
确认