ffmpeg根据输入的参数截取视频
一、概述
在日常的开发中,经常会遇到视频截取的需求,如:视频编辑。用ffmpeg的视频截取功能非常简单,只需要调用av_frame_seek函数即可。
但是需要理解av_frame_seek参数的含义,其主要功能是对音视频流的位置进行定位。
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags);
二、代码示例
- 计算开始pts和结束pts。计算公式为pts=要移动的时间/timebase。av_seek_frame是使用pts移动位置的
if (begin_seconds > 0 && end_seconds > 0) { //计算开始的pts和结束的pts //pts = seconds/(num/den)=seconds*(den/num) if (vs && vs->time_base.num > 0) { double t = (double)vs->time_base.den / (double)vs->time_base.num;//den分母/num分子 begin_pts = begin_seconds * t; end_pts = end_seconds * t; } if (as && as->time_base.num > 0) { begin_audio_pts = begin_seconds * ((double)as->time_base.den / (double)as->time_base.num); } }
- 使用av_seek_frame集合pts进行音视频位置移动
//移动到关键帧seek if (vs) { re = av_seek_frame(ic, vs->index, begin_pts, AVSEEK_FLAG_FRAME | AVSEEK_FLAG_BACKWARD); PrintError(re, "av_seek_frame"); }
- 截取到结尾
if (begin_seconds > 0 && end_seconds > 0) { AVStream* in_stream = ic->streams[pkt.stream_index]; AVStream* out_stream = nullptr; long long offset_pts = 0; //偏移pts,用于截断的开头pts运算 if (vs && pkt.stream_index == vs->index) { qDebug() << "视频:"; //超过设定的时间就退出 if (pkt.pts > end_pts) { av_packet_unref(&pkt); break; } out_stream = oc->streams[0]; offset_pts = begin_pts; } else if (as && pkt.stream_index == as->index) { qDebug() << "音频:"; out_stream = oc->streams[1]; offset_pts = begin_audio_pts; } //重新计算pts dts duration //`a * bq(输入basetime) / cq(输出basetime)` if (out_stream) { pkt.pts = av_rescale_q_rnd(pkt.pts - offset_pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX) ); pkt.dts = av_rescale_q_rnd(pkt.dts - offset_pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX) ); pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base); } pkt.pos = -1; }