一个网站做网站地图的目的,windous 系统 做网站,阿帕奇建设网站博客,免费网络电话呼叫系统用FFMPEG SDK进行视频转码压缩的时候#xff0c;转码成功后去看视频的内容#xff0c;发现音视频是不同步的。这个的确是一个恼火的事情。我在用FFMPEG SDK做h264格式的FLV文件编码Filter的时候就碰到了这个问题。经过研究发现#xff0c;FFMPEG SDK写入视频的时候有两个地方… 用FFMPEG SDK进行视频转码压缩的时候转码成功后去看视频的内容发现音视频是不同步的。这个的确是一个恼火的事情。我在用FFMPEG SDK做h264格式的FLV文件编码Filter的时候就碰到了这个问题。 经过研究发现FFMPEG SDK写入视频的时候有两个地方用来控制写入的时间戳一个是AvPacket, 一个是AvFrame。 在调用avcodec_encode_video的时候需要传入AvFrame的对象指针也就是传入一帧未压缩的视频进行压缩处理AvFrame包含一个pts的参数这个参数就是当前帧将来在还原播放的时候的时间戳。而AvPacket里面也有pts还有dts。说起这个就必须要说明一下I,P,B三种视频压缩帧。I帧就是关键帧不依赖于其他视频帧P帧是向前预测的帧只依赖于前面的视频帧而B帧是双向预测视频帧依赖于前后视频帧。由于B帧的存在因为它是双向的必须知道前面的视频帧和后面的视频帧的详细内容后才能知道本B帧最终该呈现什么图像。而pts和dts两个参数就是用来控制视频帧的显示和解码的顺序。 pts就是帧显示的顺序。 dts就是帧被读取进行解码的顺序。 如果没有B帧存在dts和pts是相同的。反之则是不相同的。关于这个的详细介绍可以参考一下mpeg的原理。 再说说AvPacket中包含的pts和dts两个到底该设置什么值 pts和dts需要设置的就是视频帧解码和显示的顺序。每增加一帧就加一并不是播放视频的时间戳。 但是实践证明经过rmvb解码的视频有时候并不是固定帧率的而是变帧率的这样如果每压缩一帧pts和dts加一的方案为导致音视频不同步。 那怎么来解决音视频同步的问题呢 请看如下代码段。 lTimeStamp 是通过directshow 获取的当前的视频帧的时间戳。 m_llframe_index为当前已经经过压缩处理的帧的数量。 首先av_rescale计算得到当前压缩处理已经需要处理什么时间戳的视频帧如果该时间戳尚未到达directshow当前提供的视频帧的时间戳则将该帧丢弃掉。 否则进行压缩操作。并设置AVPacket的pts和dts。这里假设B帧不存在。 因为在将来播放的时候视频以我们设定的固定播放帧率进行播放所以需要根据设定的播放帧率计算得到的视频帧时间戳和directshow提供的当前视频帧的时间戳进行比较设定是否需要进行实施延缓播放的策略。如果需要延缓播放则将pts增加步长2否则以普通速度播放则设置为1.dts与之相同。 __int64 x av_rescale(m_llframe_index,AV_TIME_BASE*(int64_t)c-time_base.num,c-time_base.den); if( x lTimeStamp ) { return TRUE; } m_pVideoFrame2-pts lTimeStamp; m_pVideoFrame2-pict_type 0; int out_size avcodec_encode_video( c, m_pvideo_outbuf, video_outbuf_size, m_pVideoFrame2 ); /* if zero size, it means the image was buffered */ if (out_size 0) { AVPacket pkt; av_init_packet(pkt); if( x lTimeStamp ) { pkt.pts pkt.dts m_llframe_index; pkt.duration 0; } else { pkt.duration (lTimeStamp - x)*c-time_base.den/1000000 1; pkt.pts m_llframe_index; pkt.dts pkt.pts; m_llframe_index pkt.duration; } //pkt.pts lTimeStamp * (__int64)frame_rate.den / 1000; if( c-coded_frame c-coded_frame-key_frame ) { pkt.flags | PKT_FLAG_KEY; } pkt.stream_index m_pVideoStream-index; pkt.data m_pvideo_outbuf; pkt.size out_size; /* write the compressed frame in the media file */ ret av_interleaved_write_frame( m_pAvFormatContext, pkt ); } else { ret 0; }