这是一个学习 FFmpeg 的 tutorial 系列。
这个是一个对初学者比较友好的FFmpeg学习教程,作者一步步引导我们实现了一个音视频同步的播放器。
参考链接:
建议可以打开代码+中文学习博客学习,我看了01~04篇的代码,然后就直接跳到了07的代码,结合中文博客+代码可以看懂。
#
这个代码很简单,就是解码一个视频文件,然后把前五帧视频保存为五个后缀格式 .ppm 图片视频
这个代码是把读取视频文件,然后每解码一帧,马上就用SDL显示出来。
跟02代码相比,这个添加了播放音频的部分。
FFmpeg负责把音频的从AVPacket解码为AVFrame得到原始数据,
然后SDL通过回调函数,有节奏的取出原始音频数据播放(这个是在一个独立的音频播放线程应该)
逻辑还是蛮复杂的 可以这样分析:
总共就两条主线音视频:
decode_thread :
死循环,不断读取AVPacket ,
并保存到 音频AVPacket队列, 视频AVPacket队列
音视频同步方式有三种:
音频时间轴:0-》1-》2-》3-》4-》5-》6-》7-》8-》9
int audio_decode_frame(VideoState *is, double *pts_ptr) {//省略代码//方法1:通过每一次decode获得的音频数据的字节数除以每一秒音频数据的字节数获得这一次decode的音频时长//累加这个时长,得出decode的音频最新时间is->audio_clock += (double)data_size /(double)(n * is->audio_st->codec->sample_rate);//方法2:如果AVPacket的pts有值,则可以通过pts计算 is->audio_clockif(pkt->pts != AV_NOPTS_VALUE) {is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts;}void audio_callback(void *userdata, Uint8 *stream, int len) {VideoState *is = (VideoState *)userdata;int len1, audio_size;double pts;while(len > 0) {if(is->audio_buf_index >= is->audio_buf_size) {/* We have already sent all our data; get more */audio_size = audio_decode_frame(is, &pts);if(audio_size < 0) {/* If error, output silence */is->audio_buf_size = 1024;memset(is->audio_buf, 0, is->audio_buf_size);} else {is->audio_buf_size = audio_size;}is->audio_buf_index = 0;}len1 = is->audio_buf_size - is->audio_buf_index;if(len1 > len)len1 = len;memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);len -= len1;stream += len1;is->audio_buf_index += len1;}}double get_audio_clock(VideoState *is) {double pts;int hw_buf_size, bytes_per_sec, n;//关键语句 is->audio_clock 代表已经解码的音频的数据最新时间pts = is->audio_clock; /* maintained in the audio thread */hw_buf_size = is->audio_buf_size - is->audio_buf_index;bytes_per_sec = 0;n = is->audio_st->codec->channels * 2;if(is->audio_st) {bytes_per_sec = is->audio_st->codec->sample_rate * n;}if(bytes_per_sec) {//关键语句,音频是解码到了一个buffer里面,其中一部分被SDL取走播放,还有一部分在缓冲区//已经解码的音频的数据最新时间 不能代表音频已经播放的时间,因为还有一部分解码的音频数据没有被播放//所以需要减去没有播放的音频的时间,得出准确的音频已经播放时间pts -= (double)hw_buf_size / bytes_per_sec;}return pts;}
b.如何正确设置每一帧视频的解码时间pts
c.如何调整视频播放速度快慢实现和音频的播放速度同步
以视频播放为时钟,音频播放参考视频播放时钟,调整下一帧的播放快慢实现视频同步到音频
以系统时间为时钟,音频视频同步到系统时钟
(未完待续~)
原文:http://www.cnblogs.com/bylijian/p/7151668.html