文章目录
- 前言
-
- 须知
- ffmpeg打开文件基本流程图
- ffmpeg打开媒体文件
-
- `AVFormatContext *avformat_alloc_context(void);`
- AVFormatContext 成员变量及其作用
-
- `AVInputFormat *iformat`
- `AVOutputFormat *oformat`
- `void *priv_data`
- `AVIOContext *pb`
- `unsigned int nb_streams`
- `AVStream **streams`
- `char filename[1024]`
- `int64_t duration`
- `int64_t bit_rate`
- `unsigned int nb_programs`
- `AVProgram **programs`
- `AVChapter **chapters`
- `unsigned int nb_chapters`
- `AVDictionary *metadata`
- `int flags`
- `int64_t start_time`
- `int64_t start_time_realtime`
- `int probesize`
- `int max_analyze_duration`
- `AVPacketList *packet_buffer`
- `int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options);`
- `int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);`
- `void av_dump_format(AVFormatContext *ic, int index, const char *url, int is_output);`
- `AVCodec *avcodec_find_decoder(enum AVCodecID id);`
- `const char *avcodec_get_name(enum AVCodecID id);`
- `const char *av_get_media_type_string(enum AVMediaType media_type);`
- `void avformat_close_input(AVFormatContext **s);`
- 示例
- 总结
前言
FFmpeg 是一个强大的多媒体处理库,广泛应用于音视频编解码、转换和流媒体处理等领域。C语言作为一种底层编程语言,与FFmpeg结合使用,可以高效地处理各种音视频任务。在本篇文章中,我们将探讨如何利用C语言和FFmpeg库打开一个音视频文件,并对其进行基本的处理操作。这不仅为深入学习FFmpeg的使用打下基础,也为从事多媒体处理工作的开发者提供实用的参考。
须知
本教程使用ffmpeg版本为7.0.1
如有函数不同请下载和我一样的版本
ffmpeg打开文件基本流程图
开始
↓
包含头文件和定义视频文件路径
↓
分配格式上下文
↓
打开输入文件
↓
|----------------------|
| 打开失败 |
| ↓ |
| 打印错误信息并返回 |
|----------------------|
↓
检查文件中的流信息
↓
|----------------------|
| 检查失败 |
| ↓ |
| 打印错误信息并关闭文件 |
|----------------------|
↓
打印文件格式信息
↓
遍历所有流
↓
获取流和编解码参数
↓
查找解码器
↓
打印流的基本信息
↓
|----------------------|
| 没有找到解码器 |
| ↓ |
| 打印不支持的编解码器 |
|----------------------|
↓
关闭输入文件并释放格式上下文
↓
结束
ffmpeg打开媒体文件
AVFormatContext *avformat_alloc_context(void);
- 作用: 分配并初始化
AVFormatContext
结构体。 - 参数: 无。
- 返回值: 指向新分配的
AVFormatContext
的指针。
AVFormatContext
结构体是 FFmpeg 中非常重要的一个数据结构,它包含了与多媒体文件或流相关的所有信息。以下是一些常用且重要的成员及其作用:
AVFormatContext 成员变量及其作用
AVInputFormat *iformat
- 作用: 指向输入格式的指针。当打开输入文件时,这个成员将指向描述文件格式的
AVInputFormat
结构。
AVOutputFormat *oformat
- 作用: 指向输出格式的指针。当创建输出文件时,这个成员将指向描述文件格式的
AVOutputFormat
结构。
void *priv_data
- 作用: 私有数据,存储特定于输入/输出格式的私有数据。
AVIOContext *pb
- 作用: I/O 上下文,用于管理文件或流的输入/输出操作。
unsigned int nb_streams
- 作用: 文件中的流数量。
AVStream **streams
- 作用: 指向包含所有流(音频、视频、字幕等)的指针数组。
char filename[1024]
- 作用: 文件名或 URL。
int64_t duration
- 作用: 文件的总时长(以 AV_TIME_BASE 为单位)。
int64_t bit_rate
- 作用: 文件的总比特率(以比特每秒为单位)。
unsigned int nb_programs
- 作用: 文件中节目的数量。
AVProgram **programs
- 作用: 指向包含所有节目的指针数组。
AVChapter **chapters
- 作用: 指向包含所有章节的指针数组。
unsigned int nb_chapters
- 作用: 文件中的章节数量。
AVDictionary *metadata
- 作用: 文件的元数据(如标题、作者、版权等)。
int flags
- 作用: 标志位,用于控制各种操作行为。
int64_t start_time
- 作用: 文件的开始时间(以 AV_TIME_BASE 为单位)。
int64_t start_time_realtime
- 作用: 以实时起始时间的时间戳表示的开始时间。
int probesize
- 作用: 探测的大小,用于确定文件的格式。
int max_analyze_duration
- 作用: 分析的最大时长,用于确定文件的格式。
AVPacketList *packet_buffer
- 作用: 包含读取的数据包的缓冲区。
以下示例展示如何访问 AVFormatContext
的一些成员变量:
AVFormatContext *formatContext = avformat_alloc_context();
if (avformat_open_input(&formatContext, "example.mp4", NULL, NULL) == 0) {
printf("Format: %s\n", formatContext->iformat->name);
printf("Number of streams: %u\n", formatContext->nb_streams);
printf("Duration: %" PRId64 "\n", formatContext->duration);
printf("Bit rate: %" PRId64 "\n", formatContext->bit_rate);
for (unsigned int i = 0; i < formatContext->nb_streams; i++) {
AVStream *stream = formatContext->streams[i];
printf("Stream #%u\n", i);
printf(" Codec ID: %d\n", stream->codecpar->codec_id);
printf(" Codec type: %s\n", av_get_media_type_string(stream->codecpar->codec_type));
}
avformat_close_input(&formatContext);
}
int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options);
- 作用: 打开输入文件并读取头部信息。
- 参数:
ps
: 指向AVFormatContext
指针的指针。filename
: 文件名。fmt
: 指定输入格式,可以为 NULL。options
: 一些额外的选项,可以为 NULL。
- 返回值: 成功返回 0,失败返回负值。
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);
- 作用: 检查文件中的流信息。
- 参数:
ic
:AVFormatContext
指针。options
: 一些额外的选项,可以为 NULL。
- 返回值: 成功返回非负值,失败返回负值。
void av_dump_format(AVFormatContext *ic, int index, const char *url, int is_output);
- 作用: 打印文件格式信息。
- 参数:
ic
:AVFormatContext
指针。index
: 要打印的流的索引,为 0 表示打印全部流信息。url
: 文件的 URL。is_output
: 指示是输入还是输出格式,0 表示输入,1 表示输出。
- 返回值: 无。
AVCodec *avcodec_find_decoder(enum AVCodecID id);
- 作用: 查找给定 codec id 的解码器。
- 参数:
id
: codec 的 ID。
- 返回值: 指向
AVCodec
的指针,如果未找到返回 NULL。
const char *avcodec_get_name(enum AVCodecID id);
- 作用: 获取 codec id 对应的 codec 名称。
- 参数:
id
: codec 的 ID。
- 返回值: codec 名称的字符串指针。
const char *av_get_media_type_string(enum AVMediaType media_type);
- 作用: 获取媒体类型的字符串表示。
- 参数:
media_type
: 媒体类型。
- 返回值: 媒体类型名称的字符串指针。
void avformat_close_input(AVFormatContext **s);
- 作用: 关闭输入文件并释放格式上下文。
- 参数:
s
: 指向AVFormatContext
指针的指针。
- 返回值: 无。
示例
#include <stdio.h>
#include "include/libavcodec/avcodec.h"
#include "include/libavformat/avformat.h"
#include "include/libavutil/avutil.h"
int main() {
const char *videoname = "/home/ubuntu/MyFFMPEG/template_c_first/test2.mp4";
//打开输入文件并读取头部信息
AVFormatContext *formatContext = avformat_alloc_context();
if(avformat_open_input(&formatContext,videoname,NULL,NULL) != 0)
{
printf("open err:%s\n",videoname);
return -1;
}
// 检查文件中的流信息
if (avformat_find_stream_info(formatContext, NULL) < 0) {
printf("Could not find stream information in file %s\n", videoname);
avformat_close_input(&formatContext);
return -1;
}
// 打印文件格式信息
av_dump_format(formatContext, 0, videoname, 0);
// 遍历所有流并打印流信息
for (unsigned int i = 0; i < formatContext->nb_streams; i++) {
AVStream *stream = formatContext->streams[i];
AVCodecParameters *codecParams = stream->codecpar;
AVCodec *codec = avcodec_find_decoder(codecParams->codec_id);
if (codec == NULL) {
printf("Unsupported codec!\n");
continue;
}
printf("Stream #%u:\n", i);
printf(" Codec: %s (%s)\n", codec->name, avcodec_get_name(codecParams->codec_id));
printf(" Type: %s\n", av_get_media_type_string(codecParams->codec_type));
printf(" Duration: %ld\n", stream->duration);
printf(" Time base: %d/%d\n", stream->time_base.num, stream->time_base.den);
}
// 关闭输入文件并释放格式上下文
avformat_close_input(&formatContext);
return 0;
}
输出:
ubuntu@ubuntu-virtual-machine:~/MyFFMPEG/template_c_first/build$ ./ffmpeg_test
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/home/ubuntu/MyFFMPEG/template_c_first/test2.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf61.1.100
description : Packed by Bilibili XCoder v2.0.2
Duration: 00:00:30.07, start: 0.000000, bitrate: 3275 kb/s
Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 3124 kb/s, 60 fps, 60 tbr, 16k tbn (default)
Metadata:
handler_name : Bento4 Video Handler
vendor_id : [0][0][0][0]
Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 135 kb/s (default)
Metadata:
handler_name : Bento4 Sound Handler
vendor_id : [0][0][0][0]
Stream #0:
Codec: h264 (h264)
Type: video
Duration: 481066
Time base: 1/16000
Stream #1:
Codec: aac (aac)
Type: audio
Duration: 1323000
Time base: 1/44100
总结
通过本文的介绍,我们了解了如何使用C语言结合FFmpeg库来打开一个音视频文件,并对其进行基本处理。FFmpeg提供了丰富的功能和灵活的接口,能够满足各种多媒体处理需求。掌握FFmpeg的使用方法,不仅能够提升我们在多媒体领域的开发效率,还能拓宽我们的技术视野。希望本篇文章能为读者提供有益的帮助,激发进一步探索FFmpeg和多媒体处理技术的兴趣。