生而自由

自由而无用的灵魂

FFMPEG系列之三:视频封装为MP4文件

上一篇讲到了将帧(AVFrame)编码为H264视频流,并直接写文件保存。这样保存的是裸的视频流,大部分播放器是无法正常播放的--要么直接打不开、要么播放时有“快进”的现象,只有KMPlayer、PotPlayer这些专业的播放器可以播放。

原因在于我们平常接触的视频文件如MP4、AVI、KMV等其实是视频的“容器”,容器里面封装了视频流、音频流、字幕流等各种流,而且可以同时包含多个同种流--比如包含多个字幕流,这样在播放时就可以切换字幕了。同时容器的头部一般还提供了相当多的信息--如其中包含的流信息、编码信息等--以使解码时能正确地解码。所以只有将视频流封装到容器中,才能说真正地得到了一个视频文件。

示例代码同样来自FFMPEG官方示例:https://ffmpeg.org/doxygen/2.8/muxing_8c-example.html,这里仅摘取了其中的部分重要代码。与上一篇文章中的代码对比,可以发现仅仅添加如下改动即可:

  1. 首先得获取AVFormatContext,通过avformat_alloc_output_context2(&oc, NULL, NULL, filename)即可获取。
  2. 同样的先通过avcodec_find_encoder找到编码器,然后以该编码器为参数再往AVFormatContext里面添加一个视频流:avformat_new_stream(oc, *codec)。
  3. 从视频流里面就可以拿到AVCodecContext了(上文中是avcodec_alloc_context3得到的),和上文一样,比特率、视频宽高之类的都在它上面设置就行了,不过注意time_base要在AVStream上设置,然后同样的以avcodec_open2来用编码器打开AVCodecContext就行了。
  4. 写文件时,先打开文件:avio_open(&oc->pb, filename, AVIO_FLAG_WRITE),再写入容器头信息:avformat_write_header(oc, NULL),然后写入编码后的AVPacket时用av_interleaved_write_frame(oc, &pkt)来写入,最后在结束时使用av_write_trailer(oc)来写入尾部,当然还要使用avio_closep(&oc->pb)来关闭输出文件。

 

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.