解封装:如下图所示,就是将FLV、MKV、MP4等文件解封装为视频H.264或H.265压缩数据,音频MP3或AAC的压缩数据,下图为常用的基本操作。

ffmpeg使用解封装的基本流程如下:

在使用FFmpeg API之前,需要先注册API,然后才能使用API。当然,新版本ffmpeg库不需要再调用下面的方法。
av_register_all()
初始化网络配置
avformat_network_init
设置一些参数,如下图所示,设置了最大延迟、传输协议等参数。
- //参数设置
- AVDictionary *opts = NULL;
-
- //设置rtsp流已tcp协议打开
- av_dict_set(&opts, "rtsp_transport", "tcp", 0);
- av_dict_set(&opts, "max_delay", "500", 0);
- av_dict_set(&opts, "buffer_size", "1024000", 0);
- av_dict_set(&opts, "probsize", "4096", 0);
- av_dict_set(&opts, "fps", "25", 0);
构建AVFormatContext,声明输入的封装结构体,通过输入文件或者流地址作为封装结构的句柄。
- AVFormatContext* inputFmtCtx = nullptr;
- const char* inputUrl = "test.mp4";
-
- ///打开输入的流,获取数据 begin
- int ret = avformat_open_input(&inputFmtCtx, inputUrl, NULL, NULL);
查找音视频流信息,通过下面的接口与AVFormatContext中建立输入文件对应的流信息。
- //查找;
- if (avformat_find_stream_info(inputFmtCtx, NULL) < 0)
- {
- printf("Couldn't find stream information.\n");
- return false;
- }
读取音视频流,采用av_read_frame来读取数据包,读出来的数据存储在AVPacket中,确定其为音频、视频、字幕数据,最后解码,或者存储。
- AVPacket* pkt = NULL;
- pkt = av_packet_alloc();
-
- while (av_read_frame(inputFmtCtx, pkt) >= 0)
- {
- //获取数据包
-
- //.....解码或者存储
-
- //重置
- av_packet_unref(pkt);
- }
上述代码所示,通过循环调用av_read_frame()读取到pkt包,然后可以进行解码或者存储数据,如果读取的数据结束,则退出循环,开始指向结束操作。
每次使用完AVPacket包后,需要重置,否则会内存泄漏。
- //重置
- av_packet_unref(pkt);
执行结束后关闭输入文件,释放资源。
- //关闭
- avformat_close_input(&inputFmtCtx);
-
- //释放
- avformat_free_context(inputFmtCtx);
-
- //释放资源
- av_packet_free(&pkt);
新建空白解决方案,如下图所示。

解决方案,右键-添加-新建项目。

新建Qt控制台程序,3_demuxDemo

