void dispThread(void *arg)
Input *input = (Input *)arg;
static const double interval = 1000000.0 / input->fps;
double q2d = av_q2d(input->tb) * 1000000.0;
int64_t pre_pts = 0;
int64_t frame_pre_pts = AV_NOPTS_VALUE;
AVFrame *pending_frm = NULL;
while (!input->is_req_exit()) {
int64_t cur_pts;
int remaining_time = 10000;
double duration = interval;
AVFrame *frm;
if (pending_frm) {
frm = pending_frm;
} else {
frm = input->PopFrame();
if (!frm) {
msleep(10);
continue;
static auto delete_func = [](AVFrame * f) {
av_frame_free(&f);
cur_pts = av_gettime_relative();
if (frame_pre_pts != AV_NOPTS_VALUE)
duration = (frm->pts - frame_pre_pts) * q2d;
int countdown = (pre_pts == 0) ? 0 : (int)(duration - (cur_pts - pre_pts));
remaining_time = std::min<int>(remaining_time, countdown);
if (input->realtime) {
countdown = 0;
remaining_time = 0;
if (countdown <= 0) {
frame_pre_pts = frm->pts;
pre_pts = cur_pts;
if (frm == pending_frm)
pending_frm = NULL;
push_frame(input->join, input->slice_idx,
std::shared_ptr<AVFrame>(frm, delete_func));
} else {
pending_frm = frm;
if (remaining_time > 0)
printf("countdown: %d, remaining_time: %d us\n",
countdown, remaining_time);
std::this_thread::sleep_for(std::chrono::microseconds(remaining_time));
if (pending_frm)
av_frame_free(&pending_frm);
- 知识点1:av_q2d(AVRational a)函数
av_q2d(AVRational);该函数负责把AVRational结构转换成double,通过这个函数可以计算出某一帧在视频中的时间位置
timestamp(秒) = pts * av_q2d(st->time_base);
计算视频长度的方法:
time(秒) = st->duration * av_q2d(st->time_base); - 知识点2:av_gettime_relative();
该函数是拿到当前的机器时间(系统时间)。
如果是直播的情况下我们不做延时。
大致的流程如下
- 取得解码视频帧
- 记录当前机器时间
- 计算当前准显示时间与上次显示时间差值d1
- 计算当前帧时间戳与上次显示时间戳差值d2
- 计算延时时间 d2 - d1
- 延时时间大于0则进行sleep延时
- 并保存当前帧在下一次循环送显
以上步骤为解决方案。请参考。
使用vue去显示时间时,常常需要对获取到的时间数据进行处理显示,这里可以使用filters过滤器的方法来进行
比如:需要显示获取到的时间与当前时间做对比,显示今天昨天前天,更早之前的时间可以显示为需要的时间格式
<!DOCTYPE html>
<meta charset="utf-8">
<script src="js/vue.js" type="text/javascript" charset="utf-8"
* Return the frame duration in seconds. Return 0 if not available.
void ff_compute_frame_duration(AVFormatContext *s, int *pnum, int *pden, AVStream *st,
前文中,我们基于
FFmpeg 利用 OpenGL ES 和 OpenSL ES 分别实现了对解码后
视频和音频的渲染,本文将实现
播放器的最后一个重要功能:音
视频同步。
老人们经常说,
播放器对音频和
视频的
播放没有绝对的静态的
同步,只有相对的动态的
同步,实际上音
视频同步就是一个“你追我赶”的过程。
音
视频的
同步方式有 3 种,即:音
视频向系统时钟
同步、音频向
视频同步及
视频向音频
同步。
音
视频解码器结构
在实现音
视频同步之前,我们先简单说下本文
播放器的大致结构,方便后面实现不同的音
视频同步方式。
要检查输入文件的时间戳是否正确,可以使用FFmpeg的"showinfo"过滤器。该过滤器会在控制台输出有关每个帧的详细信息,包括时间戳。以下是使用"showinfo"过滤器检查视频文件时间戳的示例命令:
ffmpeg -i input.mp4 -vf "showinfo" -f null -
该命令会在控制台输出与每个帧相关的信息,包括时间戳。如果时间戳有误,将会在输出中显示。类似地,可以使用"ashowinfo"过滤器检查音频文件时间戳:
ffmpeg -i input.mp4 -af "ashowinfo" -f null -
如果时间戳有误,将会在输出中显示。