2017最新注册送金娱乐网

Ffmpeg 音视频同步详解 PTS 和 DTS 音频和视频流都有一些关于以多快速度和什么时间来播放它们的信息在里面。

音频流有采样,视频流有每秒的帧率。

然而,如果我们只是 简单的通过数帧和乘以帧率的方式来同步视频,那么就很有可能会失去同步。

于是作为一种补充,在流中的包有种叫做 DTS(解码时间戳) 和 PTS (显示时间戳) 的机制。

为了这两个参数, 你需要了解电影存放的方式。

像 MPEG 等格式, 使用被叫做 B 帧 (B 表示双向 bidrectional) 的方式。

另外两种帧被叫做 I 帧和 P 帧(I 表示关键帧,P 表示预测帧)。

I 帧包含了某个特定的完整图像。

P 帧依赖于前面的 I 帧和 P 帧 并且使用比较或者差分的方式来编码。

B 帧与 P 帧有点类似,但是它是依赖于前面和后面的帧的信息的。

这也就解释了为什么我们可能在 调用 avcodec_decode_video 以后会得不到一帧图像。

所以对于一个电影,帧是这样来显示的:I B B P。

现在我们需要在显示 B 帧之前知道 P 帧中的信息。

因此,帧可能会按照这样的方式来存 储:IPBB。

这就是为什么我们会有一个解码时间戳和一个显示时间戳的原因。

解码时间戳告诉我们什么时候需要解码,显示时间戳告诉我 们什么时候需要显示。

所以,在这种情况下,我们的流可以是这样的: PTS: 1 4 2 3 DTS: 1 2 3 4 Stream: I P B B 通常 PTS 和 DTS 只有在流中有 B 帧的时候会不同。

当我们调用 av_read_frame()得到一个包的时候,PTS 和 DTS 的信息也会保存在包中。

但是我们真正想要的 PTS 是我们刚刚解码出来的 原始帧的 PTS,这样我们才能知道什么时候来显示它。

然而,我们从 avcodec_decode_video()函数中得到的帧只是一个 AVFrame,其中 并没有包含有用的 PTS 值(注意:AVFrame 并没有包含时间戳信息,但当我们等到帧的时候并不是我们想要的样子)。

然而,ffmpeg 重 新排序包以便于被 avcodec_decode_video()函数处理的包的 DTS 可以总是与其返回的 PTS 相同。

但是,另外的一个警告是:我们也并不 是总能得到这个信息。

不用担心,因为有另外一种办法可以找到帧的 PTS,我们可以让程序自己来重新排序包。

我们保存一帧的第一个包的 PTS:这将作为整个

这一帧的 PTS。

我们可以通过函数 avcodec_decode_video()来计算出哪个包是一帧的第一个包。

怎样实现呢?任何时候当一个包开始一 帧的时候,avcodec_decode_video()将调用一个函数来为一帧申请一个缓冲。

当然,ffmpeg 允许我们重新定义那个分配内存的函数。

所以 我们制作了一个新的函数来保存一个包的时间戳。

当然,尽管那样,我们可能还是得不到一个正确的时间戳。

我们将在后面处理这个问题。

同步 现在,知道了什么时候来显示一个视频帧真好,但是我们怎样来实际操作呢?这里有个主意:当我们显示了一帧以后,我们计算出下一帧 显示的时间。

然后我们简单的设置一个新的定时器来。

你可能会想,我们检查下一帧的 PTS 值而不是系统时钟来看超时是否会到。

这种方 式可以工作,但是有两种情况要处理。

首先,要知道下一个 PTS 是什么。

现在我们能添加视频速率到我们的 PTS 中--太对了!然而,有些电影需要帧重复。

这意味着我们重 复播放当前的帧。

这将导致程序显示下一帧太快了。

所以我们需要计算它们。

第二,正如程序现在这样,视频和音频播放很欢快,一点也不受同步的影响。

如果一切都工作得很好的话,我们不必担心。

但是,你的电 脑并不是最好的,很多视频文件也不是完好的。

所以,我们有三种选择:同步音频到视频,同步视频到音频,或者都同步到外部时钟(例 如你的电脑时钟)。

