ffmpeg编解码详细过程

主要流程:

1. 注册所有容器格式和CODEC:av_register_all()

2. 打开文件:av_open_input_file()

3. 从文件中提取流信息:av_find_stream_info()

4. 穷举所有的流,查找其中种类为CODEC_TYPE_VIDEO

5. 查找对应的解码器:avcodec_find_decoder()

6. 打开编解码器:avcodec_open()

7. 为解码帧分配内存:avcodec_alloc_frame()

8. 不停地从码流中提取出帧数据:av_read_frame()

9. 判断帧的类型,对于视频帧调用:avcodec_decode_video()

10. 解码完后,释放解码器:avcodec_close()

11. 关闭输入文件:av_close_input_file()

 

首先第一件事情就是开一个视频文件并从中得到流。我们要做的第一件事情就是使用av_register_all();来初始化libavformat/libavcodec: 

这一步注册库中含有的所有可用的文件格式和编码器,这样当打开一个文件时,它们才能够自动选择相应的文件格式和编码器。av_register_all()只需调用一次,所以,要放在初始化代码中。也可以仅仅注册个人的文件格式和编码。

下一步,打开文件:

AVFormatContext *pFormatCtx;
const char      *filename="myvideo.mpg";
av_open_input_file(&pFormatCtx, filename, NULL, 0, NULL)   // 打开视频文件
最后三个参数描述了文件格式,缓冲区大小(size)和格式参数;我们通过简单地指明NULL0告诉 libavformat 去自动探测文件格式并且使用默认的缓冲区大小。这里的格式参数指的是视频输出参数,比如宽高的坐标。

下一步,我们需要取出包含在文件中的流信息:
av_find_stream_info(pFormatCtx)                                // 取出流信息

AVFormatContext 结构体

dump_format(pFormatCtx, 0, filename, false);//我们可以使用这个函数把获取到得参数全部输出。

for(i=0; i<pFormatCtx->nb_streams; i++)        //区分视频流和音频流
 if(pFormatCtx->streams->codec.codec_type==CODEC_TYPE_VIDEO) //找到视频流,这里也可以换成音频
    {
        videoStream=i;
        break;
    }

接下来就需要寻找解码器

AVCodec *pCodec;
pCodec=avcodec_find_decoder(pCodecCtx->codec_id);

avcodec_open(pCodecCtx, pCodec)    // 打开解码器
给视频帧分配空间以便存储解码后的图片:

AVFrame *pFrame;
pFrame=avcodec_alloc_frame();

/开始解码///

第一步当然是读数据:

我们将要做的是通过读取包来读取整个视频流,然后把它解码成帧,最后转换格式并且保存。

while(av_read_frame(pFormatCtx, &packet)>=0) {     //读数据

     if(packet.stream_index==videoStream){         //判断是否视频流

         avcodec_decode_video(pCodecCtx,pFrame, &frameFinished,

packet.data, packet.size);                         //解码

     if(frameFinished) {

img_convert((AVPicture *)pFrameRGB, PIX_FMT_RGB24,(AVPicture*)pFrame, pCodecCtx->pix_fmt, pCodecCtx->width,pCodecCtx->height);//转换   }   

SaveFrame(pFrameRGB, pCodecCtx->width,pCodecCtx->height, i); //保存数据

av_free_packet(&packet);                       //释放

av_read_frame()读取一个包并且把它保存到AVPacket结构体中。这些数据可以在后面通过av_free_packet()来释 放。函数avcodec_decode_video()把包转换为帧。然而当解码一个包的时候,我们可能没有得到我们需要的关于帧的信息。因此,当我们得 到下一帧的时候,avcodec_decode_video()为我们设置了帧结束标志frameFinished。最后,我们使用 img_convert()函数来把帧从原始格式(pCodecCtx->pix_fmt)转换成为RGB格式。要记住,你可以把一个 AVFrame结构体的指针转换为AVPicture结构体的指针。最后,我们把帧和高度宽度信息传递给我们的SaveFrame函数。

到此解码完毕,显示过程使用SDL完成考虑到我们以后会使用firmware进行显示操作,SDL忽略不讲。

音视频同步

DTS(解码时间戳)和PTS(显示时间戳)

当我们调用av_read_frame()得到一个包的时候,PTSDTS的信息也会保存在包中。但是我们真正想要的PTS是我们刚刚解码出来的 原始帧 PTS,这样我们才能知道什么时候来显示它。然而,我们从avcodec_decode_video()函数中得到的帧只是一个AVFrame,其中并 没有包含有用的PTS值(注意:AVFrame并没有包含时间戳信息,但当我们等到帧的时候并不是我们想要的样子)。。我们保存一帧的第一个包的PTS 这将作为整个这一帧的PTS。我们 可以通过函数avcodec_decode_video()来计算出哪个包是一帧的第一个包。怎样实现呢?任何时候当一个包开始一帧的时 候,avcodec_decode_video()将调用一个函数来为一帧申请一个缓冲。当然,ffmpeg允许我们重新定义那个分配内存的函数。计算前 一帧和现在这一帧的时间戳来预测出下一个时间戳的时间。同时,我们需要同步视频到音频。我们将设置一个音频时间audioclock;一个内部值记录了我 们正在播放的音频的位置。就像从任意的mp3播放器中读出来的数字一样。既然我们把视频同步到音频,视频线程使用这个值来算出是否太快还是太慢。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
FFmpeg是一个开源的跨平台多媒体框架,它可以处理视频、音频以及流媒体等多种不同的媒体格式。在使用FFmpeg进行媒体处理的过程中,编解码是其中最为核心的部分之一。下面我们将通过图文的形式,详细讲解FFmpeg编解码流程。 1. 媒体文件解析 在进行编解码之前,首先需要对媒体文件进行解析,获取媒体文件的基本信息以及相关的参数。对于视频文件,需要获取视频的分辨率、帧率、编码格式等信息;对于音频文件,需要获取音频的采样率、声道数、编码格式等信息。 2. 解码器初始化 FFmpeg中的解码器用于将媒体文件中的编码数据解码成原始数据。在进行解码之前,需要先对解码器进行初始化,包括选择合适的解码器、设置解码器参数等。 3. 解码数据 解码器初始化完成后,可以开始对媒体文件中的编码数据进行解码。解码器会将编码数据解码成原始数据,包括视频帧和音频样本等。 4. 编码器初始化 在进行编码之前,需要对编码器进行初始化,包括选择合适的编码器、设置编码器参数等。编码器用于将原始数据编码成压缩数据,以便于在传输、存储等环节中进行处理。 5. 编码数据 编码器初始化完成后,可以开始对原始数据进行编码。编码器会将原始数据编码成压缩数据,包括视频帧和音频样本等。 6. 数据封装 在编码完成后,需要对压缩数据进行封装,生成标准的媒体格式。对于视频文件,常见的媒体格式包括MP4、AVI、FLV等;对于音频文件,常见的媒体格式包括MP3、WAV等。 7. 输出数据 封装完成后,可以将生成的媒体文件输出到指定的位置,包括本地文件、网络流等。 总体来说,FFmpeg编解码流程可以分为媒体文件解析、解码器初始化、解码数据、编码器初始化、编码数据、数据封装和输出数据等七个步骤。通过这些步骤,可以将不同格式的媒体文件进行编解码处理,实现多媒体处理的各种需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值