ffmpeg解封装及解码实战
目录
- 封装格式相关函数
- 解封装流程
- 补充
- 分离AAC和H264
1. 封装格式相关函数
1. 基本概念

2. 相关函数
1. avformat_alloc_context();负责申请一个AVFormatContext结构的内存,并进行简单初始化
2. avformat_free_context();释放AVFormatContext及其所有流。
3. avformat_close_input();关闭解复用器。关闭后就不再需要使用avformat_free_context 进行释放
4. avformat_open_input();打开输入视频文件
- 打开一个输入流并读取报头。编解码器未打开。
- 流必须用avformat_close_input()关闭。
- ps指向用户提供的AVFormatContext(由avformat_alloc_context分配)的指针。可能是一个指向NULL的指针,在哪种情况下AVFormatContext是由这个分配的函数并写入ps。
- 内部有调用avformat_alloc_context()
5. avformat_find_stream_info():获取音视频文件信息
6. av_read_frame(); 读取音视频包
7. avformat_seek_file(); 定位文件
8. av_seek_frame():定位文件
2. 解封装流程

3. 补充
1. 区分不同的码流
- AVMEDIA_TYPE_VIDEO视频流:video_index = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO,
-1,-1, NULL, 0) - AVMEDIA_TYPE_AUDIO音频流:audio_index = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO,
-1,-1, NULL, 0) - AVPacket 里面也有一个index的字段
2. 补充点
- avformat_open_input和avformat_find_stream_info分别用于打开一个流和分析流信息。
- 在初始信息不足的情况下(比如FLV和H264文件),avformat_find_stream_info接口需要在内部调用read_frame_internal接口读取流数据(音视频帧),然后再分析后,设置核心数据结构AVFormatContext。
- 由于需要读取数据包, avformat_find_stream_info接口会带来很大的延迟
4. 分离AAC和H264
- 代码
#include <stdio.h>
#include <libavformat/avformat.h>
int main(int argc, char **argv) {
const char *default_filename = "believe.mp4";
char *in_filename = NULL;
if (argv[1] == NULL) {
in_filename = default_filename;
} else {
in_filename = argv[1];
}
printf("in_filename = %s\n", in_filename);
AVFormatContext *ifmt_ctx = NULL;
int videoindex = -1;
int audioindex = -1;
int ret = avformat_open_input(&ifmt_ctx, in_filename, NULL, NULL);
if (ret < 0)
{
char buf[1024] = {0};
av_strerror(ret, buf, sizeof(buf) - 1);
printf("open %s failed:%s\n", in_filename, buf);
goto failed;
}
ret = avformat_find_stream_info(ifmt_ctx, NULL);
if (ret < 0)
{
char buf[1024] = {0};
av_strerror(ret, buf, sizeof(buf) - 1);
printf("avformat_find_stream_info %s failed:%s\n", in_filename, buf);
goto failed;
}
printf_s("\n==== av_dump_format in_filename:%s ===\n", in_filename);
av_dump_format(ifmt_ctx, 0, in_filename, 0);
printf_s("\n==== av_dump_format finish =======\n\n");
printf("media name:%s\n", ifmt_ctx->url);
printf("stream number:%d\n", ifmt_ctx->nb_streams);
printf("media average ratio:%lldkbps\n", (int64_t)(ifmt_ctx->bit_rate / 1024));
int total_seconds, hour, minute, second;
total_seconds = (ifmt_ctx->duration) / AV_TIME_BASE;
hour = total_seconds / 3600;
minute = (total_seconds % 3600) / 60;
second = (total_seconds % 60);
printf("total duration: %02d:%02d:%02d\n", hour, minute, second);
printf("\n");
for (uint32_t i = 0; i < ifmt_ctx->nb_streams; i++) {
AVStream *in_stream = ifmt_ctx->streams[i];
if (AVMEDIA_TYPE_AUDIO == in_stream->codecpar->codec_type) {
printf("----- Audio info:\n");
printf("index:%d\n", in_stream->index);
printf("samplerate:%dHz\n", in_stream->codecpar->sample_rate);
if (AV_SAMPLE_FMT_FLTP == in_stream->codecpar->format) {
printf("sampleformat:AV_SAMPLE_FMT_FLTP\n");
} else if (AV_SAMPLE_FMT_S16P == in_stream->codecpar->format) {
printf("sampleformat:AV_SAMPLE_FMT_S16P\n");
}
printf("channel number:%d\n", in_stream->codecpar->channels);
if (AV_CODEC_ID_AAC == in_stream->codecpar->codec_id) {
printf("audio codec:AAC\n");
} else if (AV_CODEC_ID_MP3 == in_stream->codecpar->codec_id) {
printf("audio codec:MP3\n");
} else {
printf("audio codec_id:%d\n", in_stream->codecpar->codec_id);
}
if (in_stream->duration != AV_NOPTS_VALUE) {
int duration_audio = (in_stream->duration) * av_q2d(in_stream->time_base);
printf("audio duration: %02d:%02d:%02d\n",
duration_audio / 3600, (duration_audio % 3600) / 60, (duration_audio % 60));
} else {
printf("audio duration unknown");
}
printf("\n");
audioindex = i;
} else if (AVMEDIA_TYPE_VIDEO == in_stream->codecpar->codec_type)
{
printf("----- Video info:\n");
printf("index:%d\n", in_stream->index);
printf("fps:%lffps\n", av_q2d(in_stream->avg_frame_rate));
if (AV_CODEC_ID_MPEG4 == in_stream->codecpar->codec_id)
{
printf("video codec:MPEG4\n");
} else if (AV_CODEC_ID_H264 == in_stream->codecpar->codec_id)
{
printf("video codec:H264\n");
} else {
printf("video codec_id:%d\n", in_stream->codecpar->codec_id);
}
printf("width:%d height:%d\n", in_stream->codecpar->width,
in_stream->codecpar->height);
if (in_stream->duration != AV_NOPTS_VALUE) {
int duration_video = (in_stream->duration) * av_q2d(in_stream->time_base);
printf("video duration: %02d:%02d:%02d\n",
duration_video / 3600,
(duration_video % 3600) / 60,
(duration_video % 60));
} else {
printf("video duration unknown");
}
printf("\n");
videoindex = i;
}
}
AVPacket *pkt = av_packet_alloc();
int pkt_count = 0;
int print_max_count = 10;
printf("\n-----av_read_frame start\n");
while (1) {
ret = av_read_frame(ifmt_ctx, pkt);
if (ret < 0) {
printf("av_read_frame end\n");
break;
}
if (pkt_count++ < print_max_count) {
if (pkt->stream_index == audioindex) {
printf("audio pts: %lld\n", pkt->pts);
printf("audio dts: %lld\n", pkt->dts);
printf("audio size: %d\n", pkt->size);
printf("audio pos: %lld\n", pkt->pos);
printf("audio duration: %lf\n\n",
pkt->duration * av_q2d(ifmt_ctx->streams[audioindex]->time_base));
} else if (pkt->stream_index == videoindex) {
printf("video pts: %lld\n", pkt->pts);
printf("video dts: %lld\n", pkt->dts);
printf("video size: %d\n", pkt->size);
printf("video pos: %lld\n", pkt->pos);
printf("video duration: %lf\n\n",
pkt->duration * av_q2d(ifmt_ctx->streams[videoindex]->time_base));
} else {
printf("unknown stream_index:\n", pkt->stream_index);
}
}
av_packet_unref(pkt);
}
if (pkt)
av_packet_free(&pkt);
failed:
if (ifmt_ctx)
avformat_close_input(&ifmt_ctx);
getchar();
return 0;
}
- 结果
