ffmpeg API 笔记:使用libavcodec/libavformat/libswscale

December 11, 2009

Update 2010.1.5: 其实研究ffmpeg不用找什么教程,第一步应该是下载ffmpeg的源码包。下面提到的An FFmpeg and SDL Tutorial确实有讲解,但是教程总是跟不上代码的变化的,所以直接看可工作代码最好;ffmpeg的结构很分明,后台是几个库:libxxx,前台是三个程序ffmpeg, ffplay, ffserver,那篇教程说的就是ffplay的实现。一个播放器,其实重点不是解码,解码的东西是lib去做的,主要是做声音视频的时钟同步。ffplay的代码可以说是一个可用播放器最简单的实现了,源码里面有个output_example.c,可以说是最基本的api示范吧。ffmpeg是转换编码解码转换程序,因为涉及重新采样等等,所以代码量也不少的。


这两天"调研"了下ffmpeg的API,不得不承认被雷倒:ffmpeg又是一个很geek的项目,纯社区开发,基于逆向,功能强大,但是文档极度有限,想了解API?看源码去…… 网上关于ffmpeg API的资料,无非是ffmpeg文档里面的两个链接,Using libavformat and libavcodec by
Martin Böhme(以及其Update,介绍了新引入的API)跟An FFmpeg and SDL Tutorial
by Stephen Dranger;两个tutorial基于ffmpeg 0.4.8,现在ffmpeg发布的版本是0.5.0,好像数值相差不大,不过0.4.8是5年前的了(相比之下wine用了15年版本号才到达1.0,有过之余无不及),两个教程里面的代码在0.5.0下一编译,哇,一堆错误,可不仅有些api函数变了,有些结构成员压根就没了,头文件的位置更是不一样(各个库分家了)……所以我调试了好几个小时,终于把例子的代码弄好(其实Martin Böhme那篇有一段09年加入的更新说明,链接了有相关的解决办法,我一开始没注意,几个小时自己解决,不过也有收获)。

最后我调试好的代码流程:打开一个视频文件,抓取前5帧保存为文件;
【基于Stephen Dranger的Tutorial1】源码在此:GoogleCode

av_register_all();//初始化ffmpeg库,如果系统里面的ffmpeg没配置好这里会出错
av_open_input_file();
av_find_stream_info();//查找文件的流信息
dump_format();//dump只是个调试函数,输出文件的音、视频流的基本信息了,帧率、分辨率、音频采样等等
for(...);//遍历文件的各个流,找到第一个视频流,并记录该流的编码信息
sws_getContext();//根据编码信息设置渲染格式
avcodec_find_decoder();//在库里面查找支持该格式的解码器
avcodec_open();//打开解码器
pFrame=avcodec_alloc_frame();//分配一个帧指针,指向解码后的原始帧
pFrameRGB=avcodec_alloc_frame();//分配一个帧指针,指向存放转换成RGB后的帧
avpicture_fill(pFrameRGB);//给pFrameRGB帧加上分配的内存;
while true{av_read_frame();//读取一个帧(到最后帧则break)
avcodec_decode_video();//解码该帧
sws_scale();//把该帧转换(渲染)成RGB
SaveFrame();//对前5帧保存成ppm图形文件(这个是自定义函数,非API)
av_free_packet();//释放本次读取的帧内存
}
avcodec_close();
av_close_input_file();

用到的API就这么多,当然实际代码稍复杂一点;ppm图像是类似BMP的非压缩格式,SaveFrame就是相当于把pFrameRGB的内存拷贝进文件,写文件并不复杂;

调试过程的问题,首先是头文件,ffmpeg 0.5.0的API已经拆分成好几个独立的库,用pacman -Ql ffmpeg看了下文件分布,在include下好几个目录都是它的,看名字可以大概猜出他们的功能:

libavcodec:CODEC其实是Coder/Decoder的缩写,也就是编码解码器;
libavdevice:对输出输入设备的支持;
libavformat:对音频视频格式的解析
libavutil:集项工具;
libpostproc:后期效果处理;
libswscale:视频场景比例缩放、色彩映射转换;

