libav/FFMPEG 视频音频编解码库使用
2015-12-30 16:50
926 查看
简介
在开始的时候,使用一个v4l2的lib example代码,用起来不错,但是后来使用sony的相机之后发现需要解码(MJPG),但是试了很多方法都不行,其中包括opencv的videoCapture, 使用ffmpeg解码,后来采用libav,的方式可以成功。Libav是ffmpeg的devel版本。
在使用的时候包含
LIBS += -L -lavcodec -lavformat -lavutil -lavdevice -lswscale -lx264
由于调用的是c程序,因此需要使用extern c.
#define __STDC_CONSTANT_MACROS #define __STDC_LIMIT_MACROS #define UINT64_C extern "C" { #include <libavformat/avformat.h> #include "libavcodec/avcodec.h" #include "libavutil/mathematics.h" #include "libavutil/samplefmt.h" #include "libswscale/swscale.h" #include <libavdevice/avdevice.h> #include <libswscale/swscale.h> }
使用流程
1. 注册
av_register_all(); avdevice_register_all(); avcodec_register_all(); avformat_network_init();
ffmpeg注册复用器,编码器等的函数
av_register_all()。该函数在所有基于ffmpeg的应用程序中几乎都是第一个被调用的。只有调用了该函数,才能使用复用器,编码器等。
ffmpeg注册编解码器等的函数
avcodec_register_all()(注意不是
av_register_all(),那是注册所有东西的)。该函数在所有基于ffmpeg的应用程序中几乎都是第一个被调用的。只有调用了该函数,才能使用编解码器等。
在使用libavdevice之前,必须先运行
avdevice_register_all()对设备进行注册,否则就会出错。
avdevice_register_all()的注册方式。
《最简单的基于FFmpeg的AVDevice例子(读取摄像头)》
http://blog.csdn.net/leixiaohua1020/article/details/39702113
2.内存操作
内存操作的常见函数位于libavutil\mem.c中。FFmpeg开发中最常使用的几个函数:av_malloc(),av_realloc(),av_mallocz(),av_calloc(),av_free(),av_freep()。
av_malloc()是FFmpeg中最常见的内存分配函数。
一个介绍基本函数流程的jpeg
http://img.my.csdn.net/uploads/201503/12/1426134989_1189.jpg
3.主循环之前的配置
过程开始于avformat_open_input,因此该函数的重要性不可忽视。在该函数中,FFMPEG完成了:
输入输出结构体AVIOContext的初始化;
输入数据的协议(例如RTMP,或者file)的识别(通过一套评分机制):1判断文件名的后缀 2读取文件头的数据进行比对;
使用获得最高分的文件协议对应的URLProtocol,通过函数指针的方式,与FFMPEG连接(非专业用词);
4.主循环
剩下的就是调用该URLProtocol的函数进行open,read等操作了FFMPEG中结构体很多。最关键的结构体可以分成以下几类:
a)解协议(http,rtsp,rtmp,mms)
AVIOContext,URLProtocol,URLContext主要存储视音频使用的协议的类型以及状态。URLProtocol存储输入视音频使用的封装格式。每种协议都对应一个URLProtocol结构。(注意:FFMPEG中文件也被当做一种协议“file”)b)解封装(flv,avi,rmvb,mp4)
AVFormatContext主要存储视音频封装格式中包含的信息;AVInputFormat存储输入视音频使用的封装格式。每种视音频封装格式都对应一个AVInputFormat 结构。c)解码(h264,mpeg2,aac,mp3)
每个AVStream存储一个视频/音频流的相关数据;每个AVStream对应一个AVCodecContext,存储该视频/音频流使用解码方式的相关数据;每个AVCodecContext中对应一个AVCodec,包含该视频/音频对应的解码器。每种解码器都对应一个AVCodec结构。d) 存数据
视频的话,每个结构一般是存一帧;音频可能有好几帧解码前数据:AVPacket
解码后数据:AVFrame
他们之间的对应关系如下所示:
具体函数
初始化和销毁
下文简单分析一下上述几个结构体的初始化和销毁函数。这些函数列表如下。结构体 | 初始化 | 销毁 |
---|---|---|
AVFormatContext | avformat_alloc_context() | avformat_free_context() |
AVIOContext | avio_alloc_context() | |
AVStream | avformat_new_stream() | |
AVCodecContext | avcodec_alloc_context3() | |
AVFrame | av_frame_alloc() | av_frame_free() |
/ | av_image_fill_arrays() | |
AVPacket | av_init_packet() | av_free_packet() |
/ | av_new_packet() |
avformat_open_input()。该函数用于打开多媒体数据并且获得一些相关的信息。它的声明位于libavformat\avformat.h,如下所示。
int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options);
ps:函数调用成功之后处理过的AVFormatContext结构体。
file:打开的视音频流的URL。
fmt:强制指定AVFormatContext中AVInputFormat的。这个参数一般情况下可以设置为NULL,这样FFmpeg可以自动检测AVInputFormat。
dictionay:附加的一些选项,一般情况下可以设置为NULL。
函数执行成功的话,其返回值大于等于0。
avformat_find_stream_info()。该函数可以读取一部分视音频数据并且获得一些相关的信息。avformat_find_stream_info()的声明位于libavformat\avformat.h,如下所示。
设置解码格式
code and encodeavcodec_find_encoder() avcodec_find_decoder()
avcodec_find_encoder()用于查找FFmpeg的编码器,avcodec_find_decoder()用于查找FFmpeg的解码器。
我的编码器使用了x264库,如果使用ffmpeg,可以参考
http://blog.csdn.net/leixiaohua1020/article/details/25430425
avcodec_open2()
所做的工作,如下所列:
(1)为各种结构体分配内存(通过各种av_malloc()实现)。
(2)将输入的AVDictionary形式的选项设置到AVCodecContext。
(3)其他一些零零碎碎的检查,比如说检查编解码器是否处于“实验”阶段。
(4)如果是编码器,检查输入参数是否符合编码器的要求
(5)调用AVCodec的init()初始化具体的解码器。
主循环
av_read_frame()
av_read_frame()的作用是读取码流中的音频若干帧或者视频一帧。例如,解码视频的时候,每解码一个视频帧,需要先调用 av_read_frame()获得一帧视频的压缩数据,然后才能对该数据进行解码(例如H.264中一帧压缩数据通常对应一个NAL)。
对该函数源代码的分析是很久之前做的了,现在翻出来,用博客记录一下。
上代码之前,先参考了其他人对av_read_frame()的解释,在此做一个参考:
通过av_read_packet(***),读取一个包,需要说明的是此函数必须是包含整数帧的,不存在半帧的情况,以ts流为例,是读取一个完整的PES包(一个完整pes包包含若干视频或音频es包),读取完毕后,通过av_parser_parse2(***)分析出视频一帧(或音频若干帧),返回,下次进入循环的时候,如果上次的数据没有完全取完,则st = s->cur_st;不会是NULL,即再此进入av_parser_parse2(***)流程,而不是下面的av_read_packet(**)流程,这样就保证了,如果读取一次包含了N帧视频数据(以视频为例),则调用av_read_frame(***)N次都不会去读数据,而是返回第一次读取的数据,直到全部解析完毕。
av_read_frame()的声明位于libavformat\avformat.h,如下所示。
avcodec_decode_video2()
ffmpeg中的avcodec_decode_video2()的作用是解码一帧视频数据。输入一个压缩编码的结构体AVPacket,输出一个解码后的结构体AVFrame。该函数的声明位于libavcodec\avcodec.h,如下所示。从代码中可以看出,avcodec_decode_video2()主要做了以下几个方面的工作:
(1)对输入的字段进行了一系列的检查工作:例如宽高是否正确,输入是否为视频等等。
(2)通过ret = avctx->codec->decode(avctx, picture, got_picture_ptr,&tmp)这句代码,调用了相应AVCodec的decode()函数,完成了解码操作。
(3)对得到的AVFrame的一些字段进行了赋值,例如宽高、像素格式等等。
其中第二部是关键的一步,它调用了AVCodec的decode()方法完成了解码。AVCodec的decode()方法是一个函数指针,指向了具体解码器的解码函数。
相关文章推荐
- [CSS3] Media Query & Responsive Design
- 操作
- window.onload与$(document).ready()比较
- Google Protocol Buffers 入门
- mongoDB 入门指南、示例
- 利用了相对坐标解决了商城项目开发中的一个问题。
- linux 进程数最大值修改
- jqury 修改颜色 位置等
- 递归下降语法分析程序设计
- 创业记-我的技术选型
- 游标更新 for update 与for update of 字段的区别
- python ---用户输入
- Javascript 把网页加入浏览器收藏夹。
- 某个文件夹下最新文件,某个字符串改成utf-8格式
- 浅谈 JS 创建对象的 8 种模式
- JMX解释
- Java操作MongoDB
- Mac 输入法符号
- sql语句,外键约束
- js浏览器对象