ffmpeg的开源代码自行在ffmpeg的官方下载(http://ffmpeg.org/)
编译
编译之前需要先安装gcc编译器,本文使用的是arm-linux的交叉编译器,这里简称arm-linux-gcc
本文使用的版本是 ffmpeg-3.3.3,下载得到ffmpeg-3.3.3.tar.bz2
mkdir dist
tar xvf ffmpeg-3.3.3.tar.bz2
cd ffmpeg-3.3.3
./configure --cc="arm-linux-gcc" --cxx="arm-linux-g++" --ar="arm-linux-ar" --prefix=$(pwd)/../dist --enable-cross-compile --target-os=none --arch=x86_32 --cpu=generic \
--enable-gpl --enable-version3 --disable-avdevice --disable-avformat --disable-swresample --disable-postproc --disable-avfilter \
--disable-programs --disable-logging --disable-everything --enable-decoder=hevc --enable-decoder=h264 \
--disable-ffplay --disable-ffprobe --disable-ffserver --disable-asm --disable-doc --disable-devices --disable-network \
--disable-hwaccels --disable-parsers --disable-bsfs --disable-debug --disable-protocols --disable-indevs --disable-outdevs
make
make install
configure命令的使用可以输入./configure –help查看,根据具体需求启用/禁用相关选项。为了裁剪代码,本文使用的编译选项只开启h264和h265的解码,其他功能禁用掉。编译生成静态lib库*.a,不生成可执行程序,可以方便在demo程序中直接调用。
以上命令都执行完之后,在dist目录中会生成libavcodec.a和libavutil.a
api使用
需要用到的api
void avcodec_register_all(void);
AVCodec *avcodec_find_decoder(enum AVCodecID id);
AVCodecContext *avcodec_alloc_context3(const AVCodec *codec);
int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
void av_free(void *ptr);
AVFrame *av_frame_alloc(void);
int avcodec_close(AVCodecContext *avctx);
int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
int *got_picture_ptr,
const AVPacket *avpkt);
在demo程序调用api
这里只写基本框架
AVCodec * m_codec = NULL;
AVCodecContext * m_context = NULL;
AVFrame *m_pic = NULL;
//初始化解码器
int ffmpeg_init(AVCodec *m_codec, AVCodecContext *m_context, AVFrame *m_pic,int AV_CODEC_ID)
{
avcodec_register_all();
// AV_CODEC_ID H264是AV_CODEC_ID_H264, H265是AV_CODEC_ID_HEVC, 具体看ffmpeg源码中的宏定义
m_codec = avcodec_find_decoder(AV_CODEC_ID);
m_context = libffmpeg.avcodec_alloc_context3(m_codec);
int avcodecopenRes = avcodec_open2(m_context, m_codec, 0);
if (avcodecopenRes < 0){
if (m_context){
av_free(m_context);
m_context = NULL;
return -1;
}
}
m_pic = av_frame_alloc();
if (!m_pic){
if (m_context){
avcodec_close(m_context);
av_free(m_context);
m_context = NULL;
}
return -1;
}
return 0;
}
//解码, 把原始的H264/H265视频帧数据传入,得到解码后的YUV数据
int ffmpeg_decode(AVCodecContext *m_context, AVFrame *m_pic,unsigned char *avpkt_data,int avpkt_size)
{
AVPacket avpkt;
memset(&avpkt,0,sizeof(AVPacket));
avpkt.data = avpkt_data;
avpkt.size = avpkt_size;
int got_picture_ptr=0;
int ret_value=0;
ret_value=avcodec_decode_video2(m_context, m_pic, &got_picture_ptr,&avpkt);
if(ret_value>0 && got_picture_ptr>0){
return 0;
}
else{
return -1;
}
}
/*
解码后的yuv数据在AVFrame *m_pic之中
m_pic->width 表示视频画面的像素宽度
m_pic->height 表示视频画面的像素高度
m_pic->format 表示yuv的格式,如比YUV420、YUV422、YUV444等,具体看ffmpeg源码中的枚举enum AVPixelFormat已经相关宏定义
m_pic->data[3] 表示解码后的yuv数据中元素data[0]、data[1]、data[2]分别表示Y、U、V
m_pic->linesize[3] 表示解码后的Y、U、V数据每行的size,linesize[0]、linesize[1]、linesize[2]分别表示Y、U、V
*/
//释放解码器
void ffmpeg_free(AVCodec *m_codec, AVCodecContext *m_context, AVFrame *m_pic)
{
if (m_codec && m_context){
m_codec->close(m_context);
m_codec = NULL;
}
if (this.m_context)
{
avcodec_close(m_context);
av_free(m_context);
}
if (m_pic)
{
av_free(m_pic);
}
m_pic = NULL;
m_codec = NULL;
m_context = NULL;
}