修改好头文件包含,终于少了些not declared错误;

Martin Böhme那篇教程的代码是使用g++编译的,虽然代码是C风格;在我修改了头文件以及一些错误之后,居然链接出错,av_register_all什么的函数统统undefined reference,想到ffmpeg是纯C实现,以及以前用g++编译GTK出现回呼函数找不到的经历,相信又是g++的function mangling搞的,Google了一下,解决方法是把几个头文件包含在exterc "C"里面。

代码里面的错误还涉及一些结构成员的变化,比如

pFormatCtx->streams[i]->codec.codec_type==CODEC_TYPE_VIDEO

就有个类型错误,因为0.5.0里面的codec已经是指针,而不是结构了,要把.换成->,而相应地获得解码器指针,不再需要&:

pCodecCtx=&pFormatCtx->streams[videoStream]->codec;

原教程提到一个视频码率的rate的Hack:

    // Hack to correct wrong frame rates that seem to be generated by some codecs<br />    if(pCodecCtx->frame_rate>1000 && pCodecCtx->frame_rate_base==1)<br />        pCodecCtx->frame_rate_base=1000;

好吧现在frame_rate跟frame_rate_base压根就没了,去掉算了;

最麻烦的变化还是原代码里面的img_convert,就是解码出一个帧的数据后,需要转换成RGB格式才能写入文件,然而这个函数在0.5.0里面彻底没了。尝试把img_convert完全注释掉,把原始帧img_convert写入文件,还算可喜的是能够看到图形,只是被分成三个画面的通道图形罢了;

Google了一番,还是回到 Stephen Dranger的An FFmpeg and SDL Tutorial第八节,介绍了swscale的接口,虽然里面的例子是转换成SDL所用的YUV,而不是RGB;注意到其使用的参数PIX_FMT_YUV420P,跟img_convert所用的PIX_FMT_RGB24有相同前序,就试试照样花虎了;
给sws_getContext传入源格式的H/W,格式,输出格式的H/W,PIX_FMT_RGB24格式,其中有个参数flags的解释是 specify which algorithm and options to use for rescaling,是选择在缩放过程中是使用线性还是双立方等算法(参数文档没说,要找看源码去),这里照抄了例子里面的SWS_BICUBIC。获得这个SwsContext,类似python的re.compile,再用这个转换器去转换每一个帧,所以后面每次解码了帧后,调用sws_scale,跟原来的img_convert倒是挺像;

也就是说,以后如果需要对视频进行4:3跟16:9的转换,就是在sws_getContext的参数里面做设置了;

最后整个程序正常,会把视频的前5帧抓成图像了,只是会有个小警告:

[swscaler @ 0x1d8f670]No accelerated colorspace conversion found.

估计是转换成RGB,swscale里面没有特别优化的算法?

目前发现程序运行的时候CPU占用很高,是因为程序还没有控制帧速的时钟,只会用尽CPU的性能不断的读取解码;

PT修改过可编译通过(ffmpeg 5.0/gcc 4.4.2/ubuntu 9.10)的前三个Tutorial代码可在Google Code查看下载。(编译方法请看各个文件头部的注释说明)

tags: ffmpeg,img_convert,libavcodec,libavformat,libswscale
posted in Programming by BOYPT

Follow comments via the RSS Feed | Leave a comment |Trackback URL

