前言

在学习FFmpeg的时候很有幸读到了雷霄骅博士的博客,非常感谢他留下的宝贵财富,知识是不朽的。

1 FFmpeg库简介

androidffmpeg硬解码 ffmpeg android硬件解码_ndk

2 总体流程图如下

androidffmpeg硬解码 ffmpeg android硬件解码_ndk_02


以上的所有函数都比较重要,需要记住。另外由于FFmpeg版本的改变,其中的不少函数也进行了修改。修改的地方大家可以查看ffmpeg-3.4.1\doc\APIchanges文件,里面有不同版本函数更改的说明。

2.1 FFmpeg解码函数简介

av_register_all() :注册所有组件
avformat_open_input() :打开输入视频文件
avformat_find_stream_info() :获取视频文件信息
avcodec_find_decoder() :查找解码器
avcodec_open2() : 打开解码器
av_read_frame() : 从输入文件读取一帧压缩数据;
avcodec_decode_video2() 解码一帧压缩数据
avcodec_close() 关闭解码器
avformat_close_input() 关闭输入视频文件

2.2 FFmpeg解码的数据结构

androidffmpeg硬解码 ffmpeg android硬件解码_androidffmpeg硬解码_03


有的视频含有字幕,还会有AVStrean[3]

androidffmpeg硬解码 ffmpeg android硬件解码_FFmpeg_04

读取例如MP4格式的数据,就会得到stream数组,含有音视频和字幕那么数组的长度就是3,这里不确定哪个是音视频,这里就需要
遍历数组判断。

//视频解码,需要找到视频对应的AVStream所在format_ctx->streams的索引位置
    //获取音频和视频流的索引位置
    int i;
    for(i = 0; i < format_ctx->nb_streams;i++){
        if(format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){
            player->video_stream_index = i;
        }
        else if(format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO){
            player->audio_stream_index = i;
        }
    }

然后根据索引的位置获取相应的解码器

得到解码器上下文
    AVFormatContext *format_ctx = player->input_format_ctx;
    //获取解码器
    AVCodecContext *codec_ctx = format_ctx->streams[stream_idx]->codec;

2.3 FFmpeg数据结构简介

  • AVFormatContext
    封装格式上下文结构体,也是统领全局的结构体,保存了视频文件的封装格式相关信息
    初始化 AVFormatContext *pFormatCtx = avformat_alloc_context();
  • AVInputFormat
    每种封装格式(例如FLV,MKV,MP4,AVI)对应一个该结构体
    初始化AVInputFormat *av_input_format = pFormatCtx->iformat;
  • AVStream
    视频文件中每个视频(音频)流对应的一个该结构体
    pFormatCtx->streams[i]
  • AVCodecContext
    编码器上下文结构体,保存了视频(音频)编解码相关信息
    AVCodecContext *pCodecCtx = pFormatCtx->streams[v_stream_idx]->codec;
  • AVCodec
    每种视频(音频)编解码器(例如H.264解码器)对应一个该结构体
    AVCodec *pCodec = avcodec_find_decoder(pCodecCtx->codec_id)
  • AVPacket
    AVPacket用于存储一帧一帧的压缩数据(H264)
    缓冲区,开辟空间
    AVPacket *packet = (AVPacket*)av_malloc(sizeof(AVPacket));

androidffmpeg硬解码 ffmpeg android硬件解码_androidffmpeg硬解码_05

  • AVFrame
    存储一帧解码后像素(采样)数据
    AVFrame *pFrame = av_frame_alloc();

3 总结

基础很重要,前期由于纠结一些细节导致学习效率很低,经过这一段时间的学习、总结发现还是要将基础打牢才能事半功倍。