这篇文章是我自己看的,你未必能看懂,当做我自己的备份。
FFmpeg是复杂的开源系统,刚开始玩只知道用命令ffmpeg -i test.mp4 这样的。其实普通用户能有用这个命令ffmpeg和FFmpeg框架是有区别的。
其实ffmpeg这个命令是一个程序,代码是FFmpeg的根目录ffmpeg.c编译出来的。这个ffmpeg.c调用了FFmpeg框架libavformat,libavcodec,libavfilters,libavutil的API,实现了对命令 ffmpeg -i test.mp4的解析。同理,ffplay其实是ffplay.c编译出来的,它调用了FFmpeg框架和SDL进行编译,FFmpeg作为编解码库,然后SDL作为显示渲染YUV。
所以FFmpeg框架是不包含ffmpeg.c,fflpay,ffserver等这些的。你可以把它们当做使用FFmpeg框架的案例!
如果我们自己要写代码进行解析mp4为YUV,进行滤镜处理,进行分离音频,以及合成MP4等,那么就跟ffmpeg 这样的命令一毛钱关系都没有了。我们是通过调用FFmpeg的框架的API进行处理的,各种东西就需要我们处理。
比如先注册各种东西,检测输入文件和输出文件,得出InputStream以及上下文context什么的。
Context什么的都是程序运行的时候才能决定的。比如AVFormatContext。
通过av_read_frame从AVFormatContext里面读取AVPacket(包),可以循环读,如果返回-1,标示结束。
再判断&packet.stream_index是音频还是视频,通过av_find_best_stream函数调用访问AVFormatContext就能知道音频和视频流的标示是0还是1.
判断搞定后,可以从AVFormatContext的streams数组中获取AVStream.
可以通过stream->avg_frame_rate.num/stream->avg_frame.den得到fps.帧率。
同时也可以通过avcodec_decode_video2函数的调用,参数是AVFormatContext和AVPacket 以及AVFrame得到一帧Frame。
那么这个AVFrame的pts可以通过这个函数av_frame_get_best_effort_timestamp(frame)获得。
//===========如果通过AVFliter滤镜处理===============
上面得到AVFrame之后,如果之前我们已经初始化了AVFilterGraph,已经把AVFilterLink搞定,那么就可以通过
av_buffsersrc_add_frame函数参数是AVFilterContext和AVFrame(我们读到的frame),添加这个帧到滤镜去,滤镜自己处理了后。
通过av_buffersink_get_buffer_ref获取滤镜后的AVFilterBufferRef(这个结构体保存了处理后的数据),结构和AVFrame差不多,可以copy过去。
一般AVFilterBufferRef通过函数sws_scale进行YUV的尺寸调整,否则在特殊情况下会导致视频绿屏。
调整YUV 后,就可以写入文件什么的,或者拿去播放了。
(貌似滤镜通过后,pts会改变,需要调整,还没具体测试,只是看到AVFilterBufferRef的结构这么说)
//===============================================
如果我们得到AVFrame后不打算通过滤镜,那么就是把AVFrame的data保存了,一般是YUV数据。
如上就是基本的简单了解。需要注意的是time_base这个东西,AVCodectContext里面的time_base和AVStream里面的time_base是不一样的。
其实每个结构体的time_base都不一样,解码和编码不一样。
关于音视频同步问题,如果保存YUV后,编码成h264的时候就需要注意了,原视频的帧率是多少。如果本来是30帧每秒,fps=30,你硬是设置
为num=1,den=25,结果就是视频和音频不同步,原因是视频放得太慢了。还有一个就是如果本来是fps=19,你设置为25后,结果就是视频也许
播放OK,但是会发现视频最后几帧不见了(也就是视频变短了,其实是播放的速度太快,后面几帧一闪而过)。
最后几篇比较有用的文章:
MAC上搭建直播环境:nginx+rmtp环境,http://blog.csdn.net/yangxiao_xiang/article/details/51861688
推流,MAC上推摄像头和桌面:http://blog.chinaunix.net/uid-11344913-id-4665455.html
AVFilter最有用的实战:http://blog.csdn.net/encoder1234/article/details/53908931