ffmpeg API FR NET相关推荐

  1. ffmpeg API 笔记:使用libavcodec/libavformat/libswscale ffmpeg例子

    ffmpeg API 笔记:使用libavcodec/libavformat/libswscale December 11, 2009 Update 2010.1.5: 其实研究ffmpeg不用找什么 ...

  2. 学习FFmpeg API –解码视频

    转自:http://my.oschina.net/u/555701/blog/56616 ffmpeg是编解码的利器,用了很久,以前看过dranger 的教程,非常精彩,受益颇多,是学习ffmpeg ...

  3. 学习FFmpeg API -解码视频

    版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] Tutorial 1 Decoding video frames 视频播放过程 声明变量 打开文件 分配图像缓存 获取图像 ff ...

  4. 【AVD】杀鸡用牛刀,FFmpeg API 加载存储图片,比 ImageMagic 和 stb_image 快多了

    最近工作中遇到一个需求.现有代码中的图形库使用 ImageMagic 加载图片并做简单处理,但是在移植到 iOS 平台的过程中遇到了些问题.于是找到我,看能否用 FFmpeg 实现图片的从文件中读取加 ...

  5. 使用FFMpeg API 获取摄像头的图像数据

    文章目录 1. 获取摄像头的信息 2. 打开并初始化摄像头 3. 获取摄像头数据及渲染 摄像头是我们比较常用的外设,很多场景我们都会用到摄像头.比如视频直播.视频监控等各个领域都会用到摄像头.摄像头图 ...

  6. ffmpeg api推流,谷歌浏览器播放大华、海康威视网络摄像头rtsp视频流方案(hls、m3u8、flv、webrtc、srs、nginx、nginx-rtmp、rtmp)比较

    ffmpeg api推流,谷歌浏览器播放大华.海康威视网络摄像头rtsp视频流方案(hls.m3u8.flv.webrtc.srs.nginx.nginx-rtmp.rtmp)比较 将网络摄像头视频流 ...

  7. ffmpeg api解码音频,得到pcm数据

    ffmpeg api解码音频,得到pcm数据,程序如下: extern "C" { #include "libavutil/avutil.h" #include ...

  8. ffmpeg api接口实现rtmp推流的两种方式

    FFmpeg 版本 version 4.0.2 搭建Rtmp服务 具体可以参考一下其它文章,本文主要讲的是如何使用FFmpeg api接口实现推流功能 推流flv文件 av_register_all( ...

  9. 学习FFmpeg API – 解码视频流程总结

    转载原文地址 FFMPEG 是编解码的利器,用了很久,以前看过dranger 的教程,非常精彩,受益颇多,是学习ffmpeg api很好的材料.可惜的是其针对的ffmpeg版本已经比较老了,而ffmp ...

最新文章

  1. 根据IP查找在交换机上的端口
  2. CSS中块级格式化上下文(BFC)的特性与应用
  3. git diff命令输出的含义
  4. [置顶] 我的程序员之路(4)---C语言课程设计
  5. ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 安装过程
  6. 解决Qt5 Creator无法切换输入法(fcitx),Ubuntu中不能使用搜狗输入法录入汉字问题...
  7. python自带的解释器叫做_python学习
  8. Hibernate的CRUD重用性
  9. 安装centos7步骤_Centos7下源码编译安装mysql5.7 详细步骤 小白也能安装
  10. 网络通信第一课 C++封装HTTP请求报文说明
  11. linux accept 修改数据包,Linux协议栈accept和syn队列问题
  12. 读赵凯华之《新概念物理教程.热学》
  13. Excel函数大全-12统计函数
  14. 51单片机 - 红外遥控时钟
  15. VMware 虚拟机操作命令收集
  16. mkv格式用什么播放器打开?视频转换器怎样操作
  17. python实现12306自助刷票下单
  18. cropperjs裁剪后图片变大的问题
  19. 人脸和身份证不匹配_人脸识别身份信息不匹配是什么意思
  20. python民宿房间预订管理平台系统django549

热门文章

  1. python OpenCV:绘制一个圆形图片
  2. 需求分析-需求调研步骤和方法
  3. 2019.02.24
  4. ARM嵌入式主板之路
  5. Oracle计算偏差率的方法
  6. IC卡·一卡一密加密 动态数据防伪方案实现
  7. 【2023年最新版】Kali安装详细教程
  8. 开启Fluter基础之旅四-------表格、动画、手势
  9. 算法_二叉树_二叉树的最大深度
  10. 经典案例oracle和mysql分别比较