从现在开始,我们将同步视频到音频。

写代码:获得帧的时间戳 现在让我们到代码中来做这些事情。

我们将需要为我们的大结构体添加一些成员,但是我们会根据需要来做。

首先,让我们看一下视频线 程。

记住,在这里我们得到了解码线程输出到队列中的包。

这里我们需要的是从 avcodec_decode_video 函数中得到帧的时间戳。

我们讨 论的第一种方式是从上次处理的包中得到 DTS,这是很容易的: double pts; for(;;) { if(packet_queue_get(&is->videoq, packet, 1) < 0) { // means we quit getting packets

break; } pts = 0; // Decode video frame len1 = avcodec_decode_video(is->video_st->codec, pFrame, &frameFinished, packet->data, packet->size); if(packet->dts != AV_NOPTS_VALUE) { pts = packet->dts; } else { pts = 0; } pts *= av_q2d(is->video_st->time_base); 如果我们得不到 PTS 就把它设置为 0。

好,那是很容易的。

但是我们所说的如果包的 DTS 不能帮到我们,我们需要使用这一帧的第一个包的 PTS。

我们通过让 ffmpeg 使用我们 自己的申请帧程序来实现。

下面的是函数的格式:

intget_buffer(structAVCodecContext *c, AVFrame *pic); void release_buffer(structAVCodecContext *c, AVFrame *pic); 申请函数没有告诉我们关于包的任何事情, 所以我们要自己每次在得到一个包的时候把 PTS 保存到一个全局变量中去。

我们自己以读到它。

然后,我们把值保存到 AVFrame 结构体难理解的变量中去。

所以一开始,这就是我们的函数: uint64_t global_video_pkt_pts = AV_NOPTS_VALUE; intour_get_buffer(structAVCodecContext *c, AVFrame *pic) { int ret = avcodec_default_get_buffer(c, pic); uint64_t *pts = av_malloc(sizeof(uint64_t)); *pts = global_video_pkt_pts; pic->opaque = pts; return ret; } void our_release_buffer(structAVCodecContext *c, AVFrame *pic) { if(pic) av_freep(&pic->opaque); avcodec_default_release_buffer(c, pic); } 函数 avcodec_default_get_buffer 和 avcodec_default_release_buffer 是 ffmpeg 中默认的申请缓冲的函数。

函数 av_freep 是一个内存管理

函数,它不但把内存释放而且把指针设置为 NULL。

现在到了我们流打开的函数(stream_component_open),我们添加这几行来告诉 ffmpeg 如何去做: codecCtx->get_buffer = our_get_buffer; codecCtx->release_buffer = our_release_buffer; 现在我们必需添加代码来保存 PTS 到全局变量中,然后在需要的时候来使用它。

我们的代码现在看起来应该是这样子: for(;;) { if(packet_queue_get(&is->videoq, packet, 1) < 0) { // means we quit getting packets break; } pts = 0; // Save global pts to be stored in pFrame in first call global_video_pkt_pts = packet->pts; // Decode video frame len1 = avcodec_decode_video(is->video_st->codec, pFrame, &frameFinished, packet->data, packet->size);

if(packet->dts == AV_NOPTS_VALUE &&pFrame->opaque && *(uint64_t*)pFrame->opaque != AV_NOPTS_VALUE) { pts = *(uint64_t *)pFrame->opaque; } else if(packet->dts != AV_NOPTS_VALUE) { pts = packet->dts; } else { pts = 0; } pts *= av_q2d(is->video_st->time_base); 技术提示:你可能已经注意到我们使用 int64 来表示 PTS。

这是因为 PTS 是以整型来保存的。

这个值是一个时间戳相当于时间的度量,用 来以流的 time_base 为单位进行时间度量。

例如,如果一个流是 24 帧每秒,值为 42 的 PTS 表示这一帧应该排在第 42 个帧的位置如果我 们每秒有 24 帧(这里并不完全正确)。

我们可以通过除以帧率来把这个值转化为秒。

流中的 time_base 值表示 1/framerate (对于固定帧率来说) , 所以得到了以秒为单位的 PTS, 我们需要乘以 time_base。

写代码:使用 PTS 来同步 现在我们得到了 PTS。

我们要注意前面讨论到的两个同步问题。

我们将定义一个函数叫做 synchronize_video,它可以更新同步的 PTS。

这个函数也能最终处理我们得不到 PTS 的情况。

同时我们要知道下一帧的时间以便于正确设置刷新速率。

我们可以使用内部的反映当前视 频已经播放时间的时钟 video_clock 来完成这个功能。

我们把这些值添加到大结构体中。

typedefstructVideoState {

  • 基于FFMPEG解码的音视频同步实现

    基于FFMPEG解码的音视频同步实现

    基于FFMPEG解码的音视频同步实现...

    贡献者:网络收集
    830445
  • Ffmpeg音视频同步收集

    Ffmpeg音视频同步收集

    Ffmpeg音视频同步收集...

    贡献者:网络收集
    160430
  • ffmpeg的快速音视频开发2017最新注册送金娱乐网

    ffmpeg的快速音视频开发2017最新注册送金娱乐网

    ffmpeg的快速音视频开发2017最新注册送金娱乐网...

    贡献者:网络收集
    132243
  • 一种基于FFMPEG的音视频同步算法

    一种基于FFMPEG的音视频同步算法

    一种基于FFMPEG的音视频同步算法...

    贡献者:网络收集
    965001
  • FFMPEG解码流程理解搜集整理及tutorial5的理解,主要是音视频同步

    FFMPEG解码流程理解搜集整理及tutorial5的理解,主要是音视频同步

    FFMPEG解码流程理解搜集整理及tutorial5的理解,主要是音视频同步...

    贡献者:网络收集
    451838
  • FFMPEG音视频同步原理

    FFMPEG音视频同步原理

    FFMPEG音视频同步原理...

    贡献者:网络收集
    298728
  • 音视频同步原理[ffmpeg]

    音视频同步原理[ffmpeg]

    音视频同步原理[ffmpeg]...

    贡献者:网络收集
    289738
  • ffmpeg的快速音视频开发

    ffmpeg的快速音视频开发

    ffmpeg的快速音视频开发...

    贡献者:网络收集
    579233
  • 浅析DirectShow音视频同步解决方案

    浅析DirectShow音视频同步解决方案

    浅析DirectShow音视频同步解决方案...

    贡献者:网络收集
    951670
  • 音视频的同步问题

    音视频的同步问题

    音视频的同步问题...

    贡献者:网络收集
    873980
  • 网友在搜
    麻将绝技 槲叶落山路 阿阿阿 transparent qq密码怎么修改 console.log u盘安装ubuntu 怎么下载mv 罪恶都市超级作弊器 新版itunes js正则 ppjoy phpstatic 迅雷7 崩溃 神武辅助免费版 dnf骑士贞德 天正8.5过期补丁 网络竞价赚钱 小米路由器有什么用 starglow 简单百宝箱怎么用 性侵犯 情侣交换日记 瑞雨整容前 田中千绘三级 胸交 女性性病图片 曝baby怀孕 用矿泉水洗脸好吗 吴昕家 李卉老公 陈赫娄艺潇百里挑一 毛孔清洁器 冲田杏梨最好看的一部 梅根福克斯 大尺度 谢羽亿近况 从后面进入 涓子主演的电视剧 大宝sod蜜保质期 郭书瑶三围 邵乔茵 汤唯资料 默多克前妻安娜 韩国美女宋宝儿 耻骨 拥抱 成人论坛 性爱网 饥渴 色猫网 色猫网 婚外恋 偶偶吧 u点 俩性 纤纤玉手 撸撸碰 阴蒂在哪

    声明:本站内容部分源于网络转载,出于传递更多信息之目的,并不意味着赞同其观点或证实其描述。文章内容仅供参考,请咨询相关专业人士。

    如果无意之中侵犯了您的版权,或有意见、反馈或投诉等情况, 联系我们:点击这里给我发消息

    Copyright © 2016 All Rights Reserved 紫菜网 手机站