1.2 Ffmpeg 学习笔记
基本概念
ffmpeg 是一个用于处理视频、音频、图片等多媒体文件的工具。
ffmpeg 的主要功能有:
- 音视频格式转换
- 音视频编码
- 音视频裁剪
- 音视频混音
- 音视频转码
- 音视频水印
- 音视频拼接
- 音视频解码
AVPacket
AVPacket 是一个结构体,用于存储一个音频或视频数据包。
一个包里面包含音频或视频数据、时间戳、数据大小等信息。
通常内部包含一个或者多个AVFrame。
AVFrame
AVFrame 是一个结构体,用于存储一个音频或视频帧的数据。
读取基本流程
- 打开文件封装实例
- 查找流信息
- 获取视频流索引
- 查找音频流索引
找到对应的流关联的解码器ID,并分配一个解码器实例,拷贝源文件参数给解码器实例。 这只是打开文件封装实例,后续的解码操作都是基于这个封装实例。
- 打开文件封装实例
AVFormatContext *in_fmt_ctx ;
int ret = avformat_open_input(&in_fmt_ctx, src_name, NULL, NULL);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Can't open file %s.\n", src_name);
return -1;
}
- 查找流信息
ret = avformat_find_stream_info(in_fmt_ctx, NULL);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Can't find stream information.\n");
return -1;
}
- 获取视频流索引
int video_stream_idx = -1;
// 找到视频流的索引
video_stream_idx = av_find_best_stream(in_fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
if (video_stream_idx >= 0) {
src_video = in_fmt_ctx->streams[video_stream_idx];
enum AVCodecID video_codec_id = src_video->codecpar->codec_id;
// 查找视频解码器
AVCodec *video_codec = (AVCodec*) avcodec_find_decoder(video_codec_id);
if (!video_codec) {
qCritical() << "video_codec not found" << '\n';
return -1;
}
video_decode_ctx = avcodec_alloc_context3(video_codec); // 分配解码器的实例
if (!video_decode_ctx) {
qCritical() << "video_decode_ctx is null" << '\n';
return -1;
}
// 把视频流中的编解码参数复制给解码器的实例
avcodec_parameters_to_context(video_decode_ctx, src_video->codecpar);
ret = avcodec_open2(video_decode_ctx, video_codec, NULL); // 打开解码器的实例
if (ret < 0) {
qCritical() << "Can't open video_decode_ctx" << '\n';
return -1;
}
}
- 查找音频流索引
int audio_stream_idx = -1;
audio_stream_idx = av_find_best_stream(in_fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
if (audio_stream_idx >= 0) {
src_audio = in_fmt_ctx->streams[audio_stream_idx];
enum AVCodecID audio_codec_id = src_audio->codecpar->codec_id;
// 查找音频解码器
AVCodec *audio_codec = (AVCodec*) avcodec_find_decoder(audio_codec_id);
if (!audio_codec) {
qCritical() << "audio_codec not found" << '\n';
return -1;
}
audio_decode_ctx = avcodec_alloc_context3(audio_codec); // 分配解码器的实例
if (!audio_decode_ctx) {
qCritical() << "audio_decode_ctx is null" << '\n';
return -1;
}
// 把音频流中的编解码参数复制给解码器的实例
avcodec_parameters_to_context(audio_decode_ctx, src_audio->codecpar);
ret = avcodec_open2(audio_decode_ctx, audio_codec, NULL); // 打开解码器的实例
if (ret < 0) {
qCritical() << "Can't open audio_decode_ctx" << '\n';
return -1;
}
}