1. 首先注册 av_register_all();注册ffmpeg。如有需要可以自己用其它挨批分别注册
2. 用avcodec_alloc_context3函数分配一个解码环境m_av_ctx,并设置 m_av_ctx->codec_type = AVMEDIA_TYPE_VIDEO;m_av_ctx->codec_id = AV_CODEC_ID_H264;
3. 将解码与解码环境(m_av_ctx)关联。使用avcodec_find_decoder找到h264的。
例如:AVCodec* codec = avcodec_find_decoder(m_av_ctx->codec_id);
使用avcodec_open2函数将解码器与解码环境关联。
例如:int ret = avcodec_open2(m_av_ctx,codec,0);
4. 编写OnDecodec 函数,用于解码h264数据。
int OnDecodec(unsigned char* buf,int len)
{
AVPacket packet;
av_init_packet(&packet);
packet.size = len;
packet.data =buf;
int ret =0;
int got =0;
ret = avcodec_decode_video2(m_av_ctx,m_av_frame,&got,&packet);
if(ret<0)
{
return -1;
}
if(ret!=len)
{
return -1;
}
if(!got)
return -1;
.....
//解码成功
return ret;
}
5. 将h264数据给OnDecodec函数即可。
以下是相关源码 (解码为yuv420p数据,这里转成了RGB数据)
//
// FF264Decoder.hpp
// M51Ios
//
// Created by mac on 2019/11/28.
// Copyright © 2019 mac. All rights reserved.
//
#ifndef FF264Decoder_hpp
#define FF264Decoder_hpp
#include <stdio.h>
extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/imgutils.h"
#include "libswscale/swscale.h"
}
class CFF264Decoder
{
public:
CFF264Decoder();
~CFF264Decoder();
int OnDecodec(unsigned char* buf,int len);
unsigned char* GetImgBuf(int &OutWidth,int &OutHeight);
void OnLock();
void OnUnLock();
private:
AVCodecContext* m_av_ctx=0;
AVFrame* m_av_frame=0;
void* m_lock=0;
int m_nLastWidth=0;
int m_nLastHeight=0;
struct SwsContext* m_img_convert_ctx=0;
unsigned char* m_pConverBuf=0;
int m_nConverBufLen=0;
};
#endif /* FF264Decoder_hpp */
//
// FF264Decoder.cpp
// M51Ios
//
// Created by mac on 2019/11/28.
// Copyright © 2019 mac. All rights reserved.
//
#include "FF264Decoder.hpp"
#include "sdk51see.h"
CFF264Decoder::CFF264Decoder()
{
// InitFF();
m_av_ctx = avcodec_alloc_context3(nullptr);
m_av_ctx->codec_type=AVMEDIA_TYPE_VIDEO;
m_av_ctx->codec_id=AV_CODEC_ID_H264;
m_av_ctx->pix_fmt= AV_PIX_FMT_YUV420P;
m_av_ctx->extradata = 0;
m_av_ctx->extradata_size = 0;
m_av_ctx->thread_count=1;
m_av_ctx->thread_type = FF_THREAD_SLICE;
m_av_ctx->opaque = this;
m_av_ctx->refcounted_frames=1;
AVCodec* codec = avcodec_find_decoder(m_av_ctx->codec_id);
int ret = avcodec_open2(m_av_ctx,codec,0);
if(ret<0)
{
printf("open avcodec err ");
}
m_av_frame=av_frame_alloc();
//av_frame_free(&m_);
m_lock=M51C_NewLock();
}
CFF264Decoder::~CFF264Decoder()
{
M51C_DelLock(m_lock);
av_frame_free(&m_av_frame);
avcodec_free_context(&m_av_ctx);
sws_freeContext(m_img_convert_ctx);
av_free(m_pConverBuf);
}
int CFF264Decoder::OnDecodec(unsigned char* buf,int len)
{
AVPacket packet;
av_init_packet(&packet);
packet.size = len;
packet.data =buf;
int ret =0;
int got =0;
ret = avcodec_decode_video2(m_av_ctx,m_av_frame,&got,&packet);
if(ret<0)
{
return -1;
}
if(ret!=len)
{
return -1;
}
if(!got)
return -1;
printf("av:%d wh:%d-%d\n",len,m_av_frame->width,m_av_frame->height);
printf("%d-%d-%d\n",len,m_av_frame->linesize[0],
m_av_frame->linesize[1],
m_av_frame->linesize[2]);
if(m_av_frame->width!=m_nLastWidth ||
m_av_frame->height!=m_nLastHeight)
{
if(m_img_convert_ctx)
sws_freeContext(m_img_convert_ctx);
m_img_convert_ctx =0;
int needlen= avpicture_get_size(AV_PIX_FMT_RGBA, m_av_frame->width,m_av_frame->height);
if(m_nConverBufLen < needlen){
M51C_Lock(m_lock);
if(m_pConverBuf)
av_free(m_pConverBuf);
m_pConverBuf=(unsigned char*)av_malloc(needlen);
m_nConverBufLen = needlen;
M51C_UnLock(m_lock);
}
}
m_nLastWidth = m_av_frame->width;
m_nLastHeight = m_av_frame->height;
m_img_convert_ctx = sws_getCachedContext(m_img_convert_ctx,
m_nLastWidth,m_nLastHeight,(AVPixelFormat)m_av_frame->format,
m_nLastWidth,m_nLastHeight,AV_PIX_FMT_RGBA,
SWS_FAST_BILINEAR,
0,0,0);
AVPicture pic;
avpicture_fill(&pic, m_pConverBuf, AV_PIX_FMT_RGBA,m_nLastWidth , m_nLastHeight);
M51C_Lock(m_lock);
sws_scale(m_img_convert_ctx,
m_av_frame->data,m_av_frame->linesize,0,m_av_frame->height,
pic.data,pic.linesize);
M51C_UnLock(m_lock);
av_frame_unref(m_av_frame);
return 1;
}
void CFF264Decoder::OnLock()
{
M51C_Lock(m_lock);
}
void CFF264Decoder::OnUnLock()
{
M51C_UnLock(m_lock);
}
unsigned char* CFF264Decoder::GetImgBuf(int &OutWidth,int &OutHeight)
{
OutWidth=m_nLastWidth;
OutHeight=m_nLastHeight;
return m_pConverBuf;
}