然后,配置ffmpeg的编译环境:看目录4。
解封装源码示例:
- #include
-
- extern "C" {
- #include "libavutil/avstring.h"
- #include "libavutil/channel_layout.h"
- #include "libavutil/eval.h"
- #include "libavutil/mathematics.h"
- #include "libavutil/pixdesc.h"
- #include "libavutil/imgutils.h"
- #include "libavutil/dict.h"
- #include "libavutil/fifo.h"
- #include "libavutil/parseutils.h"
- #include "libavutil/samplefmt.h"
- #include "libavutil/time.h"
- #include "libavutil/bprint.h"
- #include "libavutil/opt.h"
- #include "libavformat/avformat.h"
- #include "libavcodec/avcodec.h"
- #include "libavfilter/avfilter.h"
- #include "libavdevice/avdevice.h"
- #include "libswscale/swscale.h"
- #include "libavutil/opt.h"
- #include "libavutil/imgutils.h"
- #include "libavcodec/avfft.h"
- #include "libswresample/swresample.h"
- }
-
- #include
- using namespace std;
-
- static double r2d(AVRational r)
- {
- return r.den == 0 ? 0 : (double)r.num / (double)r.den;
- }
-
- int main(int argc, char *argv[])
- {
- QCoreApplication a(argc, argv);
-
- //av_register_all();
- avformat_network_init();
-
- AVDictionary* options = NULL;
-
- av_dict_set(&options, "buffer_size", "1024000", 0);
- av_dict_set(&options, "max_delay", "500000", 0);
- av_dict_set(&options, "stimeout", "2000000", 0);
- av_dict_set(&options, "rtsp_transport", "tcp", 0);
-
- AVFormatContext* inputFmtCtx = nullptr;
- const char* inputUrl = "F:/1920x1080.mp4";
-
- ///打开输入的流,获取数据 begin
- int ret = avformat_open_input(&inputFmtCtx, inputUrl, NULL, NULL);
- if (ret != 0)
- {
- printf("Couldn't open input stream.\n");
- return -1;
- }
-
- int vIndex = -1;
- int aIndex = -1;
-
- //查找;
- if (avformat_find_stream_info(inputFmtCtx, NULL) < 0)
- {
- printf("Couldn't find stream information.\n");
- return false;
- }
-
-
- for (int i = 0; i < inputFmtCtx->nb_streams/*视音频流的个数*/; i++)
- {
- //查找视频
- if (inputFmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
- {
- vIndex = i;
- }
- else if (inputFmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
- {
- aIndex = i;
- }
- }
-
- //===================video=================
- //视频宽
- int width = inputFmtCtx->streams[vIndex]->codecpar->width;
-
- //视频高
- int height = inputFmtCtx->streams[vIndex]->codecpar->height;
-
- //视频总时长s
- int64_t m_totalTime = static_cast<double>(inputFmtCtx->duration) / AV_TIME_BASE;
-
- //获取帧率;
- int fps = r2d(inputFmtCtx->streams[vIndex]->avg_frame_rate);
- if (fps == 0)
- {
- fps = 25;
- }
-
- int iHour, iMinute, iSecond, iTotalSeconds;//HH:MM:SS
- //打印结构体信息
- puts("AVFormatContext信息:");
- puts("---------------------------------------------");
- iTotalSeconds = (int)inputFmtCtx->duration/*微秒*/ / 1000000;
- iHour = iTotalSeconds / 3600;//小时
- iMinute = iTotalSeconds % 3600 / 60;//分钟
- iSecond = iTotalSeconds % 60;//秒
- printf("持续时间:%02d:%02d:%02d\n", iHour, iMinute, iSecond);
- printf("平均混合码率:%d kb/s\n", inputFmtCtx->bit_rate / 1000);
- printf("视音频个数:%d\n", inputFmtCtx->nb_streams);
- puts("---------------------------------------------");
-
- puts("AVInputFormat信息:");
- puts("---------------------------------------------");
- printf("封装格式名称:%s\n", inputFmtCtx->iformat->name);
- printf("封装格式长名称:%s\n", inputFmtCtx->iformat->long_name);
- printf("封装格式扩展名:%s\n", inputFmtCtx->iformat->extensions);
- printf("封装格式ID:%d\n", inputFmtCtx->iformat->raw_codec_id);
- puts("---------------------------------------------");
-
- puts("AVStream信息:");
- puts("---------------------------------------------");
- printf("视频流标识符:%d\n", inputFmtCtx->streams[vIndex]->index);
- printf("音频流标识符:%d\n", inputFmtCtx->streams[aIndex]->index);
- printf("视频流长度:%d微秒\n", inputFmtCtx->streams[vIndex]->duration);
- printf("音频流长度:%d微秒\n", inputFmtCtx->streams[aIndex]->duration);
- puts("---------------------------------------------");
-
- printf("视频时长:%d微秒\n", inputFmtCtx->streams[vIndex]->duration);
- printf("音频时长:%d微秒\n", inputFmtCtx->streams[aIndex]->duration);
- printf("视频宽:%d\n", inputFmtCtx->streams[vIndex]->codecpar->width);
- printf("视频高:%d\n", inputFmtCtx->streams[vIndex]->codecpar->height);
- printf("音频采样率:%d\n", inputFmtCtx->streams[aIndex]->codecpar->sample_rate);
- printf("音频信道数目:%d\n", inputFmtCtx->streams[aIndex]->codecpar->channels);
-
- puts("AVFormatContext元数据:");
- puts("---------------------------------------------");
- AVDictionaryEntry *dict = NULL;
- while (dict = av_dict_get(inputFmtCtx->metadata, "", dict, AV_DICT_IGNORE_SUFFIX))
- {
- printf("[%s] = %s\n", dict->key, dict->value);
- }
- puts("---------------------------------------------");
-
- puts("AVStream视频元数据:");
- puts("---------------------------------------------");
- dict = NULL;
- while (dict = av_dict_get(inputFmtCtx->streams[vIndex]->metadata, "", dict, AV_DICT_IGNORE_SUFFIX))
- {
- printf("[%s] = %s\n", dict->key, dict->value);
- }
- puts("---------------------------------------------");
-
- puts("AVStream音频元数据:");
- puts("---------------------------------------------");
- dict = NULL;
- while (dict = av_dict_get(inputFmtCtx->streams[aIndex]->metadata, "", dict, AV_DICT_IGNORE_SUFFIX))
- {
- printf("[%s] = %s\n", dict->key, dict->value);
- }
- puts("---------------------------------------------");
-
-
- av_dump_format(inputFmtCtx, -1, inputUrl, 0);
- printf("\n\n编译信息:\n%s\n\n", avcodec_configuration());
-
- AVPacket* pkt = NULL;
- pkt = av_packet_alloc();
-
- while (av_read_frame(inputFmtCtx, pkt) >= 0)
- {
- //获取数据包
-
- //.....解码或者存储
-
- //重置
- av_packet_unref(pkt);
- }
-
-
- //关闭
- avformat_close_input(&inputFmtCtx);
-
- //释放
- avformat_free_context(inputFmtCtx);
-
- //释放资源
- av_packet_free(&pkt);
-
-
- return a.exec();
- }
运行截图:

完整工程: