问题描述:
最近在研究短视频功能,发现编码出来的mp4文件的duration 比 原始文件的 时间大一倍
ffmpeg 命令行查看并不是stream 里面的时间出了问题,问题应该是最后计算填写头里面的封装信息出错了,详细如下:
ffprobe -print_format json -show_format -show_streams -i output_cut.mp4
通过二进制比较 为“elst” 的字段出了问题
比较结果如图红色部分,详细如下
正确的时间为 00 00 24 48 错误的时间字段 为 00 00 48 62
mp4 封装 “elst ” 字段对应数据结构如下:
aligned(8) class EditListBox extends FullBox(‘elst’, version, 0) {
unsigned int(32) entry_count;
for (i=1; i <= entry_count; i++) {
if (version==1) {
unsigned int(64) segment_duration;
int(64) media_time;
} else { // version==0
unsigned int(32) segment_duration;
int(32) media_time;
}
int(16) media_rate_integer;
int(16) media_rate_fraction = 0;
}
}
解决方案:
参考了 ffmpeg/libavformat/tests/movenc.c 里面的代码 ,由于目前资源无法设置0分,只能最低分了,资源如下
http://download.csdn.net/download/gavin_liang/10049224
也可以下载源码查看;
关键代码标注
发现由于在 encoder 之后code timebase -> stream timebase 转化的时候 pkt->duration 要同样做处理
自身代码处理方法如下:
intFFMPEGFileOutputImp::write_frame(AVFormatContext*fmt_ctx,AVRational*time_base,AVStream*st,AVPacket*pkt,intstream_type)
{
/* rescale output packet timestamp values from codec to stream timebase */
av_packet_rescale_ts(pkt, *time_base, st->time_base);
pkt->stream_index= st->index;
int64_ttmp = st->time_base.den;
switch(stream_type) {
caseAVMEDIA_TYPE_AUDIO:
pkt->duration=1024LL * ((st->time_base.den/ st->time_base.num) /44100);
break;
caseAVMEDIA_TYPE_VIDEO:
pkt->duration= (st->time_base.den/ st->time_base.num) /STREAM_FRAME_RATE;
break;
default:
break;
}
/* Write the compressed frame to the media file. */
// log_packet(fmt_ctx, pkt);
returnav_interleaved_write_frame(fmt_ctx, pkt);
}
目前看问题得到解决,以上方式仅供参考,有更好的办法欢迎讨论
网友评论